2009-08-07 33 views
8

Ich benutze numerische Bibliothek Bindungen für Boost UBlas, um ein einfaches lineares System zu lösen. Folgendes funktioniert gut, außer es ist beschränkt auf die Handhabung von Matrizen A (m x m) für relativ kleine 'm'.C++ Speicher effiziente Lösung für Ax = b Linear Algebra System

In der Praxis habe ich eine viel größere Matrix mit der Dimension m = 10^6 (bis zu 10^7).
Gibt es einen vorhandenen C++ - Ansatz zum Lösen von Ax = b, der Speicher effizient verwendet.

#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

die offensichtliche Aufzeigen, eine Matrix, die eine Größe Array 4x10^bis 4x10 12^14 Bytes ist, oder 4 bis 400 Terabytes für eine einzelne Matrix allein. (es sei denn, wie unten erwähnt, ist es spärlich) – cyberconte

Antwort

13

Kurze Antwort: Verwenden Sie keine Boost LAPACK Bindungen, diese wurden für dichte Matrizen, nicht dünn besetzten Matrizen, verwenden Sie stattdessen UMFPACK.

Lange Antwort: UMFPACK ist eine der besten Bibliotheken zum Lösen von Ax = b, wenn A groß und spärlich ist.

ist Below Beispielcode (basierend auf umfpack_simple.c), die eine einfache und Ab erzeugt und löst 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); 
} 

Die Funktion generate_sparse_matrix_problem schafft die Matrix A und die rechten Seite b. Die Matrix wird zuerst in Triplettform konstruiert. Die Vektoren Ti, Tj und Tx beschreiben vollständig A. Die Triplet-Form ist einfach zu erstellen, aber effiziente Sparse-Matrix-Methoden erfordern das komprimierte Sparse-Spaltenformat. Die Konvertierung erfolgt mit umfpack_di_triplet_to_col.

Eine symbolische Faktorisierung wird mit umfpack_di_symbolic durchgeführt. Eine spärliche LU-Zerlegung von A wird mit umfpack_di_numeric durchgeführt. Die unteren und oberen Dreieckslösungen werden mit umfpack_di_solve durchgeführt.

Mit n als 500.000, auf meinem Computer dauert das gesamte Programm etwa eine Sekunde zu laufen. Valgrind berichtet, dass 369.239.649 Bytes (knapp über 352 MB) zugewiesen wurden.

Beachten Sie diese page diskutiert Boost-Unterstützung für dünn besetzte Matrizen in Triplet (Koordinaten) und komprimiertes Format. Wenn Sie möchten, können Sie Routinen schreiben, um diese Boost-Objekte in die einfachen Arrays UMFPACK zu konvertieren, die als Eingabe benötigt werden.

+0

+1 für Schulstolz :) – ccook

6

Angenommen, Ihre große Matrizen sind spärlich, die ich hoffe, dass sie in dieser Größe sind, haben einen Blick auf das PARDISO Projekt, das eine spärliche lineare Solver ist, ist es das, was Sie brauchen, wenn Sie Matrizen behandeln möchten so groß wie du gesagt hast. Ermöglicht eine effiziente Speicherung von nur Werten ungleich Null und ist viel schneller als das Lösen des gleichen Systems von dichten Matrizen.

+2

Ganz zu schweigen von der O (m^3) -Zeitkomplexität der naiven Lösung! Sogar der Kluge, von dem Knuth spricht, ist O (m^2.7ish) ... Wenn diese Matrizen nicht spärlich sind, brauchen Sie einen Cluster und einen erstklassigen numerischen Analysanden ... – dmckee

+1

+1 für spärliche Matrix-Idee. Ich fand Numerus-Bibliotheken und Vergleiche in PARDISO-Papier über den Vergleich varous Sparse-Matrix-Bibliotheken ftp://ftp.numerical.rl.ac.uk/pub/reports/ghsRAL200505.pdf Dies kann verwendet werden, um andere erkannte dünn besetzten Matrix-Bibliotheken zu finden. –

3

Nicht sicher C++ Implementierungen, aber es gibt mehrere Dinge, die Sie tun können, wenn der Speicher ist ein Problem von der Art der Matrix je mit Ihnen zu tun hat:

  1. Wenn Ihre Matrix ist spärlich oder gebändert, Sie kann einen Sparse- oder Bandbreitenlöser verwenden. Diese speichern keine Elemente außerhalb des Bandes.
  2. Sie können einen Wavefront-Solver verwenden, der die Matrix auf der Festplatte speichert und nur die Matrixwellenfront für die Dekomposition einbringt.
  3. Sie können vermeiden, die Matrix vollständig zu lösen und iterative Methoden zu verwenden.
  4. Sie können Monte-Carlo-Methoden der Lösung versuchen.
+0

@ duffymo: danke. Ich habe die Implementierung des iterativen Ansatzes in C++ betrachtet, aber sie müssen immer noch in einer Matrix gespeichert werden. http://freenet-homepage.de/guwi17/ublas/examples/ Wenn ich falsch liege, Kennen Sie irgendeine mem effiziente Implementierung in C++ für iterative? – neversaint

+0

Richtig, Dummkopf. Ich hätte mich daran erinnern sollen. Ich würde parallele Algorithmen untersuchen, da das Problem, das Workout auf N Prozessoren zu verteilen und es wieder zusammen zu stricken, um das Ergebnis zu erhalten, für das Problem relevant ist, es vorübergehend auf die Festplatte zu verschieben. – duffymo

6

Ich nehme an, dass Ihre Matrix dicht ist. Wenn es spärlich ist, können Sie zahlreiche spezialisierte Algorithmen finden, wie bereits von DeusAduro und duffymo erwähnt.

Wenn Sie keinen (ausreichend großen) Cluster zur Verfügung haben, sollten Sie sich die Algorithmen ansehen, die außerhalb des Kerns liegen. ScaLAPACK hat einige Out-of-Core-Löser als Teil seiner prototype package, siehe die Dokumentation here und Google für weitere Details. Wenn Sie im Internet nach "Out-of-Core LU/(Matrix-) Solvern/Paketen" suchen, erhalten Sie Links zu einer Fülle weiterer Algorithmen und Tools. Ich bin kein Experte für diese.

Für dieses Problem würden die meisten Menschen jedoch einen Cluster verwenden. Das Paket, das Sie auf fast jedem Cluster finden, ist wieder ScaLAPACK. Darüber hinaus gibt es in der Regel zahlreiche weitere Pakete auf dem typischen Cluster, so dass Sie auswählen können, was zu Ihrem Problem passt (Beispiele here und here).

Bevor Sie mit dem Codieren beginnen, möchten Sie wahrscheinlich schnell überprüfen, wie lange es dauern wird, um Ihr Problem zu lösen. Ein typischer Löser benötigt etwa 0 (3 * N^3) Flops (N ist die Dimension der Matrix). Wenn N = 100000 ist, betrachten Sie daher 3000000 Gflops. Unter der Annahme, dass Ihr In-Memory-Solver 10 Gflops/s pro Kern leistet, betrachten Sie 3 1/2 Tage auf einem einzelnen Kern. Wenn die Algorithmen gut skalieren, sollte die Erhöhung der Anzahl der Kerne die Zeit in der Nähe von linear reduzieren. Hinzu kommt die I/O.

+0

Vorbehalt: Das obige O (3 * N^3) setzt voraus, dass Sie komplexe Zahlen verwenden. Bei reellen Zahlen dividiere alles durch 6, d. H. Irgendwo um O (0.5 * N^3). – stephan

3

Werfen Sie einen Blick auf die list of freely available software for the solution of linear algebra problems, zusammengestellt von Jack Dongarra und Hatem Ltaief.

Ich denke, dass Sie für die Problemgröße, die Sie betrachten, wahrscheinlich einen iterativen Algorithmus benötigen. Wenn Sie die Matrix A nicht in einem Sparse-Format speichern möchten, können Sie eine matrixfreie Implementierung verwenden.Iterative Algorithmen müssen typischerweise nicht auf einzelne Einträge der Matrix A zugreifen, sie müssen nur Matrix-Vektor-Produkte Av (und manchmal A^T v, das Produkt der transponierten Matrix mit dem Vektor) berechnen. Wenn die Bibliothek also gut entworfen ist, sollte es ausreichen, wenn Sie eine Klasse übergeben, die Matrix-Vektor-Produkte zu beherrschen weiß.