PolyFEM
Loading...
Searching...
No Matches
NLProblem.cpp
Go to the documentation of this file.
1#include "NLProblem.hpp"
2
6
8
9#include <polysolve/linear/Solver.hpp>
10#ifdef POLYSOLVE_WITH_SPQR
11#include <Eigen/SPQRSupport>
12#include <SuiteSparseQR.hpp>
13#endif
14
15#include <armadillo>
16
17#include <igl/cat.h>
18#include <igl/Timer.h>
19
20#include <set>
21
22/*
23m \frac{\partial^2 u}{\partial t^2} = \psi = \text{div}(\sigma[u])\newline
24u^{t+1} = u(t+\Delta t)\approx u(t) + \Delta t \dot u + \frac{\Delta t^2} 2 \ddot u \newline
25= u(t) + \Delta t \dot u + \frac{\Delta t^2}{2} \psi\newline
26M u^{t+1}_h \approx M u^t_h + \Delta t M v^t_h + \frac{\Delta t^2} {2} A u^{t+1}_h \newline
27%
28M (u^{t+1}_h - (u^t_h + \Delta t v^t_h)) - \frac{\Delta t^2} {2} A u^{t+1}_h
29*/
30// mü = ψ = div(σ[u])
31// uᵗ⁺¹ = u(t + Δt) ≈ u(t) + Δtu̇ + ½Δt²ü = u(t) + Δtu̇ + ½Δt²ψ
32// Muₕᵗ⁺¹ ≈ Muₕᵗ + ΔtMvₕᵗ ½Δt²Auₕᵗ⁺¹
33// Root-finding form:
34// M(uₕᵗ⁺¹ - (uₕᵗ + Δtvₕᵗ)) - ½Δt²Auₕᵗ⁺¹ = 0
35
36namespace polyfem::solver
37{
38
39 namespace
40 {
41#ifdef POLYSOLVE_WITH_SPQR
42 void fill_cholmod(Eigen::SparseMatrix<double, Eigen::ColMajor, long> &mat, cholmod_sparse &cmat)
43 {
44 long *p = mat.outerIndexPtr();
45
46 cmat.nzmax = mat.nonZeros();
47 cmat.nrow = mat.rows();
48 cmat.ncol = mat.cols();
49 cmat.p = p;
50 cmat.i = mat.innerIndexPtr();
51 cmat.x = mat.valuePtr();
52 cmat.z = 0;
53 cmat.sorted = 1;
54 cmat.packed = 1;
55 cmat.nz = 0;
56 cmat.dtype = 0;
57 cmat.stype = -1;
58 cmat.xtype = CHOLMOD_REAL;
59 cmat.dtype = CHOLMOD_DOUBLE;
60 cmat.stype = 0;
61 cmat.itype = CHOLMOD_LONG;
62 }
63#endif
64 arma::sp_mat fill_arma(const StiffnessMatrix &mat)
65 {
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());
69
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);
73
74 arma::sp_mat amat(rowind, colptr, values, mat.rows(), mat.cols(), false);
75
76 return amat;
77 }
78
79 StiffnessMatrix fill_eigen(const arma::sp_mat &mat)
80 {
81 // convert to eigen sparse
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);
84
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);
87 return out;
88 }
89
90 } // namespace
92 const int full_size,
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)
96 : FullNLProblem(forms),
97 full_size_(full_size),
98 t_(0),
99 penalty_forms_(penalty_forms),
100 solver_(solver)
101 {
104 }
105
107 const int full_size,
108 const std::shared_ptr<utils::PeriodicBoundary> &periodic_bc,
109 const double t,
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)
113 : FullNLProblem(forms),
114 full_size_(full_size),
115 t_(t),
116 penalty_forms_(penalty_forms),
117 solver_(solver)
118 {
121 }
122
124 {
125 return 1;
126
127 // double total_weight = 0;
128 // for (const auto &f : forms_)
129 // total_weight += f->weight();
130 // if (full_size() == current_size())
131 // {
132 // for (const auto &f : penalty_forms_)
133 // total_weight += f->weight() * f->lagrangian_weight();
134 // }
135
136 // logger().debug("Normalizing forms with scale: {}", total_weight);
137
138 // for (auto &f : forms_)
139 // f->set_scale(total_weight);
140 // for (auto &f : penalty_forms_)
141 // f->set_scale(total_weight);
142
143 // return total_weight;
144 }
145
147 {
148 if (penalty_forms_.empty())
149 {
151 return;
152 }
153 igl::Timer timer;
154
155 if (penalty_forms_.size() == 1 && penalty_forms_.front()->has_projection())
156 {
157 Q2_ = penalty_forms_.front()->constraint_projection_matrix();
158 Q2t_ = Q2_.transpose();
159
160 reduced_size_ = Q2_.cols();
161 if (reduced_size_ == 0)
162 return;
164
165 timer.start();
166 StiffnessMatrix Q2tQ2 = Q2t_ * Q2_;
167 solver_->analyze_pattern(Q2tQ2, Q2tQ2.rows());
168 solver_->factorize(Q2tQ2);
169 timer.stop();
170 logger().debug("Factorization and computation of Q2tQ2 took: {}", timer.getElapsedTime());
171
172 std::vector<std::shared_ptr<Form>> tmp;
173 tmp.insert(tmp.end(), penalty_forms_.begin(), penalty_forms_.end());
174 penalty_problem_ = std::make_shared<FullNLProblem>(tmp);
175
177
178 return;
179 }
180
181 std::vector<Eigen::Triplet<double>> Ae;
182 int index = 0;
183 for (const auto &f : penalty_forms_)
184 {
185 const auto &tmp = f->constraint_matrix();
186 for (int i = 0; i < tmp.outerSize(); i++)
187 {
188 for (typename StiffnessMatrix::InnerIterator it(tmp, i); it; ++it)
189 {
190 Ae.emplace_back(index + it.row(), it.col(), it.value());
191 }
192 }
193 index += tmp.rows();
194 }
195 StiffnessMatrix A(index, full_size_);
196 A.setFromTriplets(Ae.begin(), Ae.end());
197 A.makeCompressed();
198
199 int constraint_size = A.rows();
200 num_penalty_constraints_ = A.rows();
201 Eigen::SparseMatrix<double, Eigen::ColMajor, long> At = A.transpose();
202 At.makeCompressed();
203
204 logger().debug("Constraint size: {} x {}", A.rows(), A.cols());
205
206#ifdef POLYSOLVE_WITH_SPQR
207 timer.start();
208
209 cholmod_common cc;
210 cholmod_l_start(&cc); // start CHOLMOD
211
212 // const int ordering = 0; // all, except 3:given treated as 0:fixed
213 const int ordering = SPQR_ORDERING_DEFAULT; // all, except 3:given treated as 0:fixed
214 const double tol = SPQR_DEFAULT_TOL;
215 SuiteSparse_long econ = At.rows();
216 SuiteSparse_long *E; // permutation of 0:n-1, NULL if identity
217
218 cholmod_sparse Ac, *Qc, *Rc;
219
220 fill_cholmod(At, Ac);
221
222 const auto rank = SuiteSparseQR<double>(ordering, tol, econ, &Ac,
223 // outputs
224 &Qc, &Rc, &E, &cc);
225
226 if (!Rc)
227 log_and_throw_error("Failed to factorize constraints matrix");
228
229 const auto n = Rc->ncol;
230 P_.resize(n);
231 if (E)
232 {
233 for (long j = 0; j < n; j++)
234 P_.indices()(j) = E[j];
235 }
236 else
237 P_.setIdentity();
238
239 if (Qc->stype != 0 || Qc->sorted != 1 || Qc->packed != 1 || Rc->stype != 0 || Rc->sorted != 1 || Rc->packed != 1)
240 log_and_throw_error("Q and R must be unsymmetric sorted and packed");
241
242 const StiffnessMatrix Q = Eigen::Map<Eigen::SparseMatrix<double, Eigen::ColMajor, long>>(
243 Qc->nrow, Qc->ncol, Qc->nzmax,
244 static_cast<long *>(Qc->p), static_cast<long *>(Qc->i), static_cast<double *>(Qc->x));
245
246 const StiffnessMatrix R = Eigen::Map<Eigen::SparseMatrix<double, Eigen::ColMajor, long>>(
247 Rc->nrow, Rc->ncol, Rc->nzmax,
248 static_cast<long *>(Rc->p), static_cast<long *>(Rc->i), static_cast<double *>(Rc->x));
249
250 cholmod_l_free_sparse(&Qc, &cc);
251 cholmod_l_free_sparse(&Rc, &cc);
252 std::free(E);
253 cholmod_l_finish(&cc);
254
255 timer.stop();
256 logger().debug("QR took: {}", timer.getElapsedTime());
257#else
258 timer.start();
259
260 // Eigen::SparseQR<StiffnessMatrix, Eigen::NaturalOrdering<int>> QR(At);
261 Eigen::SparseQR<StiffnessMatrix, Eigen::COLAMDOrdering<int>> QR(At);
262
263 timer.stop();
264 logger().debug("QR took: {}", timer.getElapsedTime());
265
266 if (QR.info() != Eigen::Success)
267 log_and_throw_error("Failed to factorize constraints matrix");
268
269 timer.start();
271 Q = QR.matrixQ();
272 timer.stop();
273 logger().debug("Computation of Q took: {}", timer.getElapsedTime());
274
275 const Eigen::SparseMatrix<double, Eigen::RowMajor> R = QR.matrixR();
276
277 P_ = QR.colsPermutation();
278#endif
279
280 for (; constraint_size >= 0; --constraint_size)
281 {
282 const StiffnessMatrix tmp = R.row(constraint_size);
283 if (tmp.nonZeros() != 0)
284 {
285 constraint_size++;
286 break;
287 }
288 }
289 if (constraint_size != num_penalty_constraints_)
290 logger().warn("Matrix A is not full rank, constraint size: {} instead of {}", constraint_size, num_penalty_constraints_);
291
292 reduced_size_ = full_size_ - constraint_size;
293
294 timer.start();
295
296 Q1_ = Q.leftCols(constraint_size);
297 assert(Q1_.rows() == full_size_);
298 assert(Q1_.cols() == constraint_size);
299
300 Q2_ = Q.rightCols(reduced_size_);
301 Q2t_ = Q2_.transpose();
302
303 assert(Q2_.rows() == full_size_);
304 assert(Q2_.cols() == reduced_size_);
305
306 R1_ = R.topRows(constraint_size);
307 assert(R1_.rows() == constraint_size);
308 assert(R1_.cols() == num_penalty_constraints_);
309
310 assert((Q1_.transpose() * Q2_).norm() < 1e-10);
311
312 timer.stop();
313 logger().debug("Getting Q1 Q2, R1 took: {}", timer.getElapsedTime());
314
315 timer.start();
316
317 // arma::sp_mat q2a = fill_arma(Q2_);
318 // arma::sp_mat q2tq2 = q2a.t() * q2a;
319 // const StiffnessMatrix Q2tQ2 = fill_eigen(q2tq2);
320 StiffnessMatrix Q2tQ2 = Q2t_ * Q2_;
321 timer.stop();
322 logger().debug("Getting Q2'*Q2, took: {}", timer.getElapsedTime());
323
324 timer.start();
325 solver_->analyze_pattern(Q2tQ2, Q2tQ2.rows());
326 solver_->factorize(Q2tQ2);
327 timer.stop();
328 logger().debug("Factorization of Q2'*Q2 took: {}", timer.getElapsedTime());
329
330#ifndef NDEBUG
331 StiffnessMatrix test = R.bottomRows(reduced_size_);
332 assert(test.nonZeros() == 0);
333
334 StiffnessMatrix test1 = R1_.row(R1_.rows() - 1);
335 assert(test1.nonZeros() != 0);
336#endif
337
338 // assert((Q1_ * R1_ - At * P_).norm() < 1e-10);
339
340 std::vector<std::shared_ptr<Form>> tmp;
341 tmp.insert(tmp.end(), penalty_forms_.begin(), penalty_forms_.end());
342 penalty_problem_ = std::make_shared<FullNLProblem>(tmp);
343
345 }
346
348 {
349 if (penalty_forms_.size() == 1 && penalty_forms_.front()->has_projection())
350 {
351 Q1R1iTb_ = penalty_forms_.front()->constraint_projection_vector();
352 return;
353 }
354
355 igl::Timer timer;
356 timer.start();
357 // x = Q1 * R1^(-T) * P^T b + Q2 * y
358 int index = 0;
359 TVector constraint_values(num_penalty_constraints_);
360 for (const auto &f : penalty_forms_)
361 {
362 constraint_values.segment(index, f->constraint_value().rows()) = f->constraint_value();
363 index += f->constraint_value().rows();
364 }
365 constraint_values = P_.transpose() * constraint_values;
366
367 Eigen::VectorXd sol;
368
369 if (R1_.rows() == R1_.cols())
370 {
371 sol = R1_.transpose().triangularView<Eigen::Lower>().solve(constraint_values);
372 }
373 else
374 {
375
376#ifdef POLYSOLVE_WITH_SPQR
377 Eigen::SparseMatrix<double, Eigen::ColMajor, long> R1t = R1_.transpose();
378 cholmod_common cc;
379 cholmod_l_start(&cc); // start CHOLMOD
380 cholmod_sparse R1tc;
381 fill_cholmod(R1t, R1tc);
382
383 cholmod_dense b;
384 b.nrow = constraint_values.size();
385 b.ncol = 1;
386 b.nzmax = constraint_values.size();
387 b.d = constraint_values.size();
388 b.x = constraint_values.data();
389 b.z = 0;
390 b.xtype = CHOLMOD_REAL;
391 b.dtype = 0;
392
393 const int ordering = SPQR_ORDERING_DEFAULT; // all, except 3:given treated as 0:fixed
394 const double tol = SPQR_DEFAULT_TOL;
395
396 cholmod_dense *solc = SuiteSparseQR<double>(ordering, tol, &R1tc, &b, &cc);
397
398 sol = Eigen::Map<Eigen::VectorXd>(static_cast<double *>(solc->x), solc->nrow);
399
400 cholmod_l_free_dense(&solc, &cc);
401 cholmod_l_finish(&cc);
402#else
403 Eigen::SparseQR<StiffnessMatrix, Eigen::COLAMDOrdering<int>> solver;
404 solver.compute(R1_.transpose());
405 if (solver.info() != Eigen::Success)
406 {
407 log_and_throw_error("Failed to factorize R1^T");
408 }
409 sol = solver.solve(constraint_values);
410#endif
411 }
412
413 assert((R1_.transpose() * sol - constraint_values).norm() < 1e-10);
414
415 Q1R1iTb_ = Q1_ * sol;
416
417 timer.stop();
418 logger().debug("Computing Q1R1iTb took: {}", timer.getElapsedTime());
419 }
420
421 void NLProblem::init_lagging(const TVector &x)
422 {
424
426 penalty_problem_->init_lagging(x);
427 }
428
429 void NLProblem::update_lagging(const TVector &x, const int iter_num)
430 {
432
434 penalty_problem_->update_lagging(x, iter_num);
435 }
436
437 void NLProblem::update_quantities(const double t, const TVector &x)
438 {
439 t_ = t;
440 const TVector full = reduced_to_full(x);
441 assert(full.size() == full_size_);
442 for (auto &f : forms_)
443 f->update_quantities(t, full);
444
445 for (auto &f : penalty_forms_)
446 f->update_quantities(t, x);
447
449 }
450
451 void NLProblem::line_search_begin(const TVector &x0, const TVector &x1)
452 {
454
456 penalty_problem_->line_search_begin(x0, x1);
457 }
458
459 double NLProblem::max_step_size(const TVector &x0, const TVector &x1)
460 {
462
464 max_step = std::min(max_step, penalty_problem_->max_step_size(x0, x1));
465
466 return max_step;
467 }
468
469 bool NLProblem::is_step_valid(const TVector &x0, const TVector &x1)
470 {
472
473 if (penalty_problem_ && valid && full_size() == current_size())
474 valid = penalty_problem_->is_step_valid(x0, x1);
475
476 return valid;
477 }
478
479 bool NLProblem::is_step_collision_free(const TVector &x0, const TVector &x1)
480 {
482
483 if (penalty_problem_ && free && full_size() == current_size())
484 free = penalty_problem_->is_step_collision_free(x0, x1);
485
486 return free;
487 }
488
489 double NLProblem::value(const TVector &x)
490 {
491 // TODO: removed fearure const bool only_elastic
493
495 {
496 res += penalty_problem_->value(x);
497 }
498
499 return res;
500 }
501
502 void NLProblem::gradient(const TVector &x, TVector &grad)
503 {
505
506 if (full_size() != current_size())
507 {
508 if (penalty_forms_.size() == 1 && penalty_forms_.front()->can_project())
509 penalty_forms_.front()->project_gradient(grad);
510 else
511 grad = Q2t_ * grad;
512 }
513 else if (penalty_problem_)
514 {
515 TVector tmp;
516 penalty_problem_->gradient(x, tmp);
517 grad += tmp;
518 }
519 }
520
521 void NLProblem::hessian(const TVector &x, THessian &hessian)
522 {
524
525 if (full_size() != current_size())
526 {
528 }
529 else if (penalty_problem_)
530 {
531 THessian tmp;
532 penalty_problem_->hessian(x, tmp);
533 hessian += tmp;
534 }
535 }
536
537 void NLProblem::solution_changed(const TVector &newX)
538 {
540
542 penalty_problem_->solution_changed(newX);
543 }
544
545 void NLProblem::post_step(const polysolve::nonlinear::PostStepData &data)
546 {
547 FullNLProblem::post_step(polysolve::nonlinear::PostStepData(data.iter_num, data.solver_info, reduced_to_full(data.x), reduced_to_full(data.grad)));
548
550 penalty_problem_->post_step(data);
551
552 // TODO: add me back
553 static int nsolves = 0;
554 if (data.iter_num == 0)
555 nsolves++;
556 // if (state && state->args["output"]["advanced"]["save_nl_solve_sequence"])
557 // {
558 // const Eigen::MatrixXd displacements = utils::unflatten(reduced_to_full(data.x), state->mesh->dimension());
559 // io::OBJWriter::write(
560 // state->resolve_output_path(fmt::format("nonlinear_solve{:04d}_iter{:04d}.obj", nsolves, data.iter_num)),
561 // state->collision_mesh.displace_vertices(displacements),
562 // state->collision_mesh.edges(), state->collision_mesh.faces());
563 // }
564 }
565
566 NLProblem::TVector NLProblem::full_to_reduced(const TVector &full) const
567 {
568 // Reduced is already at the full size
569 if (full_size() == current_size() || full.size() == current_size())
570 {
571 return full;
572 }
573
574 TVector reduced(reduced_size());
575 const TVector k = full - Q1R1iTb_;
576 const TVector rhs = Q2t_ * k;
577 solver_->solve(rhs, reduced);
578
579#ifndef NDEBUG
580 StiffnessMatrix Q2tQ2 = Q2t_ * Q2_;
581 // std::cout << "err " << (Q2tQ2 * reduced - rhs).norm() << std::endl;
582 assert((Q2tQ2 * reduced - rhs).norm() < 1e-8);
583#endif
584
585 return reduced;
586 }
587
588 NLProblem::TVector NLProblem::full_to_reduced_grad(const TVector &full) const
589 {
590 TVector grad = full;
591 if (penalty_forms_.size() == 1 && penalty_forms_.front()->can_project())
592 penalty_forms_.front()->project_gradient(grad);
593 else
594 grad = Q2t_ * grad;
595
596 return grad;
597 }
598
599 NLProblem::TVector NLProblem::reduced_to_full(const TVector &reduced) const
600 {
601 // Full is already at the reduced size
602 if (full_size() == current_size() || full_size() == reduced.size())
603 {
604 return reduced;
605 }
606
607 // x = Q1 * R1^(-T) * P^T b + Q2 * y
608
609 const TVector full = Q1R1iTb_ + Q2_ * reduced;
610
611#ifndef NDEBUG
612 for (const auto &f : penalty_forms_)
613 {
614 // std::cout << f->compute_error(full) << std::endl;
615 assert(f->compute_error(full) < 1e-8);
616 }
617#endif
618
619 return full;
620 }
621
623 {
624 if (penalty_forms_.size() == 1 && penalty_forms_.front()->can_project())
625 penalty_forms_.front()->project_hessian(hessian);
626 else
627 {
628 // arma::sp_mat q2a = fill_arma(Q2_);
629 // arma::sp_mat ha = fill_arma(hessian);
630 // arma::sp_mat q2thq2 = q2a.t() * ha * q2a;
631 // hessian = fill_eigen(q2thq2);
632 hessian = Q2t_ * hessian * Q2_;
633 // remove numerical zeros
634 hessian.prune([](const Eigen::Index &row, const Eigen::Index &col, const Scalar &value) {
635 return std::abs(value) > 1e-10;
636 });
637 }
638 }
639} // namespace polyfem::solver
int x
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.
Definition NLProblem.hpp:71
StiffnessMatrix R1_
R1 block of the QR decomposition of the constraints matrix.
Definition NLProblem.hpp:93
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.
Definition NLProblem.hpp:94
double normalize_forms() override
StiffnessMatrix Q2_
Q2 block of the QR decomposition of the constraints matrix.
Definition NLProblem.hpp:91
virtual bool is_step_valid(const TVector &x0, const TVector &x1) override
int reduced_size_
Size of the reduced problem.
Definition NLProblem.hpp:72
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)
Definition NLProblem.cpp:91
virtual TVector full_to_reduced_grad(const TVector &full) const
StiffnessMatrix Q2t_
Q2 transpose.
Definition NLProblem.hpp:92
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
std::vector< std::shared_ptr< AugmentedLagrangianForm > > penalty_forms_
Definition NLProblem.hpp:88
virtual double value(const TVector &x) override
StiffnessMatrix Q1_
Q1 block of the QR decomposition of the constraints matrix.
Definition NLProblem.hpp:90
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_
Definition NLProblem.hpp:96
void solution_changed(const TVector &new_x) override
std::shared_ptr< FullNLProblem > penalty_problem_
Definition NLProblem.hpp:98
TVector Q1R1iTb_
Q1_ * (R1_.transpose().triangularView<Eigen::Upper>().solve(constraint_values_))
Definition NLProblem.hpp:95
void full_hessian_to_reduced_hessian(StiffnessMatrix &hessian) const
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:22