Ax = b线性代数系统的C ++内存有效解决方案

时间:2009-08-07 00:03:52

标签: c++ boost linear-algebra lapack umfpack

我正在使用Boost UBlas的数​​字库绑定来解决一个简单的线性系统。 以下工作正常,但它仅限于相对处理矩阵A(m x m) 小'​​''。

在实践中,我有一个更大的矩阵,维数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;
}

6 个答案:

答案 0 :(得分:14)

简短回答:不要使用Boost的LAPACK绑定,这些绑定是为密集矩阵设计的, 不是稀疏矩阵,而是使用UMFPACK

答案很长:当{A很大且稀疏时,UMFPACK是解决Ax = b的最佳库之一。

以下是生成简单umfpack_simple.cA的示例代码(基于b) 并解决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);
}

函数generate_sparse_matrix_problem创建矩阵A和 右侧b。矩阵首先以三重形式构建。该 向量Ti,Tj和Tx完全描述A.三胞胎形式很容易创建但是 有效的稀疏矩阵方法需要压缩稀疏列格式。转变 使用umfpack_di_triplet_to_col执行。

使用umfpack_di_symbolic执行符号分解。稀疏 使用A执行umfpack_di_numeric的LU分解。 使用umfpack_di_solve执行下三角和上三角解算。

n为500,000,在我的机器上,整个程序需要大约一秒钟才能运行。 Valgrind报告分配了369,239,649字节(仅略高于352 MB)。

请注意,此page讨论了Boost对Triplet(坐标)中稀疏矩阵的支持 和压缩格式。如果您愿意,可以编写例程来转换这些boost对象 简单数组UMFPACK需要输入。

答案 1 :(得分:6)

假设你的巨大矩阵是稀疏的,我希望它们是那么大,看看PARDISO项目是一个稀疏线性求解器,如果你想处理矩阵,这就是你需要的就像你说的那么大。允许有效存储非零值,并且比解决相同的密集矩阵系统快得多。

答案 2 :(得分:6)

我认为你的矩阵是密集的。如果它是稀疏的,您可以找到许多专门的算法,如DeusAduroduffymo所述。

如果您没有足够大的(足够大的)群集,那么您需要查看核心外算法。 ScaLAPACK prototype package有一些核心外解决方案作为其here的一部分,请参阅文档Googlehere以获取更多详细信息。在网上搜索“核外LU /(矩阵)求解器/包”将为您提供大量其他算法和工具的链接。我不是那些专家。

对于这个问题,大多数人会使用群集。您将在几乎任何群集上找到的包再次是ScaLAPACK。此外,典型群集上通常还有许多其他软件包,因此您可以选择适合您问题的软件包(示例here和{{3}})。

在开始编码之前,您可能希望快速检查解决问题所需的时间。典型的求解器需要大约O(3 * N ^ 3)个触发器(N是矩阵的维数)。如果N = 100000,那么您将看到3000000 Gflops。假设您的内存中求解器每个核心的速度为10 Gflops / s,那么您在单个核心上看到的是3 1/2天。由于算法可以很好地扩展,因此增加内核数量可以减少接近线性的时间。最重要的是I / O.

答案 3 :(得分:3)

不确定C ++实现,但如果内存是一个问题,你可以做几件事,具体取决于你正在处理的矩阵类型:

  1. 如果矩阵稀疏或带状,则可以使用稀疏或带宽求解器。这些不会在乐队之外存储零元素。
  2. 您可以使用波前求解器,它将矩阵存储在磁盘上,并仅引入矩阵波前以进行分解。
  3. 您可以避免完全解决矩阵并使用迭代方法。
  4. 您可以尝试蒙特卡罗解决方案。

答案 4 :(得分:3)

看看由Jack Dongarra和Hatem Ltaief编辑的list of freely available software for the solution of linear algebra problems

我认为对于你正在研究的问题规模,你可能需要一个迭代算法。如果您不想以稀疏格式存储矩阵A,则可以使用无矩阵实现。迭代算法通常不需要访问矩阵A的各个条目,它们仅需要计算矩阵向量乘积Av(有时是A ^ T v,转置矩阵与向量的乘积)。因此,如果库设计得很好,那么如果你传授一个知道如何制作矩阵矢量产品的类就足够了。

答案 5 :(得分:1)

由于接受的答案表明存在UMFPACK。但是如果你使用BOOST,你仍然可以在BOOST中使用紧凑矩阵并使用UMFPACK来解决系统问题。有一个绑定,使它很容易:

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

它大约两年了,但它只是一个约束力(以及其他一些)。

查看相关问题: UMFPACK and BOOST's uBLAS Sparse Matrix