Решение C++ с эффективным использованием памяти для системы линейной алгебры Ax=b

Я использую привязки числовой библиотеки для Boost UBlas для решения простой линейной системы. Следующее работает нормально, за исключением того, что оно ограничено обработкой матриц A (m x m) для относительно небольшого «m».

На практике у меня есть гораздо большая матрица с размером m = 10 ^ 6 (до 10 ^ 7).
Существует ли подход C++ для решения Ax=b, который эффективно использует память.

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

person neversaint    schedule 07.08.2009    source источник
comment
Указав на очевидное, матрица с размером массива составляет от 4x10 ^ 12 до 4x 10 ^ 14 байт или от 4 до 400 терабайт для одной матрицы. (если, как отмечено ниже, его редкость)   -  person cyberconte    schedule 14.08.2009


Ответы (6)


Краткий ответ: не используйте привязки Boost LAPACK, они были разработаны для плотных, а не разреженных матриц, вместо этого используйте UMFPACK.

Длинный ответ: UMFPACK — одна из лучших библиотек для решения Ax=b, когда A большое и разреженное.

Ниже приведен пример кода (на основе umfpack_simple.c), который генерирует простые A и 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. Форму триплета легко создать, но для эффективных методов разреженных матриц требуется формат Compressed Sparse Column. Преобразование выполняется с помощью umfpack_di_triplet_to_col.

Символическая факторизация выполняется с помощью umfpack_di_symbolic. Разреженное LU-разложение A выполняется с umfpack_di_numeric. Нижний и верхний треугольные решения выполняются с помощью umfpack_di_solve.

С n как 500 000 на моей машине вся программа выполняется примерно за секунду. Valgrind сообщает, что было выделено 369 239 649 байт (чуть более 352 МБ).

Обратите внимание, что на этой странице обсуждается поддержка Boost для разреженные матрицы в формате Triplet (координата) и Compressed. Если хотите, вы можете написать подпрограммы для преобразования этих объектов повышения в простые массивы, которые UMFPACK требует в качестве входных данных.

person codehippo    schedule 14.08.2009

Предполагая, что ваши огромные матрицы разрежены (я надеюсь, что они такого размера), взгляните на PARDISO. проект, который представляет собой разреженный линейный решатель, это то, что вам нужно, если вы хотите обрабатывать матрицы такого размера, как вы сказали. Позволяет эффективно хранить только ненулевые значения и намного быстрее, чем решение той же системы плотных матриц.

person DeusAduro    schedule 07.08.2009
comment
Не говоря уже о временной сложности O(m^3) наивного решения! Даже умный, о котором говорит Кнут, - это O (m ^ 2,7ish) ... Если эти матрицы не разрежены, вам нужен кластер и первоклассный числовой аналитик ... - person dmckee --- ex-moderator kitten; 07.08.2009
comment
+1 за идею разреженной матрицы. Я нашел многочисленные библиотеки и их сравнения в статье PARDISO о сравнении различных библиотек разреженных матриц ftp.numerical.rl.ac.uk/pub/reports/ghsRAL200505.pdf Это можно использовать для поиска других известных библиотек разреженных матриц. - person Luka Rahne; 07.08.2009

Я предполагаю, что ваша матрица плотная. Если он разреженный, вы можете найти множество специализированных алгоритмов, как уже упоминалось в DeusAduro и даффимо.

Если у вас нет (достаточно большого) кластера в вашем распоряжении, вы хотите взглянуть на внеядерные алгоритмы. ScaLAPACK имеет несколько внешних решателей как часть его пакет-прототип, см. документацию здесь и Google для более подробной информации. Поиск в Интернете «вне основных LU / (матричных) решателей / пакетов» даст вам ссылки на множество дополнительных алгоритмов и инструментов. Я не специалист по тех.

Однако для решения этой проблемы большинство людей использовали бы кластер. Пакет, который вы найдете почти в любом кластере, снова называется ScaLAPACK. Кроме того, обычно в типичном кластере имеется множество других пакетов, так что вы можете выбрать то, что подходит для вашей задачи (примеры здесь и здесь ).

Прежде чем приступить к кодированию, вы, вероятно, захотите быстро проверить, сколько времени потребуется для решения вашей проблемы. Типичный решатель занимает около O (3 * N ^ 3) флопов (N - размерность матрицы). Если N = 100 000, значит, вы смотрите на 3 000 000 Gflops. Предполагая, что ваш решатель в памяти выполняет 10 Гфлопс/с на ядро, вы рассчитываете на 3 1/2 дня на одном ядре. Поскольку алгоритмы хорошо масштабируются, увеличение количества ядер должно сократить время почти линейно. Кроме того, идет ввод-вывод.

person stephan    schedule 11.08.2009
comment
Предостережение: приведенный выше O(3*N^3) предполагает, что вы используете комплексные числа. Для действительных чисел разделите все на 6, то есть где-то около O (0,5 * N ^ 3). - person stephan; 13.08.2009

Не уверен насчет реализаций С++, но есть несколько вещей, которые вы можете сделать, если проблема с памятью, в зависимости от типа матрицы, с которой вы имеете дело:

  1. Если ваша матрица разреженная или ленточная, вы можете использовать разреженный или полосовой решатель. Они не хранят нулевые элементы вне диапазона.
  2. Вы можете использовать решатель волнового фронта, который сохраняет матрицу на диске и вводит только матричный волновой фронт для разложения.
  3. Можно вообще не решать матрицу и использовать итерационные методы.
  4. Вы можете попробовать методы решения Монте-Карло.
person duffymo    schedule 07.08.2009
comment
@duffymo: спасибо. Я просмотрел реализацию итеративного подхода на С++, но они все еще требуют сохранения его в матрице. freenet-homepage.de/guwi17/ublas/examples Если я ошибаюсь, сделайте Вы знаете какую-нибудь эффективную реализацию mem на C++ для итерации? - person neversaint; 07.08.2009
comment
Правильно, глупый сопляк. Я должен был помнить это. Я бы исследовал параллельные алгоритмы, потому что проблема разделения работы на N процессоров и объединения ее обратно для получения результата уместна для проблемы временного перемещения ее на диск. - person duffymo; 07.08.2009

Взгляните на список свободно доступных программ для решения задач линейной алгебры. задачи, составленный Джеком Донгаррой и Хатемом Лтаифом.

Я думаю, что для размера проблемы, на который вы смотрите, вам, вероятно, нужен итеративный алгоритм. Если вы не хотите хранить матрицу A в разреженном формате, вы можете использовать реализацию без матрицы. Итерационные алгоритмы обычно не нуждаются в доступе к отдельным элементам матрицы A, им нужно только вычислить произведение матрицы на вектор Av (а иногда и A ^ T v, произведение транспонированной матрицы на вектор). Итак, если библиотека хорошо спроектирована, должно быть достаточно, если вы передадите ей класс, который знает, как делать матрично-векторные произведения.

person Jitse Niesen    schedule 12.08.2009

Как следует из принятого ответа, существует UMFPACK. Но если вы используете BOOST, вы все равно можете использовать компактные матрицы в BOOST и использовать UMFPACK для решения системы. Существует привязка, которая упрощает:

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

Ему около двух лет, но это просто привязка (вместе с несколькими другими).

см. соответствующий вопрос: разреженная матрица UMFPACK и BOOST uBLAS

person ccook    schedule 22.10.2010