I have 8x8 matrix where I have 15 diagonals. upper left corner “diagonal 1” and the lower right corner “diagonal 15”. I want to zero out the specific sets of diagonals like {9, 10, 11, 12, 13, 14, 15} or {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}. Anyone please give me solution?
I believe you can use:
M = M - diag(diag(M,k),k);
where k is 0 for the main diagonal, negative for the lower diagonals (up to -7), positive for the upper diagonals (up to 7).
EDIT: My bad, this only zero out one of the diagonal of your choice. You can repeat the process for all the diagonals you want to zero out but that might not be optimal:
for k=[9 10 11 12 13 14 15]
M = M - diag(diag(M,k-length(M)),k-length(M));
end
I'm not sure if I understand your question correctly. Are you trying to zero out some subset of elements on the main diagonal, or are you trying to zero out an entire diagonal? Either way, you can look into using Matlab's "diag" function.
If you want to just zero out some elements on the main diagonal, you could use something like:
% A is a 15 x 15 matrix, want to zero out {1,2,3,8}th elements on the diagonal
d = diag(A); % diagonal elements of A
d([4:7 9:15]) = 0; % zero out the elements you want to KEEP
A = A - diag(d); % diag d is a diagonal matrix with d on the main diagonal
But it would be easier with a for loop:
for i=[1,2,3,8]
A(i,i) = 0;
end
Zeroing out the nth diagonal of A is actually easier:
Say you want to zero the 3rd diagonal, you would do: A = A - diag(diag(A,3),3);
I think my diagonal run the other way but you should get the idea.
Python code:
import numpy as np
matrix = np.ones((8,8))
print "matrix = \n", matrix
# Need to map "diagnals" to starting row & offset, this is for 8x8
start_map = {}
start_map[ 0] = (0, 7)
start_map[ 1] = (0, 6)
start_map[ 2] = (0, 5)
start_map[ 3] = (0, 4)
start_map[ 4] = (0, 3)
start_map[ 5] = (0, 2)
start_map[ 6] = (0, 1)
start_map[ 7] = (0, 0)
start_map[ 8] = (1, 0)
start_map[ 9] = (2, 0)
start_map[10] = (3, 0)
start_map[11] = (4, 0)
start_map[12] = (5, 0)
start_map[13] = (6, 0)
start_map[14] = (7, 0)
# Zero out selected "diagnal"
M, N = matrix.shape
for i in xrange(15):
new_matrix = np.array(matrix)
m, n = start_map[i]
while m < M and n < N:
new_matrix[m, n] = 0.0
m += 1
n += 1
print "'diag' = %d\n" % i, new_matrix
Here's the truncated output:
matrix =
[[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]]
'diag' = 0
[[ 1. 1. 1. 1. 1. 1. 1. 0.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]]
'diag' = 3
[[ 1. 1. 1. 1. 0. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 0. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 0. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 0.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]]
'diag' = 7
[[ 0. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 0. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 0. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 0. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 0. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 0. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 0. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 0.]]
'diag' = 8
[[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 0. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 0. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 0. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 0. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 0. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 0. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 0. 1.]]
'diag' = 9
[[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 1. 1. 1.]
[ 0. 1. 1. 1. 1. 1. 1. 1.]
[ 1. 0. 1. 1. 1. 1. 1. 1.]
[ 1. 1. 0. 1. 1. 1. 1. 1.]
[ 1. 1. 1. 0. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 0. 1. 1. 1.]
[ 1. 1. 1. 1. 1. 0. 1. 1.]]
If i follow you, here's a simple method:
a = rand(8,8);
indx = logical( diag(ones(1,8),0) );
a(indx) = 0;
Or in 1 line if you prefer,
a(logical(diag(ones(1,8),0))) = 0;
Note that when using diag(v,k) setting k=1 places v on the main diagonal, k=1 places v on the diagonal one place above the main diagonal, and so on.
Then repeat for non-main diagonals by changing k and the size of v accordingly.
Another way to do this is using indices directly.
For an 8x8 matrix, if you want to zero out the entries in one of the diagonals at or below the main diagonal, use this:
M((n+1):9:(64-8*n))=0;
This will run down the diagonal, stopping when it reaches the lowest row. For entries above the diagonal, instead of starting at n+1, you have to finish at 64-n, like this:
M((8*n+1):9:(64-n))=0;
In both cases, n is how far from the main diagonal you are - so n=0 is the main diagonal. This can be generalised with a bit of logic:
idx=1:9:64;
M(idx((idx+8*n)<65&(idx+8*n)>0)+8*n)=0;
For n>=0, this will select the n-th diagonal above the main diagonal. Negative values will select the diagonals below the main diagonal. Generalising further, for an NxN matrix,
idx=1:(N+1):N^2;
M(idx((idx+N*n)<=N^2&(idx+N*n)>0)+N*n)=0;
With broadcasting or appropriate use of repmat (or multiplication by a ones vector), this can be adapted to handle multiple diagonals at once, although it gets messier.
Say you have a square matrix M. If you just want to set the entire diagonal to zero, you'd do this:
M(sub2ind(size(M), [1:length(M)]',[1:length(M)]')) = 0;
If you wanted to set SOME of the diagonals to zero, say 1:5, 8:11, you can simply modify to:
M(sub2ind(size(M), [1:5, 8:11]',[1:5, 8:11]')) = 0;
Others have suggested using for loops. Don't EVER use a for loop in Matlab unless you absolutely have to. Native Matlab functions are way faster.
Another solution, based on Glen O's answer, that can work for non square matrices as well is presented below:
%% // Example inputs
N_ROWS = 6;
N_COLS = 4;
A = randi(20,N_ROWS,N_COLS);
DIAG_TO_MODIFY = -1;
REPLACE_VEC = rand(size(diag(A,DIAG_TO_MODIFY))); %// Will error if diagonal # is invalid.
%% // Processing; can be made a function
if -DIAG_TO_MODIFY > N_ROWS-1 || ...
DIAG_TO_MODIFY > N_COLS-1
error('Invalid diagonal number.');
end
if DIAG_TO_MODIFY < 0
firstInd = 1 - DIAG_TO_MODIFY;
elseif DIAG_TO_MODIFY > 0
firstInd = 1 + DIAG_TO_MODIFY*N_ROWS;
else %// DIAG_TO_MODIFY == 0
firstInd = 1;
end
A(firstInd:N_ROWS+1:end) = REPLACE_VEC;
来源:https://stackoverflow.com/questions/13593971/how-to-access-the-diagonals-of-a-matrix-and-change-the-value