DMP_BBO library
Dmp.cpp
Go to the documentation of this file.
1 
24 #include <boost/serialization/export.hpp>
25 #include <boost/serialization/vector.hpp>
26 #include <boost/archive/text_iarchive.hpp>
27 #include <boost/archive/text_oarchive.hpp>
28 #include <boost/archive/xml_iarchive.hpp>
29 #include <boost/archive/xml_oarchive.hpp>
30 #include "dmp/Dmp.hpp"
31 
34 
35 #include <cmath>
36 #include <iostream>
37 #include <fstream>
38 #include <string>
39 #include <eigen3/Eigen/Core>
40 
41 #include "dmp/Trajectory.hpp"
47 
50 
51 
52 using namespace std;
53 using namespace Eigen;
54 
55 namespace DmpBbo {
56 
58 #define SPRING segment(0*dim_orig()+0,2*dim_orig())
59 
60 #define SPRING_Y segment(0*dim_orig()+0,dim_orig())
61 
62 #define SPRING_Z segment(1*dim_orig()+0,dim_orig())
63 
64 #define GOAL segment(2*dim_orig()+0,dim_orig())
65 
66 #define PHASE segment(3*dim_orig()+0, 1)
67 
68 #define GATING segment(3*dim_orig()+1, 1)
69 
71 #define SPRINGM(T) block(0,0*dim_orig()+0,T,2*dim_orig())
72 
73 #define SPRINGM_Y(T) block(0,0*dim_orig()+0,T,dim_orig())
74 
75 #define SPRINGM_Z(T) block(0,1*dim_orig()+0,T,dim_orig())
76 
77 #define GOALM(T) block(0,2*dim_orig()+0,T,dim_orig())
78 
79 #define PHASEM(T) block(0,3*dim_orig()+0,T, 1)
80 
81 #define GATINGM(T) block(0,3*dim_orig()+1,T, 1)
82 
83 boost::mt19937 Dmp::rng = boost::mt19937(getpid() + time(0));
84 
85 Dmp::Dmp(double tau, Eigen::VectorXd y_init, Eigen::VectorXd y_attr,
86  std::vector<FunctionApproximator*> function_approximators,
87  double alpha_spring_damper,
88  DynamicalSystem* goal_system,
89  DynamicalSystem* phase_system,
90  DynamicalSystem* gating_system,
91  ForcingTermScaling scaling)
92  : DynamicalSystem(1, tau, y_init, y_attr, "name"),
93  goal_system_(goal_system),
94  phase_system_(phase_system), gating_system_(gating_system),
95  forcing_term_scaling_(scaling)
96 {
97  initSubSystems(alpha_spring_damper, goal_system, phase_system, gating_system);
98  initFunctionApproximators(function_approximators);
99 }
100 
101 
102 Dmp::Dmp(int n_dims_dmp, std::vector<FunctionApproximator*> function_approximators,
103  double alpha_spring_damper, DynamicalSystem* goal_system,
104  DynamicalSystem* phase_system, DynamicalSystem* gating_system,
105  ForcingTermScaling scaling)
106  : DynamicalSystem(1, 1.0, VectorXd::Zero(n_dims_dmp), VectorXd::Ones(n_dims_dmp), "name"),
107  goal_system_(goal_system),
108  phase_system_(phase_system), gating_system_(gating_system),
109  forcing_term_scaling_(scaling)
110 {
111  initSubSystems(alpha_spring_damper, goal_system, phase_system, gating_system);
112  initFunctionApproximators(function_approximators);
113 }
114 
115 Dmp::Dmp(double tau, Eigen::VectorXd y_init, Eigen::VectorXd y_attr,
116  std::vector<FunctionApproximator*> function_approximators,
117  DmpType dmp_type,
118  ForcingTermScaling scaling)
119  : DynamicalSystem(1, tau, y_init, y_attr, "name"),
120  forcing_term_scaling_(scaling)
121 {
122  initSubSystems(dmp_type);
123  initFunctionApproximators(function_approximators);
124 }
125 
126 Dmp::Dmp(int n_dims_dmp,
127  std::vector<FunctionApproximator*> function_approximators,
128  DmpType dmp_type, ForcingTermScaling scaling)
129  : DynamicalSystem(1, 1.0, VectorXd::Zero(n_dims_dmp), VectorXd::Ones(n_dims_dmp), "name"),
130  forcing_term_scaling_(scaling)
131 {
132  initSubSystems(dmp_type);
133  initFunctionApproximators(function_approximators);
134 }
135 
136 Dmp::Dmp(double tau, Eigen::VectorXd y_init, Eigen::VectorXd y_attr, double alpha_spring_damper, DynamicalSystem* goal_system)
137  : DynamicalSystem(1, tau, y_init, y_attr, "name"), forcing_term_scaling_(NO_SCALING)
138 {
139 
140  VectorXd one_1 = VectorXd::Ones(1);
141  VectorXd one_0 = VectorXd::Zero(1);
142  DynamicalSystem* phase_system = new ExponentialSystem(tau,one_1,one_0,4);
143  DynamicalSystem* gating_system = new ExponentialSystem(tau,one_1,one_0,4);
144  initSubSystems(alpha_spring_damper, goal_system, phase_system, gating_system);
145 
146  vector<FunctionApproximator*> function_approximators(y_init.size());
147  for (int dd=0; dd<y_init.size(); dd++)
148  function_approximators[dd] = NULL;
149  initFunctionApproximators(function_approximators);
150 }
151 
152 void Dmp::initSubSystems(DmpType dmp_type)
153 {
154  VectorXd one_1 = VectorXd::Ones(1);
155  VectorXd one_0 = VectorXd::Zero(1);
156 
157  DynamicalSystem *goal_system=NULL;
158  DynamicalSystem *phase_system=NULL;
159  DynamicalSystem *gating_system=NULL;
160  if (dmp_type==IJSPEERT_2002_MOVEMENT)
161  {
162  goal_system = NULL;
163  phase_system = new ExponentialSystem(tau(),one_1,one_0,4);
164  gating_system = new ExponentialSystem(tau(),one_1,one_0,4);
165  }
166  else if (dmp_type==KULVICIUS_2012_JOINING || dmp_type==COUNTDOWN_2013)
167  {
168  goal_system = new ExponentialSystem(tau(),initial_state(),attractor_state(),15);
169  gating_system = new SigmoidSystem(tau(),one_1,-20,0.9*tau());
170  bool count_down = (dmp_type==COUNTDOWN_2013);
171  phase_system = new TimeSystem(tau(),count_down);
172  }
173 
174  double alpha_spring_damper = 20;
175 
176  initSubSystems(alpha_spring_damper, goal_system, phase_system, gating_system);
177 }
178 
179 void Dmp::initSubSystems(double alpha_spring_damper, DynamicalSystem* goal_system,
180  DynamicalSystem* phase_system, DynamicalSystem* gating_system)
181 {
182 
183  // Make room for the subsystems
184  set_dim(3*dim_orig()+2);
185 
186  spring_system_ = new SpringDamperSystem(tau(),initial_state(),attractor_state(),alpha_spring_damper);
187  spring_system_->set_name(name()+"_spring-damper");
188 
189  goal_system_ = goal_system;
190  if (goal_system!=NULL)
191  {
192  assert(goal_system->dim()==dim_orig());
193  // Initial state of the goal system is that same as that of the DMP
194  goal_system_->set_initial_state(initial_state());
195  goal_system_->set_name(name()+"_goal");
196  }
197 
198  phase_system_ = phase_system;
199  phase_system_->set_name(name()+"_phase");
200 
201  gating_system_ = gating_system;
202  gating_system_->set_name(name()+"_gating");
203 
204  // Pre-allocate memory for real-time execution
205  attractor_state_prealloc_ = VectorXd(dim_orig());
206  initial_state_prealloc_ = VectorXd(dim_orig());
207  fa_outputs_one_prealloc_ = MatrixXd(1,dim_orig());
208  fa_outputs_prealloc_ = MatrixXd(1,dim_orig());
209  fa_output_prealloc_ = MatrixXd(1,dim_orig());
210  forcing_term_prealloc_ = VectorXd(dim_orig());
211  g_minus_y0_prealloc_ = VectorXd(dim_orig());
212 
213 }
214 
215 void Dmp::set_damping_coefficient(double damping_coefficient)
216 {
217  spring_system_->set_damping_coefficient(damping_coefficient);
218 }
219 void Dmp::set_spring_constant(double spring_constant) {
220  spring_system_->set_spring_constant(spring_constant);
221 }
222 
223 
224 void Dmp::initFunctionApproximators(vector<FunctionApproximator*> function_approximators)
225 {
226  if (function_approximators.empty())
227  return;
228 
229  assert(dim_orig()==(int)function_approximators.size());
230 
231  function_approximators_ = vector<FunctionApproximator*>(function_approximators.size());
232  for (unsigned int dd=0; dd<function_approximators.size(); dd++)
233  {
234  if (function_approximators[dd]==NULL)
235  function_approximators_[dd] = NULL;
236  else
237  function_approximators_[dd] = function_approximators[dd]->clone();
238  }
239 
240 }
241 
243 {
244  delete goal_system_;
245  delete spring_system_;
246  delete phase_system_;
247  delete gating_system_;
248  for (unsigned int ff=0; ff<function_approximators_.size(); ff++)
249  delete (function_approximators_[ff]);
250 }
251 
252 Dmp* Dmp::clone(void) const {
253  vector<FunctionApproximator*> function_approximators;
254  for (unsigned int ff=0; ff<function_approximators_.size(); ff++)
255  function_approximators.push_back(function_approximators_[ff]->clone());
256 
257  return new Dmp(tau(), initial_state(), attractor_state(), function_approximators,
258  spring_system_->damping_coefficient(), goal_system_->clone(),
259  phase_system_->clone(), gating_system_->clone());
260 }
261 
262 
263 void Dmp::integrateStart(Ref<VectorXd> x, Ref<VectorXd> xd) const
264 {
265  assert(x.size()==dim());
266  assert(xd.size()==dim());
267 
268  x.fill(0);
269  xd.fill(0);
270 
271  // Start integrating goal system if it exists
272  if (goal_system_==NULL)
273  {
274  // No goal system, simply set goal state to attractor state
275  x.GOAL = attractor_state();
276  xd.GOAL.fill(0);
277  }
278  else
279  {
280  // Goal system exists. Start integrating it.
281  goal_system_->integrateStart(x.GOAL,xd.GOAL);
282  }
283 
284 
285  // Set the attractor state of the spring system
286  spring_system_->set_attractor_state(x.GOAL);
287 
288  // Start integrating all futher subsystems
289  spring_system_->integrateStart(x.SPRING, xd.SPRING);
290  phase_system_->integrateStart( x.PHASE, xd.PHASE);
291  gating_system_->integrateStart(x.GATING, xd.GATING);
292 
293  // Add rates of change
294  differentialEquation(x,xd);
295 
296 }
297 
298 /*
299 bool Dmp::isTrained(void) const
300 {
301  for (int i_dim=0; i_dim<dim_orig(); i_dim++)
302  if (function_approximators_[i_dim]!=NULL)
303  return false;
304 
305  for (int i_dim=0; i_dim<dim_orig(); i_dim++)
306  if (function_approximators_[i_dim]->isTrained())
307  return false;
308 
309  return true;
310 }
311 */
312 
313 void Dmp::computeFunctionApproximatorOutput(const Ref<const MatrixXd>& phase_state, MatrixXd& fa_output) const
314 {
315  int T = phase_state.rows();
316  fa_output.resize(T,dim_orig());
317  fa_output.fill(0.0);
318 
319  if (T>1) {
320  fa_outputs_prealloc_.resize(T,dim_orig());
321  }
322 
323  for (int i_dim=0; i_dim<dim_orig(); i_dim++)
324  {
325  if (function_approximators_[i_dim]!=NULL)
326  {
327  if (function_approximators_[i_dim]->isTrained())
328  {
329  if (T==1)
330  {
331  function_approximators_[i_dim]->predict(phase_state,fa_outputs_one_prealloc_);
332  fa_output.col(i_dim) = fa_outputs_one_prealloc_;
333  }
334  else
335  {
336  function_approximators_[i_dim]->predict(phase_state,fa_outputs_prealloc_);
337  fa_output.col(i_dim) = fa_outputs_prealloc_;
338  }
339  }
340  }
341  }
342 }
343 
345  const Eigen::Ref<const Eigen::VectorXd>& x,
346  Eigen::Ref<Eigen::VectorXd> xd) const
347 {
348 
349  ENTERING_REAL_TIME_CRITICAL_CODE
350 
351  attractor_state(attractor_state_prealloc_);
352  if (goal_system_==NULL)
353  {
354  // If there is no dynamical system for the delayed goal, the goal is
355  // simply the attractor state
356  spring_system_->set_attractor_state(attractor_state_prealloc_);
357  // with zero change
358  xd.GOAL.fill(0);
359  }
360  else
361  {
362  // Integrate goal system and get current goal state
363  goal_system_->set_attractor_state(attractor_state_prealloc_);
364  goal_system_->differentialEquation(x.GOAL, xd.GOAL);
365  // The goal state is the attractor state of the spring-damper system
366  spring_system_->set_attractor_state(x.GOAL);
367 
368  }
369 
370 
371  // Integrate spring damper system
372  // Forcing term is added to spring_state later
373  spring_system_->differentialEquation(x.SPRING, xd.SPRING);
374 
375 
376  // Non-linear forcing term
377  phase_system_->differentialEquation(x.PHASE, xd.PHASE);
378  gating_system_->differentialEquation(x.GATING, xd.GATING);
379 
380 
381  //MatrixXd phase_state(1,1);
382  //phase_state = x.PHASE;
383  computeFunctionApproximatorOutput(x.PHASE, fa_output_prealloc_);
384 
385  // Gate the output of the function approximators
386  int t0 = 0;
387  double gating = (x.GATING)[0];
388  forcing_term_prealloc_ = gating*fa_output_prealloc_.row(t0);
389 
390 
391  // Scale the forcing term, if necessary
392  if (forcing_term_scaling_==G_MINUS_Y0_SCALING)
393  {
394  initial_state(initial_state_prealloc_);
395  g_minus_y0_prealloc_ = (attractor_state_prealloc_-initial_state_prealloc_).transpose();
396  forcing_term_prealloc_ = forcing_term_prealloc_.array()*g_minus_y0_prealloc_.array();
397  }
398  else if (forcing_term_scaling_==AMPLITUDE_SCALING)
399  {
400  forcing_term_prealloc_ = forcing_term_prealloc_.array()*trajectory_amplitudes_.array();
401  }
402 
403  // Add forcing term to the ZD component of the spring state
404  xd.SPRING_Z = xd.SPRING_Z + forcing_term_prealloc_/tau();
405 
406  EXITING_REAL_TIME_CRITICAL_CODE
407 
408 }
409 
410 void Dmp::statesAsTrajectory(const Eigen::MatrixXd& x_in, const Eigen::MatrixXd& xd_in, Eigen::MatrixXd& y_out, Eigen::MatrixXd& yd_out, Eigen::MatrixXd& ydd_out) const
411 {
412  int n_time_steps = x_in.rows();
413  y_out = x_in.SPRINGM_Y(n_time_steps);
414  yd_out = xd_in.SPRINGM_Y(n_time_steps);
415  ydd_out = xd_in.SPRINGM_Z(n_time_steps)/tau();
416  // MatrixXd z_out, zd_out;
417  // z_out = x_in.SPRINGM_Z(n_time_steps);
418  // zd_out = xd_in.SPRINGM_Z(n_time_steps);
419  // Divide by tau to go from z to y space
420  // yd = z_out/obj.tau;
421  // ydd_out = zd_out/tau();
422 }
423 
424 
425 void Dmp::statesAsTrajectory(const Eigen::VectorXd& ts, const Eigen::MatrixXd& x_in, const Eigen::MatrixXd& xd_in, Trajectory& trajectory) const {
426  int n_time_steps = ts.rows();
427 #ifndef NDEBUG // Variables below are only required for asserts; check for NDEBUG to avoid warnings.
428  int n_dims = x_in.cols();
429 #endif
430  assert(n_time_steps==x_in.rows());
431  assert(n_time_steps==xd_in.rows());
432  assert(n_dims==xd_in.cols());
433 
434  // Left column is time
435  Trajectory new_trajectory(
436  ts,
437  // y_out (see function above)
438  x_in.SPRINGM_Y(n_time_steps),
439  // yd_out (see function above)
440  xd_in.SPRINGM_Y(n_time_steps),
441  // ydd_out (see function above)
442  xd_in.SPRINGM_Z(n_time_steps)/tau()
443  );
444 
445  trajectory = new_trajectory;
446 
447 }
448 
449 void Dmp::analyticalSolution(const Eigen::VectorXd& ts, Eigen::MatrixXd& xs, Eigen::MatrixXd& xds, Eigen::MatrixXd& forcing_terms, Eigen::MatrixXd& fa_outputs) const
450 {
451  int n_time_steps = ts.size();
452  assert(n_time_steps>0);
453 
454  // Usually, we expect xs and xds to be of size T X dim(), so we resize to that. However, if the
455  // input matrices were of size dim() X T, we return the matrices of that size by doing a
456  // transposeInPlace at the end. That way, the user can also request dim() X T sized matrices.
457  bool caller_expects_transposed = (xs.rows()==dim() && xs.cols()==n_time_steps);
458 
459  // INTEGRATE SYSTEMS ANALYTICALLY AS MUCH AS POSSIBLE
460 
461  // Integrate phase
462  MatrixXd xs_phase;
463  MatrixXd xds_phase;
464  phase_system_->analyticalSolution(ts,xs_phase,xds_phase);
465 
466  // Compute gating term
467  MatrixXd xs_gating;
468  MatrixXd xds_gating;
469  gating_system_->analyticalSolution(ts,xs_gating,xds_gating);
470 
471  // Compute the output of the function approximator
472  fa_outputs.resize(ts.size(),dim_orig());
473  fa_outputs.fill(0.0);
474  //if (isTrained())
475  computeFunctionApproximatorOutput(xs_phase, fa_outputs);
476 
477  // Gate the output to get the forcing term
478  MatrixXd xs_gating_rep = xs_gating.replicate(1,fa_outputs.cols());
479  forcing_terms = fa_outputs.array()*xs_gating_rep.array();
480 
481  // Scale the forcing term, if necessary
482  if (forcing_term_scaling_==G_MINUS_Y0_SCALING)
483  {
484  MatrixXd g_minus_y0_rep = (attractor_state()-initial_state()).transpose().replicate(n_time_steps,1);
485  forcing_terms = forcing_terms.array()*g_minus_y0_rep.array();
486  }
487  else if (forcing_term_scaling_==AMPLITUDE_SCALING)
488  {
489  MatrixXd trajectory_amplitudes_rep = trajectory_amplitudes_.transpose().replicate(n_time_steps,1);
490  forcing_terms = forcing_terms.array()*trajectory_amplitudes_rep.array();
491  }
492 
493 
494  MatrixXd xs_goal, xds_goal;
495  // Get current delayed goal
496  if (goal_system_==NULL)
497  {
498  // If there is no dynamical system for the delayed goal, the goal is
499  // simply the attractor state
500  xs_goal = attractor_state().transpose().replicate(n_time_steps,1);
501  // with zero change
502  xds_goal = MatrixXd::Zero(n_time_steps,dim_orig());
503  }
504  else
505  {
506  // Integrate goal system and get current goal state
507  goal_system_->analyticalSolution(ts,xs_goal,xds_goal);
508  }
509 
510  xs.resize(n_time_steps,dim());
511  xds.resize(n_time_steps,dim());
512 
513  int T = n_time_steps;
514 
515  xs.GOALM(T) = xs_goal; xds.GOALM(T) = xds_goal;
516  xs.PHASEM(T) = xs_phase; xds.PHASEM(T) = xds_phase;
517  xs.GATINGM(T) = xs_gating; xds.GATINGM(T) = xds_gating;
518 
519 
520  // THE REST CANNOT BE DONE ANALYTICALLY
521 
522  // Reset the dynamical system, and get the first state
523  double damping = spring_system_->damping_coefficient();
524  SpringDamperSystem localspring_system_(tau(),initial_state(),attractor_state(),damping);
525 
526  // Set first attractor state
527  localspring_system_.set_attractor_state(xs_goal.row(0));
528 
529  // Start integrating spring damper system
530  int dim_spring = localspring_system_.dim();
531  VectorXd x_spring(dim_spring), xd_spring(dim_spring); // todo Why are these needed?
532  int t0 = 0;
533  localspring_system_.integrateStart(x_spring, xd_spring);
534  xs.row(t0).SPRING = x_spring;
535  xds.row(t0).SPRING = xd_spring;
536 
537  // Add forcing term to the acceleration of the spring state
538  xds.SPRINGM_Z(1) = xds.SPRINGM_Z(1) + forcing_terms.row(t0)/tau();
539 
540  // Initialize perturber, if necessary
541  if (analytical_solution_perturber_==NULL && perturbation_standard_deviation_>0.0)
542  {
543  boost::normal_distribution<> normal(0, perturbation_standard_deviation_);
544  analytical_solution_perturber_ = new boost::variate_generator<boost::mt19937&, boost::normal_distribution<> >(rng, normal);
545  }
546 
547 
548  for (int tt=1; tt<n_time_steps; tt++)
549  {
550  double dt = ts[tt]-ts[tt-1];
551 
552  // Euler integration
553  xs.row(tt).SPRING = xs.row(tt-1).SPRING + dt*xds.row(tt-1).SPRING;
554 
555  // Set the attractor state of the spring system
556  localspring_system_.set_attractor_state(xs.row(tt).GOAL);
557 
558  // Integrate spring damper system
559  localspring_system_.differentialEquation(xs.row(tt).SPRING, xd_spring);
560  xds.row(tt).SPRING = xd_spring;
561 
562  // If necessary add a perturbation. May be useful for some off-line tests.
563  RowVectorXd perturbation = RowVectorXd::Constant(dim_orig(),0.0);
564  if (analytical_solution_perturber_!=NULL)
565  for (int i_dim=0; i_dim<dim_orig(); i_dim++)
566  // Sample perturbation from a normal Gaussian distribution
567  perturbation(i_dim) = (*analytical_solution_perturber_)();
568 
569  // Add forcing term to the acceleration of the spring state
570  xds.row(tt).SPRING_Z = xds.row(tt).SPRING_Z + forcing_terms.row(tt)/tau() + perturbation;
571  // Compute y component from z
572  xds.row(tt).SPRING_Y = xs.row(tt).SPRING_Z/tau();
573 
574  }
575 
576  if (caller_expects_transposed)
577  {
578  xs.transposeInPlace();
579  xds.transposeInPlace();
580  }
581 }
582 
583 void Dmp::computeFunctionApproximatorInputsAndTargets(const Trajectory& trajectory, VectorXd& fa_inputs_phase, MatrixXd& f_target) const
584 {
585  int n_time_steps = trajectory.length();
586  double dim_data = trajectory.dim();
587 
588  if (dim_orig()!=dim_data)
589  {
590  cout << "WARNING: Cannot train " << dim_orig() << "-D DMP with " << dim_data << "-D data. Doing nothing." << endl;
591  return;
592  }
593 
594  // Integrate analytically to get goal, gating and phase states
595  MatrixXd xs_ana;
596  MatrixXd xds_ana;
597 
598  // Before, we would make clone of the dmp, and integrate it with the tau, and initial/attractor
599  // state of the trajectory. However, Thibaut needed to call this from outside the Dmp as well,
600  // with the tau/states of the this object. Therefore, we no longer clone.
601  // Dmp* dmp_clone = static_cast<Dmp*>(this->clone());
602  // dmp_clone->set_tau(trajectory.duration());
603  // dmp_clone->set_initial_state(trajectory.initial_y());
604  // dmp_clone->set_attractor_state(trajectory.final_y());
605  // dmp_clone->analyticalSolution(trajectory.ts(),xs_ana,xds_ana);
606  analyticalSolution(trajectory.ts(),xs_ana,xds_ana);
607  MatrixXd xs_goal = xs_ana.GOALM(n_time_steps);
608  MatrixXd xs_gating = xs_ana.GATINGM(n_time_steps);
609  MatrixXd xs_phase = xs_ana.PHASEM(n_time_steps);
610 
611  fa_inputs_phase = xs_phase;
612 
613  // Get parameters from the spring-dampers system to compute inverse
614  double damping_coefficient = spring_system_->damping_coefficient();
615  double spring_constant = spring_system_->spring_constant();
616  double mass = spring_system_->mass();
617  if (mass!=1.0)
618  {
619  cout << "WARNING: Usually, spring-damper system of the DMP should have mass==1, but it is " << mass << endl;
620  }
621 
622  // Compute inverse
623  f_target = tau()*tau()*trajectory.ydds() + (spring_constant*(trajectory.ys()-xs_goal) + damping_coefficient*tau()*trajectory.yds())/mass;
624 
625  //Factor out gating term
626  for (unsigned int dd=0; dd<function_approximators_.size(); dd++)
627  f_target.col(dd) = f_target.col(dd).array()/xs_gating.array();
628 
629  // Factor out scaling
630  if (forcing_term_scaling_==G_MINUS_Y0_SCALING)
631  {
632  MatrixXd g_minus_y0_rep = (attractor_state()-initial_state()).transpose().replicate(n_time_steps,1);
633  f_target = f_target.array()/g_minus_y0_rep.array();
634  }
635  else if (forcing_term_scaling_==AMPLITUDE_SCALING)
636  {
637  MatrixXd trajectory_amplitudes_rep = trajectory_amplitudes_.transpose().replicate(n_time_steps,1);
638  f_target = f_target.array()/trajectory_amplitudes_rep.array();
639  }
640 
641 }
642 
643 void Dmp::train(const Trajectory& trajectory)
644 {
645  train(trajectory,"");
646 }
647 
648 void Dmp::train(const Trajectory& trajectory, std::string save_directory, bool overwrite)
649 {
650 
651  // Set tau, initial_state and attractor_state from the trajectory
652  set_tau(trajectory.duration());
653  set_initial_state(trajectory.initial_y());
654  set_attractor_state(trajectory.final_y());
655 
656  // This needs to be computed for (optional) scaling of the forcing term.
657  // Needs to be done BEFORE computeFunctionApproximatorInputsAndTargets
658  trajectory_amplitudes_ = trajectory.getRangePerDim();
659 
660  VectorXd fa_input_phase;
661  MatrixXd f_target;
662  computeFunctionApproximatorInputsAndTargets(trajectory, fa_input_phase, f_target);
663 
664  // Some checks before training function approximators
665  assert(!function_approximators_.empty());
666 
667  for (unsigned int dd=0; dd<function_approximators_.size(); dd++)
668  {
669  // This is just boring stuff to figure out if and where to store the results of training
670  string save_directory_dim;
671  if (!save_directory.empty())
672  {
673  if (function_approximators_.size()==1)
674  save_directory_dim = save_directory;
675  else
676  save_directory_dim = save_directory + "/dim" + to_string(dd);
677  }
678 
679  // Actual training is happening here.
680  VectorXd fa_target = f_target.col(dd);
681  if (function_approximators_[dd]==NULL)
682  {
683  cerr << __FILE__ << ":" << __LINE__ << ":";
684  cerr << "WARNING: function approximator cannot be trained because it is NULL." << endl;
685  }
686  else
687  {
688  if (function_approximators_[dd]->isTrained())
689  function_approximators_[dd]->reTrain(fa_input_phase,fa_target,save_directory_dim,overwrite);
690  else
691  function_approximators_[dd]->train(fa_input_phase,fa_target,save_directory_dim,overwrite);
692  }
693  }
694 
695  if (!save_directory.empty())
696  {
697  int n_time_steps = 101;
698  VectorXd ts = VectorXd::LinSpaced(n_time_steps,0,tau());
699  Trajectory traj_reproduced;
700  analyticalSolution(ts,traj_reproduced);
701 
702  trajectory.saveToFile(save_directory,"traj_demonstration.txt",overwrite);
703  traj_reproduced.saveToFile(save_directory,"traj_reproduced.txt",overwrite);
704  }
705 
706 }
707 
708 void Dmp::getSelectableParameters(set<string>& selectable_values_labels) const {
709  assert(function_approximators_.size()>0);
710  for (int dd=0; dd<dim_orig(); dd++)
711  {
712  if (function_approximators_[dd]!=NULL)
713  {
714  if (function_approximators_[dd]->isTrained())
715  {
716  set<string> cur_labels;
717  function_approximators_[dd]->getSelectableParameters(cur_labels);
718  selectable_values_labels.insert(cur_labels.begin(), cur_labels.end());
719  }
720  }
721  }
722  selectable_values_labels.insert("goal");
723 
724  //cout << "selected_values_labels=[";
725  //for (string label : selected_values_labels)
726  // cout << label << " ";
727  //cout << "]" << endl;
728 
729 }
730 
731 void Dmp::setSelectedParameters(const set<string>& selected_values_labels)
732 {
733  assert(function_approximators_.size()>0);
734  for (int dd=0; dd<dim_orig(); dd++)
735  if (function_approximators_[dd]!=NULL)
736  if (function_approximators_[dd]->isTrained())
737  function_approximators_[dd]->setSelectedParameters(selected_values_labels);
738 
739  // Call superclass for initializations
740  Parameterizable::setSelectedParameters(selected_values_labels);
741 
742  VectorXi lengths_per_dimension = VectorXi::Zero(dim_orig());
743  for (int dd=0; dd<dim_orig(); dd++)
744  {
745  if (function_approximators_[dd]!=NULL)
746  if (function_approximators_[dd]->isTrained())
747  lengths_per_dimension[dd] = function_approximators_[dd]->getParameterVectorSelectedSize();
748 
749  if (selected_values_labels.find("goal")!=selected_values_labels.end())
750  lengths_per_dimension[dd]++;
751  }
752 
753  setVectorLengthsPerDimension(lengths_per_dimension);
754 
755 }
756 
757 void Dmp::getParameterVectorMask(const std::set<std::string> selected_values_labels, Eigen::VectorXi& selected_mask) const
758 {
759  assert(function_approximators_.size()>0);
760  for (int dd=0; dd<dim_orig(); dd++)
761  {
762  assert(function_approximators_[dd]!=NULL);
763  assert(function_approximators_[dd]->isTrained());
764  }
765 
766  selected_mask.resize(getParameterVectorAllSize());
767  selected_mask.fill(0);
768 
769  const int TMP_GOAL_NUMBER = -1;
770  int offset = 0;
771  VectorXi cur_mask;
772  for (int dd=0; dd<dim_orig(); dd++)
773  {
774  function_approximators_[dd]->getParameterVectorMask(selected_values_labels,cur_mask);
775 
776  // This makes sure that the indices for each function approximator are different
777  int mask_offset = selected_mask.maxCoeff();
778  for (int ii=0; ii<cur_mask.size(); ii++)
779  if (cur_mask[ii]!=0)
780  cur_mask[ii] += mask_offset;
781 
782  selected_mask.segment(offset,cur_mask.size()) = cur_mask;
783  offset += cur_mask.size();
784 
785  // Goal
786  if (selected_values_labels.find("goal")!=selected_values_labels.end())
787  selected_mask(offset) = TMP_GOAL_NUMBER;
788  offset++;
789 
790  }
791  assert(offset == getParameterVectorAllSize());
792 
793  // Replace TMP_GOAL_NUMBER with current max value
794  int goal_number = selected_mask.maxCoeff() + 1;
795  for (int ii=0; ii<selected_mask.size(); ii++)
796  if (selected_mask[ii]==TMP_GOAL_NUMBER)
797  selected_mask[ii] = goal_number;
798 
799 }
800 
802 {
803  int total_size = 0;
804  for (unsigned int dd=0; dd<function_approximators_.size(); dd++)
805  total_size += function_approximators_[dd]->getParameterVectorAllSize();
806 
807  // For the goal
808  total_size += dim_orig();
809  return total_size;
810 }
811 
812 
813 void Dmp::getParameterVectorAll(VectorXd& values) const
814 {
815  values.resize(getParameterVectorAllSize());
816  int offset = 0;
817  VectorXd cur_values;
818  VectorXd attractor = attractor_state();
819  for (int dd=0; dd<dim_orig(); dd++)
820  {
821  function_approximators_[dd]->getParameterVectorAll(cur_values);
822  values.segment(offset,cur_values.size()) = cur_values;
823  offset += cur_values.size();
824 
825  values(offset) = attractor(dd);
826  offset++;
827  }
828 }
829 
830 void Dmp::setParameterVectorAll(const VectorXd& values)
831 {
832  assert(values.size()==getParameterVectorAllSize());
833  int offset = 0;
834  VectorXd cur_values;
835  VectorXd attractor(dim_orig());
836  for (int dd=0; dd<dim_orig(); dd++)
837  {
838  int n_parameters_required = function_approximators_[dd]->getParameterVectorAllSize();
839  cur_values = values.segment(offset,n_parameters_required);
840  function_approximators_[dd]->setParameterVectorAll(cur_values);
841  offset += n_parameters_required;
842 
843  attractor(dd) = values(offset);
844  offset += 1;
845  }
846 
847  // Set the goal
848  set_attractor_state(attractor);
849 }
850 
851 
852 
853 void Dmp::set_tau(double tau) {
855 
856  // Set value in all relevant subsystems also
857  spring_system_->set_tau(tau);
858  if (goal_system_!=NULL)
859  goal_system_->set_tau(tau);
860  phase_system_ ->set_tau(tau);
861  gating_system_->set_tau(tau);
862 }
863 
864 void Dmp::set_initial_state(const VectorXd& y_init) {
866 
867  // Set value in all relevant subsystems also
868  spring_system_->set_initial_state(y_init);
869  if (goal_system_!=NULL)
870  goal_system_->set_initial_state(y_init);
871 }
872 
873 void Dmp::set_attractor_state(const VectorXd& y_attr) {
875 
876  // Set value in all relevant subsystems also
877  if (goal_system_!=NULL)
878  goal_system_->set_attractor_state(y_attr);
879 
880  // Do NOT do the following. The attractor state of the spring system is determined by the goal
881  // system
882  // spring_system_->set_attractor_state(y_attr);
883 
884 }
885 
886 void Dmp::set_perturbation_analytical_solution(double perturbation_standard_deviation)
887 {
888  perturbation_standard_deviation_ = perturbation_standard_deviation;
889  analytical_solution_perturber_ = NULL;
890 }
891 
892 
893 string Dmp::toString(void) const
894 {
896 }
897 
898 
899 template<class Archive>
900 void Dmp::serialize(Archive & ar, const unsigned int version)
901 {
902  // serialize base class information
903  ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(DynamicalSystem);
904  ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Parameterizable);
905 
906  ar & BOOST_SERIALIZATION_NVP(goal_system_);
907  ar & BOOST_SERIALIZATION_NVP(spring_system_);
908  ar & BOOST_SERIALIZATION_NVP(phase_system_);
909  ar & BOOST_SERIALIZATION_NVP(gating_system_);
910  ar & BOOST_SERIALIZATION_NVP(function_approximators_);
911 
912  ar & BOOST_SERIALIZATION_NVP(forcing_term_scaling_);
913  ar & BOOST_SERIALIZATION_NVP(trajectory_amplitudes_);
914 
915  ar & BOOST_SERIALIZATION_NVP(perturbation_standard_deviation_);
916 }
917 
918 }
double tau(void) const
Accessor function for the time constant.
void getParameterVectorMask(const std::set< std::string > selected_values_labels, Eigen::VectorXi &selected_mask) const
Get a mask for selecting parameters.
Definition: Dmp.cpp:757
void set_damping_coefficient(double damping_coefficient)
Accessor function for damping coefficient.
const Eigen::VectorXd & ts(void) const
Accessor function for the times at which measurements were made.
Definition: Trajectory.hpp:67
void setVectorLengthsPerDimension(const Eigen::VectorXi &lengths_per_dimension)
The vector (VectorXd) with parameter values can be split into different parts (as vector<VectorXd>; t...
void set_dim(int dim)
Set the dimensionality of the dynamical system, i.e.
virtual void set_attractor_state(const Eigen::VectorXd &y_attr)
Accessor function for the attractor state of the system.
Definition: Dmp.cpp:873
void getParameterVectorAll(Eigen::VectorXd &values) const
Return a vector that returns all available parameter values.
Definition: Dmp.cpp:813
virtual void analyticalSolution(const Eigen::VectorXd &ts, Eigen::MatrixXd &xs, Eigen::MatrixXd &xds) const =0
Return analytical solution of the system at certain times.
virtual void set_attractor_state(const Eigen::Ref< const Eigen::VectorXd > &attractor_state)
Mutator function for the attractor state of the dynamical system.
Trajectory class header file.
Implementation of Dynamical Movement Primitives.
Definition: Dmp.hpp:56
int dim_orig(void) const
Get the dimensionality of the dynamical system, i.e.
FunctionApproximator class header file.
virtual void set_tau(double tau)
Accessor function for the time constant.
Definition: Dmp.cpp:853
void set_spring_constant(double spring_constant)
Accessor function for spring constant.
SpringDamperSystem class header file.
void computeFunctionApproximatorInputsAndTargets(const Trajectory &trajectory, Eigen::VectorXd &fa_inputs_phase, Eigen::MatrixXd &fa_targets) const
Given a trajectory, compute the inputs and targets for the function approximators.
Definition: Dmp.cpp:583
ExponentialSystem class header file.
const Eigen::MatrixXd & ys(void) const
Accessor function for the positions at different times.
Definition: Trajectory.hpp:72
double duration(void) const
Get the duration of the trajectory in seconds.
Definition: Trajectory.hpp:106
Dmp class header file.
A class for storing trajectories: positions, velocities and accelerations of variables over time...
Definition: Trajectory.hpp:48
const Eigen::MatrixXd & ydds(void) const
Accessor function for the accelerations at different times.
Definition: Trajectory.hpp:82
Eigen::VectorXd initial_state(void) const
Accessor function for the initial state of the dynamical system.
Dynamical System modelling the evolution of a sigmoidal system .
virtual void statesAsTrajectory(const Eigen::MatrixXd &x_in, const Eigen::MatrixXd &xd_in, Eigen::MatrixXd &y_out, Eigen::MatrixXd &yd_out, Eigen::MatrixXd &ydd_out) const
Get the output of a DMP dynamical system as a trajectory.
Definition: Dmp.cpp:410
Class for providing access to a model&#39;s parameters as a vector.
Eigen::VectorXd final_y(void) const
Get the last state, i.e.
Definition: Trajectory.hpp:126
Dynamical System modelling the evolution of a time: .
Definition: TimeSystem.hpp:40
virtual void set_initial_state(const Eigen::VectorXd &initial_state)
Mutator function for the initial state of the dynamical system.
int getParameterVectorAllSize(void) const
Get the size of the parameter values vector when it contains all available parameter values...
Definition: Dmp.cpp:801
int dim(void) const
Get the dimensionality of the dynamical system, i.e.
double damping_coefficient(void)
Accessor function for damping coefficient.
TimeSystem class header file.
#define RETURN_STRING_FROM_BOOST_SERIALIZATION_XML(name)
Macro to convert the boost XML serialization of an object into a string.
int length(void) const
Get the length of the trajectory, i.e.
Definition: Trajectory.hpp:101
Dynamical System modelling the evolution of an exponential system: .
void differentialEquation(const Eigen::Ref< const Eigen::VectorXd > &x, Eigen::Ref< Eigen::VectorXd > xd) const
The differential equation which defines the system.
Definition: Dmp.cpp:344
virtual DynamicalSystem * clone(void) const =0
Return a pointer to a deep copy of the DynamicalSystem object.
void setSelectedParameters(const std::set< std::string > &selected_values_labels)
Determine which subset of parameters is represented in the vector returned by Parameterizable::getPar...
Definition: Dmp.cpp:731
Eigen::VectorXd getRangePerDim(void) const
Get the range of ys per dimension.
Definition: Trajectory.cpp:135
DmpType
Different types of DMPs that can be initialized.
Definition: Dmp.hpp:61
int dim(void) const
Get the dimensionality of the trajectory.
Definition: Trajectory.hpp:111
virtual void differentialEquation(const Eigen::Ref< const Eigen::VectorXd > &x, Eigen::Ref< Eigen::VectorXd > xd) const =0
The differential equation which defines the system.
virtual void train(const Trajectory &trajectory)
Train a DMP with a trajectory.
Definition: Dmp.cpp:643
const Eigen::MatrixXd & yds(void) const
Accessor function for the velocities at different times.
Definition: Trajectory.hpp:77
virtual void computeFunctionApproximatorOutput(const Eigen::Ref< const Eigen::MatrixXd > &phase_state, Eigen::MatrixXd &fa_output) const
Compute the outputs of the function approximators.
Definition: Dmp.cpp:313
std::string name(void) const
Accessor function for the name of the dynamical system.
BOOST_CLASS_EXPORT_IMPLEMENT(DmpBbo::Dmp)
For boost::serialization.
Dmp * clone(void) const
Return a deep copy of this object.
Definition: Dmp.cpp:252
void differentialEquation(const Eigen::Ref< const Eigen::VectorXd > &x, Eigen::Ref< Eigen::VectorXd > xd) const
The differential equation which defines the system.
void setParameterVectorAll(const Eigen::VectorXd &values)
Set all available parameter values with one vector.
Definition: Dmp.cpp:830
Interface for implementing dynamical systems.
virtual void setSelectedParameters(const std::set< std::string > &selected_values_labels)
Determine which subset of parameters is represented in the vector returned by Parameterizable::getPar...
virtual void integrateStart(Eigen::Ref< Eigen::VectorXd > x, Eigen::Ref< Eigen::VectorXd > xd) const
Start integrating the system.
Eigen::VectorXd initial_y(void) const
Get the first state, i.e.
Definition: Trajectory.hpp:121
SigmoidSystem class header file.
virtual void set_name(std::string name)
Mutator function for the name of the dynamical system.
Eigen::VectorXd attractor_state(void) const
Accessor function for the attractor state of the dynamical system.
double mass(void)
Accessor function for mass.
virtual int getParameterVectorSelectedSize(void) const
Get the size of the vector of selected parameters, as returned by getParameterVectorSelected(.
void set_spring_constant(double spring_constant)
Accessor function for spring constant of spring-damper system.
Definition: Dmp.cpp:219
ForcingTermScaling
Different ways to scale the forcing term.
Definition: Dmp.hpp:64
virtual void integrateStart(Eigen::Ref< Eigen::VectorXd > x, Eigen::Ref< Eigen::VectorXd > xd) const
Start integrating the system.
Definition: Dmp.cpp:263
void set_perturbation_analytical_solution(double perturbation_standard_deviation)
Add a perturbation to the forcing term when computing the analytical solution.
Definition: Dmp.cpp:886
Header file to generate strings from boost serialized files.
virtual void set_tau(double tau)
Mutator function for the time constant.
virtual void set_initial_state(const Eigen::VectorXd &y_init)
Accessor function for the initial state of the system.
Definition: Dmp.cpp:864
std::string toString(void) const
Returns a string representation of the object.
Definition: Dmp.cpp:893
Dynamical System modelling the evolution of a spring-damper system: .
void analyticalSolution(const Eigen::VectorXd &ts, Eigen::MatrixXd &xs, Eigen::MatrixXd &xds, Eigen::MatrixXd &forcing_terms, Eigen::MatrixXd &fa_output) const
Return analytical solution of the system at certain times (and return forcing terms) ...
Definition: Dmp.cpp:449
double spring_constant(void)
Accessor function for spring constant.
~Dmp(void)
Destructor.
Definition: Dmp.cpp:242
void getSelectableParameters(std::set< std::string > &selectable_values_labels) const
Return all the names of the parameter types that can be selected.
Definition: Dmp.cpp:708
bool saveToFile(std::string directory, std::string filename, bool overwrite=false) const
Save a trajectory to a file.
Definition: Trajectory.cpp:249
Header file for serialization of Eigen matrices.
void set_damping_coefficient(double damping_coefficient)
Accessor function for damping coefficient of spring-damper system.
Definition: Dmp.cpp:215