9

Boost UBlas の Numeric Library Bindings を使用して、単純な線形システムを解決しています。以下は、比較的小さい 'm' の行列 A(mxm) の処理に限定されていることを除いて、正常に機能します。

実際には、次元 m= 10^6 (最大 10^7) のはるかに大きな行列があります。
メモリを効率的に使用する Ax=b を解決するための既存の C++ アプローチはありますか。

#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;
}
4

6 に答える 6

14

短い答え: Boost のバインディングを使用しないでくださいLAPACK。これらは、疎行列ではなく、密行列用に設計されていますUMFPACK。代わりに使用してください。

長い答え: UMFPACKA が大きくてまばらな場合に Ax=b を解くのに最適なライブラリの 1 つです。

以下は、単純なand と solvesumfpack_simple.cを生成するサンプル コード ( に基づく) です。AbAx = 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);
}

この関数generate_sparse_matrix_problemは、行列Aと右辺を作成しますb。マトリックスは最初にトリプレット形式で構築されます。ベクトル Ti、Tj、および Tx は A を完全に記述します。トリプレット形式は簡単に作成できますが、効率的なスパース マトリックス メソッドには Compressed Sparse Column 形式が必要です。で変換しumfpack_di_triplet_to_colます。

でシンボリック因数分解が実行されumfpack_di_symbolicます。のスパース LU 分解はAで実行されumfpack_di_numericます。下三角と上三角の解は で実行されumfpack_di_solveます。

私のマシンでは、500,000でn、プログラム全体の実行に約 1 秒かかります。Valgrind は、369,239,649 バイト (352 MB 強) が割り当てられたと報告しています。

このページでは、トリプレット (座標) および圧縮形式のスパース行列に対する Boost のサポートについて説明しています。必要に応じて、これらのブースト オブジェクトをUMFPACK入力として必要な単純な配列に変換するルーチンを作成できます。

于 2009-08-14T19:30:28.837 に答える
6

巨大な行列がスパースであると仮定すると(そのサイズであることを願っています)、スパース線形ソルバーであるPARDISOプロジェクトを見てください。これは、あなたが言ったのと同じ大きさの行列を処理する場合に必要なものです。ゼロ以外の値のみを効率的に保存でき、密度行列の同じシステムを解くよりもはるかに高速です。

于 2009-08-07T00:09:17.333 に答える
6

あなたのマトリックスは密集していると思います。まばらな場合は、DeusAduroduffymoによって既に言及されているように、多数の特殊なアルゴリズムを見つけることができます。

自由に使える (十分な大きさの) クラスターがない場合は、アウトオブコア アルゴリズムを検討する必要があります。ScaLAPACKには、そのプロトタイプ パッケージの一部としてコア外のソルバーがいくつかあります。詳細については、こちらのドキュメントとGoogleを参照してください。Web で「out-of-core LU / (matrix) solvers / packages」を検索すると、さらに豊富なアルゴリズムとツールへのリンクが表示されます。私はそれらの専門家ではありません。

ただし、この問題については、ほとんどの人がクラスターを使用します。ほぼすべてのクラスターで見つかるパッケージは、やはり ScaLAPACK です。さらに、一般的なクラスターには通常、他にも多数のパッケージがあるため、問題に適したものを選択できます (例はこちらこちら)。

コーディングを開始する前に、問題を解決するのにかかる時間を簡単に確認したいと思うでしょう。典型的なソルバーは約 O(3*N^3) フロップ (N は行列の次元) かかります。N = 100000 の場合、3000000 Gflops を見ていることになります。インメモリ ソルバーがコアあたり 10 Gflops/s を実行すると仮定すると、単一のコアで 3 1/2 日を見ていることになります。アルゴリズムが適切にスケーリングされるため、コアの数を増やすと、時間はほぼ線形に短縮されます。その上に I/O があります。

于 2009-08-11T19:07:42.473 に答える
3

C ++の実装についてはよくわかりませんが、処理しているマトリックスのタイプに応じて、メモリが問題になる場合に実行できることがいくつかあります。

  1. 行列がスパースまたはバンドの場合は、スパースソルバーまたは帯域幅ソルバーを使用できます。これらは、帯域外にゼロ要素を格納しません。
  2. 波面ソルバーを使用できます。このソルバーは、マトリックスをディスクに保存し、分解のためにマトリックスの波面のみを取り込みます。
  3. 行列を完全に解くことを避け、反復法を使用することができます。
  4. モンテカルロ法を試すことができます。
于 2009-08-07T00:10:54.023 に答える
3

Jack Dongarra と Hatem Ltaief によって編集された、線形代数の問題を解くための無料で入手できるソフトウェアのリストをご覧ください。

あなたが見ている問題のサイズについては、おそらく反復アルゴリズムが必要だと思います。行列 A をスパース形式で保存したくない場合は、行列を使用しない実装を使用できます。反復アルゴリズムは通常、行列 A の個々のエントリにアクセスする必要はなく、行列とベクトルの積 Av (場合によっては、転置行列とベクトルの積) を計算するだけで済みます。したがって、ライブラリが適切に設計されている場合は、行列とベクトルの積を処理する方法を知っているクラスを渡すだけで十分です。

于 2009-08-12T09:43:13.793 に答える
1

受け入れられた回答が示唆するように、UMFPACK があります。ただし、BOOST を使用している場合でも、BOOST でコンパクトな行列を使用し、UMFPACK を使用して系を解くことができます。簡単にするバインディングがあります:

http://mathema.tician.de/software/boost-numeric-bindings

約 2 年の日付が付けられていますが、拘束力があるだけです (他のいくつかと一緒に)。

関連する質問を参照してください: UMFPACK と BOOST の uBLAS スパース行列

于 2010-10-22T04:03:37.890 に答える