GCC Code Coverage Report


Directory: ./
File: src/graph/helper.cc
Date: 2025-03-07 11:10:46
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