Most efficient way to put vector on the off-diagonal of the blocks of a block matrix
12 views (last 30 days)
Show older comments
David Gillcrist
on 23 May 2023
Edited: David Goodmanson
on 24 May 2023
I have two vectors each of the same length, and I want to put these vectors on the diagonal parts of each block of a matrix. Let's say my two vectors are and , both are of length , I am trying to construct an matrix that looks like
For example if my vectors were v = [1 2 3 4 5 6 7 8 9 8 7 6] and u = [9 8 7 6 5 4 3 2 1 2 3 4] then I would mant a matrix that looks like
[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
9 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 8 0 3 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 6 0 5 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 5 0 6 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 3 0 8 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 2 0 9 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 2 0 7 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 6;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0;
]
I would like to know what an efficient way of doing this, particularly with sparse arrays I could create this matrix.
0 Comments
Accepted Answer
Stephen23
on 23 May 2023
Edited: Stephen23
on 23 May 2023
v = [1,2,3,4,5,6,7,8,9,8,7,6];
u = [9,8,7,6,5,4,3,2,1,2,3,4];
L = sqrt(numel(v));
vM = reshape(v,fix(L),[]);
uM = reshape(u,fix(L),[]);
vM(end+1,:) = 0;
uM(end+1,:) = 0;
vM([2:end,1],:) = vM;
N = ceil(L).^2;
M = spdiags([uM(:),vM(:)],[-1,1],N,N);
Checking:
full(M)
0 Comments
More Answers (2)
David Goodmanson
on 24 May 2023
Edited: David Goodmanson
on 24 May 2023
Hi David,
MODIFIED
see Dyuman's comment to sensibly shorten this original code.
n = 4;
v = [1 2 3 4 5 6 7 8 9 8 7 6]; % length n*(n-1)
u = [9 8 7 6 5 4 3 2 1 2 3 4];
vv = [reshape(v,n-1,n); zeros(1,n)];
vv = vv(:);
vv(end) = [];
uu = [reshape(u,n-1,n); zeros(1,n)];
uu = uu(:);
uu(end) = [];
M = diag(vv,1) + diag(uu,-1)
you can cut even more lines using the code below but at the cost of transparancy, so I think Dyuman's version is the best one.
n = 4;
v = [1 2 3 4 5 6 7 8 9 8 7 6];
u = [9 8 7 6 5 4 3 2 1 2 3 4];
uv = [reshape([v u],n-1,2*n);zeros(1,2*n)];
M = diag(uv(1:n^2-1),1) + diag(uv(n^2+1:2*n^2-1),-1)
1 Comment
Dyuman Joshi
on 24 May 2023
You can use indexing to shorten the code by 2 lines -
n = 4;
v = [1 2 3 4 5 6 7 8 9 8 7 6]; % length n*(n-1)
u = [9 8 7 6 5 4 3 2 1 2 3 4];
vv = [reshape(v,n-1,n); zeros(1,n)];
vv = vv(1:end-1);
uu = [reshape(u,n-1,n); zeros(1,n)];
uu = uu(1:end-1);
M = diag(vv,1) + diag(uu,-1)
John D'Errico
on 23 May 2023
The most efficient way? SPDIAGS.
help spdiags
For example, to create a 6x6 sparse matrix, with an upper and lower diagonal elements as vectors of length 5, we do this:
V1 = randi(10,[5,1]); % Just some random numbers.
V2 = randi(10,[5,1]);
A = spdiags([[V1;nan],[nan;V2]],[-1,1],6,6)
full(A)
spy(A)
Note that I padded an extra element, a NaN in this case, at the beginning of V2 and the end of V1.
See Also
Categories
Find more on Creating and Concatenating Matrices in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!