LAPACK dgetrs против dgesv

В документации LAPACK

dgesv Решает общую систему линейных уравнений AX=B.

dgetrs Решает общую систему линейных уравнений AX=B, AT X=B или AH X=B, используя факторизацию LU, вычисленную DGETRF.

В чем разница ? Кроме того, я сделал следующую программу C/C++, и обе дают разные результаты. Почему это так ?

#include <iostream>
#include <iomanip>
#include <vector>
#include <math.h>
#include <time.h>
#include "stdafx.h"

using namespace std;

extern "C" {
// LU decomoposition of a general matrix
void dgetrf_(int* M, int *N, double* A, int* lda, int* IPIV, int* INFO);
//// generate inverse of a matrix given its LU decomposition
//void dgetri_(int* N, double* A, int* lda, int* IPIV, double* WORK, int*    lwork, int* INFO);
void dgetrs_(char* C, int* N, int* NRHS, double* A, int* LDA, int* IPIV, double* B, int* LDB, int* INFO);
void dgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info);
}

void solvelineq(double* A, double* B, int N)
{
int *IPIV = new int[N + 1];
int LWORK = N*N;
double *WORK = new double[LWORK];
int INFO;
char C = 'N';
int NRHS = 1;
dgetrf_(&N, &N, A, &N, IPIV, &INFO);
dgetrs_(&C, &N, &NRHS, A, &N, IPIV, B, &N, &INFO);

//dgetri_(&N, A, &N, IPIV, WORK, &LWORK, &INFO);

delete IPIV;
delete WORK;
}

double comparematrices(double* A, double* B, int N)
{
double sum = 0.;
for (int i = 0; i < N; ++i)
    sum += fabs(A[i] - B[i]);
return sum;
}

int main() {
int dim;
std::cout << "Enter Dimensions of Matrix : \n";
std::cin >> dim;
clock_t c1, c2;
c1 = clock();

vector<double> a(dim*dim);
vector<double> b(dim);
vector<double> c(dim);
vector<int> ipiv(dim);
srand(1);              // seed the random # generator with a known value
double maxr = (double)RAND_MAX;
for (int r = 0; r < dim; r++) {  // set a to a random matrix, i to the identity
    for (int c = 0; c < dim; c++) {
        a[r + c*dim] = rand() / maxr;
    }
    b[r] = rand() / maxr;
    c[r] = b[r];
}
c2 = clock();
cout << endl << dim << " x " << dim << " matrix generated in : " << double(c2 - c1) / CLK_TCK << " seconds " << endl;
// C is identical matrix to B because we are solving by two methods.

c1 = clock();
solvelineq(&*a.begin(), &*c.begin(), dim);
c2 = clock();
cout << endl << " dgetrf_ and dgetrs_ completed in : " << double(c2 - c1) / CLK_TCK << " seconds " << endl;
vector<double> a1(a);
vector<double> b1(b);
int info;
int one = 1;
c1 = clock();
dgesv_(&dim, &one, &*a.begin(), &dim, &*ipiv.begin(), &*b.begin(), &dim, &info);
c2 = clock();
cout << endl << " dgesv_ completed in : " << double(c2 - c1) / CLK_TCK << " seconds " << endl;
cout << "info is " << info << endl;
double eps = 0.;
c1 = clock();
for (int i = 0; i < dim; ++i)
{
    double sum = 0.;
    for (int j = 0; j < dim; ++j)
        sum += a1[i + j*dim] * b[j];
    eps += fabs(b1[i] - sum);
}
c2 = clock();
cout << endl << " dgesv_ check completed in : " << double(c2 - c1) / CLK_TCK << " seconds " << endl;
cout << "check is " << eps << endl;
cout << "\nFinal Matrix 1 : " << endl;
for (int i = 0; i < dim; ++i)
    cout << b[i] << endl;

cout << "\nFinal Matrix 2 : " << endl;
for (int i = 0; i < dim; ++i)
    cout << c[i] << endl;
double diff;
c1 = clock();
diff = comparematrices(&*b.begin(), &*c.begin(), dim);
c2 = clock();
cout << endl << " Both functions compared in : " << double(c2 - c1) / CLK_TCK << " seconds " << endl;
cout << "Sum of difference is : " << diff << endl;
return 0;
}

Мой результат: Введите размеры матрицы: 5

Матрица 5 x 5 сгенерирована за: 0 секунд

dgetrf_ и dgetrs_ завершены за: 0,001 секунды

dgesv_ завершено за: 0 секунд информация равна 0

dgesv_ проверка завершена за: 0 секунд проверка 2.02009e-15

Окончательная матрица 1: -2,97629 4,83948 2,00769 -1,98887 -5,15561

Окончательная матрица 2: -1,40622 2,29029 0,480829 -1,63597 0,71962

Сравнение обеих функций за: 0 секунд

Сумма разницы: 11,8743


person maverick    schedule 17.03.2016    source источник


Ответы (1)


Звонок dgesv эквивалентен звонку dgetrf и dgetrs. исходный код dgesv довольно прост. В основном он содержит вызовы функций dgetrf и dgetrs.

В этом примере результаты отличаются, потому что dgetrf изменяет матрицу A. В справочнике lapack указано:

A is DOUBLE PRECISION array, dimension (LDA,N)
On entry, the M-by-N matrix to be factored.
On exit, the factors L and U from the factorization
A = P*L*U; the unit diagonal elements of L are not stored.

В вашем примере во второй раз используется другая матрица A. Поскольку вы планируете использовать lapack, я предлагаю вам также попробовать использовать подпрограммы blas (daxpy,dnrm2).

Я создал простой пример сравнения dgesv, dgetrf и dgetrs.

#include <iostream>
#include <vector>
#include <stdlib.h>

using namespace std;

extern "C" {
  void daxpy_(int* n,double* alpha,double* dx,int* incx,double* dy,int* incy);
  double dnrm2_(int* n,double* x, int* incx);

  void dgetrf_(int* M, int *N, double* A, int* lda, int* IPIV, int* INFO);
  void dgetrs_(char* C, int* N, int* NRHS, double* A, int* LDA, int* IPIV, double* B, int* LDB, int* INFO);
  void dgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info);
}

void print(const char* head, int m, int n, double* a){
  cout << endl << head << endl << "---------" << endl;
  for(int i=0; i<m; ++i){
    for(int j=0; j<n; ++j){
      cout << a[i+j*m]<< ' ';
    }
    cout << endl;
  }
  cout << "---------" << endl;
}

int main() {
  int dim;
  std::cout << "Enter Dimensions of Matrix : \n";
  std::cin >> dim;

  vector<double> a(dim*dim);
  vector<double> b(dim);
  srand(1);              // seed the random # generator with a known value
  double maxr = (double)RAND_MAX;
  for (int r = 0; r < dim; r++) {  // set a to a random matrix, i to the identity
    for (int i = 0; i < dim; i++) {
      a[r + i*dim] = rand() / maxr;
    }
    b[r] = rand() / maxr;
  }

  int info;
  int one = 1;
  char N = 'N';
  vector<int> ipiv(dim);

  vector<double> a1(a);
  vector<double> b1(b);
  dgesv_(&dim, &one, a1.data(), &dim, ipiv.data(), b1.data(), &dim, &info);
  print("B1",5,1,b1.data());

  vector<double> a2(a);
  vector<double> b2(b);
  dgetrf_(&dim, &dim, a2.data(), &dim, ipiv.data(), &info);
  dgetrs_(&N, &dim, &one, a2.data(), &dim, ipiv.data(), b2.data(), &dim, &info);
  print("B2",5,1,b2.data());

  double d_m_one = -1e0;
  daxpy_(&dim,&d_m_one,b2.data(),&one,b1.data(),&one);
  cout << endl << "diff = " << dnrm2_(&dim,b1.data(),&one) << endl;

  return 0;
}

На моем ПК, на котором запущен случай dim=5, это дало:

B1
---------
0.782902 
3.35317 
4.40269 
-5.10512 
-1.26615 
---------

B2
---------
0.782902 
3.35317 
4.40269 
-5.10512 
-1.26615 
---------

diff = 0
person ztik    schedule 17.03.2016