C ++ 'ta LAPACK kullanmaya nasıl başlanır?


10

Hesaplama biliminde yeniyim ve entegrasyon, enterpolasyon, c ++ üzerinde RK4, Numerov vb.Gibi temel yöntemleri öğrendim, ancak son zamanlarda profesör benden matrislerle ilgili problemleri çözmek için LAPACK'i nasıl kullanacağımı öğrenmemi istedi. Örneğin karmaşık bir matrisin özdeğerlerini bulmak gibi. Hiç üçüncü taraf kütüphaneleri kullanmadım ve neredeyse her zaman kendi işlevlerimi yazıyorum. Birkaç gündür etrafta arama yapıyorum ama lapack için herhangi bir amatör dostu rehber bulamıyorum. Hepsi anlamadığım kelimelerle yazılmıştır ve zaten yazılı fonksiyonların kullanılmasının neden bu kadar karmaşık olması gerektiğini bilmiyorum. Onlar zgeev, dtrsv, vb gibi kelimelerle doludur ve sinirliyim. Sadece bu sahte kod gibi bir şey kodlamak istiyorum:

#include <lapack:matrix>
int main(){
  LapackComplexMatrix A(n,n);
  for...
   for...
    cin>>A(i,j);
  cout<<LapackEigenValues(A);
  return 0;
}

Aptal mıyım yoksa amatör mü olduğumu bilmiyorum. Ama yine de, bu o kadar zor olmamalı mı? LAPACK veya LAPACK ++ kullanmam gerektiğini bile bilmiyorum. (Kodları c ++ ile yazıyorum ve Python veya FORTRAN hakkında bilgim yok)


Belki de bu örnek yararlı olabilir: matrixprogramming.com/files/code/LAPACK
nukeguy

Yeni başlıyorsanız, belki de ArrayFire github.com/arrayfire/arrayfire gibi daha basit bir kütüphane kullanmak daha kolay olacaktır . Doğrudan C ++ 'dan çağırabilirsiniz ve API'ler daha basittir ve LAPACK'in yaptığı tüm işlemleri yapabileceğini düşünüyorum.
Vikram

Bu diğer yılında yazı , bir kullanıcı LAPACK için giriş kolaylığı olabilecek bir çok güzel sözdizimi vardır kendi sarıcı FLENS, önermektedir.
Zythos

LAPACK işlevlerini doğrudan çağırmak çok sıkıcı ve hataya açıktır. LAPACK için Armadillo gibi çok daha kolay kullanım sağlayan birkaç kullanıcı dostu C ++ sarmalayıcısı vardır . Karmaşık öz ayrışma özel kullanım durumu için, kullanıcı dostu bkz eig_gen () altında, bu LAPACK canavar sarar fonksiyonu, zheev (JOBZ, UPLO, N, A, LDA, W, İŞ, LWORK, RWORK INFO), ve elde edilen özdeğerleri ve özvektörleri standart temsiller halinde yeniden biçimlendirir.
hbrerkere

Yanıtlar:


18

Ben diğer bazı yanıtlar katılmıyorum ve ben LAPACK nasıl kullanılacağını endam inanıyoruz söylemek için gidiyorum olduğunu bilimsel bilgi işlem alanında önemli.

Bununla birlikte, LAPACK'i kullanmak için büyük bir öğrenme eğrisi vardır. Çünkü çok düşük bir seviyede yazılmıştır. Bunun dezavantajı, çok şifreli ve duyular için hoş görünmemesi. Bunun avantajı, arayüzün açık olması ve temelde asla değişmemesidir. Ek olarak, Intel Math Çekirdek Kütüphanesi gibi LAPACK uygulamaları gerçekten hızlıdır.

Kendi amaçlarım için, LAPACK altyordamlarını saran kendi üst düzey C ++ sınıflarım var. Birçok bilimsel kütüphane de altında LAPACK kullanır. Bazen bunları kullanmak daha kolaydır, ancak bence altındaki aracı anlamada çok değer var. Bu amaçla, başlamak için LAPACK kullanarak C ++ ile yazılmış küçük bir çalışma örneği sağladım. Bu, Ubuntu'da, liblapack3paket kurulu olarak ve bina için gerekli diğer paketlerle çalışır. Muhtemelen çoğu Linux dağıtımında kullanılabilir, ancak LAPACK'in kurulumu ve ona bağlanma değişebilir.

İşte dosya test_lapack.cpp

#include <iostream>
#include <fstream>


using namespace std;

// dgeev_ is a symbol in the LAPACK library files
extern "C" {
extern int dgeev_(char*,char*,int*,double*,int*,double*, double*, double*, int*, double*, int*, double*, int*, int*);
}

int main(int argc, char** argv){

  // check for an argument
  if (argc<2){
    cout << "Usage: " << argv[0] << " " << " filename" << endl;
    return -1;
  }

  int n,m;
  double *data;

  // read in a text file that contains a real matrix stored in column major format
  // but read it into row major format
  ifstream fin(argv[1]);
  if (!fin.is_open()){
    cout << "Failed to open " << argv[1] << endl;
    return -1;
  }
  fin >> n >> m;  // n is the number of rows, m the number of columns
  data = new double[n*m];
  for (int i=0;i<n;i++){
    for (int j=0;j<m;j++){
      fin >> data[j*n+i];
    }
  }
  if (fin.fail() || fin.eof()){
    cout << "Error while reading " << argv[1] << endl;
    return -1;
  }
  fin.close();

  // check that matrix is square
  if (n != m){
    cout << "Matrix is not square" <<endl;
    return -1;
  }

  // allocate data
  char Nchar='N';
  double *eigReal=new double[n];
  double *eigImag=new double[n];
  double *vl,*vr;
  int one=1;
  int lwork=6*n;
  double *work=new double[lwork];
  int info;

  // calculate eigenvalues using the DGEEV subroutine
  dgeev_(&Nchar,&Nchar,&n,data,&n,eigReal,eigImag,
        vl,&one,vr,&one,
        work,&lwork,&info);


  // check for errors
  if (info!=0){
    cout << "Error: dgeev returned error code " << info << endl;
    return -1;
  }

  // output eigenvalues to stdout
  cout << "--- Eigenvalues ---" << endl;
  for (int i=0;i<n;i++){
    cout << "( " << eigReal[i] << " , " << eigImag[i] << " )\n";
  }
  cout << endl;

  // deallocate
  delete [] data;
  delete [] eigReal;
  delete [] eigImag;
  delete [] work;


  return 0;
}

Bu komut satırı kullanılarak oluşturulabilir

g++ -o test_lapack test_lapack.cpp -llapack

Bu adlı bir yürütülebilir dosya üretir test_lapack. Bunu bir metin giriş dosyasında okumak üzere ayarladım. İşte matrix.txt3x3'lük bir matris içeren bir dosya .

3 3
-1.0 -8.0  0.0
-1.0  1.0 -5.0
 3.0  0.0  2.0

Programı çalıştırmak için

./test_lapack matrix.txt

komut satırında ve çıktı

--- Eigenvalues ---
( 6.15484 , 0 )
( -2.07742 , 3.50095 )
( -2.07742 , -3.50095 )

Yorumlar:

  • LAPACK için adlandırma şemasından atıldınız. Kısa bir açıklama burada .
  • DGEEV altyordamının arayüzü burada . Oradaki argümanların açıklamasını burada yaptığımla karşılaştırabilmelisiniz.
  • Not extern "C"Ben bir çizgi ekledim o üstündeki bölümü ve dgeev_. Çünkü kütüphane Fortran'da yazılmış ve inşa edilmiştir, bu yüzden bağlantı yaparken sembollerin eşleşmesi gerekir. Bu derleyiciye ve sisteme bağlıdır, bu yüzden bunu Windows'ta kullanırsanız, hepsinin değişmesi gerekecektir.
  • Bazı insanlar LAPACK için C arayüzünü kullanmanızı önerebilir . Haklı olabilirler, ama ben hep böyle yaptım.

3
Aradığınız şeylerin birçoğu hızlı Googlage ile bulunabilir. Belki de ne arayacağınızdan emin değilsiniz. Netlib, LAPACK'in koruyucusudur. Belgeleri burada bulabilirsiniz . Bu sayfada , LAPACK'in ana işlevlerine ilişkin kullanışlı bir tablo bulunmaktadır. Önemli olanlardan bazıları (1) denklem sistemlerini çözme, (2) özdeğer problemleri, (3) tekil değer ayrışmaları ve (4) QR faktörleştirmeleridir. DGEEV için kılavuzu anladınız mı?
Mart'ta LedHead

1
Hepsi aynı şey için farklı arayüzler. LAPACK orijinaldir. Fortran'da yazılmıştır, bu yüzden bunu kullanmak için gösterdiğim gibi C / C ++ çalışmalarından çapraz derleme yapmak için bazı oyunlar oynamak zorundasınız. LAPACKE'yi hiç kullanmadım, ancak LAPACK üzerinde bu çapraz derleme işinden kaçınan oldukça ince bir C sarıcı gibi görünüyor, ancak yine de oldukça düşük seviyeli. LAPACK ++ daha yüksek bir C ++ sarıcı gibi görünüyor, ancak artık desteklendiğini bile düşünmüyorum (biri yanılıyorsam beni düzeltiyor).
Mart'ta LedHead

1
Herhangi bir özel kod koleksiyonu bilmiyorum. Ancak Google'da LAPACK altyordam adlarından herhangi biri varsa, her zaman StackExchange sitelerinden birinde eski bir soru bulacaksınız.
Mart'ta LedHead

1
@AlirezaHashemi Bu arada, ÇALIŞMA dizisini sağlamanız gerekmesinin nedeni, kural olarak LAPACK'in alt yordamları içinde herhangi bir bellek ayırmamasıdır. LAPACK kullanıyorsanız, büyük olasılıkla bellek gobleri kullanıyoruz ve bellek ayırmak pahalıdır, bu nedenle çağıran rutinlerin bellek ayırmadan sorumlu olmasına izin vermek mantıklıdır. DGEEV ara miktarları depolamak için bellek gerektirdiğinden, bu çalışma alanını ona sağlamalıyız.
Mart'ta LedHead

1
Anladım. Ve zgeev kullanarak karmaşık bir matrisin özdeğerlerini hesaplamak için ilk kodumu başarıyla yazdım. Ve zaten daha fazlasını yapıyor! Teşekkürler!
Alireza

7

Genellikle insanlara sorularını cevaplamak yerine ne yapmaları gerektiğini düşündüğümü söylemeye direniyorum ama bu durumda bir istisna yapacağım.

Lapack FORTRAN'da yazılmıştır ve API çok FORTRAN gibidir. Lapack için arayüzü biraz daha az acı veren bir C API var, ancak Lapack'i C ++ 'dan kullanmak asla hoş bir deneyim olmayacak.

Alternatif olarak, Eigen adı verilen ve Lapack'in birçok özelliğine sahip, daha iyi Lapack uygulamalarıyla karşılaştırılabilir hesaplama performansı sağlayan ve C ++ 'dan kullanımı çok uygun olan bir C ++ matris sınıf kütüphanesi vardır. Özellikle, örnek kodunuz Eigen kullanılarak nasıl yazılabilir

#include <iostream>
using std::cout;
using std::endl;

#include <Eigen/Eigenvalues>

int main()
{
  const int n = 4;
  Eigen::MatrixXd a(n, n);
  a <<
    0.35, 0.45, -0.14, -0.17,
    0.09, 0.07, -0.54, 0.35,
    -0.44, -0.33, -0.03, 0.17,
    0.25, -0.32, -0.13, 0.11;
  Eigen::EigenSolver<Eigen::MatrixXd> es;
  es.compute(a);
  Eigen::VectorXcd ev = es.eigenvalues();
  cout << ev << endl;
}

Bu örnek özdeğer sorunu, Lapack işlevi için bir test durumudur dgeev. Bu sorun için FORTRAN kodu ve sonuçlarını görebilirsiniz dgeev Örneğin ve kendi karşılaştırmalar yaparlar.


Cevabınız ve açıklamanız için teşekkür ederiz! Bu kütüphaneyi deneyeceğim ve ihtiyaçlarına en uygun olanı seçeceğim.
Alireza

Oh, aşırı yükleniyorlar operator,! Asla gerçek uygulamada yapıldığını görmedim :-)
Wolfgang Bangerth

1
Aslında, bu operator,aşırı yük ilk göründüğünden daha ilginç / daha iyi. Matrisleri başlatmak için kullanılır. Matrisi başlatan girişler skaler sabitler olabilir, ancak daha önce tanımlanmış matrisler veya alt matrisler de olabilir. Çok MATLAB benzeri. Benim C ++ programlama yeteneği kendimi sofistike bir şey uygulamak için yeterince iyi
Bill Greene

7

Yukarıdaki ile aynı şekilde başka bir cevap.

Armadillo C ++ doğrusal cebir kütüphanesine bakmalısınız .

Artıları:

  1. İşlev sözdizimi üst düzeydir (MATLAB'a benzer). Yani hiçbir DGESVmumbo-jumbo, sadece X = solve( A, B )( garip görünen LAPACK işlev adlarının arkasında bir neden olmasına rağmen ...).
  2. Çeşitli matris ayrışmalarını uygular (LU, QR, özdeğerler, SVD, Cholesky, vb.)
  3. Doğru kullanıldığında hızlıdır .
  4. İyi belgelenmiştir .
  5. Seyrek matrisleri destekler (bunları daha sonra incelemek isteyeceksiniz).
  6. En iyi performans için süper optimize BLAS / LAPACK kitaplıklarınıza bağlayabilirsiniz.

@ BillGreene'nin kodu Armadillo ile şöyle görünecekti:

#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;

int main()
{
   const int k = 4;
   mat A = zeros<mat>(k,k) // mat == Mat<double>

   // with the << operator...
   A <<
    0.35 << 0.45 << -0.14 << -0.17 << endr
    0.09 << 0.07 << -0.54 << 0.35  << endr
    -0.44 << -0.33 << -0.03 << 0.17 << endr
    0.25 << -0.32 << -0.13 << 0.11 << endr;

   // but using an initializer list is faster
   A = { {0.35, 0.45, -0.14, -0.17}, 
         {0.09, 0.07, -0.54, 0.35}, 
         {-0.44, -0.33, -0.03, 0.17}, 
         {0.25, -0.32, -0.13, 0.11} };

   cx_vec eigval; // eigenvalues may well be complex
   cx_mat eigvec;

   // eigenvalue decomposition for general dense matrices
   eig_gen(eigval, eigvec, A);

   std::cout << eigval << std::endl;

   return 0;
}

Cevabınız ve açıklamanız için teşekkür ederiz! Bu kütüphaneyi deneyeceğim ve ihtiyaçlarına en uygun olanı seçeceğim.
Alireza
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.