ProjectionEvaluator.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011, Willow Garage, Inc.
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 Willow Garage 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 /* Author: Ioan Sucan */
36 
37 // We need this to create a temporary uBLAS vector from a C-style array without copying data
38 #define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR
39 #include "ompl/base/StateSpace.h"
40 #include "ompl/base/ProjectionEvaluator.h"
41 #include "ompl/util/Exception.h"
42 #include "ompl/util/RandomNumbers.h"
43 #include "ompl/tools/config/MagicConstants.h"
44 #include <boost/numeric/ublas/matrix_proxy.hpp>
45 #include <boost/numeric/ublas/io.hpp>
46 #include <functional>
47 #include <cmath>
48 #include <cstring>
49 #include <limits>
50 
51 ompl::base::ProjectionMatrix::Matrix ompl::base::ProjectionMatrix::ComputeRandom(const unsigned int from, const unsigned int to, const std::vector<double> &scale)
52 {
53  namespace nu = boost::numeric::ublas;
54 
55  RNG rng;
56  Matrix projection(to, from);
57 
58  for (unsigned int j = 0 ; j < from ; ++j)
59  {
60  if (scale.size() == from && fabs(scale[j]) < std::numeric_limits<double>::epsilon())
61  nu::column(projection, j) = nu::zero_vector<double>(to);
62  else
63  for (unsigned int i = 0 ; i < to ; ++i)
64  projection(i, j) = rng.gaussian01();
65  }
66 
67  for (unsigned int i = 0 ; i < to ; ++i)
68  {
69  nu::matrix_row<Matrix> row(projection, i);
70  for (unsigned int j = 0 ; j < i ; ++j)
71  {
72  nu::matrix_row<Matrix> prevRow(projection, j);
73  // subtract projection
74  row -= inner_prod(row, prevRow) * prevRow;
75  }
76  // normalize
77  row /= norm_2(row);
78  }
79 
80  assert(scale.size() == from || scale.size() == 0);
81  if (scale.size() == from)
82  {
83  unsigned int z = 0;
84  for (unsigned int i = 0 ; i < from ; ++i)
85  {
86  if (fabs(scale[i]) < std::numeric_limits<double>::epsilon())
87  z++;
88  else
89  nu::column(projection, i) /= scale[i];
90  }
91  if (z == from)
92  OMPL_WARN("Computed projection matrix is all 0s");
93  }
94  return projection;
95 }
96 
98 {
99  return ComputeRandom(from, to, std::vector<double>());
100 }
101 
102 void ompl::base::ProjectionMatrix::computeRandom(const unsigned int from, const unsigned int to, const std::vector<double> &scale)
103 {
104  mat = ComputeRandom(from, to, scale);
105 }
106 
107 void ompl::base::ProjectionMatrix::computeRandom(const unsigned int from, const unsigned int to)
108 {
109  mat = ComputeRandom(from, to);
110 }
111 
113 {
114  namespace nu = boost::numeric::ublas;
115  // create a temporary uBLAS vector from a C-style array without copying data
116  nu::shallow_array_adaptor<const double> tmp1(mat.size2(), from);
117  nu::vector<double, nu::shallow_array_adaptor<const double> > tmp2(mat.size2(), tmp1);
118  to = prod(mat, tmp2);
119 }
120 
121 void ompl::base::ProjectionMatrix::print(std::ostream &out) const
122 {
123  out << mat << std::endl;
124 }
125 
126 ompl::base::ProjectionEvaluator::ProjectionEvaluator(const StateSpace *space) :
127  space_(space),
128  bounds_(0), estimatedBounds_(0),
129  defaultCellSizes_(true), cellSizesWereInferred_(false)
130 {
131  params_.declareParam<double>("cellsize_factor", std::bind(&ProjectionEvaluator::mulCellSizes, this, std::placeholders::_1));
132 }
133 
134 ompl::base::ProjectionEvaluator::ProjectionEvaluator(const StateSpacePtr &space) :
135  space_(space.get()),
136  bounds_(0), estimatedBounds_(0),
138 {
139  params_.declareParam<double>("cellsize_factor", std::bind(&ProjectionEvaluator::mulCellSizes, this, std::placeholders::_1));
140 }
141 
142 ompl::base::ProjectionEvaluator::~ProjectionEvaluator()
143 {
144 }
145 
147 {
149 }
150 
151 void ompl::base::ProjectionEvaluator::setCellSizes(const std::vector<double> &cellSizes)
152 {
153  defaultCellSizes_ = false;
154  cellSizesWereInferred_ = false;
155  cellSizes_ = cellSizes;
156  checkCellSizes();
157 }
158 
160 {
161  bounds_ = bounds;
162  checkBounds();
163 }
164 
165 void ompl::base::ProjectionEvaluator::setCellSizes(unsigned int dim, double cellSize)
166 {
167  if (cellSizes_.size() >= dim)
168  OMPL_ERROR("Dimension %u is not defined for projection evaluator", dim);
169  else
170  {
171  std::vector<double> c = cellSizes_;
172  c[dim] = cellSize;
173  setCellSizes(c);
174  }
175 }
176 
177 double ompl::base::ProjectionEvaluator::getCellSizes(unsigned int dim) const
178 {
179  if (cellSizes_.size() > dim)
180  return cellSizes_[dim];
181  OMPL_ERROR("Dimension %u is not defined for projection evaluator", dim);
182  return 0.0;
183 }
184 
186 {
187  if (cellSizes_.size() == getDimension())
188  {
189  std::vector<double> c(cellSizes_.size());
190  for (std::size_t i = 0 ; i < cellSizes_.size() ; ++i)
191  c[i] = cellSizes_[i] * factor;
192  setCellSizes(c);
193  }
194 }
195 
197 {
198  if (getDimension() <= 0)
199  throw Exception("Dimension of projection needs to be larger than 0");
200  if (cellSizes_.size() != getDimension())
201  throw Exception("Number of dimensions in projection space does not match number of cell sizes");
202 }
203 
205 {
206  bounds_.check();
207  if (hasBounds() && bounds_.low.size() != getDimension())
208  throw Exception("Number of dimensions in projection space does not match dimension of bounds");
209 }
210 
212 {
213 }
214 
216 namespace ompl
217 {
218  namespace base
219  {
220 
221  static inline void computeCoordinatesHelper(const std::vector<double> &cellSizes, const EuclideanProjection &projection, ProjectionCoordinates &coord)
222  {
223  const std::size_t dim = cellSizes.size();
224  coord.resize(dim);
225  for (unsigned int i = 0 ; i < dim ; ++i)
226  coord[i] = (int)floor(projection(i)/cellSizes[i]);
227  }
228  }
229 }
231 
233 {
234  if (estimatedBounds_.low.empty())
235  estimateBounds();
237 }
238 
240 {
241  unsigned int dim = getDimension();
243  if (dim > 0)
244  {
246  State *s = space_->allocState();
247  EuclideanProjection proj(dim);
248 
249  estimatedBounds_.setLow(std::numeric_limits<double>::infinity());
250  estimatedBounds_.setHigh(-std::numeric_limits<double>::infinity());
251 
252  for (unsigned int i = 0 ; i < magic::PROJECTION_EXTENTS_SAMPLES ; ++i)
253  {
254  sampler->sampleUniform(s);
255  project(s, proj);
256  for (unsigned int j = 0 ; j < dim ; ++j)
257  {
258  if (estimatedBounds_.low[j] > proj[j])
259  estimatedBounds_.low[j] = proj[j];
260  if (estimatedBounds_.high[j] < proj[j])
261  estimatedBounds_.high[j] = proj[j];
262  }
263  }
264  // make bounding box 10% larger (5% padding on each side)
265  std::vector<double> diff(estimatedBounds_.getDifference());
266  for (unsigned int j = 0; j < dim; ++j)
267  {
270  }
271 
272  space_->freeState(s);
273  }
274 }
275 
277 {
278  cellSizesWereInferred_ = true;
279  if (!hasBounds())
280  inferBounds();
281  unsigned int dim = getDimension();
282  cellSizes_.resize(dim);
283  for (unsigned int j = 0 ; j < dim ; ++j)
284  {
286  if (cellSizes_[j] < std::numeric_limits<double>::epsilon())
287  {
288  cellSizes_[j] = 1.0;
289  OMPL_WARN("Inferred cell size for dimension %u of a projection for state space %s is 0. Setting arbitrary value of 1 instead.",
290  j, space_->getName().c_str());
291  }
292  }
293 }
294 
296 {
297  typedef void(ProjectionEvaluator::*setCellSizesFunctionType)(unsigned int, double);
298  typedef double(ProjectionEvaluator::*getCellSizesFunctionType)(unsigned int) const;
299 
300  if (defaultCellSizes_)
302 
303  if ((cellSizes_.size() == 0 && getDimension() > 0) || cellSizesWereInferred_)
304  inferCellSizes();
305 
306  checkCellSizes();
307  checkBounds();
308 
309  unsigned int dim = getDimension();
310  for (unsigned int i = 0 ; i < dim ; ++i)
311  params_.declareParam<double>("cellsize." + std::to_string(i),
312  std::bind((setCellSizesFunctionType)&ProjectionEvaluator::setCellSizes, this, i, std::placeholders::_1),
313  std::bind((getCellSizesFunctionType)&ProjectionEvaluator::getCellSizes, this, i));
314 }
315 
317 {
318  computeCoordinatesHelper(cellSizes_, projection, coord);
319 }
320 
322 {
323  out << "Projection of dimension " << getDimension() << std::endl;
324  out << "Cell sizes";
326  out << " (inferred by sampling)";
327  else
328  {
329  if (defaultCellSizes_)
330  out << " (computed defaults)";
331  else
332  out << " (set by user)";
333  }
334  out << ": [";
335  for (unsigned int i = 0 ; i < cellSizes_.size() ; ++i)
336  {
337  out << cellSizes_[i];
338  if (i + 1 < cellSizes_.size())
339  out << ' ';
340  }
341  out << ']' << std::endl;
342 }
343 
344 void ompl::base::ProjectionEvaluator::printProjection(const EuclideanProjection &projection, std::ostream &out) const
345 {
346  out << projection << std::endl;
347 }
348 
350  ProjectionEvaluator(space), index_(index), specifiedProj_(projToUse)
351 {
352  if (!space_->isCompound())
353  throw Exception("Cannot construct a subspace projection evaluator for a space that is not compound");
355  throw Exception("State space " + space_->getName() + " does not have a subspace at index " + std::to_string(index_));
356 }
357 
359 {
360  if (specifiedProj_)
362  else
364  if (!proj_)
365  throw Exception("No projection specified for subspace at index " + std::to_string(index_));
366 
367  cellSizes_ = proj_->getCellSizes();
369 }
370 
372 {
373  return proj_->getDimension();
374 }
375 
377 {
378  proj_->project(state->as<CompoundState>()->components[index_], projection);
379 }
virtual StateSamplerPtr allocStateSampler() const
Allocate an instance of the state sampler for this space. This sampler will be allocated with the sam...
Definition: StateSpace.cpp:790
void checkBounds() const
Check if the projection dimension matched the dimension of the bounds.
Definition of a compound state.
Definition: State.h:95
void resize(std::size_t size)
Change the number of dimensions for the bounds.
virtual void printSettings(std::ostream &out=std::cout) const
Print settings about this projection.
virtual unsigned int getDimension() const =0
Return the dimension of the projection defined by this evaluator.
std::vector< double > cellSizes_
The size of a cell, in every dimension of the projected space, in the implicitly defined integer grid...
double gaussian01()
Generate a random real using a normal distribution with mean 0 and variance 1.
Definition: RandomNumbers.h:95
virtual void setup()
Perform configuration steps, if needed.
std::vector< double > low
Lower bound.
void checkCellSizes() const
Check if cell dimensions match projection dimension.
bool cellSizesWereInferred_
Flag indicating whether projection cell sizes were automatically inferred.
A shared pointer wrapper for ompl::base::StateSpace.
A shared pointer wrapper for ompl::base::StateSampler.
void inferBounds()
Compute an approximation of the bounds for this projection space. getBounds() will then report the co...
static Matrix ComputeRandom(const unsigned int from, const unsigned int to, const std::vector< double > &scale)
Compute a random projection matrix with from columns and to rows. A vector with from elements can be ...
ProjectionEvaluatorPtr specifiedProj_
The projection that is optionally specified by the user in the constructor argument (projToUse) ...
void inferCellSizes()
Sample the state space and decide on default cell sizes. This function is called by setup() if no cel...
RealVectorBounds estimatedBounds_
An approximate bounding box for projected state values; This is the cached result of estimateBounds()...
static const double PROJECTION_EXPAND_FACTOR
When a bounding box of projected states cannot be inferred, it will be estimated by sampling states...
void print(std::ostream &out=std::cout) const
Print the contained projection matrix to a stram.
ParamSet params_
The set of parameters for this projection.
void computeRandom(const unsigned int from, const unsigned int to, const std::vector< double > &scale)
Wrapper for ComputeRandom(from, to, scale)
T * as()
Cast this instance to a desired type.
Definition: StateSpace.h:89
const StateSpace * space_
The state space this projection operates on.
bool defaultCellSizes_
Flag indicating whether cell sizes have been set by the user, or whether they were inferred automatic...
SubspaceProjectionEvaluator(const StateSpace *space, unsigned int index, const ProjectionEvaluatorPtr &projToUse=ProjectionEvaluatorPtr())
The constructor states that for space space, the projection to use is the same as the component at po...
void setLow(double value)
Set the lower bound in each dimension to a specific value.
static const unsigned int PROJECTION_EXTENTS_SAMPLES
When no cell sizes are specified for a projection, they are inferred like so:
Main namespace. Contains everything in this library.
Definition: Cost.h:42
void setHigh(double value)
Set the upper bound in each dimension to a specific value.
Random number generation. An instance of this class cannot be used by multiple threads at once (membe...
Definition: RandomNumbers.h:58
virtual void defaultCellSizes()
Set the default cell dimensions for this projection. The default implementation of this function is e...
A space to allow the composition of state spaces.
Definition: StateSpace.h:549
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
unsigned int index_
The index of the subspace from which to project.
virtual void project(const State *state, EuclideanProjection &projection) const
Compute the projection as an array of double values.
Matrix mat
Projection matrix.
virtual void printProjection(const EuclideanProjection &projection, std::ostream &out=std::cout) const
Print a euclidean projection.
std::vector< double > high
Upper bound.
void mulCellSizes(double factor)
Multiply the cell sizes in each dimension by a specified factor factor. This function does nothing if...
bool userConfigured() const
Return true if any user configuration has been done to this projection evaluator (setCellSizes() was ...
A shared pointer wrapper for ompl::base::ProjectionEvaluator.
static const double PROJECTION_DIMENSION_SPLITS
When the cell sizes for a projection are automatically computed, this value defines the number of par...
std::vector< int > ProjectionCoordinates
Grid cells corresponding to a projection value are described in terms of their coordinates.
Representation of a space in which planning can be performed. Topology specific sampling, interpolation and distance are defined.
Definition: StateSpace.h:72
boost::numeric::ublas::vector< double > EuclideanProjection
The datatype for state projections. This class contains a real vector.
Definition of an abstract state.
Definition: State.h:50
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
Definition: Console.h:66
void check() const
Check if the bounds are valid (same length for low and high, high[i] > low[i]). Throw an exception if...
virtual void project(const State *state, EuclideanProjection &projection) const =0
Compute the projection as an array of double values.
The exception type for ompl.
Definition: Exception.h:47
void declareParam(const std::string &name, const typename SpecificParam< T >::SetterFn &setter, const typename SpecificParam< T >::GetterFn &getter=typename SpecificParam< T >::GetterFn())
This function declares a parameter name, and specifies the setter and getter functions.
Definition: GenericParam.h:239
const std::vector< double > & getCellSizes() const
Get the size (each dimension) of a grid cell.
The lower and upper bounds for an Rn space.
void estimateBounds()
Fill estimatedBounds_ with an approximate bounding box for the projection space (via sampling) ...
State ** components
The components that make up a compound state.
Definition: State.h:142
virtual bool isCompound() const
Check if the state space is compound.
Definition: StateSpace.cpp:755
void setBounds(const RealVectorBounds &bounds)
Set bounds on the projection. The PDST planner needs to known the bounds on the projection. Default bounds are automatically computed by inferCellSizes().
unsigned int getSubspaceCount() const
Get the number of state spaces that make up the compound state space.
Definition: StateSpace.cpp:893
virtual void setCellSizes(const std::vector< double > &cellSizes)
Define the size (in each dimension) of a grid cell. The number of sizes set here must be the same as ...
const std::string & getName() const
Get the name of the state space.
Definition: StateSpace.cpp:196
ProjectionEvaluatorPtr getDefaultProjection() const
Get the default projection.
Definition: StateSpace.cpp:714
virtual void freeState(State *state) const =0
Free the memory of the allocated state.
const T * as() const
Cast this instance to a desired type.
Definition: State.h:74
bool hasBounds() const
Check if bounds were specified for this projection.
void project(const double *from, EuclideanProjection &to) const
Multiply the vector from by the contained projection matrix to obtain the vector to.
virtual State * allocState() const =0
Allocate a state that can store a point in the described space.
boost::numeric::ublas::matrix< double > Matrix
Datatype for projection matrices.
std::vector< double > getDifference() const
Get the difference between the high and low bounds for each dimension: result[i] = high[i] - low[i]...
virtual unsigned int getDimension() const
Return the dimension of the projection defined by this evaluator.
RealVectorBounds bounds_
A bounding box for projected state values.
virtual void setup()
Perform configuration steps, if needed.
Abstract definition for a class computing projections to Rn. Implicit integer grids are imposed on th...
ProjectionEvaluatorPtr proj_
The projection to use. This is either the same as specifiedProj_ or, if specifiedProj_ is not initial...
void computeCoordinates(const EuclideanProjection &projection, ProjectionCoordinates &coord) const
Compute integer coordinates for a projection.