12#include <lagrange/utils/build.h>
14#if LAGRANGE_TARGET_OS(APPLE)
16 #include <Accelerate/Accelerate.h>
17 #include <Eigen/Sparse>
19namespace lagrange::solver::internal {
21template <
typename MatrixType_,
int UpLo_, SparseFactorization_t Solver_,
bool EnforceSquare_>
35template <
typename MatrixType,
int UpLo = Eigen::Lower>
37 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationCholesky, true>;
50template <
typename MatrixType,
int UpLo = Eigen::Lower>
52 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLT, true>;
66template <
typename MatrixType,
int UpLo = Eigen::Lower>
67using AccelerateLDLTUnpivoted =
68 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLTUnpivoted, true>;
82template <
typename MatrixType,
int UpLo = Eigen::Lower>
83using AccelerateLDLTSBK =
84 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLTSBK, true>;
98template <
typename MatrixType,
int UpLo = Eigen::Lower>
99using AccelerateLDLTTPP =
100 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLTTPP, true>;
112template <
typename MatrixType>
113using AccelerateQR = AccelerateImpl<MatrixType, 0, SparseFactorizationQR, false>;
126template <
typename MatrixType>
127using AccelerateCholeskyAtA = AccelerateImpl<MatrixType, 0, SparseFactorizationCholeskyAtA, false>;
131struct AccelFactorizationDeleter
133 void operator()(T* sym)
143template <
typename DenseVecT,
typename DenseMatT,
typename SparseMatT,
typename NumFactT>
144struct SparseTypesTraitBase
146 typedef DenseVecT AccelDenseVector;
147 typedef DenseMatT AccelDenseMatrix;
148 typedef SparseMatT AccelSparseMatrix;
150 typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
151 typedef NumFactT NumericFactorization;
153 typedef AccelFactorizationDeleter<SymbolicFactorization> SymbolicFactorizationDeleter;
154 typedef AccelFactorizationDeleter<NumericFactorization> NumericFactorizationDeleter;
157template <
typename Scalar>
158struct SparseTypesTrait
163struct SparseTypesTrait<double> : SparseTypesTraitBase<
167 SparseOpaqueFactorization_Double>
172struct SparseTypesTrait<float> : SparseTypesTraitBase<
176 SparseOpaqueFactorization_Float>
182template <
typename MatrixType_,
int UpLo_, SparseFactorization_t Solver_,
bool EnforceSquare_>
184 :
public Eigen::SparseSolverBase<AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>>
187 using Base = Eigen::SparseSolverBase<AccelerateImpl>;
189 using Base::m_isInitialized;
192 using Base::_solve_impl;
194 typedef MatrixType_ MatrixType;
195 typedef typename MatrixType::Scalar Scalar;
196 typedef typename MatrixType::StorageIndex StorageIndex;
197 enum { ColsAtCompileTime = Eigen::Dynamic, MaxColsAtCompileTime = Eigen::Dynamic };
198 enum { UpLo = UpLo_ };
200 using AccelDenseVector =
typename internal::SparseTypesTrait<Scalar>::AccelDenseVector;
201 using AccelDenseMatrix =
typename internal::SparseTypesTrait<Scalar>::AccelDenseMatrix;
202 using AccelSparseMatrix =
typename internal::SparseTypesTrait<Scalar>::AccelSparseMatrix;
203 using SymbolicFactorization =
204 typename internal::SparseTypesTrait<Scalar>::SymbolicFactorization;
205 using NumericFactorization =
typename internal::SparseTypesTrait<Scalar>::NumericFactorization;
206 using SymbolicFactorizationDeleter =
207 typename internal::SparseTypesTrait<Scalar>::SymbolicFactorizationDeleter;
208 using NumericFactorizationDeleter =
209 typename internal::SparseTypesTrait<Scalar>::NumericFactorizationDeleter;
213 m_isInitialized =
false;
215 auto check_flag_set = [](
int value,
int flag) {
return ((value & flag) == flag); };
217 if (check_flag_set(UpLo_, Eigen::Symmetric)) {
218 m_sparseKind = SparseSymmetric;
219 m_triType = (UpLo_ & Eigen::Lower) ? SparseLowerTriangle : SparseUpperTriangle;
220 }
else if (check_flag_set(UpLo_, Eigen::UnitLower)) {
221 m_sparseKind = SparseUnitTriangular;
222 m_triType = SparseLowerTriangle;
223 }
else if (check_flag_set(UpLo_, Eigen::UnitUpper)) {
224 m_sparseKind = SparseUnitTriangular;
225 m_triType = SparseUpperTriangle;
226 }
else if (check_flag_set(UpLo_, Eigen::StrictlyLower)) {
227 m_sparseKind = SparseTriangular;
228 m_triType = SparseLowerTriangle;
229 }
else if (check_flag_set(UpLo_, Eigen::StrictlyUpper)) {
230 m_sparseKind = SparseTriangular;
231 m_triType = SparseUpperTriangle;
232 }
else if (check_flag_set(UpLo_, Eigen::Lower)) {
233 m_sparseKind = SparseTriangular;
234 m_triType = SparseLowerTriangle;
235 }
else if (check_flag_set(UpLo_, Eigen::Upper)) {
236 m_sparseKind = SparseTriangular;
237 m_triType = SparseUpperTriangle;
239 m_sparseKind = SparseOrdinary;
240 m_triType = (UpLo_ & Eigen::Lower) ? SparseLowerTriangle : SparseUpperTriangle;
243 m_order = SparseOrderDefault;
246 explicit AccelerateImpl(
const MatrixType& matrix)
254 inline Eigen::Index cols()
const {
return m_nCols; }
255 inline Eigen::Index rows()
const {
return m_nRows; }
257 Eigen::ComputationInfo info()
const
259 eigen_assert(m_isInitialized &&
"Decomposition is not initialized.");
263 void analyzePattern(
const MatrixType& matrix);
265 void factorize(
const MatrixType& matrix);
267 void compute(
const MatrixType& matrix);
269 template <
typename Rhs,
typename Dest>
270 void _solve_impl(
const Eigen::MatrixBase<Rhs>& b, Eigen::MatrixBase<Dest>& dest)
const;
273 void setOrder(SparseOrder_t order) { m_order = order; }
276 template <
typename T>
277 void buildAccelSparseMatrix(
278 const Eigen::SparseMatrix<T>& a,
279 AccelSparseMatrix& A,
280 std::vector<long>& columnStarts)
282 const Eigen::Index nColumnsStarts = a.cols() + 1;
284 columnStarts.resize(nColumnsStarts);
286 for (Eigen::Index i = 0; i < nColumnsStarts; i++) columnStarts[i] = a.outerIndexPtr()[i];
288 SparseAttributes_t attributes{};
289 attributes.transpose =
false;
290 attributes.triangle = m_triType;
291 attributes.kind = m_sparseKind;
293 SparseMatrixStructure structure{};
294 structure.attributes = attributes;
295 structure.rowCount =
static_cast<int>(a.rows());
296 structure.columnCount =
static_cast<int>(a.cols());
297 structure.blockSize = 1;
298 structure.columnStarts = columnStarts.data();
299 structure.rowIndices =
const_cast<int*
>(a.innerIndexPtr());
301 A.structure = structure;
302 A.data =
const_cast<T*
>(a.valuePtr());
305 void doAnalysis(AccelSparseMatrix& A)
307 m_numericFactorization.reset(
nullptr);
309 SparseSymbolicFactorOptions opts{};
310 opts.control = SparseDefaultControl;
311 opts.orderMethod = m_order;
312 opts.order =
nullptr;
313 opts.ignoreRowsAndColumns =
nullptr;
314 opts.malloc = malloc;
316 opts.reportError =
nullptr;
318 m_symbolicFactorization.reset(
319 new SymbolicFactorization(SparseFactor(Solver_, A.structure, opts)));
321 SparseStatus_t status = m_symbolicFactorization->status;
323 updateInfoStatus(status);
325 if (status != SparseStatusOK) m_symbolicFactorization.reset(
nullptr);
328 void doFactorization(AccelSparseMatrix& A)
330 SparseStatus_t status = SparseStatusReleased;
332 if (m_symbolicFactorization) {
333 m_numericFactorization.reset(
334 new NumericFactorization(SparseFactor(*m_symbolicFactorization, A)));
336 status = m_numericFactorization->status;
338 if (status != SparseStatusOK) m_numericFactorization.reset(
nullptr);
341 updateInfoStatus(status);
345 void updateInfoStatus(SparseStatus_t status)
const
348 case SparseStatusOK: m_info = Eigen::Success;
break;
349 case SparseFactorizationFailed:
350 case SparseMatrixIsSingular: m_info = Eigen::NumericalIssue;
break;
351 case SparseInternalError:
352 case SparseParameterError:
353 case SparseStatusReleased:
354 default: m_info = Eigen::InvalidInput;
break;
358 mutable Eigen::ComputationInfo m_info;
359 Eigen::Index m_nRows, m_nCols;
360 std::unique_ptr<SymbolicFactorization, SymbolicFactorizationDeleter> m_symbolicFactorization;
361 std::unique_ptr<NumericFactorization, NumericFactorizationDeleter> m_numericFactorization;
362 SparseKind_t m_sparseKind;
363 SparseTriangle_t m_triType;
364 SparseOrder_t m_order;
368template <
typename MatrixType_,
int UpLo_, SparseFactorization_t Solver_,
bool EnforceSquare_>
369void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::compute(
const MatrixType& a)
371 if (EnforceSquare_) {
372 eigen_assert(a.rows() == a.cols());
380 AccelSparseMatrix A{};
381 std::vector<long> columnStarts;
383 buildAccelSparseMatrix(a, A, columnStarts);
387 if (m_symbolicFactorization) doFactorization(A);
389 m_isInitialized =
true;
398template <
typename MatrixType_,
int UpLo_, SparseFactorization_t Solver_,
bool EnforceSquare_>
399void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::analyzePattern(
402 if (EnforceSquare_) {
403 eigen_assert(a.rows() == a.cols());
411 AccelSparseMatrix A{};
412 std::vector<long> columnStarts;
414 buildAccelSparseMatrix(a, A, columnStarts);
418 m_isInitialized =
true;
428template <
typename MatrixType_,
int UpLo_, SparseFactorization_t Solver_,
bool EnforceSquare_>
429void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::factorize(
const MatrixType& a)
431 eigen_assert(m_symbolicFactorization &&
"You must first call analyzePattern()");
432 eigen_assert(m_nRows == a.rows() && m_nCols == a.cols());
434 if (EnforceSquare_) {
435 eigen_assert(a.rows() == a.cols());
440 AccelSparseMatrix A{};
441 std::vector<long> columnStarts;
443 buildAccelSparseMatrix(a, A, columnStarts);
448template <
typename MatrixType_,
int UpLo_, SparseFactorization_t Solver_,
bool EnforceSquare_>
449template <
typename Rhs,
typename Dest>
450void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::_solve_impl(
451 const Eigen::MatrixBase<Rhs>& b,
452 Eigen::MatrixBase<Dest>& x)
const
454 if (!m_numericFactorization) {
455 m_info = Eigen::InvalidInput;
459 eigen_assert(m_nRows == b.rows());
460 eigen_assert(((b.cols() == 1) || b.outerStride() == b.rows()));
462 SparseStatus_t status = SparseStatusOK;
464 Scalar* b_ptr =
const_cast<Scalar*
>(b.derived().data());
465 Scalar* x_ptr =
const_cast<Scalar*
>(x.derived().data());
467 AccelDenseMatrix xmat{};
468 xmat.attributes = SparseAttributes_t();
469 xmat.columnCount =
static_cast<int>(x.cols());
470 xmat.rowCount =
static_cast<int>(x.rows());
471 xmat.columnStride = xmat.rowCount;
474 AccelDenseMatrix bmat{};
475 bmat.attributes = SparseAttributes_t();
476 bmat.columnCount =
static_cast<int>(b.cols());
477 bmat.rowCount =
static_cast<int>(b.rows());
478 bmat.columnStride = bmat.rowCount;
481 SparseSolve(*m_numericFactorization, bmat, xmat);
483 updateInfoStatus(status);