00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 #ifndef _QR_DECOMPOSITION_H
00020 #define _QR_DECOMPOSITION_H
00021 
00022 #include <lsp/givens_rotation.h>
00023 
00024 #include <limits>
00025 
00026 #include <boost/numeric/ublas/matrix.hpp>
00027 #include <boost/numeric/ublas/matrix_proxy.hpp>
00028 #include <boost/numeric/ublas/storage.hpp>
00029 
00030 using namespace boost::numeric::ublas;
00031 
00032 namespace lsp{
00033 
00034 namespace {
00035         template<class T> static T shift( T q2, T q1, T e2, T e1 ) {
00036                 typedef T value_type;
00037                 const value_type f = ( q2*q2 - q1*q1 +  e2*e2 - e1*e1 ) / ( 2*e2*q1 );
00038                 const value_type t = ( f < 0 ?
00039                         - f + std::pow(( value_type(1)+f*f ),0.5) :
00040                         - f - std::pow(( value_type(1)+f*f ),0.5) );
00041                         return ( q2*q2 + e2*(e2 - q1/t) );
00042         };
00043 };
00044 
00054 template<class T> class qr_decomposition {
00055 public:
00056         typedef T                                  matrix_type;   
00057         typedef typename matrix_type::value_type   value_type;    
00058         typedef typename matrix_type::size_type    size_type;     
00059         typedef matrix_vector_slice< matrix_type > diagonal_type; 
00060 private:
00061         struct regular_tag {};
00062         struct left_tag {};
00063         struct right_tag {};
00064 private:
00065         matrix_type& m_matrix;
00066         mutable diagonal_type m_super;
00067         mutable diagonal_type m_leading;
00068 private:
00069 
00070         template<class M1, class M2> void apply( M1& left, M2& right, const range& cell, const left_tag& ) const {
00071                 typedef givens_rotation< value_type > givens_rotation_type;
00072                 value_type z;
00073 
00074                 z = m_super( cell(0) );
00075                 m_super( cell(0) ) = 0;
00076 
00077                 for( range::const_iterator it = cell.begin() + 1; it != cell.end() ; ++it ) {
00078                         givens_rotation_type gr( m_leading(*it), z );
00079 
00080                         gr.apply( row(left, *it), row(left, cell(0)) );
00081                         if( *it == cell( cell.size() - 1 ) )
00082                                 break;
00083                         gr.apply( m_super(*it), z );
00084                 }
00085         }
00086 
00087         template<class M1, class M2> void apply( M1& left, M2& right, const range& cell, const right_tag& ) const {
00088                 typedef givens_rotation< value_type > givens_rotation_type;
00089                 value_type z;
00090 
00091                 z = m_super( cell( cell.size() - 2 ) );
00092                 m_super( cell( cell.size() - 2 ) ) = 0;
00093 
00094                 for( range::const_reverse_iterator it = cell.rbegin() + 1; it != cell.rend(); ++it ) {
00095                         givens_rotation_type gr( m_leading(*it), z );
00096 
00097                         gr.apply( column( right, *it ), column( right, cell( cell.size() - 1 ) ) );
00098                         if( *it == cell.start() )
00099                                 break;
00100                         gr.apply( m_super(*it-1), z );
00101                 }
00102         }
00103 
00104         template<class M1, class M2> void apply( M1& left, M2& right, const range& cell, const regular_tag& ) const {
00105                 typedef givens_rotation< value_type > givens_rotation_type;
00106 
00107                 const value_type lim = std::numeric_limits< value_type >::epsilon() * norm_frobenius( m_matrix ) / m_matrix.size2();
00108 
00109                 for( range::const_reverse_iterator it = cell.rbegin() + 1; it != cell.rend(); ++it ) {
00110                         while( std::abs( m_super( *it ) ) > lim ) {
00111 
00112                                 value_type en1 = ( *it != cell(0) ? m_super(*it - 1) : value_type(0) );
00113                                 value_type e0 = m_leading( cell(0) ) - shift( m_leading(*it + 1), m_leading(*it), m_super(*it), en1 ) / m_leading( cell(0) );
00114                                 value_type z = m_super( cell(0) );
00115 
00116                                 givens_rotation_type gr_left( e0, z );
00117                                 for( range::const_iterator it2 = cell.begin() + 1; *it2 != *it + 2; ++it2 ) {
00118 
00119                                         gr_left.apply( m_leading(*it2-1), m_super(*it2-1) );
00120                                         gr_left.apply( column(right,*it2-1), column(right,*it2) );
00121 
00122                                         z = gr_left.s() * m_leading(*it2);
00123                                         m_leading(*it2) = gr_left.c() * m_leading(*it2);
00124 
00125                                         givens_rotation_type gr_right( m_leading(*it2-1), z );
00126                                         gr_right.apply( m_super(*it2-1), m_leading(*it2) );
00127                                         gr_right.apply( row(left,*it2-1), row(left,*it2) );
00128 
00129                                         if( *it2 == *it + 1 ) break;
00130                                         z = gr_right.s() * m_super(*it2);
00131                                         m_super(*it2) = gr_right.c() * m_super(*it2);
00132 
00133                                         gr_left = givens_rotation_type( m_super(*it2-1), z );
00134                                 }
00135                         }
00136                         m_super( *it ) = 0;
00137                 }
00138         }
00139 
00140         template<class M1, class M2> void apply( M1& left, M2& right, const range& cell ) const {
00141 
00142                 if( cell.size() == 1 ) 
00143                         return ;
00144 
00145                 const value_type lim = 6 * std::numeric_limits< value_type >::epsilon() * norm_frobenius( m_matrix );
00146 
00147                 
00148                 for( range::const_reverse_iterator it = cell.rbegin() + 1; it != cell.rend() ; ++it ) {
00149                         if( m_leading( *it ) == 0 ) {
00150                                 apply( left, right, range( *it, cell.start() + cell.size() ), left_tag() );
00151                                 for( range::const_reverse_iterator it2 = cell.rbegin(); it2 != it; ++it2 ){
00152                                         if( std::abs( m_leading( *it2 ) ) < lim )  m_leading( *it2 ) = 0;
00153                                 }
00154                                 for( range::const_reverse_iterator it2 = cell.rbegin() + 1; it2 != it; ++it2 ){
00155                                         if( std::abs( m_super( *it2 ) ) < lim )    m_super( *it2 ) = 0;
00156                                 }
00157                                 apply( left, right, range( cell.start(), *it+1 ) );
00158                                 apply( left, right, range( *it+1, cell.start() + cell.size() ) );
00159                                 return ;
00160                         }
00161                 }
00162                 
00163                 if( m_leading( cell( cell.size() - 1 ) ) == 0 ) {
00164                         apply( left, right, cell, right_tag() );
00165                         for( range::const_reverse_iterator it2 = cell.rbegin(); it2 != cell.rend(); ++it2 ){
00166                                 if( std::abs( m_leading( *it2 ) ) < lim )  m_leading( *it2 ) = 0;
00167                         }
00168                         for( range::const_reverse_iterator it2 = cell.rbegin() + 1; it2 != cell.rend(); ++it2 ){
00169                                 if( std::abs( m_super( *it2 ) ) < lim )  m_super( *it2 ) = 0;
00170                         }
00171                         apply( left, right, range( cell.start(), cell(cell.size()-1) ) );
00172                         return ;
00173                 }
00174 
00175                 
00176                 for( range::const_reverse_iterator it = cell.rbegin() + 1; it != cell.rend(); ++it ) {
00177                         if( m_super( *it ) == 0 ) {
00178                                 apply( left, right, range( cell.start(), *it + 1 ) );
00179                                 apply( left, right, range( *it + 1, cell.start() + cell.size() ) );
00180                                 return ;
00181                         }
00182                 }
00183 
00184                 apply( left, right, cell, regular_tag() );
00185 
00186         }
00187 
00188 public:
00194         qr_decomposition( matrix_type& matrix ):
00195                 m_matrix( matrix ),
00196                 m_super(   matrix, slice(0, 1, matrix.size2() - 1), slice(1, 1, matrix.size2() - 1) ),
00197                 m_leading( matrix, slice(0, 1, matrix.size2()),     slice(0, 1, matrix.size2())     ) {
00198 
00199                 assert( matrix.upper() == 1 && matrix.lower() == 0 );
00200         }
00201 
00217         template<class M1, class M2> void apply( M1& left, M2& right ) const {
00218                 apply( left, right, range(0, std::min( m_matrix.size1(), m_matrix.size2() ) ) );
00219         }
00220 
00221 };
00222 
00223 };
00224 
00225 #endif // _QR_DECOMPOSITION_H
00226