In che modo l'operatore MATLAB backslash risolve per le matrici quadrate?


36

Stavo confrontando alcuni dei miei codici con codici MATLAB "stock". Sono sorpreso dai risultati.

Ho eseguito un codice di esempio (Sparse Matrix)

n = 5000;
a = diag(rand(n,1));
b = rand(n,1);
disp('For a\b');
tic;a\b;toc;
disp('For LU');
tic;LULU;toc;
disp('For Conj Grad');
tic;conjgrad(a,b,1e-8);toc;
disp('Inv(A)*B');
tic;inv(a)*b;toc;

Risultati:

    For a\b
    Elapsed time is 0.052838 seconds.

    For LU
    Elapsed time is 7.441331 seconds.

    For Conj Grad
    Elapsed time is 3.819182 seconds.

    Inv(A)*B
    Elapsed time is 38.511110 seconds.

Per matrice densa:

n = 2000;
a = rand(n,n);
b = rand(n,1);
disp('For a\b');
tic;a\b;toc;
disp('For LU');
tic;LULU;toc;
disp('For Conj Grad');
tic;conjgrad(a,b,1e-8);toc;
disp('For INV(A)*B');
tic;inv(a)*b;toc;

risultati:

For a\b
Elapsed time is 0.575926 seconds.

For LU
Elapsed time is 0.654287 seconds.

For Conj Grad
Elapsed time is 9.875896 seconds.

Inv(A)*B
Elapsed time is 1.648074 seconds.

Come diavolo è incredibile?


1
La barra rovesciata integrata di MATLAB, in altre parole il risolutore diretto per un sistema di equazioni lineari, utilizza il metodo Multifrontale per matrice sparsa, ecco perché A \ B è così fantastico.
Shuhao Cao,

1
Utilizza il codice di Tim Davis disponibile su cise.ufl.edu/research/sparse . Anche la bellezza scompare quando hai un problema non banale
Stali

1
Che cos'è "LULU"? Perché pensi che sia una buona implementazione di una fattorizzazione LU e successiva risoluzione diretta?
Jed Brown,

3
@Nunoxic Quale implementazione? L'hai scritto tu stesso? L'algebra lineare densa ad alte prestazioni, sebbene generalmente ben compresa in modo algoritmico, non è facile da implementare in modo efficiente su hardware moderno. Le migliori implementazioni BLAS / Lapack dovrebbero avvicinarsi al picco per una matrice di quelle dimensioni. Inoltre, dai tuoi commenti, ho l'impressione che pensi che LU e l'eliminazione gaussiana siano algoritmi diversi.
Jed Brown,

1
Chiama un codice Fortran scritto usando Intel MKL.
Inchiesta il

Risposte:


37

In Matlab, il comando '\' richiama un algoritmo che dipende dalla struttura della matrice A e include i controlli (piccolo overhead) sulle proprietà di A.

  1. Se A è scarso e fasciato, utilizzare un solutore fasciato.
  2. Se A è una matrice triangolare superiore o inferiore, utilizzare un algoritmo di sostituzione all'indietro.
  3. Se A è simmetrico e presenta elementi diagonali realmente positivi, prova una fattorizzazione di Cholesky. Se A è scarso, utilizzare prima il riordino per ridurre al minimo il riempimento.
  4. Se nessuno dei criteri sopra è soddisfatto, esegui una fattorizzazione triangolare generale usando l'eliminazione gaussiana con rotazione parziale.
  5. Se A è scarso, utilizzare la libreria UMFPACK.
  6. Se A non è quadrato, utilizzare algoritmi basati sulla fattorizzazione QR per sistemi indeterminati.

Per ridurre il sovraccarico è possibile utilizzare il comando linsolve in Matlab e selezionare personalmente un risolutore adatto tra queste opzioni.


Supponendo che io abbia a che fare con una matrice densa non strutturata 10000x10000 con tutti gli elementi diversi da zero (alto livello di densità), quale sarebbe la mia scommessa migliore? Voglio isolare quell'algoritmo che funziona per matrici dense. È LU, QR o eliminazione gaussiana?
Inchiesta il

1
Sembra un passaggio 4 in cui viene invocata l'eliminazione gaussiana che corrisponde al caso più generale in cui nessuna struttura di A può essere sfruttata per migliorare le prestazioni. Quindi, sostanzialmente si tratta di una fattorizzazione LU e successiva in avanti seguita da una fase di sostituzione all'indietro.
Allan P. Engsig-Karup,

Grazie! Penso che ciò mi dia una direzione per pensare. Attualmente, l'eliminazione gaussiana è la migliore che abbiamo per risolvere tali problemi non strutturati, è corretto?
Inchiesta il

37

Se vuoi vedere cosa a\bfa per la tua matrice particolare, puoi impostare spparms('spumoni',1)e capire esattamente quale algoritmo ti ha colpito. Per esempio:

spparms('spumoni',1);
A = delsq(numgrid('B',256));
b = rand(size(A,2),1);
mldivide(A,b);  % another way to write A\b

uscirà

sp\: bandwidth = 254+1+254.
sp\: is A diagonal? no.
sp\: is band density (0.01) > bandden (0.50) to try banded solver? no.
sp\: is A triangular? no.
sp\: is A morally triangular? no.
sp\: is A a candidate for Cholesky (symmetric, real positive diagonal)? yes.
sp\: is CHOLMOD's symbolic Cholesky factorization (with automatic reordering) successful? yes.
sp\: is CHOLMOD's numeric Cholesky factorization successful? yes.
sp\: is CHOLMOD's triangular solve successful? yes.

quindi posso vedere che "\" ha finito per usare "CHOLMOD" in questo caso.


3
+1 per le nuove impostazioni MATLAB di cui non avevo mai sentito parlare. Ben fatto, signore.
Geoff Oxberry,

2
Ehi grazie! È dentro help mldivide.
dranxo,

16

Per matrici sparse, Matlab usa UMFPACK per l' \operazione " ", che, nel tuo esempio, fondamentalmente scorre i valori di a, li inverte e li moltiplica con i valori di b. Per questo esempio, tuttavia, dovresti usare b./diag(a), che è molto più veloce.

Per i sistemi densi, l'operatore barra rovesciata è un po 'più complicato. Una breve descrizione di ciò che viene fatto quando viene fornito qui . Secondo tale descrizione, nel tuo esempio, Matlab risolverebbe a\busando la sostituzione a ritroso. Per le matrici quadrate generali, viene utilizzata una decomposizione LU.


Regd. Scarsità, l'inv di una matrice diag sarebbe semplicemente il reciproco degli elementi diagonali, quindi b./diag(a) avrebbe funzionato, ma a \ b funziona perfettamente anche per matrici sparse generali. Perché non è linsolve o LULU (la mia versione ottimizzata di LU) non più veloce di a \ b per matrici dense in quel caso.
Inchiesta il

@Nunoxic Il tuo LULU fa qualcosa per rilevare la diagonalità o la triangolarità della matrice densa? In caso contrario, ci vorrà altrettanto tempo con ogni matrice, indipendentemente dal suo contenuto o struttura.
Pedro

Un po '. Ma, con i flag OPT linsolve, ho definito tutto ciò che c'è da definire sulla struttura. Tuttavia, a \ b è più veloce.
Inchiesta il

@Nunoxic, ogni volta che si chiama una funzione utente, si generano spese generali. Matlab fa tutto per il backslash internamente, ad es. La decomposizione e la successiva applicazione del lato destro, con un minimo sovraccarico, e sarà quindi più veloce. Inoltre, nei test, è necessario utilizzare più di una chiamata per ottenere tempi affidabili, ad es tic; for k=1:100, a\b; end; toc.
Pedro

5

Come regola empirica, se hai una matrice sparsa di ragionevole complessità (cioè, non deve essere lo stencil a 5 punti ma può in effetti essere una discretizzazione delle equazioni di Stokes per le quali il numero di nonzeros per riga è molto più grande di 5), quindi un risolutore diretto sparso come UMFPACK batte tipicamente un risolutore iterativo di Krylov se il problema non è più grande di circa 100.000 incognite.

In altre parole, per la maggior parte delle matrici sparse risultanti da discretizzazioni 2D, l'alternativa più rapida è un risolutore diretto. Solo per problemi 3D in cui si superano rapidamente le 100.000 incognite, diventa indispensabile utilizzare un risolutore iterativo.


3
Non mi è chiaro come questo risponda alla domanda, ma ho anche messo in discussione la premessa. È vero che i solutori diretti tendono a funzionare bene per problemi 2D di dimensioni modeste, ma i solutori diretti tendono a soffrire in 3D ben prima di 100.000 incognite (i separatori di vertici sono molto più grandi rispetto al 2D). Inoltre, sostengo che nella maggior parte dei casi (ad es. Operatori ellittici), i solutori iterativi possono essere resi più veloci dei solutori diretti anche per problemi 2D di dimensioni moderate, ma potrebbe richiedere uno sforzo significativo per farlo (ad es. Usando gli ingredienti giusti per far funzionare il multigrid) .
Jed Brown,

1
Se i tuoi problemi sono ragionevolmente piccoli e non vuoi pensare alla progettazione di solutori impliciti, o se i tuoi problemi sono molto difficili (come Maxwell ad alta frequenza) e non vuoi dedicare la tua carriera alla progettazione di buoni solutori, allora io concordo sul fatto che i risolutori diretti sparsi sono un'ottima scelta.
Jed Brown,

In realtà il mio problema è progettare un buon risolutore denso. Non ho un'applicazione particolare in quanto tale (quindi nessuna struttura). Volevo modificare alcuni dei miei codici e renderli competitivi con ciò che viene attualmente utilizzato. Ero solo curioso di a \ b e di come batte sempre la merda dal mio codice.
Inchiesta il

@JedBrown: Sì, forse con un notevole sforzo si può ottenere che i solutori iterativi battano un risolutore diretto anche per piccoli problemi 2d. Ma perché farlo? Per problemi con <100k incognite, i solutori diretti sparsi in 2d sono abbastanza veloci. Quello che volevo dire è: per problemi così piccoli, non perdere tempo a armeggiare e capire la migliore combinazione di parametri: prendi solo la blackbox.
Wolfgang Bangerth,

Esiste già un ordine di grandezza di differenza di runtime tra un Chigrky sparse e un multigrid geometrico (basato su matrice) per problemi 2D "facili" con 100k dofs che utilizzano uno stencil a 5 punti (~ 0,5 secondi rispetto a ~ 0,05 secondi). Se lo stencil utilizza secondi vicini (ad es. Discretizzazione del quarto ordine, Newton per alcune scelte di reologia non lineare, stabilizzazione, ecc.), Le dimensioni dei separatori di vertici raddoppiano all'incirca, quindi il costo della risoluzione diretta aumenta di circa 8 volte (il costo è maggiore dipendente dal problema per MG). Con molti passaggi temporali o loop di ottimizzazione / UQ, queste differenze sono significative.
Jed Brown,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.