Reputation: 170
Say I have a matrix A of dimension NxV. I want to create a larger matrix of size NTxVT, i.e. I want to replace each element e of the matrix A(e) with diag(T)*A(e)., while keeping the general orientation of the matrix (for instance, A(e) is to the left of A(e-1), so diag(T)*A(e) is to the left of diag(T)*A(e-1).
Is there a trick to accomplish this in matlab? (making each diagonal matrix and concatenating them will take forever).
Many thanks ^^
Upvotes: 6
Views: 199
Reputation: 221524
Using good old-fashioned matrix multiplication
-
M = reshape(diag(T)*A(:).',[size(A,1)*size(T,1) size(A,2)])
Sample run -
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
Upvotes: 1
Reputation: 112659
Using just indexing:
A = magic(3);
T = diag([-1 1]); %// example data from Daniel's 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));
Upvotes: 1
Reputation: 13131
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 the idea from this example
Upvotes: 6
Reputation: 36710
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 this is reshaped to a 2D-Matrix.
The image processing toolbox provides another solution which is very short but slow:
A = magic(3);
T = [-1 1]
T = diag(T);
M=blockproc(A,[1 1],@(x) x.data.*T);
And finally a implementation which generates a sparse matrix, which might be helpful for large T as 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 is of size nx1 the sparse solution cuts your memory usage by a factor of roughly n/1.55.
Upvotes: 4
Reputation: 51450
The simplest way I can think of is to combine arrayfun and cell2mat functions:
B = cell2mat(arrayfun((@(x) T .* x), A, 'UniformOutput', false));
First, I transformed matrix A
into a cell array of matrices T .* x
where x
is an element of A
(a assumed that T
is a matrix).
Then I used cell2mat
to transform in back into a matrix.
Here is a complete example (execute online):
A = magic(3);
T = diag([-1 1]);
B = cell2mat(arrayfun((@(x) T .* x), A, 'UniformOutput', false));
resulting in:
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
Upvotes: 3