Skip to content
Snippets Groups Projects
helper.cc 46.7 KiB
Newer Older
Joseph Mirabel's avatar
Joseph Mirabel committed
// Copyright (c) 2016, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-manipulation.
// hpp-manipulation is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-manipulation is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-manipulation. If not, see <http://www.gnu.org/licenses/>.

#include <hpp/manipulation/graph/helper.hh>

#include <tr1/unordered_map>
#include <tr1/unordered_set>

#include <boost/array.hpp>
#include <boost/regex.hpp>
Joseph Mirabel's avatar
Joseph Mirabel committed
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
#include <pinocchio/multibody/model.hpp>

Joseph Mirabel's avatar
Joseph Mirabel committed
#include <hpp/util/debug.hh>

#include <hpp/pinocchio/gripper.hh>
#include <pinocchio/multibody/model.hpp>
Joseph Mirabel's avatar
Joseph Mirabel committed

#include <hpp/constraints/differentiable-function.hh>
#include <hpp/constraints/locked-joint.hh>
Joseph Mirabel's avatar
Joseph Mirabel committed

#include <hpp/manipulation/handle.hh>
#include <hpp/manipulation/graph/state.hh>
Joseph Mirabel's avatar
Joseph Mirabel committed
#include <hpp/manipulation/graph/edge.hh>
#include <hpp/manipulation/graph/state-selector.hh>
#include <hpp/manipulation/graph/guided-state-selector.hh>
#include <hpp/manipulation/problem-solver.hh>
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
#define CASE_TO_STRING(var, value) ( (var & value) ? std::string(#value) : std::string() )

Joseph Mirabel's avatar
Joseph Mirabel committed
namespace hpp {
  namespace manipulation {
    namespace graph {
Joseph Mirabel's avatar
Joseph Mirabel committed
      namespace helper {
        typedef constraints::Implicit Implicit;
        typedef constraints::ImplicitPtr_t ImplicitPtr_t;
Joseph Mirabel's avatar
Joseph Mirabel committed
        template <bool forPath>
          void NumericalConstraintsAndPassiveDofs::addToComp
          (GraphComponentPtr_t comp) const
        {
          if (nc.empty ()) return;
          StatePtr_t n;
Joseph Mirabel's avatar
Joseph Mirabel committed
          if (forPath) {
            n = HPP_DYNAMIC_PTR_CAST (State, comp);
            if (!n) throw std::logic_error ("Wrong type: expect a State");
Joseph Mirabel's avatar
Joseph Mirabel committed
          }
          NumericalConstraints_t::const_iterator it;
          IntervalsContainer_t::const_iterator itpdof = pdof.begin ();
          for (it = nc.begin (); it != nc.end (); ++it) {
            if (*it) {
              if (forPath) n->addNumericalConstraintForPath (*it, *itpdof);
              else      comp->addNumericalConstraint (*it, *itpdof);
            }
Joseph Mirabel's avatar
Joseph Mirabel committed
            ++itpdof;
          }
          assert (itpdof == pdof.end ());
Joseph Mirabel's avatar
Joseph Mirabel committed
        }
Joseph Mirabel's avatar
Joseph Mirabel committed

        template <bool param>
          void NumericalConstraintsAndPassiveDofs::specifyFoliation
          (LevelSetEdgePtr_t lse) const
        {
          NumericalConstraints_t::const_iterator it;
          IntervalsContainer_t::const_iterator itpdof = pdof.begin ();
          for (it = nc.begin (); it != nc.end (); ++it) {
            if (*it) {
              if (param) lse->insertParamConstraint (*it, *itpdof);
              else   lse->insertConditionConstraint (*it, *itpdof);
            }
Joseph Mirabel's avatar
Joseph Mirabel committed
            ++itpdof;
          }
          assert (itpdof == pdof.end ());
        }

        void FoliatedManifold::addToState (StatePtr_t comp) const
Joseph Mirabel's avatar
Joseph Mirabel committed
        {
          nc.addToComp <false> (comp);
          nc_path.addToComp <true> (comp);
        }

        void FoliatedManifold::addToEdge (EdgePtr_t comp) const
        {
          nc_fol.addToComp <false> (comp);
Joseph Mirabel's avatar
Joseph Mirabel committed
        }
Joseph Mirabel's avatar
Joseph Mirabel committed

        void FoliatedManifold::specifyFoliation (LevelSetEdgePtr_t lse) const
        {
          nc.specifyFoliation <false> (lse);
          nc_fol.specifyFoliation <true> (lse);
Joseph Mirabel's avatar
Joseph Mirabel committed
        }
Joseph Mirabel's avatar
Joseph Mirabel committed

        namespace {
Joseph Mirabel's avatar
Joseph Mirabel committed
          template <int gCase>
            struct CaseTraits {
              static const bool pregrasp = (gCase & WithPreGrasp);
              static const bool preplace = (gCase & WithPrePlace);
              static const bool intersec = !((gCase & NoGrasp) || (gCase & NoPlace));
              static const bool valid =
                   ( (gCase & WithPreGrasp) || (gCase & GraspOnly) || (gCase & NoGrasp) )
                && ( (gCase & WithPrePlace) || (gCase & PlaceOnly) || (gCase & NoPlace) )
                && !((gCase & NoGrasp) && (gCase & NoPlace));
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
              static const std::size_t nbWaypoints = (pregrasp?1:0) + (intersec?1:0) + (preplace?1:0);
              static const std::size_t Nstates = 2 + nbWaypoints;
Joseph Mirabel's avatar
Joseph Mirabel committed
              static const std::size_t Nedges = 1 + nbWaypoints;
              // static const std::size_t iNpregrasp = pregrasp?1 + 1:nbWaypoints;
              // static const std::size_t iNpreplace = pregrasp?1 + 1:nbWaypoints;
              typedef boost::array <StatePtr_t, Nstates> StateArray;
Joseph Mirabel's avatar
Joseph Mirabel committed
              typedef boost::array <EdgePtr_t, Nedges> EdgeArray;

              static inline const StatePtr_t& Npregrasp (const StateArray& n) { assert (pregrasp); return n[1]; }
              static inline const StatePtr_t& Nintersec (const StateArray& n) { assert (intersec); return n[1 + (pregrasp?1:0)]; }
              static inline const StatePtr_t& Npreplace (const StateArray& n) { assert (preplace); return n[1 + (pregrasp?1:0) + (intersec?1:0)]; }
Joseph Mirabel's avatar
Joseph Mirabel committed
              static inline std::string caseToString ()
              {
                return CASE_TO_STRING (gCase, NoGrasp)
                  +    CASE_TO_STRING (gCase, GraspOnly)
                  +    CASE_TO_STRING (gCase, WithPreGrasp)
                  + " - "
                  +    CASE_TO_STRING (gCase, NoPlace)
                  +    CASE_TO_STRING (gCase, PlaceOnly)
                  +    CASE_TO_STRING (gCase, WithPrePlace);
              }

Joseph Mirabel's avatar
Joseph Mirabel committed
              static inline EdgePtr_t makeWE (
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const std::string& name,
                  const StatePtr_t& from, const StatePtr_t& to,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const size_type& w)
              {
Joseph Mirabel's avatar
Joseph Mirabel committed
                if (Nedges > 1) {
                  WaypointEdgePtr_t we = boost::static_pointer_cast <WaypointEdge>
                      (from->linkTo (name, to, w, WaypointEdge::create));
                  we->nbWaypoints (nbWaypoints);
                  return we;
                } else return from->linkTo (name, to, w, Edge::create);
              static inline StateArray makeWaypoints (
                  const StatePtr_t& from, const StatePtr_t& to,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const std::string& name)
              {
                StateSelectorPtr_t ns = from->parentGraph ()->stateSelector ();
                StateArray states;
Joseph Mirabel's avatar
Joseph Mirabel committed
                std::size_t r = 0;
                states[r] = from; ++r;
Joseph Mirabel's avatar
Joseph Mirabel committed
                if (pregrasp) {
                  states[r] = ns->createState (name + "_pregrasp", true); ++r;
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                if (intersec) {
                  states[r] = ns->createState (name + "_intersec", true); ++r;
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                if (preplace) {
                  states[r] = ns->createState (name + "_preplace", true); ++r;
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                states[r] = to;
                return states;
Joseph Mirabel's avatar
Joseph Mirabel committed
              static inline EdgePtr_t makeLSEgrasp (const std::string& name,
                  const StateArray& n, const EdgeArray& e,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const size_type w, LevelSetEdgePtr_t& gls)
              {
                if (Nedges > 1) {
                  const std::size_t T = (pregrasp?1:0) + (intersec?1:0);
                  WaypointEdgePtr_t we = boost::static_pointer_cast <WaypointEdge>
                    (n.front()->linkTo (name + "_ls", n.back(), w,
                                        WaypointEdge::create));
                  we->nbWaypoints (nbWaypoints);
                  gls = linkWaypoint <LevelSetEdge> (n, T-1, T, name, "ls");
                  for (std::size_t i = 0; i < Nedges; ++i)
                    we->setWaypoint (i, e[i], n[i+1]);
Joseph Mirabel's avatar
Joseph Mirabel committed
                  we->setWaypoint (T-1, gls, n[T]);
                  gls->state (n.front());
                  gls->setShort (pregrasp);
Joseph Mirabel's avatar
Joseph Mirabel committed
                  return we;
                } else {
                  assert (gCase == (GraspOnly | NoPlace)
                      && "Cannot implement a LevelSetEdge for grasping");
                  gls = boost::static_pointer_cast <LevelSetEdge>
                    (n.front()->linkTo (name + "_ls", n.back(), w,
                                        LevelSetEdge::create));
                  return gls;
                }
              }

              static inline EdgePtr_t makeLSEplace (const std::string& name,
                  const StateArray& n, const EdgeArray& e,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const size_type w, LevelSetEdgePtr_t& pls)
              {
                if (Nedges > 1) {
                  const std::size_t T = (pregrasp?1:0) + (intersec?1:0);
                  WaypointEdgePtr_t we = boost::static_pointer_cast <WaypointEdge>
                    (n.back()->linkTo (name + "_ls", n.front(), w,
                                       WaypointEdge::create));
                  we->nbWaypoints (nbWaypoints);
                  pls = linkWaypoint <LevelSetEdge> (n, T+1, T, name, "ls");
                  // for (std::size_t i = Nedges - 1; i != 0; --i)
                  for (std::size_t k = 0; k < Nedges; ++k) {
                    std::size_t i = Nedges  - 1 - k;
Joseph Mirabel's avatar
Joseph Mirabel committed
                    we->setWaypoint (Nedges - 1 - i, e[i], n[i]);
Joseph Mirabel's avatar
Joseph Mirabel committed
                  we->setWaypoint (Nedges - 1 - T, pls, n[T]);
                  pls->state (n.back ());
Joseph Mirabel's avatar
Joseph Mirabel committed
                  pls->setShort (preplace);
                  return we;
                } else {
                  assert (gCase == (NoGrasp | PlaceOnly)
                      && "Cannot implement a LevelSetEdge for placement");
Joseph Mirabel's avatar
Joseph Mirabel committed
                  pls = boost::static_pointer_cast <LevelSetEdge>
                    (n.back()->linkTo (name + "_ls", n.front(), w,
                                       LevelSetEdge::create));
                  return pls;
                }
              }

Joseph Mirabel's avatar
Joseph Mirabel committed
              template <typename EdgeType>
              static inline boost::shared_ptr<EdgeType> linkWaypoint (
                  const StateArray& states,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const std::size_t& iF, const std::size_t& iT,
                  const std::string& prefix,
                  const std::string& suffix = "")
              {
                std::stringstream ss;
                ss << prefix << "_" << iF << iT;
                if (suffix.length () > 0) ss << "_" << suffix;
                return boost::static_pointer_cast <EdgeType>
                    (states[iF]->linkTo (ss.str(), states[iT], -1, EdgeType::create));
Joseph Mirabel's avatar
Joseph Mirabel committed
              }
Joseph Mirabel's avatar
Joseph Mirabel committed

              template <bool forward>
              static inline EdgeArray linkWaypoints (
                  const StateArray& states, const EdgePtr_t& edge,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const std::string& name)
              {
                EdgeArray e;
Joseph Mirabel's avatar
Joseph Mirabel committed
                WaypointEdgePtr_t we = HPP_DYNAMIC_PTR_CAST(WaypointEdge, edge);
Joseph Mirabel's avatar
Joseph Mirabel committed
                if (forward)
                  for (std::size_t i = 0; i < Nedges; ++i) {
                    e[i] = linkWaypoint <Edge> (states, i, i + 1, name);
                    we->setWaypoint (i, e[i], states[i+1]);
Joseph Mirabel's avatar
Joseph Mirabel committed
                  }
                else
                  // for (std::size_t i = Nedges - 1; i != 0; --i) {
                  for (std::size_t k = 0; k < Nedges; ++k) {
                    std::size_t i = Nedges  - 1 - k;
                    e[i] = linkWaypoint <Edge> (states, i + 1, i, name);
                    we->setWaypoint (Nedges - 1 - i, e[i], states[i]);
Joseph Mirabel's avatar
Joseph Mirabel committed
                  }
                return e;
              }

              static inline void setStateConstraints (const StateArray& n,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const FoliatedManifold& g, const FoliatedManifold& pg,
                  const FoliatedManifold& p, const FoliatedManifold& pp,
                  const FoliatedManifold& m)
Joseph Mirabel's avatar
Joseph Mirabel committed
              {
                // From and to are not populated automatically
                // to avoid duplicates.
                if (pregrasp) {
                  p .addToState (Npregrasp (n));
                  pg.addToState (Npregrasp (n));
                  m .addToState (Npregrasp (n));
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                if (intersec) {
                  p .addToState (Nintersec (n));
                  g .addToState (Nintersec (n));
                  m .addToState (Nintersec (n));
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                if (preplace) {
                  pp.addToState (Npreplace (n));
                  g .addToState (Npreplace (n));
                  m .addToState (Npreplace (n));
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
              }

              static inline void setEdgeConstraints (const EdgeArray& e,
                  const FoliatedManifold& g, const FoliatedManifold& p,
                  const FoliatedManifold& m)
              {
                // The border B
                const std::size_t B = (pregrasp?1:0) + (intersec?1:0);
                for (std::size_t i = 0; i < B     ; ++i) p.addToEdge (e[i]);
                for (std::size_t i = B; i < Nedges; ++i) g.addToEdge (e[i]);
                for (std::size_t i = 0; i < Nedges; ++i) m.addToEdge (e[i]);
              }

              template <bool forward>
              static inline void setEdgeProp
              (const EdgeArray& e, const StateArray& n)
Joseph Mirabel's avatar
Joseph Mirabel committed
              {
                /// Last is short
                const std::size_t K = (forward?1:0);
                for (std::size_t i = K; i < Nedges - 1 + K; ++i)
                  e[i]->setShort (true);
                // The border B
                std::size_t B;
                if ((gCase & NoGrasp)) // There is no grasp
                  B = 0;
                else // There is a grasp
                  B = 1 + (pregrasp?1:0);
                for (std::size_t i = 0; i < B     ; ++i) e[i]->state (n[0]);
                for (std::size_t i = B; i < Nedges; ++i) e[i]->state (n[Nstates-1]);
Joseph Mirabel's avatar
Joseph Mirabel committed
        template <int gCase> Edges_t createEdges (
Joseph Mirabel's avatar
Joseph Mirabel committed
              const std::string& forwName,   const std::string& backName,
              const StatePtr_t& from,         const StatePtr_t& to,
Joseph Mirabel's avatar
Joseph Mirabel committed
              const size_type& wForw,        const size_type& wBack,
              const FoliatedManifold& grasp, const FoliatedManifold& pregrasp,
              const FoliatedManifold& place, const FoliatedManifold& preplace,
              const bool levelSetGrasp,      const bool levelSetPlace,
              const FoliatedManifold& submanifoldDef)
          {
Joseph Mirabel's avatar
Joseph Mirabel committed
            typedef CaseTraits<gCase> T;
Joseph Mirabel's avatar
Joseph Mirabel committed
            hppDout (info, "Creating edges " << forwName << " and " << backName
               << "\ncase is " << T::caseToString ());
Joseph Mirabel's avatar
Joseph Mirabel committed
            assert (T::valid && "Not a valid case.");
            typedef typename T::StateArray StateArray;
Joseph Mirabel's avatar
Joseph Mirabel committed
            typedef typename T::EdgeArray EdgeArray;
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
            // Create the edges
            EdgePtr_t weForw = T::makeWE (forwName, from, to, wForw),
                      weBack = T::makeWE (backName, to, from, wBack),
                      weForwLs, weBackLs;
Joseph Mirabel's avatar
Joseph Mirabel committed

            std::string name = forwName;
            StateArray n = T::makeWaypoints (from, to, name);
Joseph Mirabel's avatar
Joseph Mirabel committed
            EdgeArray eF = T::template linkWaypoints <true> (n, weForw, name);
            // Set the states constraints
            // Note that submanifold is not taken into account for states
Joseph Mirabel's avatar
Joseph Mirabel committed
            // because the edges constraints will enforce configuration to stay
            // in a leaf, and so in the manifold itself.
            T::setStateConstraints (n, grasp, pregrasp, place, preplace,
Joseph Mirabel's avatar
Joseph Mirabel committed

            // Set the edges properties
Joseph Mirabel's avatar
Joseph Mirabel committed
            T::template setEdgeProp <true> (eF, n);
Joseph Mirabel's avatar
Joseph Mirabel committed

            // Set the edges constraints
Joseph Mirabel's avatar
Joseph Mirabel committed
            T::setEdgeConstraints (eF, grasp, place, submanifoldDef);
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
            LevelSetEdgePtr_t gls;
            if (levelSetGrasp)
              weForwLs = T::makeLSEgrasp (name, n, eF, 10*wForw, gls);

Joseph Mirabel's avatar
Joseph Mirabel committed
            // Populate bacward edge
Joseph Mirabel's avatar
Joseph Mirabel committed
            EdgeArray eB = T::template linkWaypoints <false> (n, weBack, name);
Joseph Mirabel's avatar
Joseph Mirabel committed
            T::template setEdgeProp <false> (eB, n);
Joseph Mirabel's avatar
Joseph Mirabel committed

            T::setEdgeConstraints (eB, grasp, place, submanifoldDef);
Joseph Mirabel's avatar
Joseph Mirabel committed
            LevelSetEdgePtr_t pls;
            if (levelSetPlace)
              weBackLs = T::makeLSEplace (name, n, eB, 10*wBack, pls);

            Edges_t ret = boost::assign::list_of (weForw)(weBack);
Joseph Mirabel's avatar
Joseph Mirabel committed

            if (levelSetPlace) {
Joseph Mirabel's avatar
Joseph Mirabel committed
              if (!place.foliated ()) {
Joseph Mirabel's avatar
Joseph Mirabel committed
                hppDout (warning, "You asked for a LevelSetEdge for placement, "
                    "but did not specify the target foliation. "
                    "It will have no effect");
              }
Joseph Mirabel's avatar
Joseph Mirabel committed
              grasp.addToEdge (pls);
              place.specifyFoliation (pls);
              submanifoldDef.addToEdge (pls);
              pls->buildHistogram ();
              place.addToEdge (weBackLs);
              submanifoldDef.addToEdge (weBackLs);
              ret.push_back (weBackLs);
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
            if (levelSetGrasp) {
Joseph Mirabel's avatar
Joseph Mirabel committed
              if (!grasp.foliated ()) {
Joseph Mirabel's avatar
Joseph Mirabel committed
                hppDout (warning, "You asked for a LevelSetEdge for grasping, "
                    "but did not specify the target foliation. "
                    "It will have no effect");
              }
Joseph Mirabel's avatar
Joseph Mirabel committed
              place.addToEdge (gls);
              grasp.specifyFoliation (gls);
              submanifoldDef.addToEdge (gls);
              gls->buildHistogram ();
              grasp.addToEdge (weForwLs);
              submanifoldDef.addToEdge (weForwLs);
              ret.push_back (weForwLs);
            return ret;
        EdgePtr_t createLoopEdge (
              const std::string& loopName,
              const StatePtr_t& state,
              const size_type& w,
              const bool levelSet,
              const FoliatedManifold& submanifoldDef)
        {
          // Create the edges
          EdgePtr_t loop;
          if (levelSet)
               loop = state->linkTo (loopName, state, w, LevelSetEdge::create);
          else loop = state->linkTo (loopName, state, w, Edge::create);
          loop->state (state);
          submanifoldDef.addToEdge (loop);

          if (levelSet) {
            if (!submanifoldDef.foliated ()) {
              hppDout (warning, "You asked for a LevelSetEdge for looping, "
                  "but did not specify the target foliation. "
                  "It will have no effect");
            }
            LevelSetEdgePtr_t ls = HPP_DYNAMIC_PTR_CAST (LevelSetEdge, loop);
            submanifoldDef.specifyFoliation (ls);
            ls->buildHistogram ();
          }

          return loop;
        }

Joseph Mirabel's avatar
Joseph Mirabel committed
        void graspManifold (
            const GripperPtr_t& gripper, const HandlePtr_t& handle,
            FoliatedManifold& grasp, FoliatedManifold& pregrasp)
        {
          ImplicitPtr_t gc  = handle->createGrasp (gripper, "");
Joseph Mirabel's avatar
Joseph Mirabel committed
          grasp.nc.nc.push_back (gc);
          grasp.nc.pdof.push_back (segments_t ());
Joseph Mirabel's avatar
Joseph Mirabel committed
          grasp.nc_path.nc.push_back (gc);
          // TODO: see function declaration
          grasp.nc_path.pdof.push_back (segments_t ());
          ImplicitPtr_t gcc = handle->createGraspComplement
Joseph Mirabel's avatar
Joseph Mirabel committed
          if (gcc->function ().outputSize () > 0) {
            grasp.nc_fol.nc.push_back (gcc);
            grasp.nc_fol.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
          }

          const value_type c = handle->clearance () + gripper->clearance ();
          ImplicitPtr_t pgc = handle->createPreGrasp (gripper, c, "");
Joseph Mirabel's avatar
Joseph Mirabel committed
          pregrasp.nc.nc.push_back (pgc);
          pregrasp.nc.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
          pregrasp.nc_path.nc.push_back (pgc);
          pregrasp.nc_path.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
        }

        void strictPlacementManifold (
            const ImplicitPtr_t placement,
            const ImplicitPtr_t preplacement,
            const ImplicitPtr_t placementComplement,
Joseph Mirabel's avatar
Joseph Mirabel committed
            FoliatedManifold& place, FoliatedManifold& preplace)
        {
          place.nc.nc.push_back (placement);
          place.nc.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
          place.nc_path.nc.push_back (placement);
          place.nc_path.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
          if (placementComplement && placementComplement->function().outputSize () > 0) {
            place.nc_fol.nc.push_back (placementComplement);
            place.nc_fol.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
          }

          preplace.nc.nc.push_back (preplacement);
          preplace.nc.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
          preplace.nc_path.nc.push_back (preplacement);
          preplace.nc_path.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
        }

        void relaxedPlacementManifold (
            const ImplicitPtr_t placement,
            const ImplicitPtr_t preplacement,
Joseph Mirabel's avatar
Joseph Mirabel committed
            const LockedJoints_t objectLocks,
            FoliatedManifold& place, FoliatedManifold& preplace)
        {
          if (placement) {
            place.nc.nc.push_back (placement);
            place.nc.pdof.push_back (segments_t());
            // The placement constraints are not required in the path, as long as
            // they are satisfied at both ends and the object does not move. The
            // former condition is ensured by the placement constraints on both
            // ends and the latter is ensure by the LockedJoint constraints.
            place.nc_path.nc.push_back (placement);
            place.nc_path.pdof.push_back (segments_t());
          std::copy (objectLocks.begin(), objectLocks.end(), std::back_inserter(place.lj_fol));
Joseph Mirabel's avatar
Joseph Mirabel committed

          if (placement && preplacement) {
            preplace.nc.nc.push_back (preplacement);
            preplace.nc.pdof.push_back (segments_t());
            // preplace.nc_path.nc.push_back (preplacement);
            // preplace.nc_path.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
        namespace {
          typedef std::size_t index_t;
          typedef std::vector <index_t> IndexV_t;
          typedef std::list <index_t> IndexL_t;
          typedef std::pair <index_t, index_t> Grasp_t;
          typedef boost::tuple <StatePtr_t,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  FoliatedManifold>
                    StateAndManifold_t;
Joseph Mirabel's avatar
Joseph Mirabel committed
          //typedef std::vector <index_t, index_t> GraspV_t;
          /// GraspV_t corresponds to a unique ID of a  permutation.
          /// - its size is the number of grippers,
          /// - the values correpond to the index of the handle (0..nbHandle-1), or
          ///   nbHandle to mean no handle. 
          typedef std::vector <index_t> GraspV_t;
          struct CompiledRule {
              Accept,
              Refuse,
              NoMatch,
              Undefined
            };
            std::vector<boost::regex> handles;
            Status status;
            CompiledRule (const Result& res, const Rule& r);
            Status check (const std::vector<std::string>& names, const GraspV_t& g) const
              const std::size_t nG = g.size();
              assert(nG == handles.size());
              for (std::size_t i = 0; i < nG; ++i) {
                if (handles[i].empty()) continue;
                if (!boost::regex_match(names[g[i]], handles[i]))
                  return NoMatch;
              }
              return status;
            }
          };
          typedef std::vector<CompiledRule> CompiledRules_t;
Joseph Mirabel's avatar
Joseph Mirabel committed

          struct Result {
Joseph Mirabel's avatar
Joseph Mirabel committed
            GraphPtr_t graph;
            typedef unsigned long stateid_type;
            std::tr1::unordered_map<stateid_type, StateAndManifold_t> states;
            typedef std::pair<stateid_type, stateid_type> edgeid_type;
            struct edgeid_hash {
              std::tr1::hash<edgeid_type::first_type> first;
              std::tr1::hash<edgeid_type::second_type> second;
              std::size_t operator() (const edgeid_type& eid) const {
                return first(eid.first) + second(eid.second);
              }
            };
            std::tr1::unordered_set<edgeid_type, edgeid_hash> edges;
            std::vector< boost::array<ImplicitPtr_t,3> > graspCs;
Joseph Mirabel's avatar
Joseph Mirabel committed
            index_t nG, nOH;
            GraspV_t dims;
            const Grippers_t& gs;
            const Objects_t& ohs;
            std::vector<std::string> handleNames;
            CompiledRules_t rules;
            CompiledRule::Status defaultAcceptationPolicy;
Joseph Mirabel's avatar
Joseph Mirabel committed

            Result (const ProblemSolverPtr_t problem, const Grippers_t& grippers, const Objects_t& objects, GraphPtr_t g) :
              ps (problem), graph (g), nG (grippers.size ()), nOH (0), gs (grippers), ohs (objects),
              defaultAcceptationPolicy (CompiledRule::Refuse)
Joseph Mirabel's avatar
Joseph Mirabel committed
            {
              BOOST_FOREACH (const Object_t& o, objects) {
                nOH += o.get<1>().size();
                BOOST_FOREACH (const HandlePtr_t& h, o.get<1>()) {
                  handleNames.push_back(h->name());
                }
Joseph Mirabel's avatar
Joseph Mirabel committed
              }
              handleNames.push_back("");
Joseph Mirabel's avatar
Joseph Mirabel committed
              dims.resize (nG);
              dims[0] = nOH + 1;
              for (index_t i = 1; i < nG; ++i)
                dims[i] = dims[i-1] * (nOH + 1);
              graspCs.resize (nG * nOH);
            }

            void setRules (const Rules_t& r)
            {
              for (Rules_t::const_iterator _r = r.begin(); _r != r.end(); ++_r)
                rules.push_back (CompiledRule(*this, *_r));
            }

            bool graspIsAllowed (const GraspV_t& idxOH) const
            {
              assert (idxOH.size () == nG);
              for (std::size_t r = 0; r < rules.size(); ++r) {
                switch (rules[r].check(handleNames,idxOH)) {
                  case CompiledRule::Accept : return true;
                  case CompiledRule::Refuse : return false;
                  case CompiledRule::NoMatch: continue; // Check next rule
                  default: throw std::invalid_argument ("Rules are ill-defined.");
              return (defaultAcceptationPolicy == CompiledRule::Accept);
            inline stateid_type stateid (const GraspV_t& iG)
Joseph Mirabel's avatar
Joseph Mirabel committed
            {
              stateid_type iGOH = iG[0];
              stateid_type res;
Joseph Mirabel's avatar
Joseph Mirabel committed
              for (index_t i = 1; i < nG; ++i) {
                res = iGOH + dims[i] * (iG[i]);
                if (res < iGOH) {
                  hppDout (info, "State ID overflowed. There are too many states...");
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                iGOH = res;
                // iGOH += dims[i] * (iG[i]);
              }
            bool hasState (const GraspV_t& iG)
              return states.count(stateid(iG)) > 0;
            StateAndManifold_t& operator() (const GraspV_t& iG)
              return states [stateid(iG)];
            }

            bool hasEdge (const GraspV_t& g1, const GraspV_t& g2)
            {
              return edges.count(edgeid_type(stateid(g1), stateid(g2))) > 0;
            }

            void addEdge (const GraspV_t& g1, const GraspV_t& g2)
            {
              edges.insert(edgeid_type(stateid(g1), stateid(g2)));
            inline boost::array<ImplicitPtr_t,3>& graspConstraint (
                const index_t& iG, const index_t& iOH)
            {
              boost::array<ImplicitPtr_t,3>& gcs =
                graspCs [iG * nOH + iOH];
              if (!gcs[0]) {
                hppDout (info, "Create grasps constraints for ("
                    << iG << ", " << iOH << ")");
                const GripperPtr_t& g (gs[iG]);
                const HandlePtr_t& h (handle (iOH));
                const std::string& grasp = g->name() + " grasps " + h->name();
                if (!ps->numericalConstraints.has(grasp)) {
                  ps->createGraspConstraint (grasp, g->name(), h->name());
                }
                gcs[0] = ps->numericalConstraints.get(grasp);
                gcs[1] = ps->numericalConstraints.get(grasp + "/complement");
                const std::string& pregrasp = g->name() + " pregrasps " + h->name();
                if (!ps->numericalConstraints.has(pregrasp)) {
                  ps->createPreGraspConstraint (pregrasp, g->name(), h->name());
                }
                gcs[2] = ps->numericalConstraints.get(pregrasp);
Joseph Mirabel's avatar
Joseph Mirabel committed
            const Object_t& object (const index_t& iOH) const {
              index_t iH = iOH;
              BOOST_FOREACH (const Object_t& o, ohs) {
                if (iH < o.get<1>().size()) return o;
                iH -= o.get<1>().size();
              }
              throw std::out_of_range ("Handle index");
            }

            const HandlePtr_t& handle (const index_t& iOH) const {
              index_t iH = iOH;
              BOOST_FOREACH (const Object_t& o, ohs) {
                if (iH < o.get<1>().size()) return o.get<1>()[iH];
                iH -= o.get<1>().size();
              }
              throw std::out_of_range ("Handle index");
            }
Joseph Mirabel's avatar
Joseph Mirabel committed

            /// Check if an object can be placed
            bool objectCanBePlaced (const Object_t& o) const
              // If the object has no joint, then it cannot be placed.
              return (o.get<0>().get<2>().size() > 0);
            /// Check is an object is grasped by the GraspV_t
            bool isObjectGrasped (const GraspV_t& idxOH,
                const Object_t& o) const
            {
              assert (idxOH.size () == nG);
              for (std::size_t i = 0; i < idxOH.size (); ++i)
                if (idxOH[i] < nOH) // This grippers grasps an object
                  if (o.get<2>() == object(idxOH[i]).get<2>())
                    return true;
              return false;
            }

            /// Get a state name from a set of grasps
            std::string name (const GraspV_t& idxOH, bool abbrev = false) const {
              assert (idxOH.size () == nG);
              std::stringstream ss;
              bool first = true;
              std::string sepGOH = (abbrev?"-":" grasps "),
                          sep    = (abbrev?":":" : ");
              for (std::size_t i = 0; i < idxOH.size (); ++i) {
                if (idxOH[i] < nOH) { // This grippers grasps an object
                  if (first) first = false; else ss << sep; 
                  if (abbrev) ss << i << sepGOH << idxOH[i];
                  else
                    ss << gs[i]->name() << sepGOH << handle (idxOH[i])->name ();
                }
              }
              if (first) return (abbrev?"f":"free");
              return ss.str();
            }

            /// Get an edge name from a set of grasps
            std::pair<std::string, std::string> name
              (const GraspV_t& gFrom, const GraspV_t& gTo, const index_t iG)
            {
              const std::string nf (name (gFrom, true)),
                                nt (name (gTo, true));
              std::stringstream ssForw, ssBack;
              const char sep[] = " | ";
              ssForw << gs[iG]->name() << " > " << handle (gTo[iG])->name () << sep << nf;
              ssBack << gs[iG]->name() << " < " << handle (gTo[iG])->name () << sep << nt;
              return std::make_pair (ssForw.str(), ssBack.str ());
            }

            std::string nameLoopEdge (const GraspV_t& gFrom)
            {
              const std::string nf (name (gFrom, true));
              std::stringstream ss;
              const char sep[] = " | ";
              ss << "Loop" << sep << nf;
              return ss.str();
Joseph Mirabel's avatar
Joseph Mirabel committed
            }

            void graspManifold (const index_t& iG, const index_t& iOH,
                FoliatedManifold& grasp, FoliatedManifold& pregrasp)
            {
              boost::array<ImplicitPtr_t,3>& gcs
                = graspConstraint (iG, iOH);
              grasp.nc.nc.push_back (gcs[0]);
              grasp.nc.pdof.push_back (segments_t ());
              grasp.nc_path.nc.push_back (gcs[0]);
              // TODO: see function declaration
              grasp.nc_path.pdof.push_back (segments_t ());
              if (gcs[1]->function ().outputSize () > 0) {
                grasp.nc_fol.nc.push_back (gcs[1]);
                grasp.nc_fol.pdof.push_back (segments_t());
              }

              pregrasp.nc.nc.push_back (gcs[2]);
              pregrasp.nc.pdof.push_back (segments_t());
              pregrasp.nc_path.nc.push_back (gcs[2]);
              pregrasp.nc_path.pdof.push_back (segments_t());
Joseph Mirabel's avatar
Joseph Mirabel committed
          };

          CompiledRule::CompiledRule (const Result& res, const Rule& r) :
            handles(res.nG), status (r.link_ ? Accept : Refuse)
          {
            assert(r.grippers_.size() == r.handles_.size());
            for (std::size_t j = 0; j < r.grippers_.size(); ++j) {
              boost::regex gripper (r.grippers_[j]);
              for (std::size_t i = 0; i < res.nG; ++i) {
                if (boost::regex_match(res.gs[i]->name(), gripper)) {
                  assert(handles[i].empty() && "Two gripper regex match the different gripper names.");
                  handles[i] = r.handles_[j];
          const StateAndManifold_t& makeState (Result& r, const GraspV_t& g,
Joseph Mirabel's avatar
Joseph Mirabel committed
          {
            StateAndManifold_t& nam = r (g);
Joseph Mirabel's avatar
Joseph Mirabel committed
            if (!nam.get<0>()) {
              hppDout (info, "Creating state " << r.name (g));
              nam.get<0>() = r.graph->stateSelector ()->createState
                (r.name (g), false, priority);
Joseph Mirabel's avatar
Joseph Mirabel committed
              // Loop over the grippers and create grasping constraints if required
              FoliatedManifold unused;
              std::set <index_t> idxsOH;
              for (index_t i = 0; i < r.nG; ++i) {
                if (g[i] < r.nOH) {
                  idxsOH.insert (g[i]);
                  r.graspManifold (i, g[i], nam.get<1>(), unused);
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
              }
              index_t iOH = 0;
              BOOST_FOREACH (const Object_t& o, r.ohs) {
                if (!r.objectCanBePlaced(o)) continue;
Joseph Mirabel's avatar
Joseph Mirabel committed
                bool oIsGrasped = false;
                // TODO: use the fact that the set is sorted.
                // BOOST_FOREACH (const HandlePtr_t& h, o.get<1>())
Joseph Mirabel's avatar
Joseph Mirabel committed
                for (index_t i = 0; i < o.get<1>().size(); ++i) {
                  if (idxsOH.erase (iOH) == 1) oIsGrasped = true;
                  ++iOH;
                }
                if (!oIsGrasped)
                  relaxedPlacementManifold (o.get<0>().get<0>(),
                      o.get<0>().get<1>(),
                      o.get<0>().get<2>(),
                      nam.get<1>(), unused);
              }
              nam.get<1>().addToState (nam.get<0>());

              createLoopEdge (r.nameLoopEdge (g),
                  false,
                  // TODO nam.get<1>().foliated(),
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
Joseph Mirabel's avatar
Joseph Mirabel committed

          /// Arguments are such that
          /// \li gTo[iG] != gFrom[iG]
          /// \li for all i != iG, gTo[iG] == gFrom[iG]
          void makeEdge (Result& r,
              const GraspV_t& gFrom, const GraspV_t& gTo,
              const index_t iG, const int priority)
            if (r.hasEdge(gFrom, gTo)) {
              hppDout (warning, "Prevented creation of duplicated edge\nfrom "
                  << r.name (gFrom) << "\nto " << r.name (gTo));
              return;
            }
            const StateAndManifold_t& from = makeState (r, gFrom, priority),
                                     to   = makeState (r, gTo, priority+1);
            const Object_t& o = r.object (gTo[iG]);

            // Detect when grasping an object already grasped.
            // or when there is no placement information for it.
            bool noPlace = !r.objectCanBePlaced(o)
                         || r.isObjectGrasped (gFrom, o);
            FoliatedManifold grasp, pregrasp, place, preplace,
                             submanifold;
            r.graspManifold (iG, gTo[iG], grasp, pregrasp);
            if (!noPlace) {
              relaxedPlacementManifold (o.get<0>().get<0>(),
                  o.get<0>().get<1>(),
                  o.get<0>().get<2>(),
                  place, preplace);
            }
            std::pair<std::string, std::string> names =
              r.name (gFrom, gTo, iG);
            {
              FoliatedManifold unused;
              std::set <index_t> idxsOH;
              for (index_t i = 0; i < r.nG; ++i) {
                if (gFrom[i] < r.nOH) {
                  idxsOH.insert (gFrom[i]);
                  r.graspManifold (i, gFrom[i], submanifold, unused);
                }
              }
              index_t iOH = 0;
              BOOST_FOREACH (const Object_t& o, r.ohs) {
                if (!r.objectCanBePlaced(o)) continue;
                bool oIsGrasped = false;
                const index_t iOHstart = iOH;
                for (; iOH < iOHstart + o.get<1>().size(); ++iOH) {
                  if (iOH == gTo [iG]) {
                    oIsGrasped = true;
                    iOH = iOHstart + o.get<1>().size();
                    break;
                  }
                  if (idxsOH.erase (iOH) == 1) oIsGrasped = true;
                }
                if (!oIsGrasped)
                  relaxedPlacementManifold (o.get<0>().get<0>(),
                      o.get<0>().get<1>(),
                      o.get<0>().get<2>(),
                      submanifold, unused);
              }
            }
            if (pregrasp.empty ()) {
              if (noPlace)
                createEdges <GraspOnly | NoPlace> (
                    names.first           , names.second,
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else if (preplace.empty ())
                createEdges <GraspOnly | PlaceOnly> (
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else {
                hppDout (error, "GraspOnly | WithPrePlace not implemeted yet");
                /*
                   createEdges <GraspOnly | WithPrePlace> (
                   from.get<0> ()        , to.get<0>(),
                   1                     , 1,
                   grasp                 , pregrasp,
                   place                 , preplace,
                   grasp.foliated ()     , place.foliated(),
                   submanifold); // */
Joseph Mirabel's avatar
Joseph Mirabel committed
              }
              if (noPlace)
                createEdges <WithPreGrasp | NoPlace> (
                    names.first           , names.second,
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else if (preplace.empty ())
                createEdges <WithPreGrasp | PlaceOnly> (
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else
                createEdges <WithPreGrasp | WithPrePlace> (
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
            r.addEdge(gFrom, gTo);
Joseph Mirabel's avatar
Joseph Mirabel committed

          /// idx are the available grippers
          void recurseGrippers (Result& r,
              const IndexV_t& idx_g, const IndexV_t& idx_oh,
              const GraspV_t& grasps, const int depth)
            bool curGraspIsAllowed = r.graspIsAllowed(grasps);
            if (curGraspIsAllowed) makeState (r, grasps, depth);
            if (idx_g.empty () || idx_oh.empty ()) return;
            IndexV_t nIdx_g (idx_g.size() - 1);
            IndexV_t nIdx_oh (idx_oh.size() - 1);
            for (IndexV_t::const_iterator itx_g = idx_g.begin ();
                itx_g != idx_g.end (); ++itx_g) {
              // Copy all element except itx_g
              std::copy (boost::next (itx_g), idx_g.end (),
                  std::copy (idx_g.begin (), itx_g, nIdx_g.begin ())
Joseph Mirabel's avatar
Joseph Mirabel committed
                  );
              for (IndexV_t::const_iterator itx_oh = idx_oh.begin ();
                  itx_oh != idx_oh.end (); ++itx_oh) {
                // Create the edge for the selected grasp
                GraspV_t nGrasps = grasps;
                nGrasps [*itx_g] = *itx_oh;

                bool nextGraspIsAllowed = r.graspIsAllowed(nGrasps);
                if (nextGraspIsAllowed) makeState (r, nGrasps, depth + 1);

                if (curGraspIsAllowed && nextGraspIsAllowed)
                  makeEdge (r, grasps, nGrasps, *itx_g, depth);
                // Copy all element except itx_oh
                std::copy (boost::next (itx_oh), idx_oh.end (),
                    std::copy (idx_oh.begin (), itx_oh, nIdx_oh.begin ())
                    );
                // Do all the possible combination below this new grasp
                recurseGrippers (r, nIdx_g, nIdx_oh, nGrasps, depth + 2);
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
          }
        }

        void graphBuilder (
Joseph Mirabel's avatar
Joseph Mirabel committed
            const Objects_t& objects,