From d4243797f73f4dc5fbc0f6bfdb1aad60fb87925f Mon Sep 17 00:00:00 2001
From: Joseph Mirabel <jmirabel@laas.fr>
Date: Wed, 26 Jul 2017 13:47:51 +0200
Subject: [PATCH] Add SplineGradientBased for manipulation path

---
 CMakeLists.txt                                |   1 +
 .../spline-gradient-based.hh                  |  75 +++++++++
 src/CMakeLists.txt                            |   1 +
 .../spline-gradient-based.cc                  | 148 ++++++++++++++++++
 src/problem-solver.cc                         |   9 ++
 5 files changed, 234 insertions(+)
 create mode 100644 include/hpp/manipulation/path-optimization/spline-gradient-based.hh
 create mode 100644 src/path-optimization/spline-gradient-based.cc

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90672b7..2295f4f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,6 +104,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/keypoints.hh
+  include/hpp/manipulation/path-optimization/spline-gradient-based.hh
 
   include/hpp/manipulation/problem-target/state.hh
   )
diff --git a/include/hpp/manipulation/path-optimization/spline-gradient-based.hh b/include/hpp/manipulation/path-optimization/spline-gradient-based.hh
new file mode 100644
index 0000000..ec924bb
--- /dev/null
+++ b/include/hpp/manipulation/path-optimization/spline-gradient-based.hh
@@ -0,0 +1,75 @@
+// Copyright (c) 2017, 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_PATH_OPTIMIZATION_SPLINE_GRADIENT_BASED_HH
+# define HPP_MANIPULATION_PATH_OPTIMIZATION_SPLINE_GRADIENT_BASED_HH
+
+#include <hpp/core/path-optimization/spline-gradient-based.hh>
+
+#include <hpp/manipulation/config.hh>
+#include <hpp/manipulation/problem.hh>
+
+namespace hpp {
+  namespace manipulation {
+    /// \addtogroup path_optimization
+    /// \{
+    namespace pathOptimization {
+      template <int _PolynomeBasis, int _SplineOrder>
+      class HPP_MANIPULATION_DLLAPI SplineGradientBased :
+        public core::pathOptimization::SplineGradientBased<_PolynomeBasis, _SplineOrder>
+      {
+        public:
+          enum {
+            PolynomeBasis = _PolynomeBasis,
+            SplineOrder = _SplineOrder
+          };
+          typedef core::pathOptimization::SplineGradientBased<PolynomeBasis, SplineOrder>
+            Parent_t;
+          typedef boost::shared_ptr<SplineGradientBased> Ptr_t;
+
+          typedef typename Parent_t::Spline      Spline;
+          typedef typename Parent_t::SplinePtr_t SplinePtr_t;
+          typedef typename Parent_t::Splines_t   Splines_t;
+
+          /// Return shared pointer to new object.
+          static Ptr_t create (const Problem& problem);
+
+          /// This is only for compatibility purpose (with ProblemSolver).
+          /// problem is statically casted to an object of type
+          /// const manipulation::Problem& and method create(const Problem&)
+          /// is called.
+          static Ptr_t createFromCore (const core::Problem& problem);
+
+        protected:
+          typedef typename Parent_t::LinearConstraint LinearConstraint;
+          typedef typename Parent_t::Solvers_t        Solvers_t;
+
+          SplineGradientBased (const Problem& problem);
+
+          virtual void initializePathValidation(const Splines_t& splines);
+
+          virtual void addProblemConstraints (const core::PathVectorPtr_t& init,
+              const Splines_t& splines, LinearConstraint& lc, Solvers_t& ess) const;
+
+          virtual void constrainEndIntoState (const core::PathPtr_t& path,
+              const size_type& idxSpline, const SplinePtr_t& spline,
+              const graph::StatePtr_t state, LinearConstraint& lc) const;
+      }; // SplineGradientBased
+    } // namespace pathOptimization
+  }  // namespace manipulation
+} // namespace hpp
+
+#endif // HPP_MANIPULATION_PATH_OPTIMIZATION_GRADIENT_BASED_HH
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d721213..b7810d4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -50,6 +50,7 @@ SET(SOURCES
 
   path-optimization/config-optimization.cc
   path-optimization/keypoints.cc
+  path-optimization/spline-gradient-based.cc
 
   problem-target/state.cc
   )
diff --git a/src/path-optimization/spline-gradient-based.cc b/src/path-optimization/spline-gradient-based.cc
new file mode 100644
index 0000000..0e4c0dd
--- /dev/null
+++ b/src/path-optimization/spline-gradient-based.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2017, 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/spline-gradient-based.hh>
+
+#include <hpp/core/path-optimization/spline-gradient-based/linear-constraint.hh>
+
+#include <hpp/manipulation/constraint-set.hh>
+#include <hpp/manipulation/graph/state.hh>
+#include <hpp/manipulation/graph/edge.hh>
+
+namespace hpp {
+  namespace manipulation {
+    namespace pathOptimization {
+
+      template <int _PB, int _SO>
+      SplineGradientBased<_PB, _SO>::SplineGradientBased (const Problem& problem)
+        : Parent_t (problem)
+      {
+        this->checkOptimum_ = true;
+      }
+
+      // ----------- Convenience class -------------------------------------- //
+
+      // ----------- Resolution steps --------------------------------------- //
+
+      template <int _PB, int _SO>
+      typename SplineGradientBased<_PB, _SO>::Ptr_t SplineGradientBased<_PB, _SO>::create
+      (const Problem& problem)
+      {
+	SplineGradientBased* ptr = new SplineGradientBased (problem);
+	Ptr_t shPtr (ptr);
+	return shPtr;
+      }
+
+      template <int _PB, int _SO>
+      typename SplineGradientBased<_PB, _SO>::Ptr_t SplineGradientBased<_PB, _SO>::createFromCore
+      (const core::Problem& problem)
+      {
+        HPP_STATIC_CAST_REF_CHECK(const Problem, problem);
+        return create (static_cast<const Problem&>(problem));
+      }
+
+      template <int _PB, int _SO>
+      void SplineGradientBased<_PB, _SO>::initializePathValidation
+      (const Splines_t& splines)
+      {
+        this->validations_.resize(splines.size());
+        for (std::size_t i = 0; i < splines.size(); ++i) {
+          ConstraintSetPtr_t set = HPP_STATIC_PTR_CAST (ConstraintSet, splines[i]->constraints ());
+          if (set && set->edge())
+            this->validations_[i] = set->edge()->pathValidation();
+          else
+            this->validations_[i] = this->problem().pathValidation();
+        }
+      }
+
+      template <int _PB, int _SO>
+      void SplineGradientBased<_PB, _SO>::addProblemConstraints
+      (const core::PathVectorPtr_t& init, const Splines_t& splines, LinearConstraint& lc, Solvers_t& ss) const
+      {
+        assert (init->numberPaths() == splines.size() && ss.size() == splines.size());
+
+        const std::size_t last = splines.size() - 1;
+        for (std::size_t i = 0; i < last; ++i) {
+          core::PathPtr_t path = init->pathAtRank(i);
+          ConstraintSetPtr_t set = HPP_STATIC_PTR_CAST (ConstraintSet, splines[i]->constraints ());
+          if (!set || !set->edge())
+            std::invalid_argument ("Cannot optimize a path that has not been "
+                "generated with a graph.");
+          graph::EdgePtr_t transition = set->edge();
+
+          this->addProblemConstraintOnPath (path, i, splines[i], lc, ss[i]);
+
+          bool reversed = transition->direction (path);
+
+          // The path should always go through the start and end states of the
+          // transition.
+          if (reversed && transition->state() != from) {
+            // Do something different
+            constrainEndIntoState (path, i, splines[i], from, lc);
+          } else if (!reversed && transition->state() != transition->to()) {
+            // Do something different
+            constrainEndIntoState (path, i, splines[i], transition->to(), lc);
+          }
+        }
+        this->addProblemConstraintOnPath (init->pathAtRank(last), last, splines[last], lc, ss[last]);
+      }
+
+      template <int _PB, int _SO>
+      void SplineGradientBased<_PB, _SO>::constrainEndIntoState
+      (const core::PathPtr_t& path, const size_type& idxSpline,
+       const SplinePtr_t& spline, const graph::StatePtr_t state,
+       LinearConstraint& lc) const
+      {
+        typename Spline::BasisFunctionVector_t B1;
+        spline->basisFunctionDerivative(0, 1, B1);
+        // TODO Should we add zero velocity sometimes ?
+
+        ConstraintSetPtr_t set = state->configConstraint();
+        value_type guessThreshold = this->problem().getParameter ("SplineGradientBased/guessThreshold", value_type(-1));
+        Eigen::RowBlockIndexes select =
+          this->computeActiveParameters (path, set->configProjector()->solver(), guessThreshold);
+
+        const size_type rDof = this->robot_->numberDof(),
+                        col  = idxSpline * Spline::NbCoeffs * rDof,
+                        row = lc.J.rows(),
+                        nOutVar = select.nbIndexes();
+
+        // Add nOutVar constraints
+        lc.addRows(nOutVar);
+        matrix_t I = select.rview(matrix_t::Identity(rDof, rDof));
+        for (size_type k = 0; k < Spline::NbCoeffs; ++k)
+          lc.J.block  (row, col + k * rDof, nOutVar, rDof) = B1(k) * I;
+        lc.b.segment(row, nOutVar) = select.rview(spline->parameters().transpose() * B1);
+
+        assert ((lc.J.block(row, col, nOutVar, rDof * Spline::NbCoeffs) * spline->rowParameters())
+            .isApprox(lc.b.segment(row, nOutVar)));
+      }
+
+      // ----------- Optimize ----------------------------------------------- //
+
+      // ----------- Convenience functions ---------------------------------- //
+
+      // ----------- Instanciate -------------------------------------------- //
+
+      template class SplineGradientBased<core::path::CanonicalPolynomeBasis, 1>; // equivalent to StraightPath
+      template class SplineGradientBased<core::path::CanonicalPolynomeBasis, 2>;
+      template class SplineGradientBased<core::path::CanonicalPolynomeBasis, 3>;
+      template class SplineGradientBased<core::path::BernsteinBasis, 1>; // equivalent to StraightPath
+      template class SplineGradientBased<core::path::BernsteinBasis, 2>;
+      template class SplineGradientBased<core::path::BernsteinBasis, 3>;
+    } // namespace pathOptimization
+  }  // namespace manipulation
+} // namespace hpp
diff --git a/src/problem-solver.cc b/src/problem-solver.cc
index 66c130e..7c7278c 100644
--- a/src/problem-solver.cc
+++ b/src/problem-solver.cc
@@ -48,6 +48,7 @@
 #include "hpp/manipulation/graph-steering-method.hh"
 #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/problem-target/state.hh"
 
 #if HPP_MANIPULATION_HAS_WHOLEBODY_STEP
@@ -100,6 +101,14 @@ namespace hpp {
           GraphConfigOptimizationTraits
             <pathOptimization::ConfigOptimizationTraits>
             >);
+
+      parent_t::add <PathOptimizerBuilder_t> ("SplineGradientBased_cannonical1",pathOptimization::SplineGradientBased<core::path::CanonicalPolynomeBasis, 1>::createFromCore);
+      parent_t::add <PathOptimizerBuilder_t> ("SplineGradientBased_cannonical2",pathOptimization::SplineGradientBased<core::path::CanonicalPolynomeBasis, 2>::createFromCore);
+      parent_t::add <PathOptimizerBuilder_t> ("SplineGradientBased_cannonical3",pathOptimization::SplineGradientBased<core::path::CanonicalPolynomeBasis, 3>::createFromCore);
+      parent_t::add <PathOptimizerBuilder_t> ("SplineGradientBased_bezier1",pathOptimization::SplineGradientBased<core::path::BernsteinBasis, 1>::createFromCore);
+      parent_t::add <PathOptimizerBuilder_t> ("SplineGradientBased_bezier2",pathOptimization::SplineGradientBased<core::path::BernsteinBasis, 2>::createFromCore);
+      parent_t::add <PathOptimizerBuilder_t> ("SplineGradientBased_bezier3",pathOptimization::SplineGradientBased<core::path::BernsteinBasis, 3>::createFromCore);
+
       using core::SteeringMethodBuilder_t;
       parent_t::add <SteeringMethodBuilder_t> ("Graph-SteeringMethodStraight",
           GraphSteeringMethod::create <core::SteeringMethodStraight>);
-- 
GitLab