From ade78b38a1ff2612ea7a383dae4fd8d4aebded18 Mon Sep 17 00:00:00 2001
From: Joseph Mirabel <jmirabel@laas.fr>
Date: Wed, 4 Jul 2018 11:18:30 +0200
Subject: [PATCH] Add path optimization EnforceTransitionSemantic

---
 CMakeLists.txt                                |   1 +
 .../enforce-transition-semantic.hh            |  60 +++++++
 src/CMakeLists.txt                            |   1 +
 .../enforce-transition-semantic.cc            | 164 ++++++++++++++++++
 src/problem-solver.cc                         |   3 +
 5 files changed, 229 insertions(+)
 create mode 100644 include/hpp/manipulation/path-optimization/enforce-transition-semantic.hh
 create mode 100644 src/path-optimization/enforce-transition-semantic.cc

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 52942a00..764cdc2f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,6 +101,7 @@ SET (${PROJECT_NAME}_HEADERS
 
   include/hpp/manipulation/path-optimization/small-steps.hh
   include/hpp/manipulation/path-optimization/config-optimization.hh
+  include/hpp/manipulation/path-optimization/enforce-transition-semantic.hh
   include/hpp/manipulation/path-optimization/keypoints.hh
   include/hpp/manipulation/path-optimization/spline-gradient-based.hh
 
diff --git a/include/hpp/manipulation/path-optimization/enforce-transition-semantic.hh b/include/hpp/manipulation/path-optimization/enforce-transition-semantic.hh
new file mode 100644
index 00000000..de218025
--- /dev/null
+++ b/include/hpp/manipulation/path-optimization/enforce-transition-semantic.hh
@@ -0,0 +1,60 @@
+// Copyright (c) 2018, 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/>.
+
+#ifndef HPP_MANIPULATION_PATHOPTIMIZATION_ENFORCE_TRANSITION_SEMANTIC_HH
+#define HPP_MANIPULATION_PATHOPTIMIZATION_ENFORCE_TRANSITION_SEMANTIC_HH
+
+# include <hpp/core/path-optimizer.hh>
+
+# include <hpp/manipulation/problem.hh>
+
+namespace hpp {
+  namespace manipulation {
+    namespace pathOptimization {
+      using hpp::core::Path;
+      using hpp::core::PathPtr_t;
+      using hpp::core::PathVector;
+      /// \addtogroup path_optimization
+      /// \{
+
+      class HPP_MANIPULATION_DLLAPI EnforceTransitionSemantic : public core::PathOptimizer
+      {
+        public:
+          typedef hpp::core::PathVectorPtr_t PathVectorPtr_t;
+          typedef boost::shared_ptr<EnforceTransitionSemantic> Ptr_t;
+
+          static Ptr_t create (const core::Problem& problem) {
+            const Problem& p = dynamic_cast <const Problem&> (problem);
+            return Ptr_t (new EnforceTransitionSemantic (p));
+          }
+
+          virtual PathVectorPtr_t optimize (const PathVectorPtr_t& path);
+
+        protected:
+          /// Constructor
+          EnforceTransitionSemantic (const Problem& problem) :
+            PathOptimizer (problem), problem_ (problem) {}
+
+        private:
+          const Problem& problem_;
+      };
+
+      /// \}
+    } // namespace pathOptimization
+  } // namespace manipulation
+} // namespace hpp
+
+#endif // HPP_MANIPULATION_PATHOPTIMIZATION_ENFORCE_TRANSITION_SEMANTIC_HH
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 05380d4c..d66da53e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -49,6 +49,7 @@ SET(SOURCES
   path-optimization/config-optimization.cc
   path-optimization/keypoints.cc
   path-optimization/spline-gradient-based.cc
+  path-optimization/enforce-transition-semantic.cc
 
   problem-target/state.cc
 
diff --git a/src/path-optimization/enforce-transition-semantic.cc b/src/path-optimization/enforce-transition-semantic.cc
new file mode 100644
index 00000000..14221df9
--- /dev/null
+++ b/src/path-optimization/enforce-transition-semantic.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2018, 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/path-optimization/enforce-transition-semantic.hh>
+
+#include <hpp/pinocchio/util.hh>
+#include <hpp/core/path-vector.hh>
+
+#include <hpp/manipulation/constraint-set.hh>
+#include <hpp/manipulation/graph/edge.hh>
+#include <hpp/manipulation/graph/graph.hh>
+#include <hpp/manipulation/graph/state.hh>
+
+namespace hpp {
+  namespace manipulation {
+    namespace pathOptimization {
+      using hpp::core::Path;
+      using hpp::core::PathPtr_t;
+      using hpp::core::PathVector;
+      using hpp::core::PathVectorPtr_t;
+      using graph::Edges_t;
+      using graph::StatePtr_t;
+
+
+      Edges_t getAllEdges (const StatePtr_t& from, const StatePtr_t& to)
+      {
+        Edges_t edges;
+        for (graph::Neighbors_t::const_iterator it = from->neighbors ().begin ();
+            it != from->neighbors ().end (); ++it) {
+          if (it->second->to () == to)
+            edges.push_back (it->second);
+        }
+        for (Edges_t::const_iterator it = from->hiddenNeighbors ().begin ();
+            it != from->hiddenNeighbors ().end (); ++it) {
+          if ((*it)->to () == to)
+            edges.push_back (*it);
+        }
+        return edges;
+      }
+
+      PathVectorPtr_t EnforceTransitionSemantic::optimize (const PathVectorPtr_t& path)
+      {
+        PathVectorPtr_t input = PathVector::create (
+              path->outputSize(), path->outputDerivativeSize()); 
+        PathVectorPtr_t output = PathVector::create (
+              path->outputSize(), path->outputDerivativeSize()); 
+        path->flatten (input);
+
+        ConstraintSetPtr_t c;
+        for (std::size_t i = 0; i < input->numberPaths(); ++i) {
+          PathPtr_t current = input->pathAtRank (i);
+          output->appendPath(current);
+          c = HPP_DYNAMIC_PTR_CAST (ConstraintSet, current->constraints ());
+          if (!c) {
+            hppDout(info, "No manipulation::ConstraintSet");
+            break;
+          }
+          Configuration_t q0 = current->initial();
+          Configuration_t q1 = current->end    ();
+          StatePtr_t src = c->edge()->from();
+          StatePtr_t dst = c->edge()->to  ();
+          if (src == dst) continue;
+
+          bool q0_in_src = src->contains(q0);
+          bool q1_in_src = src->contains(q1);
+          bool q0_in_dst = dst->contains(q0);
+          bool q1_in_dst = dst->contains(q1);
+
+          if (q0_in_src && q1_in_dst) // Nominal case
+            continue;
+          hppDout (warning, "Transition " << i << ". "
+              "\nsrc=" << src->name() <<
+              "\ndst=" << dst->name() <<
+              "\nq0_in_src=" << q0_in_src <<
+              "\nq1_in_src=" << q1_in_src <<
+              "\nq0_in_dst=" << q0_in_dst <<
+              "\nq1_in_dst=" << q1_in_dst <<
+              setpyformat <<
+              "\nq0=" << one_line(q0) <<
+              "\nq1=" << one_line(q1) <<
+              unsetpyformat <<
+              "\nTrying with state.");
+
+          StatePtr_t from, to;
+          if (q0_in_dst && q1_in_src) { // Reversed from nominal case
+            from = dst;
+            to = src;
+          } else if (q0_in_dst && q1_in_dst) {
+            from = dst;
+            to = dst;
+          } else if (q0_in_src && q1_in_src) {
+            from = src;
+            to = src;
+          } else if (q0_in_src) { // Keep same transition
+            continue;
+          } else if (q0_in_dst) { // Reverse current transition
+            from = dst;
+            to = src;
+          } else if (q1_in_src) { // Keep same transition
+            continue;
+          } else if (q1_in_dst) { // Reverse current transition
+            from = dst;
+            to = src;
+          }
+          if (from && to) {
+            // Check that a path from dst to to exists.
+            Edges_t transitions = getAllEdges(from, to);
+            if (transitions.size() >= 1)
+            {
+              if (transitions.size() > 1)
+              {
+                hppDout (info, "More than one transition...");
+              }
+              c->edge(transitions[0]);
+              continue;
+            }
+          }
+          hppDout (warning, "Enable to find a suitable transition for " << i << ". "
+              "\nsrc=" << src->name() <<
+              "\ndst=" << dst->name() <<
+              "\nq0_in_src=" << q0_in_src <<
+              "\nq1_in_src=" << q1_in_src <<
+              "\nq0_in_dst=" << q0_in_dst <<
+              "\nq1_in_dst=" << q1_in_dst <<
+              setpyformat <<
+              "\nq0=" << one_line(q0) <<
+              "\nq1=" << one_line(q1) <<
+              unsetpyformat <<
+              "\nTrying with state.");
+
+          StatePtr_t state = c->edge()->state();
+          // Check that a path from dst to to exists.
+          Edges_t transitions = getAllEdges(state, state);
+          if (transitions.size() >= 1)
+          {
+            if (transitions.size() > 1)
+            {
+              hppDout (info, "More than one transition...");
+            }
+            c->edge(transitions[0]);
+            continue;
+          } else {
+            hppDout (error, "Enable to find a suitable transition for " << *current);
+          }
+        }
+        return output;
+      }
+
+    } // namespace pathOptimization
+  } // namespace manipulation
+} // namespace hpp
diff --git a/src/problem-solver.cc b/src/problem-solver.cc
index ffde8570..49e99c38 100644
--- a/src/problem-solver.cc
+++ b/src/problem-solver.cc
@@ -55,6 +55,7 @@
 #include "hpp/manipulation/path-optimization/config-optimization.hh"
 #include "hpp/manipulation/path-optimization/keypoints.hh"
 #include "hpp/manipulation/path-optimization/spline-gradient-based.hh"
+#include "hpp/manipulation/path-optimization/enforce-transition-semantic.hh"
 #include "hpp/manipulation/problem-target/state.hh"
 #include "hpp/manipulation/steering-method/cross-state-optimization.hh"
 #include "hpp/manipulation/steering-method/graph.hh"
@@ -133,6 +134,8 @@ namespace hpp {
           GraphConfigOptimizationTraits
             <pathOptimization::ConfigOptimizationTraits>
             >);
+      pathOptimizers.add ("EnforceTransitionSemantic",
+          pathOptimization::EnforceTransitionSemantic::create);
 
       pathProjectors.add ("Progressive",
           createPathProjector <core::pathProjector::Progressive>);
-- 
GitLab