2009-08-07 10 views
8

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

На практике у меня есть гораздо большая матрица с размером 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; 
} 
+2

Указывая на очевидное, матрицу, массив размера является 4x10^12 до 4x10^14 байт, или 4 до 400 терабайт для только одной матрицы. (если, как отмечено ниже, его разреженный) – cyberconte

ответ

13

Короткий ответ: Не используйте LAPACK привязок BOOST эти были предназначены для плотных матриц, не разреженные матрицы, используйте 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. Форма триплета легко создать, но для эффективных разреженных матричных методов длятребуется формат сжатой разреженной колонки. Конверсия выполняется с umfpack_di_triplet_to_col.

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

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

Заметим, что page обсуждает поддержку Boost для разреженных матриц в Триплете (координата) и сжатом формате. Если вам нравится, вы можете написать процедуры для преобразования этих объектов boost в простые массивы UMFPACK требует ввода.

+0

+1 для школьной гордости :) – ccook

6

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

+2

Не говоря уже о временной сложности O (m^3) наивного решения! Даже умный, о котором говорит Кнут, - это O (m^2.7ish) ... Если эти матрицы не разрежены, вам нужен кластер и первоклассный численный аналитик ... – dmckee

+1

+1 для идеи с разреженной матрицей. Я нашел библиотеки Numus и их сравнения в документации PARDISO о сравнении разнородных разреженных матричных библиотек ftp://ftp.numerical.rl.ac.uk/pub/reports/ghsRAL200505.pdf Это можно использовать для поиска других распознанных разреженных матричных библиотек. –

3

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

  1. Если матрица разреженной или полосчатые, вам может использовать разреженный или разрешительный фильтр. Они не хранят нулевые элементы вне диапазона.
  2. Вы можете использовать решатель волнового фронта, который хранит матрицу на диске и выводит только матричный волновой фронт для разложения.
  3. Вы можете избежать полного решения матрицы и использовать итерационные методы.
  4. Вы можете попробовать методы решения Монте-Карло.
+0

@duffymo: спасибо. Я рассмотрел реализацию итеративного подхода в C++, но они все еще требуют хранения его в матрице. http://freenet-homepage.de/guwi17/ublas/examples/ Если я ошибаюсь, знаете ли вы, что эффективная реализация mem на C++ для итеративного? – neversaint

+0

Правильно, глупо. Я должен был это вспомнить. Я бы исследовал параллельные алгоритмы, потому что проблема разделения работы на N процессоров и вязания их вместе для получения результата связана с проблемой временного перемещения на диск. – duffymo

6

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

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

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

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

+0

Предостережение: вышеупомянутое O (3 * N^3) предполагает, что вы используете комплексные числа. Для вещественных чисел делим все на 6, т. Е. Где-нибудь вокруг O (0.5 * N^3). – stephan

3

Посмотрите на list of freely available software for the solution of linear algebra problems, составленный Джеком Донгаррой и Хатемом Лэйтом.

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

1

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

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

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

см родственный вопрос: UMFPACK and BOOST's uBLAS Sparse Matrix