SpaceInformation.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2010, Rice University
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 Rice University 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 #include "ompl/base/SpaceInformation.h"
38 #include "ompl/base/samplers/UniformValidStateSampler.h"
39 #include "ompl/base/DiscreteMotionValidator.h"
40 #include "ompl/base/spaces/ReedsSheppStateSpace.h"
41 #include "ompl/base/spaces/DubinsStateSpace.h"
42 #include "ompl/util/Exception.h"
43 #include "ompl/util/Time.h"
44 #include "ompl/tools/config/MagicConstants.h"
45 #include <queue>
46 #include <cassert>
47 
48 ompl::base::SpaceInformation::SpaceInformation(const StateSpacePtr &space) :
49  stateSpace_(space), setup_(false)
50 {
51  if (!stateSpace_)
52  throw Exception("Invalid space definition");
54  params_.include(stateSpace_->params());
55 }
56 
58 {
59  if (!stateValidityChecker_)
60  {
61  stateValidityChecker_.reset(new AllValidStateValidityChecker(this));
62  OMPL_WARN("State validity checker not set! No collision checking is performed");
63  }
64 
65  if (!motionValidator_)
66  setDefaultMotionValidator();
67 
68  stateSpace_->setup();
69  if (stateSpace_->getDimension() <= 0)
70  throw Exception("The dimension of the state space we plan in must be > 0");
71 
72  params_.clear();
73  params_.include(stateSpace_->params());
74 
75  setup_ = true;
76 }
77 
79 {
80  return setup_;
81 }
82 
84 {
85  class BoostFnStateValidityChecker : public StateValidityChecker
86  {
87  public:
88 
89  BoostFnStateValidityChecker(SpaceInformation *si,
90  const StateValidityCheckerFn &fn) : StateValidityChecker(si), fn_(fn)
91  {
92  }
93 
94  virtual bool isValid(const State *state) const
95  {
96  return fn_(state);
97  }
98 
99  protected:
100 
102  };
103 
104  if (!svc)
105  throw Exception("Invalid function definition for state validity checking");
106 
107  setStateValidityChecker(StateValidityCheckerPtr(dynamic_cast<StateValidityChecker*>(new BoostFnStateValidityChecker(this, svc))));
108 }
109 
111 {
112  if (dynamic_cast<ReedsSheppStateSpace*>(stateSpace_.get()))
113  motionValidator_.reset(new ReedsSheppMotionValidator(this));
114  else if (dynamic_cast<DubinsStateSpace*>(stateSpace_.get()))
115  motionValidator_.reset(new DubinsMotionValidator(this));
116  else
117  motionValidator_.reset(new DiscreteMotionValidator(this));
118 }
119 
120 
122 {
123  vssa_ = vssa;
124  setup_ = false;
125 }
126 
128 {
129  vssa_ = ValidStateSamplerAllocator();
130  setup_ = false;
131 }
132 
133 unsigned int ompl::base::SpaceInformation::randomBounceMotion(const StateSamplerPtr &sss, const State *start, unsigned int steps, std::vector<State*> &states, bool alloc) const
134 {
135  if (alloc)
136  {
137  states.resize(steps);
138  for (unsigned int i = 0 ; i < steps ; ++i)
139  states[i] = allocState();
140  }
141  else
142  if (states.size() < steps)
143  steps = states.size();
144 
145  const State *prev = start;
146  std::pair<State*, double> lastValid;
147  unsigned int j = 0;
148  for (unsigned int i = 0 ; i < steps ; ++i)
149  {
150  sss->sampleUniform(states[j]);
151  lastValid.first = states[j];
152  if (checkMotion(prev, states[j], lastValid) || lastValid.second > std::numeric_limits<double>::epsilon())
153  prev = states[j++];
154  }
155 
156  return j;
157 }
158 
159 bool ompl::base::SpaceInformation::searchValidNearby(const ValidStateSamplerPtr &sampler, State *state, const State *near, double distance) const
160 {
161  if (state != near)
162  copyState(state, near);
163 
164  // fix bounds, if needed
165  if (!satisfiesBounds(state))
166  enforceBounds(state);
167 
168  bool result = isValid(state);
169 
170  if (!result)
171  {
172  // try to find a valid state nearby
173  State *temp = cloneState(state);
174  result = sampler->sampleNear(state, temp, distance);
175  freeState(temp);
176  }
177 
178  return result;
179 }
180 
181 bool ompl::base::SpaceInformation::searchValidNearby(State *state, const State *near, double distance, unsigned int attempts) const
182 {
183  if (satisfiesBounds(near) && isValid(near))
184  {
185  if (state != near)
186  copyState(state, near);
187  return true;
188  }
189  else
190  {
191  // try to find a valid state nearby
193  uvss->setNrAttempts(attempts);
194  return searchValidNearby(ValidStateSamplerPtr(uvss), state, near, distance);
195  }
196 }
197 
198 unsigned int ompl::base::SpaceInformation::getMotionStates(const State *s1, const State *s2, std::vector<State*> &states, unsigned int count, bool endpoints, bool alloc) const
199 {
200  // add 1 to the number of states we want to add between s1 & s2. This gives us the number of segments to split the motion into
201  count++;
202 
203  if (count < 2)
204  {
205  unsigned int added = 0;
206 
207  // if they want endpoints, then at most endpoints are included
208  if (endpoints)
209  {
210  if (alloc)
211  {
212  states.resize(2);
213  states[0] = allocState();
214  states[1] = allocState();
215  }
216  if (states.size() > 0)
217  {
218  copyState(states[0], s1);
219  added++;
220  }
221 
222  if (states.size() > 1)
223  {
224  copyState(states[1], s2);
225  added++;
226  }
227  }
228  else
229  if (alloc)
230  states.resize(0);
231  return added;
232  }
233 
234  if (alloc)
235  {
236  states.resize(count + (endpoints ? 1 : -1));
237  if (endpoints)
238  states[0] = allocState();
239  }
240 
241  unsigned int added = 0;
242 
243  if (endpoints && states.size() > 0)
244  {
245  copyState(states[0], s1);
246  added++;
247  }
248 
249  /* find the states in between */
250  for (unsigned int j = 1 ; j < count && added < states.size() ; ++j)
251  {
252  if (alloc)
253  states[added] = allocState();
254  stateSpace_->interpolate(s1, s2, (double)j / (double)count, states[added]);
255  added++;
256  }
257 
258  if (added < states.size() && endpoints)
259  {
260  if (alloc)
261  states[added] = allocState();
262  copyState(states[added], s2);
263  added++;
264  }
265 
266  return added;
267 }
268 
269 
270 bool ompl::base::SpaceInformation::checkMotion(const std::vector<State*> &states, unsigned int count, unsigned int &firstInvalidStateIndex) const
271 {
272  assert(states.size() >= count);
273  for (unsigned int i = 0 ; i < count ; ++i)
274  if (!isValid(states[i]))
275  {
276  firstInvalidStateIndex = i;
277  return false;
278  }
279  return true;
280 }
281 
282 bool ompl::base::SpaceInformation::checkMotion(const std::vector<State*> &states, unsigned int count) const
283 {
284  assert(states.size() >= count);
285  if (count > 0)
286  {
287  if (count > 1)
288  {
289  if (!isValid(states.front()))
290  return false;
291  if (!isValid(states[count - 1]))
292  return false;
293 
294  // we have 2 or more states, and the first and last states are valid
295 
296  if (count > 2)
297  {
298  std::queue< std::pair<int, int> > pos;
299  pos.push(std::make_pair(0, count - 1));
300 
301  while (!pos.empty())
302  {
303  std::pair<int, int> x = pos.front();
304 
305  int mid = (x.first + x.second) / 2;
306  if (!isValid(states[mid]))
307  return false;
308 
309  pos.pop();
310 
311  if (x.first < mid - 1)
312  pos.push(std::make_pair(x.first, mid));
313  if (x.second > mid + 1)
314  pos.push(std::make_pair(mid, x.second));
315  }
316  }
317  }
318  else
319  return isValid(states.front());
320  }
321  return true;
322 }
323 
325 {
326  if (vssa_)
327  return vssa_(this);
328  else
330 }
331 
332 double ompl::base::SpaceInformation::probabilityOfValidState(unsigned int attempts) const
333 {
334  if (attempts == 0)
335  return 0.0;
336 
337  unsigned int valid = 0;
338  unsigned int invalid = 0;
339 
340  StateSamplerPtr ss = allocStateSampler();
341  State *s = allocState();
342 
343  for (unsigned int i = 0 ; i < attempts ; ++i)
344  {
345  ss->sampleUniform(s);
346  if (isValid(s))
347  ++valid;
348  else
349  ++invalid;
350  }
351 
352  freeState(s);
353 
354  return (double)valid / (double)(valid + invalid);
355 }
356 
358 {
359  // take the square root here because we in fact have a nested for loop
360  // where each loop executes #attempts steps (the sample() function of the UniformValidStateSampler if a for loop too)
361  attempts = std::max((unsigned int)floor(sqrt((double)attempts) + 0.5), 2u);
362 
363  StateSamplerPtr ss = allocStateSampler();
365  uvss->setNrAttempts(attempts);
366 
367  State *s1 = allocState();
368  State *s2 = allocState();
369 
370  std::pair<State*, double> lastValid;
371  lastValid.first = nullptr;
372 
373  double d = 0.0;
374  unsigned int count = 0;
375  for (unsigned int i = 0 ; i < attempts ; ++i)
376  if (uvss->sample(s1))
377  {
378  ++count;
379  ss->sampleUniform(s2);
380  if (checkMotion(s1, s2, lastValid))
381  d += distance(s1, s2);
382  else
383  d += distance(s1, s2) * lastValid.second;
384  }
385 
386  freeState(s2);
387  freeState(s1);
388  delete uvss;
389 
390  if (count > 0)
391  return d / (double)count;
392  else
393  return 0.0;
394 }
395 
396 void ompl::base::SpaceInformation::samplesPerSecond(double &uniform, double &near, double &gaussian, unsigned int attempts) const
397 {
398  StateSamplerPtr ss = allocStateSampler();
399  std::vector<State*> states(attempts + 1);
400  allocStates(states);
401 
402  time::point start = time::now();
403  for (unsigned int i = 0 ; i < attempts ; ++i)
404  ss->sampleUniform(states[i]);
405  uniform = (double)attempts / time::seconds(time::now() - start);
406 
407  double d = getMaximumExtent() / 10.0;
408  ss->sampleUniform(states[attempts]);
409 
410  start = time::now();
411  for (unsigned int i = 1 ; i <= attempts ; ++i)
412  ss->sampleUniformNear(states[i - 1], states[i], d);
413  near = (double)attempts / time::seconds(time::now() - start);
414 
415  start = time::now();
416  for (unsigned int i = 1 ; i <= attempts ; ++i)
417  ss->sampleGaussian(states[i - 1], states[i], d);
418  gaussian = (double)attempts / time::seconds(time::now() - start);
419 
420  freeStates(states);
421 }
422 
423 void ompl::base::SpaceInformation::printSettings(std::ostream &out) const
424 {
425  out << "Settings for the state space '" << stateSpace_->getName() << "'" << std::endl;
426  out << " - state validity check resolution: " << (getStateValidityCheckingResolution() * 100.0) << '%' << std::endl;
427  out << " - valid segment count factor: " << stateSpace_->getValidSegmentCountFactor() << std::endl;
428  out << " - state space:" << std::endl;
429  stateSpace_->printSettings(out);
430  out << std::endl << "Declared parameters:" << std::endl;
431  params_.print(out);
432  ValidStateSamplerPtr vss = allocValidStateSampler();
433  out << "Valid state sampler named " << vss->getName() << " with parameters:" << std::endl;
434  vss->params().print(out);
435 }
436 
438 {
439  out << "Properties of the state space '" << stateSpace_->getName() << "'" << std::endl;
440  out << " - signature: ";
441  std::vector<int> sig;
442  stateSpace_->computeSignature(sig);
443  for (std::size_t i = 0 ; i < sig.size() ; ++i)
444  out << sig[i] << " ";
445  out << std::endl;
446  out << " - dimension: " << stateSpace_->getDimension() << std::endl;
447  out << " - extent: " << stateSpace_->getMaximumExtent() << std::endl;
448  if (isSetup())
449  {
450  bool result = true;
451  try
452  {
453  stateSpace_->sanityChecks();
454  }
455  catch(Exception &e)
456  {
457  result = false;
458  out << std::endl << " - SANITY CHECKS FOR STATE SPACE ***DID NOT PASS*** (" << e.what() << ")" << std::endl << std::endl;
459  OMPL_ERROR(e.what());
460  }
461  if (result)
462  out << " - sanity checks for state space passed" << std::endl;
463  out << " - probability of valid states: " << probabilityOfValidState(magic::TEST_STATE_COUNT) << std::endl;
464  out << " - average length of a valid motion: " << averageValidMotionLength(magic::TEST_STATE_COUNT) << std::endl;
465  double uniform, near, gaussian;
466  samplesPerSecond(uniform, near, gaussian, magic::TEST_STATE_COUNT);
467  out << " - average number of samples drawn per second: sampleUniform()=" << uniform << " sampleUniformNear()=" << near << " sampleGaussian()=" << gaussian << std::endl;
468  }
469  else
470  out << "Call setup() before to get more information" << std::endl;
471 }
virtual bool sample(State *state)
Sample a state. Return false in case of failure.
bool searchValidNearby(State *state, const State *near, double distance, unsigned int attempts) const
Find a valid state near a given one. If the given state is valid, it will be returned itself...
void include(const ParamSet &other, const std::string &prefix="")
Include the params of a different ParamSet into this one. Optionally include a prefix for each of the...
A shared pointer wrapper for ompl::base::ValidStateSampler.
A shared pointer wrapper for ompl::base::StateSpace.
A shared pointer wrapper for ompl::base::StateSampler.
virtual void printSettings(std::ostream &out=std::cout) const
Print information about the current instance of the state space.
void setStateValidityChecker(const StateValidityCheckerPtr &svc)
Set the instance of the state validity checker to use. Parallel implementations of planners assume th...
A motion validator that only uses the state validity checker. Motions are checked for validity at a s...
double averageValidMotionLength(unsigned int attempts) const
Estimate the length of a valid motion. setup() is assumed to have been called.
unsigned int randomBounceMotion(const StateSamplerPtr &sss, const State *start, unsigned int steps, std::vector< State * > &states, bool alloc) const
Produce a valid motion starting at start by randomly bouncing off of invalid states. The start state start is not included in the computed motion (states). Returns the number of elements written to states (less or equal to steps).
A state sampler that only samples valid states, uniformly.
void setDefaultMotionValidator()
Set default motion validator for the state space.
A shared pointer wrapper for ompl::base::StateValidityChecker.
The simplest state validity checker: all states are valid.
duration seconds(double sec)
Return the time duration representing a given number of seconds.
Definition: Time.h:78
ValidStateSamplerPtr allocValidStateSampler() const
Allocate an instance of a valid state sampler for this space. If setValidStateSamplerAllocator() was ...
StateSpacePtr stateSpace_
The state space planning is to be performed in.
void setValidStateSamplerAllocator(const ValidStateSamplerAllocator &vssa)
Set the allocator to use for a valid state sampler. This replaces the default uniform valid state sam...
virtual void printProperties(std::ostream &out=std::cout) const
Print properties of the current instance of the state space.
bool checkMotion(const State *s1, const State *s2, std::pair< State *, double > &lastValid) const
Incrementally check if the path between two motions is valid. Also compute the last state that was va...
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
void samplesPerSecond(double &uniform, double &near, double &gaussian, unsigned int attempts) const
Estimate the number of samples that can be drawn per second, using the sampler returned by allocState...
Abstract definition for a class checking the validity of states. The implementation of this class mus...
double probabilityOfValidState(unsigned int attempts) const
Estimate probability of sampling a valid state. setup() is assumed to have been called.
A Reeds-Shepp motion validator that only uses the state validity checker. Motions are checked for val...
The base class for space information. This contains all the information about the space planning is d...
virtual void setup()
Perform additional setup tasks (run once, before use). If state validity checking resolution has not ...
Definition of an abstract state.
Definition: State.h:50
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
Definition: Console.h:66
A Dubins motion validator that only uses the state validity checker. Motions are checked for validity...
unsigned int getMotionStates(const State *s1, const State *s2, std::vector< State * > &states, unsigned int count, bool endpoints, bool alloc) const
Get count states that make up a motion between s1 and s2. Returns the number of states that were adde...
The exception type for ompl.
Definition: Exception.h:47
std::function< bool(const State *)> StateValidityCheckerFn
If no state validity checking class is specified (StateValidityChecker), a std::function can be speci...
point now()
Get the current time point.
Definition: Time.h:72
static const unsigned int TEST_STATE_COUNT
When multiple states need to be generated as part of the computation of various information (usually ...
void clearValidStateSamplerAllocator()
Clear the allocator used for the valid state sampler. This will revert to using the uniform valid sta...
std::chrono::system_clock::time_point point
Representation of a point in time.
Definition: Time.h:66
std::function< ValidStateSamplerPtr(const SpaceInformation *)> ValidStateSamplerAllocator
Definition of a function that can allocate a valid state sampler.
ParamSet params_
Combined parameters for the contained classes.
bool isSetup() const
Return true if setup was called.
void setNrAttempts(unsigned int attempts)
Finding a valid sample usually requires performing multiple attempts. This call allows setting the nu...