/src/eigen/Eigen/src/Cholesky/LDLT.h
Line | Count | Source |
1 | | // This file is part of Eigen, a lightweight C++ template library |
2 | | // for linear algebra. |
3 | | // |
4 | | // Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr> |
5 | | // Copyright (C) 2009 Keir Mierle <mierle@gmail.com> |
6 | | // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> |
7 | | // Copyright (C) 2011 Timothy E. Holy <tim.holy@gmail.com > |
8 | | // |
9 | | // This Source Code Form is subject to the terms of the Mozilla |
10 | | // Public License v. 2.0. If a copy of the MPL was not distributed |
11 | | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
12 | | // SPDX-License-Identifier: MPL-2.0 |
13 | | |
14 | | #ifndef EIGEN_LDLT_H |
15 | | #define EIGEN_LDLT_H |
16 | | |
17 | | // IWYU pragma: private |
18 | | #include "./InternalHeaderCheck.h" |
19 | | |
20 | | namespace Eigen { |
21 | | |
22 | | namespace internal { |
23 | | template <typename MatrixType_, int UpLo_> |
24 | | struct traits<LDLT<MatrixType_, UpLo_> > : traits<MatrixType_> { |
25 | | using XprKind = MatrixXpr; |
26 | | using StorageKind = SolverStorage; |
27 | | using StorageIndex = int; |
28 | | enum { Flags = 0 }; |
29 | | }; |
30 | | |
31 | | template <typename MatrixType, int UpLo> |
32 | | struct LDLT_Traits; |
33 | | |
34 | | // PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef |
35 | | enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite }; |
36 | | } // namespace internal |
37 | | |
38 | | /** \ingroup Cholesky_Module |
39 | | * |
40 | | * \class LDLT |
41 | | * |
42 | | * \brief Robust Cholesky decomposition of a matrix with pivoting |
43 | | * |
44 | | * \tparam MatrixType_ the type of the matrix of which to compute the LDL^T Cholesky decomposition |
45 | | * \tparam UpLo_ the triangular part that will be used for the decomposition: Lower (default) or Upper. |
46 | | * The other triangular part won't be read. |
47 | | * |
48 | | * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite |
49 | | * matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L |
50 | | * is lower triangular with a unit diagonal and D is a diagonal matrix. |
51 | | * |
52 | | * The decomposition uses pivoting to ensure stability, so that D will have |
53 | | * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root |
54 | | * on D also stabilizes the computation. |
55 | | * |
56 | | * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky |
57 | | * decomposition to determine whether a system of equations has a solution. |
58 | | * |
59 | | * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. |
60 | | * |
61 | | * D is purely diagonal, so this class cannot factor an indefinite matrix. For a self-adjoint matrix |
62 | | * that is indefinite, use BunchKaufman, which produces a block-diagonal D. |
63 | | * |
64 | | * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT, class BunchKaufman |
65 | | */ |
66 | | template <typename MatrixType_, int UpLo_> |
67 | | class LDLT : public SolverBase<LDLT<MatrixType_, UpLo_> > { |
68 | | public: |
69 | | using MatrixType = MatrixType_; |
70 | | using Base = SolverBase<LDLT>; |
71 | | friend class SolverBase<LDLT>; |
72 | | |
73 | | EIGEN_GENERIC_PUBLIC_INTERFACE(LDLT) |
74 | | enum { |
75 | | MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, |
76 | | MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, |
77 | | UpLo = UpLo_ |
78 | | }; |
79 | | using TmpMatrixType = Matrix<Scalar, RowsAtCompileTime, 1, 0, MaxRowsAtCompileTime, 1>; |
80 | | |
81 | | using TranspositionType = Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime>; |
82 | | using PermutationType = PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime>; |
83 | | |
84 | | using Traits = internal::LDLT_Traits<MatrixType, UpLo>; |
85 | | |
86 | | /** \brief Default Constructor. |
87 | | * |
88 | | * The default constructor is useful in cases in which the user intends to |
89 | | * perform decompositions via LDLT::compute(const MatrixType&). |
90 | | */ |
91 | | LDLT() |
92 | | : m_matrix(), |
93 | | m_l1_norm(0), |
94 | | m_transpositions(), |
95 | | m_sign(internal::ZeroSign), |
96 | | m_isInitialized(false), |
97 | | m_info(InvalidInput) {} |
98 | | |
99 | | /** \brief Default Constructor with memory preallocation |
100 | | * |
101 | | * Like the default constructor but with preallocation of the internal data |
102 | | * according to the specified problem \a size. |
103 | | * \sa LDLT() |
104 | | */ |
105 | | explicit LDLT(Index size) |
106 | | : m_matrix(size, size), |
107 | | m_l1_norm(0), |
108 | | m_transpositions(size), |
109 | | m_temporary(size), |
110 | | m_sign(internal::ZeroSign), |
111 | | m_isInitialized(false), |
112 | | m_info(InvalidInput) {} |
113 | | |
114 | | /** \brief Constructor with decomposition |
115 | | * |
116 | | * This calculates the decomposition for the input \a matrix. |
117 | | * |
118 | | * \sa LDLT(Index size) |
119 | | */ |
120 | | template <typename InputType> |
121 | | explicit LDLT(const EigenBase<InputType>& matrix) |
122 | | : m_matrix(matrix.rows(), matrix.cols()), |
123 | | m_l1_norm(0), |
124 | | m_transpositions(matrix.rows()), |
125 | | m_temporary(matrix.rows()), |
126 | | m_sign(internal::ZeroSign), |
127 | | m_isInitialized(false), |
128 | | m_info(InvalidInput) { |
129 | | compute(matrix.derived()); |
130 | | } |
131 | | |
132 | | /** \brief Constructs a LDLT factorization from a given matrix |
133 | | * |
134 | | * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c |
135 | | * MatrixType is a Eigen::Ref. |
136 | | * |
137 | | * \sa LDLT(const EigenBase&) |
138 | | */ |
139 | | template <typename InputType> |
140 | | explicit LDLT(EigenBase<InputType>& matrix) |
141 | 514 | : m_matrix(matrix.derived()), |
142 | 514 | m_l1_norm(0), |
143 | 514 | m_transpositions(matrix.rows()), |
144 | 514 | m_temporary(matrix.rows()), |
145 | 514 | m_sign(internal::ZeroSign), |
146 | 514 | m_isInitialized(false), |
147 | 514 | m_info(InvalidInput) { |
148 | 514 | compute(matrix.derived()); |
149 | 514 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::EigenBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&) Line | Count | Source | 141 | 279 | : m_matrix(matrix.derived()), | 142 | 279 | m_l1_norm(0), | 143 | 279 | m_transpositions(matrix.rows()), | 144 | 279 | m_temporary(matrix.rows()), | 145 | 279 | m_sign(internal::ZeroSign), | 146 | 279 | m_isInitialized(false), | 147 | 279 | m_info(InvalidInput) { | 148 | 279 | compute(matrix.derived()); | 149 | 279 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::EigenBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) Line | Count | Source | 141 | 235 | : m_matrix(matrix.derived()), | 142 | 235 | m_l1_norm(0), | 143 | 235 | m_transpositions(matrix.rows()), | 144 | 235 | m_temporary(matrix.rows()), | 145 | 235 | m_sign(internal::ZeroSign), | 146 | 235 | m_isInitialized(false), | 147 | 235 | m_info(InvalidInput) { | 148 | 235 | compute(matrix.derived()); | 149 | 235 | } |
|
150 | | |
151 | | /** Clear any existing decomposition |
152 | | * \sa rankUpdate(w,sigma) |
153 | | */ |
154 | | void setZero() { m_isInitialized = false; } |
155 | | |
156 | | /** \returns a view of the upper triangular matrix U */ |
157 | 124 | inline typename Traits::MatrixU matrixU() const { |
158 | 124 | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
159 | 124 | return Traits::getU(m_matrix); |
160 | 124 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::matrixU() const Line | Count | Source | 157 | 62 | inline typename Traits::MatrixU matrixU() const { | 158 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 159 | 62 | return Traits::getU(m_matrix); | 160 | 62 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::matrixU() const Line | Count | Source | 157 | 62 | inline typename Traits::MatrixU matrixU() const { | 158 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 159 | 62 | return Traits::getU(m_matrix); | 160 | 62 | } |
|
161 | | |
162 | | /** \returns a view of the lower triangular matrix L */ |
163 | 124 | inline typename Traits::MatrixL matrixL() const { |
164 | 124 | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
165 | 124 | return Traits::getL(m_matrix); |
166 | 124 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::matrixL() const Line | Count | Source | 163 | 62 | inline typename Traits::MatrixL matrixL() const { | 164 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 165 | 62 | return Traits::getL(m_matrix); | 166 | 62 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::matrixL() const Line | Count | Source | 163 | 62 | inline typename Traits::MatrixL matrixL() const { | 164 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 165 | 62 | return Traits::getL(m_matrix); | 166 | 62 | } |
|
167 | | |
168 | | /** \returns the permutation matrix P as a transposition sequence. |
169 | | */ |
170 | | inline const TranspositionType& transpositionsP() const { |
171 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
172 | | return m_transpositions; |
173 | | } |
174 | | |
175 | | /** \returns the coefficients of the diagonal matrix D */ |
176 | 124 | inline Diagonal<const MatrixType> vectorD() const { |
177 | 124 | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
178 | 124 | return m_matrix.diagonal(); |
179 | 124 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::vectorD() const Line | Count | Source | 176 | 62 | inline Diagonal<const MatrixType> vectorD() const { | 177 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 178 | 62 | return m_matrix.diagonal(); | 179 | 62 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::vectorD() const Line | Count | Source | 176 | 62 | inline Diagonal<const MatrixType> vectorD() const { | 177 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 178 | 62 | return m_matrix.diagonal(); | 179 | 62 | } |
|
180 | | |
181 | | /** \returns true if the matrix is positive (semidefinite) */ |
182 | 124 | inline bool isPositive() const { |
183 | 124 | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
184 | 124 | return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; |
185 | 124 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::isPositive() const Line | Count | Source | 182 | 62 | inline bool isPositive() const { | 183 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 184 | 62 | return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; | 185 | 62 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::isPositive() const Line | Count | Source | 182 | 62 | inline bool isPositive() const { | 183 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 184 | 62 | return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; | 185 | 62 | } |
|
186 | | |
187 | | /** \returns true if the matrix is negative (semidefinite) */ |
188 | 124 | inline bool isNegative(void) const { |
189 | 124 | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
190 | 124 | return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; |
191 | 124 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::isNegative() const Line | Count | Source | 188 | 62 | inline bool isNegative(void) const { | 189 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 190 | 62 | return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; | 191 | 62 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::isNegative() const Line | Count | Source | 188 | 62 | inline bool isNegative(void) const { | 189 | 62 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 190 | 62 | return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; | 191 | 62 | } |
|
192 | | |
193 | | #ifdef EIGEN_PARSED_BY_DOXYGEN |
194 | | /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A. |
195 | | * |
196 | | * This function also supports in-place solves using the syntax <tt>x = decompositionObject.solve(x)</tt> . |
197 | | * |
198 | | * \note_about_checking_solutions |
199 | | * |
200 | | * More precisely, this method solves \f$ A x = b \f$ using the decomposition \f$ A = P^T L D L^* P \f$ |
201 | | * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, |
202 | | * \f$ L^* y_4 = y_3 \f$ and \f$ P x = y_4 \f$ in succession. If the matrix \f$ A \f$ is singular, then |
203 | | * \f$ D \f$ will also be singular (all the other matrices are invertible). In that case, the |
204 | | * least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function |
205 | | * computes the least-square solution of \f$ A x = b \f$ if \f$ A \f$ is singular. |
206 | | * |
207 | | * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt() |
208 | | */ |
209 | | template <typename Rhs> |
210 | | inline Solve<LDLT, Rhs> solve(const MatrixBase<Rhs>& b) const; |
211 | | #endif |
212 | | |
213 | | template <typename Derived> |
214 | | bool solveInPlace(MatrixBase<Derived>& bAndX) const; |
215 | | |
216 | | template <typename InputType> |
217 | | LDLT& compute(const EigenBase<InputType>& matrix); |
218 | | |
219 | | /** \returns an estimate of the reciprocal condition number of the matrix of |
220 | | * which \c *this is the LDLT decomposition. |
221 | | */ |
222 | | RealScalar rcond() const { |
223 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
224 | | return internal::rcond_estimate_helper(m_l1_norm, *this); |
225 | | } |
226 | | |
227 | | template <typename Derived> |
228 | | LDLT& rankUpdate(const MatrixBase<Derived>& w, const RealScalar& alpha = 1); |
229 | | |
230 | | /** \returns the determinant of the matrix of which *this is the Cholesky decomposition. |
231 | | * |
232 | | * It has only linear complexity (that is, O(n) where n is the dimension of the square matrix) |
233 | | * as the Cholesky decomposition has already been computed. |
234 | | * |
235 | | * \warning a determinant can be very big or small, so for matrices |
236 | | * of large enough dimension, there is a risk of overflow/underflow. |
237 | | * One way to work around that is to use logAbsDeterminant() and signDeterminant() instead. |
238 | | * Also, do not rely on the determinant being exactly zero for testing |
239 | | * singularity or rank-deficiency. |
240 | | * |
241 | | * \pre info() returns \c Success. A failed factorization does not represent the input matrix. |
242 | | * |
243 | | * \sa absDeterminant(), logAbsDeterminant(), signDeterminant(), MatrixBase::determinant() |
244 | | */ |
245 | | Scalar determinant() const; |
246 | | |
247 | | /** \returns the absolute value of the determinant of the matrix of which *this is the Cholesky decomposition. |
248 | | * |
249 | | * It has only linear complexity (that is, O(n) where n is the dimension of the square matrix) |
250 | | * as the Cholesky decomposition has already been computed. |
251 | | * |
252 | | * \warning a determinant can be very big or small, so for matrices |
253 | | * of large enough dimension, there is a risk of overflow/underflow. |
254 | | * One way to work around that is to use logAbsDeterminant() instead. |
255 | | * |
256 | | * \pre info() returns \c Success. A failed factorization does not represent the input matrix. |
257 | | * |
258 | | * \sa determinant(), logAbsDeterminant(), signDeterminant(), MatrixBase::determinant() |
259 | | */ |
260 | | RealScalar absDeterminant() const; |
261 | | |
262 | | /** \returns the natural log of the absolute value of the determinant of the matrix of which *this is the Cholesky |
263 | | * decomposition. |
264 | | * |
265 | | * It has only linear complexity (that is, O(n) where n is the dimension of the square matrix) |
266 | | * as the Cholesky decomposition has already been computed. |
267 | | * |
268 | | * \note This method is useful to work around the risk of overflow/underflow that's inherent |
269 | | * to determinant computation. |
270 | | * |
271 | | * \pre info() returns \c Success. A failed factorization does not represent the input matrix. |
272 | | * |
273 | | * \sa determinant(), absDeterminant(), signDeterminant(), MatrixBase::determinant() |
274 | | */ |
275 | | RealScalar logAbsDeterminant() const; |
276 | | |
277 | | /** \returns the sign of the determinant of the matrix of which *this is the Cholesky decomposition, |
278 | | * that is, \c 1, \c -1, or \c 0 if the matrix is singular. |
279 | | * |
280 | | * It has only linear complexity (that is, O(n) where n is the dimension of the square matrix) |
281 | | * as the Cholesky decomposition has already been computed. |
282 | | * |
283 | | * \pre info() returns \c Success. A failed factorization does not represent the input matrix. |
284 | | * |
285 | | * \sa determinant(), absDeterminant(), logAbsDeterminant(), MatrixBase::determinant() |
286 | | */ |
287 | | Scalar signDeterminant() const; |
288 | | |
289 | | /** \returns the internal LDLT decomposition matrix |
290 | | * |
291 | | * TODO: document the storage layout. |
292 | | */ |
293 | | inline const MatrixType& matrixLDLT() const { |
294 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
295 | | return m_matrix; |
296 | | } |
297 | | |
298 | | MatrixType reconstructedMatrix() const; |
299 | | |
300 | | /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix |
301 | | * is self-adjoint. |
302 | | * |
303 | | * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: |
304 | | * \code x = decomposition.adjoint().solve(b) \endcode |
305 | | */ |
306 | | const LDLT& adjoint() const { return *this; } |
307 | | |
308 | 124 | EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return m_matrix.rows(); }Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::rows() const Line | Count | Source | 308 | 62 | EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return m_matrix.rows(); } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::rows() const Line | Count | Source | 308 | 62 | EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return m_matrix.rows(); } |
|
309 | 0 | EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return m_matrix.cols(); }Unexecuted instantiation: Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::cols() const Unexecuted instantiation: Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::cols() const |
310 | | |
311 | | /** \brief Reports whether previous computation was successful. |
312 | | * |
313 | | * \returns \c Success if computation was successful, |
314 | | * \c NumericalIssue if the factorization failed because of a zero pivot. |
315 | | */ |
316 | 514 | ComputationInfo info() const { |
317 | 514 | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
318 | 514 | return m_info; |
319 | 514 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::info() const Line | Count | Source | 316 | 279 | ComputationInfo info() const { | 317 | 279 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 318 | 279 | return m_info; | 319 | 279 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::info() const Line | Count | Source | 316 | 235 | ComputationInfo info() const { | 317 | 235 | eigen_assert(m_isInitialized && "LDLT is not initialized."); | 318 | 235 | return m_info; | 319 | 235 | } |
|
320 | | |
321 | | #ifndef EIGEN_PARSED_BY_DOXYGEN |
322 | | template <typename RhsType, typename DstType> |
323 | | void _solve_impl(const RhsType& rhs, DstType& dst) const; |
324 | | |
325 | | template <bool Conjugate, typename RhsType, typename DstType> |
326 | | void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const; |
327 | | #endif |
328 | | |
329 | | protected: |
330 | | EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) |
331 | | |
332 | | /** \internal |
333 | | * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. |
334 | | * The strict upper part is used during the decomposition, the strict lower |
335 | | * part correspond to the coefficients of L (its diagonal is equal to 1 and |
336 | | * is not stored), and the diagonal entries correspond to D. |
337 | | */ |
338 | | MatrixType m_matrix; |
339 | | RealScalar m_l1_norm; |
340 | | TranspositionType m_transpositions; |
341 | | TmpMatrixType m_temporary; |
342 | | internal::SignMatrix m_sign; |
343 | | bool m_isInitialized; |
344 | | ComputationInfo m_info; |
345 | | }; |
346 | | |
347 | | namespace internal { |
348 | | |
349 | | template <int UpLo> |
350 | | struct ldlt_inplace; |
351 | | |
352 | | template <> |
353 | | struct ldlt_inplace<Lower> { |
354 | | template <typename MatrixType, typename TranspositionType, typename Workspace> |
355 | 514 | static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) { |
356 | 514 | using std::abs; |
357 | 514 | using Scalar = typename MatrixType::Scalar; |
358 | 514 | using RealScalar = typename MatrixType::RealScalar; |
359 | 514 | using IndexType = typename TranspositionType::StorageIndex; |
360 | 514 | eigen_assert(mat.rows() == mat.cols()); |
361 | 514 | const Index size = mat.rows(); |
362 | 514 | bool found_zero_pivot = false; |
363 | 514 | bool ret = true; |
364 | | |
365 | 514 | if (size <= 1) { |
366 | 10 | transpositions.setIdentity(); |
367 | 10 | if (size == 0) |
368 | 0 | sign = ZeroSign; |
369 | 10 | else if (numext::real(mat.coeff(0, 0)) > static_cast<RealScalar>(0)) |
370 | 3 | sign = PositiveSemiDef; |
371 | 7 | else if (numext::real(mat.coeff(0, 0)) < static_cast<RealScalar>(0)) |
372 | 5 | sign = NegativeSemiDef; |
373 | 2 | else |
374 | 2 | sign = ZeroSign; |
375 | 10 | return true; |
376 | 10 | } |
377 | | |
378 | 8.15k | for (Index k = 0; k < size; ++k) { |
379 | | // Find largest diagonal element |
380 | 7.70k | Index index_of_biggest_in_corner; |
381 | 7.70k | mat.diagonal().tail(size - k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); |
382 | 7.70k | index_of_biggest_in_corner += k; |
383 | | |
384 | 7.70k | transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); |
385 | 7.70k | if (k != index_of_biggest_in_corner) { |
386 | | // apply the transposition while taking care to consider only |
387 | | // the lower triangular part |
388 | 4.17k | Index s = size - index_of_biggest_in_corner - 1; // trailing size after the biggest element |
389 | 4.17k | mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); |
390 | 4.17k | mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); |
391 | 4.17k | std::swap(mat.coeffRef(k, k), mat.coeffRef(index_of_biggest_in_corner, index_of_biggest_in_corner)); |
392 | 17.7k | for (Index i = k + 1; i < index_of_biggest_in_corner; ++i) { |
393 | 13.5k | Scalar tmp = mat.coeffRef(i, k); |
394 | 13.5k | mat.coeffRef(i, k) = numext::conj(mat.coeffRef(index_of_biggest_in_corner, i)); |
395 | 13.5k | mat.coeffRef(index_of_biggest_in_corner, i) = numext::conj(tmp); |
396 | 13.5k | } |
397 | 4.17k | EIGEN_IF_CONSTEXPR (NumTraits<Scalar>::IsComplex) |
398 | | mat.coeffRef(index_of_biggest_in_corner, k) = numext::conj(mat.coeff(index_of_biggest_in_corner, k)); |
399 | 4.17k | } |
400 | | |
401 | | // partition the matrix: |
402 | | // A00 | - | - |
403 | | // lu = A10 | A11 | - |
404 | | // A20 | A21 | A22 |
405 | 7.70k | Index rs = size - k - 1; |
406 | 7.70k | Block<MatrixType, Dynamic, 1> A21(mat, k + 1, k, rs, 1); |
407 | 7.70k | Block<MatrixType, 1, Dynamic> A10(mat, k, 0, 1, k); |
408 | 7.70k | Block<MatrixType, Dynamic, Dynamic> A20(mat, k + 1, 0, rs, k); |
409 | | |
410 | 7.70k | if (k > 0) { |
411 | 7.20k | temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); |
412 | 7.20k | mat.coeffRef(k, k) -= (A10 * temp.head(k)).value(); |
413 | 7.20k | if (rs > 0) A21.noalias() -= A20 * temp.head(k); |
414 | 7.20k | } |
415 | | |
416 | | // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot |
417 | | // was smaller than the cutoff value. However, since LDLT is not rank-revealing |
418 | | // we should only make sure that we do not introduce INF or NaN values. |
419 | | // Remark that LAPACK also uses 0 as the cutoff value. |
420 | 7.70k | RealScalar realAkk = numext::real(mat.coeffRef(k, k)); |
421 | 7.70k | bool pivot_is_valid = (abs(realAkk) > RealScalar(0)); |
422 | | |
423 | 7.70k | if (k == 0 && !pivot_is_valid) { |
424 | | // The entire diagonal is zero, there is nothing more to do |
425 | | // except filling the transpositions, and checking whether the matrix is zero. |
426 | 52 | sign = ZeroSign; |
427 | 541 | for (Index j = 0; j < size; ++j) { |
428 | 489 | transpositions.coeffRef(j) = IndexType(j); |
429 | 489 | ret = ret && (mat.col(j).tail(size - j - 1).array() == Scalar(0)).all(); |
430 | 489 | } |
431 | 52 | return ret; |
432 | 52 | } |
433 | | |
434 | 7.65k | if ((rs > 0) && pivot_is_valid) |
435 | 1.29k | A21 /= realAkk; |
436 | 6.35k | else if (rs > 0) |
437 | 5.90k | ret = ret && (A21.array() == Scalar(0)).all(); |
438 | | |
439 | 7.65k | if (found_zero_pivot && pivot_is_valid) |
440 | 394 | ret = false; // factorization failed |
441 | 7.25k | else if (!pivot_is_valid) |
442 | 6.25k | found_zero_pivot = true; |
443 | | |
444 | 7.65k | if (sign == PositiveSemiDef) { |
445 | 292 | if (realAkk < static_cast<RealScalar>(0)) sign = Indefinite; |
446 | 7.36k | } else if (sign == NegativeSemiDef) { |
447 | 3.82k | if (realAkk > static_cast<RealScalar>(0)) sign = Indefinite; |
448 | 3.82k | } else if (sign == ZeroSign) { |
449 | 452 | if (realAkk > static_cast<RealScalar>(0)) |
450 | 129 | sign = PositiveSemiDef; |
451 | 323 | else if (realAkk < static_cast<RealScalar>(0)) |
452 | 323 | sign = NegativeSemiDef; |
453 | 452 | } |
454 | 7.65k | } |
455 | | |
456 | 452 | return ret; |
457 | 504 | } bool Eigen::internal::ldlt_inplace<1>::unblocked<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Transpositions<-1, -1, int>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::Matrix<float, -1, -1, 0, -1, -1>&, Eigen::Transpositions<-1, -1, int>&, Eigen::Matrix<float, -1, 1, 0, -1, 1>&, Eigen::internal::SignMatrix&) Line | Count | Source | 355 | 279 | static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) { | 356 | 279 | using std::abs; | 357 | 279 | using Scalar = typename MatrixType::Scalar; | 358 | 279 | using RealScalar = typename MatrixType::RealScalar; | 359 | 279 | using IndexType = typename TranspositionType::StorageIndex; | 360 | 279 | eigen_assert(mat.rows() == mat.cols()); | 361 | 279 | const Index size = mat.rows(); | 362 | 279 | bool found_zero_pivot = false; | 363 | 279 | bool ret = true; | 364 | | | 365 | 279 | if (size <= 1) { | 366 | 4 | transpositions.setIdentity(); | 367 | 4 | if (size == 0) | 368 | 0 | sign = ZeroSign; | 369 | 4 | else if (numext::real(mat.coeff(0, 0)) > static_cast<RealScalar>(0)) | 370 | 2 | sign = PositiveSemiDef; | 371 | 2 | else if (numext::real(mat.coeff(0, 0)) < static_cast<RealScalar>(0)) | 372 | 1 | sign = NegativeSemiDef; | 373 | 1 | else | 374 | 1 | sign = ZeroSign; | 375 | 4 | return true; | 376 | 4 | } | 377 | | | 378 | 4.61k | for (Index k = 0; k < size; ++k) { | 379 | | // Find largest diagonal element | 380 | 4.36k | Index index_of_biggest_in_corner; | 381 | 4.36k | mat.diagonal().tail(size - k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); | 382 | 4.36k | index_of_biggest_in_corner += k; | 383 | | | 384 | 4.36k | transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); | 385 | 4.36k | if (k != index_of_biggest_in_corner) { | 386 | | // apply the transposition while taking care to consider only | 387 | | // the lower triangular part | 388 | 2.32k | Index s = size - index_of_biggest_in_corner - 1; // trailing size after the biggest element | 389 | 2.32k | mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); | 390 | 2.32k | mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); | 391 | 2.32k | std::swap(mat.coeffRef(k, k), mat.coeffRef(index_of_biggest_in_corner, index_of_biggest_in_corner)); | 392 | 10.3k | for (Index i = k + 1; i < index_of_biggest_in_corner; ++i) { | 393 | 8.03k | Scalar tmp = mat.coeffRef(i, k); | 394 | 8.03k | mat.coeffRef(i, k) = numext::conj(mat.coeffRef(index_of_biggest_in_corner, i)); | 395 | 8.03k | mat.coeffRef(index_of_biggest_in_corner, i) = numext::conj(tmp); | 396 | 8.03k | } | 397 | 2.32k | EIGEN_IF_CONSTEXPR (NumTraits<Scalar>::IsComplex) | 398 | | mat.coeffRef(index_of_biggest_in_corner, k) = numext::conj(mat.coeff(index_of_biggest_in_corner, k)); | 399 | 2.32k | } | 400 | | | 401 | | // partition the matrix: | 402 | | // A00 | - | - | 403 | | // lu = A10 | A11 | - | 404 | | // A20 | A21 | A22 | 405 | 4.36k | Index rs = size - k - 1; | 406 | 4.36k | Block<MatrixType, Dynamic, 1> A21(mat, k + 1, k, rs, 1); | 407 | 4.36k | Block<MatrixType, 1, Dynamic> A10(mat, k, 0, 1, k); | 408 | 4.36k | Block<MatrixType, Dynamic, Dynamic> A20(mat, k + 1, 0, rs, k); | 409 | | | 410 | 4.36k | if (k > 0) { | 411 | 4.08k | temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); | 412 | 4.08k | mat.coeffRef(k, k) -= (A10 * temp.head(k)).value(); | 413 | 4.08k | if (rs > 0) A21.noalias() -= A20 * temp.head(k); | 414 | 4.08k | } | 415 | | | 416 | | // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot | 417 | | // was smaller than the cutoff value. However, since LDLT is not rank-revealing | 418 | | // we should only make sure that we do not introduce INF or NaN values. | 419 | | // Remark that LAPACK also uses 0 as the cutoff value. | 420 | 4.36k | RealScalar realAkk = numext::real(mat.coeffRef(k, k)); | 421 | 4.36k | bool pivot_is_valid = (abs(realAkk) > RealScalar(0)); | 422 | | | 423 | 4.36k | if (k == 0 && !pivot_is_valid) { | 424 | | // The entire diagonal is zero, there is nothing more to do | 425 | | // except filling the transpositions, and checking whether the matrix is zero. | 426 | 28 | sign = ZeroSign; | 427 | 281 | for (Index j = 0; j < size; ++j) { | 428 | 253 | transpositions.coeffRef(j) = IndexType(j); | 429 | 253 | ret = ret && (mat.col(j).tail(size - j - 1).array() == Scalar(0)).all(); | 430 | 253 | } | 431 | 28 | return ret; | 432 | 28 | } | 433 | | | 434 | 4.33k | if ((rs > 0) && pivot_is_valid) | 435 | 713 | A21 /= realAkk; | 436 | 3.62k | else if (rs > 0) | 437 | 3.37k | ret = ret && (A21.array() == Scalar(0)).all(); | 438 | | | 439 | 4.33k | if (found_zero_pivot && pivot_is_valid) | 440 | 224 | ret = false; // factorization failed | 441 | 4.11k | else if (!pivot_is_valid) | 442 | 3.56k | found_zero_pivot = true; | 443 | | | 444 | 4.33k | if (sign == PositiveSemiDef) { | 445 | 165 | if (realAkk < static_cast<RealScalar>(0)) sign = Indefinite; | 446 | 4.17k | } else if (sign == NegativeSemiDef) { | 447 | 2.14k | if (realAkk > static_cast<RealScalar>(0)) sign = Indefinite; | 448 | 2.14k | } else if (sign == ZeroSign) { | 449 | 247 | if (realAkk > static_cast<RealScalar>(0)) | 450 | 74 | sign = PositiveSemiDef; | 451 | 173 | else if (realAkk < static_cast<RealScalar>(0)) | 452 | 173 | sign = NegativeSemiDef; | 453 | 247 | } | 454 | 4.33k | } | 455 | | | 456 | 247 | return ret; | 457 | 275 | } |
bool Eigen::internal::ldlt_inplace<1>::unblocked<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Transpositions<-1, -1, int>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1>&, Eigen::Transpositions<-1, -1, int>&, Eigen::Matrix<double, -1, 1, 0, -1, 1>&, Eigen::internal::SignMatrix&) Line | Count | Source | 355 | 235 | static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) { | 356 | 235 | using std::abs; | 357 | 235 | using Scalar = typename MatrixType::Scalar; | 358 | 235 | using RealScalar = typename MatrixType::RealScalar; | 359 | 235 | using IndexType = typename TranspositionType::StorageIndex; | 360 | 235 | eigen_assert(mat.rows() == mat.cols()); | 361 | 235 | const Index size = mat.rows(); | 362 | 235 | bool found_zero_pivot = false; | 363 | 235 | bool ret = true; | 364 | | | 365 | 235 | if (size <= 1) { | 366 | 6 | transpositions.setIdentity(); | 367 | 6 | if (size == 0) | 368 | 0 | sign = ZeroSign; | 369 | 6 | else if (numext::real(mat.coeff(0, 0)) > static_cast<RealScalar>(0)) | 370 | 1 | sign = PositiveSemiDef; | 371 | 5 | else if (numext::real(mat.coeff(0, 0)) < static_cast<RealScalar>(0)) | 372 | 4 | sign = NegativeSemiDef; | 373 | 1 | else | 374 | 1 | sign = ZeroSign; | 375 | 6 | return true; | 376 | 6 | } | 377 | | | 378 | 3.54k | for (Index k = 0; k < size; ++k) { | 379 | | // Find largest diagonal element | 380 | 3.34k | Index index_of_biggest_in_corner; | 381 | 3.34k | mat.diagonal().tail(size - k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); | 382 | 3.34k | index_of_biggest_in_corner += k; | 383 | | | 384 | 3.34k | transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); | 385 | 3.34k | if (k != index_of_biggest_in_corner) { | 386 | | // apply the transposition while taking care to consider only | 387 | | // the lower triangular part | 388 | 1.84k | Index s = size - index_of_biggest_in_corner - 1; // trailing size after the biggest element | 389 | 1.84k | mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); | 390 | 1.84k | mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); | 391 | 1.84k | std::swap(mat.coeffRef(k, k), mat.coeffRef(index_of_biggest_in_corner, index_of_biggest_in_corner)); | 392 | 7.40k | for (Index i = k + 1; i < index_of_biggest_in_corner; ++i) { | 393 | 5.55k | Scalar tmp = mat.coeffRef(i, k); | 394 | 5.55k | mat.coeffRef(i, k) = numext::conj(mat.coeffRef(index_of_biggest_in_corner, i)); | 395 | 5.55k | mat.coeffRef(index_of_biggest_in_corner, i) = numext::conj(tmp); | 396 | 5.55k | } | 397 | 1.84k | EIGEN_IF_CONSTEXPR (NumTraits<Scalar>::IsComplex) | 398 | | mat.coeffRef(index_of_biggest_in_corner, k) = numext::conj(mat.coeff(index_of_biggest_in_corner, k)); | 399 | 1.84k | } | 400 | | | 401 | | // partition the matrix: | 402 | | // A00 | - | - | 403 | | // lu = A10 | A11 | - | 404 | | // A20 | A21 | A22 | 405 | 3.34k | Index rs = size - k - 1; | 406 | 3.34k | Block<MatrixType, Dynamic, 1> A21(mat, k + 1, k, rs, 1); | 407 | 3.34k | Block<MatrixType, 1, Dynamic> A10(mat, k, 0, 1, k); | 408 | 3.34k | Block<MatrixType, Dynamic, Dynamic> A20(mat, k + 1, 0, rs, k); | 409 | | | 410 | 3.34k | if (k > 0) { | 411 | 3.11k | temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); | 412 | 3.11k | mat.coeffRef(k, k) -= (A10 * temp.head(k)).value(); | 413 | 3.11k | if (rs > 0) A21.noalias() -= A20 * temp.head(k); | 414 | 3.11k | } | 415 | | | 416 | | // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot | 417 | | // was smaller than the cutoff value. However, since LDLT is not rank-revealing | 418 | | // we should only make sure that we do not introduce INF or NaN values. | 419 | | // Remark that LAPACK also uses 0 as the cutoff value. | 420 | 3.34k | RealScalar realAkk = numext::real(mat.coeffRef(k, k)); | 421 | 3.34k | bool pivot_is_valid = (abs(realAkk) > RealScalar(0)); | 422 | | | 423 | 3.34k | if (k == 0 && !pivot_is_valid) { | 424 | | // The entire diagonal is zero, there is nothing more to do | 425 | | // except filling the transpositions, and checking whether the matrix is zero. | 426 | 24 | sign = ZeroSign; | 427 | 260 | for (Index j = 0; j < size; ++j) { | 428 | 236 | transpositions.coeffRef(j) = IndexType(j); | 429 | 236 | ret = ret && (mat.col(j).tail(size - j - 1).array() == Scalar(0)).all(); | 430 | 236 | } | 431 | 24 | return ret; | 432 | 24 | } | 433 | | | 434 | 3.31k | if ((rs > 0) && pivot_is_valid) | 435 | 583 | A21 /= realAkk; | 436 | 2.73k | else if (rs > 0) | 437 | 2.52k | ret = ret && (A21.array() == Scalar(0)).all(); | 438 | | | 439 | 3.31k | if (found_zero_pivot && pivot_is_valid) | 440 | 170 | ret = false; // factorization failed | 441 | 3.14k | else if (!pivot_is_valid) | 442 | 2.68k | found_zero_pivot = true; | 443 | | | 444 | 3.31k | if (sign == PositiveSemiDef) { | 445 | 127 | if (realAkk < static_cast<RealScalar>(0)) sign = Indefinite; | 446 | 3.19k | } else if (sign == NegativeSemiDef) { | 447 | 1.67k | if (realAkk > static_cast<RealScalar>(0)) sign = Indefinite; | 448 | 1.67k | } else if (sign == ZeroSign) { | 449 | 205 | if (realAkk > static_cast<RealScalar>(0)) | 450 | 55 | sign = PositiveSemiDef; | 451 | 150 | else if (realAkk < static_cast<RealScalar>(0)) | 452 | 150 | sign = NegativeSemiDef; | 453 | 205 | } | 454 | 3.31k | } | 455 | | | 456 | 205 | return ret; | 457 | 229 | } |
|
458 | | |
459 | | // Reference for the algorithm: Davis and Hager, "Multiple Rank |
460 | | // Modifications of a Sparse Cholesky Factorization" (Algorithm 1) |
461 | | // Trivial rearrangements of their computations (Timothy E. Holy) |
462 | | // allow their algorithm to work for rank-1 updates even if the |
463 | | // original matrix is not of full rank. |
464 | | // Here only rank-1 updates are implemented, to reduce the |
465 | | // requirement for intermediate storage and improve accuracy |
466 | | template <typename MatrixType, typename WDerived> |
467 | | static bool updateInPlace(MatrixType& mat, MatrixBase<WDerived>& w, |
468 | | const typename MatrixType::RealScalar& sigma = 1) { |
469 | | using numext::isfinite; |
470 | | using Scalar = typename MatrixType::Scalar; |
471 | | using RealScalar = typename MatrixType::RealScalar; |
472 | | |
473 | | const Index size = mat.rows(); |
474 | | eigen_assert(mat.cols() == size && w.size() == size); |
475 | | |
476 | | RealScalar alpha = 1; |
477 | | |
478 | | // Apply the update |
479 | | for (Index j = 0; j < size; j++) { |
480 | | // Check for termination due to an original decomposition of low-rank |
481 | | if (!(isfinite)(alpha)) break; |
482 | | |
483 | | // Update the diagonal terms |
484 | | RealScalar dj = numext::real(mat.coeff(j, j)); |
485 | | Scalar wj = w.coeff(j); |
486 | | RealScalar swj2 = sigma * numext::abs2(wj); |
487 | | RealScalar gamma = dj * alpha + swj2; |
488 | | |
489 | | // A zero contribution leaves both quantities unchanged, but spelling that out as an addition of swj2/alpha and |
490 | | // swj2/dj evaluates 0/0 when alpha or the pivot is zero. The resulting NaN reaches the termination test above |
491 | | // on the next iteration, which reads it as a low-rank signal and abandons the remainder of the update. Skip the |
492 | | // no-op instead. A zero pivot with a nonzero contribution still yields an infinite alpha, so genuine low-rank |
493 | | // termination is unaffected. |
494 | | if (!numext::is_exactly_zero(swj2)) { |
495 | | mat.coeffRef(j, j) += swj2 / alpha; |
496 | | alpha += swj2 / dj; |
497 | | } |
498 | | |
499 | | // Update the terms of L |
500 | | Index rs = size - j - 1; |
501 | | w.tail(rs) -= wj * mat.col(j).tail(rs); |
502 | | if (!numext::is_exactly_zero(gamma)) mat.col(j).tail(rs) += (sigma * numext::conj(wj) / gamma) * w.tail(rs); |
503 | | } |
504 | | return true; |
505 | | } |
506 | | |
507 | | template <typename MatrixType, typename TranspositionType, typename Workspace, typename WType> |
508 | | static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, |
509 | | const typename MatrixType::RealScalar& sigma = 1) { |
510 | | // Apply the permutation to the input w |
511 | | tmp = transpositions * w; |
512 | | |
513 | | return ldlt_inplace<Lower>::updateInPlace(mat, tmp, sigma); |
514 | | } |
515 | | }; |
516 | | |
517 | | template <> |
518 | | struct ldlt_inplace<Upper> { |
519 | | template <typename MatrixType, typename TranspositionType, typename Workspace> |
520 | | static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, |
521 | | SignMatrix& sign) { |
522 | | Transpose<MatrixType> matt(mat); |
523 | | return ldlt_inplace<Lower>::unblocked(matt, transpositions, temp, sign); |
524 | | } |
525 | | |
526 | | template <typename MatrixType, typename TranspositionType, typename Workspace, typename WType> |
527 | | static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, |
528 | | const typename MatrixType::RealScalar& sigma = 1) { |
529 | | Transpose<MatrixType> matt(mat); |
530 | | return ldlt_inplace<Lower>::update(matt, transpositions, tmp, w.conjugate(), sigma); |
531 | | } |
532 | | }; |
533 | | |
534 | | template <typename MatrixType> |
535 | | struct LDLT_Traits<MatrixType, Lower> { |
536 | | using MatrixL = const TriangularView<const MatrixType, UnitLower>; |
537 | | using MatrixU = const TriangularView<const typename MatrixType::AdjointReturnType, UnitUpper>; |
538 | 124 | static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); }Eigen::internal::LDLT_Traits<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::getL(Eigen::Matrix<float, -1, -1, 0, -1, -1> const&) Line | Count | Source | 538 | 62 | static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } |
Eigen::internal::LDLT_Traits<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::getL(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&) Line | Count | Source | 538 | 62 | static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } |
|
539 | 124 | static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); }Eigen::internal::LDLT_Traits<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::getU(Eigen::Matrix<float, -1, -1, 0, -1, -1> const&) Line | Count | Source | 539 | 62 | static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } |
Eigen::internal::LDLT_Traits<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::getU(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&) Line | Count | Source | 539 | 62 | static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } |
|
540 | | }; |
541 | | |
542 | | template <typename MatrixType> |
543 | | struct LDLT_Traits<MatrixType, Upper> { |
544 | | using MatrixL = const TriangularView<const typename MatrixType::AdjointReturnType, UnitLower>; |
545 | | using MatrixU = const TriangularView<const MatrixType, UnitUpper>; |
546 | | static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } |
547 | | static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } |
548 | | }; |
549 | | |
550 | | } // end namespace internal |
551 | | |
552 | | /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix |
553 | | */ |
554 | | template <typename MatrixType, int UpLo_> |
555 | | template <typename InputType> |
556 | 514 | LDLT<MatrixType, UpLo_>& LDLT<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) { |
557 | 514 | eigen_assert(a.rows() == a.cols()); |
558 | 514 | const Index size = a.rows(); |
559 | | |
560 | 514 | m_matrix = a.derived(); |
561 | | |
562 | | // Compute matrix L1 norm = max abs column sum over the implicit self-adjoint matrix. |
563 | 514 | m_l1_norm = m_matrix.template selfadjointView<UpLo_>().l1Norm(); |
564 | | |
565 | 514 | m_transpositions.resize(size); |
566 | 514 | m_isInitialized = false; |
567 | 514 | m_temporary.resize(size); |
568 | 514 | m_sign = internal::ZeroSign; |
569 | | |
570 | 514 | m_info = internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success |
571 | 514 | : NumericalIssue; |
572 | | |
573 | 514 | m_isInitialized = true; |
574 | 514 | return *this; |
575 | 514 | } Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>& Eigen::LDLT<Eigen::Matrix<float, -1, -1, 0, -1, -1>, 1>::compute<Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::EigenBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&) Line | Count | Source | 556 | 279 | LDLT<MatrixType, UpLo_>& LDLT<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) { | 557 | 279 | eigen_assert(a.rows() == a.cols()); | 558 | 279 | const Index size = a.rows(); | 559 | | | 560 | 279 | m_matrix = a.derived(); | 561 | | | 562 | | // Compute matrix L1 norm = max abs column sum over the implicit self-adjoint matrix. | 563 | 279 | m_l1_norm = m_matrix.template selfadjointView<UpLo_>().l1Norm(); | 564 | | | 565 | 279 | m_transpositions.resize(size); | 566 | 279 | m_isInitialized = false; | 567 | 279 | m_temporary.resize(size); | 568 | 279 | m_sign = internal::ZeroSign; | 569 | | | 570 | 279 | m_info = internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success | 571 | 279 | : NumericalIssue; | 572 | | | 573 | 279 | m_isInitialized = true; | 574 | 279 | return *this; | 575 | 279 | } |
Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>& Eigen::LDLT<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1>::compute<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::EigenBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&) Line | Count | Source | 556 | 235 | LDLT<MatrixType, UpLo_>& LDLT<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) { | 557 | 235 | eigen_assert(a.rows() == a.cols()); | 558 | 235 | const Index size = a.rows(); | 559 | | | 560 | 235 | m_matrix = a.derived(); | 561 | | | 562 | | // Compute matrix L1 norm = max abs column sum over the implicit self-adjoint matrix. | 563 | 235 | m_l1_norm = m_matrix.template selfadjointView<UpLo_>().l1Norm(); | 564 | | | 565 | 235 | m_transpositions.resize(size); | 566 | 235 | m_isInitialized = false; | 567 | 235 | m_temporary.resize(size); | 568 | 235 | m_sign = internal::ZeroSign; | 569 | | | 570 | 235 | m_info = internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success | 571 | 235 | : NumericalIssue; | 572 | | | 573 | 235 | m_isInitialized = true; | 574 | 235 | return *this; | 575 | 235 | } |
|
576 | | |
577 | | /** Update the LDLT decomposition: given a decomposition of \f$ A = P^TLDL^*P \f$, efficiently compute the |
578 | | * decomposition of \f$ A + \sigma w w^* \f$. |
579 | | * |
580 | | * If \c *this holds no factorization yet, A is taken to be zero and the decomposition is built from scratch; info() |
581 | | * then reports \c Success. An update applied to an existing factorization leaves info() unchanged, so a |
582 | | * \c NumericalIssue already reported for that factorization stands until compute() replaces it or setZero() discards |
583 | | * it. LLT::rankUpdate() differs on both counts: it requires an existing factorization and re-reports the status on |
584 | | * every call. |
585 | | * |
586 | | * \note rcond(), isPositive() and isNegative() are not maintained across rank updates. rcond() keeps using the L1 |
587 | | * norm recorded by the last compute(), which is zero when there was none, and the definiteness flags are assigned |
588 | | * only where this function builds a factorization from scratch, from the sign of \a sigma alone. |
589 | | * |
590 | | * \param w a vector to be incorporated into the decomposition. |
591 | | * \param sigma a scalar, +1 for updates and -1 for "downdates," which correspond to removing previously-added column |
592 | | * vectors. Optional; default value is +1. |
593 | | * |
594 | | * \sa setZero() |
595 | | */ |
596 | | template <typename MatrixType, int UpLo_> |
597 | | template <typename Derived> |
598 | | LDLT<MatrixType, UpLo_>& LDLT<MatrixType, UpLo_>::rankUpdate( |
599 | | const MatrixBase<Derived>& w, const typename LDLT<MatrixType, UpLo_>::RealScalar& sigma) { |
600 | | using IndexType = typename TranspositionType::StorageIndex; |
601 | | const Index size = w.rows(); |
602 | | if (m_isInitialized) { |
603 | | eigen_assert(m_matrix.rows() == size); |
604 | | } else { |
605 | | m_matrix.resize(size, size); |
606 | | m_matrix.setZero(); |
607 | | m_transpositions.resize(size); |
608 | | for (Index i = 0; i < size; i++) m_transpositions.coeffRef(i) = IndexType(i); |
609 | | m_temporary.resize(size); |
610 | | m_sign = sigma >= 0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; |
611 | | m_isInitialized = true; |
612 | | // Assigned here rather than after the branch: updating an existing factorization keeps the status it already has. |
613 | | m_info = Success; |
614 | | } |
615 | | |
616 | | internal::ldlt_inplace<UpLo>::update(m_matrix, m_transpositions, m_temporary, w, sigma); |
617 | | |
618 | | return *this; |
619 | | } |
620 | | |
621 | | // A = P^T L D L^* P with L unit lower triangular and D real diagonal, so det(A) = prod(D_ii). |
622 | | |
623 | | template <typename MatrixType_, int UpLo_> |
624 | | typename LDLT<MatrixType_, UpLo_>::Scalar LDLT<MatrixType_, UpLo_>::determinant() const { |
625 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
626 | | eigen_assert(m_info == Success && "LDLT failed because of a zero pivot."); |
627 | | return Scalar(vectorD().real().prod()); |
628 | | } |
629 | | |
630 | | template <typename MatrixType_, int UpLo_> |
631 | | typename LDLT<MatrixType_, UpLo_>::RealScalar LDLT<MatrixType_, UpLo_>::absDeterminant() const { |
632 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
633 | | eigen_assert(m_info == Success && "LDLT failed because of a zero pivot."); |
634 | | return numext::abs(vectorD().real().prod()); |
635 | | } |
636 | | |
637 | | template <typename MatrixType_, int UpLo_> |
638 | | typename LDLT<MatrixType_, UpLo_>::RealScalar LDLT<MatrixType_, UpLo_>::logAbsDeterminant() const { |
639 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
640 | | eigen_assert(m_info == Success && "LDLT failed because of a zero pivot."); |
641 | | return vectorD().real().cwiseAbs().array().log().sum(); |
642 | | } |
643 | | |
644 | | template <typename MatrixType_, int UpLo_> |
645 | | typename LDLT<MatrixType_, UpLo_>::Scalar LDLT<MatrixType_, UpLo_>::signDeterminant() const { |
646 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
647 | | eigen_assert(m_info == Success && "LDLT failed because of a zero pivot."); |
648 | | return Scalar(vectorD().real().array().sign().prod()); |
649 | | } |
650 | | |
651 | | #ifndef EIGEN_PARSED_BY_DOXYGEN |
652 | | template <typename MatrixType_, int UpLo_> |
653 | | template <typename RhsType, typename DstType> |
654 | | void LDLT<MatrixType_, UpLo_>::_solve_impl(const RhsType& rhs, DstType& dst) const { |
655 | | _solve_impl_transposed<true>(rhs, dst); |
656 | | } |
657 | | |
658 | | template <typename MatrixType_, int UpLo_> |
659 | | template <bool Conjugate, typename RhsType, typename DstType> |
660 | | void LDLT<MatrixType_, UpLo_>::_solve_impl_transposed(const RhsType& rhs, DstType& dst) const { |
661 | | // dst = P b |
662 | | dst = m_transpositions * rhs; |
663 | | |
664 | | // dst = L^-1 (P b) |
665 | | // dst = L^-*T (P b) |
666 | | matrixL().template conjugateIf<!Conjugate>().solveInPlace(dst); |
667 | | |
668 | | // dst = D^-* (L^-1 P b) |
669 | | // dst = D^-1 (L^-*T P b) |
670 | | // more precisely, use pseudo-inverse of D (see bug 241) |
671 | | using std::abs; |
672 | | const typename Diagonal<const MatrixType>::RealReturnType vecD(vectorD()); |
673 | | // In some previous versions, tolerance was set to the max of 1/highest (or rather numeric_limits::min()) |
674 | | // and the maximal diagonal entry * epsilon as motivated by LAPACK's xGELSS: |
675 | | // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits<RealScalar>::epsilon(),RealScalar(1) |
676 | | // / NumTraits<RealScalar>::highest()); However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the |
677 | | // highest diagonal element is not well justified and leads to numerical issues in some cases. Moreover, Lapack's |
678 | | // xSYTRS routines use 0 for the tolerance. Using numeric_limits::min() gives us more robustness to denormals. |
679 | | RealScalar tolerance = (std::numeric_limits<RealScalar>::min)(); |
680 | | for (Index i = 0; i < vecD.size(); ++i) { |
681 | | if (abs(vecD(i)) > tolerance) |
682 | | dst.row(i) /= vecD(i); |
683 | | else |
684 | | dst.row(i).setZero(); |
685 | | } |
686 | | |
687 | | // dst = L^-* (D^-* L^-1 P b) |
688 | | // dst = L^-T (D^-1 L^-*T P b) |
689 | | matrixL().transpose().template conjugateIf<Conjugate>().solveInPlace(dst); |
690 | | |
691 | | // dst = P^T (L^-* D^-* L^-1 P b) = A^-1 b |
692 | | // dst = P^-T (L^-T D^-1 L^-*T P b) = A^-1 b |
693 | | dst = m_transpositions.transpose() * dst; |
694 | | } |
695 | | #endif |
696 | | |
697 | | /** \internal use x = ldlt_object.solve(x); |
698 | | * |
699 | | * This is the \em in-place version of solve(). |
700 | | * |
701 | | * \param bAndX represents both the right-hand side matrix b and result x. |
702 | | * |
703 | | * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. |
704 | | * |
705 | | * This version avoids a copy when the right hand side matrix b is not |
706 | | * needed anymore. |
707 | | * |
708 | | * \sa LDLT::solve(), MatrixBase::ldlt() |
709 | | */ |
710 | | template <typename MatrixType, int UpLo_> |
711 | | template <typename Derived> |
712 | | bool LDLT<MatrixType, UpLo_>::solveInPlace(MatrixBase<Derived>& bAndX) const { |
713 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
714 | | eigen_assert(m_matrix.rows() == bAndX.rows()); |
715 | | |
716 | | bAndX = this->solve(bAndX); |
717 | | |
718 | | return true; |
719 | | } |
720 | | |
721 | | /** \returns the matrix represented by the decomposition, |
722 | | * i.e., it returns the product: P^T L D L^* P. |
723 | | * This function is provided for debug purpose. */ |
724 | | template <typename MatrixType, int UpLo_> |
725 | | MatrixType LDLT<MatrixType, UpLo_>::reconstructedMatrix() const { |
726 | | eigen_assert(m_isInitialized && "LDLT is not initialized."); |
727 | | const Index size = m_matrix.rows(); |
728 | | MatrixType res(size, size); |
729 | | |
730 | | // P |
731 | | res.setIdentity(); |
732 | | res = transpositionsP() * res; |
733 | | // L^* P |
734 | | res = matrixU() * res; |
735 | | // D(L^*P) |
736 | | res = vectorD().real().asDiagonal() * res; |
737 | | // L(DL^*P) |
738 | | res = matrixL() * res; |
739 | | // P^T (LDL^*P) |
740 | | res = transpositionsP().transpose() * res; |
741 | | |
742 | | return res; |
743 | | } |
744 | | |
745 | | /** \cholesky_module |
746 | | * \returns the Cholesky decomposition with full pivoting without square root of \c *this |
747 | | * \sa MatrixBase::ldlt() |
748 | | */ |
749 | | template <typename MatrixType, unsigned int UpLo> |
750 | | inline LDLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo> SelfAdjointView<MatrixType, UpLo>::ldlt() |
751 | | const { |
752 | | return LDLT<PlainObject, UpLo>(m_matrix); |
753 | | } |
754 | | |
755 | | /** \cholesky_module |
756 | | * \returns the Cholesky decomposition with full pivoting without square root of \c *this |
757 | | * \sa SelfAdjointView::ldlt() |
758 | | */ |
759 | | template <typename Derived> |
760 | | inline LDLT<typename MatrixBase<Derived>::PlainObject> MatrixBase<Derived>::ldlt() const { |
761 | | return LDLT<PlainObject>(derived()); |
762 | | } |
763 | | |
764 | | } // end namespace Eigen |
765 | | |
766 | | #endif // EIGEN_LDLT_H |