Понимание 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-документации.
если вы хотите использовать 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% этого, и каждая строка кода стоила того.