Предположим, что у меня есть матрица NxN A, индексный вектор V, состоящий из подмножества чисел 1: N и значения K, и я хочу сделать это:
for i = V
A(i,i) = K
end
Есть ли способ сделать это в одном утверждении w/vectorization?
например. A (что-то) = K
Оператор A(V,V) = K
не будет работать, он назначает недиагональные элементы, и это не то, что я хочу. например:.
>> A = zeros(5);
>> V = [1 3 4];
>> A(V,V) = 1
A =
1 0 1 1 0
0 0 0 0 0
1 0 1 1 0
1 0 1 1 0
0 0 0 0 0
Я обычно использую EYE для этого:
A = magic(4)
A(logical(eye(size(A)))) = 99
A =
99 2 3 13
5 99 10 8
9 7 99 12
4 14 15 99
В качестве альтернативы вы можете просто создать список линейных индексов, так как от одного диагонального элемента до следующего он принимает шаги nRows+1
:
[nRows,nCols] = size(A);
A(1:(nRows+1):nRows*nCols) = 101
A =
101 2 3 13
5 101 10 8
9 7 101 12
4 14 15 101
Если вы хотите получить доступ к подмножеству диагональных элементов, вам необходимо создать список диагональных индексов:
subsetIdx = [1 3];
diagonalIdx = (subsetIdx-1) * (nRows + 1) + 1;
A(diagonalIdx) = 203
A =
203 2 3 13
5 101 10 8
9 7 203 12
4 14 15 101
В качестве альтернативы вы можете создать логический индексный массив с помощью diag
(работает только для квадратных массивов)
diagonalIdx = false(nRows,1);
diagonalIdx(subsetIdx) = true;
A(diag(diagonalIdx)) = -1
A =
-1 2 3 13
5 101 10 8
9 7 -1 12
4 14 15 101
diag
, прежде чем я помню, как использовать eye
>> tt = zeros(5,5)
tt =
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
>> tt(1:6:end) = 3
tt =
3 0 0 0 0
0 3 0 0 0
0 0 3 0 0
0 0 0 3 0
0 0 0 0 3
и более общий:
>> V=[1 2 5]; N=5;
>> tt = zeros(N,N);
>> tt((N+1)*(V-1)+1) = 3
tt =
3 0 0 0 0
0 3 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 3
Это основано на том, что к матрицам можно обращаться как к одномерным массивам (векторам), где 2 индекса (m, n) заменяются линейным отображением m * N + n.
Предположим, что K - значение. Команда
A=A-diag(K-diag(A))
может быть немного быстрее
>> A=randn(10000,10000);
>> tic;A(logical(eye(size(A))))=12;toc
Истекшее время - 0,517575 секунд.
>> tic;A=A+diag((99-diag(A)));toc
Истекшее время составляет 0.353408 секунд.
Но он потребляет больше памяти.
A(logical(eye(size(A))))=K
гибкий, быстрый и надежный
A = zeros(7,6);
V = [1 3 5];
[n m] = size(A);
diagIdx = 1:n+1:n*m;
A( diagIdx(V) ) = 1
A =
1 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 1 0
0 0 0 0 0 0
0 0 0 0 0 0
Я бы использовал sub2ind
и передавал диагональные индексы в качестве параметров x и y:
A = zeros(4)
V=[2 4]
idx = sub2ind(size(A), V,V)
% idx = [6, 16]
A(idx) = 1
% A =
% 0 0 0 0
% 0 1 0 0
% 0 0 0 0
% 0 0 0 1