Replace each element in the matrix with a diagonal matrix

Let's say that I have a matrix A of dimension NxV. I want to create a large NTxVT sized matrix, i.e. I want to replace each element e of the matrix A (e) with diag (T) * A (e). Keeping the general orientation of the matrix (for example, A (e) is to the left of A (e-1), therefore diag (T) * A (e) is to the left of diag (T) * A (e-1).

Is there a trick to achieving this in Matlab? (forcing each diagonal matrix and concatenating them forever).

Thanks a lot ^^

+6
source share
5 answers
A = magic(3); T = diag([-1 1]); kron(A,T) 

gives

 -8 0 -1 0 -6 0 0 8 0 1 0 6 -3 0 -5 0 -7 0 0 3 0 5 0 7 -4 0 -9 0 -2 0 0 4 0 9 0 2 

ps. I copied this idea from this example

+6
source

Here is a solution using bsxfun

 A = magic(3); T = [-1 1] T = diag(T); M=bsxfun(@times,permute(A,[3,1,4,2]),permute(T,[1,3,2,4])); M=reshape(M,size(T).*size(A)); 

It creates a 4D matrix, where the individual blocks are M(:,i,:,j) , then converted to a 2D matrix.

The image processing toolkit provides another very short but slow solution:

 A = magic(3); T = [-1 1] T = diag(T); M=blockproc(A,[1 1],@(x) x.data.*T); 

And finally, an implementation that generates a sparse matrix, which can be useful for large T, since your matrix will contain many zeros:

 T=[-1 1]; A=magic(3); %p and q hold the positions where the first element element is stored. Check sparse(p(:),q(:),A(:)) to understand this intermediate step [p,q]=ndgrid(1:numel(T):numel(T)*size(A,1),1:numel(T):numel(T)*size(A,2)); %now p and q are extended to hold the indices for all elements tP=bsxfun(@plus,p(:),0:numel(T)-1); tQ=bsxfun(@plus,q(:),0:numel(T)-1); % tA=bsxfun(@times,A(:),T); M=sparse(tP,tQ,tA); 

When T has size nx1, a sparse solution reduces your memory usage by about n / 1.55.

+4
source

The easiest way I can imagine is to combine arrayfun and cell2mat :

 B = cell2mat(arrayfun((@(x) T .* x), A, 'UniformOutput', false)); 

First I converted the matrix A to an array of matrix cells T .* x , where x is an element of A (it is assumed that T is a matrix).

Then I used cell2mat to convert back to matrix.

Here is a complete example ( run online ):

 A = magic(3); T = diag([-1 1]); B = cell2mat(arrayfun((@(x) T .* x), A, 'UniformOutput', false)); 

as a result of:

 B = -8 0 -1 0 -6 0 0 8 0 1 0 6 -3 0 -5 0 -7 0 0 3 0 5 0 7 -4 0 -9 0 -2 0 0 4 0 9 0 2 
+3
source

Using only indexing:

 A = magic(3); T = diag([-1 1]); %// example data from Daniel answer [a1, a2] = size(A); [t1, t2] = size(T); M = A(ceil(1/t1:1/t1:a1), ceil(1/t2:1/t2:a2)).*T(repmat(1:t1,1,a1), repmat(1:t2,1,a2)); 
+1
source

Using good old-fashioned matrix multiplication -

 M = reshape(diag(T)*A(:).',[size(A,1)*size(T,1) size(A,2)]) 

Run Example -

 A = magic(4) T = magic(3) M = reshape(diag(T)*A(:).',[size(A,1)*size(T,1) size(A,2)]) 

will result in -

 A = 16 2 3 13 5 11 10 8 9 7 6 12 4 14 15 1 T = %// Notice that only diag(T) elements would be used to calculate M 8 1 6 3 5 7 4 9 2 M = 128 16 24 104 80 10 15 65 32 4 6 26 40 88 80 64 25 55 50 40 10 22 20 16 72 56 48 96 45 35 30 60 18 14 12 24 32 112 120 8 20 70 75 5 8 28 30 2 
+1
source

Source: https://habr.com/ru/post/984069/


All Articles