bio_ik
MoveIt kinematics_base plugin based on particle optimization & GA
ik_cppoptlib.cpp
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2016-2017, Philipp Sebastian Ruppel
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include "ik_base.h"
36 
37 #include "cppoptlib/boundedproblem.h"
38 #include "cppoptlib/meta.h"
39 #include "cppoptlib/problem.h"
40 
41 namespace bio_ik
42 {
43 
44 /*
45 struct IKOptLibProblem : cppoptlib::Problem<double>
46 {
47  IKBase* ik;
48  std::vector<double> fk_values;
49  IKOptLibProblem(IKBase* ik) : ik(ik)
50  {
51  }
52  void initialize()
53  {
54  // set all variables to initial guess, including inactive ones
55  fk_values = ik->problem.initial_guess;
56  }
57  double value(const TVector& x)
58  {
59  // fill in active variables and compute fitness
60  for(size_t i = 0; i < ik->problem.active_variables.size(); i++) fk_values[ik->problem.active_variables[i]] = x[i];
61  return ik->computeFitness(fk_values);
62  }
63  bool callback(const cppoptlib::Criteria<double>& state, const TVector& x)
64  {
65  // check ik timeout
66  return ros::WallTime::now().toSec() < ik->problem.timeout;
67  }
68 };
69 */
70 
71 // problem description for cppoptlib
72 struct IKOptLibProblem : cppoptlib::BoundedProblem<double>
73 {
74  IKBase* ik;
75  std::vector<double> fk_values;
77  : cppoptlib::BoundedProblem<double>(TVector(ik->problem.active_variables.size()), TVector(ik->problem.active_variables.size()))
78  , ik(ik)
79  {
80  // init bounds
81  for(size_t i = 0; i < ik->problem.active_variables.size(); i++)
82  {
83  m_lowerBound[i] = ik->modelInfo.getMin(ik->problem.active_variables[i]);
84  m_upperBound[i] = ik->modelInfo.getMax(ik->problem.active_variables[i]);
85  // m_lowerBound[i] = fmax(m_lowerBound[i], -100);
86  // m_upperBound[i] = fmin(m_upperBound[i], 100);
87  }
88  }
89  void initialize()
90  {
91  // set all variables to initial guess, including inactive ones
92  fk_values = ik->problem.initial_guess;
93  }
94  double value(const TVector& x)
95  {
96  // fill in active variables and compute fitness
97  for(size_t i = 0; i < ik->problem.active_variables.size(); i++)
98  fk_values[ik->problem.active_variables[i]] = x[i];
99  // for(size_t i = 0; i < ik->active_variables.size(); i++) LOG(i, x[i]); LOG("");
100  // for(size_t i = 0; i < ik->active_variables.size(); i++) std::cerr << ((void*)*(uint64_t*)&x[i]) << " "; std::cerr << std::endl;
101  // size_t h = 0; for(size_t i = 0; i < ik->active_variables.size(); i++) h ^= (std::hash<double>()(x[i]) << i); LOG((void*)h);
102  return ik->computeFitness(fk_values);
103  }
104  bool callback(const cppoptlib::Criteria<double>& state, const TVector& x)
105  {
106  // check ik timeout
107  return ros::WallTime::now().toSec() < ik->problem.timeout;
108  }
109 };
110 
111 // ik solver using cppoptlib
112 template <class SOLVER, int reset_if_stuck, int threads> struct IKOptLib : IKBase
113 {
114  // current solution
115  std::vector<double> solution, best_solution, temp;
116 
117  // cppoptlib solver
118  std::shared_ptr<SOLVER> solver;
119 
120  // cppoptlib problem description
121  IKOptLibProblem f;
122 
123  // reset flag
124  bool reset;
125 
126  // stop criteria
127  cppoptlib::Criteria<double> crit;
128 
129  IKOptLib(const IKParams& p)
130  : IKBase(p)
131  , f(this)
132  {
133  }
134 
135  void initialize(const Problem& problem)
136  {
137  IKBase::initialize(problem);
138 
139  // set initial guess
140  solution = problem.initial_guess;
141 
142  // randomize if more than 1 thread
143  reset = false;
144  if(thread_index > 0) reset = true;
145 
146  // init best solution
147  best_solution = solution;
148 
149  // initialize cppoptlib problem description
150  f = IKOptLibProblem(this);
151  f.initialize();
152 
153  // init stop criteria (timeout will be handled explicitly)
154  crit = cppoptlib::Criteria<double>::defaults();
155  // crit.iterations = SIZE_MAX;
156  crit.gradNorm = 1e-10;
157  // p.node_handle.param("optlib_stop", crit.gradNorm, crit.gradNorm);
158 
159  if(!solver) solver = std::make_shared<SOLVER>();
160  }
161 
162  const std::vector<double>& getSolution() const { return best_solution; }
163 
164  void step()
165  {
166  // set stop criteria
167  solver->setStopCriteria(crit);
168 
169  // random reset if stuck (and if random resets are enabled)
170  if(reset)
171  {
172  // LOG("RESET");
173  reset = false;
174  for(auto& vi : problem.active_variables)
175  solution[vi] = random(modelInfo.getMin(vi), modelInfo.getMax(vi));
176  }
177 
178  // set to current positions
179  temp = solution;
180  typename SOLVER::TVector x(problem.active_variables.size());
181  for(size_t i = 0; i < problem.active_variables.size(); i++)
182  x[i] = temp[problem.active_variables[i]];
183 
184  // solve
185  solver->minimize(f, x);
186 
187  // get results
188  for(size_t i = 0; i < problem.active_variables.size(); i++)
189  temp[problem.active_variables[i]] = x[i];
190 
191  // update solution
192  if(computeFitness(temp) < computeFitness(solution))
193  {
194  solution = temp;
195  }
196  else
197  {
198  if(reset_if_stuck) reset = true;
199  }
200 
201  // update best solution
202  if(computeFitness(solution) < computeFitness(best_solution))
203  {
204  best_solution = solution;
205  }
206  }
207 
208  size_t concurrency() const { return threads; }
209 };
210 }
211 
212 static std::string mkoptname(std::string name, int reset, int threads)
213 {
214  name = "optlib_" + name;
215  if(reset) name += "_r";
216  if(threads > 1) name += "_" + std::to_string(threads);
217  return name;
218 }
219 
220 #define IKCPPOPTX(n, t, reset, threads) static bio_ik::IKFactory::Class<bio_ik::IKOptLib<cppoptlib::t<bio_ik::IKOptLibProblem>, reset, threads>> ik_optlib_##t##reset##threads(mkoptname(n, reset, threads));
221 
222 //#define IKCPPOPT(n, t) static bio_ik::IKFactory::Class<bio_ik::IKOptLib<cppoptlib::t<bio_ik::IKOptLibProblem>>> ik_optlib_##t(n)
223 
224 #define IKCPPOPT(n, t) \
225  IKCPPOPTX(n, t, 0, 1) \
226  IKCPPOPTX(n, t, 0, 2) \
227  IKCPPOPTX(n, t, 0, 4) \
228  IKCPPOPTX(n, t, 1, 1) \
229  IKCPPOPTX(n, t, 1, 2) \
230  IKCPPOPTX(n, t, 1, 4)
231 
232 #include "cppoptlib/solver/bfgssolver.h"
233 IKCPPOPT("bfgs", BfgsSolver);
234 
235 //#include "cppoptlib/solver/cmaesbsolver.h"
236 // IKCPPOPT("cmaesb", CMAesBSolver);
237 
238 //#include "cppoptlib/solver/cmaessolver.h"
239 // IKCPPOPT("cmaes", CMAesSolver);
240 
241 #include "cppoptlib/solver/conjugatedgradientdescentsolver.h"
242 IKCPPOPT("cgd", ConjugatedGradientDescentSolver);
243 
244 #include "cppoptlib/solver/gradientdescentsolver.h"
245 IKCPPOPT("gd", GradientDescentSolver);
246 
247 #include "cppoptlib/solver/lbfgsbsolver.h"
248 IKCPPOPT("lbfgsb", LbfgsbSolver);
249 
250 #include "cppoptlib/solver/lbfgssolver.h"
251 IKCPPOPT("lbfgs", LbfgsSolver);
252 
253 #include "cppoptlib/solver/neldermeadsolver.h"
254 IKCPPOPT("nm", NelderMeadSolver);
255 
256 #include "cppoptlib/solver/newtondescentsolver.h"
257 IKCPPOPT("nd", NewtonDescentSolver);