SPARSdb.cpp
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Rutgers the State University of New Jersey, New Brunswick
5  * Copyright (c) 2014, University of Colorado, Boulder
6  * All Rights Reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of Rutgers University nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 /* Author: Andrew Dobson, Dave Coleman */
37 
38 #include <ompl/tools/thunder/SPARSdb.h>
39 #include <ompl/geometric/planners/prm/ConnectionStrategy.h>
40 #include <ompl/base/goals/GoalSampleableRegion.h>
41 #include <ompl/tools/config/SelfConfig.h>
42 #include <ompl/util/Console.h>
43 #include <boost/graph/astar_search.hpp>
44 #include <boost/graph/incremental_components.hpp>
45 #include <boost/property_map/vector_property_map.hpp>
46 #include <boost/foreach.hpp>
47 
48 // Allow hooks for visualizing planner
49 //#define OMPL_THUNDER_DEBUG
50 
51 #define foreach BOOST_FOREACH
52 #define foreach_reverse BOOST_REVERSE_FOREACH
53 
54 // edgeWeightMap methods ////////////////////////////////////////////////////////////////////////////
55 
56 BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept<ompl::geometric::SPARSdb::edgeWeightMap, ompl::geometric::SPARSdb::Edge>));
57 
59  const EdgeCollisionStateMap &collisionStates)
60  : g_(graph),
61  collisionStates_(collisionStates)
62 {
63 }
64 
66 {
67  // Get the status of collision checking for this edge
68  if (collisionStates_[e] == IN_COLLISION)
69  return std::numeric_limits<double>::infinity();
70 
71  return boost::get(boost::edge_weight, g_, e);
72 }
73 
74 namespace boost
75 {
77 {
78  return m.get(e);
79 }
80 }
81 
82 // CustomVisitor methods ////////////////////////////////////////////////////////////////////////////
83 
84 BOOST_CONCEPT_ASSERT((boost::AStarVisitorConcept<ompl::geometric::SPARSdb::CustomVisitor, ompl::geometric::SPARSdb::Graph>));
85 
87  : goal(goal)
88 {
89 }
90 
92 {
93  if (u == goal)
94  throw foundGoalException();
95 }
96 
97 // SPARSdb methods ////////////////////////////////////////////////////////////////////////////////////////
98 
100  base::Planner(si, "SPARSdb"),
101  // Numeric variables
102  stretchFactor_(3.),
104  denseDeltaFraction_(.001),
105  maxFailures_(5000),
107  nearSamplePoints_((2*si_->getStateDimension())),
108  // Property accessors of edges
109  edgeWeightProperty_(boost::get(boost::edge_weight, g_)),
111  // Property accessors of vertices
112  stateProperty_(boost::get(vertex_state_t(), g_)),
113  colorProperty_(boost::get(vertex_color_t(), g_)),
115  // Disjoint set accessors
116  disjointSets_(boost::get(boost::vertex_rank, g_),
117  boost::get(boost::vertex_predecessor, g_)),
118  addedSolution_(false),
120  iterations_(0),
121  sparseDelta_(0.),
122  denseDelta_(0.),
123  verbose_(false)
124 {
127  specs_.optimizingPaths = true;
128 
129  psimp_.reset(new PathSimplifier(si_));
130 
131  Planner::declareParam<double>("stretch_factor", this, &SPARSdb::setStretchFactor, &SPARSdb::getStretchFactor, "1.1:0.1:3.0");
132  Planner::declareParam<double>("sparse_delta_fraction", this, &SPARSdb::setSparseDeltaFraction, &SPARSdb::getSparseDeltaFraction, "0.0:0.01:1.0");
133  Planner::declareParam<double>("dense_delta_fraction", this, &SPARSdb::setDenseDeltaFraction, &SPARSdb::getDenseDeltaFraction, "0.0:0.0001:0.1");
134  Planner::declareParam<unsigned int>("max_failures", this, &SPARSdb::setMaxFailures, &SPARSdb::getMaxFailures, "100:10:3000");
135 }
136 
138 {
139  freeMemory();
140 }
141 
143 {
144  Planner::setup();
145  if (!nn_)
146  nn_.reset(tools::SelfConfig::getDefaultNearestNeighbors<Vertex>(this));
147  nn_->setDistanceFunction(std::bind(&SPARSdb::distanceFunction, this, std::placeholders::_1, std::placeholders::_2));
148  double maxExt = si_->getMaximumExtent();
149  sparseDelta_ = sparseDeltaFraction_ * maxExt;
150  denseDelta_ = denseDeltaFraction_ * maxExt;
151 
152  if (!sampler_)
153  sampler_ = si_->allocValidStateSampler();
154 }
155 
157 {
158  Planner::setProblemDefinition(pdef);
159  clearQuery();
160 }
161 
163 {
164  startM_.clear();
165  goalM_.clear();
166  pis_.restart();
167 }
168 
170 {
171  Planner::clear();
172  clearQuery();
173  resetFailures();
174  iterations_ = 0;
175  freeMemory();
176  if (nn_)
177  nn_->clear();
178 }
179 
181 {
182  Planner::clear();
183  sampler_.reset();
184 
185  foreach (Vertex v, boost::vertices(g_))
186  {
187  foreach (InterfaceData &d, interfaceDataProperty_[v].interfaceHash | boost::adaptors::map_values)
188  d.clear(si_);
189  if( stateProperty_[v] != nullptr )
190  si_->freeState(stateProperty_[v]);
191  stateProperty_[v] = nullptr;
192  }
193  g_.clear();
194 
195  if (nn_)
196  nn_->clear();
197 }
198 
199 bool ompl::geometric::SPARSdb::getSimilarPaths(int nearestK, const base::State* start, const base::State* goal,
200  CandidateSolution &candidateSolution,
202 {
203  // TODO: nearestK unused
204 
205  // Get neighbors near start and goal. Note: potentially they are not *visible* - will test for this later
206 
207  // Start
208  OMPL_INFORM("Looking for a node near the problem start");
209  if (!findGraphNeighbors(start, startVertexCandidateNeighbors_))
210  {
211  OMPL_INFORM("No graph neighbors found for start within radius %f", sparseDelta_);
212  return false;
213  }
214  if (verbose_)
215  OMPL_INFORM("Found %d nodes near start", startVertexCandidateNeighbors_.size());
216 
217  // Goal
218  OMPL_INFORM("Looking for a node near the problem goal");
219  if (!findGraphNeighbors(goal, goalVertexCandidateNeighbors_))
220  {
221  OMPL_INFORM("No graph neighbors found for goal within radius %f", sparseDelta_);
222  return false;
223  }
224  if (verbose_)
225  OMPL_INFORM("Found %d nodes near goal", goalVertexCandidateNeighbors_.size());
226 
227  // Get paths between start and goal
228  bool result = getPaths(startVertexCandidateNeighbors_, goalVertexCandidateNeighbors_,
229  start, goal, candidateSolution, ptc);
230 
231  // Error check
232  if (!result)
233  {
234  OMPL_INFORM("getSimilarPaths(): SPARSdb returned FALSE for getPaths");
235  return false;
236  }
237  if (!candidateSolution.path_)
238  {
239  OMPL_ERROR("getSimilarPaths(): SPARSdb returned solution is nullptr");
240  return false;
241  }
242 
243  // Debug output
244  if (false)
245  {
246  ompl::geometric::PathGeometric geometricSolution
247  = static_cast<ompl::geometric::PathGeometric&>(*candidateSolution.path_);
248 
249  for (std::size_t i = 0; i < geometricSolution.getStateCount(); ++i)
250  {
251  OMPL_INFORM(" getSimilarPaths(): Adding state %f to plannerData", i );
252  si_->printState(geometricSolution.getState(i), std::cout);
253  }
254  }
255 
256  return result;
257 }
258 
259 bool ompl::geometric::SPARSdb::getPaths(const std::vector<Vertex> &candidateStarts,
260  const std::vector<Vertex> &candidateGoals,
261  const base::State* actualStart,
262  const base::State* actualGoal,
263  CandidateSolution &candidateSolution,
265 {
266  // Try every combination of nearby start and goal pairs
267  foreach (Vertex start, candidateStarts)
268  {
269  // Check if this start is visible from the actual start
270  if (!si_->checkMotion(actualStart, stateProperty_[start]))
271  {
272  if (verbose_)
273  OMPL_WARN("FOUND CANDIDATE START THAT IS NOT VISIBLE ");
274  continue; // this is actually not visible
275  }
276 
277  foreach (Vertex goal, candidateGoals)
278  {
279  if (verbose_)
280  OMPL_INFORM(" foreach_goal: Checking motion from %d to %d", actualGoal, stateProperty_[goal]);
281 
282  // Check if our planner is out of time
283  if (ptc == true)
284  {
285  OMPL_DEBUG("getPaths function interrupted because termination condition is true.");
286  return false;
287  }
288 
289  // Check if this goal is visible from the actual goal
290  if (!si_->checkMotion(actualGoal, stateProperty_[goal]))
291  {
292  if (verbose_)
293  OMPL_INFORM("FOUND CANDIDATE GOAL THAT IS NOT VISIBLE! ");
294  continue; // this is actually not visible
295  }
296 
297  // Repeatidly search through graph for connection then check for collisions then repeat
298  if (lazyCollisionSearch( start, goal, actualStart, actualGoal, candidateSolution, ptc))
299  {
300  // Found a path
301  return true;
302  }
303  else
304  {
305  // Did not find a path
306  OMPL_INFORM("Did not find a path, looking for other start/goal combinations ");
307  }
308 
309  } // foreach
310  } // foreach
311 
312  return false;
313 }
314 
316  const Vertex &goal,
317  const base::State* actualStart,
318  const base::State* actualGoal,
319  CandidateSolution &candidateSolution,
321 {
322  base::Goal *g = pdef_->getGoal().get(); // for checking isStartGoalPairValid
323 
324  // Vector to store candidate paths in before they are converted to PathPtrs
325  std::vector<Vertex> vertexPath;
326 
327  // decide if start and goal are connected
328  // TODO this does not compute dynamic graphcs
329  // i.e. it will say its the same components even when an edge has been disabled
330  bool same_component = true; //sameComponent(start, goal); // TODO is this important? I disabled it during dev and never used it
331 
332  // Check if the chosen start and goal can be used together to satisfy problem
333  if (!same_component)
334  {
335  if (verbose_)
336  OMPL_INFORM(" Goal and start are not part of same component, skipping ");
337  return false;
338  }
339 
340  // TODO: remove this because start and goal are not either start nor goals
341  if (!g->isStartGoalPairValid(stateProperty_[goal], stateProperty_[start]))
342  {
343  if (verbose_)
344  OMPL_INFORM(" Start and goal pair are not valid combinations, skipping ");
345  return false;
346  }
347 
348  // Make sure that the start and goal aren't so close together that they find the same vertex
349  if (start == goal)
350  {
351  if (verbose_)
352  OMPL_INFORM(" Start equals goal, skipping ");
353  return false;
354  }
355 
356 
357  // Keep looking for paths between chosen start and goal until one is found that is valid,
358  // or no further paths can be found between them because of disabled edges
359  // this is necessary for lazy collision checking i.e. rerun after marking invalid edges we found
360  bool havePartialSolution = false;
361  while (true)
362  {
363  if (verbose_)
364  OMPL_INFORM(" while true: look for valid paths between start and goal");
365 
366  // Check if our planner is out of time
367  if (ptc == true)
368  {
369  OMPL_DEBUG("lazyCollisionSearch: function interrupted because termination condition is true.");
370  return false;
371  }
372 
373  // Attempt to find a solution from start to goal
374  if (!constructSolution(start, goal, vertexPath))
375  {
376  // We will stop looking through this start-goal combination, but perhaps this partial solution is good
377  if (verbose_)
378  OMPL_INFORM(" unable to construct solution between start and goal using astar");
379 
380  // no solution path found. check if a previous partially correct solution was found
381  if (havePartialSolution && false) // TODO: re-implement partial solution logic
382  {
383  if (verbose_)
384  OMPL_INFORM("has partial solution ");
385  // Save this candidateSolution for later
386  convertVertexPathToStatePath(vertexPath, actualStart, actualGoal, candidateSolution);
387  return false;
388  }
389 
390  if (verbose_)
391  OMPL_INFORM(" no partial solution found on this astar search, keep looking through start-goal combos");
392 
393  // no path found what so ever
394  //return false;
395  return false;
396  }
397  havePartialSolution = true; // we have found at least one path at this point. may be invalid
398 
399  if (verbose_)
400  {
401  OMPL_INFORM(" has at least a partial solution, maybe exact solution");
402  OMPL_INFORM(" Solution has %d vertices", vertexPath.size());
403  }
404 
405  // Check if all the points in the potential solution are valid
406  if (lazyCollisionCheck(vertexPath, ptc))
407  {
408  if (verbose_)
409  {
410  OMPL_INFORM("---------- lazy collision check returned valid ");
411  }
412 
413  // the path is valid, we are done!
414  convertVertexPathToStatePath(vertexPath, actualStart, actualGoal, candidateSolution);
415  return true;
416  }
417  // else, loop with updated graph that has the invalid edges/states disabled
418  } // while
419 
420  // we never found a valid path
421  return false;
422 }
423 
425  std::vector<Vertex> &vertexPath) const
426 {
427  Vertex *vertexPredecessors = new Vertex[boost::num_vertices(g_)];
428  bool foundGoal = false;
429 
430  double *vertexDistances = new double[boost::num_vertices(g_)];
431 
432  try
433  {
434  boost::astar_search(g_, // graph
435  start, // start state
436  std::bind(&SPARSdb::distanceFunction, this, std::placeholders::_1, goal), // the heuristic
437  // ability to disable edges (set cost to inifinity):
438  boost::weight_map(edgeWeightMap(g_, edgeCollisionStateProperty_)).
439  predecessor_map(vertexPredecessors).
440  distance_map(&vertexDistances[0]).
441  visitor(CustomVisitor(goal)));
442  }
444  {
445  // the custom exception from CustomVisitor
446  if (verbose_ && false)
447  {
448  OMPL_INFORM("constructSolution: Astar found goal vertex ------------------------");
449  OMPL_INFORM("distance to goal: %f", vertexDistances[goal]);
450  }
451 
452  if (vertexDistances[goal] > 1.7e+308) // terrible hack for detecting infinity
453  //double diff = d[goal] - std::numeric_limits<double>::infinity();
454  //if ((diff < std::numeric_limits<double>::epsilon()) && (-diff < std::numeric_limits<double>::epsilon()))
455  // check if the distance to goal is inifinity. if so, it is unreachable
456  //if (d[goal] >= std::numeric_limits<double>::infinity())
457  {
458  if (verbose_)
459  OMPL_INFORM("Distance to goal is infinity");
460  foundGoal = false;
461  }
462  else
463  {
464  // Only clear the vertexPath after we know we have a new solution, otherwise it might have a good
465  // previous one
466  vertexPath.clear(); // remove any old solutions
467 
468  // Trace back the shortest path in reverse and only save the states
469  Vertex v;
470  for (v = goal; v != vertexPredecessors[v]; v = vertexPredecessors[v])
471  {
472  vertexPath.push_back(v);
473  }
474  if (v != goal) // TODO explain this because i don't understand
475  {
476  vertexPath.push_back(v);
477  }
478 
479  foundGoal = true;
480  }
481  }
482 
483  delete[] vertexPredecessors;
484  delete[] vertexDistances;
485 
486  // No solution found from start to goal
487  return foundGoal;
488 }
489 
490 bool ompl::geometric::SPARSdb::lazyCollisionCheck(std::vector<Vertex> &vertexPath,
492 {
493  OMPL_DEBUG("Starting lazy collision checking");
494 
495  bool hasInvalidEdges = false;
496 
497  // Initialize
498  Vertex fromVertex = vertexPath[0];
499  Vertex toVertex;
500 
501  // Loop through every pair of states and make sure path is valid.
502  for (std::size_t toID = 1; toID < vertexPath.size(); ++toID)
503  {
504  // Increment location on path
505  toVertex = vertexPath[toID];
506 
507  // Check if our planner is out of time
508  if (ptc == true)
509  {
510  OMPL_DEBUG("Lazy collision check function interrupted because termination condition is true.");
511  return false;
512  }
513 
514  Edge thisEdge = boost::edge(fromVertex, toVertex, g_).first;
515 
516  // Has this edge already been checked before?
517  if (edgeCollisionStateProperty_[thisEdge] == NOT_CHECKED)
518  {
519  // Check path between states
520  if (!si_->checkMotion(stateProperty_[fromVertex], stateProperty_[toVertex]))
521  {
522  // Path between (from, to) states not valid, disable the edge
523  OMPL_INFORM(" DISABLING EDGE from vertex %f to vertex %f", fromVertex, toVertex);
524 
525  // Disable edge
526  edgeCollisionStateProperty_[thisEdge] = IN_COLLISION;
527  }
528  else
529  {
530  // Mark edge as free so we no longer need to check for collision
531  edgeCollisionStateProperty_[thisEdge] = FREE;
532  }
533  }
534 
535  // Check final result
536  if (edgeCollisionStateProperty_[thisEdge] == IN_COLLISION)
537  {
538  // Remember that this path is no longer valid, but keep checking remainder of path edges
539  hasInvalidEdges = true;
540  }
541 
542  // switch vertex focus
543  fromVertex = toVertex;
544  }
545 
546  OMPL_INFORM("Done lazy collision checking");
547 
548  // TODO: somewhere in the code we need to reset all edges collision status back to NOT_CHECKED for future queries
549 
550  // Only return true if nothing was found invalid
551  return !hasInvalidEdges;
552 }
553 
555 {
556  return boost::same_component(m1, m2, disjointSets_);
557 }
558 
560 {
561  return consecutiveFailures_ >= maxFailures_;
562 }
563 
564 void ompl::geometric::SPARSdb::printDebug(std::ostream &out) const
565 {
566  out << "SPARSdb Debug Output: " << std::endl;
567  out << " Settings: " << std::endl;
568  out << " Max Failures: " << getMaxFailures() << std::endl;
569  out << " Dense Delta Fraction: " << getDenseDeltaFraction() << std::endl;
570  out << " Sparse Delta Fraction: " << getSparseDeltaFraction() << std::endl;
571  out << " Sparse Delta: " << sparseDelta_ << std::endl;
572  out << " Stretch Factor: " << getStretchFactor() << std::endl;
573  out << " Maximum Extent: " << si_->getMaximumExtent() << std::endl;
574  out << " Status: " << std::endl;
575  out << " Vertices Count: " << getNumVertices() << std::endl;
576  out << " Edges Count: " << getNumEdges() << std::endl;
577  out << " Iterations: " << getIterations() << std::endl;
578  out << " Consecutive Failures: " << consecutiveFailures_ << std::endl;
579  out << " Number of guards: " << nn_->size() << std::endl << std::endl;
580 }
581 
582 bool ompl::geometric::SPARSdb::getGuardSpacingFactor(const double pathLength, int &numGuards, double &spacingFactor)
583 {
584  static const double factorHigh = 1.9;
585  static const double factorLow = 1.1;
586  double minPathLength = sparseDelta_ * factorLow;
587 
588  // Check if the path length is too short
589  if (pathLength < minPathLength )
590  {
591  OMPL_INFORM("Path length is too short to get a correct sparcing factor: length: %f, min: %f ", pathLength, minPathLength);
592  spacingFactor = factorLow;
593  return true; // still attempt
594  }
595 
596  // Get initial guess using med value
597  double numGuardsFraction = pathLength / (sparseDelta_ * factorLow);
598  if (verbose_)
599  {
600  OMPL_INFORM("getGuardSpacingFactor: ");
601  OMPL_INFORM(" pathLength: %f", pathLength);
602  OMPL_INFORM(" sparseDelta: %f", sparseDelta_);
603  OMPL_INFORM(" min pathLength: %f", minPathLength);
604  OMPL_INFORM(" numGuardsFraction: %f", numGuardsFraction);
605  }
606 
607  // Round down to nearest integer
608  numGuards = numGuardsFraction;
609 
610  static std::size_t MAX_ATTEMPTS = 4;
611  for (std::size_t i = 0; i < MAX_ATTEMPTS; ++i)
612  {
613  if (verbose_)
614  OMPL_INFORM(" numGuards: %d", numGuards);
615 
616  // Find the factor to achieve this number of guards
617  spacingFactor = pathLength / (sparseDelta_ * numGuards);
618  if (verbose_)
619  OMPL_INFORM(" new spacingFactor: %f", spacingFactor);
620 
621  // Check if this factor is too low
622  if ( spacingFactor < factorLow )
623  {
624  if (verbose_)
625  OMPL_INFORM(" spacing factor is too low ");
626  numGuards ++;
627  continue;
628  }
629  else if ( spacingFactor > factorHigh )
630  {
631  if (verbose_)
632  OMPL_INFORM(" spacing factor is too high ");
633  numGuards --;
634  continue;
635  }
636  else
637  return true; // a good value
638  }
639 
640  OMPL_ERROR("Unable to find correct spacing factor - perhaps this is a bug");
641  spacingFactor = factorLow;
642  return true; // still attempt
643 }
644 
645 bool ompl::geometric::SPARSdb::addPathToRoadmap(const base::PlannerTerminationCondition &ptc,
646  ompl::geometric::PathGeometric& solutionPath)
647 {
648  // Check that the query vertex is initialized (used for internal nearest neighbor searches)
649  checkQueryStateInitialization();
650 
651  // Error check
652  if (solutionPath.getStateCount() < 2)
653  {
654  OMPL_ERROR("Less than 2 states were passed to addPathToRoadmap in the solution path");
655  return false;
656  }
657 
658  // Find spacing factor - 2.0 would be a perfect amount, but we leave room for rounding/interpolation errors and curves in path
659  int numGuards; // unused variable that indicates how many guards we will add
660  double spacingFactor;
661  if (!getGuardSpacingFactor( solutionPath.length(), numGuards, spacingFactor ))
662  return false;
663 
664  OMPL_DEBUG("Expected number of necessary coverage guards is calculated to be %i from the original path state count %i",
665  numGuards, solutionPath.getStateCount());
666 
667  unsigned int n = 0;
668  const int n1 = solutionPath.getStateCount() - 1;
669  for (int i = 0 ; i < n1 ; ++i)
670  n += si_->getStateSpace()->validSegmentCount(solutionPath.getState(i), solutionPath.getState(i + 1));
671 
672  solutionPath.interpolate(n);
673 
674  // Debug
675  if (verbose_)
676  {
677  OMPL_INFORM("-------------------------------------------------------");
678  OMPL_INFORM("Attempting to add %d states to roadmap", solutionPath.getStateCount());
679  OMPL_INFORM("-------------------------------------------------------");
680  }
681 
682  // Try to add the start first, but don't force it
683  addStateToRoadmap(ptc, solutionPath.getState(0));
684 
685 #ifdef OMPL_THUNDER_DEBUG
686  visualizeStateCallback(solutionPath.getState(solutionPath.getStateCount() - 1), 3, sparseDelta_);
687 #endif
688 
689  // Add solution states to SPARSdb one by one ---------------------------
690 
691  // Track which nodes we've already tried to add
692  std::vector<std::size_t> addedStateIDs;
693  // Track which nodes we will attempt to use as connectivity states
694  std::vector<std::size_t> connectivityStateIDs;
695  //std::vector<base::State*> connectivityStates;
696 
697  double distanceFromLastState = 0;
698 
699  std::size_t lastStateID = 0; // track the id in the solutionPath of the last state
700 
701  for (std::size_t i = 1; i < solutionPath.getStateCount(); ++i) // skip 0 and last because those are start/goal and are already added
702  {
703  distanceFromLastState = si_->distance( solutionPath.getState(i), solutionPath.getState(lastStateID));
704 
705  if (verbose_ && false)
706  {
707  OMPL_INFORM("Index %d at distance %f from last state ", i, distanceFromLastState);
708  }
709 
710  if (distanceFromLastState >= sparseDelta_ * spacingFactor)
711  {
712  if (verbose_)
713  {
714  OMPL_INFORM("Adding state %d of %d", i, solutionPath.getStateCount());
715  }
716 
717  // Show the candidate state in Rviz for path insertion of GUARDS
718 #ifdef OMPL_THUNDER_DEBUG
719  visualizeStateCallback(solutionPath.getState(i), 1, sparseDelta_);
720 #endif
721 
722  // Add a single state to the roadmap
723  if (!addStateToRoadmap(ptc, solutionPath.getState(i)))
724  {
725  if (verbose_)
726  {
727  OMPL_INFORM("Last state added to roadmap failed ");
728  }
729  }
730 
731  // Now figure out midpoint state between lastState and i
732  std::size_t midStateID = (i - lastStateID)/2 + lastStateID;
733  connectivityStateIDs.push_back(midStateID);
734 
735  double distA = si_->distance( solutionPath.getState(lastStateID), solutionPath.getState(midStateID));
736  double distB = si_->distance( solutionPath.getState(i), solutionPath.getState(midStateID));
737  double diff = distA - distB;
738  if ((diff < std::numeric_limits<double>::epsilon()) && (-diff < std::numeric_limits<double>::epsilon()))
739  if (verbose_)
740  OMPL_WARN("DISTANCES ARE DIFFERENT ");
741 
742  // Save this state as the new last state
743  lastStateID = i;
744  // Remember which nodes we've already added / attempted to add
745  addedStateIDs.push_back(midStateID);
746  addedStateIDs.push_back(i);
747 
748  }
749  // Close up if it doesn't do it automatically
750  else if (i == solutionPath.getStateCount() - 1)
751  {
752  if (verbose_)
753  OMPL_INFORM("Last state - do special midpoint");
754 
755  // Now figure out midpoint state between lastState and i
756  std::size_t midStateID = (i - lastStateID)/2 + lastStateID;
757  connectivityStateIDs.push_back(midStateID);
758  addedStateIDs.push_back(midStateID);
759  if (verbose_)
760  OMPL_INFORM("Mid state is %d", midStateID);
761  }
762  }
763 
764  // Attempt to add the goal directly
765  addStateToRoadmap(ptc, solutionPath.getState(solutionPath.getStateCount() - 1));
766 
767  if (verbose_)
768  {
769  OMPL_INFORM("-------------------------------------------------------");
770  OMPL_INFORM("-------------------------------------------------------");
771  OMPL_INFORM("Adding connectivity states ----------------------------");
772  OMPL_INFORM("-------------------------------------------------------");
773  OMPL_INFORM("-------------------------------------------------------");
774  }
775 
776  for (std::size_t i = 0; i < connectivityStateIDs.size(); ++i)
777  {
778  base::State* connectivityState = solutionPath.getState( connectivityStateIDs[i] );
779 
780  if (verbose_)
781  {
782  OMPL_INFORM("Adding connectvity state ", i);
783  }
784 
785 #ifdef OMPL_THUNDER_DEBUG
786  // Show the candidate state in Rviz for path insertion of BRIDGES (CONNECTIVITY)
787  visualizeStateCallback(connectivityState, 2, sparseDelta_);
788  sleep(0.5);
789 #endif
790 
791  // Add a single state to the roadmap
792  addStateToRoadmap(ptc, connectivityState);
793  }
794 
795  // Add remaining states at random
796  if (verbose_)
797  {
798  OMPL_INFORM("-------------------------------------------------------");
799  OMPL_INFORM("-------------------------------------------------------");
800  OMPL_INFORM("Adding remaining states randomly ----------------------");
801  OMPL_INFORM("-------------------------------------------------------");
802  OMPL_INFORM("-------------------------------------------------------");
803  }
804 
805  // Create a vector of shuffled indexes
806  std::vector<std::size_t> shuffledIDs;
807  std::size_t usedIDTracker = 0;
808  for (std::size_t i = 1; i < solutionPath.getStateCount(); ++i) // skip 0 because start already added
809  {
810  // Check if we've already used this id
811  if (usedIDTracker < addedStateIDs.size() && i == addedStateIDs[usedIDTracker])
812  {
813  // skip this id
814  usedIDTracker ++;
815  continue;
816  }
817 
818  shuffledIDs.push_back(i); // 1 2 3...
819  }
820 
821  std::random_shuffle ( shuffledIDs.begin(), shuffledIDs.end() ); // using built-in random generator:
822 
823  // Add each state randomly
824  for (std::size_t i = 0; i < shuffledIDs.size(); ++i)
825  {
826 
827 #ifdef OMPL_THUNDER_DEBUG
828  visualizeStateCallback(solutionPath.getState(shuffledIDs[i]), 1, sparseDelta_);
829 #endif
830 
831  // Add a single state to the roadmap
832  addStateToRoadmap(ptc, solutionPath.getState(shuffledIDs[i]));
833  }
834 
835  bool benchmarkLogging = true;
836  if (benchmarkLogging)
837  {
838  OMPL_DEBUG("ompl::geometric::SPARSdb: Benchmark logging enabled (slower)");
839 
840  // Return the result of inserting into database, if applicable
841  return checkStartGoalConnection( solutionPath );
842  }
843 
844  return true;
845 }
846 
847 bool ompl::geometric::SPARSdb::checkStartGoalConnection(ompl::geometric::PathGeometric& solutionPath)
848 {
849  // Make sure path has states
850  if (solutionPath.getStateCount() < 2)
851  {
852  OMPL_ERROR("Not enought states (< 2) in the solutionPath");
853  return false;
854  }
855 
856  bool error = false;
857  CandidateSolution candidateSolution;
858  do
859  {
860  base::State* actualStart = solutionPath.getState(0);
861  base::State* actualGoal = solutionPath.getState(solutionPath.getStateCount() - 1);
862 
863  /* The whole neighborhood set which has been most recently computed */
864  std::vector<Vertex> graphNeighborhood;
865  /* The visible neighborhood set which has been most recently computed */
866  std::vector<Vertex> visibleNeighborhood;
867 
868  // Get start vertex
869  findGraphNeighbors(actualStart, graphNeighborhood, visibleNeighborhood);
870  if (!visibleNeighborhood.size())
871  {
872  OMPL_ERROR("No vertexes found near start");
873  error = true;
874  break;
875  }
876  Vertex closeStart = visibleNeighborhood[0];
877 
878  // Get goal vertex
879  findGraphNeighbors(actualGoal, graphNeighborhood, visibleNeighborhood);
880  if (!visibleNeighborhood.size())
881  {
882  OMPL_ERROR("No vertexes found near goal");
883  error = true;
884  break;
885  }
886  Vertex closeGoal = visibleNeighborhood[0];
887 
888  // Check if connected
889  if (false)
890  if (!sameComponent(closeStart, closeGoal))
891  {
892  OMPL_ERROR("Start and goal are not connected!");
893  error = true;
894  break;
895  }
896 
897  // Get new path from start to goal
898  std::vector<Vertex> vertexPath;
899  if (!constructSolution(closeStart, closeGoal, vertexPath))
900  {
901  OMPL_ERROR("Unable to find path from start to goal - perhaps because of new obstacles");
902  error = true;
903  break;
904  }
905 
906  // Convert to PathGeometric
907  bool disableCollisionWarning = true; // this is just for benchmarking purposes
908  if (!convertVertexPathToStatePath(vertexPath, actualStart, actualGoal, candidateSolution, disableCollisionWarning))
909  {
910  OMPL_ERROR("Unable to convert to state path");
911  error = true;
912  break;
913  }
914  } while(false);
915 
916  // Check distance of new path from old path
917  double originalLength = solutionPath.length();
918 
919  OMPL_DEBUG("Results of attempting to make insertion in SPARSdb ");
920  OMPL_DEBUG("-------------------------------------------------------");
921  OMPL_DEBUG("Original length: %f", originalLength);
922 
923  if (error)
924  {
925  OMPL_ERROR("UNABLE TO GET PATH");
926 
927  // Record this for plotting
928  numPathInsertionFailures_++;
929  }
930  else
931  {
932  double newLength = candidateSolution.getGeometricPath().length();
933  double percentIncrease = 100 - originalLength / newLength * 100;
934  OMPL_DEBUG("New length: %f", newLength);
935  OMPL_DEBUG("Percent increase: %f %%", percentIncrease);
936  }
937 
938  return !error; // return true if it inserted correctly
939 }
940 
941 bool ompl::geometric::SPARSdb::addStateToRoadmap(const base::PlannerTerminationCondition &ptc, base::State *newState)
942 {
943  bool stateAdded = false;
944  // Check that the query vertex is initialized (used for internal nearest neighbor searches)
945  checkQueryStateInitialization();
946 
947  // Deep copy
948  base::State *qNew = si_->cloneState(newState);
949  base::State *workState = si_->allocState();
950 
951  /* The whole neighborhood set which has been most recently computed */
952  std::vector<Vertex> graphNeighborhood;
953  /* The visible neighborhood set which has been most recently computed */
954  std::vector<Vertex> visibleNeighborhood;
955 
956  ++iterations_;
957 
958  findGraphNeighbors(qNew, graphNeighborhood, visibleNeighborhood);
959 
960  if (verbose_)
961  {
962  OMPL_INFORM(" graph neighborhood: %d | visible neighborhood: %d", graphNeighborhood.size(),
963  visibleNeighborhood.size());
964 
965  foreach(Vertex v, visibleNeighborhood)
966  {
967  OMPL_INFORM("Visible neighbor is vertex %f with distance %f ",
968  v, si_->distance( qNew, stateProperty_[v]));
969  }
970  }
971 
972  if (verbose_)
973  OMPL_INFORM(" - checkAddCoverage() Are other nodes around it visible?");
974  // Coverage criterion
975  if (!checkAddCoverage(qNew, visibleNeighborhood)) // Always add a node if no other nodes around it are visible (GUARD)
976  {
977  if (verbose_)
978  OMPL_INFORM(" -- checkAddConnectivity() Does this node connect neighboring nodes that are not connected? ");
979  // Connectivity criterion
980  if (!checkAddConnectivity(qNew, visibleNeighborhood))
981  {
982  if (verbose_)
983  OMPL_INFORM(" --- checkAddInterface() Does this node's neighbor's need it to better connect them? ");
984  if (!checkAddInterface(qNew, graphNeighborhood, visibleNeighborhood))
985  {
986  if (verbose_)
987  OMPL_INFORM(" ---- Ensure SPARS asymptotic optimality");
988  if (visibleNeighborhood.size() > 0)
989  {
990  std::map<Vertex, base::State*> closeRepresentatives;
991  if (verbose_)
992  OMPL_INFORM(" ----- findCloseRepresentatives()");
993 
994  findCloseRepresentatives(workState, qNew, visibleNeighborhood[0], closeRepresentatives, ptc);
995  if (verbose_)
996  OMPL_INFORM("------ Found %d close representatives", closeRepresentatives.size());
997 
998  for (std::map<Vertex, base::State*>::iterator it = closeRepresentatives.begin(); it != closeRepresentatives.end(); ++it)
999  {
1000  if (verbose_)
1001  OMPL_INFORM(" ------ Looping through close representatives");
1002  updatePairPoints(visibleNeighborhood[0], qNew, it->first, it->second);
1003  updatePairPoints(it->first, it->second, visibleNeighborhood[0], qNew);
1004  }
1005  if (verbose_)
1006  OMPL_INFORM(" ------ checkAddPath()");
1007  if (checkAddPath(visibleNeighborhood[0]))
1008  {
1009  if (verbose_)
1010  {
1011  OMPL_INFORM("nearest visible neighbor added ");
1012  }
1013  }
1014 
1015  for (std::map<Vertex, base::State*>::iterator it = closeRepresentatives.begin(); it != closeRepresentatives.end(); ++it)
1016  {
1017  if (verbose_)
1018  OMPL_INFORM(" ------- Looping through close representatives to add path");
1019  checkAddPath(it->first);
1020  si_->freeState(it->second);
1021  }
1022  if (verbose_)
1023  OMPL_INFORM("------ Done with inner most loop ");
1024  }
1025  }
1026  else // added for interface
1027  {
1028  stateAdded = true;
1029  }
1030  }
1031  else // added for connectivity
1032  {
1033  stateAdded = true;
1034  }
1035  }
1036  else // added for coverage
1037  {
1038  stateAdded = true;
1039  }
1040 
1041  if (!stateAdded)
1042  ++consecutiveFailures_;
1043 
1044  si_->freeState(workState);
1045  si_->freeState(qNew);
1046 
1047  return stateAdded;
1048 }
1049 
1051 {
1052  if (boost::num_vertices(g_) < 1)
1053  {
1054  queryVertex_ = boost::add_vertex( g_ );
1055  stateProperty_[queryVertex_] = nullptr;
1056  }
1057 }
1058 
1060 {
1061  // Disabled
1063 }
1064 
1065 bool ompl::geometric::SPARSdb::checkAddCoverage(const base::State *qNew, std::vector<Vertex> &visibleNeighborhood)
1066 {
1067  if (visibleNeighborhood.size() > 0)
1068  return false;
1069  //No free paths means we add for coverage
1070  if (verbose_)
1071  OMPL_INFORM(" --- Adding node for COVERAGE ");
1072  Vertex v = addGuard(si_->cloneState(qNew), COVERAGE);
1073  if (verbose_)
1074  OMPL_INFORM(" Added vertex %f", v);
1075 
1076  return true;
1077 }
1078 
1079 bool ompl::geometric::SPARSdb::checkAddConnectivity(const base::State *qNew, std::vector<Vertex> &visibleNeighborhood)
1080 {
1081  // Identify visibile nodes around our new state that are unconnected (in different connected components)
1082  // and connect them
1083 
1084  std::vector<Vertex> statesInDiffConnectedComponents; // links
1085  if (visibleNeighborhood.size() > 1) // if less than 2 there is no way to find a pair of nodes in different connected components
1086  {
1087  //For each neighbor
1088  for (std::size_t i = 0; i < visibleNeighborhood.size(); ++i)
1089  {
1090  //For each other neighbor
1091  for (std::size_t j = i + 1; j < visibleNeighborhood.size(); ++j)
1092  {
1093  //If they are in different components
1094  if (!sameComponent(visibleNeighborhood[i], visibleNeighborhood[j]))
1095  {
1096  statesInDiffConnectedComponents.push_back(visibleNeighborhood[i]);
1097  statesInDiffConnectedComponents.push_back(visibleNeighborhood[j]);
1098  }
1099  }
1100  }
1101 
1102  // Were any diconnected states found?
1103  if (statesInDiffConnectedComponents.size() > 0)
1104  {
1105  if (verbose_)
1106  OMPL_INFORM(" --- Adding node for CONNECTIVITY ");
1107  //Add the node
1108  Vertex newVertex = addGuard(si_->cloneState(qNew), CONNECTIVITY);
1109 
1110  for (std::size_t i = 0; i < statesInDiffConnectedComponents.size() ; ++i)
1111  {
1112  //If there's no edge between the two new states
1113  // DTC: this should actually never happen - we just created the new vertex so
1114  // why would it be connected to anything?
1115  if (!boost::edge(newVertex, statesInDiffConnectedComponents[i], g_).second)
1116  {
1117  //The components haven't been united by previous links
1118  if (!sameComponent(statesInDiffConnectedComponents[i], newVertex))
1119  connectGuards(newVertex, statesInDiffConnectedComponents[i]);
1120  }
1121  }
1122 
1123  return true;
1124  }
1125  }
1126  return false;
1127 }
1128 
1129 bool ompl::geometric::SPARSdb::checkAddInterface(const base::State *qNew, std::vector<Vertex> &graphNeighborhood, std::vector<Vertex> &visibleNeighborhood)
1130 {
1131  //If we have at least 2 neighbors
1132  if (visibleNeighborhood.size() > 1)
1133  {
1134  // If the two closest nodes are also visible
1135  if (graphNeighborhood[0] == visibleNeighborhood[0] && graphNeighborhood[1] == visibleNeighborhood[1])
1136  {
1137  // If our two closest neighbors don't share an edge
1138  if (!boost::edge(visibleNeighborhood[0], visibleNeighborhood[1], g_).second)
1139  {
1140  //If they can be directly connected
1141  if (si_->checkMotion(stateProperty_[visibleNeighborhood[0]], stateProperty_[visibleNeighborhood[1]]))
1142  {
1143  //Connect them
1144  if (verbose_)
1145  OMPL_INFORM(" --- INTERFACE: directly connected nodes ");
1146  connectGuards(visibleNeighborhood[0], visibleNeighborhood[1]);
1147  //And report that we added to the roadmap
1148  resetFailures();
1149  //Report success
1150  return true;
1151  }
1152  else
1153  {
1154  //Add the new node to the graph, to bridge the interface
1155  if (verbose_)
1156  OMPL_INFORM(" --- Adding node for INTERFACE ");
1157  Vertex v = addGuard(si_->cloneState(qNew), INTERFACE);
1158  connectGuards(v, visibleNeighborhood[0]);
1159  connectGuards(v, visibleNeighborhood[1]);
1160  if (verbose_)
1161  OMPL_INFORM(" --- INTERFACE: connected two neighbors through new interface node ");
1162  //Report success
1163  return true;
1164  }
1165  }
1166  }
1167  }
1168  return false;
1169 }
1170 
1172 {
1173  bool spannerPropertyWasViolated = false;
1174 
1175  std::vector< Vertex > rs;
1176  foreach( Vertex r, boost::adjacent_vertices( v, g_ ) )
1177  rs.push_back(r);
1178 
1179  /* Candidate x vertices as described in the method, filled by function computeX(). */
1180  std::vector<Vertex> Xs;
1181 
1182  /* Candidate v" vertices as described in the method, filled by function computeVPP(). */
1183  std::vector<Vertex> VPPs;
1184 
1185  for (std::size_t i = 0; i < rs.size() && !spannerPropertyWasViolated; ++i)
1186  {
1187  Vertex r = rs[i];
1188  computeVPP(v, r, VPPs);
1189  foreach (Vertex rp, VPPs)
1190  {
1191  //First, compute the longest path through the graph
1192  computeX(v, r, rp, Xs);
1193  double rm_dist = 0.0;
1194  foreach( Vertex rpp, Xs)
1195  {
1196  double tmp_dist = (si_->distance( stateProperty_[r], stateProperty_[v] )
1197  + si_->distance( stateProperty_[v], stateProperty_[rpp] ) )/2.0;
1198  if( tmp_dist > rm_dist )
1199  rm_dist = tmp_dist;
1200  }
1201 
1202  InterfaceData& d = getData( v, r, rp );
1203 
1204  //Then, if the spanner property is violated
1205  if (rm_dist > stretchFactor_ * d.d_)
1206  {
1207  spannerPropertyWasViolated = true; //Report that we added for the path
1208  if (si_->checkMotion(stateProperty_[r], stateProperty_[rp]))
1209  connectGuards(r, rp);
1210  else
1211  {
1212  PathGeometric *p = new PathGeometric( si_ );
1213  if (r < rp)
1214  {
1215  p->append(d.sigmaA_);
1216  p->append(d.pointA_);
1217  p->append(stateProperty_[v]);
1218  p->append(d.pointB_);
1219  p->append(d.sigmaB_);
1220  }
1221  else
1222  {
1223  p->append(d.sigmaB_);
1224  p->append(d.pointB_);
1225  p->append(stateProperty_[v]);
1226  p->append(d.pointA_);
1227  p->append(d.sigmaA_);
1228  }
1229 
1230  psimp_->reduceVertices(*p, 10);
1231  psimp_->shortcutPath(*p, 50);
1232 
1233  if (p->checkAndRepair(100).second)
1234  {
1235  Vertex prior = r;
1236  Vertex vnew;
1237  std::vector<base::State*>& states = p->getStates();
1238 
1239  foreach (base::State *st, states)
1240  {
1241  // no need to clone st, since we will destroy p; we just copy the pointer
1242  if (verbose_)
1243  OMPL_INFORM(" --- Adding node for QUALITY");
1244  vnew = addGuard(st , QUALITY);
1245 
1246  connectGuards(prior, vnew);
1247  prior = vnew;
1248  }
1249  // clear the states, so memory is not freed twice
1250  states.clear();
1251  connectGuards(prior, rp);
1252  }
1253 
1254  delete p;
1255  }
1256  }
1257  }
1258  }
1259 
1260  if (!spannerPropertyWasViolated)
1261  {
1262  if (verbose_)
1263  {
1264  OMPL_INFORM(" ------- Spanner property was NOT violated, SKIPPING");
1265  }
1266  }
1267 
1268  return spannerPropertyWasViolated;
1269 }
1270 
1272 {
1273  consecutiveFailures_ = 0;
1274 }
1275 
1276 void ompl::geometric::SPARSdb::findGraphNeighbors(base::State *st, std::vector<Vertex> &graphNeighborhood,
1277  std::vector<Vertex> &visibleNeighborhood)
1278 {
1279  visibleNeighborhood.clear();
1280  stateProperty_[ queryVertex_ ] = st;
1281  nn_->nearestR( queryVertex_, sparseDelta_, graphNeighborhood);
1282  if (verbose_ && false)
1283  OMPL_INFORM("Finding nearest nodes in NN tree within radius %f", sparseDelta_);
1284  stateProperty_[ queryVertex_ ] = nullptr;
1285 
1286  //Now that we got the neighbors from the NN, we must remove any we can't see
1287  for (std::size_t i = 0; i < graphNeighborhood.size() ; ++i )
1288  if (si_->checkMotion(st, stateProperty_[graphNeighborhood[i]]))
1289  visibleNeighborhood.push_back(graphNeighborhood[i]);
1290 }
1291 
1292 bool ompl::geometric::SPARSdb::findGraphNeighbors(const base::State *state, std::vector<Vertex> &graphNeighborhood)
1293 {
1294  base::State* stateCopy = si_->cloneState(state);
1295 
1296  // Don't check for visibility
1297  graphNeighborhood.clear();
1298  stateProperty_[ queryVertex_ ] = stateCopy;
1299 
1300  // Double the range of sparseDelta_ up to 3 times until at least 1 neighbor is found
1301  std::size_t expandNeighborhoodSearchAttempts = 3;
1302  double neighborSearchRadius;
1303  static const double EXPAND_NEIGHBORHOOD_RATE = 0.25; // speed to which we look outside the original sparse delta neighborhood
1304  for (std::size_t i = 0; i < expandNeighborhoodSearchAttempts; ++i)
1305  {
1306  neighborSearchRadius = sparseDelta_ + i*EXPAND_NEIGHBORHOOD_RATE*sparseDelta_;
1307  if (verbose_)
1308  {
1309  OMPL_INFORM("-------------------------------------------------------");
1310  OMPL_INFORM("Attempt %d to find neighborhood at radius %f", i+1, neighborSearchRadius);
1311  OMPL_INFORM("-------------------------------------------------------");
1312  }
1313 
1314  nn_->nearestR( queryVertex_, neighborSearchRadius, graphNeighborhood);
1315 
1316  // Check if at least one neighbor found
1317  if (graphNeighborhood.size() > 0)
1318  break;
1319  }
1320  stateProperty_[ queryVertex_ ] = nullptr;
1321 
1322  // Check if no neighbors found
1323  if (!graphNeighborhood.size())
1324  {
1325  return false;
1326  }
1327  return true;
1328 }
1329 
1331 {
1332  std::vector< Vertex > hold;
1333  nn_->nearestR( v, sparseDelta_, hold );
1334 
1335  std::vector< Vertex > neigh;
1336  for (std::size_t i = 0; i < hold.size(); ++i)
1337  if (si_->checkMotion( stateProperty_[v], stateProperty_[hold[i]]))
1338  neigh.push_back( hold[i] );
1339 
1340  foreach (Vertex vp, neigh)
1341  connectGuards(v, vp);
1342 }
1343 
1345 {
1346  std::vector<Vertex> nbh;
1347  stateProperty_[ queryVertex_ ] = st;
1348  nn_->nearestR( queryVertex_, sparseDelta_, nbh);
1349  stateProperty_[queryVertex_] = nullptr;
1350 
1351  if (verbose_)
1352  OMPL_INFORM(" ------- findGraphRepresentative found %d nearest neighbors of distance %f",
1353  nbh.size(), sparseDelta_);
1354 
1355  Vertex result = boost::graph_traits<Graph>::null_vertex();
1356 
1357  for (std::size_t i = 0 ; i< nbh.size() ; ++i)
1358  {
1359  if (verbose_)
1360  OMPL_INFORM(" -------- Checking motion of graph rep candidate %d", i);
1361  if (si_->checkMotion(st, stateProperty_[nbh[i]]))
1362  {
1363  if (verbose_)
1364  OMPL_INFORM(" --------- VALID ");
1365  result = nbh[i];
1366  break;
1367  }
1368  }
1369  return result;
1370 }
1371 
1373  std::map<Vertex, base::State*> &closeRepresentatives,
1375 {
1376  // Properly clear the vector by also deleting previously sampled unused states
1377  for (std::map<Vertex, base::State*>::iterator it = closeRepresentatives.begin(); it != closeRepresentatives.end(); ++it)
1378  si_->freeState(it->second);
1379  closeRepresentatives.clear();
1380 
1381  //denseDelta_ = 0.25 * sparseDelta_;
1382  nearSamplePoints_ /= 10; // HACK - this makes it look for the same number of samples as dimensions
1383 
1384  if (verbose_)
1385  OMPL_INFORM(" ----- nearSamplePoints: %f, denseDelta: %f", nearSamplePoints_, denseDelta_);
1386 
1387  // Then, begin searching the space around new potential state qNew
1388  for (unsigned int i = 0 ; i < nearSamplePoints_ && ptc == false ; ++i)
1389  {
1390  do
1391  {
1392  sampler_->sampleNear(workState, qNew, denseDelta_);
1393 
1394 #ifdef OMPL_THUNDER_DEBUG
1395  visualizeStateCallback(workState, 3, sparseDelta_);
1396  sleep(0.1);
1397 #endif
1398 
1399  if (verbose_)
1400  {
1401  OMPL_INFORM(" ------ findCloseRepresentatives sampled state ");
1402 
1403  if (!si_->isValid(workState))
1404  {
1405  OMPL_INFORM(" ------ isValid ");
1406  }
1407  if (si_->distance(qNew, workState) > denseDelta_)
1408  {
1409  OMPL_INFORM(" ------ Distance too far ");
1410  }
1411  if (!si_->checkMotion(qNew, workState))
1412  {
1413  OMPL_INFORM(" ------ Motion invalid ");
1414  }
1415  }
1416 
1417  } while ((!si_->isValid(workState) || si_->distance(qNew, workState) > denseDelta_ || !si_->checkMotion(qNew, workState)) && ptc == false);
1418 
1419  // if we were not successful at sampling a desirable state, we are out of time
1420  if (ptc == true)
1421  {
1422  if (verbose_)
1423  OMPL_INFORM(" ------ We are out of time ");
1424  break;
1425  }
1426 
1427  if (verbose_)
1428  OMPL_INFORM(" ------ Find graph representative ");
1429 
1430  // Compute who his graph neighbors are
1431  Vertex representative = findGraphRepresentative(workState);
1432 
1433  // Assuming this sample is actually seen by somebody (which he should be in all likelihood)
1434  if (representative != boost::graph_traits<Graph>::null_vertex())
1435  {
1436 
1437  if (verbose_)
1438  OMPL_INFORM(" ------ Representative is not null ");
1439 
1440  //If his representative is different than qNew
1441  if (qRep != representative)
1442  {
1443  if (verbose_)
1444  OMPL_INFORM(" ------ qRep != representative ");
1445 
1446  //And we haven't already tracked this representative
1447  if (closeRepresentatives.find(representative) == closeRepresentatives.end())
1448  {
1449  if (verbose_)
1450  OMPL_INFORM(" ------ Track the representative");
1451  //Track the representativen
1452  closeRepresentatives[representative] = si_->cloneState(workState);
1453  }
1454  }
1455  else
1456  {
1457  if (verbose_)
1458  OMPL_INFORM(" ------ qRep == representative, no good ");
1459  }
1460  }
1461  else
1462  {
1463  if (verbose_)
1464  OMPL_INFORM(" ------ Rep is null ");
1465 
1466  //This guy can't be seen by anybody, so we should take this opportunity to add him
1467  if (verbose_)
1468  OMPL_INFORM(" --- Adding node for COVERAGE");
1469  addGuard(si_->cloneState(workState), COVERAGE);
1470 
1471  if (verbose_)
1472  {
1473  OMPL_INFORM(" ------ STOP EFFORS TO ADD A DENSE PATH");
1474  }
1475 
1476  //We should also stop our efforts to add a dense path
1477  for (std::map<Vertex, base::State*>::iterator it = closeRepresentatives.begin(); it != closeRepresentatives.end(); ++it)
1478  si_->freeState(it->second);
1479  closeRepresentatives.clear();
1480  break;
1481  }
1482  } // for loop
1483 }
1484 
1486 {
1487  //First of all, we need to compute all candidate r'
1488  std::vector<Vertex> VPPs;
1489  computeVPP(rep, r, VPPs);
1490 
1491  //Then, for each pair Pv(r,r')
1492  foreach (Vertex rp, VPPs)
1493  //Try updating the pair info
1494  distanceCheck(rep, q, r, s, rp);
1495 }
1496 
1497 void ompl::geometric::SPARSdb::computeVPP(Vertex v, Vertex vp, std::vector<Vertex> &VPPs)
1498 {
1499  VPPs.clear();
1500  foreach( Vertex cvpp, boost::adjacent_vertices( v, g_ ) )
1501  if( cvpp != vp )
1502  if( !boost::edge( cvpp, vp, g_ ).second )
1503  VPPs.push_back( cvpp );
1504 }
1505 
1506 void ompl::geometric::SPARSdb::computeX(Vertex v, Vertex vp, Vertex vpp, std::vector<Vertex> &Xs)
1507 {
1508  Xs.clear();
1509 
1510  foreach (Vertex cx, boost::adjacent_vertices(vpp, g_))
1511  if (boost::edge(cx, v, g_).second && !boost::edge(cx, vp, g_).second)
1512  {
1513  InterfaceData& d = getData( v, vpp, cx );
1514  if ((vpp < cx && d.pointA_) || (cx < vpp && d.pointB_))
1515  Xs.push_back( cx );
1516  }
1517  Xs.push_back(vpp);
1518 }
1519 
1521 {
1522  if( vp < vpp )
1523  return VertexPair( vp, vpp );
1524  else if( vpp < vp )
1525  return VertexPair( vpp, vp );
1526  else
1527  throw Exception( name_, "Trying to get an index where the pairs are the same point!");
1528 }
1529 
1531 {
1532  return interfaceDataProperty_[v].interfaceHash[index( vp, vpp )];
1533 }
1534 
1536 {
1537  //Get the info for the current representative-neighbors pair
1538  InterfaceData& d = getData( rep, r, rp );
1539 
1540  if (r < rp) // FIRST points represent r (the guy discovered through sampling)
1541  {
1542  if (d.pointA_ == nullptr) // If the point we're considering replacing (P_v(r,.)) isn't there
1543  //Then we know we're doing better, so add it
1544  d.setFirst(q, s, si_);
1545  else //Otherwise, he is there,
1546  {
1547  if (d.pointB_ == nullptr) //But if the other guy doesn't exist, we can't compare.
1548  {
1549  //Should probably keep the one that is further away from rep? Not known what to do in this case.
1550  // TODO: is this not part of the algorithm?
1551  }
1552  else //We know both of these points exist, so we can check some distances
1553  if (si_->distance(q, d.pointB_) < si_->distance(d.pointA_, d.pointB_))
1554  //Distance with the new point is good, so set it.
1555  d.setFirst( q, s, si_ );
1556  }
1557  }
1558  else // SECOND points represent r (the guy discovered through sampling)
1559  {
1560  if (d.pointB_ == nullptr) //If the point we're considering replacing (P_V(.,r)) isn't there...
1561  //Then we must be doing better, so add it
1562  d.setSecond(q, s, si_);
1563  else //Otherwise, he is there
1564  {
1565  if (d.pointA_ == nullptr) //But if the other guy doesn't exist, we can't compare.
1566  {
1567  //Should we be doing something cool here?
1568  }
1569  else
1570  if (si_->distance(q, d.pointA_) < si_->distance(d.pointB_, d.pointA_))
1571  //Distance with the new point is good, so set it
1572  d.setSecond(q, s, si_);
1573  }
1574  }
1575 
1576  // Lastly, save what we have discovered
1577  interfaceDataProperty_[rep].interfaceHash[index(r, rp)] = d;
1578 }
1579 
1581 {
1582  stateProperty_[ queryVertex_ ] = st;
1583 
1584  std::vector< Vertex > hold;
1585  nn_->nearestR( queryVertex_, sparseDelta_, hold );
1586 
1587  stateProperty_[queryVertex_] = nullptr;
1588 
1589  //For each of the vertices
1590  foreach (Vertex v, hold)
1591  {
1592  foreach (VertexPair r, interfaceDataProperty_[v].interfaceHash | boost::adaptors::map_keys)
1593  interfaceDataProperty_[v].interfaceHash[r].clear(si_);
1594  }
1595 }
1596 
1598 {
1599  Vertex m = boost::add_vertex(g_);
1600  stateProperty_[m] = state;
1601  colorProperty_[m] = type;
1602 
1603  //assert(si_->isValid(state));
1604  abandonLists(state);
1605 
1606  disjointSets_.make_set(m);
1607  nn_->add(m);
1608  resetFailures();
1609 
1610  if (verbose_)
1611  {
1612  OMPL_INFORM(" ---- addGuard() of type %f", type);
1613  }
1614 #ifdef OMPL_THUNDER_DEBUG
1615  visualizeStateCallback(state, 4, sparseDelta_); // Candidate node has already (just) been added
1616  sleep(0.1);
1617 #endif
1618 
1619 
1620  return m;
1621 }
1622 
1624 {
1625  //OMPL_INFORM("connectGuards called ---------------------------------------------------------------- ");
1626  assert(v <= getNumVertices());
1627  assert(vp <= getNumVertices());
1628 
1629  if (verbose_)
1630  {
1631  OMPL_INFORM(" ------- connectGuards/addEdge: Connecting vertex %f to vertex %f", v, vp);
1632  }
1633 
1634  // Create the new edge
1635  Edge e = (boost::add_edge(v, vp, g_)).first;
1636 
1637  // Add associated properties to the edge
1638  edgeWeightProperty_[e] = distanceFunction(v, vp); // TODO: use this value with astar
1639  edgeCollisionStateProperty_[e] = NOT_CHECKED;
1640 
1641  // Add the edge to the incrementeal connected components datastructure
1642  disjointSets_.union_set(v, vp);
1643 
1644  // Debug in Rviz
1645 #ifdef OMPL_THUNDER_DEBUG
1646  visualizeEdgeCallback(stateProperty_[v], stateProperty_[vp]);
1647  sleep(0.8);
1648 #endif
1649 
1650 }
1651 
1652 bool ompl::geometric::SPARSdb::convertVertexPathToStatePath(std::vector<Vertex> &vertexPath,
1653  const base::State* actualStart,
1654  const base::State* actualGoal,
1655  CandidateSolution &candidateSolution,
1656  bool disableCollisionWarning)
1657 {
1658  if (!vertexPath.size())
1659  return false;
1660 
1662  candidateSolution.isApproximate_ = false; // assume path is valid
1663 
1664  // Add original start if it is different than the first state
1665  if (actualStart != stateProperty_[vertexPath.back()])
1666  {
1667  pathGeometric->append(actualStart);
1668 
1669  // Add the edge status
1670  // the edge from actualStart to start is always valid otherwise we would not have used that start
1671  candidateSolution.edgeCollisionStatus_.push_back(FREE);
1672  }
1673 
1674  // Reverse the vertexPath and convert to state path
1675  for (std::size_t i = vertexPath.size(); i > 0; --i)
1676  {
1677  pathGeometric->append(stateProperty_[vertexPath[i-1]]);
1678 
1679  // Add the edge status
1680  if (i > 1) // skip the last vertex (its reversed)
1681  {
1682  Edge thisEdge = boost::edge(vertexPath[i-1], vertexPath[i-2], g_).first;
1683 
1684  // Check if any edges in path are not free (then it an approximate path)
1685  if (edgeCollisionStateProperty_[thisEdge] == IN_COLLISION)
1686  {
1687  candidateSolution.isApproximate_ = true;
1688  candidateSolution.edgeCollisionStatus_.push_back(IN_COLLISION);
1689  }
1690  else if (edgeCollisionStateProperty_[thisEdge] == NOT_CHECKED)
1691  {
1692  if (!disableCollisionWarning)
1693  OMPL_ERROR("A chosen path has an edge that has not been checked for collision. This should not happen");
1694  candidateSolution.edgeCollisionStatus_.push_back(NOT_CHECKED);
1695  }
1696  else
1697  {
1698  candidateSolution.edgeCollisionStatus_.push_back(FREE);
1699  }
1700  }
1701  }
1702 
1703  // Add original goal if it is different than the last state
1704  if (actualGoal != stateProperty_[vertexPath.front()])
1705  {
1706  pathGeometric->append(actualGoal);
1707 
1708  // Add the edge status
1709  // the edge from actualGoal to goal is always valid otherwise we would not have used that goal
1710  candidateSolution.edgeCollisionStatus_.push_back(FREE);
1711  }
1712 
1713  candidateSolution.path_ = base::PathPtr(pathGeometric);
1714 
1715  return true;
1716 }
1717 
1719 {
1720  Planner::getPlannerData(data);
1721 
1722  // Explicitly add start and goal states:
1723  for (size_t i = 0; i < startM_.size(); ++i)
1724  data.addStartVertex(base::PlannerDataVertex(stateProperty_[startM_[i]], (int)START));
1725 
1726  for (size_t i = 0; i < goalM_.size(); ++i)
1727  data.addGoalVertex(base::PlannerDataVertex(stateProperty_[goalM_[i]], (int)GOAL));
1728 
1729  // I'm curious:
1730  if (goalM_.size() > 0)
1731  {
1732  throw Exception(name_, "SPARS2 has goal states?");
1733  }
1734  if (startM_.size() > 0)
1735  {
1736  throw Exception(name_, "SPARS2 has start states?");
1737  }
1738 
1739  // If there are even edges here
1740  if (boost::num_edges( g_ ) > 0)
1741  {
1742  // Adding edges and all other vertices simultaneously
1743  foreach (const Edge e, boost::edges(g_))
1744  {
1745  const Vertex v1 = boost::source(e, g_);
1746  const Vertex v2 = boost::target(e, g_);
1747 
1748  // TODO save weights!
1749  data.addEdge(base::PlannerDataVertex(stateProperty_[v1], (int)colorProperty_[v1]),
1750  base::PlannerDataVertex(stateProperty_[v2], (int)colorProperty_[v2]));
1751 
1752  //OMPL_INFORM("Adding edge from vertex of type %d to vertex of type %d", colorProperty_[v1], colorProperty_[v2]);
1753  }
1754  }
1755  //else
1756  // OMPL_INFORM("%s: There are no edges in the graph!", getName().c_str());
1757 
1758  // Make sure to add edge-less nodes as well
1759  foreach (const Vertex n, boost::vertices(g_))
1760  if (boost::out_degree(n, g_) == 0)
1761  data.addVertex(base::PlannerDataVertex(stateProperty_[n], (int)colorProperty_[n]));
1762 
1763  data.properties["iterations INTEGER"] = boost::lexical_cast<std::string>(iterations_);
1764 }
1765 
1767 {
1768  // Check that the query vertex is initialized (used for internal nearest neighbor searches)
1769  checkQueryStateInitialization();
1770 
1771  // Add all vertices
1772  if (verbose_)
1773  {
1774  OMPL_INFORM("SPARS::setPlannerData: numVertices=%d", data.numVertices());
1775  }
1776  OMPL_INFORM("Loading PlannerData into SPARSdb");
1777 
1778  std::vector<Vertex> idToVertex;
1779 
1780  // Temp disable verbose mode for loading database
1781  bool wasVerbose = verbose_;
1782  verbose_ = false;
1783 
1784  OMPL_INFORM("Loading vertices:");
1785  // Add the nodes to the graph
1786  for (std::size_t vertexID = 0; vertexID < data.numVertices(); ++vertexID)
1787  {
1788  // Get the state from loaded planner data
1789  const base::State *oldState = data.getVertex(vertexID).getState();
1790  base::State *state = si_->cloneState(oldState);
1791 
1792  // Get the tag, which in this application represents the vertex type
1793  GuardType type = static_cast<GuardType>( data.getVertex(vertexID).getTag() );
1794 
1795  // ADD GUARD
1796  idToVertex.push_back(addGuard(state, type ));
1797  }
1798 
1799  OMPL_INFORM("Loading edges:");
1800  // Add the corresponding edges to the graph
1801  std::vector<unsigned int> edgeList;
1802  for (std::size_t fromVertex = 0; fromVertex < data.numVertices(); ++fromVertex)
1803  {
1804  edgeList.clear();
1805 
1806  // Get the edges
1807  data.getEdges(fromVertex, edgeList); // returns num of edges
1808 
1809  Vertex m = idToVertex[fromVertex];
1810 
1811  // Process edges
1812  for (std::size_t edgeId = 0; edgeId < edgeList.size(); ++edgeId)
1813  {
1814  std::size_t toVertex = edgeList[edgeId];
1815  Vertex n = idToVertex[toVertex];
1816 
1817  // Add the edge to the graph
1818  const base::Cost weight(0);
1819  if (verbose_ && false)
1820  {
1821  OMPL_INFORM(" Adding edge from vertex id %d to id %d into edgeList", fromVertex, toVertex);
1822  OMPL_INFORM(" Vertex %d to %d", m, n);
1823  }
1824  connectGuards(m, n);
1825  }
1826  } // for
1827 
1828  // Re-enable verbose mode, if necessary
1829  verbose_ = wasVerbose;
1830 }
1831 
1833 {
1834  foreach (const Edge e, boost::edges(g_))
1835  edgeCollisionStateProperty_[e] = NOT_CHECKED; // each edge has an unknown state
1836 }
double d_
Last known distance between the two interfaces supported by points_ and sigmas.
Definition: SPARSdb.h:126
bool approximateSolutions
Flag indicating whether the planner is able to compute approximate solutions.
Definition: Planner.h:212
virtual void setup()
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition: SPARSdb.cpp:142
double denseDeltaFraction_
Maximum range for allowing two samples to support an interface as a fraction of maximum extent...
Definition: SPARSdb.h:739
double getSparseDeltaFraction() const
Retrieve the sparse graph visibility range delta.
Definition: SPARSdb.h:442
void setDenseDeltaFraction(double d)
Sets interface support tolerance as a fraction of max. extent.
Definition: SPARSdb.h:416
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique...
Definition: PlannerData.h:163
double getStretchFactor() const
Retrieve the spanner's set stretch factor.
Definition: SPARSdb.h:448
boost::property_map< Graph, vertex_color_t >::type colorProperty_
Access to the colors for the vertices.
Definition: SPARSdb.h:763
Interface information storage class, which does bookkeeping for criterion four.
Definition: SPARSdb.h:115
boost::property_map< Graph, edge_collision_state_t >::type EdgeCollisionStateMap
Access map that stores the lazy collision checking status of each edge.
Definition: SPARSdb.h:313
A shared pointer wrapper for ompl::base::ProblemDefinition.
bool convertVertexPathToStatePath(std::vector< Vertex > &vertexPath, const base::State *actualStart, const base::State *actualGoal, CandidateSolution &candidateSolution, bool disableCollisionWarning=false)
Convert astar results to correctly ordered path.
Definition: SPARSdb.cpp:1652
SPARSdb(const base::SpaceInformationPtr &si)
Constructor.
Definition: SPARSdb.cpp:99
The planner failed to find a solution.
Definition: PlannerStatus.h:62
void setMaxFailures(unsigned int m)
Sets the maximum failures until termination.
Definition: SPARSdb.h:424
GoalType recognizedGoal
The type of goal specification the planner can use.
Definition: Planner.h:206
Graph g_
Connectivity graph.
Definition: SPARSdb.h:721
void findGraphNeighbors(base::State *state, std::vector< Vertex > &graphNeighborhood, std::vector< Vertex > &visibleNeighborhood)
Finds visible nodes in the graph near state.
Definition: SPARSdb.cpp:1276
boost::property_map< Graph, boost::edge_weight_t >::type edgeWeightProperty_
Access to the weights of each Edge.
Definition: SPARSdb.h:754
boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties > Graph
Definition: SPARSdb.h:301
boost::disjoint_sets< boost::property_map< Graph, boost::vertex_rank_t >::type, boost::property_map< Graph, boost::vertex_predecessor_t >::type > disjointSets_
Data structure that maintains the connected components.
Definition: SPARSdb.h:772
bool constructSolution(const Vertex start, const Vertex goal, std::vector< Vertex > &vertexPath) const
Given two milestones from the same connected component, construct a path connecting them and set it a...
Definition: SPARSdb.cpp:424
void clear(const base::SpaceInformationPtr &si)
Clears the given interface data.
Definition: SPARSdb.h:139
bool checkAddCoverage(const base::State *qNew, std::vector< Vertex > &visibleNeighborhood)
Checks to see if the sample needs to be added to ensure coverage of the space.
Definition: SPARSdb.cpp:1065
unsigned int addGoalVertex(const PlannerDataVertex &v)
Adds the given vertex to the graph data, and marks it as a start vertex. The vertex index is returned...
bool lazyCollisionCheck(std::vector< Vertex > &vertexPath, const base::PlannerTerminationCondition &ptc)
Check recalled path for collision and disable as needed.
Definition: SPARSdb.cpp:490
Abstract definition of goals.
Definition: Goal.h:62
bool verbose_
Option to enable debugging output.
Definition: SPARSdb.h:796
boost::property_map< Graph, vertex_interface_data_t >::type interfaceDataProperty_
Access to the interface pair information for the vertices.
Definition: SPARSdb.h:766
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
bool addedSolution_
A flag indicating that a solution has been added during solve()
Definition: SPARSdb.h:777
base::State * pointA_
States which lie inside the visibility region of a vertex and support an interface.
Definition: SPARSdb.h:118
bool checkAddPath(Vertex v)
Checks vertex v for short paths through its region and adds when appropriate.
Definition: SPARSdb.cpp:1171
void distanceCheck(Vertex rep, const base::State *q, Vertex r, const base::State *s, Vertex rp)
Performs distance checking for the candidate new state, q against the current information.
Definition: SPARSdb.cpp:1535
unsigned int addVertex(const PlannerDataVertex &st)
Adds the given vertex to the graph data. The vertex index is returned. Duplicates are not added...
double sparseDeltaFraction_
Maximum visibility range for nodes in the graph as a fraction of maximum extent.
Definition: SPARSdb.h:736
bool checkAddInterface(const base::State *qNew, std::vector< Vertex > &graphNeighborhood, std::vector< Vertex > &visibleNeighborhood)
Checks to see if the current sample reveals the existence of an interface, and if so...
Definition: SPARSdb.cpp:1129
Struct for passing around partially solved solutions.
Definition: SPARSdb.h:240
void append(const base::State *state)
Append state to the end of this path. The memory for state is copied.
virtual ~SPARSdb()
Destructor.
Definition: SPARSdb.cpp:137
void computeX(Vertex v, Vertex vp, Vertex vpp, std::vector< Vertex > &Xs)
Computes all nodes which qualify as a candidate x for v, v', and v".
Definition: SPARSdb.cpp:1506
base::State * getState(unsigned int index)
Get the state located at index along the path.
virtual double length() const
Compute the length of a geometric path (sum of lengths of segments that make up the path) ...
void resetFailures()
A reset function for resetting the failures count.
Definition: SPARSdb.cpp:1271
std::size_t getStateCount() const
Get the number of states (way-points) that make up this path.
void freeMemory()
Free all the memory allocated by the planner.
Definition: SPARSdb.cpp:180
unsigned int getEdges(unsigned int v, std::vector< unsigned int > &edgeList) const
Returns a list of the vertex indexes directly connected to vertex with index v (outgoing edges)...
void printDebug(std::ostream &out=std::cout) const
Print debug information about planner.
Definition: SPARSdb.cpp:564
void examine_vertex(Vertex u, const Graph &g) const
Definition: SPARSdb.cpp:91
std::pair< bool, bool > checkAndRepair(unsigned int attempts)
Check if the path is valid. If it is not, attempts are made to fix the path by sampling around invali...
unsigned int maxFailures_
The number of consecutive failures to add to the graph before termination.
Definition: SPARSdb.h:742
bool getSimilarPaths(int nearestK, const base::State *start, const base::State *goal, CandidateSolution &candidateSolution, const base::PlannerTerminationCondition &ptc)
Search the roadmap for the best path close to the given start and goal states that is valid...
Definition: SPARSdb.cpp:199
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition: PlannerData.h:59
void findCloseRepresentatives(base::State *workState, const base::State *qNew, Vertex qRep, std::map< Vertex, base::State * > &closeRepresentatives, const base::PlannerTerminationCondition &ptc)
Finds representatives of samples near qNew_ which are not his representative.
Definition: SPARSdb.cpp:1372
virtual base::PlannerStatus solve(const base::PlannerTerminationCondition &ptc)
Function that can solve the motion planning problem. This function can be called multiple times on th...
Definition: SPARSdb.cpp:1059
unsigned int numPathInsertionFailures_
Track how many solutions fail to have connectivity at end.
Definition: SPARSdb.h:745
base::State * sigmaA_
States which lie just outside the visibility region of a vertex and support an interface.
Definition: SPARSdb.h:122
Vertex findGraphRepresentative(base::State *st)
Finds the representative of the input state, st.
Definition: SPARSdb.cpp:1344
void checkQueryStateInitialization()
Check that the query vertex is initialized (used for internal nearest neighbor searches) ...
Definition: SPARSdb.cpp:1050
edgeWeightMap(const Graph &graph, const EdgeCollisionStateMap &collisionStates)
Definition: SPARSdb.cpp:58
std::vector< base::State * > & getStates()
Get the states that make up the path (as a reference, so it can be modified, hence the function is no...
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
void interpolate(unsigned int count)
Insert a number of states in a path so that the path is made up of exactly count states. States are inserted uniformly (more states on longer segments). Changes are performed only if a path has less than count states.
long unsigned int iterations_
A counter for the number of iterations of the algorithm.
Definition: SPARSdb.h:783
unsigned int getMaxFailures() const
Retrieve the maximum consecutive failure limit.
Definition: SPARSdb.h:430
VertexPair index(Vertex vp, Vertex vpp)
Rectifies indexing order for accessing the vertex data.
Definition: SPARSdb.cpp:1520
unsigned int numVertices() const
Retrieve the number of vertices in this structure.
virtual void clear()
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Definition: SPARSdb.cpp:169
void clearEdgeCollisionStates()
Clear all past edge state information about in collision or not.
Definition: SPARSdb.cpp:1832
double distanceFunction(const Vertex a, const Vertex b) const
Compute distance between two milestones (this is simply distance between the states of the milestones...
Definition: SPARSdb.h:709
void setPlannerData(const base::PlannerData &data)
Set the sparse graph from file.
Definition: SPARSdb.cpp:1766
A class to store the exit status of Planner::solve()
Definition: PlannerStatus.h:48
virtual bool addEdge(unsigned int v1, unsigned int v2, const PlannerDataEdge &edge=PlannerDataEdge(), Cost weight=Cost(1.0))
Adds a directed edge between the given vertex indexes. An optional edge structure and weight can be s...
virtual bool isStartGoalPairValid(const State *, const State *) const
Since there can be multiple starting states (and multiple goal states) it is possible certain pairs a...
Definition: Goal.h:138
boost::graph_traits< Graph >::vertex_descriptor Vertex
Vertex in Graph.
Definition: SPARSdb.h:304
This class contains routines that attempt to simplify geometric paths.
A shared pointer wrapper for ompl::base::SpaceInformation.
const PlannerDataVertex & getVertex(unsigned int index) const
Retrieve a reference to the vertex object with the given index. If this vertex does not exist...
bool getPaths(const std::vector< Vertex > &candidateStarts, const std::vector< Vertex > &candidateGoals, const base::State *actualStart, const base::State *actualGoal, CandidateSolution &candidateSolution, const base::PlannerTerminationCondition &ptc)
Check if there exists a solution, i.e., there exists a pair of milestones such that the first is in s...
Definition: SPARSdb.cpp:259
unsigned int nearSamplePoints_
Number of sample points to use when trying to detect interfaces.
Definition: SPARSdb.h:748
bool reachedFailureLimit() const
Returns whether we have reached the iteration failures limit, maxFailures_.
Definition: SPARSdb.cpp:559
void computeVPP(Vertex v, Vertex vp, std::vector< Vertex > &VPPs)
Computes all nodes which qualify as a candidate v" for v and vp.
Definition: SPARSdb.cpp:1497
unsigned int addStartVertex(const PlannerDataVertex &v)
Adds the given vertex to the graph data, and marks it as a start vertex. The vertex index is returned...
bool checkAddConnectivity(const base::State *qNew, std::vector< Vertex > &visibleNeighborhood)
Checks to see if the sample needs to be added to ensure connectivity.
Definition: SPARSdb.cpp:1079
Definition of an abstract state.
Definition: State.h:50
boost::graph_traits< Graph >::edge_descriptor Edge
Edge in Graph.
Definition: SPARSdb.h:307
void setSparseDeltaFraction(double D)
Sets vertex visibility range as a fraction of max. extent.
Definition: SPARSdb.h:408
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
Definition: Console.h:66
boost::property_map< Graph, vertex_state_t >::type stateProperty_
Access to the internal base::state at each Vertex.
Definition: SPARSdb.h:760
double stretchFactor_
Stretch Factor as per graph spanner literature (multiplicative bound on path quality) ...
Definition: SPARSdb.h:733
void setSecond(const base::State *p, const base::State *s, const base::SpaceInformationPtr &si)
Sets information for the second interface (i.e. interface with larger index vertex).
Definition: SPARSdb.h:180
PlannerSpecs specs_
The specifications of the planner (its capabilities)
Definition: Planner.h:410
double sparseDelta_
Maximum visibility range for nodes in the graph.
Definition: SPARSdb.h:786
The exception type for ompl.
Definition: Exception.h:47
#define OMPL_DEBUG(fmt,...)
Log a formatted debugging string.
Definition: Console.h:70
unsigned int consecutiveFailures_
A counter for the number of consecutive failed iterations of the algorithm.
Definition: SPARSdb.h:780
void approachGraph(Vertex v)
Approaches the graph from a given vertex.
Definition: SPARSdb.cpp:1330
EdgeCollisionStateMap edgeCollisionStateProperty_
Access to the collision checking state of each Edge.
Definition: SPARSdb.h:757
virtual int getTag() const
Returns the integer tag associated with this vertex.
Definition: PlannerData.h:69
InterfaceData & getData(Vertex v, Vertex vp, Vertex vpp)
Retrieves the Vertex data associated with v,vp,vpp.
Definition: SPARSdb.cpp:1530
bool sameComponent(Vertex m1, Vertex m2)
Check if two milestones (m1 and m2) are part of the same connected component. This is not a const fun...
Definition: SPARSdb.cpp:554
void updatePairPoints(Vertex rep, const base::State *q, Vertex r, const base::State *s)
High-level method which updates pair point information for repV_ with neighbor r. ...
Definition: SPARSdb.cpp:1485
PathSimplifierPtr psimp_
A path simplifier used to simplify dense paths added to the graph.
Definition: SPARSdb.h:751
bool optimizingPaths
Flag indicating whether the planner attempts to optimize the path and reduce its length until the max...
Definition: Planner.h:216
std::pair< VertexIndexType, VertexIndexType > VertexPair
Pair of vertices which support an interface.
Definition: SPARSdb.h:111
Vertex addGuard(base::State *state, GuardType type)
Construct a guard for a given state (state) and store it in the nearest neighbors data structure...
Definition: SPARSdb.cpp:1597
double getDenseDeltaFraction() const
Retrieve the dense graph interface support delta.
Definition: SPARSdb.h:436
Definition of a geometric path.
Definition: PathGeometric.h:60
void abandonLists(base::State *st)
When a new guard is added at state st, finds all guards who must abandon their interface information ...
Definition: SPARSdb.cpp:1580
bool lazyCollisionSearch(const Vertex &start, const Vertex &goal, const base::State *actualStart, const base::State *actualGoal, CandidateSolution &candidateSolution, const base::PlannerTerminationCondition &ptc)
Repeatidly search through graph for connection then check for collisions then repeat.
Definition: SPARSdb.cpp:315
void connectGuards(Vertex v, Vertex vp)
Connect two guards in the roadmap.
Definition: SPARSdb.cpp:1623
SpaceInformationPtr si_
The space information for which planning is done.
Definition: Planner.h:398
void clearQuery()
Clear the query previously loaded from the ProblemDefinition. Subsequent calls to solve() will reuse ...
Definition: SPARSdb.cpp:162
virtual const State * getState() const
Retrieve the state associated with this vertex.
Definition: PlannerData.h:73
void setFirst(const base::State *p, const base::State *s, const base::SpaceInformationPtr &si)
Sets information for the first interface (i.e. interface with smaller index vertex).
Definition: SPARSdb.h:165
void setStretchFactor(double t)
Sets the stretch factor.
Definition: SPARSdb.h:402
GuardType
Enumeration which specifies the reason a guard is added to the spanner.
Definition: SPARSdb.h:93
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition: Cost.h:47
virtual void setProblemDefinition(const base::ProblemDefinitionPtr &pdef)
Set the problem definition for the planner. The problem needs to be set before calling solve()...
Definition: SPARSdb.cpp:156
A shared pointer wrapper for ompl::base::Path.
double denseDelta_
Maximum range for allowing two samples to support an interface.
Definition: SPARSdb.h:789
std::map< std::string, std::string > properties
Any extra properties (key-value pairs) the planner can set.
Definition: PlannerData.h:397
virtual void getPlannerData(base::PlannerData &data) const
Get information about the current run of the motion planner. Repeated calls to this function will upd...
Definition: SPARSdb.cpp:1718
This bit is set if casting to sampleable goal regions (ompl::base::GoalSampleableRegion) is possible...
Definition: GoalTypes.h:55
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition: Console.h:68