GCC Code Coverage Report


Directory: ./
File: src/path-optimization/spline-gradient-based.cc
Date: 2025-03-07 11:10:46
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