I am trying to index (not get) the diagonals of a matrix in matlab.

Say I have a matrix "M", that is n by n. Then I want to obtain all indeces of all possible diagonals in the matrix "M".

I know that the center diagonal is indexed by

M(1:(n+1):end)

and all the following diagonals above it are indexed as:

M((1+1*n):(n+1):end)M((1+2*n):(n+1):end)...M((1+n*n):(n+1):end)

Now I also want to get the diagonals below. I cannot for the life of me figure out how to however.

Reproducible example:

rng(1); % set seedn = 4;M = rand(n);

yielding

M =0.562408 0.947364 0.655088 0.1817020.960604 0.268834 0.469042 0.0891670.578719 0.657845 0.516215 0.4190000.226410 0.601666 0.169212 0.378740

where I would like to index the lower diagonals, e.g. the subdiagonal:

0.960604 0.657845 0.169212

That is, I don't need to get the diagonal by e.g. the diags function, but access the index (since I ultimately want to replace the matrix entries diagonal by diagonal).

2

Best Answer


As you already noted, you can use the diag function to get the main diagonal and other diagonals above or below the main diagonals,

M = magic(4) % Test dataM =16 2 3 135 11 10 89 7 6 124 14 15 1diag(M, -1)ans =5715

but you can not assign values to the diagonal with the diag function:

diag(M, -1) = [3; 2; 1]Index in position 2 is invalid. Array indices must be positive integers or logical values.

Instead, we can use logical indexing by indexing the array M with a logical matrix of the same size. We can easily create this matrix using the diag function, by creating a diagonal matrix with ones on the specified diagonal:

diag(ones(1, 3), -1)ans =0 0 0 01 0 0 00 1 0 00 0 1 0

To use this matrix for logical indexing, we need to convert it from double to logical with the logical function.

M(logical(diag(ones(1, 3), -1)))ans =5715

or assign new values to it with

M(logical(diag(ones(1, 3), -1))) = [99, 98, 97]M =16 2 3 1399 11 10 89 98 6 124 14 97 1

There is a slightly more performant way of using diag to get indices to a diagonal:

n = 5; % matrix sizeM = reshape(1:n*n,n,n); % matrix with linear indicesindices = diag(M, ii); % indices to diagonal ii

However, it is much easier to just compute the right indices directly. As discovered by OP, the upper diagonal elements are given by:

indices = (1+ii*n):(n+1):(n*n);

(Note that the parenthesis are not necessary, as the colon operator has the lowest precedence.)

The lower diagonal elements are given by:

indices = (1+ii):(n+1):((n-ii)*n);

Both series are identical for the main diagonal, where ii=0.

We can verify correctness of these calculations by using the first method:

n = 5; % matrix sizeM = reshape(1:n*n,n,n); % matrix with linear indicesfor ii=1:n-1indices = (1+ii*n):(n+1):(n*n);assert(isequal(indices, diag(M, ii).'))indices = (1+ii):(n+1):((n-ii)*n);assert(isequal(indices, diag(M, -ii).'))end