2014-09-16 13 views
5

Supponiamo che io abbia una matrice di elementi in questo modo:efficiente calcolare una matrice 3D di prodotti esterni - MATLAB

A = reshape(1:25, 5, 5) 

A = 

1  6 11 16 21 
2  7 12 17 22 
3  8 13 18 23 
4  9 14 19 24 
5 10 15 20 25 

Vorrei calcolare in modo efficiente una matrice 3D di prodotti esterni, in modo tale che l'i esimo la fetta di questa matrice di output è il prodotto esterno della colonna i th di A con se stesso. Il prodotto esterno tra due vettori u e v è semplicemente u*v.' se u e v sono entrambi vettori di colonna.

Pertanto, ogni fetta di questa matrice di uscita B dovrebbe essere strutturata in modo tale che:

B(:,:,1) = A(:,1) * A(:,1).'; 
B(:,:,2) = A(:,2) * A(:,2).'; 
     ... 
     ... 
B(:,:,5) = A(:,5) * A(:,5).'; 

mio metodo attuale è il seguente. Ho provato facendo in questo modo usando arrayfun e cell2mat:

cellmatr = arrayfun(@(x) A(:,x) * A(:,x).', 1:size(A,2), 'uni', 0); 
out = reshape(cell2mat(cellmatr), size(A,1), size(A,1), size(A,2)); 

semplicemente ciclare su un array di indici lineare tra 1 ed altrettante colonne abbiamo in A, e per ciascun elemento di questa matrice, accedo corrispondente colonna e calcolare il prodotto esterno. L'output fornirà quindi una griglia 1D di celle, che poi riconvertirò in una matrice 2D, quindi rimodellare in una matrice 3D per trovare la matrice 3D dei prodotti esterni.

Tuttavia, per le matrici di grandi dimensioni, questo è piuttosto lento. Ho anche provato a sostituire il prodotto matrice con kron (ad esempio kron(A(:,x), A(:,x))) all'interno della mia chiamata arrayfun, ma questo è ancora abbastanza lento per i miei scopi.


Qualcuno sa di un modo efficiente per calcolare questa matrice 3D di prodotti esterni in questo modo?

+0

hai guardato in questo: http://www.mathworks.com/matlabcentral/fileexchange/25977-mtimesx- supporto veloce-multiplo-multi-dimensionale – bla

+0

@natan - Non ce l'ho, ma grazie per il link a FEX! – rayryeng

+0

Mi chiedo quanto sarebbe efficace contro la risposta di Divakar ... – bla

risposta

8

Questo è solo un lieve miglioramento rispetto a Divakar's answer. E 'un po' più veloce perché sostituisce una permute 3D-array con permute 2D-array:

B = bsxfun(@times, permute(A, [1 3 2]), permute(A, [3 1 2])); 
+1

Solo un commento sulla temporizzazione - quando ho inserito questo nel mio algoritmo complessivo, il tempo impiegato per completare l'algoritmo con ciascuna soluzione era il seguente con una matrice '3125 x 3125': Divakar: 0,403 secondi, Amro: 0,304 secondi, Luis Mendo: 0,284 secondi. Ho eseguito 100 prove di dati casuali e ho calcolato una media dei tempi. – rayryeng

+0

Appena controllato per essere sicuro. Questo calcolerà anche il complesso insieme di prodotti esterni "diagonali" (solo gli indici corrispondenti) tra i vettori in due matrici separate. Sostituendo il secondo 'A' con' conj (B) 'calcoleremo' per k = 1: n; C (:,:, k) = A (:, k) * B (:, k) '; END; '. –

3

Questo -

B = permute(bsxfun(@times,A,permute(A,[3 2 1])),[1 3 2]) 
+0

Ho sempre difficoltà con 'permute', quindi ho dovuto interrompere ogni affermazione una alla volta e vedere cosa succede ad ogni passo. Capisco cosa sta succedendo adesso e vorrei averlo capito da solo!Ad ogni modo, penso che sia stata una buona domanda da porre :) – rayryeng

+2

Questo sembra essere un po 'più veloce, in quanto sostituisce una permutazione di un array 3D con permute 2D-array: 'B = bsxfun (@ times, permute (A, [ 1 3 2]), permute (A, [3 1 2])); ' –

+0

@LuisMendo - Il tuo tweak nella soluzione batte effettivamente il ciclo' for'. – rayryeng

7

Per affermare l'ovvio, hai provato un semplice ciclo for:

[m,n] = size(A); 
B = zeros(m,m,n); 
for i=1:n 
    B(:,:,i) = A(:,i) * A(:,i).'; 
end 

Sarete sorpresi di quanto velocemente in modo competitivo sia.

+0

Non ho considerato un ciclo 'for' perché non pensavo che avrebbe funzionato. Ho appena eseguito alcuni test e questo è in realtà leggermente più veloce di 'permute/bsxfun'. Ben fatto Amro. – rayryeng

+3

+1 amro, a volte anche l'ovvio bisogno di menzionare. Preferisco anche questo su bsxfun, molto più leggibile ... – bla

+0

Anche questa è un'ottima soluzione! + 1 BTW pre-allocazione con 'B (m, m, n) = 0;' potrebbe essere considerato anche. – Divakar

Problemi correlati