Qual è il modo migliore per determinare il numero di non zeri nella moltiplicazione di matrici sparse?


17

Mi chiedevo se esiste un metodo rapido ed efficiente per trovare in anticipo il numero di non zeri per l'operazione di moltiplicazione delle matrici sparse supponendo che entrambe le matrici siano in formato CSC o CSR.

So che ce n'è uno nel pacchetto smmp ma ho bisogno di qualcosa che sia già implementato in C o C ++.

Qualsiasi aiuto sarà apprezzato. Grazie in anticipo.


le tue matrici hanno qualche simmetria o una struttura rispetto alla posizione delle loro voci diverse da zero?
Godric Seer,

@GodricSeer ... no Sto solo parlando di matrici sparse generali. Matlab ha nnz (A) dove A è un metodo a matrice sparsa per scoprire il numero di non zeri. Mi chiedevo se esistesse un tale metodo.
Recker,

Personalmente non riesco a pensare ad alcun modo per calcolare quel numero che sarebbe di ordine inferiore rispetto al semplice fare la moltiplicazione della matrice senza sfruttare una simmetria o una struttura. Suppongo che lo desideri per l'allocazione della memoria prima di eseguire la moltiplicazione?
Godric Seer,

Inoltre, ho trovato questo documento che descrive come stimare il numero su un prodotto a matrice booleana (che è identico al conteggio degli elementi in qualsiasi prodotto a matrice).
Godric Seer,

@ GodricSeer..Sì hai ragione, ho bisogno del numero esatto solo per l'allocazione della memoria della matrice risultante.Grazie per il collegamento alla carta, però, ciò potrebbe farmi iniziare in qualche direzione per un po '.
Recker,

Risposte:


14

Puoi semplicemente simulare il prodotto matrice-matrice formando il prodotto dei due modelli di sparsità - ovvero, consideri il modello di sparsità (che è memorizzato in matrici separate in formato CSR) come una matrice che contiene uno zero o uno in ogni voce. L'esecuzione di questo prodotto simulato richiede solo di formare il eoperazione su questi zeri e uno ed è quindi molto più veloce del prodotto matrice-matrice reale - in effetti, tutto ciò che devi fare è passare attraverso le righe e le colonne delle due matrici e verificare che ci sia almeno una voce in un riga e colonna con cui moltiplichi dove entrambe le matrici sono diverse da zero. Si tratta di un'operazione a basso costo, in ogni caso molto più economica rispetto al fatto di dover effettivamente fare la moltiplicazione in virgola mobile nel prodotto reale che non solo richiede di eseguire l'aritmetica in virgola mobile (costosa) ma anche di leggere i numeri in virgola mobile effettivi dalla memoria ( ancora più costoso, ma non è necessario quando si moltiplica il modello di sparsità perché i valori diversi da zero della matrice sono memorizzati separatamente in CSR).


6
Questo si chiama moltiplicazione simbolica. Non è necessariamente meno costoso della moltiplicazione numerica, soprattutto in parallelo, ma deve essere eseguito una sola volta per modello di sparsità. Molti algoritmi eseguiranno l'operazione più volte con valori numerici diversi ma con lo stesso modello di sparsità, nel qual caso la moltiplicazione simbolica può essere riutilizzata.
Jed Brown,

È una buona idea, ma dati i milioni di transistor che eseguono il float * in parallelo, stiamo solo parlando di un risparmio di velocità del 50% o giù di lì.
Evgeni Sergeev,

1
@EvgeniSergeev: il punto non sono i risparmi nei calcoli, ma i risparmi nel trasferimento della memoria. Dato che oggi impieghi l'80% o più del tempo per il trasferimento di memoria per una moltiplicazione di matrici sparse, probabilmente guadagni in modo significativo se non devi leggere / scrivere dati in virgola mobile da / in memoria.
Wolfgang Bangerth,

CmKO(mK)

O(mK)pm=KO(mplogp)O(m2)

13

In realtà ho scritto il codice originale in Matlab per A * B, sia A che B sparsi. La pre-allocazione dello spazio per il risultato è stata davvero la parte interessante. Abbiamo osservato ciò che Godric sottolinea: che conoscere il numero di nonzeros in AB è costoso come calcolare AB.

Abbiamo realizzato l'implementazione iniziale di Matlab sparsa intorno al 1990, prima del documento di Edith Cohen che forniva il primo modo pratico e veloce per stimare accuratamente le dimensioni di AB. Abbiamo messo insieme uno stimatore di dimensioni inferiori e se abbiamo esaurito lo spazio a metà del calcolo, abbiamo raddoppiato l'allocazione e copiato il risultato parzialmente calcolato.

Non so cosa ci sia in Matlab ora.

Un'altra possibilità sarebbe quella di calcolare AB una colonna alla volta. Ogni colonna può essere memorizzata temporaneamente in un accumulatore sparse (vedere la carta Matlab sparsa per una spiegazione di queste) e lo spazio allocato per contenere esattamente le dimensioni conosciute della colonna dei risultati. Il risultato sarebbe in forma di colonna sparsa compressa sparsa - ogni colonna in CSC ma nessuna contiguità intercolonna - usando 2 vettori di numcol di lunghezza (inizio col, lunghezza col), anziché uno, come metadati. È un modulo di archiviazione che può valere la pena dare un'occhiata; ha un altro punto di forza: puoi far crescere una colonna senza riallocare l'intera matrice.


Bene per la mia implementazione della GPU, alla fine ho trovato prima la struttura diversa da zero e poi ho trovato la matrice effettiva. Le prestazioni sono state orribili come previsto. Penso che usano il metodo descritto in questo libro per moltiplicare efficacemente le due matrici sparse su MATLAB.
Recker,

2
Davvero fantastico, grazie per la prospettiva storica, e benvenuto su Scicomp :)
Aron Ahmadia,

4

Questo documento descrive un algoritmo per approssimare la dimensione di un risultante dal prodotto matrice di due matrici sparse.

Il problema con la ricerca di un numero esatto di voci diverse da zero in una moltiplicazione di matrice sparsa è che ciascun elemento nel risultante dipende dall'interazione di due vettori, entrambi i quali probabilmente contengono almeno alcuni elementi diversi da zero. Pertanto, per calcolare il numero è necessario valutare le operazioni logiche su una coppia di vettori per ogni elemento nel risultante. Il problema è che richiede un numero di operazioni simile al numero di operazioni necessarie per calcolare il prodotto matrice stesso. Nei miei commenti ho menzionato la possibilità di sfruttare alcune strutture negli elementi diversi da zero delle matrici originali, tuttavia quegli stessi exploit potrebbero essere utilizzati per ridurre il lavoro svolto anche nella moltiplicazione delle matrici.

Probabilmente sarebbe meglio usare la carta di cui sopra per sopravvalutare i requisiti di memoria, eseguire la moltiplicazione e quindi troncare la memoria allocata o spostare la matrice risultante in un array di dimensioni più appropriate. Inoltre, i prodotti a matrice sparsa non sono un evento raro, e quasi garantirei che questo problema sia stato risolto in precedenza. Un po 'di ricerca in alcune librerie open source di matrice sparsa dovrebbe portarti agli algoritmi che usano per preallocare la memoria.


0

Per CSR o CSC, sei sicuro che l'array di elementi della matrice non abbia già zero? In tal caso è semplice capire quanti elementi diversi da zero ci sono, usando qualcosa di simile a:

int nnz = sizeof(My_Array)/sizeof(long int);

Tuttavia, se questo non è il caso (sembra un po 'troppo facile) ciò che potresti provare è una riduzione . Se la tua matrice di elementi matrice è molto grande, questo potrebbe essere il modo più efficiente per calcolare il numero di elementi diversi da zero. Molte librerie C / C ++ parallele come Thrust (una libreria CUDA) o OpenCL (che non hai bisogno di una GPU da usare) hanno il supporto per riduzioni condizionali - per ogni elemento, aggiungi il risultato di Condition(Element). Se imposti la condizione Element != 0su, sommerai il numero di elementi diversi da zero. È inoltre possibile rimuovere gli elementi a valore zero dall'array di elementi, dall'array di indici di riga / colonna e regolare i puntatori di colonna / riga.


grazie per la tua risposta ... ma mi riferivo ai non zeri in A * B dove A e B sono matrici sparse. Ho bisogno in anticipo del numero di non zeri in modo da poter allocare l'esatta quantità di memoria per memorizzare la matrice risultante.
Recker,

0

Il modo più semplice per implementare la CSR è provare

std::vector< std::map<int, complex<float>> > 

per rappresentare la tua matrice. In tal caso, non ti preoccuperai davvero del numero di elementi diversi da zero, tutto è accessibile tramite

std::map< int, complex<float> >::iterator

su ogni riga. I migliori ..


2
STL, perché quando pensavi che le tue routine di matrice sparsa non potessero essere rallentate.
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.