kronecker product for an array of matrices [duplicate] - matlab

I have two tensor: x is 2-by-2-by-3, y is also 2-by-2-by-3. Define each frontal slice of tensor is x1 x2 x3,y1,y2,y3. xi or yi are 2-by-2 matrix. How can I do kronecker product between x and y in matlab? What I want to get is kron(x1,y1),kron(x2,y2),kron(x3,y3) in matlab simultaneously without any looping.

This works for arbitrary sizes of x and y:
Build a 5D array z. The first two dimensions contain the products of combinations of rows of x and y; the next two contain the products of combinations of columns of x and y; and the fifth is the original third dimension.
That arrray is reshaped, collapsing dimensions first ant second on one hand, and third and fourth on the other hand, to produce the final result:
Code:
z = bsxfun(#times, permute(x, [4 1 5 2 3]), permute(y, [1 4 2 5 3])); %// step 1
z = reshape(z, size(x,1)^2, size(x,2)^2, size(x,3)); %//step 2

This could be one approach -
%// Pre-processing part
[m,n,r] = size(x) %// Get size
N = m*n %// number of elements in one 3D slice
%// ------------- PART 1: Get indices for each 3D slice
%// Get the first mxm block of kron-corresponding indices and then add to
%// each such block for the indices corresponding to the kron multiplications
%// of each iteration
a1 = bsxfun(#plus,reshape([0:N-1]*N+1,m,m),permute([0:N-1],[1 3 2]))
%// Now, a1 is a 3D array, we need to make 2D array out of it.
%// So, concatenate along rows to make it a "slimish" 2D array
a2 = reshape(permute(a1,[1 3 2]),size(a1,1)*size(a1,3),[])
%// Cut after every N rows to make it a square 2D array.
%// These are the indices for each frontal tensor of kron muliplications
slice_idx = reshape(permute(reshape(a2,N,size(a2,1)/N,[]),[1 3 2]),N,N)
%// ------------- PART 2: Get kron equivalent output
%// Perform x:(Nx1) x y:(1xN) multiplications
vals = bsxfun(#times,reshape(x,m*n,1,r),reshape(y,1,m*n,r)) %//multiplications
%// Get indices for all 3D slices and then index into those multiplications
%// with these for the final kron equivalent output
all_idx=bsxfun(#plus,slice_idx,permute([0:r-1]*m*m*n*n,[1 3 2])) %//all indices
out = vals(all_idx) %// final output of kron equivalent multiplications

Related

3d matrix: how to use (row, column) pairs with 3rd dimension wildcard in MATLAB?

I have a 3 dimensional matrix, and a list of (row, column) pairs. I would like to extract the 2 dimensional matrix that corresponds to the elements in those positions, projected through the depth of the matrix. For instance, suppose,
>> a = rand(4, 3, 2)
a(:,:,1) =
0.5234 0.7057 0.0282
0.6173 0.2980 0.9041
0.7337 0.9380 0.9639
0.0591 0.8765 0.1693
a(:,:,2) =
0.8803 0.2094 0.5841
0.7151 0.9174 0.6203
0.7914 0.7674 0.6194
0.2009 0.2542 0.3600
>> rows = [1 4 2 1];
>> cols = [1 2 1 3];
What I'd like to get is,
0.5234 0.8765 0.6173 0.0282
0.8803 0.2542 0.7151 0.5841
maybe with some permutation of dimensions. Also, although this example has the wildcard in the last dimension, I also have cases where it's in the first or second.
I naively tried a(rows, cols, :) and got a 3d matrix where the diagonal plane is what I want. I also found sub2ind, which will extract the desired elements from the a(:,:,1) plane. I could work with one of these to get to what I want, but I'm wondering is there a more canonical, elegant, or efficient method that I'm missing?
Update
This was the solution I used, based on the answer posted below,
sz = size(a);
subs = [repmat(rows, [1, sz(3)]);
repmat(cols, [1, sz(3)]);
repelem([1:sz(3)], length(rows))];
result = a(sub2ind(sz, subs(1,:), subs(2,:), subs(3,:)));
sub2ind is pretty much what you have to use here to convert your subscripts into linear indices (apart from manually computing the linear indices yourself). You can do something like the following which will convert the rows and cols to a linear index (in a 2D slice) and then it adds an offset (equal to the number of elements in a 2D slice) to these indices to sample all elements in the third dimension.
sz = size(a);
inds = sub2ind(sz(1:2), rows, cols);
inds = bsxfun(#plus, inds, (0:(sz(3)-1)).' * prod(sz(1:2)));
result = a(inds);
And to actually compute the linear indices yourself
inds = (cols - 1) * sz(1) + rows;
inds = bsxfun(#plus, inds, (0:(sz(3) - 1)).' * prod(sz(1:2)));
result = a(inds);
Another option would be to permute your initial matrix to bring the third dimension to the first dimension, reshape it to a 2D matrix, and then use the linear index as the second subscript
% Create a new temporary matrix
anew = reshape(permute(a, [3, 1, 2]), size(a, 3), []);
% Grab all rows (the 3rd dimension) and compute the columns to grab
result = anew(:, (cols - 1) * size(a, 1) + rows);

Kronecker product between two tensors

I have two tensor: x is 2-by-2-by-3, y is also 2-by-2-by-3. Define each frontal slice of tensor is x1 x2 x3,y1,y2,y3. xi or yi are 2-by-2 matrix. How can I do kronecker product between x and y in matlab? What I want to get is kron(x1,y1),kron(x2,y2),kron(x3,y3) in matlab simultaneously without any looping.
This works for arbitrary sizes of x and y:
Build a 5D array z. The first two dimensions contain the products of combinations of rows of x and y; the next two contain the products of combinations of columns of x and y; and the fifth is the original third dimension.
That arrray is reshaped, collapsing dimensions first ant second on one hand, and third and fourth on the other hand, to produce the final result:
Code:
z = bsxfun(#times, permute(x, [4 1 5 2 3]), permute(y, [1 4 2 5 3])); %// step 1
z = reshape(z, size(x,1)^2, size(x,2)^2, size(x,3)); %//step 2
This could be one approach -
%// Pre-processing part
[m,n,r] = size(x) %// Get size
N = m*n %// number of elements in one 3D slice
%// ------------- PART 1: Get indices for each 3D slice
%// Get the first mxm block of kron-corresponding indices and then add to
%// each such block for the indices corresponding to the kron multiplications
%// of each iteration
a1 = bsxfun(#plus,reshape([0:N-1]*N+1,m,m),permute([0:N-1],[1 3 2]))
%// Now, a1 is a 3D array, we need to make 2D array out of it.
%// So, concatenate along rows to make it a "slimish" 2D array
a2 = reshape(permute(a1,[1 3 2]),size(a1,1)*size(a1,3),[])
%// Cut after every N rows to make it a square 2D array.
%// These are the indices for each frontal tensor of kron muliplications
slice_idx = reshape(permute(reshape(a2,N,size(a2,1)/N,[]),[1 3 2]),N,N)
%// ------------- PART 2: Get kron equivalent output
%// Perform x:(Nx1) x y:(1xN) multiplications
vals = bsxfun(#times,reshape(x,m*n,1,r),reshape(y,1,m*n,r)) %//multiplications
%// Get indices for all 3D slices and then index into those multiplications
%// with these for the final kron equivalent output
all_idx=bsxfun(#plus,slice_idx,permute([0:r-1]*m*m*n*n,[1 3 2])) %//all indices
out = vals(all_idx) %// final output of kron equivalent multiplications

Linear index of the maximum of a multi-dimensional matrix - MATLAB

Let's say I have a 3-dimensional matrix and have computed the max along the second dimension, and want to get the linear indices of the max values. However, the max-function only returns the subscripts along one dimension.
A = randn([5,5,5]); % Generate random matrix
[M, Ind] = max(A,[],2); % Take the max along dimension 2
How do I transfer the index to linear indexing, such that
M == A(Ind)
becomes true?
My intention for this problem is that I have two multi-dimensional matrices and need to compute the max in the first one. Then, I want to access the values in the second matrix at exactly those positions where I found a max in the first one.
One way is to use sub2ind:
A = randn([5,5,5]);
[M, col] = max(A,[],2);
[m,n,o] = size(A);
dim1 = mod((0:m*o-1)', m)+1;
dim2 = col(:);
dim3 = ceil((1:m*o)/m)';
ind = sub2ind(size(A), dim1, dim2, dim3)
verify it works with
isequal(M(:), A(ind))
to get them to have the same shape as M:
reshape(ind, m, 1, o)
Create the indices for the other dimensions.
In dim 1 the index needs to change fastest: [1,2,...,size(A,1)] and this size(A,3) times:
idx1 = repmat((1:size(A,1))',size(A,3),1);
In dim 2 the index is given by Ind.
In dim 3 the index need to change slowest: [1,1,...,1] for size(A,1) times and then [2,2,...,2] and so on until size(A,3).
idx3 = ones(size(A,1),1)*(1:size(A,3));
Access single values:
M_ = A(sub2ind(size(A),idx1(:),Ind(:),idx3(:)));
Compare:
M(:) == M_
3-dimensional case:
[m, n, p] = size(A);
[M, Ind] = max(A,[],2);
LinInd = bsxfun(#plus, (1:m).', (0:p-1)*m*n); %'//
LinInd = LinInd(:) + (Ind(:)-1)*m;
The desired linear index is LinInd. This produces
A(LinInd) == M(:)
with all true entries (note you need (:) on the right-hand side so that the comparison makes sense).
General multi-dimensonal case:
d = 3; %// dimension along which max will be computed
s = size(A);
sLow = prod(s(1:d-1));
sHigh = prod(s(d+1:end));
[M, Ind] = max(A,[],d);
LinInd = bsxfun(#plus, (1:sLow).', (0:sHigh-1)*sLow*s(d)); %'//
LinInd = LinInd(:) + (Ind(:)-1)*sLow;
Let's suppose A and B are the two matrices you have and you need to get max indices from A and use those indices to index into B for the desired output. One approach to achieve the same could be like this -
%// Your code to get Ind
A = randn([5,5,5]); % Generate random matrix
[M, Ind] = max(A,[],2); % Take the max along dimension 2
%// ------- Solution code -------------
%// Get the size of A
[n1,n2,n3] = size(A)
%// Linear indices corresponding to column and third dimension indices
col_dim3_lin_idx = bsxfun(#plus,(Ind-1)*n1,permute([0:n3-1]*n1*n2,[1 3 2]))
%// Finally get the overall linear indices
linear_index = bsxfun(#plus,col_dim3_lin_idx,[1:n1]') %//'
%// Get the corresponding elements from B
out = B(linear_index)
Slightly different way to have the desired linear indices as a 2D array would be like this -
[n1,n2,n3] = size(A) %// Get the size of A
idx = bsxfun(#plus,bsxfun(#plus,squeeze((Ind-1)*n1),[0:n3-1]*n1*n2),[1:n1]')
idx(:) would be the column vector of linear indices with this new approach, which you can index into B i.e. B(idx(:)) to have the desired output as a column vector.

How to represent a vector as a matrix?

I have a vector of length 3. i want to represent it as a matrix of dimension 4*2. ie) if the length of vector is n then matrix should be of dimension (n+1)*2. The matrix should have elements arranged as follows:
Vector= [2 3 4]
Matrix = [0 2;2 3;3 4;4 0]
You can solve your problem easily with simple operations:
vector = [2 3 4];
matrix = [0 vector; vector 0]';
' is used to transpose the matrix.
Additionally there are two useful functions in Matlab to manipulate matrices and vectors:
reshape()
repmat()
The command reshape from Matlab is the basis of my answer to your question:
B = reshape(A,m,n) returns the m-by-n matrix B whose elements are taken column-wise from A. An error results if A does not have m*n elements (from the official Matlab help).
You basically add zeros at the beginning and at the end and then have every number in the vector occur twice (if you "unfold"/reshape the matrix). So lets construct the desired matrix by reversing this description:
%set input vector
v = [2 3 4];
%"double" the numbers, v_ is my temporary storage variable
v_ = [v; v];
%align all numbers along one dimension
v_ = reshape(v_, 2*length(v), 1)
%add zeros at beginning and end
v_ = [0 v_ 0];
%procude final matrix
m = reshape(v_, length(v)+1, 2);
in short
%set input vector
v = [2 3 4];
%"double" the numbers, v_ is my temporary storage variable
%all values are aligned as row vector
%zeros are added at beginning and end
v_ = [0, v, v, 0];
%produce final matrix
m = reshape(v_, length(v)+1, 2);
I haven't checked it, since I don't have a Matlab at hand right now, but you should get the idea.
Edit
The answer by 13aumi manages this task even without the reshape command. However, you need to pay close attention to the shape of v (row- vs- column-vector).

Matlab d-dimensional multipication table?

I'm new to Matlab and I'm trying to solve a problem that involves creating a d dimensional multiplication table where each edge goes from 1 to n. The problem statement says that inputting d = 0 should return the number 1 and d = 1 should return a column vector with the elements 1 to n.
Ideally, I would just create a matrix of 1 to n along d dimensions and then iterate through for each element setting it equal to the product of the indices, but I don't know how to create the d dimensional matrix.
Can anyone help me with this problem?
You can create the table with repeated use of bsxfun. At each iteration, the vector 1,2,...,n is shifted to a new dimension and multiplied (with singleton expansion) by the previous result.
%// Data
d = 3;
n = 10;
%// Computations
vector = (1:n).'; %// first dimension: column vector
result = 1; %// initialization
for n = 1:d
result = bsxfun(#times, result, vector); %// new dimension
vector = shiftdim(vector,-1); %// shift to the next dimension
end