TooN
QR.h
1 //-*- c++ -*-
2 
3 // Copyright (C) 2012, Edward Rosten (ed@edwardrosten.com)
4 
5 //All rights reserved.
6 //
7 //Redistribution and use in source and binary forms, with or without
8 //modification, are permitted provided that the following conditions
9 //are met:
10 //1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 //THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
17 //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 //IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 //ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
20 //LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 //CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 //SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 //INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 //CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 //ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 //POSSIBILITY OF SUCH DAMAGE.
27 
28 
29 #ifndef TOON_INC_QR_H
30 #define TOON_INC_QR_H
31 #include <TooN/TooN.h>
32 #include <algorithm>
33 #include <cmath>
34 
35 namespace TooN
36 {
51 template<int Rows=Dynamic, int Cols=Rows, typename Precision=double> class QR
52 {
53 
54  private:
55  static const int square_Size = (Rows>=0 && Cols>=0)?(Rows<Cols?Rows:Cols):Dynamic;
56 
57  public:
61  template<int R, int C, class P, class B>
62  QR(const Matrix<R,C,P,B>& m_)
63  :m(m_), Q(Identity(square_size()))
64  {
65  //pivot is set to all zeros, which means all columns are free columns
66  //and can take part in column pivoting.
67 
68  compute();
69  }
70 
73  {
74  return m;
75  }
76 
79  {
80  return Q;
81  }
82 
83  private:
84 
85  template<class B1, class B2>
86  void pre_multiply_by_householder(Matrix<Dynamic, Dynamic, Precision, B1>& A, const Vector<Dynamic, Precision, B2>& v, Precision s)
87  {
88  //The Householder matrix is P = 1 - v*v/s
89 
90  //PA = (1 - v*v^T/s) A = A - v*v^T A
91  //
92  // [ v1 ] [ v1 v2 v2 v4 ] [ | | ]
93  // = A - [ v2 ] [ a1 | a2 | ... ]
94  // [ v3 ] [ | | ]
95  // [ v4 ] [ | | ]
96 
97  // [ v1 ] [ va1 va2 va3 va4 ]
98  // = A - [ v2 ]
99  // [ v3 ]
100  // [ v4 ]
101 
102  // [ v1 (v a1) ]
103  // = A - [ v2 (v a2) ]
104  // [ v3 (v a3) ]
105  // [ v4 (v a4) ]
106 
107  for(int col=0; col < A.num_cols(); col++)
108  {
109  Precision va = v * A.T()[col] / s;
110 
111  for(int row=0; row < A.num_rows(); row++)
112  A[row][col] -= v[row] * va;
113  }
114  }
115 
116  void compute()
117  {
118 
119  //QR decomposition makes use of Householder reflections.
120  // A = QR,
121 
122  //Q1 A = Q1 QR
123  // Q2 Q1 A = Q2 Q1 R
124  // ...
125  // Q^-1 A = R
126  //
127  // Pick a sequence of Qn which makes R upper triangular.
128  //
129  // The sequence Qn ... Q1 is equal to Q^-1
130  //
131  // Qi has the form of a Householder reflection
132 
133  for(int n=0; n < square_size()-1; n++)
134  {
135  using std::sqrt;
136 
137  int sz = square_size() - n;
138  int nc = m.num_cols() - n;
139 
140  //Compute the reflection on a submatrix
141  //such that it never breaks the triangular
142  //properties of the matrix being created.
143 
145 
146  //Now perform a householder reduction on the first column
147 
148  //Define x to be the first column
149  //auto x = s.T()[0];
150 
151 
152  //The reflection vector is u = x - |x| * [ 1 0 ... 0] * sgn(x_0)
153  //
154  //let a = |x| * sgn(x_0])
155 
156  Precision nx2 = norm_sq(s.T()[0]);
157 
158  Precision a = sqrt(nx2) * (s.T()[0][0] < 0?-1:1);
159 
160  //We now want the vector u = x - ae
161  //
162  // Multipling (I - 2 hat(u) * hat(u)^T) * s will zero out the first column of s except
163  // for the first element. The matrix P = is orthogonal, a bit like Qn
164  //
165  //Since x is no longer needed, we can just modify the first element
166  s.T()[0][0] -= a;
167  //auto& u = x;
168 
169  //We want H = norm_sq(u)/2 = a (a - x_0) = a * -u_0
170  Precision H = -a * s.T()[0][0];
171 
172 
173  //Note that we're working on a reduced sized matrix here.
174  //
175  //The actual householder matrix, P, is:
176  //
177  // [ 1 | 0 ]
178  // [___1|_____________]
179  // [ |[ ^ ^T ] ]
180  // [ 0 |[ u * u ] ]
181  // [ |[ ] ]
182 
183  // We want m <- P * m
184  // and Q <- P * Q
185  //
186  //
187  // Since m is going towards upper triangular and so has lots of zeros
188  // we can compute it by performing the multiplication in just the
189  // lower block:
190  //
191 
192  // [ 1 | 0 ] [ m1 | m2 ] [ m1 | m2 ]
193  // [___1|_____________] [____|_______ ] [____|______]
194  // [ |[ ^ ^T ] ] [ | ] = [ | ]
195  // [ 0 |[I-u* u ] ] [ 0 | m3 ] [ 0 | .... ]
196  // [ |[ ] ] [ | ] [ | ]
197 
198  // Q does not have the column of zeros, so the multiplication has to be performed on
199  // the whole width
200 
201  //This can be done in place except that the first column of s holds u
202  pre_multiply_by_householder(s.slice(0, 1, sz, nc-1).ref(), s.T()[0], H);
203 
204  //Also update the Q matrix
205  pre_multiply_by_householder(Q.slice(n,0,sz,square_size()).ref(), s.T()[0], H);
206 
207  //Now do the first column multiplication...
208  //Which makes it upper triangular.
209 
210  s[0][0] = a;
211  s.T()[0].slice(1, sz-1) = Zeros;
212 
213  }
214 
215  //Note above that we've build up Q^-1, so we need to transpose Q now
216  //to invert it
217 
218  using std::swap;
219  for(int r=0; r < Q.num_rows(); r++)
220  for(int c=r+1; c < Q.num_cols(); c++)
221  swap(Q[r][c], Q[c][r]);
222 
223  }
224 
227 
228 
229  int square_size()
230  {
231  return std::min(m.num_rows(), m.num_cols());
232  }
233 };
234 
235 
236 
237 
238 
239 
240 }
241 
242 #endif
const Matrix< square_Size, square_Size, Precision, ColMajor > & get_Q()
Return Q.
Definition: QR.h:78
Matrix & ref()
return me as a non const reference - useful for temporaries
Definition: matrix.hh:298
Pretty generic SFINAE introspection generator.
Definition: vec_test.cc:21
A vector.
Definition: vector.hh:126
Precision norm_sq(const Vector< Size, Precision, Base > &v)
Compute the norm of v.
Definition: helpers.h:106
const Matrix< Rows, Cols, Precision > & get_R()
Return R.
Definition: QR.h:72
QR(const Matrix< R, C, P, B > &m_)
Construct the QR decomposition of a matrix.
Definition: QR.h:62
Matrix< R, C, P > sqrt(const Matrix< R, C, P, B > &m)
computes a matrix square root of a matrix m by the product form of the Denman and Beavers iteration a...
Definition: helpers.h:350
Performs QR decomposition.
Definition: QR.h:51