9#include <polysolve/linear/Solver.hpp>
10#ifdef POLYSOLVE_WITH_SPQR
11#include <Eigen/SPQRSupport>
12#include <SuiteSparseQR.hpp>
41#ifdef POLYSOLVE_WITH_SPQR
42 void fill_cholmod(Eigen::SparseMatrix<double, Eigen::ColMajor, long> &mat, cholmod_sparse &cmat)
44 long *p = mat.outerIndexPtr();
46 cmat.nzmax = mat.nonZeros();
47 cmat.nrow = mat.rows();
48 cmat.ncol = mat.cols();
50 cmat.i = mat.innerIndexPtr();
51 cmat.x = mat.valuePtr();
58 cmat.xtype = CHOLMOD_REAL;
59 cmat.dtype = CHOLMOD_DOUBLE;
61 cmat.itype = CHOLMOD_LONG;
66 std::vector<unsigned long long> rowind_vect(mat.innerIndexPtr(), mat.innerIndexPtr() + mat.nonZeros());
67 std::vector<unsigned long long> colptr_vect(mat.outerIndexPtr(), mat.outerIndexPtr() + mat.outerSize() + 1);
68 std::vector<double> values_vect(mat.valuePtr(), mat.valuePtr() + mat.nonZeros());
70 arma::dvec values(values_vect.data(), values_vect.size(),
false);
71 arma::uvec rowind(rowind_vect.data(), rowind_vect.size(),
false);
72 arma::uvec colptr(colptr_vect.data(), colptr_vect.size(),
false);
74 arma::sp_mat amat(rowind, colptr, values, mat.rows(), mat.cols(),
false);
82 std::vector<long> outerIndexPtr(mat.row_indices, mat.row_indices + mat.n_nonzero);
83 std::vector<long> innerIndexPtr(mat.col_ptrs, mat.col_ptrs + mat.n_cols + 1);
85 const StiffnessMatrix out = Eigen::Map<const Eigen::SparseMatrix<double, Eigen::ColMajor, long>>(
86 mat.n_rows, mat.n_cols, mat.n_nonzero, innerIndexPtr.data(), outerIndexPtr.data(), mat.values);
93 const std::vector<std::shared_ptr<Form>> &forms,
94 const std::vector<std::shared_ptr<AugmentedLagrangianForm>> &penalty_forms,
95 const std::shared_ptr<polysolve::linear::Solver> &solver)
97 full_size_(full_size),
99 penalty_forms_(penalty_forms),
108 const std::shared_ptr<utils::PeriodicBoundary> &periodic_bc,
110 const std::vector<std::shared_ptr<Form>> &forms,
111 const std::vector<std::shared_ptr<AugmentedLagrangianForm>> &penalty_forms,
112 const std::shared_ptr<polysolve::linear::Solver> &solver)
114 full_size_(full_size),
116 penalty_forms_(penalty_forms),
165 solver_->analyze_pattern(Q2tQ2, Q2tQ2.rows());
168 logger().debug(
"Factorization and computation of Q2tQ2 took: {}", timer.getElapsedTime());
170 std::vector<std::shared_ptr<Form>> tmp;
179 std::vector<Eigen::Triplet<double>> Ae;
183 const auto &tmp = f->constraint_matrix();
184 for (
int i = 0; i < tmp.outerSize(); i++)
186 for (
typename StiffnessMatrix::InnerIterator it(tmp, i); it; ++it)
188 Ae.emplace_back(index + it.row(), it.col(), it.value());
194 A.setFromTriplets(Ae.begin(), Ae.end());
197 int constraint_size = A.rows();
199 Eigen::SparseMatrix<double, Eigen::ColMajor, long> At = A.transpose();
202 logger().debug(
"Constraint size: {} x {}", A.rows(), A.cols());
204#ifdef POLYSOLVE_WITH_SPQR
208 cholmod_l_start(&cc);
211 const int ordering = SPQR_ORDERING_DEFAULT;
212 const double tol = SPQR_DEFAULT_TOL;
213 SuiteSparse_long econ = At.rows();
216 cholmod_sparse Ac, *Qc, *Rc;
218 fill_cholmod(At, Ac);
220 const auto rank = SuiteSparseQR<double>(ordering, tol, econ, &Ac,
227 const auto n = Rc->ncol;
231 for (
long j = 0; j < n; j++)
232 P_.indices()(j) = E[j];
237 if (Qc->stype != 0 || Qc->sorted != 1 || Qc->packed != 1 || Rc->stype != 0 || Rc->sorted != 1 || Rc->packed != 1)
240 const StiffnessMatrix Q = Eigen::Map<Eigen::SparseMatrix<double, Eigen::ColMajor, long>>(
241 Qc->nrow, Qc->ncol, Qc->nzmax,
242 static_cast<long *
>(Qc->p),
static_cast<long *
>(Qc->i),
static_cast<double *
>(Qc->x));
244 const StiffnessMatrix R = Eigen::Map<Eigen::SparseMatrix<double, Eigen::ColMajor, long>>(
245 Rc->nrow, Rc->ncol, Rc->nzmax,
246 static_cast<long *
>(Rc->p),
static_cast<long *
>(Rc->i),
static_cast<double *
>(Rc->x));
248 cholmod_l_free_sparse(&Qc, &cc);
249 cholmod_l_free_sparse(&Rc, &cc);
251 cholmod_l_finish(&cc);
254 logger().debug(
"QR took: {}", timer.getElapsedTime());
259 Eigen::SparseQR<StiffnessMatrix, Eigen::COLAMDOrdering<int>> QR(At);
262 logger().debug(
"QR took: {}", timer.getElapsedTime());
264 if (QR.info() != Eigen::Success)
271 logger().debug(
"Computation of Q took: {}", timer.getElapsedTime());
273 const Eigen::SparseMatrix<double, Eigen::RowMajor> R = QR.matrixR();
275 P_ = QR.colsPermutation();
278 for (; constraint_size >= 0; --constraint_size)
281 if (tmp.nonZeros() != 0)
294 Q1_ = Q.leftCols(constraint_size);
296 assert(
Q1_.cols() == constraint_size);
304 R1_ = R.topRows(constraint_size);
305 assert(
R1_.rows() == constraint_size);
308 assert((
Q1_.transpose() *
Q2_).norm() < 1e-10);
311 logger().debug(
"Getting Q1 Q2, R1 took: {}", timer.getElapsedTime());
320 logger().debug(
"Getting Q2'*Q2, took: {}", timer.getElapsedTime());
323 solver_->analyze_pattern(Q2tQ2, Q2tQ2.rows());
326 logger().debug(
"Factorization of Q2'*Q2 took: {}", timer.getElapsedTime());
330 assert(test.nonZeros() == 0);
333 assert(test1.nonZeros() != 0);
338 std::vector<std::shared_ptr<Form>> tmp;
360 constraint_values.segment(index, f->constraint_value().rows()) = f->constraint_value();
361 index += f->constraint_value().rows();
363 constraint_values =
P_.transpose() * constraint_values;
367 if (
R1_.rows() ==
R1_.cols())
369 sol =
R1_.transpose().triangularView<Eigen::Lower>().solve(constraint_values);
374#ifdef POLYSOLVE_WITH_SPQR
375 Eigen::SparseMatrix<double, Eigen::ColMajor, long> R1t =
R1_.transpose();
377 cholmod_l_start(&cc);
379 fill_cholmod(R1t, R1tc);
382 b.nrow = constraint_values.size();
384 b.nzmax = constraint_values.size();
385 b.d = constraint_values.size();
386 b.x = constraint_values.data();
388 b.xtype = CHOLMOD_REAL;
391 const int ordering = SPQR_ORDERING_DEFAULT;
392 const double tol = SPQR_DEFAULT_TOL;
394 cholmod_dense *solc = SuiteSparseQR<double>(ordering, tol, &R1tc, &b, &cc);
396 sol = Eigen::Map<Eigen::VectorXd>(
static_cast<double *
>(solc->x), solc->nrow);
398 cholmod_l_free_dense(&solc, &cc);
399 cholmod_l_finish(&cc);
401 Eigen::SparseQR<StiffnessMatrix, Eigen::COLAMDOrdering<int>> solver;
402 solver.compute(
R1_.transpose());
403 if (solver.info() != Eigen::Success)
407 sol = solver.solve(constraint_values);
411 assert((
R1_.transpose() * sol - constraint_values).norm() < 1e-10);
416 logger().debug(
"Computing Q1R1iTb took: {}", timer.getElapsedTime());
441 f->update_quantities(t, full);
444 f->update_quantities(t,
x);
551 static int nsolves = 0;
552 if (data.iter_num == 0)
574 const TVector rhs =
Q2t_ * k;
580 assert((Q2tQ2 * reduced - rhs).norm() < 1e-8);
613 assert(f->compute_error(full) < 1e-8);
632 hessian.prune([](
const Eigen::Index &row,
const Eigen::Index &col,
const Scalar &
value) {
633 return std::abs(
value) > 1e-10;
virtual double max_step_size(const TVector &x0, const TVector &x1) override
virtual void init_lagging(const TVector &x)
virtual void hessian(const TVector &x, THessian &hessian) override
virtual bool is_step_collision_free(const TVector &x0, const TVector &x1)
std::vector< std::shared_ptr< Form > > forms_
virtual void post_step(const polysolve::nonlinear::PostStepData &data) override
virtual void update_lagging(const TVector &x, const int iter_num)
virtual bool is_step_valid(const TVector &x0, const TVector &x1) override
virtual double value(const TVector &x) override
virtual void solution_changed(const TVector &new_x) override
virtual void gradient(const TVector &x, TVector &gradv) override
virtual void line_search_begin(const TVector &x0, const TVector &x1) override
const int full_size_
Size of the full problem.
StiffnessMatrix R1_
R1 block of the QR decomposition of the constraints matrix.
void line_search_begin(const TVector &x0, const TVector &x1) override
Eigen::PermutationMatrix< Eigen::Dynamic, Eigen::Dynamic > P_
Permutation matrix of the QR decomposition of the constraints matrix.
double normalize_forms() override
StiffnessMatrix Q2_
Q2 block of the QR decomposition of the constraints matrix.
virtual bool is_step_valid(const TVector &x0, const TVector &x1) override
int reduced_size_
Size of the reduced problem.
virtual void post_step(const polysolve::nonlinear::PostStepData &data) override
NLProblem(const int full_size, const std::vector< std::shared_ptr< Form > > &forms, const std::vector< std::shared_ptr< AugmentedLagrangianForm > > &penalty_forms, const std::shared_ptr< polysolve::linear::Solver > &solver)
virtual TVector full_to_reduced_grad(const TVector &full) const
StiffnessMatrix Q2t_
Q2 transpose.
TVector full_to_reduced(const TVector &full) const
virtual void update_quantities(const double t, const TVector &x)
virtual void gradient(const TVector &x, TVector &gradv) override
void init_lagging(const TVector &x) override
virtual bool is_step_collision_free(const TVector &x0, const TVector &x1) override
TVector reduced_to_full(const TVector &reduced) const
void update_lagging(const TVector &x, const int iter_num) override
void update_constraint_values()
std::vector< std::shared_ptr< AugmentedLagrangianForm > > penalty_forms_
virtual double value(const TVector &x) override
StiffnessMatrix Q1_
Q1 block of the QR decomposition of the constraints matrix.
virtual double max_step_size(const TVector &x0, const TVector &x1) override
virtual void hessian(const TVector &x, THessian &hessian) override
std::shared_ptr< polysolve::linear::Solver > solver_
void solution_changed(const TVector &new_x) override
std::shared_ptr< FullNLProblem > penalty_problem_
int num_penalty_constraints_
TVector Q1R1iTb_
Q1_ * (R1_.transpose().triangularView<Eigen::Upper>().solve(constraint_values_))
void full_hessian_to_reduced_hessian(StiffnessMatrix &hessian) const
spdlog::logger & logger()
Retrieves the current logger.
void log_and_throw_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix