Lagrange
Loading...
Searching...
No Matches
AccelerateSupport.h
1
9
10#pragma once
11
12#include <lagrange/utils/build.h>
13
14#if LAGRANGE_TARGET_OS(APPLE)
15
16 #include <Accelerate/Accelerate.h>
17 #include <Eigen/Sparse>
18
19namespace lagrange::solver::internal {
20
21template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
22class AccelerateImpl;
23
35template <typename MatrixType, int UpLo = Eigen::Lower>
36using AccelerateLLT =
37 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationCholesky, true>;
38
50template <typename MatrixType, int UpLo = Eigen::Lower>
51using AccelerateLDLT =
52 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLT, true>;
53
66template <typename MatrixType, int UpLo = Eigen::Lower>
67using AccelerateLDLTUnpivoted =
68 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLTUnpivoted, true>;
69
82template <typename MatrixType, int UpLo = Eigen::Lower>
83using AccelerateLDLTSBK =
84 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLTSBK, true>;
85
98template <typename MatrixType, int UpLo = Eigen::Lower>
99using AccelerateLDLTTPP =
100 AccelerateImpl<MatrixType, UpLo | Eigen::Symmetric, SparseFactorizationLDLTTPP, true>;
101
112template <typename MatrixType>
113using AccelerateQR = AccelerateImpl<MatrixType, 0, SparseFactorizationQR, false>;
114
126template <typename MatrixType>
127using AccelerateCholeskyAtA = AccelerateImpl<MatrixType, 0, SparseFactorizationCholeskyAtA, false>;
128
129namespace internal {
130template <typename T>
131struct AccelFactorizationDeleter
132{
133 void operator()(T* sym)
134 {
135 if (sym) {
136 SparseCleanup(*sym);
137 delete sym;
138 sym = nullptr;
139 }
140 }
141};
142
143template <typename DenseVecT, typename DenseMatT, typename SparseMatT, typename NumFactT>
144struct SparseTypesTraitBase
145{
146 typedef DenseVecT AccelDenseVector;
147 typedef DenseMatT AccelDenseMatrix;
148 typedef SparseMatT AccelSparseMatrix;
149
150 typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
151 typedef NumFactT NumericFactorization;
152
153 typedef AccelFactorizationDeleter<SymbolicFactorization> SymbolicFactorizationDeleter;
154 typedef AccelFactorizationDeleter<NumericFactorization> NumericFactorizationDeleter;
155};
156
157template <typename Scalar>
158struct SparseTypesTrait
159{
160};
161
162template <>
163struct SparseTypesTrait<double> : SparseTypesTraitBase<
164 DenseVector_Double,
165 DenseMatrix_Double,
166 SparseMatrix_Double,
167 SparseOpaqueFactorization_Double>
168{
169};
170
171template <>
172struct SparseTypesTrait<float> : SparseTypesTraitBase<
173 DenseVector_Float,
174 DenseMatrix_Float,
175 SparseMatrix_Float,
176 SparseOpaqueFactorization_Float>
177{
178};
179
180} // end namespace internal
181
182template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
183class AccelerateImpl
184 : public Eigen::SparseSolverBase<AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>>
185{
186protected:
187 using Base = Eigen::SparseSolverBase<AccelerateImpl>;
188 using Base::derived;
189 using Base::m_isInitialized;
190
191public:
192 using Base::_solve_impl;
193
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_ };
199
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;
210
211 AccelerateImpl()
212 {
213 m_isInitialized = false;
214
215 auto check_flag_set = [](int value, int flag) { return ((value & flag) == flag); };
216
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;
238 } else {
239 m_sparseKind = SparseOrdinary;
240 m_triType = (UpLo_ & Eigen::Lower) ? SparseLowerTriangle : SparseUpperTriangle;
241 }
242
243 m_order = SparseOrderDefault;
244 }
245
246 explicit AccelerateImpl(const MatrixType& matrix)
247 : AccelerateImpl()
248 {
249 compute(matrix);
250 }
251
252 ~AccelerateImpl() {}
253
254 inline Eigen::Index cols() const { return m_nCols; }
255 inline Eigen::Index rows() const { return m_nRows; }
256
257 Eigen::ComputationInfo info() const
258 {
259 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
260 return m_info;
261 }
262
263 void analyzePattern(const MatrixType& matrix);
264
265 void factorize(const MatrixType& matrix);
266
267 void compute(const MatrixType& matrix);
268
269 template <typename Rhs, typename Dest>
270 void _solve_impl(const Eigen::MatrixBase<Rhs>& b, Eigen::MatrixBase<Dest>& dest) const;
271
273 void setOrder(SparseOrder_t order) { m_order = order; }
274
275private:
276 template <typename T>
277 void buildAccelSparseMatrix(
278 const Eigen::SparseMatrix<T>& a,
279 AccelSparseMatrix& A,
280 std::vector<long>& columnStarts)
281 {
282 const Eigen::Index nColumnsStarts = a.cols() + 1;
283
284 columnStarts.resize(nColumnsStarts);
285
286 for (Eigen::Index i = 0; i < nColumnsStarts; i++) columnStarts[i] = a.outerIndexPtr()[i];
287
288 SparseAttributes_t attributes{};
289 attributes.transpose = false;
290 attributes.triangle = m_triType;
291 attributes.kind = m_sparseKind;
292
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());
300
301 A.structure = structure;
302 A.data = const_cast<T*>(a.valuePtr());
303 }
304
305 void doAnalysis(AccelSparseMatrix& A)
306 {
307 m_numericFactorization.reset(nullptr);
308
309 SparseSymbolicFactorOptions opts{};
310 opts.control = SparseDefaultControl;
311 opts.orderMethod = m_order;
312 opts.order = nullptr;
313 opts.ignoreRowsAndColumns = nullptr;
314 opts.malloc = malloc;
315 opts.free = free;
316 opts.reportError = nullptr;
317
318 m_symbolicFactorization.reset(
319 new SymbolicFactorization(SparseFactor(Solver_, A.structure, opts)));
320
321 SparseStatus_t status = m_symbolicFactorization->status;
322
323 updateInfoStatus(status);
324
325 if (status != SparseStatusOK) m_symbolicFactorization.reset(nullptr);
326 }
327
328 void doFactorization(AccelSparseMatrix& A)
329 {
330 SparseStatus_t status = SparseStatusReleased;
331
332 if (m_symbolicFactorization) {
333 m_numericFactorization.reset(
334 new NumericFactorization(SparseFactor(*m_symbolicFactorization, A)));
335
336 status = m_numericFactorization->status;
337
338 if (status != SparseStatusOK) m_numericFactorization.reset(nullptr);
339 }
340
341 updateInfoStatus(status);
342 }
343
344protected:
345 void updateInfoStatus(SparseStatus_t status) const
346 {
347 switch (status) {
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;
355 }
356 }
357
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;
365};
366
368template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
369void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::compute(const MatrixType& a)
370{
371 if (EnforceSquare_) {
372 eigen_assert(a.rows() == a.cols());
373 do {
374 } while (0);
375 }
376
377 m_nRows = a.rows();
378 m_nCols = a.cols();
379
380 AccelSparseMatrix A{};
381 std::vector<long> columnStarts;
382
383 buildAccelSparseMatrix(a, A, columnStarts);
384
385 doAnalysis(A);
386
387 if (m_symbolicFactorization) doFactorization(A);
388
389 m_isInitialized = true;
390}
391
398template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
399void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::analyzePattern(
400 const MatrixType& a)
401{
402 if (EnforceSquare_) {
403 eigen_assert(a.rows() == a.cols());
404 do {
405 } while (0);
406 }
407
408 m_nRows = a.rows();
409 m_nCols = a.cols();
410
411 AccelSparseMatrix A{};
412 std::vector<long> columnStarts;
413
414 buildAccelSparseMatrix(a, A, columnStarts);
415
416 doAnalysis(A);
417
418 m_isInitialized = true;
419}
420
428template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
429void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::factorize(const MatrixType& a)
430{
431 eigen_assert(m_symbolicFactorization && "You must first call analyzePattern()");
432 eigen_assert(m_nRows == a.rows() && m_nCols == a.cols());
433
434 if (EnforceSquare_) {
435 eigen_assert(a.rows() == a.cols());
436 do {
437 } while (0);
438 }
439
440 AccelSparseMatrix A{};
441 std::vector<long> columnStarts;
442
443 buildAccelSparseMatrix(a, A, columnStarts);
444
445 doFactorization(A);
446}
447
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
453{
454 if (!m_numericFactorization) {
455 m_info = Eigen::InvalidInput;
456 return;
457 }
458
459 eigen_assert(m_nRows == b.rows());
460 eigen_assert(((b.cols() == 1) || b.outerStride() == b.rows()));
461
462 SparseStatus_t status = SparseStatusOK;
463
464 Scalar* b_ptr = const_cast<Scalar*>(b.derived().data());
465 Scalar* x_ptr = const_cast<Scalar*>(x.derived().data());
466
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;
472 xmat.data = x_ptr;
473
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;
479 bmat.data = b_ptr;
480
481 SparseSolve(*m_numericFactorization, bmat, xmat);
482
483 updateInfoStatus(status);
484}
485
486} // namespace lagrange::solver::internal
487
488#endif