TooN 2.1
|
00001 //-*- c++ -*- 00002 00003 // Copyright (C) 2012, Edward Rosten (ed@edwardrosten.com) 00004 // 00005 // This file is part of the TooN Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 2, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // You should have received a copy of the GNU General Public License along 00017 // with this library; see the file COPYING. If not, write to the Free 00018 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 00019 // USA. 00020 00021 // As a special exception, you may use this file as part of a free software 00022 // library without restriction. Specifically, if other files instantiate 00023 // templates or use macros or inline functions from this file, or you compile 00024 // this file and link it with other files to produce an executable, this 00025 // file does not by itself cause the resulting executable to be covered by 00026 // the GNU General Public License. This exception does not however 00027 // invalidate any other reasons why the executable file might be covered by 00028 // the GNU General Public License. 00029 00030 00031 #ifndef TOON_INC_QR_H 00032 #define TOON_INC_QR_H 00033 #include <TooN/TooN.h> 00034 #include <cmath> 00035 00036 namespace TooN 00037 { 00038 /** 00039 Performs %QR decomposition. 00040 00041 @warning this will only work if the number of columns is greater than 00042 the number of rows! 00043 00044 The QR decomposition operates on a matrix A. 00045 In general: 00046 \f[ 00047 A = QR 00048 \f] 00049 00050 @ingroup gDecomps 00051 */ 00052 template<int Rows=Dynamic, int Cols=Rows, typename Precision=double> class QR 00053 { 00054 00055 private: 00056 static const int square_Size = (Rows>=0 && Cols>=0)?(Rows<Cols?Rows:Cols):Dynamic; 00057 00058 public: 00059 /// Construct the %QR decomposition of a matrix. This initialises the class, and 00060 /// performs the decomposition immediately. 00061 /// @param m The matrix to decompose 00062 template<int R, int C, class P, class B> 00063 QR(const Matrix<R,C,P,B>& m_) 00064 :m(m_), Q(Identity(square_size())) 00065 { 00066 //pivot is set to all zeros, which means all columns are free columns 00067 //and can take part in column pivoting. 00068 00069 compute(); 00070 } 00071 00072 ///Return R 00073 const Matrix<Rows, Cols, Precision>& get_R() 00074 { 00075 return m; 00076 } 00077 00078 ///Return Q 00079 const Matrix<square_Size, square_Size, Precision, ColMajor>& get_Q() 00080 { 00081 return Q; 00082 } 00083 00084 private: 00085 00086 template<class B1, class B2> 00087 void pre_multiply_by_householder(Matrix<Dynamic, Dynamic, Precision, B1>& A, const Vector<Dynamic, Precision, B2>& v, Precision s) 00088 { 00089 //The Householder matrix is P = 1 - v*v/s 00090 00091 //PA = (1 - v*v^T/s) A = A - v*v^T A 00092 // 00093 // [ v1 ] [ v1 v2 v2 v4 ] [ | | ] 00094 // = A - [ v2 ] [ a1 | a2 | ... ] 00095 // [ v3 ] [ | | ] 00096 // [ v4 ] [ | | ] 00097 00098 // [ v1 ] [ va1 va2 va3 va4 ] 00099 // = A - [ v2 ] 00100 // [ v3 ] 00101 // [ v4 ] 00102 00103 // [ v1 (v a1) ] 00104 // = A - [ v2 (v a2) ] 00105 // [ v3 (v a3) ] 00106 // [ v4 (v a4) ] 00107 00108 for(int col=0; col < A.num_cols(); col++) 00109 { 00110 Precision va = v * A.T()[col] / s; 00111 00112 for(int row=0; row < A.num_rows(); row++) 00113 A[row][col] -= v[row] * va; 00114 } 00115 } 00116 00117 void compute() 00118 { 00119 00120 //QR decomposition makes use of Householder reflections. 00121 // A = QR, 00122 00123 //Q1 A = Q1 QR 00124 // Q2 Q1 A = Q2 Q1 R 00125 // ... 00126 // Q^-1 A = R 00127 // 00128 // Pick a sequence of Qn which makes R upper triangular. 00129 // 00130 // The sequence Qn ... Q1 is equal to Q^-1 00131 // 00132 // Qi has the form of a Householder reflection 00133 00134 for(int n=0; n < square_size()-1; n++) 00135 { 00136 using std::sqrt; 00137 00138 int sz = square_size() - n; 00139 int nc = m.num_cols() - n; 00140 00141 //Compute the reflection on a submatrix 00142 //such that it never breaks the triangular 00143 //properties of the matrix being created. 00144 00145 Matrix<Dynamic, Dynamic, Precision, typename Matrix<Rows,Cols,Precision>::SliceBase> s = m.slice(n, n, sz, nc); 00146 00147 //Now perform a householder reduction on the first column 00148 00149 //Define x to be the first column 00150 //auto x = s.T()[0]; 00151 00152 00153 //The reflection vector is u = x - |x| * [ 1 0 ... 0] * sgn(x_0) 00154 // 00155 //let a = |x| * sgn(x_0]) 00156 00157 Precision nx2 = norm_sq(s.T()[0]); 00158 00159 Precision a = sqrt(nx2) * (s.T()[0][0] < 0?-1:1); 00160 00161 //We now want the vector u = x - ae 00162 // 00163 // Multipling (I - 2 hat(u) * hat(u)^T) * s will zero out the first column of s except 00164 // for the first element. The matrix P = is orthogonal, a bit like Qn 00165 // 00166 //Since x is no longer needed, we can just modify the first element 00167 s.T()[0][0] -= a; 00168 //auto& u = x; 00169 00170 //We want H = norm_sq(u)/2 = a (a - x_0) = a * -u_0 00171 Precision H = -a * s.T()[0][0]; 00172 00173 00174 //Note that we're working on a reduced sized matrix here. 00175 // 00176 //The actual householder matrix, P, is: 00177 // 00178 // [ 1 | 0 ] 00179 // [___1|_____________] 00180 // [ |[ ^ ^T ] ] 00181 // [ 0 |[ u * u ] ] 00182 // [ |[ ] ] 00183 00184 // We want m <- P * m 00185 // and Q <- P * Q 00186 // 00187 // 00188 // Since m is going towards upper triangular and so has lots of zeros 00189 // we can compute it by performing the multiplication in just the 00190 // lower block: 00191 // 00192 00193 // [ 1 | 0 ] [ m1 | m2 ] [ m1 | m2 ] 00194 // [___1|_____________] [____|_______ ] [____|______] 00195 // [ |[ ^ ^T ] ] [ | ] = [ | ] 00196 // [ 0 |[I-u* u ] ] [ 0 | m3 ] [ 0 | .... ] 00197 // [ |[ ] ] [ | ] [ | ] 00198 00199 // Q does not have the column of zeros, so the multiplication has to be performed on 00200 // the whole width 00201 00202 //This can be done in place except that the first column of s holds u 00203 pre_multiply_by_householder(s.slice(0, 1, sz, nc-1).ref(), s.T()[0], H); 00204 00205 //Also update the Q matrix 00206 pre_multiply_by_householder(Q.slice(n,0,sz,square_size()).ref(), s.T()[0], H); 00207 00208 //Now do the first column multiplication... 00209 //Which makes it upper triangular. 00210 00211 s[0][0] = a; 00212 s.T()[0].slice(1, sz-1) = Zeros; 00213 00214 } 00215 00216 //Note above that we've build up Q^-1, so we need to transpose Q now 00217 //to invert it 00218 00219 using std::swap; 00220 for(int r=0; r < Q.num_rows(); r++) 00221 for(int c=r+1; c < Q.num_cols(); c++) 00222 swap(Q[r][c], Q[c][r]); 00223 00224 } 00225 00226 Matrix<Rows, Cols, Precision> m; 00227 Matrix<square_Size, square_Size, Precision, ColMajor> Q; 00228 00229 00230 int square_size() 00231 { 00232 return std::min(m.num_rows(), m.num_cols()); 00233 } 00234 }; 00235 00236 00237 00238 00239 00240 00241 } 00242 00243 #endif