GCC Code Coverage Report


Directory: ./
File: include/hpp/constraints/explicit-constraint-set.hh
Date: 2025-05-05 12:19:30
Exec Total Coverage
Lines: 46 55 83.6%
Branches: 22 68 32.4%

Line Branch Exec Source
1 // Copyright (c) 2017, Joseph Mirabel
2 // Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3 //
4
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // 1. Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 // DAMAGE.
28
29 #ifndef HPP_CONSTRAINTS_EXPLICIT_CONSTRAINT_SET_HH
30 #define HPP_CONSTRAINTS_EXPLICIT_CONSTRAINT_SET_HH
31
32 #include <hpp/constraints/config.hh>
33 #include <hpp/constraints/differentiable-function-set.hh>
34 #include <hpp/constraints/fwd.hh>
35 #include <hpp/constraints/matrix-view.hh>
36 #include <vector>
37
38 namespace hpp {
39 namespace constraints {
40 /// \addtogroup solvers
41 /// \{
42
43 /**
44 Set of explicit constraints
45
46 This class combines compatible explicit constraints as
47 defined in the following paper published in Robotics Science and System
48 2018: https://hal.archives-ouvertes.fr/hal-01804774/file/paper.pdf,
49 Section II-B Definition 4.
50
51 An explicit constraint \f$E=(in,out,f)\f$ on a robot
52 configuration space \f$\mathcal{C}\f$ is defined by
53 \li a subset of input indices
54 \f$in\subset\{1,\cdots, \dim\mathcal{C}\}\f$,
55 \li a subset of output indices
56 \f$out\subset\{1,\cdots, \dim\mathcal{C}\}\f$,
57 \li a smooth mapping \f$f\f$ from \f$\mathbf{R}^{|in|}\f$ to
58 \f$\mathbf{R}^{|out|}\f$, satisfying the following properties: \li \f$in\cap out
59 = \emptyset\f$, \li for any \f$\mathbf{p}\in\mathcal{C}\f$, \f$\mathbf{q} =
60 E(\mathbf{p})\f$ is defined by \f{eqnarray}
61 &\mathbf{q}_{\bar{out}} = \mathbf{p}_{\bar{out}}\\
62 &\mathbf{q}_{out} = f (\mathbf{p}_{in}).
63 \f}
64
65 \note Right hand side.
66
67 For manipulation planning, it is useful to handle a parameterizable
68 right hand side \f$rhs\f$. The expression above thus becomes
69
70 \f{equation}
71 \mathbf{q}_{out} = f (\mathbf{p}_{in}) + rhs.
72 \f}
73
74 The right hand side may be set using the various methods
75 ExplicitConstraintSet::rightHandSide and
76 ExplicitConstraintSet::rightHandSideFromInput.
77
78 \note For some applications like manipulation planning, an
79 invertible function \f$ g \f$ (of known inverse \f$ g^{-1} \f$)
80 can be specified for each explicit constraint \f$E\f$. The above expression
81 then becomes:
82 \f{equation}
83 g(\mathbf{q}_{out}) = f(\mathbf{p}_{in}) + rhs
84 \f}
85
86 To add explicit constraints, use methods ExplicitConstraintSet::add. If the
87 constraint to add is not compatible with the previous one, this method
88 returns -1.
89
90 Method ExplicitConstraintSet::solve solves the explicit constraints.
91
92 The combination of compatible explicit constraints is an explicit
93 constraint. As such this class can be considered as an explicit constraint.
94
95 We will therefore use the following notation
96 \li \f$in\f$ for the set of indices of input variables,
97 \li \f$out\f$ for the set of indices of output variables.
98 **/
99 class HPP_CONSTRAINTS_DLLAPI ExplicitConstraintSet {
100 public:
101 typedef Eigen::RowBlockIndices RowBlockIndices;
102 typedef Eigen::ColBlockIndices ColBlockIndices;
103 typedef Eigen::MatrixBlockView<matrix_t, Eigen::Dynamic, Eigen::Dynamic,
104 false, false>
105 MatrixBlockView;
106
107 /// \name Resolution
108 /// \{
109
110 /// Solve the explicit constraints
111 /// \param arg input configuration,
112 /// \retval arg output configuration satisfying the explicit
113 /// constraints:
114 /// \f$\mathbf{q}_{out} = g^{-1}
115 /// \left(f(\mathbf{q}_{in}) + rhs\right)\f$
116 bool solve(vectorOut_t arg) const;
117
118 /// Size of error vector
119 /// \note that this size may differ from size of \link
120 /// ExplicitConstraintSet::outDers outDers output\endlink,
121 2012 size_type errorSize() const { return errorSize_; }
122
123 /// Whether input vector satisfies the constraints of the solver
124 /// \param arg input vector
125 /// \param errorThreshold threshold to compare against the norms of
126 /// the constraint errors. Default value is accessible via
127 /// methods errorThreshold.
128 bool isSatisfied(vectorIn_t arg, value_type errorThreshold = -1) const;
129
130 /// Whether input vector satisfies the constraints of the solver
131 /// \param arg input vector
132 /// \retval error the constraint errors
133 /// \param errorThreshold threshold to compare against the norms of
134 /// the constraint errors. Default value is accessible via
135 /// methods errorThreshold.
136 bool isSatisfied(vectorIn_t arg, vectorOut_t error,
137 value_type errorThreshold = -1) const;
138
139 /// Whether a constraint is satisfied for an input vector
140 ///
141 /// \param constraint, the constraint in the solver,
142 /// \param arg the input vector
143 /// \retval error the error of the constraint.
144 /// \retval constraintFound whether the constraint belongs to the
145 /// solver,
146 /// \return true if constraint belongs to solver and error is below
147 /// the threshold, false otherwise.
148 bool isConstraintSatisfied(const ImplicitPtr_t& constraint, vectorIn_t arg,
149 vectorOut_t error, bool& constraintFound) const;
150 /// \}
151
152 /// \name Construction of the problem
153 /// \{
154
155 /// Attempt to add an explicit constraint
156 ///
157 /// \param constraint explicit constraint
158 /// \return the index of the function if the function was added,
159 /// -1 otherwise.
160 /// \note A function can be added iff it is compatible with the
161 /// previously added functions.
162 size_type add(const ExplicitPtr_t& constraint);
163
164 /// Check whether an explicit numerical constraint has been added
165 /// \param numericalConstraint explicit numerical constraint
166 /// \return true if the constraint is in the set.
167 /// \note Comparison between constraints is performed by
168 /// function names. This means that two constraints with the
169 /// same function names are considered as equal.
170 bool contains(const ExplicitPtr_t& numericalConstraint) const;
171
172 /// Constructor
173 ///
174 /// \param space Lie group on which constraints are defined.
175 7437 ExplicitConstraintSet(const LiegroupSpacePtr_t& space)
176 7437 : configSpace_(space),
177
1/2
✓ Branch 1 taken 7437 times.
✗ Branch 2 not taken.
7437 inArgs_(),
178
1/2
✓ Branch 1 taken 7437 times.
✗ Branch 2 not taken.
7437 notOutArgs_(),
179
1/2
✓ Branch 1 taken 7437 times.
✗ Branch 2 not taken.
7437 inDers_(),
180
1/2
✓ Branch 1 taken 7437 times.
✗ Branch 2 not taken.
7437 notOutDers_(),
181
1/2
✓ Branch 1 taken 7437 times.
✗ Branch 2 not taken.
7437 outArgs_(),
182
1/2
✓ Branch 1 taken 7437 times.
✗ Branch 2 not taken.
7437 outDers_(),
183
2/4
✓ Branch 3 taken 7437 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7437 times.
✗ Branch 7 not taken.
7437 argFunction_(Eigen::VectorXi::Constant(space->nq(), -1)),
184
2/4
✓ Branch 3 taken 7437 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7437 times.
✗ Branch 7 not taken.
7437 derFunction_(Eigen::VectorXi::Constant(space->nv(), -1)),
185 7437 errorThreshold_(Eigen::NumTraits<value_type>::epsilon()),
186 7437 errorSize_(0)
187 // , Jg (nv, nv)
188 ,
189
1/2
✓ Branch 3 taken 7437 times.
✗ Branch 4 not taken.
7437 arg_(space->nq()),
190
1/2
✓ Branch 3 taken 7437 times.
✗ Branch 4 not taken.
7437 diff_(space->nv()),
191
2/4
✓ Branch 1 taken 7437 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 7437 times.
✗ Branch 7 not taken.
14874 diffSmall_() {
192
1/2
✓ Branch 3 taken 7437 times.
✗ Branch 4 not taken.
7437 notOutArgs_.addRow(0, space->nq());
193
1/2
✓ Branch 3 taken 7437 times.
✗ Branch 4 not taken.
7437 notOutDers_.addCol(0, space->nv());
194 7437 }
195
196 /// \}
197
198 /// \name Parameters
199 /// \{
200
201 /// Set error threshold
202 1015 void errorThreshold(const value_type& threshold) {
203 1015 errorThreshold_ = threshold;
204 1015 }
205 /// Get error threshold
206 value_type errorThreshold() const { return errorThreshold_; }
207 /// Get error threshold
208 value_type squaredErrorThreshold() const {
209 return errorThreshold_ * errorThreshold_;
210 }
211
212 /// \}
213
214 /// \name Input and outputs
215 /// \{
216
217 /// Set \f$in\f$ of input configuration variables
218 9 const RowBlockIndices& inArgs() const { return inArgs_; }
219
220 /// Set of input velocity variables
221 13397 const ColBlockIndices& inDers() const { return inDers_; }
222
223 /// Set \f$i\overline{n\cup ou}t\f$ of other configuration variables
224 ///
225 /// Configuration variables that are not output variables
226 7 const RowBlockIndices& notOutArgs() const { return notOutArgs_; }
227
228 /// Set \f$i\overline{n\cup ou}t\f$ of other velocity variables
229 ///
230 /// Velocity variables that are not output variables
231 30 const ColBlockIndices& notOutDers() const { return notOutDers_; }
232
233 /// Same as \ref inArgs
234 ColBlockIndices activeParameters() const;
235
236 /// Same as \ref inDers
237 const ColBlockIndices& activeDerivativeParameters() const;
238
239 /// Returns a matrix of integer whose:
240 /// - rows correspond to functions
241 /// - cols correspond to DoF
242 /// - values correspond to the dependency degree of a function wrt to
243 /// a DoF
244 3 const Eigen::MatrixXi& inOutDependencies() const {
245 3 return inOutDependencies_;
246 }
247
248 /// Same as \ref inOutDependencies except that cols correpond to DoFs.
249 Eigen::MatrixXi inOutDofDependencies() const;
250
251 2 const Eigen::VectorXi& derFunction() const { return derFunction_; }
252
253 /// Set \f$out\f$ of output configuration variables
254 /// \return the set of intervals corresponding the the configuration
255 /// variables that are ouputs of the combination of explicit
256 /// constraints.
257 9 const RowBlockIndices& outArgs() const { return outArgs_; }
258
259 /// Set of output velocity variables
260 /// \return the set of intervals corresponding the the velocity
261 /// variables that are ouputs of the combination of explicit
262 /// constraints.
263 188 const RowBlockIndices& outDers() const { return outDers_; }
264
265 /// The Lie group on which constraints are defined
266 1 LiegroupSpacePtr_t configSpace() const { return configSpace_; }
267
268 /// The number of variables
269 1 std::size_t nq() const { return configSpace_->nq(); }
270
271 /// The number of derivative variables
272 1059 std::size_t nv() const { return configSpace_->nv(); }
273
274 /// \}
275
276 /// Return Jacobian matrix of output variable wrt not output variables
277 ///
278 /// \retval jacobian Jacobian matrix of the mapping from non output
279 /// variables to output variables. The columns of this matrix
280 /// corresponding to variables \f$in\f$ are filled with the
281 /// Jacobian of \f$f\f$:
282 /// \f{equation}
283 /// \frac{\partial f}{\partial \mathbf{q}_{in}}
284 /// (\mathbf{q}_{in}).
285 /// \f}
286 /// The columns corresponding to variables
287 /// \f$i\overline{n\cup ou}t\f$ are set to 0.
288 187 inline MatrixBlockView jacobianNotOutToOut(matrix_t& jacobian) const {
289 187 return MatrixBlockView(jacobian, outDers_.nbIndices(), outDers_.indices(),
290 374 notOutDers_.nbIndices(), notOutDers_.indices());
291 }
292
293 /** Compute the Jacobian of the explicit constraint resolution
294
295 \param q input configuration
296 \param jacobian square Jacobian matrix of same size as velocity
297 i.e. given by \ref nv method.
298
299 The result is the Jacobian of the explicit constraint set considered
300 as a projector that maps to any \f$\mathbf{p}\in\mathcal{C}\f$,
301 \f$\mathbf{q} = E(\mathbf{p})\f$ defined by
302 \f{eqnarray}
303 \mathbf{q}_{\bar{out}} &=& \mathbf{p}_{\bar{out}} \\
304 \mathbf{q}_{out} &=& f (\mathbf{p}_{in}) + rhs
305 \f}
306
307 \warning it is assumed solve(q) has been called before.
308 */
309 void jacobian(matrixOut_t jacobian, vectorIn_t q) const;
310
311 /// \name Right hand side accessors
312 /// \{
313
314 /// Compute right hand side of constraints using input configuration.
315 ///
316 /// \param p vector in \f$\mathcal{C}\f$.
317 ///
318 /// For each explicit constraint \f$E=(in,out,f)\f$, compute the right
319 /// hand side as follows:
320 /// \f{equation}
321 /// rhs = f (\mathbf{q}),
322 /// \f}
323 /// where in general
324 ///\f{equation}
325 /// f(\mathbf{q}) = \mathbf{p}_{out} - f(\mathbf{q}_{in),
326 /// \f}
327 /// in such a way that all \f$\mathbf{q}\f$ satisfies the explicit
328 /// constraint.
329 /// \note For hpp::constraints::explicit_::RelativePose, the implicit
330 /// formulation does not derive from the explicit one. The
331 /// right hand side considered is the right hand side of the
332 /// implicit formulation.
333 vector_t rightHandSideFromInput(vectorIn_t p);
334
335 /// Compute right hand side of constraint using input configuration.
336 ///
337 /// \param constraint explicit constraint,
338 /// \param p vector in \f$\mathcal{C}\f$.
339 ///
340 /// Let \f$E=(in,out,f)\f$ be the explicit constraint, compute the right
341 /// hand side as follows:
342 /// \f{equation}
343 /// rhs = f (\mathbf{q}),
344 /// \f}
345 /// where in general
346 ///\f{equation}
347 /// f(\mathbf{q}) = \mathbf{p}_{out} - f(\mathbf{q}_{in),
348 /// \f}
349 /// in such a way that all \f$\mathbf{q}\f$ satisfies the explicit
350 /// constraint.
351 /// \note For hpp::constraints::explicit_::RelativePose, the implicit
352 /// formulation does not derive from the explicit one. The
353 /// right hand side considered is the right hand side of the
354 /// implicit formulation.
355 bool rightHandSideFromInput(const ExplicitPtr_t& constraint, vectorIn_t p);
356
357 /// Compute right hand side of constraint using input configuration.
358 ///
359 /// \param i index of the explicit constraint,
360 /// \param p vector in \f$\mathcal{C}\f$.
361 ///
362 /// Let \f$E=(in,out,f)\f$ be the explicit constraint, compute the right
363 /// hand side as follows:
364 /// \f{equation}
365 /// rhs = f (\mathbf{q}),
366 /// \f}
367 /// where in general
368 ///\f{equation}
369 /// f(\mathbf{q}) = \mathbf{p}_{out} - f(\mathbf{q}_{in),
370 /// \f}
371 /// in such a way that all \f$\mathbf{q}\f$ satisfies the explicit
372 /// constraint.
373 /// \note For hpp::constraints::explicit_::RelativePose, the implicit
374 /// formulation does not derive from the explicit one. The
375 /// right hand side considered is the right hand side of the
376 /// implicit formulation.
377 void rightHandSideFromInput(const size_type& i, vectorIn_t p);
378
379 /// Set the right hand sides of the explicit constraints.
380 ///
381 /// \param rhs the right hand side.
382 ///
383 /// The components of rhs are dispatched to the right hand sides of the
384 /// explicit constraints in the order they are added.
385 void rightHandSide(vectorIn_t rhs);
386
387 /// Set the right hand side for a given explicit constraint
388 ///
389 /// \param constraint the explicit constraint,
390 /// \param rhs right hand side.
391 bool rightHandSide(const ExplicitPtr_t& constraint, vectorIn_t rhs);
392
393 /// Get the right hand side for a given explicit constraint
394 ///
395 /// \param constraint the explicit constraint,
396 /// \param rhs right hand side.
397 bool getRightHandSide(const ExplicitPtr_t& constraint, vectorOut_t rhs) const;
398
399 /// Set the right hand side for a given explicit constraint
400 ///
401 /// \param i order of the explicit constraint,
402 /// \param rhs right hand side.
403 void rightHandSide(const size_type& i, vectorIn_t rhs);
404
405 /// Get the right hand sides
406 /// \return the right hand sides of the explicit constraints stacked
407 /// into a vector
408 vector_t rightHandSide() const;
409
410 /// Get size of the right hand side
411 ///
412 /// See documentation of classes Implicit and Explicit for details.
413 size_type rightHandSideSize() const;
414
415 /// \}
416
417 std::ostream& print(std::ostream& os) const;
418
419 private:
420 typedef std::vector<bool> Computed_t;
421
422 /// Compute output variables with respect to input variables
423 /// \param i index of explicit constraint,
424 /// \retval arg configuration of the system in which output variables
425 /// are set to their values.
426 void solveExplicitConstraint(const std::size_t& i, vectorOut_t arg) const;
427 /// Compute rows of Jacobian corresponding to output of function
428 ///
429 /// \param i index of the explicit constraint,
430 /// \retval J Jacobian in which rows are computed
431 ///
432 /// Let
433 /// \li E = (f, in, out) be the explicit constraint of index i,
434 /// \li E.jacobian be the Jacobian of f,
435 /// \li E.in the input velocity variables of the constraints,
436 /// \li E.out the output velocity variables of the constraints,
437 /// \li Jin the matrix composed of E.in rows of J,
438 /// \li Jout the matrix composed of E.out rows of J,
439 /// then,
440 /// Jout = E.jacobian * Jin
441 void computeJacobian(const std::size_t& i, matrixOut_t J) const;
442 void computeOrder(const std::size_t& iF, std::size_t& iOrder,
443 Computed_t& computed);
444
445 LiegroupSpacePtr_t configSpace_;
446
447 struct Data {
448 Data(const ExplicitPtr_t& constraint);
449 ExplicitPtr_t constraint;
450 RowBlockIndices equalityIndices;
451 LiegroupElement rhs_implicit;
452 // implicit formulation
453 mutable LiegroupElement h_value;
454 // explicit formulation
455 mutable vector_t qin, qout;
456 mutable LiegroupElement f_value, res_qout;
457 // jacobian of f
458 mutable matrix_t jacobian;
459 }; // struct Data
460
461 RowBlockIndices inArgs_, notOutArgs_;
462 ColBlockIndices inDers_, notOutDers_;
463 /// Output indices
464 RowBlockIndices outArgs_, outDers_;
465
466 Eigen::MatrixXi inOutDependencies_;
467
468 std::vector<Data> data_;
469 std::vector<std::size_t> computationOrder_;
470 /// For each configuration variable i, argFunction_[i] is the index in
471 /// data_ of the function that computes this configuration
472 /// variable.
473 /// -1 means that the configuration variable is not ouput of any
474 /// function in data_.
475 Eigen::VectorXi argFunction_, derFunction_;
476 value_type errorThreshold_;
477 size_type errorSize_;
478 // mutable matrix_t Jg;
479 mutable vector_t arg_, diff_, diffSmall_;
480
481 /// Constructor for serialization
482 ExplicitConstraintSet()
483 : inArgs_(),
484 notOutArgs_(),
485 inDers_(),
486 notOutDers_(),
487 outArgs_(),
488 outDers_(),
489 errorThreshold_(Eigen::NumTraits<value_type>::epsilon()),
490 errorSize_(0) {}
491 /// Initialization for serialization
492 1 void init(const LiegroupSpacePtr_t& space) {
493 1 configSpace_ = space;
494
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 argFunction_ = Eigen::VectorXi::Constant(space->nq(), -1);
495
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 derFunction_ = Eigen::VectorXi::Constant(space->nv(), -1);
496 1 arg_.resize(space->nq());
497 1 diff_.resize(space->nv());
498
499
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 notOutArgs_.addRow(0, space->nq());
500
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 notOutDers_.addCol(0, space->nv());
501 1 }
502
503 friend class solver::BySubstitution;
504 }; // class ExplicitConstraintSet
505 /// \}
506 } // namespace constraints
507 } // namespace hpp
508
509 #endif // HPP_CONSTRAINTS_EXPLICIT_CONSTRAINT_SET_HH
510