Medial Code Documentation
Loading...
Searching...
No Matches
UpperBidiagonalization.h
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
14namespace Eigen {
15
16namespace internal {
17// UpperBidiagonalization will probably be replaced by a Bidiagonalization class, don't want to make it stable API.
18// At the same time, it's useful to keep for now as it's about the only thing that is testing the BandMatrix class.
19
20template<typename _MatrixType> class UpperBidiagonalization
21{
22 public:
23
24 typedef _MatrixType MatrixType;
25 enum {
26 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
27 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
28 ColsAtCompileTimeMinusOne = internal::decrement_size<ColsAtCompileTime>::ret
29 };
30 typedef typename MatrixType::Scalar Scalar;
31 typedef typename MatrixType::RealScalar RealScalar;
38 typedef HouseholderSequence<
39 const MatrixType,
42 typedef HouseholderSequence<
43 const typename internal::remove_all<typename MatrixType::ConjugateReturnType>::type,
47
54 UpperBidiagonalization() : m_householder(), m_bidiagonal(), m_isInitialized(false) {}
55
56 explicit UpperBidiagonalization(const MatrixType& matrix)
57 : m_householder(matrix.rows(), matrix.cols()),
58 m_bidiagonal(matrix.cols(), matrix.cols()),
59 m_isInitialized(false)
60 {
61 compute(matrix);
62 }
63
64 UpperBidiagonalization& compute(const MatrixType& matrix);
65 UpperBidiagonalization& computeUnblocked(const MatrixType& matrix);
66
67 const MatrixType& householder() const { return m_householder; }
68 const BidiagonalType& bidiagonal() const { return m_bidiagonal; }
69
70 const HouseholderUSequenceType householderU() const
71 {
72 eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized.");
73 return HouseholderUSequenceType(m_householder, m_householder.diagonal().conjugate());
74 }
75
76 const HouseholderVSequenceType householderV() // const here gives nasty errors and i'm lazy
77 {
78 eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized.");
79 return HouseholderVSequenceType(m_householder.conjugate(), m_householder.const_derived().template diagonal<1>())
80 .setLength(m_householder.cols()-1)
81 .setShift(1);
82 }
83
84 protected:
85 MatrixType m_householder;
86 BidiagonalType m_bidiagonal;
87 bool m_isInitialized;
88};
89
90// Standard upper bidiagonalization without fancy optimizations
91// This version should be faster for small matrix size
92template<typename MatrixType>
93void upperbidiagonalization_inplace_unblocked(MatrixType& mat,
94 typename MatrixType::RealScalar *diagonal,
95 typename MatrixType::RealScalar *upper_diagonal,
96 typename MatrixType::Scalar* tempData = 0)
97{
98 typedef typename MatrixType::Scalar Scalar;
99
100 Index rows = mat.rows();
101 Index cols = mat.cols();
102
104 TempType tempVector;
105 if(tempData==0)
106 {
107 tempVector.resize(rows);
108 tempData = tempVector.data();
109 }
110
111 for (Index k = 0; /* breaks at k==cols-1 below */ ; ++k)
112 {
113 Index remainingRows = rows - k;
114 Index remainingCols = cols - k - 1;
115
116 // construct left householder transform in-place in A
117 mat.col(k).tail(remainingRows)
118 .makeHouseholderInPlace(mat.coeffRef(k,k), diagonal[k]);
119 // apply householder transform to remaining part of A on the left
120 mat.bottomRightCorner(remainingRows, remainingCols)
121 .applyHouseholderOnTheLeft(mat.col(k).tail(remainingRows-1), mat.coeff(k,k), tempData);
122
123 if(k == cols-1) break;
124
125 // construct right householder transform in-place in mat
126 mat.row(k).tail(remainingCols)
127 .makeHouseholderInPlace(mat.coeffRef(k,k+1), upper_diagonal[k]);
128 // apply householder transform to remaining part of mat on the left
129 mat.bottomRightCorner(remainingRows-1, remainingCols)
130 .applyHouseholderOnTheRight(mat.row(k).tail(remainingCols-1).adjoint(), mat.coeff(k,k+1), tempData);
131 }
132}
133
151template<typename MatrixType>
152void upperbidiagonalization_blocked_helper(MatrixType& A,
153 typename MatrixType::RealScalar *diagonal,
154 typename MatrixType::RealScalar *upper_diagonal,
155 Index bs,
156 Ref<Matrix<typename MatrixType::Scalar, Dynamic, Dynamic,
157 traits<MatrixType>::Flags & RowMajorBit> > X,
158 Ref<Matrix<typename MatrixType::Scalar, Dynamic, Dynamic,
159 traits<MatrixType>::Flags & RowMajorBit> > Y)
160{
161 typedef typename MatrixType::Scalar Scalar;
162 typedef typename MatrixType::RealScalar RealScalar;
163 typedef typename NumTraits<RealScalar>::Literal Literal;
164 static const int StorageOrder =
165 (traits<MatrixType>::Flags & RowMajorBit) ? RowMajor : ColMajor;
166 typedef InnerStride<StorageOrder == ColMajor ? 1 : Dynamic> ColInnerStride;
167 typedef InnerStride<StorageOrder == ColMajor ? Dynamic : 1> RowInnerStride;
168 typedef Ref<Matrix<Scalar, Dynamic, 1>, 0, ColInnerStride> SubColumnType;
169 typedef Ref<Matrix<Scalar, 1, Dynamic>, 0, RowInnerStride> SubRowType;
170 typedef Ref<Matrix<Scalar, Dynamic, Dynamic, StorageOrder > > SubMatType;
171
172 Index brows = A.rows();
173 Index bcols = A.cols();
174
175 Scalar tau_u, tau_u_prev(0), tau_v;
176
177 for(Index k = 0; k < bs; ++k)
178 {
179 Index remainingRows = brows - k;
180 Index remainingCols = bcols - k - 1;
181
182 SubMatType X_k1( X.block(k,0, remainingRows,k) );
183 SubMatType V_k1( A.block(k,0, remainingRows,k) );
184
185 // 1 - update the k-th column of A
186 SubColumnType v_k = A.col(k).tail(remainingRows);
187 v_k -= V_k1 * Y.row(k).head(k).adjoint();
188 if(k) v_k -= X_k1 * A.col(k).head(k);
189
190 // 2 - construct left Householder transform in-place
191 v_k.makeHouseholderInPlace(tau_v, diagonal[k]);
192
193 if(k+1<bcols)
194 {
195 SubMatType Y_k ( Y.block(k+1,0, remainingCols, k+1) );
196 SubMatType U_k1 ( A.block(0,k+1, k,remainingCols) );
197
198 // this eases the application of Householder transforAions
199 // A(k,k) will store tau_v later
200 A(k,k) = Scalar(1);
201
202 // 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 )
203 {
204 SubColumnType y_k( Y.col(k).tail(remainingCols) );
205
206 // let's use the beginning of column k of Y as a temporary vector
207 SubColumnType tmp( Y.col(k).head(k) );
208 y_k.noalias() = A.block(k,k+1, remainingRows,remainingCols).adjoint() * v_k; // bottleneck
209 tmp.noalias() = V_k1.adjoint() * v_k;
210 y_k.noalias() -= Y_k.leftCols(k) * tmp;
211 tmp.noalias() = X_k1.adjoint() * v_k;
212 y_k.noalias() -= U_k1.adjoint() * tmp;
213 y_k *= numext::conj(tau_v);
214 }
215
216 // 4 - update k-th row of A (it will become u_k)
217 SubRowType u_k( A.row(k).tail(remainingCols) );
218 u_k = u_k.conjugate();
219 {
220 u_k -= Y_k * A.row(k).head(k+1).adjoint();
221 if(k) u_k -= U_k1.adjoint() * X.row(k).head(k).adjoint();
222 }
223
224 // 5 - construct right Householder transform in-place
225 u_k.makeHouseholderInPlace(tau_u, upper_diagonal[k]);
226
227 // this eases the application of Householder transformations
228 // A(k,k+1) will store tau_u later
229 A(k,k+1) = Scalar(1);
230
231 // 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 )
232 {
233 SubColumnType x_k ( X.col(k).tail(remainingRows-1) );
234
235 // let's use the beginning of column k of X as a temporary vectors
236 // note that tmp0 and tmp1 overlaps
237 SubColumnType tmp0 ( X.col(k).head(k) ),
238 tmp1 ( X.col(k).head(k+1) );
239
240 x_k.noalias() = A.block(k+1,k+1, remainingRows-1,remainingCols) * u_k.transpose(); // bottleneck
241 tmp0.noalias() = U_k1 * u_k.transpose();
242 x_k.noalias() -= X_k1.bottomRows(remainingRows-1) * tmp0;
243 tmp1.noalias() = Y_k.adjoint() * u_k.transpose();
244 x_k.noalias() -= A.block(k+1,0, remainingRows-1,k+1) * tmp1;
245 x_k *= numext::conj(tau_u);
246 tau_u = numext::conj(tau_u);
247 u_k = u_k.conjugate();
248 }
249
250 if(k>0) A.coeffRef(k-1,k) = tau_u_prev;
251 tau_u_prev = tau_u;
252 }
253 else
254 A.coeffRef(k-1,k) = tau_u_prev;
255
256 A.coeffRef(k,k) = tau_v;
257 }
258
259 if(bs<bcols)
260 A.coeffRef(bs-1,bs) = tau_u_prev;
261
262 // update A22
263 if(bcols>bs && brows>bs)
264 {
265 SubMatType A11( A.bottomRightCorner(brows-bs,bcols-bs) );
266 SubMatType A10( A.block(bs,0, brows-bs,bs) );
267 SubMatType A01( A.block(0,bs, bs,bcols-bs) );
268 Scalar tmp = A01(bs-1,0);
269 A01(bs-1,0) = Literal(1);
270 A11.noalias() -= A10 * Y.topLeftCorner(bcols,bs).bottomRows(bcols-bs).adjoint();
271 A11.noalias() -= X.topLeftCorner(brows,bs).bottomRows(brows-bs) * A01;
272 A01(bs-1,0) = tmp;
273 }
274}
275
284template<typename MatrixType, typename BidiagType>
285void upperbidiagonalization_inplace_blocked(MatrixType& A, BidiagType& bidiagonal,
286 Index maxBlockSize=32,
287 typename MatrixType::Scalar* /*tempData*/ = 0)
288{
289 typedef typename MatrixType::Scalar Scalar;
290 typedef Block<MatrixType,Dynamic,Dynamic> BlockType;
291
292 Index rows = A.rows();
293 Index cols = A.cols();
294 Index size = (std::min)(rows, cols);
295
296 // X and Y are work space
297 enum { StorageOrder = (traits<MatrixType>::Flags & RowMajorBit) ? RowMajor : ColMajor };
298 Matrix<Scalar,
299 MatrixType::RowsAtCompileTime,
300 Dynamic,
301 StorageOrder,
302 MatrixType::MaxRowsAtCompileTime> X(rows,maxBlockSize);
303 Matrix<Scalar,
304 MatrixType::ColsAtCompileTime,
305 Dynamic,
306 StorageOrder,
307 MatrixType::MaxColsAtCompileTime> Y(cols,maxBlockSize);
308 Index blockSize = (std::min)(maxBlockSize,size);
309
310 Index k = 0;
311 for(k = 0; k < size; k += blockSize)
312 {
313 Index bs = (std::min)(size-k,blockSize); // actual size of the block
314 Index brows = rows - k; // rows of the block
315 Index bcols = cols - k; // columns of the block
316
317 // partition the matrix A:
318 //
319 // | A00 A01 A02 |
320 // | |
321 // A = | A10 A11 A12 |
322 // | |
323 // | A20 A21 A22 |
324 //
325 // where A11 is a bs x bs diagonal block,
326 // and let:
327 // | A11 A12 |
328 // B = | |
329 // | A21 A22 |
330
331 BlockType B = A.block(k,k,brows,bcols);
332
333 // This stage performs the bidiagonalization of A11, A21, A12, and updating of A22.
334 // Finally, the algorithm continue on the updated A22.
335 //
336 // However, if B is too small, or A22 empty, then let's use an unblocked strategy
337 if(k+bs==cols || bcols<48) // somewhat arbitrary threshold
338 {
339 upperbidiagonalization_inplace_unblocked(B,
340 &(bidiagonal.template diagonal<0>().coeffRef(k)),
341 &(bidiagonal.template diagonal<1>().coeffRef(k)),
342 X.data()
343 );
344 break; // We're done
345 }
346 else
347 {
348 upperbidiagonalization_blocked_helper<BlockType>( B,
349 &(bidiagonal.template diagonal<0>().coeffRef(k)),
350 &(bidiagonal.template diagonal<1>().coeffRef(k)),
351 bs,
352 X.topLeftCorner(brows,bs),
353 Y.topLeftCorner(bcols,bs)
354 );
355 }
356 }
357}
358
359template<typename _MatrixType>
360UpperBidiagonalization<_MatrixType>& UpperBidiagonalization<_MatrixType>::computeUnblocked(const _MatrixType& matrix)
361{
362 Index rows = matrix.rows();
363 Index cols = matrix.cols();
364 EIGEN_ONLY_USED_FOR_DEBUG(cols);
365
366 eigen_assert(rows >= cols && "UpperBidiagonalization is only for Arices satisfying rows>=cols.");
367
368 m_householder = matrix;
369
370 ColVectorType temp(rows);
371
372 upperbidiagonalization_inplace_unblocked(m_householder,
373 &(m_bidiagonal.template diagonal<0>().coeffRef(0)),
374 &(m_bidiagonal.template diagonal<1>().coeffRef(0)),
375 temp.data());
376
377 m_isInitialized = true;
378 return *this;
379}
380
381template<typename _MatrixType>
382UpperBidiagonalization<_MatrixType>& UpperBidiagonalization<_MatrixType>::compute(const _MatrixType& matrix)
383{
384 Index rows = matrix.rows();
385 Index cols = matrix.cols();
386 EIGEN_ONLY_USED_FOR_DEBUG(rows);
387 EIGEN_ONLY_USED_FOR_DEBUG(cols);
388
389 eigen_assert(rows >= cols && "UpperBidiagonalization is only for Arices satisfying rows>=cols.");
390
391 m_householder = matrix;
392 upperbidiagonalization_inplace_blocked(m_householder, m_bidiagonal);
393
394 m_isInitialized = true;
395 return *this;
396}
397
398#if 0
403template<typename Derived>
404const UpperBidiagonalization<typename MatrixBase<Derived>::PlainObject>
405MatrixBase<Derived>::bidiagonalization() const
406{
407 return UpperBidiagonalization<PlainObject>(eval());
408}
409#endif
410
411} // end namespace internal
412
413} // end namespace Eigen
414
415#endif // EIGEN_BIDIAGONALIZATION_H
\householder_module
Definition HouseholderSequence.h:123
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:50
Definition UpperBidiagonalization.h:21
UpperBidiagonalization()
Default Constructor.
Definition UpperBidiagonalization.h:54
Eigen::Index Index
Definition UpperBidiagonalization.h:32
@ ColMajor
Storage order is column major (see TopicStorageOrders).
Definition Constants.h:319
@ RowMajor
Storage order is row major (see TopicStorageOrders).
Definition Constants.h:321
@ OnTheRight
Apply transformation on the right.
Definition Constants.h:334
const unsigned int RowMajorBit
for a matrix, this means that the storage order is row-major.
Definition Constants.h:66
Namespace containing all symbols from the Eigen library.
Definition LDLT.h:16
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition Meta.h:74
const int Dynamic
This value means that a positive quantity (e.g., a size) is not known at compile-time,...
Definition Constants.h:22
Definition Householder.h:18
Definition Meta.h:126
Definition inference.c:32