6#if defined(TINYOPT_ENABLE_SUITESPARSE)
14#include <tinyopt/types.h>
16namespace tinyopt::suitesparse_detail {
19 cholmod_common value{};
20 bool started = cholmod_start(&value) != 0;
23 if (started) cholmod_finish(&value);
28 cholmod_common *common;
30 void operator()(cholmod_factor *factor)
const {
31 if (factor) cholmod_free_factor(&factor, common);
36 cholmod_common *common;
38 void operator()(cholmod_dense *dense)
const {
39 if (dense) cholmod_free_dense(&dense, common);
43template <
typename Scalar,
int RowsAtCompileTime>
44std::optional<Vector<Scalar, RowsAtCompileTime>> SolveWithView(
45 const SparseMatrix<Scalar> &A,
const Vector<Scalar, RowsAtCompileTime> &b) {
46 if (A.rows() != A.cols() || A.rows() != b.size() || A.rows() == 0)
return std::nullopt;
48 static_assert(std::is_same_v<Scalar, double> || std::is_same_v<Scalar, float>);
49 static_assert(std::is_same_v<typename SparseMatrix<Scalar>::StorageIndex,
int>);
52 if (!context.started)
return std::nullopt;
53 context.value.print = 0;
55 cholmod_sparse matrix{};
56 matrix.nrow =
static_cast<size_t>(A.rows());
57 matrix.ncol =
static_cast<size_t>(A.cols());
58 matrix.nzmax =
static_cast<size_t>(A.data().allocatedSize());
59 matrix.p =
const_cast<int *
>(A.outerIndexPtr());
60 matrix.i =
const_cast<int *
>(A.innerIndexPtr());
61 matrix.x =
const_cast<Scalar *
>(A.valuePtr());
62 matrix.nz = A.isCompressed() ? nullptr :
const_cast<int *
>(A.innerNonZeroPtr());
64 matrix.itype = CHOLMOD_INT;
65 matrix.xtype = CHOLMOD_REAL;
66 matrix.dtype = std::is_same_v<Scalar, double> ? CHOLMOD_DOUBLE : CHOLMOD_SINGLE;
68 matrix.packed = A.isCompressed();
70 std::unique_ptr<cholmod_factor, FactorDeleter> factor(
71 cholmod_analyze(&matrix, &context.value), FactorDeleter{&context.value});
72 if (!factor || !cholmod_factorize(&matrix, factor.get(), &context.value) ||
73 factor->minor != matrix.ncol)
77 rhs.nrow =
static_cast<size_t>(b.size());
79 rhs.nzmax =
static_cast<size_t>(b.size());
81 rhs.x =
const_cast<Scalar *
>(b.data());
82 rhs.xtype = CHOLMOD_REAL;
83 rhs.dtype = matrix.dtype;
85 std::unique_ptr<cholmod_dense, DenseDeleter> result(
86 cholmod_solve(CHOLMOD_A, factor.get(), &rhs, &context.value),
87 DenseDeleter{&context.value});
88 if (!result)
return std::nullopt;
90 using Result = Vector<Scalar, RowsAtCompileTime>;
91 Result solution(b.size());
92 Eigen::Map<const Vector<Scalar>> result_view(
static_cast<const Scalar *
>(result->x), b.size());
93 solution = result_view;
94 if (!solution.allFinite())
return std::nullopt;
98template <
typename Scalar,
int RowsAtCompileTime>
99std::optional<Vector<Scalar, RowsAtCompileTime>> Solve(
100 const SparseMatrix<Scalar> &A,
const Vector<Scalar, RowsAtCompileTime> &b) {
101 return SolveWithView<Scalar, RowsAtCompileTime>(A, b);