pinocchio 4.1.0
A fast and flexible implementation of Rigid Body Dynamics algorithms and their analytical derivatives
Loading...
Searching...
No Matches
pgs-solver.hpp
1//
2// Copyright (c) 2022-2024 INRIA
3//
4
5#pragma once
6
7// IWYU pragma: begin_keep
8#include <cassert>
9#include <cstddef>
10#include <optional>
11#include <limits>
12#include <vector>
13
14#include <Eigen/Core>
15
16#include <boost/fusion/container/vector/vector.hpp>
17
18#include "pinocchio/macros.hpp"
19#include "pinocchio/eigen-common.hpp"
20
21#include "pinocchio/utils/check.hpp"
22#include "pinocchio/utils/reference.hpp"
23
24#include "pinocchio/container/eigen-storage.hpp"
25
26#include "pinocchio/math.hpp"
27
28#include "pinocchio/constraints.hpp"
29
30#include "pinocchio/algorithm/solvers/fwd.hpp"
31#include "pinocchio/algorithm/solvers/constraint-solver-base.hpp"
32#include "pinocchio/algorithm/solvers/constraint-solver-utils.hpp"
33// IWYU pragma: end_keep
34
35namespace pinocchio
36{
37 // fwd declarations for PGS-internal structs
38 // user-api structs are fwd delclared in solvers/fwd.hpp.
39 // see below for definitions
40 namespace internal
41 {
42 template<typename Scalar, int Options>
43 struct PGSSolverWorkspaceTpl;
44 }
45
46 template<typename _Scalar, int _Options>
47 struct traits<PGSConstraintSolverTpl<_Scalar, _Options>>
48 {
49 typedef _Scalar Scalar;
50 static constexpr int Options = _Options;
51
52 typedef PGSSolverSettingsTpl<Scalar> SolverSettings;
53 typedef PGSSolverResultTpl<Scalar, Options> SolverResult;
54 };
55
57 template<typename _Scalar, int _Options>
58 struct PGSConstraintSolverTpl : ConstraintSolverBase<PGSConstraintSolverTpl<_Scalar, _Options>>
59 {
60 typedef _Scalar Scalar;
61 static constexpr int Options = _Options;
62 typedef PGSConstraintSolverTpl Self;
63 typedef ConstraintSolverBase<Self> Base;
64 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Options> VectorXs;
65 typedef Eigen::Ref<const VectorXs> RefConstVectorXs;
66
67 typedef internal::PGSSolverWorkspaceTpl<Scalar, Options> PGSSolverWorkspace;
68 typedef PGSSolverSettingsTpl<Scalar> PGSSolverSettings;
69 typedef PGSSolverResultTpl<Scalar, Options> PGSSolverResult;
70 typedef PGSSolverStatsTpl<Scalar> PGSSolverStats;
71
72 using Base::reset;
73 using Base::timerStart;
74 using Base::timerStop;
75
84 explicit PGSConstraintSolverTpl(std::size_t max_problem_size = 0)
85 : Base()
86 , stats()
87 , m_workspace(max_problem_size)
88 , m_is_valid(false)
89 {
90 // we need to call reset - the solver needs to look as if it never ran
91 reset();
92 }
93
96 bool isValid() const
97 {
98 return m_is_valid;
99 }
100
101 template<
102 typename DelassusDerived,
103 typename VectorLike,
104 typename ConstraintModel,
105 typename ConstraintModelAllocator,
106 typename ConstraintData,
107 typename ConstraintDataAllocator>
108 bool solveImpl(
109 DelassusOperatorBase<DelassusDerived> & delassus,
110 const Eigen::MatrixBase<VectorLike> & g,
111 const std::vector<ConstraintModel, ConstraintModelAllocator> & constraint_models,
112 const std::vector<ConstraintData, ConstraintDataAllocator> & constraint_datas,
113 const PGSSolverSettings & settings,
114 PGSSolverResult & result);
115
116 void resetImpl()
117 {
118 stats.reset();
119 m_workspace.reset();
120 m_is_valid = false;
121 }
122
124 PGSSolverStats stats;
125
126 protected:
130 PGSSolverWorkspace m_workspace;
131
135
136 }; // struct PGSConstraintSolverTpl
137
138 template<typename _Scalar>
139 struct traits<PGSSolverSettingsTpl<_Scalar>>
140 {
141 typedef _Scalar Scalar;
142 };
143
146 template<typename _Scalar>
147 struct PGSSolverSettingsTpl : ConstraintSolverSettingsBase<PGSSolverSettingsTpl<_Scalar>>
148 {
149 typedef _Scalar Scalar;
150 typedef PGSSolverSettingsTpl Self;
151 typedef ConstraintSolverSettingsBase<Self> Base;
152 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> VectorXs;
153
156 std::size_t max_iterations = 1000,
157 Scalar absolute_feasibility_tol = Scalar(1e-6),
158 Scalar relative_feasibility_tol = Scalar(1e-6),
159 Scalar absolute_complementarity_tol = Scalar(1e-6),
160 Scalar relative_complementarity_tol = Scalar(1e-6),
161 bool solve_ncp = true,
162 bool measure_timings = false,
163 bool stat_record = false,
164 Scalar over_relaxation = Scalar(1))
165 : Base(
166 max_iterations,
167 absolute_feasibility_tol,
168 relative_feasibility_tol,
169 absolute_complementarity_tol,
170 relative_complementarity_tol,
171 solve_ncp,
172 measure_timings,
173 stat_record)
175 {
176 }
177
178 void checkValidityImpl() const
179 {
180 PINOCCHIO_CHECK_INPUT_ARGUMENT(
181 over_relaxation < Scalar(2) && over_relaxation > Scalar(0),
182 "over_relaxation should lie in ]0,2[.");
183 }
184
185 // ----------------------
186 // General settings
187
189 using Base::max_iterations;
190
192 using Base::absolute_feasibility_tol;
193
195 using Base::relative_feasibility_tol;
196
198 using Base::absolute_complementarity_tol;
199
201 using Base::relative_complementarity_tol;
202
205 using Base::solve_ncp;
206
208 using Base::measure_timings;
209
211 using Base::stat_record;
212
213 // ----------------------
214 // PGS specific settings
215
218 }; // struct PGSSolverSettingsTpl
219
220 template<typename _Scalar, int _Options>
221 struct traits<PGSSolverResultTpl<_Scalar, _Options>>
222 {
223 typedef _Scalar Scalar;
224 static constexpr int Options = _Options;
225 };
226
231 template<typename _Scalar, int _Options>
232 struct PGSSolverResultTpl : ConstraintSolverResultBase<PGSSolverResultTpl<_Scalar, _Options>>
233 {
234 typedef _Scalar Scalar;
235 static constexpr int Options = _Options;
236 typedef PGSSolverResultTpl Self;
237 typedef ConstraintSolverResultBase<Self> Base;
238
239 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Options> VectorXs;
240 typedef Eigen::Ref<const VectorXs> RefConstVectorXs;
241 typedef internal::EigenStorageTpl<VectorXs> VectorXsStorage;
242
243 using Base::constraintSize;
244 using Base::setConstraintImpulseGuess;
245 using Base::setConstraintVelocityGuess;
246
249 : Base()
250 , problem_size(0)
251 , impulse_guess(std::nullopt)
252 {
253 }
254
257 {
258 *this = other;
259 }
260
263 {
264 if (this != &other)
265 {
266 Base::operator=(other);
268 // Since some members are maps reference on EigenStorage, we cannot simply copy them.
269 // Thus we need to explicitly say we copy the storage, and the maps will automatically point
270 // to the new storage.
271 x_storage = other.x_storage;
272 y_storage = other.y_storage;
273
274 // special care must be taken for the optional guesses
275 if (other.impulse_guess)
276 {
277 setConstraintImpulseGuess(other.impulse_guess.value());
278 }
279 else
280 {
281 clearConstraintImpulseGuessImpl();
282 }
283 }
284 return *this;
285 }
286
289 {
290 return static_cast<int>(problem_size);
291 }
292
293 void resetImpl()
294 {
295 impulse_guess.reset();
296
297 // set solution to nan - solver has not run
298 x.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
299 y.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
300 }
301
303 void resize(std::size_t problem_size_)
304 {
305 problem_size = problem_size_;
306
307 Eigen::Index np = static_cast<Eigen::Index>(problem_size);
308 x_storage.resize(np);
309 y_storage.resize(np);
310 }
311
313 template<typename VectorLike>
314 void retrievePrimalSolution(const Eigen::MatrixBase<VectorLike> & primal_solution_) const
315 {
316 auto & primal_solution = primal_solution_.const_cast_derived();
317 primal_solution = x;
318 }
319
321 template<typename VectorLike>
322 void retrieveDualSolution(const Eigen::MatrixBase<VectorLike> & dual_solution_) const
323 {
324 auto & dual_solution = dual_solution_.const_cast_derived();
325 dual_solution = y;
326 }
327
328 template<typename VectorLike>
329 void setConstraintImpulseGuessImpl(const Eigen::MatrixBase<VectorLike> & impulse_guess_in)
330 {
331 m_impulse_guess_storage.resize(impulse_guess_in.size());
332 m_impulse_guess = impulse_guess_in;
333 impulse_guess.emplace(m_impulse_guess);
334 }
335
336 void clearConstraintImpulseGuessImpl()
337 {
339 impulse_guess.reset();
340 }
341
342 template<typename VectorLike>
343 void setConstraintVelocityGuessImpl(const Eigen::MatrixBase<VectorLike> & /*velocity_guess_*/)
344 {
345 // do nothing, no velocity guess for PGS
346 }
347
348 void clearConstraintVelocityGuessImpl()
349 {
350 // do nothing, no velocity guess for PGS
351 }
352
353 template<typename VectorLike>
354 void
355 retrieveConstraintImpulsesImpl(const Eigen::MatrixBase<VectorLike> & constraint_impulses_) const
356 {
357 auto & constraint_impulses = constraint_impulses_.const_cast_derived();
358 constraint_impulses = x;
359 }
360
364 template<typename VectorLike>
366 const Eigen::MatrixBase<VectorLike> & constraint_velocities_) const
367 {
368 auto & constraint_velocities = constraint_velocities_.const_cast_derived();
369 constraint_velocities = y;
370 }
371
373 using Base::iterations;
374
376 using Base::converged;
377
379 using Base::primal_feasibility;
380
382 using Base::dual_feasibility;
383
385 using Base::complementarity;
386
388 std::size_t problem_size;
389
390 // ----------------------
391 // Solution warmstart
392
394 std::optional<RefConstVectorXs> impulse_guess;
395
396 // ----------------------
397 // Solution - output of the solver
398
402 VectorXsStorage x_storage;
403 typename VectorXsStorage::RefMapType x = x_storage.map();
404
406 VectorXsStorage y_storage;
407 typename VectorXsStorage::RefMapType y = y_storage.map();
408
410 VectorXsStorage m_impulse_guess_storage;
411 typename VectorXsStorage::RefMapType m_impulse_guess = m_impulse_guess_storage.map();
412 }; // struct PGSSolverResultTpl
413
414 template<typename _Scalar>
415 struct traits<PGSSolverStatsTpl<_Scalar>>
416 {
417 typedef _Scalar Scalar;
418 };
419
422 template<typename _Scalar>
423 struct PGSSolverStatsTpl : ConstraintSolverStatsBase<PGSSolverStatsTpl<_Scalar>>
424 {
425 typedef _Scalar Scalar;
426 typedef PGSSolverStatsTpl Self;
427 typedef ConstraintSolverStatsBase<Self> Base;
428
429 using Base::reserve;
430
433 : Base()
434 {
435 }
436
438 explicit PGSSolverStatsTpl(std::size_t max_iterations)
439 : Base(max_iterations)
440 {
441 reserve(max_iterations);
442 }
443
444 void reserveImpl(std::size_t /*max_iterations*/)
445 {
446 // No extra fields to reserve for PGS stats.
447 }
448
449 void resetImpl()
450 {
451 // No extra fields to reset for PGS stats.
452 }
453
455 using Base::iterations;
456
458 using Base::primal_feasibility;
459
461 using Base::dual_feasibility;
462
464 using Base::dual_feasibility_ncp;
465
467 using Base::complementarity;
468 }; // struct PGSSolverStatsTpl
469
470 namespace internal
471 {
474 template<typename _Scalar, int _Options>
475 struct PGSSolverWorkspaceTpl
476 {
477 typedef _Scalar Scalar;
478 static constexpr int Options = _Options;
479 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Options> VectorXs;
480 typedef internal::EigenStorageTpl<VectorXs> VectorXsStorage;
481 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Options> MatrixXs;
482 typedef internal::EigenStorageTpl<MatrixXs> MatrixXsStorage;
483
485 PGSSolverWorkspaceTpl(std::size_t problem_size = 0)
486 : problem_size(problem_size)
487 {
488 resize(problem_size);
489 reset();
490 }
491
493 PGSSolverWorkspaceTpl(const PGSSolverWorkspaceTpl & other)
494 : PGSSolverWorkspaceTpl(0)
495 {
496 *this = other;
497 }
498
500 PGSSolverWorkspaceTpl & operator=(const PGSSolverWorkspaceTpl & other)
501 {
502 if (this != &other)
503 {
504 problem_size = other.problem_size;
505
506 // Since some members are maps reference on EigenStorage, we cannot simply copy them.
507 // Thus we need to explicitly say we copy the storage, and the maps will automatically
508 // point to the new storage.
509 delassus_matrix_storage = other.delassus_matrix_storage;
510 x_storage = other.x_storage;
511 x_previous_storage = other.x_previous_storage;
512 y_storage = other.y_storage;
513 rhs_storage = other.rhs_storage;
514 tmp_storage = other.tmp_storage;
515 }
516 return *this;
517 }
518
520 void reset()
521 {
522 resize(problem_size);
523
524#ifndef NDEBUG
525 delassus_matrix.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
526 x.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
527 x_previous.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
528 y.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
529 tmp.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
530 rhs.setConstant(std::numeric_limits<Scalar>::quiet_NaN());
531#endif
532 }
533
535 void resize(std::size_t problem_size_)
536 {
537 problem_size = problem_size_;
538
539 Eigen::Index np = static_cast<Eigen::Index>(problem_size);
540 delassus_matrix_storage.resize(np, np);
541 x_storage.resize(np);
542 x_previous_storage.resize(np);
543 y_storage.resize(np);
544 tmp_storage.resize(np);
545 rhs_storage.resize(np);
546 }
547
549 std::size_t problem_size;
550
552 MatrixXsStorage delassus_matrix_storage;
553 typename MatrixXsStorage::RefMapType delassus_matrix = delassus_matrix_storage.map();
554
556 VectorXsStorage x_storage;
557 typename VectorXsStorage::RefMapType x = x_storage.map();
558
560 VectorXsStorage x_previous_storage;
561 typename VectorXsStorage::RefMapType x_previous = x_previous_storage.map();
562
564 VectorXsStorage y_storage;
565 typename VectorXsStorage::RefMapType y = y_storage.map();
566
568 VectorXsStorage rhs_storage;
569 typename VectorXsStorage::RefMapType rhs = rhs_storage.map();
570
572 VectorXsStorage tmp_storage;
573 typename VectorXsStorage::RefMapType tmp = tmp_storage.map();
574 }; // struct PGSSolverWorkspaceTpl
575 } // namespace internal
576
577} // namespace pinocchio
578
579// IWYU pragma: begin_exports
580#include "pinocchio/src/algorithm/solvers/pgs-solver.hxx"
581// IWYU pragma: end_exports
Main pinocchio namespace.
Definition treeview.dox:11
Projected Gauss Siedel solver.
bool isValid() const
Returns true if solver is in a valid state (it has solved a constraint problem). If so,...
PGSConstraintSolverTpl(std::size_t max_problem_size=0)
Default constructor.
Struct describing the solution of the PGS constraint solver after calling the solve method....
PGSSolverResultTpl()
Default constructor.
void resize(std::size_t problem_size_)
Resize the primal/dual vectors of the solution.
void retrieveDualSolution(const Eigen::MatrixBase< VectorLike > &dual_solution_) const
Retrieve dual solution.
PGSSolverResultTpl(const PGSSolverResultTpl &other)
Copy constructor.
PGSSolverResultTpl & operator=(const PGSSolverResultTpl &other)
Assignment operator.
void retrievePrimalSolution(const Eigen::MatrixBase< VectorLike > &primal_solution_) const
Retrieve primal solution.
void retrieveConstraintVelocitiesImpl(const Eigen::MatrixBase< VectorLike > &constraint_velocities_) const
VectorXsStorage m_impulse_guess_storage
Storage for the optional impulse guess.
Settings for the PGS constraint solver loop.
PGSSolverSettingsTpl(std::size_t max_iterations=1000, Scalar absolute_feasibility_tol=Scalar(1e-6), Scalar relative_feasibility_tol=Scalar(1e-6), Scalar absolute_complementarity_tol=Scalar(1e-6), Scalar relative_complementarity_tol=Scalar(1e-6), bool solve_ncp=true, bool measure_timings=false, bool stat_record=false, Scalar over_relaxation=Scalar(1))
Default constructor.
Struct to track per iteration progress of PGS constraint solver.
PGSSolverStatsTpl(std::size_t max_iterations)
Constructor given a maximum iteration of the solver.
PGSSolverStatsTpl()
Default constructor.