GCC Code Coverage Report


Directory: ./
File: src/graph/helper.cc
Date: 2025-05-07 11:07:45
Exec Total Coverage
Lines: 0 484 0.0%
Branches: 0 778 0.0%

Line Branch Exec Source
1 // Copyright (c) 2016, 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 <array>
30 #include <boost/regex.hpp>
31 #include <hpp/constraints/differentiable-function.hh>
32 #include <hpp/constraints/locked-joint.hh>
33 #include <hpp/manipulation/graph/edge.hh>
34 #include <hpp/manipulation/graph/guided-state-selector.hh>
35 #include <hpp/manipulation/graph/helper.hh>
36 #include <hpp/manipulation/graph/state-selector.hh>
37 #include <hpp/manipulation/graph/state.hh>
38 #include <hpp/manipulation/handle.hh>
39 #include <hpp/manipulation/problem-solver.hh>
40 #include <hpp/pinocchio/gripper.hh>
41 #include <hpp/util/debug.hh>
42 #include <iterator>
43 #include <pinocchio/multibody/model.hpp>
44 #include <unordered_map>
45 #include <unordered_set>
46
47 #define CASE_TO_STRING(var, value) \
48 ((var & value) ? std::string(#value) : std::string())
49
50 namespace hpp {
51 namespace manipulation {
52 namespace graph {
53 namespace helper {
54 typedef constraints::Implicit Implicit;
55 typedef constraints::ImplicitPtr_t ImplicitPtr_t;
56
57 template <bool forPath>
58 ✗ void addToComp(const NumericalConstraints_t& nc, GraphComponentPtr_t comp) {
59 ✗ if (nc.empty()) return;
60 ✗ StatePtr_t n;
61 if (forPath) {
62 n = HPP_DYNAMIC_PTR_CAST(State, comp);
63 if (!n) throw std::logic_error("Wrong type: expect a State");
64 }
65 ✗ for (const auto& c : nc)
66 ✗ if (c) {
67 if (forPath)
68 n->addNumericalConstraintForPath(c);
69 else
70 ✗ comp->addNumericalConstraint(c);
71 }
72 }
73
74 template <bool param>
75 void specifyFoliation(const NumericalConstraints_t& nc, LevelSetEdgePtr_t lse) {
76 for (const auto& c : nc)
77 if (c) {
78 if (param)
79 lse->insertParamConstraint(c);
80 else
81 lse->insertConditionConstraint(c);
82 }
83 }
84
85 ✗ void FoliatedManifold::addToState(StatePtr_t comp) const {
86 ✗ addToComp<false>(nc, comp);
87 ✗ addToComp<false>(nc_path, comp);
88 }
89
90 ✗ void FoliatedManifold::addToEdge(EdgePtr_t comp) const {
91 ✗ addToComp<false>(nc_fol, comp);
92 }
93
94 ✗ void FoliatedManifold::specifyFoliation(LevelSetEdgePtr_t lse) const {
95 ✗ for (const auto& c : nc) lse->insertConditionConstraint(c);
96 ✗ for (const auto& c : nc_fol) lse->insertConditionConstraint(c);
97 }
98
99 namespace {
100 template <int gCase>
101 struct CaseTraits {
102 static const bool pregrasp = (gCase & WithPreGrasp);
103 static const bool preplace = (gCase & WithPrePlace);
104 static const bool intersec = !((gCase & NoGrasp) || (gCase & NoPlace));
105
106 static const bool valid =
107 ((gCase & WithPreGrasp) || (gCase & GraspOnly) || (gCase & NoGrasp)) &&
108 ((gCase & WithPrePlace) || (gCase & PlaceOnly) || (gCase & NoPlace)) &&
109 !((gCase & NoGrasp) && (gCase & NoPlace));
110
111 static const std::size_t nbWaypoints =
112 (pregrasp ? 1 : 0) + (intersec ? 1 : 0) + (preplace ? 1 : 0);
113 static const std::size_t Nstates = 2 + nbWaypoints;
114 static const std::size_t Nedges = 1 + nbWaypoints;
115 // static const std::size_t iNpregrasp = pregrasp?1 + 1:nbWaypoints;
116 // static const std::size_t iNpreplace = pregrasp?1 + 1:nbWaypoints;
117 typedef std::array<StatePtr_t, Nstates> StateArray;
118 typedef std::array<EdgePtr_t, Nedges> EdgeArray;
119
120 ✗ static inline const StatePtr_t& Npregrasp(const StateArray& n) {
121 assert(pregrasp);
122 ✗ return n[1];
123 }
124 ✗ static inline const StatePtr_t& Nintersec(const StateArray& n) {
125 assert(intersec);
126 ✗ return n[1 + (pregrasp ? 1 : 0)];
127 }
128 ✗ static inline const StatePtr_t& Npreplace(const StateArray& n) {
129 assert(preplace);
130 ✗ return n[1 + (pregrasp ? 1 : 0) + (intersec ? 1 : 0)];
131 }
132
133 static inline std::string caseToString() {
134 return CASE_TO_STRING(gCase, NoGrasp) + CASE_TO_STRING(gCase, GraspOnly) +
135 CASE_TO_STRING(gCase, WithPreGrasp) + " - " +
136 CASE_TO_STRING(gCase, NoPlace) + CASE_TO_STRING(gCase, PlaceOnly) +
137 CASE_TO_STRING(gCase, WithPrePlace);
138 }
139
140 ✗ static inline EdgePtr_t makeWE(const std::string& name,
141 const StatePtr_t& from, const StatePtr_t& to,
142 const size_type& w) {
143 if (Nedges > 1) {
144 ✗ WaypointEdgePtr_t we = static_pointer_cast<WaypointEdge>(
145 from->linkTo(name, to, w, WaypointEdge::create));
146 ✗ we->nbWaypoints(nbWaypoints);
147 ✗ return we;
148 ✗ } else
149 ✗ return from->linkTo(name, to, w, Edge::create);
150 }
151
152 ✗ static inline StateArray makeWaypoints(const StatePtr_t& from,
153 const StatePtr_t& to,
154 const std::string& name) {
155 ✗ StateSelectorPtr_t ns = from->parentGraph()->stateSelector();
156 ✗ StateArray states;
157 ✗ std::size_t r = 0;
158 ✗ states[r] = from;
159 ✗ ++r;
160 if (pregrasp) {
161 ✗ states[r] = ns->createState(name + "_pregrasp", true);
162 ✗ ++r;
163 }
164 if (intersec) {
165 ✗ states[r] = ns->createState(name + "_intersec", true);
166 ✗ ++r;
167 }
168 if (preplace) {
169 ✗ states[r] = ns->createState(name + "_preplace", true);
170 ✗ ++r;
171 }
172 ✗ states[r] = to;
173 ✗ return states;
174 }
175
176 ✗ static inline EdgePtr_t makeLSEgrasp(const std::string& name,
177 const StateArray& n, const EdgeArray& e,
178 const size_type w,
179 LevelSetEdgePtr_t& gls) {
180 if (Nedges > 1) {
181 ✗ const std::size_t T = (pregrasp ? 1 : 0) + (intersec ? 1 : 0);
182 ✗ WaypointEdgePtr_t we = static_pointer_cast<WaypointEdge>(
183 ✗ n.front()->linkTo(name + "_ls", n.back(), w, WaypointEdge::create));
184 ✗ we->nbWaypoints(nbWaypoints);
185 ✗ gls = linkWaypoint<LevelSetEdge>(n, T - 1, T, name, "ls");
186 ✗ for (std::size_t i = 0; i < Nedges; ++i)
187 ✗ we->setWaypoint(i, e[i], n[i + 1]);
188 ✗ we->setWaypoint(T - 1, gls, n[T]);
189 ✗ gls->state(n.front());
190 ✗ gls->setShort(pregrasp);
191 ✗ return we;
192 ✗ } else {
193 assert(gCase == (GraspOnly | NoPlace) &&
194 "Cannot implement a LevelSetEdge for grasping");
195 ✗ gls = static_pointer_cast<LevelSetEdge>(
196 ✗ n.front()->linkTo(name + "_ls", n.back(), w, LevelSetEdge::create));
197 ✗ return gls;
198 }
199 }
200
201 ✗ static inline EdgePtr_t makeLSEplace(const std::string& name,
202 const StateArray& n, const EdgeArray& e,
203 const size_type w,
204 LevelSetEdgePtr_t& pls) {
205 if (Nedges > 1) {
206 ✗ const std::size_t T = (pregrasp ? 1 : 0) + (intersec ? 1 : 0);
207 ✗ WaypointEdgePtr_t we = static_pointer_cast<WaypointEdge>(
208 ✗ n.back()->linkTo(name + "_ls", n.front(), w, WaypointEdge::create));
209 ✗ we->nbWaypoints(nbWaypoints);
210 ✗ pls = linkWaypoint<LevelSetEdge>(n, T + 1, T, name, "ls");
211 // for (std::size_t i = Nedges - 1; i != 0; --i)
212 ✗ for (std::size_t k = 0; k < Nedges; ++k) {
213 ✗ std::size_t i = Nedges - 1 - k;
214 ✗ we->setWaypoint(Nedges - 1 - i, e[i], n[i]);
215 }
216 ✗ we->setWaypoint(Nedges - 1 - T, pls, n[T]);
217 ✗ pls->state(n.back());
218 ✗ pls->setShort(preplace);
219 ✗ return we;
220 ✗ } else {
221 ✗ assert(gCase == (NoGrasp | PlaceOnly) &&
222 "Cannot implement a LevelSetEdge for placement");
223 pls = static_pointer_cast<LevelSetEdge>(
224 n.back()->linkTo(name + "_ls", n.front(), w, LevelSetEdge::create));
225 return pls;
226 }
227 }
228
229 template <typename EdgeType>
230 ✗ static inline shared_ptr<EdgeType> linkWaypoint(
231 const StateArray& states, const std::size_t& iF, const std::size_t& iT,
232 const std::string& prefix, const std::string& suffix = "") {
233 ✗ std::stringstream ss;
234 ✗ ss << prefix << "_" << iF << iT;
235 ✗ if (suffix.length() > 0) ss << "_" << suffix;
236 return static_pointer_cast<EdgeType>(
237 ✗ states[iF]->linkTo(ss.str(), states[iT], -1, EdgeType::create));
238 }
239
240 template <bool forward>
241 ✗ static inline EdgeArray linkWaypoints(const StateArray& states,
242 const EdgePtr_t& edge,
243 const std::string& name) {
244 ✗ EdgeArray e;
245 ✗ WaypointEdgePtr_t we = HPP_DYNAMIC_PTR_CAST(WaypointEdge, edge);
246 if (forward)
247 ✗ for (std::size_t i = 0; i < Nedges; ++i) {
248 ✗ e[i] = linkWaypoint<Edge>(states, i, i + 1, name);
249 ✗ we->setWaypoint(i, e[i], states[i + 1]);
250 }
251 else
252 // for (std::size_t i = Nedges - 1; i != 0; --i) {
253 ✗ for (std::size_t k = 0; k < Nedges; ++k) {
254 ✗ std::size_t i = Nedges - 1 - k;
255 ✗ e[i] = linkWaypoint<Edge>(states, i + 1, i, name);
256 ✗ we->setWaypoint(Nedges - 1 - i, e[i], states[i]);
257 }
258 ✗ return e;
259 }
260
261 ✗ static inline void setStateConstraints(const StateArray& n,
262 const FoliatedManifold& g,
263 const FoliatedManifold& pg,
264 const FoliatedManifold& p,
265 const FoliatedManifold& pp,
266 const FoliatedManifold& m) {
267 // From and to are not populated automatically
268 // to avoid duplicates.
269 if (pregrasp) {
270 ✗ p.addToState(Npregrasp(n));
271 ✗ pg.addToState(Npregrasp(n));
272 ✗ m.addToState(Npregrasp(n));
273 }
274 if (intersec) {
275 ✗ p.addToState(Nintersec(n));
276 ✗ g.addToState(Nintersec(n));
277 ✗ m.addToState(Nintersec(n));
278 }
279 if (preplace) {
280 ✗ pp.addToState(Npreplace(n));
281 ✗ g.addToState(Npreplace(n));
282 ✗ m.addToState(Npreplace(n));
283 }
284 }
285
286 ✗ static inline void setEdgeConstraints(const EdgeArray& e,
287 const FoliatedManifold& g,
288 const FoliatedManifold& p,
289 const FoliatedManifold& m) {
290 // The border B
291 ✗ const std::size_t B = (pregrasp ? 1 : 0) + (intersec ? 1 : 0);
292 ✗ for (std::size_t i = 0; i < B; ++i) p.addToEdge(e[i]);
293 ✗ for (std::size_t i = B; i < Nedges; ++i) g.addToEdge(e[i]);
294 ✗ for (std::size_t i = 0; i < Nedges; ++i) m.addToEdge(e[i]);
295 }
296
297 template <bool forward>
298 ✗ static inline void setEdgeProp(const EdgeArray& e, const StateArray& n) {
299 /// Last is short
300 ✗ const std::size_t K = (forward ? 1 : 0);
301 ✗ for (std::size_t i = K; i < Nedges - 1 + K; ++i) e[i]->setShort(true);
302 // The border B
303 std::size_t B;
304 if ((gCase & NoGrasp)) // There is no grasp
305 B = 0;
306 else // There is a grasp
307 ✗ B = 1 + (pregrasp ? 1 : 0);
308 ✗ for (std::size_t i = 0; i < B; ++i) e[i]->state(n[0]);
309 ✗ for (std::size_t i = B; i < Nedges; ++i) e[i]->state(n[Nstates - 1]);
310 }
311 };
312 } // namespace
313
314 template <int gCase>
315 ✗ Edges_t createEdges(const std::string& forwName, const std::string& backName,
316 const StatePtr_t& from, const StatePtr_t& to,
317 const size_type& wForw, const size_type& wBack,
318 const FoliatedManifold& grasp,
319 const FoliatedManifold& pregrasp,
320 const FoliatedManifold& place,
321 const FoliatedManifold& preplace, const bool levelSetGrasp,
322 const bool levelSetPlace,
323 const FoliatedManifold& submanifoldDef) {
324 typedef CaseTraits<gCase> T;
325 hppDout(info, "Creating edges " << forwName << " and " << backName
326 << "\ncase is " << T::caseToString());
327 assert(T::valid && "Not a valid case.");
328 typedef typename T::StateArray StateArray;
329 typedef typename T::EdgeArray EdgeArray;
330
331 // Create the edges
332 ✗ EdgePtr_t weForw = T::makeWE(forwName, from, to, wForw),
333 ✗ weBack = T::makeWE(backName, to, from, wBack), weForwLs, weBackLs;
334
335 ✗ std::string name = forwName;
336 ✗ StateArray n = T::makeWaypoints(from, to, name);
337
338 ✗ EdgeArray eF = T::template linkWaypoints<true>(n, weForw, name);
339
340 // Set the states constraints
341 // Note that submanifold is not taken into account for states
342 // because the edges constraints will enforce configuration to stay
343 // in a leaf, and so in the manifold itself.
344 ✗ T::setStateConstraints(n, grasp, pregrasp, place, preplace, submanifoldDef);
345
346 // Set the edges properties
347 ✗ T::template setEdgeProp<true>(eF, n);
348
349 // Set the edges constraints
350 ✗ T::setEdgeConstraints(eF, grasp, place, submanifoldDef);
351
352 ✗ LevelSetEdgePtr_t gls;
353 ✗ if (levelSetGrasp) weForwLs = T::makeLSEgrasp(name, n, eF, 10 * wForw, gls);
354
355 // Populate bacward edge
356 ✗ name = backName;
357 ✗ EdgeArray eB = T::template linkWaypoints<false>(n, weBack, name);
358
359 ✗ T::template setEdgeProp<false>(eB, n);
360
361 ✗ T::setEdgeConstraints(eB, grasp, place, submanifoldDef);
362
363 ✗ LevelSetEdgePtr_t pls;
364 ✗ if (levelSetPlace) weBackLs = T::makeLSEplace(name, n, eB, 10 * wBack, pls);
365
366 ✗ Edges_t ret{weForw, weBack};
367
368 ✗ if (levelSetPlace) {
369 ✗ if (!place.foliated()) {
370 hppDout(warning,
371 "You asked for a LevelSetEdge for placement, "
372 "but did not specify the target foliation. "
373 "It will have no effect");
374 }
375 ✗ grasp.addToEdge(pls);
376 ✗ place.specifyFoliation(pls);
377 ✗ submanifoldDef.addToEdge(pls);
378 ✗ pls->buildHistogram();
379 ✗ place.addToEdge(weBackLs);
380 ✗ submanifoldDef.addToEdge(weBackLs);
381 ✗ ret.push_back(weBackLs);
382 }
383 ✗ if (levelSetGrasp) {
384 ✗ if (!grasp.foliated()) {
385 hppDout(warning,
386 "You asked for a LevelSetEdge for grasping, "
387 "but did not specify the target foliation. "
388 "It will have no effect");
389 }
390 ✗ place.addToEdge(gls);
391 ✗ grasp.specifyFoliation(gls);
392 ✗ submanifoldDef.addToEdge(gls);
393 ✗ gls->buildHistogram();
394 ✗ grasp.addToEdge(weForwLs);
395 ✗ submanifoldDef.addToEdge(weForwLs);
396 ✗ ret.push_back(weForwLs);
397 }
398
399 ✗ return ret;
400 }
401
402 ✗ EdgePtr_t createLoopEdge(const std::string& loopName, const StatePtr_t& state,
403 const size_type& w, const bool levelSet,
404 const FoliatedManifold& submanifoldDef) {
405 // Create the edges
406 ✗ EdgePtr_t loop;
407 ✗ if (levelSet)
408 ✗ loop = state->linkTo(loopName, state, w, LevelSetEdge::create);
409 else
410 ✗ loop = state->linkTo(loopName, state, w, Edge::create);
411
412 ✗ loop->state(state);
413 ✗ submanifoldDef.addToEdge(loop);
414
415 ✗ if (levelSet) {
416 ✗ if (!submanifoldDef.foliated()) {
417 hppDout(warning,
418 "You asked for a LevelSetEdge for looping, "
419 "but did not specify the target foliation. "
420 "It will have no effect");
421 }
422 ✗ LevelSetEdgePtr_t ls = HPP_DYNAMIC_PTR_CAST(LevelSetEdge, loop);
423 ✗ submanifoldDef.specifyFoliation(ls);
424 ✗ ls->buildHistogram();
425 }
426
427 ✗ return loop;
428 }
429
430 ✗ void graspManifold(const GripperPtr_t& gripper, const HandlePtr_t& handle,
431 FoliatedManifold& grasp, FoliatedManifold& pregrasp) {
432 ✗ ImplicitPtr_t gc = handle->createGrasp(gripper, "");
433 ✗ grasp.nc.push_back(gc);
434 ✗ grasp.nc_path.push_back(gc);
435 ✗ ImplicitPtr_t gcc = handle->createGraspComplement(gripper, "");
436 ✗ if (gcc->function().outputSize() > 0) grasp.nc_fol.push_back(gcc);
437
438 ✗ const value_type c = handle->clearance() + gripper->clearance();
439 ✗ ImplicitPtr_t pgc = handle->createPreGrasp(gripper, c, "");
440 ✗ pregrasp.nc.push_back(pgc);
441 ✗ pregrasp.nc_path.push_back(pgc);
442 }
443
444 ✗ void strictPlacementManifold(const ImplicitPtr_t placement,
445 const ImplicitPtr_t preplacement,
446 const ImplicitPtr_t placementComplement,
447 FoliatedManifold& place,
448 FoliatedManifold& preplace) {
449 ✗ place.nc.push_back(placement);
450 ✗ place.nc_path.push_back(placement);
451 ✗ if (placementComplement && placementComplement->function().outputSize() > 0)
452 ✗ place.nc_fol.push_back(placementComplement);
453
454 ✗ preplace.nc.push_back(preplacement);
455 ✗ preplace.nc_path.push_back(preplacement);
456 }
457
458 ✗ void relaxedPlacementManifold(const ImplicitPtr_t placement,
459 const ImplicitPtr_t preplacement,
460 const LockedJoints_t objectLocks,
461 FoliatedManifold& place,
462 FoliatedManifold& preplace) {
463 ✗ if (placement) {
464 ✗ place.nc.push_back(placement);
465 // The placement constraints are not required in the path, as long as
466 // they are satisfied at both ends and the object does not move. The
467 // former condition is ensured by the placement constraints on both
468 // ends and the latter is ensure by the LockedJoint constraints.
469 ✗ place.nc_path.push_back(placement);
470 }
471 ✗ std::copy(objectLocks.begin(), objectLocks.end(),
472 ✗ std::back_inserter(place.lj_fol));
473
474 ✗ if (placement && preplacement) {
475 ✗ preplace.nc.push_back(preplacement);
476 // preplace.nc_path.push_back (preplacement);
477 }
478 }
479
480 namespace {
481 typedef std::size_t index_t;
482 typedef std::vector<index_t> IndexV_t;
483 typedef std::list<index_t> IndexL_t;
484 typedef std::pair<index_t, index_t> Grasp_t;
485 typedef std::tuple<StatePtr_t, FoliatedManifold> StateAndManifold_t;
486 // typedef std::vector <index_t, index_t> GraspV_t;
487 /// GraspV_t corresponds to a unique ID of a permutation.
488 /// - its size is the number of grippers,
489 /// - the values correpond to the index of the handle (0..nbHandle-1), or
490 /// nbHandle to mean no handle.
491 typedef std::vector<index_t> GraspV_t;
492 struct Result;
493 struct CompiledRule {
494 enum Status { Accept, Refuse, NoMatch, Undefined };
495 std::vector<boost::regex> handles;
496 Status status;
497 CompiledRule(const Result& res, const Rule& r);
498 ✗ Status check(const std::vector<std::string>& names, const GraspV_t& g) const {
499 ✗ const std::size_t nG = g.size();
500 ✗ assert(nG == handles.size());
501 ✗ for (std::size_t i = 0; i < nG; ++i) {
502 ✗ if (handles[i].empty()) continue;
503 ✗ if (!boost::regex_match(names[g[i]], handles[i])) return NoMatch;
504 }
505 ✗ return status;
506 }
507 };
508 typedef std::vector<CompiledRule> CompiledRules_t;
509
510 struct Result {
511 ProblemSolverPtr_t ps;
512 GraphPtr_t graph;
513 typedef unsigned long stateid_type;
514 std::unordered_map<stateid_type, StateAndManifold_t> states;
515 typedef std::pair<stateid_type, stateid_type> edgeid_type;
516 struct edgeid_hash {
517 std::hash<edgeid_type::first_type> first;
518 std::hash<edgeid_type::second_type> second;
519 ✗ std::size_t operator()(const edgeid_type& eid) const {
520 ✗ return first(eid.first) + second(eid.second);
521 }
522 };
523 std::unordered_set<edgeid_type, edgeid_hash> edges;
524 std::vector<std::array<ImplicitPtr_t, 3> > graspCs;
525 index_t nG, nOH;
526 GraspV_t dims;
527 const Grippers_t& gs;
528 const Objects_t& ohs;
529 std::vector<std::string> handleNames;
530 CompiledRules_t rules;
531 CompiledRule::Status defaultAcceptationPolicy;
532
533 ✗ Result(const ProblemSolverPtr_t problem, const Grippers_t& grippers,
534 const Objects_t& objects, GraphPtr_t g)
535 ✗ : ps(problem),
536 ✗ graph(g),
537 ✗ nG(grippers.size()),
538 ✗ nOH(0),
539 ✗ gs(grippers),
540 ✗ ohs(objects),
541 ✗ defaultAcceptationPolicy(CompiledRule::Refuse) {
542 ✗ for (const Object_t& o : objects) {
543 ✗ nOH += std::get<1>(o).size();
544 ✗ for (const HandlePtr_t& h : std::get<1>(o))
545 ✗ handleNames.push_back(h->name());
546 }
547 ✗ handleNames.push_back("");
548 ✗ dims.resize(nG);
549 ✗ dims[0] = nOH + 1;
550 ✗ for (index_t i = 1; i < nG; ++i) dims[i] = dims[i - 1] * (nOH + 1);
551 ✗ graspCs.resize(nG * nOH);
552 }
553
554 ✗ void setRules(const Rules_t& r) {
555 ✗ for (Rules_t::const_iterator _r = r.begin(); _r != r.end(); ++_r)
556 ✗ rules.push_back(CompiledRule(*this, *_r));
557 }
558
559 ✗ bool graspIsAllowed(const GraspV_t& idxOH) const {
560 ✗ assert(idxOH.size() == nG);
561 ✗ for (std::size_t r = 0; r < rules.size(); ++r) {
562 ✗ switch (rules[r].check(handleNames, idxOH)) {
563 ✗ case CompiledRule::Accept:
564 ✗ return true;
565 ✗ case CompiledRule::Refuse:
566 ✗ return false;
567 ✗ case CompiledRule::NoMatch:
568 ✗ continue; // Check next rule
569 ✗ default:
570 ✗ throw std::invalid_argument("Rules are ill-defined.");
571 }
572 }
573 ✗ return (defaultAcceptationPolicy == CompiledRule::Accept);
574 }
575
576 ✗ inline stateid_type stateid(const GraspV_t& iG) {
577 ✗ stateid_type iGOH = iG[0];
578 stateid_type res;
579 ✗ for (index_t i = 1; i < nG; ++i) {
580 ✗ res = iGOH + dims[i] * (iG[i]);
581 if (res < iGOH) {
582 hppDout(info, "State ID overflowed. There are too many states...");
583 }
584 ✗ iGOH = res;
585 // iGOH += dims[i] * (iG[i]);
586 }
587 ✗ return iGOH;
588 }
589
590 bool hasState(const GraspV_t& iG) { return states.count(stateid(iG)) > 0; }
591
592 ✗ StateAndManifold_t& operator()(const GraspV_t& iG) {
593 ✗ return states[stateid(iG)];
594 }
595
596 ✗ bool hasEdge(const GraspV_t& g1, const GraspV_t& g2) {
597 ✗ return edges.count(edgeid_type(stateid(g1), stateid(g2))) > 0;
598 }
599
600 ✗ void addEdge(const GraspV_t& g1, const GraspV_t& g2) {
601 ✗ edges.insert(edgeid_type(stateid(g1), stateid(g2)));
602 }
603
604 ✗ inline std::array<ImplicitPtr_t, 3>& graspConstraint(const index_t& iG,
605 const index_t& iOH) {
606 ✗ std::array<ImplicitPtr_t, 3>& gcs = graspCs[iG * nOH + iOH];
607 ✗ if (!gcs[0]) {
608 hppDout(info,
609 "Create grasps constraints for (" << iG << ", " << iOH << ")");
610 ✗ const GripperPtr_t& g(gs[iG]);
611 ✗ const HandlePtr_t& h(handle(iOH));
612 ✗ const std::string& grasp = g->name() + " grasps " + h->name();
613 ✗ if (!ps->numericalConstraints.has(grasp)) {
614 ✗ ps->createGraspConstraint(grasp, g->name(), h->name());
615 }
616 ✗ gcs[0] = ps->numericalConstraints.get(grasp);
617 ✗ gcs[1] = ps->numericalConstraints.get(grasp + "/complement");
618 ✗ const std::string& pregrasp = g->name() + " pregrasps " + h->name();
619 ✗ if (!ps->numericalConstraints.has(pregrasp)) {
620 ✗ ps->createPreGraspConstraint(pregrasp, g->name(), h->name());
621 }
622 ✗ gcs[2] = ps->numericalConstraints.get(pregrasp);
623 }
624 ✗ return gcs;
625 }
626
627 ✗ const Object_t& object(const index_t& iOH) const {
628 ✗ index_t iH = iOH;
629 ✗ for (const Object_t& o : ohs) {
630 ✗ if (iH < std::get<1>(o).size()) return o;
631 ✗ iH -= std::get<1>(o).size();
632 }
633 ✗ throw std::out_of_range("Handle index");
634 }
635
636 ✗ const HandlePtr_t& handle(const index_t& iOH) const {
637 ✗ index_t iH = iOH;
638 ✗ for (const Object_t& o : ohs) {
639 ✗ if (iH < std::get<1>(o).size()) return std::get<1>(o)[iH];
640 ✗ iH -= std::get<1>(o).size();
641 }
642 ✗ throw std::out_of_range("Handle index");
643 }
644
645 /// Check if an object can be placed
646 ✗ bool objectCanBePlaced(const Object_t& o) const {
647 // If the object has no joint, then it cannot be placed.
648 ✗ return (std::get<2>(std::get<0>(o)).size() > 0);
649 }
650
651 /// Check is an object is grasped by the GraspV_t
652 ✗ bool isObjectGrasped(const GraspV_t& idxOH, const Object_t& o) const {
653 ✗ assert(idxOH.size() == nG);
654 ✗ for (std::size_t i = 0; i < idxOH.size(); ++i)
655 ✗ if (idxOH[i] < nOH) // This grippers grasps an object
656 ✗ if (std::get<2>(o) == std::get<2>(object(idxOH[i]))) return true;
657 ✗ return false;
658 }
659
660 /// Get a state name from a set of grasps
661 ✗ std::string name(const GraspV_t& idxOH, bool abbrev = false) const {
662 ✗ assert(idxOH.size() == nG);
663 ✗ std::stringstream ss;
664 ✗ bool first = true;
665 ✗ std::string sepGOH = (abbrev ? "-" : " grasps "),
666 ✗ sep = (abbrev ? ":" : " : ");
667 ✗ for (std::size_t i = 0; i < idxOH.size(); ++i) {
668 ✗ if (idxOH[i] < nOH) { // This grippers grasps an object
669 ✗ if (first)
670 ✗ first = false;
671 else
672 ✗ ss << sep;
673 ✗ if (abbrev)
674 ✗ ss << i << sepGOH << idxOH[i];
675 else
676 ✗ ss << gs[i]->name() << sepGOH << handle(idxOH[i])->name();
677 }
678 }
679 ✗ if (first) return (abbrev ? "f" : "free");
680 ✗ return ss.str();
681 }
682
683 /// Get an edge name from a set of grasps
684 ✗ std::pair<std::string, std::string> name(const GraspV_t& gFrom,
685 const GraspV_t& gTo,
686 const index_t iG) {
687 ✗ const std::string nf(name(gFrom, true)), nt(name(gTo, true));
688 ✗ std::stringstream ssForw, ssBack;
689 ✗ const char sep[] = " | ";
690 ✗ ssForw << gs[iG]->name() << " > " << handle(gTo[iG])->name() << sep << nf;
691 ✗ ssBack << gs[iG]->name() << " < " << handle(gTo[iG])->name() << sep << nt;
692 ✗ return std::make_pair(ssForw.str(), ssBack.str());
693 }
694
695 ✗ std::string nameLoopEdge(const GraspV_t& gFrom) {
696 ✗ const std::string nf(name(gFrom, true));
697 ✗ std::stringstream ss;
698 ✗ const char sep[] = " | ";
699 ✗ ss << "Loop" << sep << nf;
700 ✗ return ss.str();
701 }
702
703 ✗ void graspManifold(const index_t& iG, const index_t& iOH,
704 FoliatedManifold& grasp, FoliatedManifold& pregrasp) {
705 ✗ std::array<ImplicitPtr_t, 3>& gcs = graspConstraint(iG, iOH);
706 ✗ grasp.nc.push_back(gcs[0]);
707 ✗ grasp.nc_path.push_back(gcs[0]);
708 ✗ if (gcs[1]->function().outputSize() > 0) grasp.nc_fol.push_back(gcs[1]);
709
710 ✗ pregrasp.nc.push_back(gcs[2]);
711 ✗ pregrasp.nc_path.push_back(gcs[2]);
712 }
713 };
714
715 ✗ CompiledRule::CompiledRule(const Result& res, const Rule& r)
716 ✗ : handles(res.nG), status(r.link_ ? Accept : Refuse) {
717 ✗ assert(r.grippers_.size() == r.handles_.size());
718 ✗ for (std::size_t j = 0; j < r.grippers_.size(); ++j) {
719 ✗ boost::regex gripper(r.grippers_[j]);
720 ✗ for (std::size_t i = 0; i < res.nG; ++i) {
721 ✗ if (boost::regex_match(res.gs[i]->name(), gripper)) {
722 ✗ assert(handles[i].empty() &&
723 "Two gripper regex match the different gripper names.");
724 ✗ handles[i] = r.handles_[j];
725 }
726 }
727 }
728 }
729
730 ✗ const StateAndManifold_t& makeState(Result& r, const GraspV_t& g,
731 const int priority) {
732 ✗ StateAndManifold_t& nam = r(g);
733 ✗ if (!std::get<0>(nam)) {
734 hppDout(info, "Creating state " << r.name(g));
735 ✗ std::get<0>(nam) =
736 ✗ r.graph->stateSelector()->createState(r.name(g), false, priority);
737 // Loop over the grippers and create grasping constraints if required
738 ✗ FoliatedManifold unused;
739 ✗ std::set<index_t> idxsOH;
740 ✗ for (index_t i = 0; i < r.nG; ++i) {
741 ✗ if (g[i] < r.nOH) {
742 ✗ idxsOH.insert(g[i]);
743 ✗ r.graspManifold(i, g[i], std::get<1>(nam), unused);
744 }
745 }
746 ✗ index_t iOH = 0;
747 ✗ for (const Object_t& o : r.ohs) {
748 ✗ if (!r.objectCanBePlaced(o)) continue;
749 ✗ bool oIsGrasped = false;
750 // TODO: use the fact that the set is sorted.
751 // for (const HandlePtr_t& h : std::get<0>(o))
752 ✗ for (index_t i = 0; i < std::get<1>(o).size(); ++i) {
753 ✗ if (idxsOH.erase(iOH) == 1) oIsGrasped = true;
754 ✗ ++iOH;
755 }
756 ✗ if (!oIsGrasped) {
757 ✗ const auto& pc(std::get<0>(o));
758 ✗ relaxedPlacementManifold(std::get<0>(pc), std::get<1>(pc),
759 ✗ std::get<2>(pc), std::get<1>(nam), unused);
760 }
761 }
762 ✗ std::get<1>(nam).addToState(std::get<0>(nam));
763
764 ✗ createLoopEdge(r.nameLoopEdge(g), std::get<0>(nam), 0, false,
765 // TODO std::get<1>(nam).foliated(),
766 ✗ std::get<1>(nam));
767 }
768 ✗ return nam;
769 }
770
771 /// Arguments are such that
772 /// \li gTo[iG] != gFrom[iG]
773 /// \li for all i != iG, gTo[iG] == gFrom[iG]
774 ✗ void makeEdge(Result& r, const GraspV_t& gFrom, const GraspV_t& gTo,
775 const index_t iG, const int priority) {
776 ✗ if (r.hasEdge(gFrom, gTo)) {
777 hppDout(warning, "Prevented creation of duplicated edge\nfrom "
778 << r.name(gFrom) << "\nto " << r.name(gTo));
779 ✗ return;
780 }
781 ✗ const StateAndManifold_t &from = makeState(r, gFrom, priority),
782 ✗ to = makeState(r, gTo, priority + 1);
783 ✗ const Object_t& o = r.object(gTo[iG]);
784
785 // Detect when grasping an object already grasped.
786 // or when there is no placement information for it.
787 ✗ bool noPlace = !r.objectCanBePlaced(o) || r.isObjectGrasped(gFrom, o);
788
789 ✗ FoliatedManifold grasp, pregrasp, place, preplace, submanifold;
790 ✗ r.graspManifold(iG, gTo[iG], grasp, pregrasp);
791 ✗ if (!noPlace) {
792 ✗ const auto& pc(std::get<0>(o));
793 ✗ relaxedPlacementManifold(std::get<0>(pc), std::get<1>(pc), std::get<2>(pc),
794 place, preplace);
795 }
796 ✗ std::pair<std::string, std::string> names = r.name(gFrom, gTo, iG);
797 {
798 ✗ FoliatedManifold unused;
799 ✗ std::set<index_t> idxsOH;
800 ✗ for (index_t i = 0; i < r.nG; ++i) {
801 ✗ if (gFrom[i] < r.nOH) {
802 ✗ idxsOH.insert(gFrom[i]);
803 ✗ r.graspManifold(i, gFrom[i], submanifold, unused);
804 }
805 }
806 ✗ index_t iOH = 0;
807 ✗ for (const Object_t& o : r.ohs) {
808 ✗ if (!r.objectCanBePlaced(o)) continue;
809 ✗ bool oIsGrasped = false;
810 ✗ const index_t iOHstart = iOH;
811 ✗ for (; iOH < iOHstart + std::get<1>(o).size(); ++iOH) {
812 ✗ if (iOH == gTo[iG]) {
813 ✗ oIsGrasped = true;
814 ✗ iOH = iOHstart + std::get<1>(o).size();
815 ✗ break;
816 }
817 ✗ if (idxsOH.erase(iOH) == 1) oIsGrasped = true;
818 }
819 ✗ if (!oIsGrasped) {
820 ✗ const auto& pc(std::get<0>(o));
821 ✗ relaxedPlacementManifold(std::get<0>(pc), std::get<1>(pc),
822 ✗ std::get<2>(pc), submanifold, unused);
823 }
824 }
825 }
826 ✗ if (pregrasp.empty()) {
827 ✗ if (noPlace)
828 ✗ createEdges<GraspOnly | NoPlace>(
829 ✗ names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1,
830 ✗ grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(),
831 submanifold);
832 ✗ else if (preplace.empty())
833 ✗ createEdges<GraspOnly | PlaceOnly>(
834 ✗ names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1,
835 ✗ grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(),
836 submanifold);
837 else {
838 hppDout(error, "GraspOnly | WithPrePlace not implemeted yet");
839 /*
840 createEdges <GraspOnly | WithPrePlace> (
841 names.first , names.second,
842 std::get<0>(from) , std::get<0>(to),
843 1 , 1,
844 grasp , pregrasp,
845 place , preplace,
846 grasp.foliated () , place.foliated(),
847 submanifold); // */
848 }
849 } else {
850 ✗ if (noPlace)
851 ✗ createEdges<WithPreGrasp | NoPlace>(
852 ✗ names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1,
853 ✗ grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(),
854 submanifold);
855 ✗ else if (preplace.empty())
856 ✗ createEdges<WithPreGrasp | PlaceOnly>(
857 ✗ names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1,
858 ✗ grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(),
859 submanifold);
860 else
861 ✗ createEdges<WithPreGrasp | WithPrePlace>(
862 ✗ names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1,
863 ✗ grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(),
864 submanifold);
865 }
866 ✗ r.addEdge(gFrom, gTo);
867 }
868
869 /// idx are the available grippers
870 ✗ void recurseGrippers(Result& r, const IndexV_t& idx_g, const IndexV_t& idx_oh,
871 const GraspV_t& grasps, const int depth) {
872 ✗ bool curGraspIsAllowed = r.graspIsAllowed(grasps);
873 ✗ if (curGraspIsAllowed) makeState(r, grasps, depth);
874
875 ✗ if (idx_g.empty() || idx_oh.empty()) return;
876 ✗ IndexV_t nIdx_g(idx_g.size() - 1);
877 ✗ IndexV_t nIdx_oh(idx_oh.size() - 1);
878 ✗ for (IndexV_t::const_iterator itx_g = idx_g.begin(); itx_g != idx_g.end();
879 ✗ ++itx_g) {
880 // Copy all element except itx_g
881 ✗ std::copy(std::next(itx_g), idx_g.end(),
882 std::copy(idx_g.begin(), itx_g, nIdx_g.begin()));
883 ✗ for (IndexV_t::const_iterator itx_oh = idx_oh.begin();
884 ✗ itx_oh != idx_oh.end(); ++itx_oh) {
885 // Create the edge for the selected grasp
886 ✗ GraspV_t nGrasps = grasps;
887 ✗ nGrasps[*itx_g] = *itx_oh;
888
889 ✗ bool nextGraspIsAllowed = r.graspIsAllowed(nGrasps);
890 ✗ if (nextGraspIsAllowed) makeState(r, nGrasps, depth + 1);
891
892 ✗ if (curGraspIsAllowed && nextGraspIsAllowed)
893 ✗ makeEdge(r, grasps, nGrasps, *itx_g, depth);
894
895 // Copy all element except itx_oh
896 ✗ std::copy(std::next(itx_oh), idx_oh.end(),
897 std::copy(idx_oh.begin(), itx_oh, nIdx_oh.begin()));
898 // Do all the possible combination below this new grasp
899 ✗ recurseGrippers(r, nIdx_g, nIdx_oh, nGrasps, depth + 2);
900 }
901 }
902 }
903 } // namespace
904
905 ✗ void graphBuilder(const ProblemSolverPtr_t& ps, const Objects_t& objects,
906 const Grippers_t& grippers, GraphPtr_t graph,
907 const Rules_t& rules) {
908 ✗ if (!graph) throw std::logic_error("The graph must be initialized");
909 ✗ StateSelectorPtr_t ns = graph->stateSelector();
910 ✗ if (!ns) throw std::logic_error("The graph does not have a StateSelector");
911
912 ✗ Result r(ps, grippers, objects, graph);
913 ✗ r.setRules(rules);
914
915 ✗ IndexV_t availG(r.nG), availOH(r.nOH);
916 ✗ for (index_t i = 0; i < r.nG; ++i) availG[i] = i;
917 ✗ for (index_t i = 0; i < r.nOH; ++i) availOH[i] = i;
918
919 ✗ GraspV_t iG(r.nG, r.nOH);
920
921 ✗ recurseGrippers(r, availG, availOH, iG, 0);
922
923 hppDout(info, "Created a graph with " << r.states.size()
924 << " states "
925 "and "
926 << r.edges.size() << " edges.");
927 }
928
929 ✗ GraphPtr_t graphBuilder(const ProblemSolverPtr_t& ps,
930 const std::string& graphName, const Strings_t& griNames,
931 const std::vector<ObjectDef_t>& objs,
932 const Strings_t& envNames,
933 const std::vector<Rule>& rules,
934 const value_type& prePlaceWidth) {
935 ✗ if (ps->graphs.has(graphName))
936 ✗ throw std::invalid_argument("A graph named " + graphName +
937 ✗ " already exists.");
938
939 ✗ const Device& robot = *(ps->robot());
940 ✗ const pinocchio::Model& model = robot.model();
941 ✗ Grippers_t grippers(griNames.size());
942 ✗ index_t i = 0;
943 ✗ for (const std::string& gn : griNames) {
944 ✗ grippers[i] = robot.grippers.get(gn);
945 ✗ ++i;
946 }
947 ✗ Objects_t objects(objs.size());
948 ✗ i = 0;
949 ✗ const value_type margin = 1e-3;
950 ✗ bool prePlace = (prePlaceWidth > 0);
951 ✗ for (const ObjectDef_t& od : objs) {
952 // Create handles
953 ✗ std::get<2>(objects[i]) = i;
954 ✗ std::get<1>(objects[i]).resize(od.handles.size());
955 ✗ Handles_t::iterator it = std::get<1>(objects[i]).begin();
956 ✗ for (const std::string& hn : od.handles) {
957 ✗ *it = robot.handles.get(hn);
958 ✗ ++it;
959 }
960 // Create placement
961 ✗ const std::string placeN = "place_" + od.name;
962 ✗ const std::string preplaceN = "pre" + placeN;
963 // If user provides constraint "place_objectName",
964 // then
965 // use this as placement and use "preplace_objectName" for
966 // pre-placement if defined.
967 // else if contact surfaces are defined and selected
968 // create default placement constraint using the ProblemSolver
969 // methods createPlacementConstraint and createPrePlacementConstraint
970 ✗ auto& pc(std::get<0>(objects[i]));
971 ✗ if (ps->numericalConstraints.has(placeN)) {
972 ✗ std::get<0>(pc) = ps->numericalConstraints.get(placeN);
973 ✗ if (ps->numericalConstraints.has(preplaceN)) {
974 ✗ std::get<1>(pc) = ps->numericalConstraints.get(preplaceN);
975 }
976 ✗ } else if (!envNames.empty() && !od.shapes.empty()) {
977 ✗ ps->createPlacementConstraint(placeN, od.shapes, envNames, margin);
978 ✗ std::get<0>(pc) = ps->numericalConstraints.get(placeN);
979 ✗ if (prePlace) {
980 ✗ ps->createPrePlacementConstraint(preplaceN, od.shapes, envNames, margin,
981 prePlaceWidth);
982 ✗ std::get<1>(pc) = ps->numericalConstraints.get(preplaceN);
983 }
984 }
985 // Create object lock
986 // Loop over all frames of object, detect joint and create locked
987 // joint.
988 ✗ assert(robot.robotFrames(od.name).size() != 0);
989 ✗ for (const FrameIndex& f : robot.robotFrames(od.name)) {
990 ✗ if (model.frames[f].type != ::pinocchio::JOINT) continue;
991 ✗ const JointIndex j = model.frames[f].parent;
992 ✗ JointPtr_t oj(Joint::create(ps->robot(), j));
993 ✗ LiegroupSpacePtr_t space(oj->configurationSpace());
994 ✗ LiegroupElement lge(robot.currentConfiguration().segment(
995 oj->rankInConfiguration(), oj->configSize()),
996 ✗ space);
997 ✗ LockedJointPtr_t lj = core::LockedJoint::create(oj, lge);
998 ✗ ps->numericalConstraints.add("lock_" + oj->name(), lj);
999 ✗ std::get<2>(pc).push_back(lj);
1000 }
1001 ✗ ++i;
1002 }
1003 ✗ GraphPtr_t graph = Graph::create(graphName, ps->robot(), ps->problem());
1004 ✗ ps->graphs.add(graphName, graph);
1005 ✗ ps->constraintGraph(graphName);
1006 ✗ graph->stateSelector(
1007 ✗ GuidedStateSelector::create("stateSelector", ps->roadmap()));
1008 ✗ graph->maxIterations(ps->maxIterProjection());
1009 ✗ graph->errorThreshold(ps->errorThreshold());
1010
1011 ✗ graphBuilder(ps, objects, grippers, graph, rules);
1012 ✗ return graph;
1013 }
1014 } // namespace helper
1015 } // namespace graph
1016 } // namespace manipulation
1017 } // namespace hpp
1018