Skip to content
Snippets Groups Projects
helper.cc 44.9 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 <iterator>
#include <array>

#include <boost/regex.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>
Joseph Mirabel's avatar
Joseph Mirabel committed
          void addToComp
          (const NumericalConstraints_t& nc, GraphComponentPtr_t comp)
Joseph Mirabel's avatar
Joseph Mirabel committed
        {
          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
          }
Joseph Mirabel's avatar
Joseph Mirabel committed
          for (const auto& c : nc)
            if (c) {
              if (forPath) n->addNumericalConstraintForPath (c);
              else      comp->addNumericalConstraint (c);
Joseph Mirabel's avatar
Joseph Mirabel committed
        }
Joseph Mirabel's avatar
Joseph Mirabel committed

        template <bool param>
Joseph Mirabel's avatar
Joseph Mirabel committed
          void specifyFoliation
          (const NumericalConstraints_t& nc, LevelSetEdgePtr_t lse)
Joseph Mirabel's avatar
Joseph Mirabel committed
        {
Joseph Mirabel's avatar
Joseph Mirabel committed
          for (const auto& c : nc)
            if (c) {
              if (param) lse->insertParamConstraint (c);
              else   lse->insertConditionConstraint (c);
Joseph Mirabel's avatar
Joseph Mirabel committed
        }

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

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

        void FoliatedManifold::specifyFoliation (LevelSetEdgePtr_t lse) const
        {
Joseph Mirabel's avatar
Joseph Mirabel committed
          for (const auto& c : nc)
            lse->insertConditionConstraint (c);
          for (const auto& c : nc_fol)
            lse->insertConditionConstraint (c);
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 std::array <StatePtr_t, Nstates> StateArray;
              typedef std::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 = static_pointer_cast <WaypointEdge>
Joseph Mirabel's avatar
Joseph Mirabel committed
                      (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 = static_pointer_cast <WaypointEdge>
Joseph Mirabel's avatar
Joseph Mirabel committed
                    (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 = static_pointer_cast <LevelSetEdge>
Joseph Mirabel's avatar
Joseph Mirabel committed
                    (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 = static_pointer_cast <WaypointEdge>
Joseph Mirabel's avatar
Joseph Mirabel committed
                    (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");
                  pls = static_pointer_cast <LevelSetEdge>
Joseph Mirabel's avatar
Joseph Mirabel committed
                    (n.back()->linkTo (name + "_ls", n.front(), w,
                                       LevelSetEdge::create));
                  return pls;
                }
              }

Joseph Mirabel's avatar
Joseph Mirabel committed
              template <typename EdgeType>
              static inline 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 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 { 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.push_back (gc);
          grasp.nc_path.push_back (gc);
          ImplicitPtr_t gcc = handle->createGraspComplement
Joseph Mirabel's avatar
Joseph Mirabel committed
          if (gcc->function ().outputSize () > 0)
            grasp.nc_fol.push_back (gcc);
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.push_back (pgc);
          pregrasp.nc_path.push_back (pgc);
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)
        {
Joseph Mirabel's avatar
Joseph Mirabel committed
          place.nc.push_back (placement);
          place.nc_path.push_back (placement);
          if (placementComplement && placementComplement->function().outputSize () > 0)
            place.nc_fol.push_back (placementComplement);
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
          preplace.nc.push_back (preplacement);
          preplace.nc_path.push_back (preplacement);
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)
        {
Joseph Mirabel's avatar
Joseph Mirabel committed
            place.nc.push_back (placement);
            // 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.
Joseph Mirabel's avatar
Joseph Mirabel committed
            place.nc_path.push_back (placement);
          std::copy (objectLocks.begin(), objectLocks.end(), std::back_inserter(place.lj_fol));
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
            preplace.nc.push_back (preplacement);
            // preplace.nc_path.push_back (preplacement);
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 std::tuple <StatePtr_t, 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< std::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
            {
              for (const Object_t& o : objects) {
                nOH += std::get<1>(o).size();
                for (const HandlePtr_t& h : std::get<1>(o))
                  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 std::array<ImplicitPtr_t,3>& graspConstraint (
                const index_t& iG, const index_t& iOH)
            {
              std::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;
              for (const Object_t& o : ohs) {
                if (iH < std::get<1>(o).size()) return o;
                iH -= std::get<1>(o).size();
Joseph Mirabel's avatar
Joseph Mirabel committed
              }
              throw std::out_of_range ("Handle index");
            }

            const HandlePtr_t& handle (const index_t& iOH) const {
              index_t iH = iOH;
              for (const Object_t& o : ohs) {
                if (iH < std::get<1>(o).size()) return std::get<1>(o)[iH];
                iH -= std::get<1>(o).size();
Joseph Mirabel's avatar
Joseph Mirabel committed
              }
              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 (std::get<2>(std::get<0>(o)).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 (std::get<2>(o) == std::get<2>(object(idxOH[i])))
            /// 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)
            {
              std::array<ImplicitPtr_t,3>& gcs
                = graspConstraint (iG, iOH);
Joseph Mirabel's avatar
Joseph Mirabel committed
              grasp.nc.push_back (gcs[0]);
              grasp.nc_path.push_back (gcs[0]);
              if (gcs[1]->function ().outputSize () > 0)
                grasp.nc_fol.push_back (gcs[1]);
Joseph Mirabel's avatar
Joseph Mirabel committed
              pregrasp.nc.push_back (gcs[2]);
              pregrasp.nc_path.push_back (gcs[2]);
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);
            if (!std::get<0>(nam)) {
              hppDout (info, "Creating state " << r.name (g));
              std::get<0>(nam) = 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], std::get<1>(nam), unused);
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
              }
              index_t iOH = 0;
              for (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.
                // for (const HandlePtr_t& h : std::get<0>(o))
                for (index_t i = 0; i < std::get<1>(o).size(); ++i) {
Joseph Mirabel's avatar
Joseph Mirabel committed
                  if (idxsOH.erase (iOH) == 1) oIsGrasped = true;
                  ++iOH;
                }
                if (!oIsGrasped) {
                  const auto& pc (std::get<0>(o));
                  relaxedPlacementManifold (std::get<0>(pc),
                      std::get<1>(pc),
                      std::get<2>(pc),
                      std::get<1>(nam), unused);
                }
Joseph Mirabel's avatar
Joseph Mirabel committed
              }
              std::get<1>(nam).addToState (std::get<0>(nam));

              createLoopEdge (r.nameLoopEdge (g),
                  std::get<0>(nam), 0,
                  // TODO std::get<1>(nam).foliated(),
                  std::get<1>(nam));
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);
              const auto& pc (std::get<0>(o));
              relaxedPlacementManifold (std::get<0>(pc),
                  std::get<1>(pc),
                  std::get<2>(pc),
            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;
              for (const Object_t& o : r.ohs) {
                if (!r.objectCanBePlaced(o)) continue;
                bool oIsGrasped = false;
                const index_t iOHstart = iOH;
                for (; iOH < iOHstart + std::get<1>(o).size(); ++iOH) {
                  if (iOH == gTo [iG]) {
                    oIsGrasped = true;
                    iOH = iOHstart + std::get<1>(o).size();
                    break;
                  }
                  if (idxsOH.erase (iOH) == 1) oIsGrasped = true;
                }
                if (!oIsGrasped) {
                  const auto& pc (std::get<0>(o));
                  relaxedPlacementManifold (std::get<0>(pc),
                      std::get<1>(pc),
                      std::get<2>(pc),
                      submanifold, unused);
            if (pregrasp.empty ()) {
              if (noPlace)
                createEdges <GraspOnly | NoPlace> (
                    names.first           , names.second,
                    std::get<0>(from)     , std::get<0>(to),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else if (preplace.empty ())
                createEdges <GraspOnly | PlaceOnly> (
                    std::get<0>(from)     , std::get<0>(to),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else {
                hppDout (error, "GraspOnly | WithPrePlace not implemeted yet");
                /*
                   createEdges <GraspOnly | WithPrePlace> (
                   std::get<0>(from)     , std::get<0>(to),
                   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,
                    std::get<0>(from)     , std::get<0>(to),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else if (preplace.empty ())
                createEdges <WithPreGrasp | PlaceOnly> (
                    std::get<0>(from)     , std::get<0>(to),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else
                createEdges <WithPreGrasp | WithPrePlace> (
                    std::get<0>(from)     , std::get<0>(to),
                    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 (std::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 (std::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,
            const Grippers_t& grippers,
            GraphPtr_t graph,
            const Rules_t& rules)
Joseph Mirabel's avatar
Joseph Mirabel committed
        {
          if (!graph) throw std::logic_error ("The graph must be initialized");
          StateSelectorPtr_t ns = graph->stateSelector ();
          if (!ns) throw std::logic_error ("The graph does not have a StateSelector");
Joseph Mirabel's avatar
Joseph Mirabel committed

          Result r (ps, grippers, objects, graph);
          r.setRules (rules);
Joseph Mirabel's avatar
Joseph Mirabel committed

          IndexV_t availG (r.nG), availOH (r.nOH);
          for (index_t i = 0; i < r.nG; ++i) availG[i] = i;
          for (index_t i = 0; i < r.nOH; ++i) availOH[i] = i;

          GraspV_t iG (r.nG, r.nOH);

          recurseGrippers (r, availG, availOH, iG, 0);
          hppDout (info, "Created a graph with " << r.states.size() << " states "
              "and " << r.edges.size() << " edges.");
Joseph Mirabel's avatar
Joseph Mirabel committed
        }

        GraphPtr_t graphBuilder (
            const ProblemSolverPtr_t& ps,
            const std::string& graphName,
            const StringList_t& griNames,
            const std::list <ObjectDef_t>& objs,
            const StringList_t& envNames,