GCC Code Coverage Report


Directory: ./
File: src/path-optimization/spline-gradient-based.cc
Date: 2025-05-07 11:07:45
Exec Total Coverage
Lines: 0 123 0.0%
Branches: 0 272 0.0%

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 #include <hpp/core/path-optimization/linear-constraint.hh>
30 #include <hpp/manipulation/constraint-set.hh>
31 #include <hpp/manipulation/graph/edge.hh>
32 #include <hpp/manipulation/graph/state.hh>
33 #include <hpp/manipulation/path-optimization/spline-gradient-based.hh>
34
35 namespace hpp {
36 namespace manipulation {
37 namespace pathOptimization {
38
39 template <int _PB, int _SO>
40 ✗ SplineGradientBased<_PB, _SO>::SplineGradientBased(
41 const ProblemConstPtr_t& problem)
42 ✗ : Parent_t(problem) {
43 ✗ this->checkOptimum_ = true;
44 }
45
46 // ----------- Convenience class -------------------------------------- //
47
48 // ----------- Resolution steps --------------------------------------- //
49
50 template <int _PB, int _SO>
51 typename SplineGradientBased<_PB, _SO>::Ptr_t
52 ✗ SplineGradientBased<_PB, _SO>::create(const ProblemConstPtr_t& problem) {
53 ✗ SplineGradientBased* ptr = new SplineGradientBased(problem);
54 ✗ Ptr_t shPtr(ptr);
55 ✗ return shPtr;
56 }
57
58 template <int _PB, int _SO>
59 typename SplineGradientBased<_PB, _SO>::Ptr_t
60 ✗ SplineGradientBased<_PB, _SO>::createFromCore(
61 const core::ProblemConstPtr_t& problem) {
62 ✗ if (!HPP_DYNAMIC_PTR_CAST(const Problem, problem))
63 ✗ throw std::invalid_argument("This is not a manipulation problem.");
64 ✗ return create(HPP_STATIC_PTR_CAST(const Problem, problem));
65 }
66
67 template <int _PB, int _SO>
68 ✗ void SplineGradientBased<_PB, _SO>::initializePathValidation(
69 const Splines_t& splines) {
70 ✗ this->validations_.resize(splines.size());
71 ✗ for (std::size_t i = 0; i < splines.size(); ++i) {
72 ✗ ConstraintSetPtr_t set =
73 ✗ HPP_STATIC_PTR_CAST(ConstraintSet, splines[i]->constraints());
74 ✗ if (set && set->edge())
75 ✗ this->validations_[i] = set->edge()->pathValidation();
76 else
77 ✗ this->validations_[i] = this->problem()->pathValidation();
78 }
79 }
80
81 template <int _PB, int _SO>
82 ✗ void SplineGradientBased<_PB, _SO>::addProblemConstraints(
83 const core::PathVectorPtr_t& init, const Splines_t& splines,
84 LinearConstraint& lc, SplineOptimizationDatas_t& sods) const {
85 ✗ assert(init->numberPaths() == splines.size() &&
86 sods.size() == splines.size());
87
88 bool zeroDerivative =
89 this->problem()
90 ✗ ->getParameter(
91 "SplineGradientBased/zeroDerivativesAtStateIntersection")
92 ✗ .boolValue();
93
94 ✗ const std::size_t last = splines.size() - 1;
95 ✗ graph::StatePtr_t stateOfStart;
96 ✗ for (std::size_t i = 0; i < last; ++i) {
97 ✗ core::PathPtr_t path = init->pathAtRank(i);
98 ✗ ConstraintSetPtr_t set =
99 ✗ HPP_STATIC_PTR_CAST(ConstraintSet, splines[i]->constraints());
100 ✗ if (!set || !set->edge())
101 ✗ std::invalid_argument(
102 "Cannot optimize a path that has not been "
103 "generated with a graph.");
104 ✗ graph::EdgePtr_t transition = set->edge();
105
106 ✗ this->addProblemConstraintOnPath(path, i, splines[i], lc, sods[i]);
107
108 // The path should always go through the start and end states of the
109 // transition.
110 ✗ assert(!HPP_DYNAMIC_PTR_CAST(graph::WaypointEdge, transition));
111 ✗ graph::StatePtr_t from = transition->stateFrom();
112 ✗ graph::StatePtr_t to = transition->stateTo();
113 ✗ graph::StatePtr_t from2 = from, to2 = to;
114
115 ✗ Configuration_t q0 = path->initial(), q1 = path->end();
116 ✗ const bool src_contains_q0 = from->contains(q0);
117 ✗ const bool dst_contains_q0 = to->contains(q0);
118 ✗ const bool src_contains_q1 = from->contains(q1);
119 ✗ const bool dst_contains_q1 = to->contains(q1);
120
121 ✗ bool use_direct = src_contains_q0 && dst_contains_q1;
122 ✗ bool use_reverse = src_contains_q1 && dst_contains_q0;
123 ✗ if (use_direct && use_reverse) {
124 ✗ if (i == 0 || stateOfStart == from)
125 ✗ use_reverse = false;
126 ✗ else if (stateOfStart == to)
127 ✗ use_direct = false;
128 ✗ else if (stateOfStart) {
129 ✗ if (stateOfStart->contains(q0))
130 ✗ use_reverse = false;
131 else
132 ✗ use_direct = false; // assumes stateOfStart->contains(q0)
133 } else
134 ✗ use_reverse = false; // default if we don't know what to do...
135 }
136 ✗ if (use_direct) {
137 // Nominal case
138 ✗ if (transition->state() != to) {
139 ✗ constrainEndIntoState(path, i, splines[i], transition->stateTo(), lc);
140 }
141 ✗ stateOfStart = to;
142 ✗ } else if (use_reverse) {
143 // Reversed nominal case
144 ✗ if (transition->state() != from) {
145 ✗ constrainEndIntoState(path, i, splines[i], from, lc);
146 }
147 ✗ stateOfStart = from;
148 } else {
149 ✗ if (src_contains_q0) { // q1 must stay in state
150 ✗ to2 = transition->state();
151 ✗ stateOfStart = to;
152 ✗ } else if (dst_contains_q0) { // q1 must stay in state
153 ✗ from2 = transition->state();
154 ✗ stateOfStart = from;
155 ✗ } else if (src_contains_q1) { // q1 must stay in src
156 ✗ to2 = transition->state();
157 ✗ stateOfStart = from;
158 ✗ if (transition->state() != from) {
159 ✗ constrainEndIntoState(path, i, splines[i], from, lc);
160 }
161 ✗ } else if (dst_contains_q1) { // q1 must stay in dst
162 ✗ from2 = transition->state();
163 ✗ stateOfStart = to;
164 ✗ if (transition->state() != to) {
165 ✗ constrainEndIntoState(path, i, splines[i], to, lc);
166 }
167 } else {
168 // q0 and q1 are in state. We add no constraint.
169 hppDout(warning, "Add no constraint for this path.");
170 ✗ from2 = transition->state();
171 ✗ to2 = transition->state();
172 ✗ stateOfStart.reset();
173 }
174 }
175 ✗ if (zeroDerivative) {
176 ✗ if (!(use_reverse && src_contains_q0 && src_contains_q1) &&
177 ✗ !(use_direct && dst_contains_q0 && dst_contains_q1) && from2 != to2) {
178 ✗ constraintDerivativesAtEndOfSpline(i, splines[i], lc);
179 }
180 }
181 }
182 ✗ this->addProblemConstraintOnPath(init->pathAtRank(last), last, splines[last],
183 ✗ lc, sods[last]);
184 }
185
186 template <int _PB, int _SO>
187 ✗ void SplineGradientBased<_PB, _SO>::constrainEndIntoState(
188 const core::PathPtr_t& path, const size_type& idxSpline,
189 const SplinePtr_t& spline, const graph::StatePtr_t state,
190 LinearConstraint& lc) const {
191 ✗ typename Spline::BasisFunctionVector_t B1;
192 ✗ spline->basisFunctionDerivative(0, 1, B1);
193 // TODO Should we add zero velocity sometimes ?
194
195 ✗ ConstraintSetPtr_t set = state->configConstraint();
196 ✗ value_type guessThreshold =
197 this->problem()
198 ✗ ->getParameter("SplineGradientBased/guessThreshold")
199 ✗ .floatValue();
200 ✗ Eigen::RowBlockIndices select = this->computeActiveParameters(
201 ✗ path, set->configProjector()->solver(), guessThreshold, true);
202 hppDout(info,
203 "End of path " << idxSpline << ": do not change this dof " << select);
204 hppDout(info, "End of path " << idxSpline << ": state " << state->name());
205
206 ✗ const size_type rDof = this->robot_->numberDof(),
207 ✗ col = idxSpline * Spline::NbCoeffs * rDof, row = lc.J.rows(),
208 ✗ nOutVar = select.nbIndices();
209
210 // Add nOutVar constraints
211 ✗ lc.addRows(nOutVar);
212 ✗ matrix_t I = select.rview(matrix_t::Identity(rDof, rDof));
213 ✗ for (size_type k = 0; k < Spline::NbCoeffs; ++k)
214 ✗ lc.J.block(row, col + k * rDof, nOutVar, rDof) = B1(k) * I;
215 ✗ lc.b.segment(row, nOutVar) =
216 ✗ select.rview(spline->parameters().transpose() * B1);
217
218 ✗ assert((lc.J.block(row, col, nOutVar, rDof * Spline::NbCoeffs) *
219 spline->rowParameters())
220 .isApprox(lc.b.segment(row, nOutVar)));
221 }
222
223 template <int _PB, int _SO>
224 ✗ void SplineGradientBased<_PB, _SO>::constraintDerivativesAtEndOfSpline(
225 const size_type& idxSpline, const SplinePtr_t& spline,
226 LinearConstraint& lc) const {
227 ✗ typename Spline::BasisFunctionVector_t B1;
228 ✗ spline->basisFunctionDerivative(1, 1, B1);
229
230 // ConstraintSetPtr_t set = state->configConstraint();
231 // value_type guessThreshold = this->problem().getParameter
232 // ("SplineGradientBased/guessThreshold").floatValue(); Eigen::RowBlockIndices
233 // select = this->computeActiveParameters (path,
234 // set->configProjector()->solver(), guessThreshold);
235
236 ✗ const size_type rDof = this->robot_->numberDof(),
237 ✗ col = idxSpline * Spline::NbCoeffs * rDof, row = lc.J.rows(),
238 // nOutVar = select.nbIndices();
239 ✗ nOutVar = rDof;
240
241 // Add nOutVar constraints
242 ✗ lc.addRows(nOutVar);
243 // matrix_t I = select.rview(matrix_t::Identity(rDof, rDof));
244 ✗ matrix_t I(matrix_t::Identity(rDof, rDof));
245 ✗ for (size_type k = 0; k < Spline::NbCoeffs; ++k)
246 ✗ lc.J.block(row, col + k * rDof, nOutVar, rDof) = B1(k) * I;
247 ✗ lc.b.segment(row, nOutVar).setZero();
248
249 ✗ if (!(lc.J.block(row, col, nOutVar, rDof * Spline::NbCoeffs) *
250 spline->rowParameters())
251 ✗ .isApprox(lc.b.segment(row, nOutVar))) {
252 hppDout(error,
253 "The velocity should already be zero:\n"
254 << (lc.J.block(row, col, nOutVar, rDof * Spline::NbCoeffs) *
255 spline->rowParameters())
256 .transpose());
257 }
258 }
259
260 // ----------- Optimize ----------------------------------------------- //
261
262 // ----------- Convenience functions ---------------------------------- //
263
264 // ----------- Instanciate -------------------------------------------- //
265
266 // template class SplineGradientBased<core::path::CanonicalPolynomeBasis, 1>; //
267 // equivalent to StraightPath template class
268 // SplineGradientBased<core::path::CanonicalPolynomeBasis, 2>; template class
269 // SplineGradientBased<core::path::CanonicalPolynomeBasis, 3>;
270 template class SplineGradientBased<core::path::BernsteinBasis,
271 1>; // equivalent to StraightPath
272 // template class SplineGradientBased<core::path::BernsteinBasis, 2>;
273 template class SplineGradientBased<core::path::BernsteinBasis, 3>;
274
275 using core::Parameter;
276 using core::ParameterDescription;
277
278 ✗ HPP_START_PARAMETER_DECLARATION(SplineGradientBased)
279 ✗ core::Problem::declareParameter(ParameterDescription(
280 Parameter::BOOL, "SplineGradientBased/zeroDerivativesAtStateIntersection",
281 "Whether we should enforce a null velocity at each control point where the "
282 "state before and after is different.",
283 ✗ Parameter(false)));
284 ✗ HPP_END_PARAMETER_DECLARATION(SplineGradientBased)
285 } // namespace pathOptimization
286 } // namespace manipulation
287 } // namespace hpp
288