|
Ublas : |
Subject: Re: [ublas] matrix exponential
From: Paul Leopardi (paul.leopardi_at_[hidden])
Date: 2010-10-26 18:38:18
On Thursday 21 October 2010 20:32:43 Kraus Philipp wrote:
> Am 21.10.2010 um 09:31 schrieb sguazt:
> > On Thu, Oct 21, 2010 at 8:52 AM, David Bellot
> > <david.bellot_at_[hidden]> wrote:
> >
> > Actually, MATLAB uses Pad� approximation + scaling&squaring method
> > (http://www.mathworks.com/help/techdoc/ref/expm.html)
> >
> > Also OCTAVE seems to use the same algorithm:
> > http://hg.savannah.gnu.org/hgweb/octave/file/304b0ed4ca56/scripts/linear-
> > algebra/expm.m
>
> It seems the Pad approximation is the fastest one, so I would like to
> use them
See my GluCat code ( http://glucat.sf.net )
The latest version (0.5.1) uses the scaling and squaring Pade approximation
method with UBLAS matrices to calclate the exponential of a multivector.
See function exp() in matrix_multi_imp.h (code reproduced below).
The Clifford algebra notation complicates thing somewhat, but you can get a
good idea of the algorithm from reading the code. See also the references
[GL]: Gene H. Golub and Charles F. van Loan,
"Matrix Computations", 3rd ed., Johns Hopkins UP, 1996.
[H]: Nicholas J. Higham
"The Scaling and Squaring Method for the Matrix Exponential Revisited",
SIAM Journal on Matrix Analysis and Applications,
Vol. 26, Issue 4 (2005), pp. 1179-1193.
Best, Paul
/// Exponential of multivector
template< typename Scalar_T, const index_t LO, const index_t HI >
const matrix_multi<Scalar_T,LO,HI>
exp(const matrix_multi<Scalar_T,LO,HI>& val)
{
// Scaling and squaring Pade' approximation of matrix exponential
// Reference: [GL], Section 11.3, p572-576
// Reference: [H]
typedef numeric_traits<Scalar_T> traits_t;
if (val.isnan())
return traits_t::NaN();
const Scalar_T scalar_val = scalar(val);
const Scalar_T scalar_exp = traits_t::exp(scalar_val);
if (traits_t::isNaN_or_isInf(scalar_exp))
return traits_t::NaN();
if (val == scalar_val)
return scalar_exp;
typedef matrix_multi<Scalar_T,LO,HI> multivector_t;
multivector_t A = val - scalar_val;
const Scalar_T pure_scale = A.norm();
if (traits_t::isNaN_or_isInf(pure_scale))
return traits_t::NaN();
if (pure_scale == Scalar_T(0))
return scalar_exp;
const int ilog2_scale =
std::max(0, traits_t::to_int(ceil((log2(pure_scale) +
Scalar_T(A.frame().count()))/Scalar_T(2)) - 3));
const Scalar_T i_scale = traits_t::pow(Scalar_T(2), ilog2_scale);
if (traits_t::isNaN_or_isInf(i_scale))
return traits_t::NaN();
A /= i_scale;
multivector_t pure_exp;
{
const int q = 13;
static Scalar_T c[q+1];
if (c[0] != Scalar_T(1))
{
c[0] = Scalar_T(1);
for (int
k = 0;
k != q;
++k)
c[k+1] = c[k]*(q-k) / ((2*q-k)*(k+1));
}
const multivector_t& A2 = A*A;
const multivector_t& A4 = A2*A2;
const multivector_t& A6 = A4*A2;
const multivector_t& U =
c[0]+A2*c[2]+A4*c[4]+A6*(c[6]+A2*c[8]+A4*c[10]+A6*c[12]);
const multivector_t& AV =
A*(c[1]+A2*c[3]+A4*c[5]+A6*(c[7]+A2*c[9]+A4*c[11]+A6*c[13]));
pure_exp = (U+AV) / (U-AV);
}
for (int
k = 0;
k != ilog2_scale;
++k)
pure_exp *= pure_exp;
return pure_exp * scalar_exp;
}