STK++ 0.9.13
STK_IQr.h
Go to the documentation of this file.
1/*--------------------------------------------------------------------*/
2/* Copyright (C) 2004-2016 Serge Iovleff, Université Lille 1, Inria
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this program; if not, write to the
16 Free Software Foundation, Inc.,
17 59 Temple Place,
18 Suite 330,
19 Boston, MA 02111-1307
20 USA
21
22 Contact : S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
23*/
24
25/*
26 * Project: stkpp::Algebra
27 * Purpose: Define The Interface SymEigen Class.
28 * Author: Serge Iovleff, S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
29 **/
30
35#ifndef STK_IQR_H
36#define STK_IQR_H
37
40
43
44#include "STK_Algebra_Util.h"
45#include "STK_Householder.h"
46#include "STK_Givens.h"
47
48#ifdef STK_ALGEBRA_DEBUG
50
51template< class Container2D >
52void print(Container2D const& A, STK::String const& name)
53{
54 stk_cout << "print: " << name << _T("\n";);
55 stk_cout << name << _T(".isRef() =") << A.isRef() << _T("\n");
56 stk_cout << name << _T(".cols() =") << A.cols() << _T("\n");
57 stk_cout << name << _T(".rows() =") << A.rows() << _T("\n\n");
58 stk_cout << name << _T(".rangeCols().isRef() =") << A.rangeCols().isRef() << _T("\n");
59 stk_cout << name << _T(".rangeCols() =\n") << A.rangeCols() << _T("\n");
60}
61
62void print(ArrayXX const& A, STK::String const& name)
63{
64 stk_cout << "print: " << name << _T("\n";);
65 stk_cout << name << _T(".isRef() =") << A.isRef() << _T("\n");
66 stk_cout << name << _T(".cols() =") << A.cols() << _T("\n");
67 stk_cout << name << _T(".rows() =") << A.rows() << _T("\n\n");
68 stk_cout << name << _T(".rangeCols().isRef() =") << A.rangeCols().isRef() << _T("\n");
69 stk_cout << name << _T(".rangeCols() =\n") << A.rangeCols() << _T("\n");
70}
71#endif
72
73namespace STK
74{
100template <class Derived>
101class IQr: public IRunnerBase, public IRecursiveTemplate<Derived>
102{
103 protected:
112 inline IQr( Array const& Q, bool ref = false)
113 : IRunnerBase(), Q_(Q, ref), compq_(false), rank_(0)
114 {
115 if (Q.beginRows() != Q.beginCols())
116 STKRUNTIME_ERROR_NO_ARG(IQR::IQR,Wrong data set: Q.beginRows() must be equal to Q.beginCols());
117 }
121 template<class DerivedExpr>
123 {
124 if (Q.beginRows() != Q.beginCols())
125 { STKRUNTIME_ERROR_NO_ARG(IQR::IQR,Wrong data set: Q.beginRows() must be equal to Q.beginCols());}
126 Q_ = Q.asDerived();
127 }
131 inline IQr( IQr const& decomp)
132 : Q_(decomp.Q_), R_(decomp.R_), compq_(decomp.compq_), rank_(decomp.rank_)
133 {}
134
135 public :
137 inline virtual ~IQr() {}
139 IQr& operator=(IQr const& decomp)
140 {
141 Q_ = decomp.Q_;
142 R_ = decomp.R_;
143 compq_ = decomp.compq_;
144 rank_ = decomp.rank_;
145 return *this;
146 }
147 // getters
149 inline bool isCompQ() const { return compq_;}
151 inline int rank() const { return rank_;}
155 inline Array const& Q() const { return Q_;}
159 inline ArrayUpperTriangularXX const& R() const { return R_;}
160
161 // setters
165 inline void setCompQ(bool compq) { compq_ = compq;}
166
167 // methods
173 virtual bool run();
179 void compQ();
183 void popBackCols(int n =1);
187 void eraseCol(int pos);
191 template<class ColVector_>
192 void pushBackCol(ColVector_ const& T);
198 template<class ColVector_>
199 void insertCol(ColVector_ const& T, int pos);
203 template<class OtherDerived>
205 { Q_ = data.asDerived(); R_.clear(); compq_ = false; rank_ = 0;}
206
207 /* TODO : Delete the ith row and update the QR decomposition
208 * TODO : Add a row with value T and update th QR decomposition
209 */
210 //void popBackRows();
211 //void eraseRows(int pos);
212 //void pushBackRows(RowVector const& T);
213 //void insertRows(RowVector const& T, int pos);
214
215 protected :
221 bool compq_;
223 int rank_;
224};
225
226template<class Derived>
228{
229 // if Q is empty, default values are ok
230 if (Q_.empty()) { compq_ = true; return true;}
231 // compute QR decomposition
232 if (!this->asDerived().runImpl()) return false;
233 // compute Q if asked
234 if (compq_) compQ();
235 // compute rank_ using maximal number of R_
236 int r = R_.beginRows();
237 Real tol = Arithmetic<Real>::epsilon() * std::abs(R_(r,r));
238
239 int n = std::min(R_.endRows(), R_.endCols());
240 for(r= R_.beginRows(), rank_=0; r<n; ++r, ++rank_) { if (std::abs(R_(r,r)) < tol) break;}
241 return true;
242}
243
244template<class Derived>
246{
247#ifdef STK_ALGEBRA_VERBOSE
248 stk_cout << _T("Entering IQr::compQ()") << _T("\n");
249#endif
250 // if Q_ is computed yet
251 if (compq_) return;
252 // number of non zero cols of Q_
253 int ncol = std::min(Q_.sizeRows(), Q_.sizeCols()), lastCol;
254 // add or remove the column
255 if (ncol < Q_.sizeCols())
256 {
257 Q_.popBackCols(Q_.sizeCols() - ncol);
258 Q_.popBackCols(Q_.sizeCols() - ncol);
259 lastCol = Q_.lastIdxCols();
260 }
261 else
262 {
263 lastCol = Q_.lastIdxCols();
264 if (ncol < Q_.sizeRows())
265 {
266 Q_.pushBackCols(Q_.sizeRows() -ncol);
267 // Initialize added columns
268 Q_.col( _R( lastCol+1, Q_.lastIdxCols()) ).setValue(0);
269 for (int i=lastCol+1; i< Q_.endCols(); ++i) { Q_(i, i) = 1.0;}
270 }
271 }
272 // compute other columns
273 for (int i=lastCol; i>=Q_.beginCols(); i--)
274 {
275 // create reference on current householder vector
276 ColVector u(Q_, _R(i, Q_.lastIdxRows()), i);
277 // Apply Householder vector to the right of the matrix
278 applyLeftHouseholderVector( Q_( _R(i, Q_.lastIdxRows()), _R(i+1, Q_.lastIdxCols())), u);
279 // update the ith column
280 Q_( _R(Q_.beginRows(),i-1) , i ) = 0.0; // 0:(i-1)
281 Q_( _R(i+1, Q_.lastIdxRows()), i ) *= Q_(i,i); // (i+1):M
282 Q_( i , i ) += 1.0; // i:i
283 // update the column i
284 }
285 // Q_ is now computed
286 compq_ = true;
287#ifdef STK_ALGEBRA_VERBOSE
288 stk_cout << _T("Terminating IQr::compQ().") << _T("\n");
289#endif
290}
291
292template<class Derived>
293void IQr<Derived>::popBackCols(int n) { R_.popBackCols(n);}
294
295/* Delete the jth column and update the QR decomposition
296 **/
297template<class Derived>
299{
300 if (pos < R_.beginCols())
301 { STKOUT_OF_RANGE_1ARG(Qr::eraseCol,pos,pos<R_.beginCols());}
302 if (R_.lastIdxCols() < pos)
303 { STKOUT_OF_RANGE_1ARG(Qr::eraseCol,pos,pos<R_.lastIdxCols()<pos);}
304 // if Q_ is not computed yet
305 if (!compq_) compQ();
306 // compute the number of iteration for updating to zeroed
307 int niter = std::min(R_.lastIdxCols(), R_.lastIdxRows());//R_.beginCols()-1+std::min(R_.sizeRows(), R_.sizeCols());
308 // Zeroed the remaining elements (z)
309 for (int iter = pos+1; iter<= niter; iter++)
310 {
312 // compute the Givens rotation
313 R_(iter-1, iter) = compGivens( R_(iter-1, iter), R_(iter, iter), cosinus, sinus);
314 R_(iter, iter) = 0.0;
315 // if necessary update R_ and Q_
316 if (sinus)
317 {
318 // create a reference on the sub-ArrayXX
319 ArrayUpperTriangularXX Rsub(R_.col( _R(iter+1, R_.lastIdxCols()) ), true);
320 // Update the next rows (iter1:ncolr_) of R_
321 leftGivens(Rsub, iter-1, iter, cosinus, sinus);
322 // Update the cols of Q_
323 rightGivens(Q_, iter-1, iter, cosinus, sinus);
324 }
325 }
326 // erase the column pos
327 R_.eraseCols(pos);
328 // update the range of the remaining cols of the container
329 R_.update( Range(pos, std::min(R_.lastIdxRows(), R_.lastIdxCols()), 0));
330}
331
332/* Adding the last column and update the QR decomposition. */
333template<class Derived>
334template<class ColVector_>
336{
337 STK_STATIC_ASSERT(ColVector_::structure_==(int)Arrays::vector_||ColVector_::structure_==(int)Arrays::point_,YOU_HAVE_TO_USE_A_VECTOR_OR_POINT_IN_THIS_METHOD)
338 // check conditions
339 if (T.range() != Q_.rows())
340 { STKRUNTIME_ERROR_NO_ARG(Qr::pushBackCol,T.range() != Q_.rows());}
341 // if Q_ is not computed yet
342 if (!compq_) compQ();
343 // Adding a column to R
344 int lastColR = R_.endCols();
345 // Create an auxiliary container
346 VectorX Rncolr = Q_.transpose() * T; // Rncolr of size Q_.cols()
347 // update Q_
348 for (int iter = Q_.lastIdxCols()-1, iter1 = Q_.lastIdxCols(); iter>=lastColR; iter--, iter1--)
349 {
351 // compute the Givens rotation
352 Rncolr[iter] = compGivens( Rncolr[iter], Rncolr[iter1], cosinus, sinus);
353 // apply Givens rotation if necessary
354 if (sinus)
355 { rightGivens(Q_, iter, iter1, cosinus, sinus);}
356 }
357 // update R_
358 R_.pushBackCols();
359 R_.col(lastColR).copy(Rncolr.sub(R_.rangeRowsInCol(lastColR)));
360}
361
362
363/* Add a column with value T at the position pos and update the QR
364 * decomposition.
365 * @param T the column to insert
366 * @param pos the position of the column to insert
367 **/
368template<class Derived>
369template<class ColVector_>
370void IQr<Derived>::insertCol(ColVector_ const& T, int pos)
371{
372 STK_STATIC_ASSERT(ColVector_::structure_==(int)Arrays::vector_||ColVector_::structure_==(int)Arrays::point_,YOU_HAVE_TO_USE_A_VECTOR_OR_POINT_IN_THIS_METHOD)
373 if (pos < R_.beginCols())
374 { STKOUT_OF_RANGE_1ARG(Qr::insertCol,pos,pos<R_.beginCols());}
375 if (R_.lastIdxCols() < pos)
376 { STKOUT_OF_RANGE_1ARG(Qr::insertCol,pos,pos<R_.lastIdxCols()<pos);}
377 if (T.range() != Q_.rows())
378 { STKRUNTIME_ERROR_1ARG(Qr::insertCol,pos,T.range() != Q_.rows());}
379 // if Q_ is not computed yet
380 if (!compq_) compQ();
381 // Adding a column to R
382 R_.insertCols(pos);
383 // update the range of the remaining cols of R_
384 R_.update( _R(pos+1, std::min(R_.lastIdxRows(), R_.lastIdxCols())) );
385 for (int i=pos+1; i< std::min(R_.endRows(), R_.endCols()); ++i) R_(i,i) = 0.0;
386
387 VectorX Rpos = Q_.transpose() * T;
388 // Zeroed the unwanted elements
389 for (int iter= Q_.lastIdxCols(), iterm1= Q_.lastIdxCols()-1; iter>pos; iterm1--, iter--)
390 {
392 // compute the Givens rotation
394 // apply Givens rotation if necessary
395 if (sinus)
396 {
397 // create a reference on the sub-ArrayXX
398 ArrayUpperTriangularXX Rsub(R_.col(_R(iter, R_.lastIdxCols())), true);
399 // Update the next rows (iter:ncolr_) of R_
401 // Update the cols of Q_
402 rightGivens(Q_, iterm1, iter, cosinus, sinus);
403 }
404 }
405 // update R_
406 R_.col(pos) = Rpos.sub(R_.rangeRowsInCol(pos));
407 R_.update(pos);
408}
409
410} // namespace STK
411
412#endif //STK_IQR_H
In this file we define and implement utilies class and method for the Algebra project.
In this file we define the ArrayXXTriangular class.
A Array2DVector is a one dimensional horizontal container.
This file define methods for displaying Arrays and Expressions.
In this file we define Givens methods used by the Algebra classes.
In this file we define the Housholder methods used by the Algebra classes.
In this file we define the Interface base class for all the running classes.
#define STKOUT_OF_RANGE_1ARG(Where, Arg, Error)
Definition STK_Macros.h:93
#define STKRUNTIME_ERROR_1ARG(Where, Arg, Error)
Definition STK_Macros.h:129
#define STKRUNTIME_ERROR_NO_ARG(Where, Error)
Definition STK_Macros.h:138
#define _R(first, last)
Utility macro that can be used in a similar way that first:last.
Definition STK_Range.h:53
In this file we define the fundamental type Real.
#define STK_STATIC_ASSERT(COND, MSG)
#define stk_cout
Standard stk output stream.
#define _T(x)
Let x unmodified.
void clear()
clear the object.
The class IQr is an interface class for the method computing the QR Decomposition of a ArrayXX.
Definition STK_IQr.h:102
virtual ~IQr()
virtual destructor
Definition STK_IQr.h:137
virtual bool run()
Compute the QR decomposition.
Definition STK_IQr.h:227
void compQ()
Compute Q (to use after run).
Definition STK_IQr.h:245
IQr & operator=(IQr const &decomp)
Operator = : overwrite the this with decomp.
Definition STK_IQr.h:139
hidden::AlgebraTraits< Derived >::RowVector RowVector
Definition STK_IQr.h:106
hidden::AlgebraTraits< Derived >::Array Array
Definition STK_IQr.h:104
int rank() const
Definition STK_IQr.h:151
ArrayUpperTriangularXX R_
R Array of th QR decomposition.
Definition STK_IQr.h:219
Array const & Q() const
give the matrix Q of the QR decomposition.
Definition STK_IQr.h:155
void pushBackCol(ColVector_ const &T)
Add a column with value T and update th QR decomposition.
Definition STK_IQr.h:335
IQr(ExprBase< DerivedExpr > const &Q)
Constructor.
Definition STK_IQr.h:122
Array Q_
Q Array of the QR decomposition.
Definition STK_IQr.h:217
void setData(ExprBase< OtherDerived > const &data)
overloading of setData.
Definition STK_IQr.h:204
ArrayUpperTriangularXX const & R() const
give the matrix R of the QR decomposition.
Definition STK_IQr.h:159
void popBackCols(int n=1)
Delete the n last columns and update the QR decomposition.
Definition STK_IQr.h:293
int rank_
estimated rank_ of the matrix A
Definition STK_IQr.h:223
bool isCompQ() const
Definition STK_IQr.h:149
void eraseCol(int pos)
Delete the column pos and update the QR decomposition.
Definition STK_IQr.h:298
IQr(Array const &Q, bool ref=false)
Constructor.
Definition STK_IQr.h:112
bool compq_
is Q computed ?
Definition STK_IQr.h:221
hidden::AlgebraTraits< Derived >::ColVector ColVector
Definition STK_IQr.h:105
void setCompQ(bool compq)
Set the compq_ flag.
Definition STK_IQr.h:165
IQr(IQr const &decomp)
Copy constructor.
Definition STK_IQr.h:131
void insertCol(ColVector_ const &T, int pos)
Add a column with value T at the position pos and update the QR decomposition.
Definition STK_IQr.h:370
Interface base class for all classes implementing the curious recursive template paradigm.
Abstract base class for all classes having a.
Definition STK_IRunner.h:65
virtual void update()
update the runner.
The MultidimRegression class allows to regress a multidimensional output variable among a multivariat...
void rightGivens(ArrayBase< TContainer2D > &M, int j1, int j2, typename TContainer2D::Type const &cosinus, typename TContainer2D::Type const &sinus)
Apply Givens rotation.
Definition STK_Givens.h:119
Real compGivens(Type const &y, Type const &z, Type &cosinus, Type &sinus)
Compute Givens rotation.
Definition STK_Givens.h:75
void applyLeftHouseholderVector(ArrayBase< Lhs > const &M, ExprBase< Rhs > const &v)
left multiplication by a Householder vector.
void leftGivens(ArrayBase< TContainer2D > &M, int i1, int i2, typename TContainer2D::Type const &cosinus, typename TContainer2D::Type const &sinus)
left multiplication by a Givens ArrayXX.
Definition STK_Givens.h:148
@ point_
row oriented vector/array/expression
@ vector_
column oriented vector/array/expression
std::basic_string< Char > String
STK fundamental type of a String.
double Real
STK fundamental type of Real values.
The namespace STK is the main domain space of the Statistical ToolKit project.
TRange< UnknownSize > Range
Definition STK_Range.h:59
Arithmetic properties of STK fundamental types.
traits class for the algebra methods.