2010-10-18 8 views
40

Supongamos que tengo una matriz NxN A, un índice vector V que consiste en un subconjunto de los números 1: N, y un valor de K, y yo quiero hacer esto:¿Cómo asignar valores en la diagonal?

for i = V 
    A(i,i) = K 
end 

¿Hay una manera de hacer esto en una declaración w/vectorization?

p. Ej. A (algo) = K

La instrucción A(V,V) = K no funcionará, asigna elementos fuera de diagonal, y esto no es lo que quiero. por ejemplo:

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

Respuesta

60

lo general el uso EYE para ello:

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 

Como alternativa, sólo puede crear la lista de índices lineales, ya que desde un elemento diagonal a la siguiente, se necesita nRows+1 pasos:

[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 

Si sólo desea acceder a un subconjunto de elementos de la diagonal, es necesario crear una lista de índices diagonales:

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 

Como alternativa, puede crear una matriz de índice de lógica usando diag (sólo funciona para matrices cuadradas)

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 
+0

fresco, funciona! aceptará cuando el estúpido temporizador se agote –

+0

@Jason S: ¡Gracias! De hecho, me parece un problema molesto; A menudo intento usar 'diag' primero, antes de recordar usar' eye' – Jonas

+0

para los segundos últimos ejemplos, sugiero usar la función sub2ind de matlab para encontrar los índices absolutos. En mi opinión, este es el enfoque más directo (y más fácil de leer) y podría reemplazar sus dos últimas sugerencias. – tc88

21
>> 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 

y más general:

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

Esto se basa en el hecho de que las matrices se pueden acceder como matrices unidimensionales (vectores), donde los 2 índices (m, n) se reemplazan por un mapeo lineal m * N + n.

+0

Solo vi su solución después de haber enviado mi edición. +1 por ser más rápido, aunque mi solución es un poco más general :) – Jonas

+1

Me gusta mucho el método tt (1: n + 1: end), ¡realmente limpio! – Erika

2
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 
2

Supongamos que K es el valor. El comando

A=A-diag(K-diag(A)) 

puede ser un poco más rápido

>> A=randn(10000,10000); 

>> tic;A(logical(eye(size(A))))=12;toc 

tiempo transcurrido es 0.517575 segundos.

>> tic;A=A+diag((99-diag(A)));toc 

El tiempo transcurrido es 0.353408 segundos.

Pero consume más memoria.

+0

He usado 'A (lógico (ojo (tamaño (A)))) = K' flexible rápido y confiable – Vass

1

que haría uso de sub2ind y pasar los índices diagonales ya que ambos parámetros x y 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 
Cuestiones relacionadas