DMP_BBO library
FunctionApproximator.cpp
Go to the documentation of this file.
1 
25 
29 
33 
34 #include <iostream>
35 #include <fstream>
36 #include <eigen3/Eigen/Core>
37 #include <boost/filesystem.hpp> // Required only for train(inputs,outputs,save_directory)
38 
39 using namespace std;
40 using namespace Eigen;
41 
42 
46 namespace DmpBbo {
47 
48 /******************************************************************************/
49 FunctionApproximator::FunctionApproximator(const MetaParameters *const meta_parameters, const ModelParameters *const model_parameters)
50 {
51  // At least one of them should not be NULL
52  assert(meta_parameters!=NULL || model_parameters!=NULL);
53 
54  if (meta_parameters==NULL)
55  meta_parameters_ = NULL;
56  else
57  meta_parameters_ = meta_parameters->clone();
58 
59  if (model_parameters==NULL)
60  model_parameters_ = NULL;
61  else
62  model_parameters_ = model_parameters->clone();
63 
64  // If both meta- and model-parameters were set, check if they have the same expected input dim.
65  if (meta_parameters_!=NULL && model_parameters_!=NULL)
66  assert(model_parameters_->getExpectedInputDim()==meta_parameters_->getExpectedInputDim());
67 
68 }
69 
70 FunctionApproximator::FunctionApproximator(const ModelParameters *const model_parameters)
71 {
72  assert(model_parameters!=NULL);
73  meta_parameters_ = NULL;
74  model_parameters_ = model_parameters->clone();
75 }
76 
77 FunctionApproximator::~FunctionApproximator(void)
78 {
79  delete meta_parameters_;
80  delete model_parameters_;
81 }
82 
83 
84 /******************************************************************************/
85 const MetaParameters* FunctionApproximator::getMetaParameters(void) const
86 {
87  return meta_parameters_;
88 };
89 
90 /******************************************************************************/
91 const ModelParameters* FunctionApproximator::getModelParameters(void) const
92 {
93  return model_parameters_;
94 };
95 
96 /******************************************************************************/
97 void FunctionApproximator::setModelParameters(ModelParameters* model_parameters)
98 {
99  if (model_parameters_!=NULL)
100  {
101  delete model_parameters_;
102  model_parameters_ = NULL;
103  }
104 
105  model_parameters_ = model_parameters;
106 }
107 
108 UnifiedModel* FunctionApproximator::getUnifiedModel(void) const
109 {
110  return model_parameters_->toUnifiedModel();
111 }
112 
113 
114 int FunctionApproximator::getExpectedInputDim(void) const
115 {
116  if (model_parameters_!=NULL)
117  return model_parameters_->getExpectedInputDim();
118  else
119  return meta_parameters_->getExpectedInputDim();
120 }
121 
122 int FunctionApproximator::getExpectedOutputDim(void) const
123 {
124  if (model_parameters_!=NULL)
125  return model_parameters_->getExpectedOutputDim();
126  else
127  return meta_parameters_->getExpectedOutputDim();
128 }
129 
130 void FunctionApproximator::reTrain(const Eigen::Ref<const Eigen::MatrixXd>& inputs, const Eigen::Ref<const Eigen::MatrixXd>& targets)
131 {
132  delete model_parameters_;
133  model_parameters_ = NULL;
134  train(inputs,targets);
135 }
136 
137 void FunctionApproximator::reTrain(const Eigen::Ref<const Eigen::MatrixXd>& inputs, const Eigen::Ref<const Eigen::MatrixXd>& targets, std::string save_directory, bool overwrite)
138 {
139  delete model_parameters_;
140  model_parameters_ = NULL;
141  train(inputs,targets,save_directory,overwrite);
142 }
143 
144 
145 void FunctionApproximator::getParameterVectorSelectedMinMax(Eigen::VectorXd& min, Eigen::VectorXd& max) const
146 {
147  if (model_parameters_==NULL)
148  {
149  cerr << __FILE__ << ":" << __LINE__ << ": Warning: Trying to access model parameters of the function approximator, but it has not been trained yet. Returning empty parameter vector." << endl;
150  min.resize(0);
151  max.resize(0);
152  return;
153  }
154 
155  model_parameters_->getParameterVectorSelectedMinMax(min,max);
156 }
157 
158 /******************************************************************************/
159 bool FunctionApproximator::checkModelParametersInitialized(void) const
160 {
161  if (model_parameters_==NULL)
162  {
163  cerr << "Warning: Trying to access model parameters of the function approximator, but it has not been trained yet. Returning empty parameter vector." << endl;
164  return false;
165  }
166  return true;
167 
168 }
169 
170 /******************************************************************************/
171 void FunctionApproximator::getParameterVectorSelected(VectorXd& values, bool normalized) const
172 {
173  if (checkModelParametersInitialized())
174  model_parameters_->getParameterVectorSelected(values, normalized);
175  else
176  values.resize(0);
177 }
178 
179 /******************************************************************************/
180 int FunctionApproximator::getParameterVectorSelectedSize(void) const
181 {
182  if (checkModelParametersInitialized())
183  return model_parameters_->getParameterVectorSelectedSize();
184  else
185  return 0;
186 }
187 
188 void FunctionApproximator::setParameterVectorSelected(const VectorXd& values, bool normalized)
189 {
190  if (checkModelParametersInitialized())
191  model_parameters_->setParameterVectorSelected(values, normalized);
192 }
193 
194 void FunctionApproximator::setSelectedParameters(const set<string>& selected_values_labels)
195 {
196  if (checkModelParametersInitialized())
197  model_parameters_->setSelectedParameters(selected_values_labels);
198 }
199 
200 void FunctionApproximator::getSelectableParameters(set<string>& labels) const
201 {
202  if (checkModelParametersInitialized())
203  model_parameters_->getSelectableParameters(labels);
204  else
205  labels.clear();
206 }
207 
208 void FunctionApproximator::getParameterVectorMask(const std::set<std::string> selected_values_labels, Eigen::VectorXi& selected_mask) const {
209  if (checkModelParametersInitialized())
210  model_parameters_->getParameterVectorMask(selected_values_labels,selected_mask);
211  else
212  selected_mask.resize(0);
213 
214 };
215 int FunctionApproximator::getParameterVectorAllSize(void) const {
216  if (checkModelParametersInitialized())
217  return model_parameters_->getParameterVectorAllSize();
218  else
219  return 0;
220 };
221 void FunctionApproximator::getParameterVectorAll(Eigen::VectorXd& values) const {
222  if (checkModelParametersInitialized())
223  model_parameters_->getParameterVectorAll(values);
224  else
225  values.resize(0);
226 };
227 void FunctionApproximator::setParameterVectorAll(const Eigen::VectorXd& values) {
228  if (checkModelParametersInitialized())
229  model_parameters_->setParameterVectorAll(values);
230 };
231 
232 string FunctionApproximator::toString(void) const
233 {
234  string name = "FunctionApproximator"+getName();
236 }
237 
238 void FunctionApproximator::generateInputsGrid(const Eigen::VectorXd& min, const Eigen::VectorXd& max, const Eigen::VectorXi& n_samples_per_dim, Eigen::MatrixXd& inputs_grid)
239 {
240  int n_dims = min.size();
241  assert(n_dims==max.size());
242  assert(n_dims==n_samples_per_dim.size());
243 
244  if (n_dims==1)
245  {
246  inputs_grid = VectorXd::LinSpaced(n_samples_per_dim[0], min[0], max[0]);
247  }
248  else if (n_dims==2)
249  {
250  int n_samples = n_samples_per_dim[0]*n_samples_per_dim[1];
251  inputs_grid = MatrixXd::Zero(n_samples, n_dims);
252  VectorXd x1 = VectorXd::LinSpaced(n_samples_per_dim[0], min[0], max[0]);
253  VectorXd x2 = VectorXd::LinSpaced(n_samples_per_dim[1], min[1], max[1]);
254  for (int ii=0; ii<x1.size(); ii++)
255  {
256  for (int jj=0; jj<x2.size(); jj++)
257  {
258  inputs_grid(ii*x2.size()+jj,0) = x1[ii];
259  inputs_grid(ii*x2.size()+jj,1) = x2[jj];
260  }
261  }
262  }
263  else
264  {
265  cerr << __FILE__ << ":" << __LINE__ << ":";
266  cerr << "Can only generate input grids for n_dims<3, but found " << n_dims << endl;
267  }
268 }
269 
270 bool FunctionApproximator::saveGridData(const VectorXd& min, const VectorXd& max, const VectorXi& n_samples_per_dim, string save_directory, bool overwrite) const
271 {
272  if (save_directory.empty())
273  return true;
274 
275  //MatrixXd inputs;
276  //FunctionApproximator::generateInputsGrid(min, max, n_samples_per_dim, inputs);
277 
278  if (model_parameters_==NULL)
279  return false;
280  UnifiedModel* mp_unified = model_parameters_->toUnifiedModel();
281  if (mp_unified==NULL)
282  return false;
283 
284  return mp_unified->saveGridData(min,max,n_samples_per_dim,save_directory,overwrite);
285 
286 }
287 
288 void FunctionApproximator::train(const Eigen::Ref<const Eigen::MatrixXd>& inputs, const Eigen::Ref<const Eigen::MatrixXd>& targets, std::string save_directory, bool overwrite)
289 {
290  train(inputs,targets);
291 
292  if (save_directory.empty())
293  return;
294 
295  if (!isTrained())
296  return;
297 
298  if (getExpectedInputDim()<3)
299  {
300 
301  VectorXd min = inputs.colwise().minCoeff();
302  VectorXd max = inputs.colwise().maxCoeff();
303 
304  int n_samples_per_dim = 100;
305  if (getExpectedInputDim()==2) n_samples_per_dim = 40;
306  VectorXi n_samples_per_dim_vec = VectorXi::Constant(getExpectedInputDim(),n_samples_per_dim);
307 
308  MatrixXd inputs_grid;
309  FunctionApproximator::generateInputsGrid(min, max, n_samples_per_dim_vec, inputs_grid);
310 
311  MatrixXd outputs_grid(inputs_grid.rows(),getExpectedOutputDim());
312  predict(inputs_grid,outputs_grid);
313 
314  saveMatrix(save_directory,"n_samples_per_dim.txt",n_samples_per_dim_vec,overwrite);
315  saveMatrix(save_directory,"inputs_grid.txt",inputs_grid,overwrite);
316  saveMatrix(save_directory,"outputs_grid.txt",outputs_grid,overwrite);
317 
318 
319  MatrixXd variances_grid(inputs_grid.rows(),getExpectedOutputDim());
320  predictVariance(inputs_grid,variances_grid);
321  if (!variances_grid.size()==0)
322  {
323  variances_grid = variances_grid.array().sqrt();
324  saveMatrix(save_directory,"variances_grid.txt",variances_grid,overwrite);
325  }
326 
327  saveGridData(min, max, n_samples_per_dim_vec, save_directory, overwrite);
328 
329  }
330 
331  MatrixXd outputs(inputs.rows(),getExpectedOutputDim());
332  predict(inputs,outputs);
333 
334 
335  // saveMatrix does not accept Ref, but only Matrix
336  MatrixXd save_matrix;
337  save_matrix = inputs;
338  saveMatrix(save_directory,"inputs.txt",save_matrix,overwrite);
339  save_matrix = targets;
340  saveMatrix(save_directory,"targets.txt",save_matrix,overwrite);
341  save_matrix = outputs;
342  saveMatrix(save_directory,"outputs.txt",save_matrix,overwrite);
343 
344 
345 
346  string filename = save_directory+"/plotdata.py";
347  ofstream outfile;
348  outfile.open(filename.c_str());
349  if (!outfile.is_open())
350  {
351  cerr << __FILE__ << ":" << __LINE__ << ":";
352  cerr << "Could not open file " << filename << " for writing." << endl;
353  }
354  else
355  {
356  // Python code generation in C++. Rock 'n' roll! ;-)
357  if (inputs.cols()==2) {
358  outfile << "from mpl_toolkits.mplot3d import Axes3D \n";
359  }
360  outfile << "import numpy \n";
361  outfile << "import matplotlib.pyplot as plt \n";
362  outfile << "directory = '" << save_directory << "' \n";
363  outfile << "inputs = numpy.loadtxt(directory+'/inputs.txt') \n";
364  outfile << "targets = numpy.loadtxt(directory+'/targets.txt') \n";
365  outfile << "outputs = numpy.loadtxt(directory+'/outputs.txt') \n";
366  outfile << "fig = plt.figure() \n";
367  if (inputs.cols()==2) {
368  outfile << "ax = Axes3D(fig) \n";
369  outfile << "ax.plot(inputs[:,0],inputs[:,1],targets, '.', label='targets',color='black') \n";
370  outfile << "ax.plot(inputs[:,0],inputs[:,1],outputs, '.', label='predictions',color='red')\n";
371  outfile << "ax.set_xlabel('input_1'); ax.set_ylabel('input_2'); ax.set_zlabel('output') \n";
372  outfile << "ax.legend(loc='lower right') \n";
373  } else {
374  outfile << "plt.plot(inputs,targets, '.', label='targets',color='black') \n";
375  outfile << "plt.plot(inputs,outputs, '.', label='predictions',color='red') \n";
376  outfile << "plt.xlabel('input'); plt.ylabel('output'); \n";
377  outfile << "plt.legend(loc='lower right') \n";
378  }
379  outfile << "plt.show() \n";
380  outfile << endl;
381 
382  outfile.close();
383  //cout << " ______________________________________________________________" << endl;
384  //cout << " | Plot saved data with:" << " 'python " << filename << "'." << endl;
385  //cout << " |______________________________________________________________" << endl;
386  }
387 
388 }
389 
390 void FunctionApproximator::setParameterVectorModifierPrivate(std::string modifier, bool new_value)
391 {
392  model_parameters_->setParameterVectorModifier(modifier,new_value);
393 }
394 
395 }
396 
UnifiedModel class header file.
virtual MetaParameters * clone(void) const =0
Return a pointer to a deep copy of the MetaParameters object.
Header file for input/output of Eigen matrices to ASCII files.
FunctionApproximator class header file.
bool saveGridData(const Eigen::VectorXd &min, const Eigen::VectorXd &max, const Eigen::VectorXi &n_samples_per_dim, std::string directory, bool overwrite=false) const
Generate a grid of inputs, and output the response of the basis functions and line segments for these...
bool saveMatrix(std::string filename, Eigen::Matrix< Scalar, RowsAtCompileTime, ColsAtCompileTime > matrix, bool overwrite=false)
Save an Eigen matrix to an ASCII file.
#define RETURN_STRING_FROM_BOOST_SERIALIZATION_XML(name)
Macro to convert the boost XML serialization of an object into a string.
The unified model, which can be used to represent the model of all other function approximators...
MetaParameters class header file.
ModelParameters class header file.
Base class for all model parameters of function approximators.
Base class for all meta-parameters of function approximators.
Header file to generate strings from boost serialized files.
int getExpectedInputDim(void) const
The expected dimensionality of the input data.
Header file for serialization of Eigen matrices.
virtual ModelParameters * clone(void) const =0
Return a pointer to a deep copy of the ModelParameters object.