Eigen  5.0.1
 
Loading...
Searching...
No Matches
SuiteSparseQRSupport.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2012 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
5// Copyright (C) 2014 Gael Guennebaud <gael.guennebaud@inria.fr>
6//
7// This Source Code Form is subject to the terms of the Mozilla
8// Public License v. 2.0. If a copy of the MPL was not distributed
9// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10// SPDX-License-Identifier: MPL-2.0
11
12#ifndef EIGEN_SUITESPARSEQRSUPPORT_H
13#define EIGEN_SUITESPARSEQRSUPPORT_H
14
15// IWYU pragma: private
16#include "./InternalHeaderCheck.h"
17
18namespace Eigen {
19
20template <typename MatrixType>
21class SPQR;
22template <typename SPQRType>
23struct SPQRMatrixQReturnType;
24template <typename SPQRType>
25struct SPQRMatrixQTransposeReturnType;
26template <typename SPQRType, typename Derived>
27struct SPQR_QProduct;
28namespace internal {
29template <typename SPQRType>
30struct traits<SPQRMatrixQReturnType<SPQRType> > {
31 typedef typename SPQRType::MatrixType ReturnType;
32 typedef typename ReturnType::Scalar Scalar;
33 typedef typename ReturnType::StorageIndex StorageIndex;
34 typedef typename ReturnType::StorageKind StorageKind;
35 static constexpr int RowsAtCompileTime = Dynamic;
36 static constexpr int ColsAtCompileTime = Dynamic;
37};
38template <typename SPQRType>
39struct traits<SPQRMatrixQTransposeReturnType<SPQRType> > {
40 typedef typename SPQRType::MatrixType ReturnType;
41};
42template <typename SPQRType, typename Derived>
43struct traits<SPQR_QProduct<SPQRType, Derived> > {
44 typedef typename Derived::PlainObject ReturnType;
45};
46} // End namespace internal
47
72template <typename MatrixType_>
73class SPQR : public SparseSolverBase<SPQR<MatrixType_> > {
74 protected:
76 using Base::m_isInitialized;
77
78 public:
79 typedef typename MatrixType_::Scalar Scalar;
80 typedef typename MatrixType_::RealScalar RealScalar;
81 typedef SuiteSparse_long StorageIndex;
84 enum { ColsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic };
85
86 public:
87 SPQR()
88 : m_analysisIsOk(false),
89 m_factorizationIsOk(false),
90 m_isRUpToDate(false),
91 m_ordering(SPQR_ORDERING_DEFAULT),
92 m_allow_tol(SPQR_DEFAULT_TOL),
93 m_tolerance(NumTraits<Scalar>::epsilon()),
94 m_cR(0),
95 m_E(0),
96 m_H(0),
97 m_HPinv(0),
98 m_HTau(0),
99 m_useDefaultThreshold(true) {
100 cholmod_l_start(&m_cc);
101 }
102
103 explicit SPQR(const MatrixType_& matrix)
104 : m_analysisIsOk(false),
105 m_factorizationIsOk(false),
106 m_isRUpToDate(false),
107 m_ordering(SPQR_ORDERING_DEFAULT),
108 m_allow_tol(SPQR_DEFAULT_TOL),
109 m_tolerance(NumTraits<Scalar>::epsilon()),
110 m_cR(0),
111 m_E(0),
112 m_H(0),
113 m_HPinv(0),
114 m_HTau(0),
115 m_useDefaultThreshold(true) {
116 cholmod_l_start(&m_cc);
117 compute(matrix);
118 }
119
120 ~SPQR() {
121 SPQR_free();
122 cholmod_l_finish(&m_cc);
123 }
124 void SPQR_free() {
125 cholmod_l_free_sparse(&m_H, &m_cc);
126 cholmod_l_free_sparse(&m_cR, &m_cc);
127 cholmod_l_free_dense(&m_HTau, &m_cc);
128 std::free(m_E);
129 m_E = nullptr;
130 std::free(m_HPinv);
131 m_HPinv = nullptr;
132 }
133
134 void compute(const MatrixType_& matrix) {
135 if (m_isInitialized) SPQR_free();
136
137 MatrixType mat(matrix);
138
139 /* Compute the default threshold as in MatLab, see:
140 * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
141 * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3
142 */
143 RealScalar pivotThreshold = m_tolerance;
144 if (m_useDefaultThreshold) {
145 RealScalar max2Norm = 0.0;
146 for (int j = 0; j < mat.cols(); j++) max2Norm = numext::maxi(max2Norm, mat.col(j).norm());
147 if (numext::is_exactly_zero(max2Norm)) max2Norm = RealScalar(1);
148 pivotThreshold = 20 * (mat.rows() + mat.cols()) * max2Norm * NumTraits<RealScalar>::epsilon();
149 }
150 cholmod_sparse A;
151 A = viewAsCholmod(mat);
152 m_rows = matrix.rows();
153 m_rank = SuiteSparseQR<Scalar>(m_ordering, pivotThreshold, internal::convert_index<StorageIndex>(matrix.cols()), &A,
154 &m_cR, &m_E, &m_H, &m_HPinv, &m_HTau, &m_cc);
155
156 if (!m_cR) {
157 m_info = NumericalIssue;
158 m_isInitialized = false;
159 return;
160 }
161 if (!m_E && !initIdentityPermutation(m_cR->ncol)) {
162 SPQR_free();
163 m_info = NumericalIssue;
164 m_isInitialized = false;
165 return;
166 }
167 m_info = Success;
168 m_isInitialized = true;
169 m_isRUpToDate = false;
170 }
174 inline Index rows() const { return m_rows; }
175
179 inline Index cols() const { return m_cR->ncol; }
180
181 template <typename Rhs, typename Dest>
182 void _solve_impl(const MatrixBase<Rhs>& b, MatrixBase<Dest>& dest) const {
183 eigen_assert(m_isInitialized && " The QR factorization should be computed first, call compute()");
184 eigen_assert(b.cols() == 1 && "This method is for vectors only");
185
186 // Compute Q^T * b
187 typename Dest::PlainObject y, y2;
188 y = matrixQ().transpose() * b;
189
190 // Solves with the triangular matrix R
191 Index rk = this->rank();
192 y2 = y;
193 y.resize((std::max)(cols(), Index(y.rows())), y.cols());
194 y.topRows(rk) = this->matrixR().topLeftCorner(rk, rk).template triangularView<Upper>().solve(y2.topRows(rk));
195
196 // Apply the column permutation
197 // colsPermutation() performs a copy of the permutation,
198 // so let's apply it manually:
199 for (Index i = 0; i < rk; ++i) dest.row(m_E[i]) = y.row(i);
200 for (Index i = rk; i < cols(); ++i) dest.row(m_E[i]).setZero();
201
202 m_info = Success;
203 }
204
207 const MatrixType& matrixR() const {
208 eigen_assert(m_isInitialized && " The QR factorization should be computed first, call compute()");
209 if (!m_isRUpToDate) {
210 m_R = viewAsEigen<Scalar, StorageIndex>(*m_cR);
211 m_isRUpToDate = true;
212 }
213 return m_R;
214 }
215
216 SPQRMatrixQReturnType<SPQR> matrixQ() const { return SPQRMatrixQReturnType<SPQR>(*this); }
218 PermutationType colsPermutation() const {
219 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
220 return PermutationType(m_E, m_cR->ncol);
221 }
222
227 Index rank() const {
228 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
229 return m_cc.SPQR_istat[4];
230 }
231
232 void setSPQROrdering(int ord) { m_ordering = ord; }
234 void setPivotThreshold(const RealScalar& tol) {
235 m_useDefaultThreshold = false;
236 m_tolerance = tol;
237 }
238
240 cholmod_common* cholmodCommon() const { return &m_cc; }
241
248 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
249 return m_info;
250 }
251
252 protected:
253 bool m_analysisIsOk;
254 bool m_factorizationIsOk;
255 mutable bool m_isRUpToDate;
256 mutable ComputationInfo m_info;
257 int m_ordering; // Ordering method to use, see SPQR's manual
258 int m_allow_tol; // Allow to use some tolerance during numerical factorization.
259 RealScalar m_tolerance; // treat columns with 2-norm below this tolerance as zero
260 mutable cholmod_sparse* m_cR = nullptr; // The sparse R factor in cholmod format
261 mutable MatrixType m_R; // The sparse matrix R in Eigen format
262 mutable StorageIndex* m_E = nullptr; // The permutation applied to columns
263 mutable cholmod_sparse* m_H = nullptr; // The householder vectors
264 mutable StorageIndex* m_HPinv = nullptr; // The row permutation of H
265 mutable cholmod_dense* m_HTau = nullptr; // The Householder coefficients
266 mutable Index m_rank; // The rank of the matrix
267 mutable cholmod_common m_cc; // Workspace and parameters
268 bool m_useDefaultThreshold; // Use default threshold
269 Index m_rows;
270
271 bool initIdentityPermutation(StorageIndex size) {
272 if (m_E || size == 0) return true;
273 // SuiteSparse can omit the permutation array when no column reordering is applied.
274 m_E = static_cast<StorageIndex*>(std::malloc(sizeof(StorageIndex) * size));
275 if (!m_E) return false;
276 for (StorageIndex i = 0; i < size; ++i) m_E[i] = i;
277 return true;
278 }
279
280 template <typename, typename>
281 friend struct SPQR_QProduct;
282};
283
284template <typename SPQRType, typename Derived>
285struct SPQR_QProduct : ReturnByValue<SPQR_QProduct<SPQRType, Derived> > {
286 typedef typename SPQRType::Scalar Scalar;
287 typedef typename SPQRType::StorageIndex StorageIndex;
288 // Define the constructor to get reference to argument types
289 SPQR_QProduct(const SPQRType& spqr, const Derived& other, bool transpose)
290 : m_spqr(spqr), m_other(other), m_transpose(transpose) {}
291
292 inline Index rows() const { return m_spqr.rows(); }
293 inline Index cols() const { return m_other.cols(); }
294 // Assign to a vector
295 template <typename ResType>
296 void evalTo(ResType& res) const {
297 evalToImpl(res, m_other);
298 }
299
300 private:
301 template <typename ResType, typename OtherDerived,
302 std::enable_if_t<(int(OtherDerived::Flags) & DirectAccessBit) == DirectAccessBit, int> = 0>
303 void evalToImpl(ResType& res, const MatrixBase<OtherDerived>& otherExpr) const {
304 cholmod_dense y_cd;
305 cholmod_dense* x_cd;
306 int method = m_transpose ? SPQR_QTX : SPQR_QX;
307 cholmod_common* cc = m_spqr.cholmodCommon();
308 y_cd = viewAsCholmod(otherExpr.const_cast_derived());
309 x_cd = SuiteSparseQR_qmult<Scalar>(method, m_spqr.m_H, m_spqr.m_HTau, m_spqr.m_HPinv, &y_cd, cc);
310 res = Matrix<Scalar, ResType::RowsAtCompileTime, ResType::ColsAtCompileTime>::Map(
311 reinterpret_cast<Scalar*>(x_cd->x), x_cd->nrow, x_cd->ncol);
312 cholmod_l_free_dense(&x_cd, cc);
313 }
314
315 template <typename ResType, typename OtherDerived,
316 std::enable_if_t<(int(OtherDerived::Flags) & DirectAccessBit) == 0, int> = 0>
317 void evalToImpl(ResType& res, const MatrixBase<OtherDerived>& otherExpr) const {
318 cholmod_dense y_cd;
319 cholmod_dense* x_cd;
320 int method = m_transpose ? SPQR_QTX : SPQR_QX;
321 cholmod_common* cc = m_spqr.cholmodCommon();
322 typename OtherDerived::PlainObject other = otherExpr;
323 y_cd = viewAsCholmod(other);
324 x_cd = SuiteSparseQR_qmult<Scalar>(method, m_spqr.m_H, m_spqr.m_HTau, m_spqr.m_HPinv, &y_cd, cc);
325 res = Matrix<Scalar, ResType::RowsAtCompileTime, ResType::ColsAtCompileTime>::Map(
326 reinterpret_cast<Scalar*>(x_cd->x), x_cd->nrow, x_cd->ncol);
327 cholmod_l_free_dense(&x_cd, cc);
328 }
329
330 template <typename ResType, typename OtherDerived>
331 void evalToImpl(ResType& res, const SparseMatrixBase<OtherDerived>& otherExpr) const {
332 cholmod_sparse y_cs;
333 cholmod_sparse* x_cs;
334 int method = m_transpose ? SPQR_QTX : SPQR_QX;
335 cholmod_common* cc = m_spqr.cholmodCommon();
336 typename OtherDerived::PlainObject other = otherExpr;
337 other.makeCompressed();
338 y_cs = viewAsCholmod(other);
339 x_cs = SuiteSparseQR_qmult<Scalar>(method, m_spqr.m_H, m_spqr.m_HTau, m_spqr.m_HPinv, &y_cs, cc);
340 res = viewAsEigen<Scalar, StorageIndex>(*x_cs);
341 cholmod_l_free_sparse(&x_cs, cc);
342 }
343
344 template <typename ResType, typename OtherScalar, int OtherOptions, typename OtherStorageIndex,
345 std::enable_if_t<std::is_same<OtherStorageIndex, StorageIndex>::value, int> = 0>
346 void evalToImpl(ResType& res, const SparseMatrix<OtherScalar, OtherOptions, OtherStorageIndex>& otherExpr) const {
347 cholmod_sparse y_cs;
348 cholmod_sparse* x_cs;
349 int method = m_transpose ? SPQR_QTX : SPQR_QX;
350 cholmod_common* cc = m_spqr.cholmodCommon();
351 const SparseMatrix<OtherScalar, OtherOptions, OtherStorageIndex>* otherPtr = &otherExpr;
352 SparseMatrix<OtherScalar, OtherOptions, OtherStorageIndex> other;
353
354 if (!otherExpr.isCompressed()) {
355 other = otherExpr;
356 other.makeCompressed();
357 otherPtr = &other;
358 }
359
360 y_cs = viewAsCholmod(*otherPtr);
361 x_cs = SuiteSparseQR_qmult<Scalar>(method, m_spqr.m_H, m_spqr.m_HTau, m_spqr.m_HPinv, &y_cs, cc);
362 res = viewAsEigen<Scalar, StorageIndex>(*x_cs);
363 cholmod_l_free_sparse(&x_cs, cc);
364 }
365
366 public:
367 const SPQRType& m_spqr;
368 const Derived& m_other;
369 bool m_transpose;
370};
371template <typename SPQRType>
372struct SPQRMatrixQReturnType : public EigenBase<SPQRMatrixQReturnType<SPQRType> > {
373 typedef typename SPQRType::Scalar Scalar;
374 static constexpr int RowsAtCompileTime = Dynamic;
375 static constexpr int ColsAtCompileTime = Dynamic;
376 SPQRMatrixQReturnType(const SPQRType& spqr) : m_spqr(spqr) {}
377 template <typename Derived>
378 SPQR_QProduct<SPQRType, Derived> operator*(const MatrixBase<Derived>& other) {
379 return SPQR_QProduct<SPQRType, Derived>(m_spqr, other.derived(), false);
380 }
381 template <typename Derived>
382 SPQR_QProduct<SPQRType, Derived> operator*(const SparseMatrixBase<Derived>& other) {
383 return SPQR_QProduct<SPQRType, Derived>(m_spqr, other.derived(), false);
384 }
385 SPQRMatrixQTransposeReturnType<SPQRType> adjoint() const { return SPQRMatrixQTransposeReturnType<SPQRType>(m_spqr); }
386 inline Index rows() const { return m_spqr.rows(); }
387 inline Index cols() const { return m_spqr.rows(); }
388 // To use for operations with the transpose of Q
389 SPQRMatrixQTransposeReturnType<SPQRType> transpose() const {
390 return SPQRMatrixQTransposeReturnType<SPQRType>(m_spqr);
391 }
392 const SPQRType& m_spqr;
393};
394
395template <typename SPQRType>
396struct SPQRMatrixQTransposeReturnType {
397 SPQRMatrixQTransposeReturnType(const SPQRType& spqr) : m_spqr(spqr) {}
398 template <typename Derived>
399 SPQR_QProduct<SPQRType, Derived> operator*(const MatrixBase<Derived>& other) {
400 return SPQR_QProduct<SPQRType, Derived>(m_spqr, other.derived(), true);
401 }
402 template <typename Derived>
403 SPQR_QProduct<SPQRType, Derived> operator*(const SparseMatrixBase<Derived>& other) {
404 return SPQR_QProduct<SPQRType, Derived>(m_spqr, other.derived(), true);
405 }
406 const SPQRType& m_spqr;
407};
408
409namespace internal {
410
411template <typename SPQRType>
412struct evaluator_traits<SPQRMatrixQReturnType<SPQRType> > {
413 typedef typename SPQRType::MatrixType MatrixType;
414 typedef typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind Kind;
415 typedef SparseShape Shape;
416};
417
418template <typename DstXprType, typename SPQRType>
419struct Assignment<DstXprType, SPQRMatrixQReturnType<SPQRType>,
420 internal::assign_op<typename DstXprType::Scalar, typename DstXprType::Scalar>, Sparse2Sparse> {
421 typedef SPQRMatrixQReturnType<SPQRType> SrcXprType;
422 typedef typename DstXprType::Scalar Scalar;
423
424 static void run(DstXprType& dst, const SrcXprType& src, const internal::assign_op<Scalar, Scalar>& /*func*/) {
425 typename DstXprType::PlainObject idMat(src.rows(), src.cols());
426 idMat.setIdentity();
427 dst = src.m_spqr.matrixQ() * idMat;
428 }
429};
430
431template <typename DstXprType, typename SPQRType>
432struct Assignment<DstXprType, SPQRMatrixQReturnType<SPQRType>,
433 internal::assign_op<typename DstXprType::Scalar, typename DstXprType::Scalar>, Sparse2Dense> {
434 typedef SPQRMatrixQReturnType<SPQRType> SrcXprType;
435 typedef typename DstXprType::Scalar Scalar;
436
437 static void run(DstXprType& dst, const SrcXprType& src, const internal::assign_op<Scalar, Scalar>& /*func*/) {
438 dst = src.m_spqr.matrixQ() * DstXprType::Identity(src.rows(), src.cols());
439 }
440};
441
442} // namespace internal
443
444} // End namespace Eigen
445#endif
constexpr RowXpr row(Index i)
Definition DenseBase.h:1094
A matrix or vector expression mapping an existing array of data.
Definition Map.h:97
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
Sparse QR factorization based on SuiteSparseQR library.
Definition SuiteSparseQRSupport.h:73
void setPivotThreshold(const RealScalar &tol)
Set the tolerance tol to treat columns with 2-norm <= tol as zero.
Definition SuiteSparseQRSupport.h:234
Index rank() const
Definition SuiteSparseQRSupport.h:227
cholmod_common * cholmodCommon() const
Definition SuiteSparseQRSupport.h:240
SPQRMatrixQReturnType< SPQR > matrixQ() const
Get an expression of the matrix Q.
Definition SuiteSparseQRSupport.h:216
ComputationInfo info() const
Reports whether previous computation was successful.
Definition SuiteSparseQRSupport.h:247
Index rows() const
Definition SuiteSparseQRSupport.h:174
Index cols() const
Definition SuiteSparseQRSupport.h:179
const MatrixType & matrixR() const
Definition SuiteSparseQRSupport.h:207
PermutationType colsPermutation() const
Get the permutation that was applied to columns of A.
Definition SuiteSparseQRSupport.h:218
void setSPQROrdering(int ord)
Set the fill-reducing ordering method to be used.
Definition SuiteSparseQRSupport.h:232
constexpr FixedBlockXpr<...,... >::Type topLeftCorner(NRowsType cRows, NColsType cCols)
Definition SparseMatrixBase.h:287
constexpr ColXpr col(Index i)
Definition SparseMatrixBase.h:1081
A versatile sparse matrix representation.
Definition SparseMatrix.h:122
Index cols() const
Definition SparseMatrix.h:162
Index rows() const
Definition SparseMatrix.h:160
ComputationInfo
Definition Constants.h:455
@ NumericalIssue
Definition Constants.h:459
@ Success
Definition Constants.h:457
constexpr unsigned int DirectAccessBit
Definition Constants.h:160
Definition EigenBase.h:34
Eigen::Index Index
Definition EigenBase.h:44