TooN 2.1
sl.h
00001 // -*- c++ -*-
00002 
00003 // Copyright (C) 2005,2009 Tom Drummond (twd20@cam.ac.uk),
00004 // Gerhard Reitmayr (gr281@cam.ac.uk)
00005 //
00006 // This file is part of the TooN Library.  This library is free
00007 // software; you can redistribute it and/or modify it under the
00008 // terms of the GNU General Public License as published by the
00009 // Free Software Foundation; either version 2, or (at your option)
00010 // any later version.
00011 
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 
00017 // You should have received a copy of the GNU General Public License along
00018 // with this library; see the file COPYING.  If not, write to the Free
00019 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00020 // USA.
00021 
00022 // As a special exception, you may use this file as part of a free software
00023 // library without restriction.  Specifically, if other files instantiate
00024 // templates or use macros or inline functions from this file, or you compile
00025 // this file and link it with other files to produce an executable, this
00026 // file does not by itself cause the resulting executable to be covered by
00027 // the GNU General Public License.  This exception does not however
00028 // invalidate any other reasons why the executable file might be covered by
00029 // the GNU General Public License.
00030 
00031 #ifndef TOON_INCLUDE_SL_H
00032 #define TOON_INCLUDE_SL_H
00033 
00034 #include <TooN/TooN.h>
00035 #include <TooN/helpers.h>
00036 #include <TooN/gaussian_elimination.h>
00037 #include <TooN/determinant.h>
00038 #include <cassert>
00039 
00040 namespace TooN {
00041 
00042 template <int N, typename P> class SL;
00043 template <int N, typename P> std::istream & operator>>(std::istream &, SL<N, P> &);
00044 
00045 /// represents an element from the group SL(n), the NxN matrices M with det(M) = 1.
00046 /// This can be used to conveniently estimate homographies on n-1 dimentional spaces.
00047 /// The implementation uses the matrix exponential function @ref exp for
00048 /// exponentiation from an element in the Lie algebra and LU to compute an inverse.
00049 /// 
00050 /// The Lie algebra are the NxN matrices M with trace(M) = 0. The N*N-1 generators used
00051 /// to represent this vector space are the following:
00052 /// - diag(...,1,-1,...), n-1 along the diagonal
00053 /// - symmetric generators for every pair of off-diagonal elements
00054 /// - anti-symmetric generators for every pair of off-diagonal elements
00055 /// This choice represents the fact that SL(n) can be interpreted as the product
00056 /// of all symmetric matrices with det() = 1 times SO(n).
00057 /// @ingroup gTransforms
00058 template <int N, typename Precision = DefaultPrecision>
00059 class SL {
00060     friend std::istream & operator>> <N,Precision>(std::istream &, SL &);
00061 public:
00062     static const int size = N;          ///< size of the matrices represented by SL<N>
00063     static const int dim = N*N - 1;     ///< dimension of the vector space represented by SL<N>
00064 
00065     /// default constructor, creates identity element
00066     SL() : my_matrix(Identity) {}
00067 
00068     /// exp constructor, creates element through exponentiation of Lie algebra vector. see @ref SL::exp.
00069     template <int S, typename P, typename B>
00070     SL( const Vector<S,P,B> & v ) { *this = exp(v); }
00071 
00072     /// copy constructor from a matrix, coerces matrix to be of determinant = 1
00073     template <int R, int C, typename P, typename A>
00074     SL(const Matrix<R,C,P,A>& M) : my_matrix(M) { coerce(); }
00075 
00076     /// returns the represented matrix
00077     const Matrix<N,N,Precision> & get_matrix() const { return my_matrix; }
00078     /// returns the inverse using LU
00079     SL inverse() const { return SL(*this, Invert()); }
00080 
00081     /// multiplies to SLs together by multiplying the underlying matrices
00082     template <typename P>
00083     SL<N,typename Internal::MultiplyType<Precision, P>::type> operator*( const SL<N,P> & rhs) const { return SL<N,typename Internal::MultiplyType<Precision, P>::type>(*this, rhs); }
00084 
00085     /// right multiplies this SL with another one
00086     template <typename P>
00087     SL operator*=( const SL<N,P> & rhs) { *this = *this*rhs; return *this; }
00088 
00089     /// exponentiates a vector in the Lie algebra to compute the corresponding element
00090     /// @arg v a vector of dimension SL::dim
00091     template <int S, typename P, typename B>
00092     static inline SL exp( const Vector<S,P,B> &);
00093 
00094     inline Vector<N*N-1, Precision> ln() const ;
00095 
00096     /// returns one generator of the group. see SL for a detailed description of 
00097     /// the generators used.
00098     /// @arg i number of the generator between 0 and SL::dim -1 inclusive
00099     static inline Matrix<N,N,Precision> generator(int);
00100 
00101 private:
00102     struct Invert {};
00103     SL( const SL & from, struct Invert ) {
00104         const Matrix<N> id = Identity;
00105         my_matrix = gaussian_elimination(from.my_matrix, id);
00106     }
00107     SL( const SL & a, const SL & b) : my_matrix(a.get_matrix() * b.get_matrix()) {}
00108 
00109     void coerce(){
00110         using std::abs;
00111         Precision det = determinant(my_matrix);
00112         assert(abs(det) > 0);
00113         using std::pow;
00114         my_matrix /= pow(det, 1.0/N);
00115     }
00116 
00117     /// these constants indicate which parts of the parameter vector 
00118     /// map to which generators
00119     ///{
00120     static const int COUNT_DIAG = N - 1;
00121     static const int COUNT_SYMM = (dim - COUNT_DIAG)/2;
00122     static const int COUNT_ASYMM = COUNT_SYMM;
00123     static const int DIAG_LIMIT = COUNT_DIAG;
00124     static const int SYMM_LIMIT = COUNT_SYMM + DIAG_LIMIT;
00125     ///}
00126 
00127     Matrix<N,N,Precision> my_matrix;
00128 };
00129 
00130 template <int N, typename Precision>
00131 template <int S, typename P, typename B>
00132 inline SL<N, Precision> SL<N, Precision>::exp( const Vector<S,P,B> & v){
00133     SizeMismatch<S,dim>::test(v.size(), dim);
00134     Matrix<N,N,Precision> t(Zeros);
00135     for(int i = 0; i < dim; ++i)
00136         t += generator(i) * v[i];
00137     SL<N, Precision> result;
00138     result.my_matrix = TooN::exp(t);
00139     return result;
00140 }
00141 
00142 template <int N, typename Precision>
00143 inline Vector<N*N-1, Precision> SL<N, Precision>::ln() const {
00144     const Matrix<N> l = TooN::log(my_matrix);
00145     Vector<SL<N,Precision>::dim, Precision> v;
00146     Precision last = 0;
00147     for(int i = 0; i < DIAG_LIMIT; ++i){    // diagonal elements
00148         v[i] = l(i,i) + last;
00149         last = l(i,i);
00150     }
00151     for(int i = DIAG_LIMIT, row = 0, col = 1; i < SYMM_LIMIT; ++i) {    // calculate symmetric and antisymmetric in one go
00152         // do the right thing here to calculate the correct indices !
00153         v[i] = (l(row, col) + l(col, row))*0.5;
00154         v[i+COUNT_SYMM] = (-l(row, col) + l(col, row))*0.5;
00155         ++col;
00156         if( col == N ){
00157             ++row;
00158             col = row+1;
00159         }
00160     }
00161     return v;
00162 }
00163 
00164 template <int N, typename Precision>
00165 inline Matrix<N,N,Precision> SL<N, Precision>::generator(int i){
00166     assert( i > -1 && i < dim );
00167     Matrix<N,N,Precision> result(Zeros);
00168     if(i < DIAG_LIMIT) {                // first ones are the diagonal ones
00169         result(i,i) = 1;
00170         result(i+1,i+1) = -1;
00171     } else if(i < SYMM_LIMIT){          // then the symmetric ones
00172         int row = 0, col = i - DIAG_LIMIT + 1;
00173         while(col > (N - row - 1)){
00174             col -= (N - row - 1); 
00175             ++row;
00176         }
00177         col += row;
00178         result(row, col) = result(col, row) = 1;
00179     } else {                            // finally the antisymmetric ones
00180         int row = 0, col = i - SYMM_LIMIT + 1;
00181         while(col > N - row - 1){
00182             col -= N - row - 1; 
00183             ++row;
00184         }
00185         col += row;
00186         result(row, col) = -1;
00187         result(col, row) = 1;
00188     }
00189     return result;
00190 }
00191 
00192 template <int S, typename PV, typename B, int N, typename P>
00193 Vector<N, typename Internal::MultiplyType<P, PV>::type> operator*( const SL<N, P> & lhs, const Vector<S,PV,B> & rhs ){
00194     return lhs.get_matrix() * rhs;
00195 }
00196 
00197 template <int S, typename PV, typename B, int N, typename P>
00198 Vector<N, typename Internal::MultiplyType<PV, P>::type> operator*( const Vector<S,PV,B> & lhs, const SL<N,P> & rhs ){
00199     return lhs * rhs.get_matrix();
00200 }
00201 
00202 template<int R, int C, typename PM, typename A, int N, typename P> inline
00203 Matrix<N, C, typename Internal::MultiplyType<P, PM>::type> operator*(const SL<N,P>& lhs, const Matrix<R, C, PM, A>& rhs){
00204     return lhs.get_matrix() * rhs;
00205 }
00206 
00207 template<int R, int C, typename PM, typename A, int N, typename P> inline
00208 Matrix<R, N, typename Internal::MultiplyType<PM, P>::type> operator*(const Matrix<R, C, PM, A>& lhs, const SL<N,P>& rhs){
00209     return lhs * rhs.get_matrix();
00210 }
00211 
00212 template <int N, typename P>
00213 std::ostream & operator<<(std::ostream & out, const SL<N, P> & h){
00214     out << h.get_matrix();
00215     return out;
00216 }
00217 
00218 template <int N, typename P>
00219 std::istream & operator>>(std::istream & in, SL<N, P> & h){
00220     in >> h.my_matrix;
00221     h.coerce();
00222     return in;
00223 }
00224 
00225 };
00226 
00227 #endif