Понимание LAPACK вызовы в c++ простой пример

Я новичок с интерфейсом LAPACK и C++/Fortran. Мне нужно решить линейные уравнения и задачи на собственные значения, используя LAPACK/BLAS на Mac OS-X Lion. OS-X Lion предоставляет оптимизированные библиотеки BLAS и LAPACK (в /usr/lib), и я связываю эти библиотеки вместо загрузки их из netlib.

моя программа (воспроизводится ниже) компилируется и работает нормально, но она дает мне неправильные ответы. Я исследовал в интернете и Stackoverflow, и проблема может иметь дело с тем, как C++ и Fortran хранят массивы в разных форматах (строка major vs столбец major). Однако, как вы увидите в моем примере, простой массив для моего примера должен выглядеть идентично в C++ и fortran. Во всяком случае, здесь.

допустим, мы хотим решить следующую линейную систему:

x + y = 2

x-y = 0

решение (x, y) = (1,1). Теперь я попытался решить эту проблему с помощью Lapack следующим образом

// LAPACK test code

#include<iostream>
#include<vector>

using namespace std;
extern "C" void dgetrs(char *TRANS, int *N, int *NRHS, double *A, 
                      int *LDA, int *IPIV, double *B, int *LDB, int *INFO );

int main()
{
    char trans = 'N';
    int dim = 2;    
    int nrhs = 1;
    int LDA = dim;
    int LDB = dim;
    int info;

    vector<double> a, b;

    a.push_back(1);
    a.push_back(1);
    a.push_back(1);
    a.push_back(-1);

    b.push_back(2);
    b.push_back(0);

    int ipiv[3];


    dgetrs(&trans, &dim, &nrhs, & *a.begin(), &LDA, ipiv, & *b.begin(), &LDB, &info);


    std::cout << "solution is:";    
    std::cout << "[" << b[0] << ", " << b[1] << ", " << "]" << std::endl;
    std::cout << "Info = " << info << std::endl; 

    return(0);
}

этот код был скомпилирован как следует:

g++ -Wall -llapack -lblas lapacktest.cpp

при запуске этого, однако, я получаю решение как (-2,2), что, очевидно, неправильно. Я пробовал всю комбинацию перестановки строк/столбцов моей матрицы a. Также соблюдайте матричное представление a должны быть идентичны в форматах строк и столбцов. Я думаю, что этот простой пример поможет мне начать работу с LAPACK, и любая помощь будет оценена.

3 ответов


вам нужно фактор матрица (по вызову dgetrf), прежде чем вы сможете решить систему с помощью dgetrs. Кроме того, вы можете использовать dgesv рутина, которая делает оба шага для вас.

кстати, вам не нужно объявлять интерфейсы самостоятельно, они находятся в заголовках ускорения:

// LAPACK test code

#include <iostream>
#include <vector>
#include <Accelerate/Accelerate.h>

using namespace std;

int main()
{
    char trans = 'N';
    int dim = 2;    
    int nrhs = 1;
    int LDA = dim;
    int LDB = dim;
    int info;

    vector<double> a, b;

    a.push_back(1);
    a.push_back(1);
    a.push_back(1);
    a.push_back(-1);

    b.push_back(2);
    b.push_back(0);

    int ipiv[3];

    dgetrf_(&dim, &dim, &*a.begin(), &LDA, ipiv, &info);
    dgetrs_(&trans, &dim, &nrhs, & *a.begin(), &LDA, ipiv, & *b.begin(), &LDB, &info);


    std::cout << "solution is:";    
    std::cout << "[" << b[0] << ", " << b[1] << ", " << "]" << std::endl;
    std::cout << "Info = " << info << std::endl; 

    return(0);
}

для тех, кто не хочет беспокоиться о структуре ускорения, я предоставляю код Stephen Canon (благодаря ему, конечно) только с чистой библиотекой linking

// LAPACK test code
//compile with: g++ main.cpp -llapack -lblas -o testprog

#include <iostream>
#include <vector>

using namespace std;

extern "C" void dgetrf_(int* dim1, int* dim2, double* a, int* lda, int* ipiv, int* info);
extern "C" void dgetrs_(char *TRANS, int *N, int *NRHS, double *A, int *LDA, int *IPIV, double *B, int *LDB, int *INFO );

int main()
{
    char trans = 'N';
    int dim = 2;
    int nrhs = 1;
    int LDA = dim;
    int LDB = dim;
    int info;

    vector<double> a, b;

    a.push_back(1);
    a.push_back(1);
    a.push_back(1);
    a.push_back(-1);

    b.push_back(2);
    b.push_back(0);

    int ipiv[3];

    dgetrf_(&dim, &dim, &*a.begin(), &LDA, ipiv, &info);
    dgetrs_(&trans, &dim, &nrhs, & *a.begin(), &LDA, ipiv, & *b.begin(), &LDB, &info);


    std::cout << "solution is:";
    std::cout << "[" << b[0] << ", " << b[1] << ", " << "]" << std::endl;
    std::cout << "Info = " << info << std::endl;

    return(0);
}

и о руководстве, есть полная версия PDF доступна на веб-сайте Intel. Вот пример их HTML-документации.

http://software.intel.com/sites/products/documentation/hpc/mkl/mklman/GUID-A02DB70F-9704-42A4-9071-D409D783D911.htm


если вы хотите использовать LAPACK с C++ , вы можете посмотреть ФЛЭНС. Он определяет интерфейсы низкого и высокого уровня для LAPACK, но также повторно реализует некоторые функции LAPACK.

с низкоуровневым интерфейсом FLENS-LAPACK вы можете использовать свои собственные типы матриц / векторов (если они имеют макет памяти lapack). Ваш зов dgetrf будет выглядеть так:

info = lapack::getrf(NoTrans, dim, nrhs, a.begin(), LDA, ipiv);

и dgetrs

lapack::getrs(NoTrans, dim, nrhs, a.begin(), LDA, ipiv, b.begin(), LDB);

так низкоуровневый Функции FLENS-LAPACK перегружены относительно типов элементов. Следовательно, функция LAPACK sgetrs, dgetrs, cgetrs, zgetrs находятся в низкоуровневом интерфейсе FLENS-LAPACK lapack::getrs. Вы также передавать параметры по значению/ссылке, а не как указатель (например,LDA вместо &LDA).

если вы используете матричные типы FLENS, вы можете закодировать его как

info = lapack::trf(NoTrans, A, ipiv);
if (info==0) {
    lapack::trs(NoTrans, A, ipiv, b);
}

или вы просто используете функцию драйвера LAPACK dgesv

lapack::sv(NoTrans, A, ipiv, b);

здесь a список FLENS-LAPACK функции драйвера.

отказ от ответственности: да, ФЛЕНС мой ребенок! Это означает, что я закодировал около 95% этого, и каждая строка кода стоила того.