2012-04-12 3 views
4

В принципе мне нужно выше. Я трал Googles и не могу найти способ реализации этого.Быстрая матричная экспоненциальная сложная симметричная трехдиагональная матрица

Я нашел эту функцию здесь http://www.guwi17.de/ublas/examples/, но это слишком медленно. Я даже написал свою собственную аппроксимацию Паде по следующей программе MATLAB, но она была только немного быстрее, чем та, что была в ссылке.

Что меня оглушает, так это то, как быстро Mathematica может вычислить экспоненты матрицы (независимо от того, волнует ли матрица tridiag, я не знаю).

Может ли кто-нибудь помочь?

EDIT: Вот что я придумал, какие-либо комментарии? Будем надеяться, что это будет полезно для будущих читателей.

Я был вне C++ какое-то время, поэтому приведенный ниже код может быть немного прерывистым/медленным, поэтому, пожалуйста, просветите меня, если увидите улучшения.

//Program will compute the matrix exponential expm(i gA). where i = sqrt(-1) and gA is a matrix 

#include <iostream> 
#include <gsl/gsl_complex.h> 
#include <gsl/gsl_complex_math.h> 
#include <gsl/gsl_matrix.h> 
#include <gsl/gsl_linalg.h> 
#include <gsl/gsl_blas.h> 


int main() { 

    int n = 100; 

    unsigned i = 0; 
    unsigned j = 0; 

    gsl_complex img = gsl_complex_rect (0.,1.); 

    gsl_matrix * gA = gsl_matrix_alloc (n, n); 


//Set gA:  
    for (i = 0; i<n; i++) { 
     for (j = 0; j<=i; j++) { 
      if(i == j) { 
       if(i == 0 || i == n-1) { 
        gsl_matrix_set (gA, i, j, 1.); 
       } else { 
        gsl_matrix_set (gA, i, j, 2.); 
       } 
      } else if(j == i-1) { 
       gsl_matrix_set (gA, i, j, 1.); 
       gsl_matrix_set (gA, j, i, 1.); 
      } else { 
       gsl_matrix_set (gA, i, j, 0.); 
       gsl_matrix_set (gA, j, i, 0.); 
     } 
    } 
} 


//get SVD of gA 
    gsl_matrix * gA_t = gsl_matrix_alloc (n, n); 
    gsl_matrix_transpose_memcpy (gA_t, gA);     

    gsl_matrix * U = gsl_matrix_alloc (n, n); 
    gsl_matrix * V= gsl_matrix_alloc (n, n); 
    gsl_vector * S = gsl_vector_alloc (n); 


    gsl_vector * work = gsl_vector_alloc (n); 
    gsl_linalg_SV_decomp (gA_t, V, S, work); 
    gsl_vector_free(work); 

    gsl_matrix_memcpy (U, gA_t); 


//Take exponential of S and form matrix 
    gsl_matrix_complex * Sp = gsl_matrix_complex_alloc (n, n); 
    gsl_matrix_complex_set_zero (Sp); 
    for (i = 0; i < n; i++) { 
     gsl_matrix_complex_set (Sp, i, i, gsl_complex_exp (gsl_complex_mul_real (img, gsl_vector_get(S, i)))); // Vector 'S' to matrix 'Sp' 
    } 

    gsl_matrix_complex * Uc = gsl_matrix_complex_alloc (n, n); 


//convert U to a complex matrix for next step 
    for (i = 0; i < n; i++) { 
     for (j = 0; j<n; j++) { 
      gsl_matrix_complex_set (Uc, i, j, gsl_complex_rect (gsl_matrix_get(U, i, j), 0.));  
     } 
    } 


//recombine U S Utranspose 
    gsl_matrix_complex * tA = gsl_matrix_complex_alloc (n, n); 
    gsl_matrix_complex * eA = gsl_matrix_complex_alloc (n, n); 
    gsl_blas_zgemm (CblasNoTrans, CblasNoTrans, GSL_COMPLEX_ONE, Uc, Sp, GSL_COMPLEX_ZERO, tA); 
    gsl_blas_zgemm (CblasNoTrans, CblasTrans, GSL_COMPLEX_ONE, tA, Uc, GSL_COMPLEX_ZERO, eA); 


//Print result 
    std::cout << "eA:" << std::endl; 
    for (i = 0; i < n; i++) 
     for (j = 0; j < n; j++) 
      printf ("%g + %g i\n", GSL_REAL(gsl_matrix_complex_get (eA, i, j)), GSL_IMAG(gsl_matrix_complex_get (eA, i, j))); 
    std::cout << "\n" << std::endl; 


//Free up 
    gsl_matrix_free(gA_t); 
    gsl_matrix_free(U); 
    gsl_matrix_free(gA); 
    gsl_matrix_free(V); 
    gsl_vector_free(S); 
    gsl_matrix_complex_free(Uc); 
    gsl_matrix_complex_free(tA);  
    gsl_matrix_complex_free(eA);  

    return 0; 
}   
+1

Нужна ли вам только одна экспоненциальная или многие с разными множителями? В последнем случае желательно диагонализировать матрицу, возможно, Mathematica делает это автоматически. – leftaroundabout

+0

Множество разных размножений. У меня есть реальная тридиагональная матрица U и нужно вычислить expm (i z U), где i = sqrt (-1) для многих значений z. Если вы рекомендуете диагонализировать матрицу, можете ли вы рекомендовать быструю библиотеку C++ для этого? –

+0

Вот что я подумал. Я лично использую CULA для этого, который специализируется на графических процессорах Nvidia. GSL также имеет приличные алгоритмы, должен работать неплохо. Оба они довольно низкоуровневые, однако - никакого приятного интерфейса C++. – leftaroundabout

ответ

0

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

 Смежные вопросы

  • Нет связанных вопросов^_^