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).
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