# Most efficient way to put vector on the off-diagonal of the blocks of a block matrix

17 visualizzazioni (ultimi 30 giorni)
David Gillcrist il 23 Mag 2023
Modificato: David Goodmanson il 24 Mag 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 CommentiMostra -2 commenti meno recentiNascondi -2 commenti meno recenti

Accedi per commentare.

### Risposta accettata

Stephen23 il 23 Mag 2023
Modificato: Stephen23 il 23 Mag 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)
ans = 16×16
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 CommentiMostra -2 commenti meno recentiNascondi -2 commenti meno recenti

Accedi per commentare.

### Più risposte (2)

David Goodmanson il 24 Mag 2023
Modificato: David Goodmanson il 24 Mag 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 CommentoMostra -1 commenti meno recentiNascondi -1 commenti meno recenti
Dyuman Joshi il 24 Mag 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)
M = 16×16
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

Accedi per commentare.

John D'Errico il 23 Mag 2023
The most efficient way? SPDIAGS.
help spdiags
SPDIAGS Sparse matrix formed from diagonals. SPDIAGS, which generalizes the function "diag", deals with three matrices, in various combinations, as both input and output. [B,d] = SPDIAGS(A) extracts all nonzero diagonals from the m-by-n matrix A. B is a min(m,n)-by-p matrix whose columns are the p nonzero diagonals of A. d is a vector of length p whose integer components specify the diagonals in A. B = SPDIAGS(A,d) extracts the diagonals specified by d. A = SPDIAGS(B,d,A) replaces the diagonals of A specified by d with the columns of B. The output is sparse. A = SPDIAGS(B,d,m,n) creates an m-by-n sparse matrix from the columns of B and places them along the diagonals specified by d. Roughly, A, B and d are related by for k = 1:p B(:,k) = diag(A,d(k)) end Example: These commands generate a sparse tridiagonal representation of the classic second difference operator on n points. e = ones(n,1); A = spdiags([e -2*e e], -1:1, n, n) Some elements of B, corresponding to positions "outside" of A, are not actually used. They are not referenced when B is an input and are set to zero when B is an output. See the documentation for an illustration of this behavior. See also DIAG, SPEYE. Documentation for spdiags doc spdiags Other uses of spdiags codistributed/spdiags gpuArray/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)
A =
(2,1) 8 (1,2) 9 (3,2) 10 (2,3) 8 (4,3) 4 (3,4) 6 (5,4) 7 (4,5) 6 (6,5) 2 (5,6) 6
full(A)
ans = 6×6
0 9 0 0 0 0 8 0 8 0 0 0 0 10 0 6 0 0 0 0 4 0 6 0 0 0 0 7 0 6 0 0 0 0 2 0
spy(A)
Note that I padded an extra element, a NaN in this case, at the beginning of V2 and the end of V1.
##### 1 CommentoMostra -1 commenti meno recentiNascondi -1 commenti meno recenti
David Gillcrist il 23 Mag 2023
This doesn't quite do what I'm asking though. Every nth value in the off diagonal needs to be zero.

Accedi per commentare.

### Categorie

Scopri di più su Sparse Matrices in Help Center e File Exchange

R2022a

### Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by