37 #include "ompl/control/planners/syclop/Syclop.h"
38 #include "ompl/base/goals/GoalSampleableRegion.h"
39 #include "ompl/base/ProblemDefinition.h"
44 const double ompl::control::Syclop::Defaults::PROB_ABANDON_LEAD_EARLY = 0.25;
45 const double ompl::control::Syclop::Defaults::PROB_KEEP_ADDING_TO_AVAIL = 0.50;
46 const double ompl::control::Syclop::Defaults::PROB_SHORTEST_PATH = 0.95;
53 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
56 std::placeholders::_1, std::placeholders::_2));
64 clearEdgeCostFactors();
66 startRegions_.clear();
76 setupRegionEstimates();
82 const int region = decomp_->locateRegion(s);
83 startRegions_.insert(region);
84 Motion *startMotion = addRoot(s);
85 graph_[boost::vertex(region, graph_)].motions.push_back(startMotion);
87 updateCoverageEstimate(graph_[boost::vertex(region, graph_)], s);
89 if (startRegions_.empty())
91 OMPL_ERROR(
"%s: There are no valid start states", getName().c_str());
96 if (goalRegions_.empty())
99 goalRegions_.insert(decomp_->locateRegion(g));
102 OMPL_ERROR(
"%s: Unable to sample a valid goal state", getName().c_str());
107 OMPL_INFORM(
"%s: Starting planning with %u states already in datastructure", getName().c_str(), numMotions_);
109 std::vector<Motion*> newMotions;
110 const Motion *solution =
nullptr;
112 double goalDist = std::numeric_limits<double>::infinity();
114 while (!ptc && !solved)
116 const int chosenStartRegion = startRegions_.sampleUniform();
117 int chosenGoalRegion = -1;
120 if (pis_.haveMoreGoalStates() && goalRegions_.size() < numMotions_/2)
124 chosenGoalRegion = decomp_->locateRegion(g);
125 goalRegions_.insert(chosenGoalRegion);
128 if (chosenGoalRegion == -1)
129 chosenGoalRegion = goalRegions_.sampleUniform();
131 leadComputeFn(chosenStartRegion, chosenGoalRegion, lead_);
132 computeAvailableRegions();
133 for (
int i = 0; i < numRegionExpansions_ && !solved && !ptc; ++i)
135 const int region = selectRegion();
136 bool improved =
false;
137 for (
int j = 0; j < numTreeSelections_ && !solved && !ptc; ++j)
140 selectAndExtend(graph_[boost::vertex(region, graph_)], newMotions);
141 for (std::vector<Motion*>::const_iterator m = newMotions.begin(); m != newMotions.end() && !ptc; ++m)
154 if (distance < goalDist)
159 const int newRegion = decomp_->locateRegion(motion->
state);
160 graph_[boost::vertex(newRegion, graph_)].motions.push_back(motion);
162 Region &newRegionObj = graph_[boost::vertex(newRegion, graph_)];
163 improved |= updateCoverageEstimate(newRegionObj, motion->
state);
167 if (newRegion != region
168 && regionsToEdge_.count(std::pair<int,int>(region,newRegion)) > 0)
170 Adjacency *adj = regionsToEdge_[std::pair<int,int>(region,newRegion)];
173 improved |= updateConnectionEstimate(graph_[boost::vertex(region, graph_)], newRegionObj, motion->
state);
177 if (newRegionObj.
pdfElem !=
nullptr)
178 availDist_.update(newRegionObj.
pdfElem, newRegionObj.
weight);
181 else if (std::find(lead_.begin(), lead_.end(), newRegion) != lead_.end())
188 if (!improved && rng_.uniform01() < probAbandonLeadEarly_)
192 bool addedSolution =
false;
193 if (solution !=
nullptr)
195 std::vector<const Motion*> mpath;
196 while (solution !=
nullptr)
198 mpath.push_back(solution);
199 solution = solution->
parent;
202 for (
int i = mpath.size()-1; i >= 0; --i)
203 if (mpath[i]->parent)
204 path->
append(mpath[i]->state, mpath[i]->control, mpath[i]->steps * siC_->getPropagationStepSize());
206 path->
append(mpath[i]->state);
207 pdef_->addSolutionPath(
base::PathPtr(path), !solved, goalDist, getName());
208 addedSolution =
true;
215 leadComputeFn = compute;
220 edgeCostFactors_.push_back(factor);
225 edgeCostFactors_.clear();
228 void ompl::control::Syclop::initRegion(Region &r)
232 r.percentValidCells = 1.0;
237 void ompl::control::Syclop::setupRegionEstimates()
239 std::vector<int> numTotal(decomp_->getNumRegions(), 0);
240 std::vector<int> numValid(decomp_->getNumRegions(), 0);
245 for (
int i = 0; i < numFreeVolSamples_; ++i)
247 sampler->sampleUniform(s);
248 int rid = decomp_->locateRegion(s);
251 if (checker->isValid(s))
258 for (
int i = 0; i < decomp_->getNumRegions(); ++i)
260 Region &r = graph_[boost::vertex(i, graph_)];
261 r.volume = decomp_->getRegionVolume(i);
262 if (numTotal[i] == 0)
263 r.percentValidCells = 1.0;
265 r.percentValidCells = ((double) numValid[i]) / (double)numTotal[i];
266 r.freeVolume = r.percentValidCells * r.volume;
267 if (r.freeVolume < std::numeric_limits<double>::epsilon())
268 r.freeVolume = std::numeric_limits<double>::epsilon();
273 void ompl::control::Syclop::updateRegion(Region &r)
275 const double f = r.freeVolume*r.freeVolume*r.freeVolume*r.freeVolume;
276 r.alpha = 1.0 / ((1 + r.covGridCells.size()) * f);
277 r.weight = f / ((1 + r.covGridCells.size())*(1 + r.numSelections*r.numSelections));
280 void ompl::control::Syclop::initEdge(Adjacency &adj,
const Region *source,
const Region *target)
285 regionsToEdge_[std::pair<int,int>(source->index, target->index)] = &adj;
288 void ompl::control::Syclop::setupEdgeEstimates()
291 for (boost::tie(ei,eend) = boost::edges(graph_) ; ei != eend; ++ei)
293 Adjacency &adj = graph_[*ei];
295 adj.numLeadInclusions = 0;
296 adj.numSelections = 0;
301 void ompl::control::Syclop::updateEdge(Adjacency &a)
304 for (std::vector<EdgeCostFactorFn>::const_iterator i = edgeCostFactors_.begin(); i != edgeCostFactors_.end(); ++i)
306 const EdgeCostFactorFn& factor = *i;
307 a.cost *= factor(a.source->index, a.target->index);
311 bool ompl::control::Syclop::updateCoverageEstimate(Region &r,
const base::State *s)
313 const int covCell = covGrid_.locateRegion(s);
314 if (r.covGridCells.count(covCell) == 1)
316 r.covGridCells.insert(covCell);
321 bool ompl::control::Syclop::updateConnectionEstimate(
const Region &c,
const Region &d,
const base::State *s)
323 Adjacency &adj = *regionsToEdge_[std::pair<int,int>(c.index,d.index)];
324 const int covCell = covGrid_.locateRegion(s);
325 if (adj.covGridCells.count(covCell) == 1)
327 adj.covGridCells.insert(covCell);
332 void ompl::control::Syclop::buildGraph()
334 VertexIndexMap index =
get(boost::vertex_index, graph_);
335 std::vector<int> neighbors;
336 for (
int i = 0; i < decomp_->getNumRegions(); ++i)
338 const RegionGraph::vertex_descriptor v = boost::add_vertex(graph_);
339 Region &r = graph_[boost::vertex(v, graph_)];
344 for (boost::tie(vi,vend) = boost::vertices(graph_); vi != vend; ++vi)
348 decomp_->getNeighbors(index[*vi], neighbors);
349 for (std::vector<int>::const_iterator j = neighbors.begin(); j != neighbors.end(); ++j)
351 RegionGraph::edge_descriptor edge;
353 boost::tie(edge, ignore) = boost::add_edge(*vi, boost::vertex(*j, graph_), graph_);
354 initEdge(graph_[edge], &graph_[*vi], &graph_[boost::vertex(*j, graph_)]);
360 void ompl::control::Syclop::clearGraphDetails()
363 for (boost::tie(vi,vend) = boost::vertices(graph_); vi != vend; ++vi)
366 for (boost::tie(ei,eend) = boost::edges(graph_); ei != eend; ++ei)
371 int ompl::control::Syclop::selectRegion()
373 const int index = availDist_.sample(rng_.uniform01());
374 Region ®ion = graph_[boost::vertex(index, graph_)];
375 ++region.numSelections;
376 updateRegion(region);
380 void ompl::control::Syclop::computeAvailableRegions()
382 for (
unsigned int i = 0; i < availDist_.size(); ++i)
383 graph_[boost::vertex(availDist_[i],graph_)].pdfElem =
nullptr;
385 for (
int i = lead_.size()-1; i >= 0; --i)
387 Region &r = graph_[boost::vertex(lead_[i], graph_)];
388 if (!r.motions.empty())
390 r.pdfElem = availDist_.add(lead_[i], r.weight);
391 if (rng_.uniform01() >= probKeepAddingToAvail_)
397 void ompl::control::Syclop::defaultComputeLead(
int startRegion,
int goalRegion, std::vector<int>& lead)
400 if (startRegion == goalRegion)
402 lead.push_back(startRegion);
406 else if (rng_.uniform01() < probShortestPath_)
408 std::vector<RegionGraph::vertex_descriptor> parents(decomp_->getNumRegions());
409 std::vector<double> distances(decomp_->getNumRegions());
413 boost::astar_search(graph_, boost::vertex(startRegion, graph_), DecompositionHeuristic(
this, getRegionFromIndex(goalRegion)),
414 boost::weight_map(
get(&Adjacency::cost, graph_)).distance_map(
415 boost::make_iterator_property_map(distances.begin(),
get(boost::vertex_index, graph_)
417 boost::make_iterator_property_map(parents.begin(),
get(boost::vertex_index, graph_))
418 ).visitor(GoalVisitor(goalRegion))
421 catch (found_goal fg)
423 int region = goalRegion;
426 while (region != startRegion)
428 region = parents[region];
431 lead.resize(leadLength);
433 for (
int i = leadLength-1; i >= 0; --i)
436 region = parents[region];
444 VertexIndexMap index =
get(boost::vertex_index, graph_);
445 std::stack<int> nodesToProcess;
446 std::vector<int> parents(decomp_->getNumRegions(), -1);
447 parents[startRegion] = startRegion;
448 nodesToProcess.push(startRegion);
449 bool goalFound =
false;
450 while (!goalFound && !nodesToProcess.empty())
452 const int v = nodesToProcess.top();
453 nodesToProcess.pop();
454 std::vector<int> neighbors;
455 boost::graph_traits<RegionGraph>::adjacency_iterator ai, aend;
456 for (boost::tie(ai,aend) = adjacent_vertices(boost::vertex(v, graph_), graph_); ai != aend; ++ai)
458 if (parents[index[*ai]] < 0)
460 neighbors.push_back(index[*ai]);
461 parents[index[*ai]] = v;
464 for (std::size_t i = 0; i < neighbors.size(); ++i)
466 const int choice = rng_.uniformInt(i, neighbors.size()-1);
467 if (neighbors[choice] == goalRegion)
469 int region = goalRegion;
471 while (region != startRegion)
473 region = parents[region];
476 lead.resize(leadLength);
478 for (
int j = leadLength-1; j >= 0; --j)
481 region = parents[region];
486 nodesToProcess.push(neighbors[choice]);
487 std::swap(neighbors[i], neighbors[choice]);
493 for (std::size_t i = 0; i < lead.size()-1; ++i)
495 Adjacency &adj = *regionsToEdge_[std::pair<int,int>(lead[i], lead[i+1])];
498 ++adj.numLeadInclusions;
504 double ompl::control::Syclop::defaultEdgeCost(
int r,
int s)
506 const Adjacency &a = *regionsToEdge_[std::pair<int,int>(r,s)];
508 const int nsel = (a.empty ? a.numLeadInclusions : a.numSelections);
509 factor = (double)(1 + nsel*nsel) / (double)(1 + a.covGridCells.size()*a.covGridCells.size());
510 factor *= (a.source->alpha * a.target->alpha);
virtual void setup()
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
base::State * state
The state contained by the motion.
Representation of an adjacency (a directed edge) between two regions in the Decomposition assigned to...
The planner failed to find a solution.
int numSelections
The number of times the low-level tree planner has selected motions from the source region when attem...
void append(const base::State *state)
Append state to the end of the path; it is assumed state is the first state, so no control is applied...
PDF< int >::Element * pdfElem
The Element corresponding to this region in the PDF of available regions.
A shared pointer wrapper for ompl::base::StateSampler.
Representation of a region in the Decomposition assigned to Syclop.
Abstract definition of goals.
std::function< void(int, int, std::vector< int > &)> LeadComputeFn
Leads should consist of a path of adjacent regions in the decomposition that start with the start reg...
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
virtual void clear()
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Representation of a motion.
Definition of a control path.
A shared pointer wrapper for ompl::base::StateValidityChecker.
virtual void clear()
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
A container that supports probabilistic sampling over weighted data.
void clearEdgeCostFactors()
Clears all edge cost factors, making all edge weights equivalent to 1.
Invalid start state or no start state specified.
virtual base::PlannerStatus solve(const base::PlannerTerminationCondition &ptc)
Continues solving until a solution is found or a given planner termination condition is met...
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
void addEdgeCostFactor(const EdgeCostFactorFn &factor)
Adds an edge cost factor to be used for edge weights between adjacent regions.
bool empty
This value is true if and only if this adjacency's source and target regions both contain zero tree m...
The planner found an exact solution.
virtual void setup()
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
std::function< double(int, int)> EdgeCostFactorFn
Each edge weight between two adjacent regions in the Decomposition is defined as a product of edge co...
A class to store the exit status of Planner::solve()
Definition of an abstract state.
virtual bool isSatisfied(const State *st) const =0
Return true if the state satisfies the goal constraints.
void setLeadComputeFn(const LeadComputeFn &compute)
Allows the user to override the lead computation function.
Element * add(const _T &d, const double w)
Adds a piece of data with a given weight to the PDF. Returns a corresponding Element, which can be used to subsequently update or remove the data from the PDF.
const Motion * parent
The parent motion in the tree.
double weight
The probabilistic weight of this region, used when sampling from PDF.
A shared pointer wrapper for ompl::base::Path.
#define OMPL_INFORM(fmt,...)
Log a formatted information string.