2009-08-07 16 views
8

Utilizzo legami di libreria numerica per Boost UBlas per risolvere un semplice sistema lineare. Quanto segue funziona bene, tranne che è limitato alla gestione delle matrici A (m x m) per relativamente "m" piccola.Soluzione di memoria C++ efficiente per Ax = b Sistema di algebra lineare

In pratica ho una matrice molto più grande con dimensione m = 10^6 (fino a 10^7).
Esiste un approccio C++ esistente per risolvere Ax = b che utilizza la memoria in modo efficiente.

#include<boost/numeric/ublas/matrix.hpp> 
#include<boost/numeric/ublas/io.hpp> 
#include<boost/numeric/bindings/traits/ublas_matrix.hpp> 
#include<boost/numeric/bindings/lapack/gesv.hpp> 
#include <boost/numeric/bindings/traits/ublas_vector2.hpp> 

// compileable with this command 


//g++ -I/home/foolb/.boost/include/boost-1_38 -I/home/foolb/.boostnumbind/include/boost-numeric-bindings solve_Axb_byhand.cc -o solve_Axb_byhand -llapack 


namespace ublas = boost::numeric::ublas; 
namespace lapack= boost::numeric::bindings::lapack; 


int main() 
{ 
    ublas::matrix<float,ublas::column_major> A(3,3); 
    ublas::vector<float> b(3); 


    for(unsigned i=0;i < A.size1();i++) 
     for(unsigned j =0;j < A.size2();j++) 
     { 
      std::cout << "enter element "<<i << j << std::endl; 
      std::cin >> A(i,j); 
     } 

    std::cout << A << std::endl; 

    b(0) = 21; b(1) = 1; b(2) = 17; 

    lapack::gesv(A,b); 

    std::cout << b << std::endl; 


    return 0; 
} 
+2

Indicando l'ovvio, una matrice che è matrice di dimensione 4x10^12 a 4x10^14 byte o 4 a 400 terabyte per solo una singola matrice. (a meno che, come indicato sotto, sia scarso) – cyberconte

risposta

13

Risposta breve: Non utilizzare i binding di Boost LAPACK, questi sono stati progettati per matrici dense, matrici non sparse, utilizzare invece UMFPACK.

Risposta lunga: UMFPACK è una delle migliori librerie per risolvere Ax = b quando A è grande e sparse.

seguito è il codice di esempio (basato su umfpack_simple.c) che genera un semplice A e b e risolve Ax = b.

#include <stdlib.h> 
#include <stdio.h> 
#include "umfpack.h" 

int *Ap; 
int *Ai; 
double *Ax; 
double *b; 
double *x; 

/* Generates a sparse matrix problem: 
    A is n x n tridiagonal matrix 
    A(i,i-1) = -1; 
    A(i,i) = 3; 
    A(i,i+1) = -1; 
*/ 
void generate_sparse_matrix_problem(int n){ 
    int i; /* row index */ 
    int nz; /* nonzero index */ 
    int nnz = 2 + 3*(n-2) + 2; /* number of nonzeros*/ 
    int *Ti; /* row indices */ 
    int *Tj; /* col indices */ 
    double *Tx; /* values */ 

    /* Allocate memory for triplet form */ 
    Ti = malloc(sizeof(int)*nnz); 
    Tj = malloc(sizeof(int)*nnz); 
    Tx = malloc(sizeof(double)*nnz); 

    /* Allocate memory for compressed sparse column form */ 
    Ap = malloc(sizeof(int)*(n+1)); 
    Ai = malloc(sizeof(int)*nnz); 
    Ax = malloc(sizeof(double)*nnz); 

    /* Allocate memory for rhs and solution vector */ 
    x = malloc(sizeof(double)*n); 
    b = malloc(sizeof(double)*n); 

    /* Construct the matrix A*/ 
    nz = 0; 
    for (i = 0; i < n; i++){ 
    if (i > 0){ 
     Ti[nz] = i; 
     Tj[nz] = i-1; 
     Tx[nz] = -1; 
     nz++; 
    } 

    Ti[nz] = i; 
    Tj[nz] = i; 
    Tx[nz] = 3; 
    nz++; 

    if (i < n-1){ 
     Ti[nz] = i; 
     Tj[nz] = i+1; 
     Tx[nz] = -1; 
     nz++; 
    } 
    b[i] = 0; 
    } 
    b[0] = 21; b[1] = 1; b[2] = 17; 
    /* Convert Triplet to Compressed Sparse Column format */ 
    (void) umfpack_di_triplet_to_col(n,n,nnz,Ti,Tj,Tx,Ap,Ai,Ax,NULL); 

    /* free triplet format */ 
    free(Ti); free(Tj); free(Tx); 
} 


int main (void) 
{ 
    double *null = (double *) NULL ; 
    int i, n; 
    void *Symbolic, *Numeric ; 
    n = 500000; 
    generate_sparse_matrix_problem(n); 
    (void) umfpack_di_symbolic (n, n, Ap, Ai, Ax, &Symbolic, null, null); 
    (void) umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, null, null); 
    umfpack_di_free_symbolic (&Symbolic); 
    (void) umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, x, b, Numeric, null, null); 
    umfpack_di_free_numeric (&Numeric); 
    for (i = 0 ; i < 10 ; i++) printf ("x [%d] = %g\n", i, x [i]); 
    free(b); free(x); free(Ax); free(Ai); free(Ap); 
    return (0); 
} 

La funzione generate_sparse_matrix_problem crea la matrice A e il lato destro b. La matrice viene prima costruita in forma di terzine. I vettori Ti, Tj e Tx descrivono completamente A. La forma di triplet è facile da creare ma i metodi di matrice sparse efficienti richiedono il formato di colonna sparsa compressa. La conversione viene eseguita con umfpack_di_triplet_to_col.

Una fattorizzazione simbolica viene eseguita con umfpack_di_symbolic. Una scarsa decomposizione LU di A viene eseguita con umfpack_di_numeric. Le soluzioni triangolari inferiore e superiore vengono eseguite con umfpack_di_solve.

Con n su 500.000, sulla mia macchina, l'intero programma impiega circa un secondo per essere eseguito. Valgrind segnala che sono stati allocati 369.239.649 byte (poco più di 352 MB).

Nota questo page descrive il supporto di Boost per le matrici sparse in Triplet (Coordinate) e il formato compresso. Se lo si desidera, è possibile scrivere routine per convertire questi oggetti boost nei matrici semplici UMFPACK come input.

+0

+1 per orgoglio scolastico :) – ccook

6

Assumendo che il enormi matrici sono scarsi, che spero siano in quel formato, dare un'occhiata al progetto PARDISO che è un risolutore lineari sparsi, questo è quello che vi serve se si desidera gestire matrici grande come hai detto tu. Permette l'archiviazione efficiente di soli valori diversi da zero ed è molto più veloce rispetto alla risoluzione dello stesso sistema di matrici dense.

+2

Per non parlare della complessità temporale O (m^3) della soluzione ingenua! Persino l'intelligente di cui Knuth parla è O (m^2.7ish) ... Se queste matrici non sono rare, è necessario un cluster e un analista numerico di prima classe ... – dmckee

+1

+1 per l'idea di matrice sparsa. Ho trovato librerie numeriche e altri confronti nel documento PARDISO sul confronto di librerie a matrice sparse varous ftp://ftp.numerical.rl.ac.uk/pub/reports/ghsRAL200505.pdf Questo può essere usato per trovare altre librerie di matrice sparse riconosciute. –

3
Non

sicuro di C++ implementazioni, ma ci sono diverse cose che puoi fare se la memoria è un problema a seconda del tipo di matrice hai a che fare con:

  1. Se la matrice è sparsa o fasciato, è può utilizzare un risolutore sparse o larghezza di banda. Questi non memorizzano elementi zero al di fuori della banda.
  2. È possibile utilizzare un risolutore wavefront, che memorizza la matrice su disco e introduce solo il fronte d'onda della matrice per la scomposizione.
  3. È possibile evitare di risolvere la matrice del tutto e utilizzare metodi iterativi.
  4. Puoi provare i metodi di soluzione Monte Carlo.
+0

@duffymo: grazie. Ho esaminato l'implementazione di un approccio iterativo in C++, ma hanno ancora bisogno di memorizzarlo in matrice. http://freenet-homepage.de/guwi17/ublas/examples/ Se ho torto, conosci qualche implementazione efficiente in C++ per iterativa? – neversaint

+0

Corretto, stupido. Avrei dovuto ricordarmelo. Indagherei su algoritmi paralleli, perché il problema di partizionare il lavoro verso N processori e di ricomporlo per ottenere il risultato è pertinente al problema di spostarlo temporaneamente su disco. – duffymo

6

Suppongo che la vostra matrice sia densa. Se è scarso, puoi trovare numerosi algoritmi specializzati come già menzionato da DeusAduro e da duffymo.

Se non si dispone di un cluster (abbastanza grande), è necessario esaminare gli algoritmi fuori dal core. ScaLAPACK ha alcuni risolutori out-of-core come parte del suo prototype package, vedere la documentazione here e Google per ulteriori dettagli. La ricerca sul web di "solutori/pacchetti LU/(matrice) fuori dal core" vi darà collegamenti a una vasta gamma di ulteriori algoritmi e strumenti. Non sono un esperto su quelli.

Per questo problema, la maggior parte delle persone usa comunque un cluster. Il pacchetto che troverai su quasi tutti i cluster è ScaLAPACK, di nuovo. Inoltre, di solito ci sono numerosi altri pacchetti nel cluster tipico, quindi puoi scegliere quello che fa per te (esempi: here e here).

Prima di iniziare la codifica, probabilmente si desidera verificare rapidamente il tempo necessario per risolvere il problema. Un solver tipico richiede circa 0 (3 * N^3) flop (N è la dimensione della matrice). Se N = 100000, stai quindi guardando a 3000000 Gflops. Supponendo che il tuo risolutore in memoria compia 10 Gflops/s per core, stai considerando 3 1/2 giorni su un singolo core. Poiché gli algoritmi si adattano bene, l'aumento del numero di core dovrebbe ridurre il tempo vicino a quello lineare. Oltre a ciò arriva l'I/O.

+0

Avvertenza: l'O precedente (3 * N^3) presuppone l'utilizzo di numeri complessi. Per i numeri reali, dividere tutto per 6, cioè da qualche parte intorno a O (0.5 * N^3). – stephan

3

Dai uno sguardo allo list of freely available software for the solution of linear algebra problems, compilato da Jack Dongarra e Hatem Ltaief.

Penso che per la dimensione del problema che stai osservando, probabilmente hai bisogno di un algoritmo iterativo. Se non si desidera memorizzare la matrice A in un formato sparse, è possibile utilizzare un'implementazione senza matrice.Gli algoritmi iterativi in ​​genere non hanno bisogno di accedere alle singole voci della matrice A, hanno solo bisogno di calcolare i prodotti a matrice di vettore Av (e talvolta A^T v, il prodotto della matrice trasposta con il vettore). Quindi, se la libreria è ben progettata, dovrebbe essere sufficiente se si passa una classe che sa come realizzare i prodotti a matrice vettoriale.

Problemi correlati