Coverage Report

Created: 2026-10-05 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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