1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2018 - 2020 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_qr_h
17 #define dealii_qr_h
18 
19 #include <deal.II/base/config.h>
20 
21 #include <deal.II/base/exceptions.h>
22 
23 #include <deal.II/lac/lapack_full_matrix.h>
24 #include <deal.II/lac/utilities.h>
25 
26 #include <boost/signals2/signal.hpp>
27 
28 #include <memory>
29 
30 DEAL_II_NAMESPACE_OPEN
31 
32 /**
33  * A base class for thin QR implementations.
34  *
35  * This class and classes derived from it are meant to build $Q$ and $R$
36  * matrices one row/column at a time, i.e., by growing $R$ matrix from an empty
37  * $0\times 0$ matrix to $N\times N$, where $N$ is the number of added column
38  * vectors.
39  *
40  * As a consequence, matrices which have the same number of rows as each vector
41  * (i.e. $Q$ matrix) is stored as a collection of vectors of `VectorType`.
42  */
43 template <typename VectorType>
44 class BaseQR
45 {
46   /**
47    * Number type for R matrix.
48    */
49   using Number = typename VectorType::value_type;
50 
51 protected:
52   /**
53    * Default private constructor.
54    */
55   BaseQR();
56 
57 public:
58   /**
59    * Destructor.
60    */
61   virtual ~BaseQR() = default;
62 
63   /**
64    * Append @p column to the QR factorization.
65    * Returns <code>true</code> if the result is successful, i.e.
66    * the columns are linearly independent. Otherwise the @p column
67    * is rejected and the return value is <code>false</code>.
68    */
69   virtual bool
70   append_column(const VectorType &column) = 0;
71 
72   /**
73    * Remove a column @p k and update QR factorization.
74    */
75   virtual void
76   remove_column(const unsigned int k = 0) = 0;
77 
78   /**
79    * Return size of the subspace.
80    */
81   unsigned int
82   size() const;
83 
84   /**
85    * Return the current upper triangular matrix R.
86    */
87   const LAPACKFullMatrix<Number> &
88   get_R() const;
89 
90   /**
91    * Solve $Rx=y$. Vectors @p x and @p y should be consistent
92    * with the current size of the subspace.
93    * If @p transpose is <code>true</code>, $R^Tx=y$ is solved instead.
94    */
95   void
96   solve(Vector<Number> &      x,
97         const Vector<Number> &y,
98         const bool            transpose = false) const;
99 
100   /**
101    * Set $y = Qx$. The size of $x$ should be consistent with the
102    * size of the R matrix.
103    */
104   virtual void
105   multiply_with_Q(VectorType &y, const Vector<Number> &x) const = 0;
106 
107   /**
108    * Set $y = Q^Tx$. The size of $x$ should be consistent with the
109    * size of column vectors.
110    */
111   virtual void
112   multiply_with_QT(Vector<Number> &y, const VectorType &x) const = 0;
113 
114   /**
115    * Set $y = QRx$. The size of $x$ should be consistent with the
116    * size of the R matrix.
117    */
118   virtual void
119   multiply_with_A(VectorType &y, const Vector<Number> &x) const = 0;
120 
121   /**
122    * Set $y = R^T Q^Tx$. The size of $x$ should be consistent with the
123    * size of column vectors.
124    */
125   virtual void
126   multiply_with_AT(Vector<Number> &y, const VectorType &x) const = 0;
127 
128   /**
129    * Connect a slot to retrieve a notification when the Givens rotations
130    * are performed.
131    *
132    * The function takes two indices, @p i and @p j, describing the plane of
133    * rotation, and a triplet of numbers @p csr (cosine, sine and radius, see
134    * Utilities::LinearAlgebra::givens_rotation()) which represents the rotation
135    * matrix.
136    */
137   boost::signals2::connection
138   connect_givens_slot(
139     const std::function<void(const unsigned int           i,
140                              const unsigned int           j,
141                              const std::array<Number, 3> &csr)> &slot);
142 
143 protected:
144   /**
145    * Compute $y=Hx$ where $H$ is the matrix formed by the column vectors stored
146    * by this object.
147    */
148   void
149   multiply_with_cols(VectorType &y, const Vector<Number> &x) const;
150 
151   /**
152    * Multiply with transpose columns stored in the object.
153    */
154   void
155   multiply_with_colsT(Vector<Number> &y, const VectorType &x) const;
156 
157   /**
158    * A vector of unique pointers to store columns.
159    */
160   std::vector<std::unique_ptr<VectorType>> columns;
161 
162   /**
163    * Matrix to store R.
164    */
165   LAPACKFullMatrix<Number> R;
166 
167   /**
168    * Current size (number of columns in Q).
169    */
170   unsigned int current_size;
171 
172   /**
173    * Signal used to retrieve a notification
174    * when Givens rotations are performed in the `(i,j)`-plane.
175    */
176   boost::signals2::signal<void(const unsigned int i,
177                                const unsigned int j,
178                                const std::array<Number, 3> &)>
179     givens_signal;
180 };
181 
182 // clang-format off
183 /**
184  * A class to compute and store the QR factorization of a matrix represented by a set of column vectors.
185  *
186  * The class is design to update a given (possibly empty) QR factorization
187  * of a matrix $A$ (constructed incrementally by providing its columns)
188  * due to the addition of a new column vector to $A$. This is equivalent to
189  * constructing an orthonormal basis by the Gram-Schmidt procedure.
190  * The class also provides update functionality when the first column
191  * is removed.
192  *
193  * The `VectorType` template argument may either be a parallel and serial vector, and only need
194  * to have basic operations such as additions, scalar product, etc.
195  * It also needs to have a copy-constructor.
196  *
197  * See sections 6.5.2-6.5.3 on pp. 335-338 in
198  * @code{.bib}
199  * @Book{Golub2013,
200  *   title     = {Matrix computations},
201  *   publisher = {Johns Hopkins University Press},
202  *   year      = {2013},
203  *   author    = {Golub, Gene H and Van Loan, Charles F},
204  *   edition   = {4},
205  *  }
206  * @endcode
207  * as well as
208  * @code{.bib}
209  * @article{Daniel1976,
210  *   author   = {Daniel, James W and Gragg, Walter Bill and Kaufman, Linda and Stewart, Gilbert W},
211  *   title    = {{Reorthogonalization and stable algorithms for updating the Gram-Schmidt QR factorization}},
212  *   journal  = {Mathematics of Computation},
213  *   year     = {1976},
214  *   volume   = {30},
215  *   number   = {136},
216  *   pages    = {772--795},
217  * }
218  * @Article{Reichel1990,
219  *   author     = {Reichel, L. and Gragg, W. B.},
220  *   title      = {{Algorithm 686: FORTRAN Subroutines for Updating the QR Decomposition}},
221  *   journal    = {ACM Trans. Math. Softw.},
222  *   year       = {1990},
223  *   volume     = {16},
224  *   number     = {4},
225  *   pages      = {369--377},
226  *   month      = dec,
227  *   issn       = {0098-3500},
228  *   acmid      = {98291},
229  *   address    = {New York, NY, USA},
230  *   doi        = {10.1145/98267.98291},
231  *   issue_date = {Dec. 1990},
232  *   numpages   = {9},
233  *   publisher  = {ACM},
234  *   url        = {http://doi.acm.org/10.1145/98267.98291},
235  *  }
236  * @endcode
237  */
238 // clang-format on
239 template <typename VectorType>
240 class QR : public BaseQR<VectorType>
241 {
242 public:
243   /**
244    * Number type for R matrix.
245    */
246   using Number = typename VectorType::value_type;
247 
248   /**
249    * Default constructor.
250    */
251   QR();
252 
253   /**
254    * Destructor.
255    */
256   virtual ~QR() = default;
257 
258   /**
259    * @copydoc BaseQR::append_column
260    *
261    * @note Currently this function always returns <code>true</code>.
262    */
263   virtual bool
264   append_column(const VectorType &column);
265 
266   /**
267    * Remove first column and update QR factorization.
268    *
269    * Starting from the given QR decomposition
270    * $QR= A = [a_1\,\dots a_n], \quad a_i \in {\mathbb R}^m$
271    * we aim at computing factorization of
272    * $\tilde Q \tilde R= \tilde A = [a_2\,\dots a_n], \quad a_i \in {\mathbb
273    * R}^m$.
274    *
275    * The standard approach is to partition $R$ as
276    * \f[
277    * R =
278    * \begin{bmatrix}
279    * r_{11} & w^T \\
280    * 0      & R_{33}
281    * \end{bmatrix}
282    * \f]
283    * It then follows that
284    * \f[
285    * Q^T \tilde A =
286    * \begin{bmatrix}
287    * 0 & w^T \\
288    * 0 & R_{33}
289    * \end{bmatrix}
290    * \f]
291    * is upper Hessenberg where unwanted sub-diagonal elements can be
292    * zeroed by a sequence of Givens rotations.
293    *
294    * Note that $\tilde R^T \tilde R = \tilde A^T \tilde A$,
295    * where the RHS is included in $A^T A = R^T R$. Therefore
296    * $\tilde R$ can be obtained by Cholesky decomposition.
297    */
298   virtual void
299   remove_column(const unsigned int k = 0);
300 
301   virtual void
302   multiply_with_Q(VectorType &y, const Vector<Number> &x) const;
303 
304   virtual void
305   multiply_with_QT(Vector<Number> &y, const VectorType &x) const;
306 
307   virtual void
308   multiply_with_A(VectorType &y, const Vector<Number> &x) const;
309 
310   virtual void
311   multiply_with_AT(Vector<Number> &y, const VectorType &x) const;
312 
313 private:
314   /**
315    * Apply givens rotation in the `(i,j)`-plane to @p Q and @p R so that
316    * <code>R(k,k)</code> is zeroed.
317    *
318    * See Chapter 5.1.9 of Golub 2013, Matrix computations.
319    */
320   void
321   apply_givens_rotation(const unsigned int i, const unsigned int k);
322 
323   /**
324    * Temporary vector needed to do Givens rotation of Q.
325    */
326   VectorType tmp;
327 };
328 
329 
330 
331 /**
332  * A class to obtain the triangular $R$ matrix of the $A=QR$ factorization
333  * together with the matrix $A$ itself. The orthonormal matrix $Q$ is not stored
334  * explicitly, the name of the class.
335  * The multiplication with $Q$ can be represented as $Q=A R^{-1}$, whereas the
336  * multiplication with $Q^T$ is given by $Q^T=R^{-T}A^T$.
337  *
338  * The class is designed to update a given (possibly empty) QR factorization
339  * due to the addition of a new column vector. This is equivalent to
340  * constructing an orthonormal basis by the Gram-Schmidt procedure.
341  * The class also provides update functionality when the column
342  * is removed.
343  *
344  * The `VectorType` template argument may either be a parallel and serial
345  * vector, and only need to have basic operations such as additions, scalar
346  * product, etc. It also needs to have a copy-constructor.
347  */
348 template <typename VectorType>
349 class ImplicitQR : public BaseQR<VectorType>
350 {
351 public:
352   /**
353    * Number type for R matrix.
354    */
355   using Number = typename VectorType::value_type;
356 
357   /**
358    * Default constructor.
359    */
360   ImplicitQR();
361 
362   /**
363    * Destructor.
364    */
365   virtual ~ImplicitQR() = default;
366 
367   virtual bool
368   append_column(const VectorType &column);
369 
370   /**
371    * Remove column and update QR factorization.
372    *
373    * Starting from the given QR decomposition
374    * $QR= A = [a_1\,\dots a_n], \quad a_i \in R^m$
375    * we aim at computing factorization of
376    * $\tilde Q \tilde R= \tilde A = [a_2\,\dots a_n], \quad a_i \in R^m$.
377    *
378    * Note that $\tilde R^T \tilde R = \tilde A^T \tilde A$,
379    * where the RHS is included in $A^T A = R^T R$. Therefore
380    * $\tilde R$ can be obtained by Cholesky decomposition.
381    */
382   virtual void
383   remove_column(const unsigned int k = 0);
384 
385   virtual void
386   multiply_with_Q(VectorType &y, const Vector<Number> &x) const;
387 
388   virtual void
389   multiply_with_QT(Vector<Number> &y, const VectorType &x) const;
390 
391   virtual void
392   multiply_with_A(VectorType &y, const Vector<Number> &x) const;
393 
394   virtual void
395   multiply_with_AT(Vector<Number> &y, const VectorType &x) const;
396 
397   /**
398    * Connect a slot to implement a custom check of linear dependency
399    * during addition of a column.
400    *
401    * Here, @p u is the last column of the to-be R matrix, @p rho
402    * is its diagonal and @p col_norm_sqr is the square of the $l2$ norm of the column.
403    * The function should return <code>true</code> if the new column is
404    * linearly independent.
405    */
406   boost::signals2::connection
407   connect_append_column_slot(
408     const std::function<bool(const Vector<Number> &u,
409                              const Number &        rho2,
410                              const Number &        col_norm_sqr)> &slot);
411 
412 private:
413   /**
414    * Apply givens rotation in the `(i,k)`-plane to zero out $R(k,k)$.
415    */
416   void
417   apply_givens_rotation(const unsigned int i, const unsigned int k);
418 
419   /**
420    * Signal used to decide if the new column is linear dependent.
421    *
422    * Here, @p u is the last column of the to-be R matrix, @p rho
423    * is its diagonal and @p col_norm_sqr is the square of the $l2$ norm of the column.
424    * The function should return <code>true</code> if the new column is
425    * linearly independent.
426    */
427   boost::signals2::signal<bool(const Vector<Number> &u,
428                                const Number &        rho,
429                                const Number &        col_norm_sqr)>
430     column_signal;
431 };
432 
433 // -------------------  inline and template functions ----------------
434 #ifndef DOXYGEN
435 
436 namespace internal
437 {
438   namespace QRImplementation
439   {
440     // We want to avoid including our own LAPACK wrapper header in any external
441     // headers to avoid possible conflicts with other packages that may define
442     // their own such header. At the same time we want to be able to call some
443     // LAPACK functions from the template functions below. To resolve both
444     // problems define some extra wrappers here that can be in the header:
445     template <typename Number>
446     void
447     call_trmv(const char            uplo,
448               const char            trans,
449               const char            diag,
450               const types::blas_int n,
451               const Number *        a,
452               const types::blas_int lda,
453               Number *              x,
454               const types::blas_int incx);
455 
456     template <typename Number>
457     void
458     call_trtrs(const char            uplo,
459                const char            trans,
460                const char            diag,
461                const types::blas_int n,
462                const types::blas_int nrhs,
463                const Number *        a,
464                const types::blas_int lda,
465                Number *              b,
466                const types::blas_int ldb,
467                types::blas_int *     info);
468   } // namespace QRImplementation
469 } // namespace internal
470 
471 
472 
473 template <typename VectorType>
BaseQR()474 BaseQR<VectorType>::BaseQR()
475   : current_size(0)
476 {
477   R.set_property(LAPACKSupport::upper_triangular);
478 }
479 
480 
481 
482 template <typename VectorType>
483 unsigned int
size()484 BaseQR<VectorType>::size() const
485 {
486   return current_size;
487 }
488 
489 
490 
491 template <typename VectorType>
492 const LAPACKFullMatrix<typename BaseQR<VectorType>::Number> &
get_R()493 BaseQR<VectorType>::get_R() const
494 {
495   return R;
496 }
497 
498 
499 
500 template <typename VectorType>
501 void
solve(Vector<Number> & x,const Vector<Number> & y,const bool transpose)502 BaseQR<VectorType>::solve(Vector<Number> &      x,
503                           const Vector<Number> &y,
504                           const bool            transpose) const
505 {
506   Assert(x.size() == this->current_size,
507          ExcDimensionMismatch(x.size(), this->current_size));
508   Assert(y.size() == this->current_size,
509          ExcDimensionMismatch(y.size(), this->current_size));
510 
511   // copy if the two vectors are not the same
512   if (&x != &y)
513     x = y;
514 
515   const int lda   = this->current_size;
516   const int ldb   = this->current_size;
517   const int N     = this->current_size;
518   const int n_rhs = 1;
519   int       info  = 0;
520   internal::QRImplementation::call_trtrs('U',
521                                          transpose ? 'T' : 'N',
522                                          'N',
523                                          N,
524                                          n_rhs,
525                                          &this->R(0, 0),
526                                          lda,
527                                          &x(0),
528                                          ldb,
529                                          &info);
530 }
531 
532 
533 
534 template <typename VectorType>
535 void
multiply_with_cols(VectorType & y,const Vector<Number> & x)536 BaseQR<VectorType>::multiply_with_cols(VectorType &          y,
537                                        const Vector<Number> &x) const
538 {
539   Assert(x.size() == this->current_size,
540          ExcDimensionMismatch(x.size(), this->current_size));
541 
542   y = 0.;
543   for (unsigned int j = 0; j < this->current_size; ++j)
544     y.add(x[j], *this->columns[j]);
545 }
546 
547 
548 
549 template <typename VectorType>
550 void
multiply_with_colsT(Vector<Number> & y,const VectorType & x)551 BaseQR<VectorType>::multiply_with_colsT(Vector<Number> &  y,
552                                         const VectorType &x) const
553 {
554   Assert(y.size() == this->current_size,
555          ExcDimensionMismatch(y.size(), this->current_size));
556 
557   for (unsigned int j = 0; j < this->current_size; ++j)
558     y[j] = (*this->columns[j]) * x;
559 }
560 
561 
562 
563 template <class VectorType>
564 boost::signals2::connection
connect_givens_slot(const std::function<void (const unsigned int i,const unsigned int j,const std::array<Number,3> &)> & slot)565 BaseQR<VectorType>::connect_givens_slot(
566   const std::function<void(const unsigned int i,
567                            const unsigned int j,
568                            const std::array<Number, 3> &)> &slot)
569 {
570   return givens_signal.connect(slot);
571 }
572 
573 
574 
575 template <class VectorType>
576 boost::signals2::connection
connect_append_column_slot(const std::function<bool (const Vector<Number> & u,const Number & rho,const Number & col_norm_sqr)> & slot)577 ImplicitQR<VectorType>::connect_append_column_slot(
578   const std::function<bool(const Vector<Number> &u,
579                            const Number &        rho,
580                            const Number &        col_norm_sqr)> &slot)
581 {
582   return column_signal.connect(slot);
583 }
584 
585 
586 
587 template <typename VectorType>
ImplicitQR()588 ImplicitQR<VectorType>::ImplicitQR()
589   : BaseQR<VectorType>()
590 {}
591 
592 
593 
594 template <typename VectorType>
595 bool
append_column(const VectorType & column)596 ImplicitQR<VectorType>::append_column(const VectorType &column)
597 {
598   if (this->current_size == 0)
599     {
600       this->R.grow_or_shrink(this->current_size + 1);
601       this->columns.push_back(std::make_unique<VectorType>(column));
602       this->R(0, 0) = column.l2_norm();
603       ++this->current_size;
604     }
605   else
606     {
607       // first get scalar products with A^T
608       Vector<Number> u(this->current_size);
609       this->multiply_with_AT(u, column);
610 
611       // now solve R^T x = (A^T * column)
612       const int lda   = this->current_size;
613       const int ldb   = this->current_size;
614       const int N     = this->current_size;
615       const int n_rhs = 1;
616       int       info  = 0;
617       internal::QRImplementation::call_trtrs(
618         'U', 'T', 'N', N, n_rhs, &this->R(0, 0), lda, &u(0), ldb, &info);
619 
620       // finally get the diagonal element:
621       // rho2 = |column|^2 - |u|^2
622       const Number column_norm_sqr = column.norm_sqr();
623       const Number rho2            = column_norm_sqr - u.norm_sqr();
624       const bool   linearly_independent =
625         column_signal.empty() ? rho2 > 0 :
626                                 column_signal(u, rho2, column_norm_sqr).get();
627 
628       // bail out if it turns out to be linearly dependent
629       if (!linearly_independent)
630         return false;
631 
632       // at this point we update is successful and we can enlarge R
633       // and store the column:
634       this->columns.push_back(std::make_unique<VectorType>(column));
635       this->R.grow_or_shrink(this->current_size + 1);
636       this->R(this->current_size, this->current_size) = std::sqrt(rho2);
637       for (unsigned int i = 0; i < this->current_size; ++i)
638         this->R(i, this->current_size) = u(i);
639 
640       this->current_size++;
641     }
642 
643   return true;
644 }
645 
646 
647 
648 template <typename VectorType>
649 void
apply_givens_rotation(const unsigned int i,const unsigned int k)650 ImplicitQR<VectorType>::apply_givens_rotation(const unsigned int i,
651                                               const unsigned int k)
652 {
653   AssertIndexRange(i, k);
654   AssertIndexRange(k, this->current_size);
655   const std::array<Number, 3> csr =
656     dealii::Utilities::LinearAlgebra::givens_rotation<Number>(this->R(i, k),
657                                                               this->R(k, k));
658 
659   // first, set k'th column:
660   this->R(i, k) = csr[2];
661   this->R(k, k) = 0.;
662   // now do the rest:
663   for (unsigned int j = 0; j < this->R.n(); ++j)
664     if (j != k)
665       {
666         const Number t = this->R(i, j);
667         this->R(i, j)  = csr[0] * this->R(i, j) + csr[1] * this->R(k, j);
668         this->R(k, j)  = -csr[1] * t + csr[0] * this->R(k, j);
669       }
670 
671   if (!this->givens_signal.empty())
672     this->givens_signal(i, k, csr);
673 }
674 
675 
676 
677 template <typename VectorType>
678 void
remove_column(const unsigned int k)679 ImplicitQR<VectorType>::remove_column(const unsigned int k)
680 {
681   // before actually removing a column from Q and resizing R,
682   // apply givens rotations to bring H into upper triangular form:
683   for (unsigned int j = k + 1; j < this->R.n(); ++j)
684     {
685       const unsigned int i = j - 1;
686       apply_givens_rotation(i, j);
687     }
688 
689   // remove last row and k-th column
690   --this->current_size;
691   this->R.remove_row_and_column(this->current_size, k);
692 
693   // Finally remove the column from A
694   this->columns.erase(this->columns.begin() + k);
695 }
696 
697 
698 
699 template <typename VectorType>
700 void
multiply_with_Q(VectorType & y,const Vector<Number> & x)701 ImplicitQR<VectorType>::multiply_with_Q(VectorType &          y,
702                                         const Vector<Number> &x) const
703 {
704   // A = QR
705   // A R^{-1} = Q
706   Vector<Number> x1 = x;
707   BaseQR<VectorType>::solve(x1, x1, false);
708   multiply_with_A(y, x1);
709 }
710 
711 
712 
713 template <typename VectorType>
714 void
multiply_with_QT(Vector<Number> & y,const VectorType & x)715 ImplicitQR<VectorType>::multiply_with_QT(Vector<Number> &  y,
716                                          const VectorType &x) const
717 {
718   // A = QR
719   // A^T = R^T Q^T
720   // {R^T}^{-1} A^T = Q^T
721   multiply_with_AT(y, x);
722   BaseQR<VectorType>::solve(y, y, true);
723 }
724 
725 
726 
727 template <typename VectorType>
728 void
multiply_with_A(VectorType & y,const Vector<Number> & x)729 ImplicitQR<VectorType>::multiply_with_A(VectorType &          y,
730                                         const Vector<Number> &x) const
731 {
732   BaseQR<VectorType>::multiply_with_cols(y, x);
733 }
734 
735 
736 
737 template <typename VectorType>
738 void
multiply_with_AT(Vector<Number> & y,const VectorType & x)739 ImplicitQR<VectorType>::multiply_with_AT(Vector<Number> &  y,
740                                          const VectorType &x) const
741 {
742   BaseQR<VectorType>::multiply_with_colsT(y, x);
743 }
744 
745 
746 
747 template <typename VectorType>
QR()748 QR<VectorType>::QR()
749   : BaseQR<VectorType>()
750 {}
751 
752 
753 
754 template <typename VectorType>
755 bool
append_column(const VectorType & column)756 QR<VectorType>::append_column(const VectorType &column)
757 {
758   // resize R:
759   this->R.grow_or_shrink(this->current_size + 1);
760   this->columns.push_back(std::make_unique<VectorType>(column));
761 
762   // now a Gram-Schmidt part: orthonormalize the new column
763   // against everything we have so far:
764   auto &last_col = *this->columns.back();
765   for (unsigned int i = 0; i < this->current_size; ++i)
766     {
767       const auto &i_col              = *this->columns[i];
768       this->R(i, this->current_size) = i_col * last_col;
769       last_col.add(-this->R(i, this->current_size), i_col);
770     }
771 
772   this->R(this->current_size, this->current_size) = last_col.l2_norm();
773 
774   Assert(this->R(this->current_size, this->current_size) > 0.,
775          ExcDivideByZero());
776   last_col *= 1. / this->R(this->current_size, this->current_size);
777 
778   ++this->current_size;
779   return true;
780 }
781 
782 
783 
784 template <typename VectorType>
785 void
apply_givens_rotation(const unsigned int i,const unsigned int k)786 QR<VectorType>::apply_givens_rotation(const unsigned int i,
787                                       const unsigned int k)
788 {
789   AssertIndexRange(i, k);
790   AssertIndexRange(k, this->current_size);
791   const std::array<Number, 3> csr =
792     dealii::Utilities::LinearAlgebra::givens_rotation<Number>(this->R(i, k),
793                                                               this->R(k, k));
794 
795   // first, set k'th column:
796   this->R(i, k) = csr[2];
797   this->R(k, k) = 0.;
798   // now do the rest:
799   for (unsigned int j = 0; j < this->R.n(); ++j)
800     if (j != k)
801       {
802         const Number t = this->R(i, j);
803         this->R(i, j)  = csr[0] * this->R(i, j) + csr[1] * this->R(k, j);
804         this->R(k, j)  = -csr[1] * t + csr[0] * this->R(k, j);
805       }
806 
807   // now adjust i,k columns due to multiplication with the
808   // transpose Givens matrix from right:
809   auto &col_i = *this->columns[i];
810   auto &col_k = *this->columns[k];
811   // save column i:
812   tmp = col_i;
813   col_i.sadd(csr[0], csr[1], col_k);
814   col_k.sadd(csr[0], -csr[1], tmp);
815 
816   if (!this->givens_signal.empty())
817     this->givens_signal(i, k, csr);
818 }
819 
820 
821 
822 template <typename VectorType>
823 void
remove_column(const unsigned int k)824 QR<VectorType>::remove_column(const unsigned int k)
825 {
826   AssertIndexRange(k, this->current_size);
827   Assert(this->current_size > 0,
828          ExcMessage("Can not remove a column if QR is empty"));
829   // apply a sequence of Givens rotations
830   // see section 6.5 "Updating matrix factorizations" in Golub 2013, Matrix
831   // computations
832 
833   // So we want to have QR for \tilde A \in R^{m*(n-1)}
834   // if we remove the column k, we end up with upper Hessenberg matrix
835   //      x x x x x
836   //        x x x x
837   // H =      x x x
838   //          x x x
839   //            x x
840   //              x
841   // where k = 2 (3rd column), m = 7, n = 6
842   //
843   // before actually removing a column from Q and resizing R,
844   // apply givens rotations to bring H into upper triangular form:
845   for (unsigned int j = k + 1; j < this->R.n(); ++j)
846     {
847       const unsigned int i = j - 1;
848       apply_givens_rotation(i, j);
849     }
850 
851   // now we can throw away the column from Q and adjust R
852   // since we do thin-QR, after Givens rotations we need to throw
853   // away the last column:
854   const unsigned int size_minus_1 = this->columns.size() - 1;
855   this->columns.erase(this->columns.begin() + size_minus_1);
856 
857   // remove last row and k-th column
858   --this->current_size;
859   this->R.remove_row_and_column(this->current_size, k);
860 }
861 
862 
863 
864 template <typename VectorType>
865 void
multiply_with_Q(VectorType & y,const Vector<Number> & x)866 QR<VectorType>::multiply_with_Q(VectorType &y, const Vector<Number> &x) const
867 {
868   BaseQR<VectorType>::multiply_with_cols(y, x);
869 }
870 
871 
872 
873 template <typename VectorType>
874 void
multiply_with_QT(Vector<Number> & y,const VectorType & x)875 QR<VectorType>::multiply_with_QT(Vector<Number> &y, const VectorType &x) const
876 {
877   BaseQR<VectorType>::multiply_with_colsT(y, x);
878 }
879 
880 
881 
882 template <typename VectorType>
883 void
multiply_with_A(VectorType & y,const Vector<Number> & x)884 QR<VectorType>::multiply_with_A(VectorType &y, const Vector<Number> &x) const
885 {
886   Vector<Number> x1   = x;
887   const int      N    = this->current_size;
888   const int      lda  = N;
889   const int      incx = 1;
890   internal::QRImplementation::call_trmv(
891     'U', 'N', 'N', N, &this->R(0, 0), lda, &x1[0], incx);
892 
893   multiply_with_Q(y, x1);
894 }
895 
896 
897 
898 template <typename VectorType>
899 void
multiply_with_AT(Vector<Number> & y,const VectorType & x)900 QR<VectorType>::multiply_with_AT(Vector<Number> &y, const VectorType &x) const
901 {
902   multiply_with_QT(y, x);
903 
904   const int N    = this->current_size;
905   const int lda  = N;
906   const int incx = 1;
907   internal::QRImplementation::call_trmv(
908     'U', 'T', 'N', N, &this->R(0, 0), lda, &y[0], incx);
909 }
910 
911 #endif // no DOXYGEN
912 
913 DEAL_II_NAMESPACE_CLOSE
914 
915 #endif
916