DMP_BBO library
ModelParametersLWR.cpp
Go to the documentation of this file.
1 
24 #include <boost/serialization/export.hpp>
25 #include <boost/archive/text_iarchive.hpp>
26 #include <boost/archive/text_oarchive.hpp>
27 #include <boost/archive/xml_iarchive.hpp>
28 #include <boost/archive/xml_oarchive.hpp>
32 
35 
36 
38 
39 //#include "dmpbbo_io/EigenFileIO.hpp"
42 
43 #include <iostream>
44 #include <fstream>
45 
46 #include <eigen3/Eigen/Core>
47 
48 
49 using namespace std;
50 using namespace Eigen;
51 
52 namespace DmpBbo {
53 
54 ModelParametersLWR::ModelParametersLWR(const Eigen::MatrixXd& centers, const Eigen::MatrixXd& widths, const Eigen::MatrixXd& slopes, const Eigen::MatrixXd& offsets, bool asymmetric_kernels, bool lines_pivot_at_max_activation)
55 :
56  centers_(centers),
57  widths_(widths),
58  slopes_(slopes),
59  offsets_(offsets),
60  asymmetric_kernels_(asymmetric_kernels),
61  lines_pivot_at_max_activation_(lines_pivot_at_max_activation),
62  slopes_as_angles_(false),
63  caching_(false)
64 {
65 #ifndef NDEBUG // Variables below are only required for asserts; check for NDEBUG to avoid warnings.
66  int n_basis_functions = centers.rows();
67  int n_dims = centers.cols();
68 #endif
69  assert(n_basis_functions==widths_.rows());
70  assert(n_dims ==widths_.cols());
71  assert(n_basis_functions==slopes_.rows());
72  assert(n_dims ==slopes_.cols());
73  assert(n_basis_functions==offsets_.rows());
74  assert(1 ==offsets_.cols());
75 
76  all_values_vector_size_ = 0;
77  all_values_vector_size_ += centers_.rows()*centers_.cols();
78  all_values_vector_size_ += widths_.rows() *widths_.cols();
79  all_values_vector_size_ += offsets_.rows()*offsets_.cols();
80  all_values_vector_size_ += slopes_.rows() *slopes_.cols();
81 
82 };
83 
85  return new ModelParametersLWR(centers_,widths_,slopes_,offsets_,asymmetric_kernels_,lines_pivot_at_max_activation_);
86 }
87 
88 void ModelParametersLWR::unnormalizedKernelActivations(const Eigen::Ref<const Eigen::MatrixXd>& inputs, Eigen::MatrixXd& kernel_activations) const
89 {
90  ENTERING_REAL_TIME_CRITICAL_CODE
91  bool normalized_basis_functions=false;
92  BasisFunction::Gaussian::activations(centers_,widths_,inputs,kernel_activations,
93  normalized_basis_functions,asymmetric_kernels_);
94  EXITING_REAL_TIME_CRITICAL_CODE
95 }
96 
97 void ModelParametersLWR::kernelActivations(const Eigen::Ref<const Eigen::MatrixXd>& inputs, Eigen::MatrixXd& kernel_activations) const
98 {
99  if (caching_)
100  {
101  // If the cached inputs matrix has the same size as the one now requested
102  // (this also takes care of the case when inputs_cached is empty and need to be initialized)
103  if ( inputs.rows()==inputs_cached_.rows() && inputs.cols()==inputs_cached_.cols() )
104  {
105  // And they have the same values
106  if ( (inputs.array()==inputs_cached_.array()).all() )
107  {
108  // Then you can return the cached values
109  kernel_activations = kernel_activations_cached_;
110  return;
111  }
112  }
113  }
114 
115  ENTERING_REAL_TIME_CRITICAL_CODE
116 
117  // Cache could not be used, actually do the work
118  bool normalize_activations = true;
119  BasisFunction::Gaussian::activations(centers_,widths_,inputs,kernel_activations,normalize_activations,asymmetric_kernels_);
120 
121  EXITING_REAL_TIME_CRITICAL_CODE
122 
123  if (caching_)
124  {
125  // Cache the current results now.
126  inputs_cached_ = inputs;
127  kernel_activations_cached_ = kernel_activations;
128  }
129 
130 }
131 
132 void ModelParametersLWR::set_lines_pivot_at_max_activation(bool lines_pivot_at_max_activation)
133 {
134  // If no change, just return
135  if (lines_pivot_at_max_activation_ == lines_pivot_at_max_activation)
136  return;
137 
138  //cout << "________________" << endl;
139  //cout << centers_.transpose() << endl;
140  //cout << slopes_.transpose() << endl;
141  //cout << offsets_.transpose() << endl;
142  //cout << "centers_ = " << centers_.rows() << "X" << centers_.cols() << endl;
143  //cout << "slopes_ = " << slopes_.rows() << "X" << slopes_.cols() << endl;
144  //cout << "offsets_ = " << offsets_.rows() << "X" << offsets_.cols() << endl;
145 
146  // If you pivot lines around the point when the basis function has maximum activation (i.e.
147  // at the center of the Gaussian), you must compute the new offset corresponding to this
148  // slope, and vice versa
149  int n_lines = centers_.rows();
150  VectorXd ac(n_lines); // slopes*centers
151  for (int i_line=0; i_line<n_lines; i_line++)
152  {
153  ac[i_line] = slopes_.row(i_line) * centers_.row(i_line).transpose();
154  }
155 
156  if (lines_pivot_at_max_activation)
157  {
158  // Representation was "y = ax + b", now it will be "y = a(x-c) + b^new"
159  // Since "y = ax + b" can be rewritten as "y = a(x-c) + (b+ac)", we know that "b^new = (ac+b)"
160  offsets_ = offsets_ + ac;
161  }
162  else
163  {
164  // Representation was "y = a(x-c) + b", now it will be "y = ax + b^new"
165  // Since "y = a(x-c) + b" can be rewritten as "y = ax + (b-ac)", we know that "b^new = (b-ac)"
166  offsets_ = offsets_ - ac;
167  }
168  // Remark, the above could have been done as a one-liner, but I prefer the more legible version.
169 
170  //cout << offsets_.transpose() << endl;
171  //cout << "offsets_ = " << offsets_.rows() << "X" << offsets_.cols() << endl;
172 
173  lines_pivot_at_max_activation_ = lines_pivot_at_max_activation;
174 }
175 
176 void ModelParametersLWR::set_slopes_as_angles(bool slopes_as_angles)
177 {
178  slopes_as_angles_ = slopes_as_angles;
179  cerr << __FILE__ << ":" << __LINE__ << ":";
180  cerr << "Not implemented yet!!!" << endl;
181  slopes_as_angles_ = false;
182 }
183 
184 /*
185 The code below was previously implemted as follows. Below is the real-time version.
186 
187 
188 void ModelParametersLWR::getLines(const Eigen::Ref<const Eigen::MatrixXd>& inputs, MatrixXd& lines) const
189 {
190  int n_time_steps = inputs.rows();
191 
192  //cout << "centers_ = " << centers_.rows() << "X" << centers_.cols() << endl;
193  //cout << "slopes_ = " << slopes_.rows() << "X" << slopes_.cols() << endl;
194  //cout << "offsets_ = " << offsets_.rows() << "X" << offsets_.cols() << endl;
195  //cout << "inputs = " << inputs.rows() << "X" << inputs.cols() << endl;
196 
197  // Compute values along lines for each time step
198  // Line representation is "y = ax + b"
199  lines = inputs*slopes_.transpose() + offsets_.transpose().replicate(n_time_steps,1);
200 
201  if (lines_pivot_at_max_activation_)
202  {
203  // Line representation is "y = a(x-c) + b", which is "y = ax - ac + b"
204  // Therefore, we still have to subtract "ac"
205  int n_lines = centers_.rows();
206  VectorXd ac(n_lines); // slopes*centers = ac
207  for (int i_line=0; i_line<n_lines; i_line++)
208  ac[i_line] = slopes_.row(i_line) * centers_.row(i_line).transpose();
209  //cout << "ac = " << ac.rows() << "X" << ac.cols() << endl;
210  lines = lines - ac.transpose().replicate(n_time_steps,1);
211  }
212  //cout << "lines = " << lines.rows() << "X" << lines.cols() << endl;
213 }
214 */
215 
216 void ModelParametersLWR::getLines(const Eigen::Ref<const Eigen::MatrixXd>& inputs, MatrixXd& lines) const
217 {
218  ENTERING_REAL_TIME_CRITICAL_CODE
219 
220  //cout << endl << "========================" << endl;
221  //cout << "lines = " << lines.rows() << "X" << lines.cols() << endl;
222  //cout << "centers_ = " << centers_.rows() << "X" << centers_.cols() << endl;
223  //cout << "slopes_ = " << slopes_.rows() << "X" << slopes_.cols() << endl;
224  //cout << "offsets_ = " << offsets_.rows() << "X" << offsets_.cols() << endl;
225  //cout << "inputs = " << inputs.rows() << "X" << inputs.cols() << endl;
226 
227  int n_time_steps = inputs.rows();
228  int n_lines = centers_.rows();
229  lines.resize(n_time_steps,n_lines);
230  //cout << "lines = " << lines.rows() << "X" << lines.cols() << endl;
231 
232 
233  // Compute values along lines for each time step
234  // Line representation is "y = ax + b"
235  for (int i_line=0; i_line<n_lines; i_line++)
236  {
237  lines.col(i_line).noalias() = inputs*slopes_.row(i_line).transpose();
238  lines.col(i_line).array() += offsets_(i_line);
239 
240  if (lines_pivot_at_max_activation_)
241  {
242  // Line representation is "y = a(x-c) + b", which is "y = ax - ac + b"
243  // Therefore, we still have to subtract "ac"
244  double ac = slopes_.row(i_line).dot(centers_.row(i_line));
245  lines.col(i_line).array() -= ac;
246  }
247  }
248 
249  EXITING_REAL_TIME_CRITICAL_CODE
250 }
251 
252 /*
253 void ModelParametersLWR::kernelActivationsSymmetric(const MatrixXd& centers, const MatrixXd& widths, const Eigen::Ref<const Eigen::MatrixXd>& inputs, MatrixXd& kernel_activations)
254 {
255  cout << __FILE__ << ":" << __LINE__ << ":Here" << endl;
256  // Check and set sizes
257  // centers = n_basis_functions x n_dim
258  // widths = n_basis_functions x n_dim
259  // inputs = n_samples x n_dim
260  // activations = n_samples x n_basis_functions
261  int n_basis_functions = centers.rows();
262  int n_samples = inputs.rows();
263  int n_dims = centers.cols();
264  assert( (n_basis_functions==widths.rows()) & (n_dims==widths.cols()) );
265  assert( (n_samples==inputs.rows() ) & (n_dims==inputs.cols()) );
266  kernel_activations.resize(n_samples,n_basis_functions);
267 
268 
269  VectorXd center, width;
270  for (int bb=0; bb<n_basis_functions; bb++)
271  {
272  center = centers.row(bb);
273  width = widths.row(bb);
274 
275  // Here, we compute the values of a (unnormalized) multi-variate Gaussian:
276  // activation = exp(-0.5*(x-mu)*Sigma^-1*(x-mu))
277  // Because Sigma is diagonal in our case, this simplifies to
278  // activation = exp(\sum_d=1^D [-0.5*(x_d-mu_d)^2/Sigma_(d,d)])
279  // = \prod_d=1^D exp(-0.5*(x_d-mu_d)^2/Sigma_(d,d))
280  // This last product is what we compute below incrementally
281 
282  kernel_activations.col(bb).fill(1.0);
283  for (int i_dim=0; i_dim<n_dims; i_dim++)
284  {
285  kernel_activations.col(bb).array() *= exp(-0.5*pow(inputs.col(i_dim).array()-center[i_dim],2)/(width[i_dim]*width[i_dim])).array();
286  }
287  }
288 }
289 */
290 
291 template<class Archive>
292 void ModelParametersLWR::serialize(Archive & ar, const unsigned int version)
293 {
294  // serialize base class information
295  ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ModelParameters);
296 
297  ar & BOOST_SERIALIZATION_NVP(centers_);
298  ar & BOOST_SERIALIZATION_NVP(widths_);
299  ar & BOOST_SERIALIZATION_NVP(slopes_);
300  ar & BOOST_SERIALIZATION_NVP(offsets_);
301  ar & BOOST_SERIALIZATION_NVP(asymmetric_kernels_);
302  ar & BOOST_SERIALIZATION_NVP(lines_pivot_at_max_activation_);
303  ar & BOOST_SERIALIZATION_NVP(slopes_as_angles_);
304  ar & BOOST_SERIALIZATION_NVP(all_values_vector_size_);
305  ar & BOOST_SERIALIZATION_NVP(caching_);
306 }
307 
309 {
310  RETURN_STRING_FROM_BOOST_SERIALIZATION_XML("ModelParametersLWR");
311 }
312 
313 void ModelParametersLWR::getSelectableParameters(set<string>& selected_values_labels) const
314 {
315  selected_values_labels = set<string>();
316  selected_values_labels.insert("centers");
317  selected_values_labels.insert("widths");
318  selected_values_labels.insert("offsets");
319  selected_values_labels.insert("slopes");
320 }
321 
322 
323 void ModelParametersLWR::getParameterVectorMask(const std::set<std::string> selected_values_labels, VectorXi& selected_mask) const
324 {
325 
326  selected_mask.resize(getParameterVectorAllSize());
327  selected_mask.fill(0);
328 
329  int offset = 0;
330  int size;
331 
332  // Centers
333  size = centers_.rows()*centers_.cols();
334  if (selected_values_labels.find("centers")!=selected_values_labels.end())
335  selected_mask.segment(offset,size).fill(1);
336  offset += size;
337 
338  // Widths
339  size = widths_.rows()*widths_.cols();
340  if (selected_values_labels.find("widths")!=selected_values_labels.end())
341  selected_mask.segment(offset,size).fill(2);
342  offset += size;
343 
344  // Offsets
345  size = offsets_.rows()*offsets_.cols();
346  if (selected_values_labels.find("offsets")!=selected_values_labels.end())
347  selected_mask.segment(offset,size).fill(3);
348  offset += size;
349 
350  // Slopes
351  size = slopes_.rows()*slopes_.cols();
352  if (selected_values_labels.find("slopes")!=selected_values_labels.end())
353  selected_mask.segment(offset,size).fill(4);
354  offset += size;
355 
356  assert(offset == getParameterVectorAllSize());
357 }
358 
359 void ModelParametersLWR::getParameterVectorAll(VectorXd& values) const
360 {
361  values.resize(getParameterVectorAllSize());
362  int offset = 0;
363 
364  for (int i_dim=0; i_dim<centers_.cols(); i_dim++)
365  {
366  values.segment(offset,centers_.rows()) = centers_.col(i_dim);
367  offset += centers_.rows();
368  }
369 
370  for (int i_dim=0; i_dim<widths_.cols(); i_dim++)
371  {
372  values.segment(offset,widths_.rows()) = widths_.col(i_dim);
373  offset += widths_.rows();
374  }
375 
376  values.segment(offset,offsets_.rows()) = offsets_;
377  offset += offsets_.rows();
378 
379  VectorXd cur_slopes;
380  for (int i_dim=0; i_dim<slopes_.cols(); i_dim++)
381  {
382  cur_slopes = slopes_.col(i_dim);
383  if (slopes_as_angles_)
384  {
385  // cur_slopes is a slope, but the values vector expects the angle with the x-axis. Do the
386  // conversion here.
387  for (int ii=0; ii<cur_slopes.size(); ii++)
388  cur_slopes[ii] = atan2(cur_slopes[ii],1.0);
389  }
390 
391  values.segment(offset,slopes_.rows()) = cur_slopes;
392  offset += slopes_.rows();
393  }
394 
395  assert(offset == getParameterVectorAllSize());
396 };
397 
398 void ModelParametersLWR::setParameterVectorAll(const VectorXd& values) {
399 
400  if (all_values_vector_size_ != values.size())
401  {
402  cerr << __FILE__ << ":" << __LINE__ << ": values is of wrong size." << endl;
403  return;
404  }
405 
406  int offset = 0;
407  int size = centers_.rows();
408  int n_dims = centers_.cols();
409  for (int i_dim=0; i_dim<n_dims; i_dim++)
410  {
411  // If the centers change, the cache for normalizedKernelActivations() must be cleared,
412  // because this function will return different values for different centers
413  if ( !(centers_.col(i_dim).array() == values.segment(offset,size).array()).all() )
414  clearCache();
415 
416  centers_.col(i_dim) = values.segment(offset,size);
417  offset += size;
418  }
419  for (int i_dim=0; i_dim<n_dims; i_dim++)
420  {
421  // If the centers change, the cache for normalizedKernelActivations() must be cleared,
422  // because this function will return different values for different centers
423  if ( !(widths_.col(i_dim).array() == values.segment(offset,size).array()).all() )
424  clearCache();
425 
426  widths_.col(i_dim) = values.segment(offset,size);
427  offset += size;
428  }
429 
430  offsets_ = values.segment(offset,size);
431  offset += size;
432  // Cache must not be cleared, because normalizedKernelActivations() returns the same values.
433 
434  MatrixXd old_slopes = slopes_;
435  for (int i_dim=0; i_dim<n_dims; i_dim++)
436  {
437  slopes_.col(i_dim) = values.segment(offset,size);
438  offset += size;
439  // Cache must not be cleared, because normalizedKernelActivations() returns the same values.
440  }
441 
442  assert(offset == getParameterVectorAllSize());
443 };
444 
445 void ModelParametersLWR::setParameterVectorModifierPrivate(std::string modifier, bool new_value)
446 {
447  if (modifier.compare("lines_pivot_at_max_activation")==0)
449 
450  if (modifier.compare("slopes_as_angles")==0)
451  set_slopes_as_angles(new_value);
452 
453 }
454 
456 {
457 
458  // LWR uses normalized basis functions
459  bool normalized_basis_functions = true;
460  return new UnifiedModel(centers_, widths_, slopes_, offsets_, normalized_basis_functions);
461 
462 }
463 
464 }
UnifiedModel class header file.
void kernelActivations(const Eigen::Ref< const Eigen::MatrixXd > &inputs, Eigen::MatrixXd &kernel_activations) const
Get the normalized kernel activations for given inputs.
ModelParameters * clone(void) const
Return a pointer to a deep copy of the ModelParameters object.
FunctionApproximator class header file.
UnifiedModel * toUnifiedModel(void) const
Convert these model parameters to unified model parameters.
Model parameters for the Locally Weighted Regression (LWR) function approximator. ...
int getParameterVectorAllSize(void) const
Get the size of the parameter values vector when it contains all available parameter values...
std::string toString(void) const
Returns a string representation of the object.
BasisFunction header file.
#define RETURN_STRING_FROM_BOOST_SERIALIZATION_XML(name)
Macro to convert the boost XML serialization of an object into a string.
void getSelectableParameters(std::set< std::string > &selected_values_labels) const
Return all the names of the parameter types that can be selected.
The unified model, which can be used to represent the model of all other function approximators...
void getLines(const Eigen::Ref< const Eigen::MatrixXd > &inputs, Eigen::MatrixXd &lines) const
Get the output of each linear model (unweighted) for the given inputs.
void setParameterVectorModifierPrivate(std::string modifier, bool new_value)
Turn certain modifiers on or off, see Parameterizable::setParameterVectorModifier().
Base class for all model parameters of function approximators.
ModelParametersLWR class header file.
BOOST_CLASS_EXPORT_IMPLEMENT(DmpBbo::ModelParametersLWR)
For boost::serialization.
void getParameterVectorMask(const std::set< std::string > selected_values_labels, Eigen::VectorXi &selected_mask) const
Get a mask for selecting parameters.
Header file to generate strings from boost serialized files.
void set_slopes_as_angles(bool slopes_as_angles)
Whether to return slopes as angles or slopes in ModelParametersLWR::getParameterVectorAll() ...
void setParameterVectorAll(const Eigen::VectorXd &values)
Set all available parameter values with one vector.
void set_lines_pivot_at_max_activation(bool lines_pivot_at_max_activation)
Set whether the offsets should be adapted so that the line segments pivot around the mode of the basi...
void unnormalizedKernelActivations(const Eigen::Ref< const Eigen::MatrixXd > &inputs, Eigen::MatrixXd &kernel_activations) const
Get the unnormalized kernel activations for given inputs.
void getParameterVectorAll(Eigen::VectorXd &all_values) const
Return a vector that returns all available parameter values.
Header file for serialization of Eigen matrices.