2010-10-18 10 views
40

Supponiamo di avere una matrice NxN A, un V indice di vettore costituito da un sottoinsieme dei numeri 1: N, e un valore K, e voglio fare questo:Come assegnare valori sulla diagonale?

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

c'è un modo per farlo questo in una dichiarazione w/vectorization?

ad es. A (qualcosa) = K

La dichiarazione A(V,V) = K non funziona, assegna elementi fuori diagonale e questo non è quello che voglio. ad esempio:

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

risposta

60

Io di solito uso EYE per questo:

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 

In alternativa, si può semplicemente creare l'elenco degli indici lineari, dal momento che da un elemento diagonale a quello successivo, ci vuole nRows+1 passi:

[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 

Se si desidera solo per accedere a un sottoinsieme di elementi diagonali, è necessario creare un elenco di indici diagonale:

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 

In alternativa, è possibile creare un array di indici logica utilizzando diag (funziona solo per array quadrati)

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, funziona! accetterà quando scade lo stupido- –

+0

@ Jason S: Grazie! In realtà trovo questo un problema fastidioso; Spesso cerco di usare 'diag' prima, prima di ricordare di usare' eye' – Jonas

+0

per il penultimo esempio, suggerisco di usare la funzione sub2ind di matlab per trovare gli indici assoluti. Secondo me, questo è l'approccio più diretto (e più leggibile) e potrebbe sostituire i tuoi ultimi due suggerimenti. – 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 

e più generale:

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

Questo si basa sulla Infatti, è possibile accedere alle matrici come matrici unidimensionali (vettori), in cui i 2 indici (m, n) sono sostituiti da una mappatura lineare m * N + n.

+0

Ho visto la soluzione solo dopo aver inviato la mia modifica. +1 per essere più veloce, anche se la mia soluzione è un po 'più generale :) – Jonas

+1

Mi piace molto il metodo tt (1: n + 1: end), davvero pulito! – 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

Supponiamo che K sia il valore. Il comando

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

può essere un po 'più veloce

>> A=randn(10000,10000); 

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

tempo trascorso è 0.517575 secondi.

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

Il tempo trascorso è 0,353408 secondi.

Ma consuma più memoria.

+0

Ho usato 'A (logico (occhio (taglia (A)))) = K' flessibile veloce ed affidabile – Vass

1

Userei sub2ind e passare gli indici diagonali sia come parametri xey:

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