Meclassic
Meclassic

Reputation: 209

Matlab: create band matrix with repeating and alternating values

Let us say that I have 7 values: a, b, c, d, e, f and g

I would like to construct an m by n matrix in this way:

[ a b c d 0 0 0 0 . . . .
[ b e f g 0 0 0 0 . . . .
[ c f a b c d 0 0 . . . .
[ d g b e f g 0 0 . . . .
[ 0 0 c f a b c d 0 0 . .
[ 0 0 d g b e f g 0 0 . .
[ . . 0 0 c f a b c d . .
[ . . 0 0 d g b e f g . .

And so forth...

Therefore, the desired matrix is symmetrical. Values a and e alternate on the main diagonal; values b and f alternate on the 1st upper diagonal; values c and g alternate on the 2nd upper diagonal; values d and 0 alternate on the 3rd upper diagonal. I would like to be able to specify the matrix size with m by n parameters.

I used to do this easily with the SparseArray and Band functions in Mathematica, but I cannot find equivalent functions in Matlab. Would there be an efficient way to construct this kind of matrix in Matlab?

Upvotes: 2

Views: 743

Answers (2)

Teddy Ort
Teddy Ort

Reputation: 766

You can use the spdiags function

Using numbers instead of letters (sparse does not support symbols) like this:

m = 10;
n = 10;
B = repmat([1:4;[5:7 0]],n/2,1);
B=[B(:,end:-1:2) B];
d=-3:3;
A = spdiags(B,d,m,n);
full(A)

which outputs:

 1     6     3     0     0     0     0     0     0     0
 2     5     2     7     4     0     0     0     0     0
 3     6     1     6     3     0     0     0     0     0
 4     7     2     5     2     7     4     0     0     0
 0     0     3     6     1     6     3     0     0     0
 0     0     4     7     2     5     2     7     4     0
 0     0     0     0     3     6     1     6     3     0
...

Explanation:

The B matrix contains the values needed on the diagonals in its columns. It is first constructed using B = repmat([1:4;[5:7 0]],n/2,1); which makes the first two rows repeat n/2 times. At that point it looks like:

 1     2     3     4
 5     6     7     0
 1     2     3     4
 5     6     7     0
 1     2     3     4
 5     6     7     0
 1     2     3     4
...

Then it is mirrored to give it the diagonals that are in the lower diagonal part using B=[B(:,end:-1:2) B]; which makes it look like:

 4     3     2     1     2     3     4
 0     7     6     5     6     7     0
 4     3     2     1     2     3     4
 0     7     6     5     6     7     0
 4     3     2     1     2     3     4
 0     7     6     5     6     7     0
 4     3     2     1     2     3     4
 ...

These are the diagonals passed to the spdiags function.

The end is a MATLAB keyword which refers to the last column or row. That indexing line says, in words: "Take all the rows of B, and the columns starting from the end, going back 1 step at a time until the second column, and place that submatrix before B." That is how the mirroring is accomplished.

Upvotes: 2

TroyHaskin
TroyHaskin

Reputation: 8401

You can use spdiags to specify the upper diagonals in a sparse matrix and then add the transpose of the strictly upper triangular part for exact symmetry:

>> n  = 6;
>> a = 1;b = 2;c = 3;d = 4;e = 5;f = 6;g = 7;
>> n  = 6;
>> A = spdiags(repmat([[a;e] , [f;b] , [c;g] , [0;d]],n/2,1),0:3,n,n);
>> A = A + triu(A,1).';
>> issymmetric(A)
ans =
     1
>> full(A)
ans =
     1     2     3     4     0     0
     2     5     6     7     0     0
     3     6     1     2     3     4
     4     7     2     5     6     7
     0     0     3     6     1     2
     0     0     4     7     2     5

You might notice I flipped b/f and 0/d to adjust for the filling behavior; there may be a better way to do this.


For non-square matrices with potentially odd dimension number, I would build the minimum-sized square sparse matrix that has the actual one as a sub-matrix and mask out the unneeded portion at the end:

>> m = 13;
>> n = 6;
>> p = max([m,n]);
>> p = p + mod(p,2); % added to make p even.
>> A = spdiags(repmat([[a;e] , [f;b] , [c;g] , [0;d]],p/2,1),0:3,p,p);
>> A = A + triu(A,1).';
>> A = A(1:m,1:n);
>> full(A)
ans =
     1     2     3     4     0     0
     2     5     6     7     0     0
     3     6     1     2     3     4
     4     7     2     5     6     7
     0     0     3     6     1     2
     0     0     4     7     2     5
     0     0     0     0     3     6
     0     0     0     0     4     7
     0     0     0     0     0     0
     0     0     0     0     0     0
     0     0     0     0     0     0
     0     0     0     0     0     0
     0     0     0     0     0     0

It's a tad inefficient to build, but easy and straight-forward.

Upvotes: 3

Related Questions