Armadillo C++ expmat stacks

限于喜欢 提交于 2019-12-12 19:39:04

问题


I'm trying to execute the expmat() function from the Armadillo c++ library but it gets stacked when i run it. First i tried in Matlab with the expm function, and with different values in the C++ program and it works in both cases. So, the problem is with something related with the values i put on the matrix, seem that some of them are too small... This is the squared [14x14] matrix i want to calculate the exponential:

mat A;
A  << 0 << -0.0000769006 << -0.0000511322 << -0.0000915495 << 0 << 0 << -0.00254523 <<                 0.00000001 << 0 << 0 << 0 << 0 << 0 << 0 << endr
    << 0.0000769006 << 0 << 0.0000915495 << -0.0000511322 << 0.0043037 << -0.00254523 << 0 << 0 << 0.00000001 << 0 << 0 << 0 << 0 << 0 << endr
    << 0.0000511322 << -0.0000915495 << 0 << 0.0000769006 << 0.00254523 << 0.0043037 << 0 << 0 << 0 << 0.00000001 << 0 << 0 << 0 << 0 << endr
    << 0.0000915495 << 0.0000511322 << -7.69006/100000 << 0 << 0 << 0 << 0.0043037 << 0 << 0 << 0 << 0.00000001 << 0 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.00000001 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.00000001 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.00000001 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << -0.0000769006 << -0.0000511322 << -0.0000915495 << 0 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.0000769006 << 0 << 0.0000915495 << -0.0000511322 << 0 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.0000511322 << -0.0000915495<< 0 << 0.0000769006 << 0 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.0000915495 << 0.0000511322 << -0.0000769006 << 0 << 0 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << -0.0043037 << -0.00254523 << 0 << 0 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.00254523 << -0.0043037 << 0 << 0 << 0 << 0 << endr
    << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0.00254523 << 0 << 0 << -0.0043037 << 0 << 0 << 0 << endr;

B = expmat(A);

When i press pause on the debug i see that line wich is being executed is:

arma_fortran(arma_dgemm)(transA, transB, m, n, k, (const T*)alpha, (const T*)A, ldA, (const T*)B, ldB, (const T*)beta, (T*)C, ldC);  

...inside the file "blas_wrapper.hpp". No errors are displayed, only the program is there but it doesn´t advance. If i use different values on the matrix i can make it working, but with the ones i displayed not...

About the LAPACK version i don´t know how to check it...

Thanks,

AV9


回答1:


In fact, any matrix with infinite norm lower than 1 may trigger some sort of nearly infinite loop. The problem does not come from your code, but from the library.

The following code, compiled by g++ main.cpp -o main -larmadillo reproduces the problem :

#include <iostream>
#include <cstdio>
#include <armadillo>

using namespace std;
using namespace arma;

int
main( int argc, char* argv[] )
{
    cout<<"start"<<endl;

    mat A=randu(2,2);
    A=A/100;
    cout<<"A is "<<endl<<A<<endl;

    double norm_val = norm(A, "inf");  
    double log2_val = eop_aux::log2(norm_val); 
    const uword s = (std::max)(uword(0), uword(log2_val) + uword(1) + uword(1));

    cout<<"norm inf is "<<norm_val<<" log of norm inf is "<<log2_val <<" uword "<<uword(log2_val)<<" nb it is "<<s<<endl;

    mat B = expmat(A);

    cout<<"B is "<<endl<<B<<endl;
    cout<<"end"<<endl;
}

And here is the reason why...

Armadillo quotes the following article to compute the matrix's exponential : Nineteen Dubious Ways to Compute the Exponential of a Matrix, Twenty-Five Years Later by C. Moler and C. Van Loan in SIAM Review, 2003. The third method, called "Scaling and squaring" is implemented by the library Armadillo. The following formula is used :

m should be large enough so as to decrase the norm of A/m and ease the exponentialisation of A/m by Taylor series.

The algorithm is the following :

  • Choose integer s so that the infinite norm of A/2^s is lower than one
  • mat AA=A/2^s
  • compute e^(AA) by Taylor series
  • compute e^(A) by squarring e^(AA) s times

In the library Armadillo, in file armadillo-4.550.3/include/armadillo_bits/op_expmat_meat.hpp here is how s is computed :

    double norm_val = norm(A, "inf");  
    double log2_val = eop_aux::log2(norm_val); 
    const uword s = (std::max)(uword(0), uword(log2_val) + uword(1) + uword(1));

If the infinite norm of A is lower than 1, log2_val is negative and casting it to uword (u stands for unsigned) fails. It results in s being very large (4294967291 for instance), and the code is stuck in a nearly infinite loop when squaring is performed.

A test should be added to the library, in file armadillo-4.550.3/include/armadillo_bits/op_expmat_meat.hpp, something like :

uword s=42;
if(log2_val<0){
   //no need to use the formula, use Taylor series
   s=0;
 }else{
   //need to decrease A and use the formula
   s=uword(log2_val)+2;
 }

instead of :

const uword s = (std::max)(uword(0), uword(log2_val) + uword(1) + uword(1));

Change file op_expmat_meat.hpp, reinstall armadillo by typing cmake . make and make install (or sudo make install) and the issue will be gone. The new result seems to be correct. If A is near 0 :

I will report this bug to the developpers of Armadillo by email. EDIT : no need to do so : as noticed by @mtall, this issue is removed in version 4.550.4. My guess is that the developpers have seen your post. The patched version has been modified a few hours ago : the developpers'team is reactive !



来源:https://stackoverflow.com/questions/27591868/armadillo-c-expmat-stacks

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!