Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:24:28

0001 //
0002 //  Copyright (c) 2007
0003 //  Tsai, Dung-Bang 
0004 //  National Taiwan University, Department of Physics
0005 // 
0006 //  E-Mail : dbtsai (at) gmail.com
0007 //  Begine : 2007/11/20
0008 //  Last modify : 2007/11/22
0009 //  Version : v0.1
0010 //
0011 //  EXPGM_PAD computes the matrix exponential exp(H) for general matrixs,
0012 //  including complex and real matrixs using the irreducible (p,p) degree
0013 //  rational Pade approximation to the exponential 
0014 //  exp(z) = r(z)=(+/-)( I+2*(Q(z)/P(z))).
0015 //
0016 //  Usage : 
0017 //
0018 //    U = expm_pad(H)
0019 //    U = expm_pad(H, p)
0020 //    
0021 //    where p is internally set to 6 (recommended and gererally satisfactory).
0022 //
0023 //  See also MATLAB supplied functions, EXPM and EXPM1.
0024 //
0025 //  Reference :
0026 //  EXPOKIT, Software Package for Computing Matrix Exponentials.
0027 //  ACM - Transactions On Mathematical Software, 24(1):130-156, 1998
0028 //
0029 //  Permission to use, copy, modify, distribute and sell this software
0030 //  and its documentation for any purpose is hereby granted without fee,
0031 //  provided that the above copyright notice appear in all copies and
0032 //  that both that copyright notice and this permission notice appear
0033 //  in supporting documentation.  The authors make no representations
0034 //  about the suitability of this software for any purpose.
0035 //  It is provided "as is" without express or implied warranty.
0036 //
0037 
0038 #ifndef _BOOST_UBLAS_EXPM_
0039 #define _BOOST_UBLAS_EXPM_
0040 #include <complex>
0041 #include <boost/numeric/ublas/vector.hpp>
0042 #include <boost/numeric/ublas/matrix.hpp>
0043 #include <boost/numeric/ublas/lu.hpp>
0044 
0045 namespace boost { namespace numeric { namespace ublas {
0046 
0047 template<typename MATRIX> MATRIX expm_pad(const MATRIX &H, const int p = 6) {
0048   typedef typename MATRIX::value_type value_type;
0049   typedef typename MATRIX::size_type size_type;
0050   typedef double real_value_type;   // Correct me. Need to modify.
0051   assert(H.size1() == H.size2());   
0052   const size_type n = H.size1();
0053   const identity_matrix<value_type> I(n);
0054   matrix<value_type> U(n,n),H2(n,n),P(n,n),Q(n,n);
0055   real_value_type norm = 0.0;
0056 
0057   // Calcuate Pade coefficients  (1-based instead of 0-based as in the c vector)
0058   vector<real_value_type> c(p+2);
0059   c(1)=1;  
0060   for(size_type i = 1; i <= p; ++i) 
0061     c(i+1) = c(i) * ((p + 1.0 - i)/(i * (2.0 * p + 1 - i)));
0062   // Calcuate the infinty norm of H, which is defined as the largest row sum of a matrix
0063   for(size_type i=0; i<n; ++i)
0064     {
0065       real_value_type temp = 0.0;
0066       for(size_type j=0;j<n;j++)
0067     temp += std::abs<real_value_type>(H(j,i)); // Correct me, if H is complex, can I use that abs?
0068       norm = std::max<real_value_type>(norm, temp);
0069     }
0070   if (norm == 0.0) 
0071     {
0072       boost::throw_exception(boost::numeric::ublas::bad_argument());
0073       std::cerr<<"Error! Null input in the routine EXPM_PAD.\n";
0074       exit(0);
0075     }
0076   // Scaling, seek s such that || H*2^(-s) || < 1/2, and set scale = 2^(-s)
0077   int s = 0;
0078   real_value_type scale = 1.0;
0079   if(norm > 0.5) {
0080     s = std::max<int>(0, static_cast<int>((log(norm) / log(2.0) + 2.0)));
0081     scale /= static_cast<real_value_type>(std::pow(2.0, s));
0082     U.assign(scale * H); // Here U is used as temp value due to that H is const
0083   }
0084   else
0085     U.assign(H);
0086   // Horner evaluation of the irreducible fraction, see the following ref above.
0087   // Initialise P (numerator) and Q (denominator) 
0088   H2.assign( prod(U, U) );
0089   Q.assign( c(p+1)*I );
0090   P.assign( c(p)*I );
0091   size_type odd = 1;
0092   for( size_type k = p - 1; k > 0; --k)
0093     {
0094       if( odd == 1)
0095     {
0096       Q = ( prod(Q, H2) + c(k) * I ); 
0097     }
0098       else
0099     {
0100       P = ( prod(P, H2) + c(k) * I );
0101     }
0102       odd = 1 - odd;
0103     }
0104   if( odd == 1)
0105     {
0106       Q = ( prod(Q, U) );   
0107       Q -= P ;
0108       //U.assign( -(I + 2*(Q\P)));
0109     }
0110   else
0111     {
0112       P = (prod(P, U));
0113       Q -= P;
0114       //U.assign( I + 2*(Q\P));
0115     }
0116   // In origine expokit package, they use lapack ZGESV to obtain inverse matrix,
0117   // and in that ZGESV routine, it uses LU decomposition for obtaing inverse matrix.
0118   // Since in ublas, there is no matrix inversion template, I simply use the build-in
0119   // LU decompostion package in ublas, and back substitute by myself.
0120   //
0121   //////////////// Implement Matrix Inversion ///////////////////////
0122   permutation_matrix<size_type> pm(n); 
0123   int res = lu_factorize(Q, pm);
0124   if( res != 0)
0125     {
0126       std::cerr << "Error in the matrix inversion in template expm_pad.\n";
0127       exit(0);
0128     }
0129   H2 = I;  // H2 is not needed anymore, so it is temporary used as identity matrix for substituting.
0130   
0131   lu_substitute(Q, pm, H2); 
0132   if( odd == 1) 
0133     U.assign( -(I + 2.0 * prod(H2, P)));
0134   else
0135     U.assign( I + 2.0 * prod(H2, P));
0136   // Squaring 
0137   for(size_t i = 0; i < s; ++i)
0138     {
0139       U = (prod(U,U));
0140     }
0141   return U;
0142  }
0143  
0144 }}}
0145 
0146 
0147 #endif