UpperBidiagonalization.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
5 // Copyright (C) 2013-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #ifndef EIGEN_BIDIAGONALIZATION_H
12 #define EIGEN_BIDIAGONALIZATION_H
13 
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 namespace internal {
19 // UpperBidiagonalization will probably be replaced by a Bidiagonalization class, don't want to make it stable API.
20 // At the same time, it's useful to keep for now as it's about the only thing that is testing the BandMatrix class.
21 
22 template<typename MatrixType_> class UpperBidiagonalization
23 {
24  public:
25 
26  typedef MatrixType_ MatrixType;
27  enum {
28  RowsAtCompileTime = MatrixType::RowsAtCompileTime,
29  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
30  ColsAtCompileTimeMinusOne = internal::decrement_size<ColsAtCompileTime>::ret
31  };
32  typedef typename MatrixType::Scalar Scalar;
33  typedef typename MatrixType::RealScalar RealScalar;
34  typedef Eigen::Index Index;
35  typedef Matrix<Scalar, 1, ColsAtCompileTime> RowVectorType;
36  typedef Matrix<Scalar, RowsAtCompileTime, 1> ColVectorType;
37  typedef BandMatrix<RealScalar, ColsAtCompileTime, ColsAtCompileTime, 1, 0, RowMajor> BidiagonalType;
38  typedef Matrix<Scalar, ColsAtCompileTime, 1> DiagVectorType;
39  typedef Matrix<Scalar, ColsAtCompileTimeMinusOne, 1> SuperDiagVectorType;
40  typedef HouseholderSequence<
41  const MatrixType,
42  const internal::remove_all_t<typename Diagonal<const MatrixType,0>::ConjugateReturnType>
43  > HouseholderUSequenceType;
44  typedef HouseholderSequence<
45  const internal::remove_all_t<typename MatrixType::ConjugateReturnType>,
46  Diagonal<const MatrixType,1>,
48  > HouseholderVSequenceType;
49 
56  UpperBidiagonalization() : m_householder(), m_bidiagonal(0, 0), m_isInitialized(false) {}
57 
58  explicit UpperBidiagonalization(const MatrixType& matrix)
59  : m_householder(matrix.rows(), matrix.cols()),
60  m_bidiagonal(matrix.cols(), matrix.cols()),
61  m_isInitialized(false)
62  {
63  compute(matrix);
64  }
65 
66  UpperBidiagonalization(Index rows, Index cols)
67  : m_householder(rows, cols),
68  m_bidiagonal(cols, cols),
69  m_isInitialized(false)
70  {}
71 
72  UpperBidiagonalization& compute(const MatrixType& matrix);
73  UpperBidiagonalization& computeUnblocked(const MatrixType& matrix);
74 
75  const MatrixType& householder() const { return m_householder; }
76  const BidiagonalType& bidiagonal() const { return m_bidiagonal; }
77 
78  const HouseholderUSequenceType householderU() const
79  {
80  eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized.");
81  return HouseholderUSequenceType(m_householder, m_householder.diagonal().conjugate());
82  }
83 
84  const HouseholderVSequenceType householderV() // const here gives nasty errors and i'm lazy
85  {
86  eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized.");
87  return HouseholderVSequenceType(m_householder.conjugate(), m_householder.const_derived().template diagonal<1>())
88  .setLength(m_householder.cols()-1)
89  .setShift(1);
90  }
91 
92  protected:
93  MatrixType m_householder;
94  BidiagonalType m_bidiagonal;
95  bool m_isInitialized;
96 };
97 
98 // Standard upper bidiagonalization without fancy optimizations
99 // This version should be faster for small matrix size
100 template<typename MatrixType>
102  typename MatrixType::RealScalar *diagonal,
103  typename MatrixType::RealScalar *upper_diagonal,
104  typename MatrixType::Scalar* tempData = 0)
105 {
106  typedef typename MatrixType::Scalar Scalar;
107 
108  Index rows = mat.rows();
109  Index cols = mat.cols();
110 
112  TempType tempVector;
113  if(tempData==0)
114  {
115  tempVector.resize(rows);
116  tempData = tempVector.data();
117  }
118 
119  for (Index k = 0; /* breaks at k==cols-1 below */ ; ++k)
120  {
121  Index remainingRows = rows - k;
122  Index remainingCols = cols - k - 1;
123 
124  // construct left householder transform in-place in A
125  mat.col(k).tail(remainingRows)
126  .makeHouseholderInPlace(mat.coeffRef(k,k), diagonal[k]);
127  // apply householder transform to remaining part of A on the left
128  mat.bottomRightCorner(remainingRows, remainingCols)
129  .applyHouseholderOnTheLeft(mat.col(k).tail(remainingRows-1), mat.coeff(k,k), tempData);
130 
131  if(k == cols-1) break;
132 
133  // construct right householder transform in-place in mat
134  mat.row(k).tail(remainingCols)
135  .makeHouseholderInPlace(mat.coeffRef(k,k+1), upper_diagonal[k]);
136  // apply householder transform to remaining part of mat on the left
137  mat.bottomRightCorner(remainingRows-1, remainingCols)
138  .applyHouseholderOnTheRight(mat.row(k).tail(remainingCols-1).adjoint(), mat.coeff(k,k+1), tempData);
139  }
140 }
141 
159 template<typename MatrixType>
161  typename MatrixType::RealScalar *diagonal,
162  typename MatrixType::RealScalar *upper_diagonal,
163  Index bs,
164  Ref<Matrix<typename MatrixType::Scalar, Dynamic, Dynamic,
165  traits<MatrixType>::Flags & RowMajorBit> > X,
166  Ref<Matrix<typename MatrixType::Scalar, Dynamic, Dynamic,
167  traits<MatrixType>::Flags & RowMajorBit> > Y)
168 {
169  typedef typename MatrixType::Scalar Scalar;
170  typedef typename MatrixType::RealScalar RealScalar;
171  typedef typename NumTraits<RealScalar>::Literal Literal;
172  static constexpr int StorageOrder = (traits<MatrixType>::Flags & RowMajorBit) ? RowMajor : ColMajor;
175  typedef Ref<Matrix<Scalar, Dynamic, 1>, 0, ColInnerStride> SubColumnType;
176  typedef Ref<Matrix<Scalar, 1, Dynamic>, 0, RowInnerStride> SubRowType;
178 
179  Index brows = A.rows();
180  Index bcols = A.cols();
181 
182  Scalar tau_u, tau_u_prev(0), tau_v;
183 
184  for(Index k = 0; k < bs; ++k)
185  {
186  Index remainingRows = brows - k;
187  Index remainingCols = bcols - k - 1;
188 
189  SubMatType X_k1( X.block(k,0, remainingRows,k) );
190  SubMatType V_k1( A.block(k,0, remainingRows,k) );
191 
192  // 1 - update the k-th column of A
193  SubColumnType v_k = A.col(k).tail(remainingRows);
194  v_k -= V_k1 * Y.row(k).head(k).adjoint();
195  if(k) v_k -= X_k1 * A.col(k).head(k);
196 
197  // 2 - construct left Householder transform in-place
198  v_k.makeHouseholderInPlace(tau_v, diagonal[k]);
199 
200  if(k+1<bcols)
201  {
202  SubMatType Y_k ( Y.block(k+1,0, remainingCols, k+1) );
203  SubMatType U_k1 ( A.block(0,k+1, k,remainingCols) );
204 
205  // this eases the application of Householder transforAions
206  // A(k,k) will store tau_v later
207  A(k,k) = Scalar(1);
208 
209  // 3 - Compute y_k^T = tau_v * ( A^T*v_k - Y_k-1*V_k-1^T*v_k - U_k-1*X_k-1^T*v_k )
210  {
211  SubColumnType y_k( Y.col(k).tail(remainingCols) );
212 
213  // let's use the beginning of column k of Y as a temporary vector
214  SubColumnType tmp( Y.col(k).head(k) );
215  y_k.noalias() = A.block(k,k+1, remainingRows,remainingCols).adjoint() * v_k; // bottleneck
216  tmp.noalias() = V_k1.adjoint() * v_k;
217  y_k.noalias() -= Y_k.leftCols(k) * tmp;
218  tmp.noalias() = X_k1.adjoint() * v_k;
219  y_k.noalias() -= U_k1.adjoint() * tmp;
220  y_k *= numext::conj(tau_v);
221  }
222 
223  // 4 - update k-th row of A (it will become u_k)
224  SubRowType u_k( A.row(k).tail(remainingCols) );
225  u_k = u_k.conjugate();
226  {
227  u_k -= Y_k * A.row(k).head(k+1).adjoint();
228  if(k) u_k -= U_k1.adjoint() * X.row(k).head(k).adjoint();
229  }
230 
231  // 5 - construct right Householder transform in-place
232  u_k.makeHouseholderInPlace(tau_u, upper_diagonal[k]);
233 
234  // this eases the application of Householder transformations
235  // A(k,k+1) will store tau_u later
236  A(k,k+1) = Scalar(1);
237 
238  // 6 - Compute x_k = tau_u * ( A*u_k - X_k-1*U_k-1^T*u_k - V_k*Y_k^T*u_k )
239  {
240  SubColumnType x_k ( X.col(k).tail(remainingRows-1) );
241 
242  // let's use the beginning of column k of X as a temporary vectors
243  // note that tmp0 and tmp1 overlaps
244  SubColumnType tmp0 ( X.col(k).head(k) ),
245  tmp1 ( X.col(k).head(k+1) );
246 
247  x_k.noalias() = A.block(k+1,k+1, remainingRows-1,remainingCols) * u_k.transpose(); // bottleneck
248  tmp0.noalias() = U_k1 * u_k.transpose();
249  x_k.noalias() -= X_k1.bottomRows(remainingRows-1) * tmp0;
250  tmp1.noalias() = Y_k.adjoint() * u_k.transpose();
251  x_k.noalias() -= A.block(k+1,0, remainingRows-1,k+1) * tmp1;
252  x_k *= numext::conj(tau_u);
253  tau_u = numext::conj(tau_u);
254  u_k = u_k.conjugate();
255  }
256 
257  if(k>0) A.coeffRef(k-1,k) = tau_u_prev;
258  tau_u_prev = tau_u;
259  }
260  else
261  A.coeffRef(k-1,k) = tau_u_prev;
262 
263  A.coeffRef(k,k) = tau_v;
264  }
265 
266  if(bs<bcols)
267  A.coeffRef(bs-1,bs) = tau_u_prev;
268 
269  // update A22
270  if(bcols>bs && brows>bs)
271  {
272  SubMatType A11( A.bottomRightCorner(brows-bs,bcols-bs) );
273  SubMatType A10( A.block(bs,0, brows-bs,bs) );
274  SubMatType A01( A.block(0,bs, bs,bcols-bs) );
275  Scalar tmp = A01(bs-1,0);
276  A01(bs-1,0) = Literal(1);
277  A11.noalias() -= A10 * Y.topLeftCorner(bcols,bs).bottomRows(bcols-bs).adjoint();
278  A11.noalias() -= X.topLeftCorner(brows,bs).bottomRows(brows-bs) * A01;
279  A01(bs-1,0) = tmp;
280  }
281 }
282 
291 template<typename MatrixType, typename BidiagType>
293  Index maxBlockSize=32,
294  typename MatrixType::Scalar* /*tempData*/ = 0)
295 {
296  typedef typename MatrixType::Scalar Scalar;
297  typedef Block<MatrixType,Dynamic,Dynamic> BlockType;
298 
299  Index rows = A.rows();
300  Index cols = A.cols();
301  Index size = (std::min)(rows, cols);
302 
303  // X and Y are work space
304  static constexpr int StorageOrder = (traits<MatrixType>::Flags & RowMajorBit) ? RowMajor : ColMajor;
305  Matrix<Scalar,
306  MatrixType::RowsAtCompileTime,
307  Dynamic,
308  StorageOrder,
309  MatrixType::MaxRowsAtCompileTime> X(rows,maxBlockSize);
310  Matrix<Scalar,
311  MatrixType::ColsAtCompileTime,
312  Dynamic,
313  StorageOrder,
314  MatrixType::MaxColsAtCompileTime> Y(cols,maxBlockSize);
315  Index blockSize = (std::min)(maxBlockSize,size);
316 
317  Index k = 0;
318  for(k = 0; k < size; k += blockSize)
319  {
320  Index bs = (std::min)(size-k,blockSize); // actual size of the block
321  Index brows = rows - k; // rows of the block
322  Index bcols = cols - k; // columns of the block
323 
324  // partition the matrix A:
325  //
326  // | A00 A01 A02 |
327  // | |
328  // A = | A10 A11 A12 |
329  // | |
330  // | A20 A21 A22 |
331  //
332  // where A11 is a bs x bs diagonal block,
333  // and let:
334  // | A11 A12 |
335  // B = | |
336  // | A21 A22 |
337 
338  BlockType B = A.block(k,k,brows,bcols);
339 
340  // This stage performs the bidiagonalization of A11, A21, A12, and updating of A22.
341  // Finally, the algorithm continue on the updated A22.
342  //
343  // However, if B is too small, or A22 empty, then let's use an unblocked strategy
344  if(k+bs==cols || bcols<48) // somewhat arbitrary threshold
345  {
347  &(bidiagonal.template diagonal<0>().coeffRef(k)),
348  &(bidiagonal.template diagonal<1>().coeffRef(k)),
349  X.data()
350  );
351  break; // We're done
352  }
353  else
354  {
355  upperbidiagonalization_blocked_helper<BlockType>( B,
356  &(bidiagonal.template diagonal<0>().coeffRef(k)),
357  &(bidiagonal.template diagonal<1>().coeffRef(k)),
358  bs,
359  X.topLeftCorner(brows,bs),
360  Y.topLeftCorner(bcols,bs)
361  );
362  }
363  }
364 }
365 
366 template<typename MatrixType_>
367 UpperBidiagonalization<MatrixType_>& UpperBidiagonalization<MatrixType_>::computeUnblocked(const MatrixType_& matrix)
368 {
369  Index rows = matrix.rows();
370  Index cols = matrix.cols();
372 
373  eigen_assert(rows >= cols && "UpperBidiagonalization is only for Arices satisfying rows>=cols.");
374 
375  m_householder = matrix;
376 
377  ColVectorType temp(rows);
378 
380  &(m_bidiagonal.template diagonal<0>().coeffRef(0)),
381  &(m_bidiagonal.template diagonal<1>().coeffRef(0)),
382  temp.data());
383 
384  m_isInitialized = true;
385  return *this;
386 }
387 
388 template<typename MatrixType_>
389 UpperBidiagonalization<MatrixType_>& UpperBidiagonalization<MatrixType_>::compute(const MatrixType_& matrix)
390 {
391  Index rows = matrix.rows();
392  Index cols = matrix.cols();
395 
396  eigen_assert(rows >= cols && "UpperBidiagonalization is only for Arices satisfying rows>=cols.");
397 
398  m_householder = matrix;
399  upperbidiagonalization_inplace_blocked(m_householder, m_bidiagonal);
400 
401  m_isInitialized = true;
402  return *this;
403 }
404 
405 #if 0
410 template<typename Derived>
411 const UpperBidiagonalization<typename MatrixBase<Derived>::PlainObject>
412 MatrixBase<Derived>::bidiagonalization() const
413 {
414  return UpperBidiagonalization<PlainObject>(eval());
415 }
416 #endif
417 
418 } // end namespace internal
419 
420 } // end namespace Eigen
421 
422 #endif // EIGEN_BIDIAGONALIZATION_H
solver compute(A)
MatrixXcf A
MatrixXf B
#define EIGEN_ONLY_USED_FOR_DEBUG(x)
Definition: Macros.h:914
#define eigen_assert(x)
Definition: Macros.h:902
Matrix< float, 1, Dynamic > MatrixType
Expression of a fixed-size or dynamic-size block.
Definition: Block.h:107
NumTraits< Scalar >::Real RealScalar
Definition: DenseBase.h:68
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
Convenience specialization of Stride to specify only an inner stride See class Map for some examples.
Definition: Stride.h:102
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:182
constexpr void resize(Index rows, Index cols)
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:285
@ ColMajor
Definition: Constants.h:321
@ RowMajor
Definition: Constants.h:323
@ OnTheRight
Definition: Constants.h:336
const unsigned int RowMajorBit
Definition: Constants.h:68
bfloat16() min(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:684
void upperbidiagonalization_inplace_unblocked(MatrixType &mat, typename MatrixType::RealScalar *diagonal, typename MatrixType::RealScalar *upper_diagonal, typename MatrixType::Scalar *tempData=0)
void upperbidiagonalization_inplace_blocked(MatrixType &A, BidiagType &bidiagonal, Index maxBlockSize=32, typename MatrixType::Scalar *=0)
void upperbidiagonalization_blocked_helper(MatrixType &A, typename MatrixType::RealScalar *diagonal, typename MatrixType::RealScalar *upper_diagonal, Index bs, Ref< Matrix< typename MatrixType::Scalar, Dynamic, Dynamic, traits< MatrixType >::Flags &RowMajorBit > > X, Ref< Matrix< typename MatrixType::Scalar, Dynamic, Dynamic, traits< MatrixType >::Flags &RowMajorBit > > Y)
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
const int Dynamic
Definition: Constants.h:24
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:231