37#include "ompl/geometric/planners/informedtrees/EITstar.h"
42#include "ompl/base/objectives/PathLengthOptimizationObjective.h"
43#include "ompl/geometric/PathGeometric.h"
45using namespace std::string_literals;
46using namespace ompl::geometric::eitstar;
53 :
ompl::
base::Planner(spaceInfo,
"EIT*")
54 , graph_(spaceInfo, solutionCost_)
55 , detectionState_(spaceInfo->allocState())
56 , space_(spaceInfo->getStateSpace())
57 , motionValidator_(spaceInfo->getMotionValidator())
62 specs_.multithreaded =
false;
63 specs_.approximateSolutions =
true;
64 specs_.optimizingPaths =
true;
66 specs_.provingSolutionNonExistence =
false;
67 specs_.canReportIntermediateSolutions =
true;
84 [
this]() {
return std::to_string(graph_.getNumberOfSampledStates()); });
86 [
this]() {
return std::to_string(numCollisionCheckedEdges_); });
88 [
this]() {
return std::to_string(graph_.getNumberOfNearestNeighborCalls()); });
93 spaceInfo_->freeState(detectionState_);
102 if (
static_cast<bool>(problem_))
105 if (!problem_->hasOptimizationObjective())
107 OMPL_WARN(
"%s: No optimization objective has been specified. The default is optimizing path "
110 problem_->setOptimizationObjective(
111 std::make_shared<ompl::base::PathLengthOptimizationObjective>(spaceInfo_));
114 if (
static_cast<bool>(problem_->getGoal()))
119 OMPL_ERROR(
"EIT* is currently only implemented for goals that can be cast to "
120 "ompl::base::GOAL_SAMPLEABLE_REGION.");
127 objective_ = problem_->getOptimizationObjective();
130 solutionCost_ = objective_->infiniteCost();
131 reverseCost_ = objective_->infiniteCost();
132 approximateSolutionCost_ = objective_->infiniteCost();
133 approximateSolutionCostToGoal_ = objective_->infiniteCost();
136 forwardQueue_ = std::make_unique<eitstar::ForwardQueue>(objective_, space_);
137 if (isMultiqueryEnabled_)
139 reverseQueue_ = std::make_unique<eitstar::ReverseQueue>(objective_, space_,
140 std::isfinite(suboptimalityFactor_));
144 reverseQueue_ = std::make_unique<eitstar::ReverseQueue>(objective_, space_,
true);
148 graph_.setup(problem_, &
pis_);
151 for (
const auto &start : graph_.getStartStates())
153 startVertices_.emplace_back(start->asForwardVertex());
157 for (
const auto &goal : graph_.getGoalStates())
159 goalVertices_.emplace_back(goal->asReverseVertex());
163 expandGoalVerticesIntoReverseQueue();
164 expandStartVerticesIntoForwardQueue();
169 OMPL_WARN(
"%s: Unable to setup without a problem definition.",
name_.c_str());
176 auto status = ensureSetup();
185 status = ensureStartAndGoalStates(terminationCondition);
195 OMPL_INFORM(
"%s: Solving the given planning problem. The current best solution cost is %.4f",
name_.c_str(),
196 solutionCost_.value());
199 while (continueSolving(terminationCondition))
201 iterate(terminationCondition);
206 status = updateSolution();
209 informAboutPlannerStatus(status);
217 forwardQueue_->clear();
222 reverseQueue_->clear();
225 startVertices_.clear();
226 goalVertices_.clear();
232 solutionCost_ =
ompl::base::Cost(std::numeric_limits<double>::signaling_NaN());
233 reverseCost_ =
ompl::base::Cost(std::numeric_limits<double>::signaling_NaN());
234 approximateSolutionCost_ =
ompl::base::Cost(std::numeric_limits<double>::signaling_NaN());
235 approximateSolutionCostToGoal_ =
ompl::base::Cost(std::numeric_limits<double>::signaling_NaN());
238 reverseSearchTag_ = 1u;
239 startExpansionGraphTag_ = 0u;
240 numSparseCollisionChecksCurrentLevel_ = initialNumSparseCollisionChecks_;
241 numSparseCollisionChecksPreviousLevel_ = 0u;
242 suboptimalityFactor_ = std::numeric_limits<double>::infinity();
252 forwardQueue_->clear();
253 reverseQueue_->clear();
254 startVertices_.clear();
255 goalVertices_.clear();
257 solutionCost_ = objective_->infiniteCost();
258 reverseCost_ = objective_->infiniteCost();
259 approximateSolutionCost_ = objective_->infiniteCost();
260 approximateSolutionCostToGoal_ = objective_->infiniteCost();
262 suboptimalityFactor_ = std::numeric_limits<double>::infinity();
263 restartReverseSearch();
265 numSparseCollisionChecksCurrentLevel_ = initialNumSparseCollisionChecks_;
267 numProcessedEdges_ = 0u;
271 if (!isMultiqueryEnabled_)
281 return solutionCost_;
286 batchSize_ = numSamples;
296 initialNumSparseCollisionChecks_ = numChecks;
297 numSparseCollisionChecksCurrentLevel_ = numChecks;
298 numSparseCollisionChecksPreviousLevel_ = 0u;
303 graph_.setRadiusFactor(factor);
308 return graph_.getRadiusFactor();
313 suboptimalityFactor_ = factor;
318 isMultiqueryEnabled_ = multiquery;
319 graph_.enableMultiquery(multiquery);
324 return isMultiqueryEnabled_;
329 graph_.setEffortThreshold(threshold);
334 return graph_.getEffortThreshold();
339 graph_.enablePruning(enable);
344 return graph_.isPruningEnabled();
349 trackApproximateSolutions_ = track;
354 return trackApproximateSolutions_;
359 graph_.setUseKNearest(useKNearest);
364 return graph_.getUseKNearest();
369 graph_.setMaxNumberOfGoals(numberOfGoals);
374 return graph_.getMaxNumberOfGoals();
379 assert(forwardQueue_);
380 return forwardQueue_->empty();
385 assert(reverseQueue_);
386 return reverseQueue_->empty();
391 return forwardQueue_->getEdges();
396 return reverseQueue_->getEdges();
402 std::vector<Edge> edges;
405 const std::function<void(
const std::shared_ptr<Vertex> &)> getEdgesRecursively =
406 [&edges, &getEdgesRecursively](
const std::shared_ptr<Vertex> &vertex)
408 for (
const auto &child : vertex->getChildren())
410 getEdgesRecursively(child);
413 if (
auto parent = vertex->getParent().lock())
415 edges.emplace_back(parent->getState(), vertex->getState());
420 for (
const auto &root : goalVertices_)
422 getEdgesRecursively(root);
431 assert(forwardQueue_);
432 if (forwardQueue_->empty())
436 return forwardQueue_->peek(suboptimalityFactor_);
441 assert(reverseQueue_);
442 if (reverseQueue_->empty())
446 return reverseQueue_->peek();
452 Planner::getPlannerData(data);
455 for (
const auto &state : graph_.getStates())
461 for (
const auto &state2 : graph_.getStates())
463 if (state->isWhitelisted(state2))
477 if (isMultiqueryEnabled_ &&
478 graph_.getStates().size() == graph_.getStartStates().size() + graph_.getGoalStates().size())
480 improveApproximation(terminationCondition);
486 if (continueReverseSearch())
488 iterateReverseSearch();
490 else if (continueForwardSearch())
492 iterateForwardSearch();
496 improveApproximation(terminationCondition);
503 void EITstar::iterateForwardSearch()
506 assert(!forwardQueue_->empty());
509 auto edge = forwardQueue_->pop(suboptimalityFactor_);
510 ++numProcessedEdges_;
513 assert(edge.source->hasForwardVertex());
514 assert(!std::isfinite(suboptimalityFactor_) || isClosed(edge.target->asReverseVertex()));
517 if (isInForwardTree(edge))
520 forwardQueue_->insertOrUpdate(expandUnlessGoal(edge.target));
525 if (!couldImproveForwardTree(edge))
534 const auto edgeCost = objective_->motionCost(edge.source->raw(), edge.target->raw());
535 const auto targetCost = combine(edge.source->getCurrentCostToCome(), edgeCost);
538 if (isBetter(targetCost, edge.target->getCurrentCostToCome()) &&
539 isBetter(combine(targetCost, edge.target->getAdmissibleCostToGo()), solutionCost_))
542 auto source = edge.source->asForwardVertex();
543 auto target = edge.target->asForwardVertex();
546 target->updateParent(source);
549 source->addChild(target);
552 target->setEdgeCost(edgeCost);
555 edge.target->setCurrentCostToCome(targetCost);
558 const auto changedVertices = target->updateCurrentCostOfChildren(objective_);
561 for (
const auto &vertex : changedVertices)
564 forwardQueue_->updateIfExists({vertex->getParent().lock()->getState(), vertex->getState()});
567 if (graph_.isGoal(vertex->getState()))
569 updateExactSolution(vertex->getState());
574 if (!graph_.isGoal(edge.target))
576 auto edges = expand(edge.target);
577 edges.erase(std::remove_if(edges.begin(), edges.end(), [&edge](
const auto &e)
578 { return e.target->getId() == edge.source->getId(); }),
580 forwardQueue_->insertOrUpdate(edges);
584 updateExactSolution(edge.target);
591 const bool inReverseTree = edge.source->asReverseVertex()->isParent(edge.target->asReverseVertex()) ||
592 edge.target->asReverseVertex()->isParent(edge.source->asReverseVertex());
598 numSparseCollisionChecksPreviousLevel_ = numSparseCollisionChecksCurrentLevel_;
599 numSparseCollisionChecksCurrentLevel_ = (2u * numSparseCollisionChecksPreviousLevel_) + 1u;
602 restartReverseSearch();
605 forwardQueue_->rebuild();
610 void EITstar::iterateReverseSearch()
613 assert(!reverseQueue_->empty());
616 auto edge = reverseQueue_->pop();
617 auto &source = edge.source;
618 auto &target = edge.target;
621 assert(source->hasReverseVertex());
624 source->asReverseVertex()->registerExpansionInReverseSearch(reverseSearchTag_);
627 if (isInReverseTree(edge))
629 auto outgoingEdges = expand(target);
630 outgoingEdges.erase(std::remove_if(outgoingEdges.begin(), outgoingEdges.end(), [&source](
const auto &e)
631 { return e.target->getId() == source->getId(); }),
632 outgoingEdges.end());
635 if (outgoingEdges.empty())
637 target->asReverseVertex()->registerExpansionInReverseSearch(reverseSearchTag_);
641 reverseQueue_->insertOrUpdate(outgoingEdges);
648 if (couldBeValid(edge))
651 const auto edgeCost = objective_->motionCostHeuristic(source->raw(), target->raw());
654 const auto effort = estimateEffortToTarget(edge);
655 const bool doesDecreaseEffort = (effort < target->getEstimatedEffortToGo());
657 if ((!isMultiqueryEnabled_ && doesImproveReverseTree(edge, edgeCost)) ||
658 (isMultiqueryEnabled_ &&
659 ((std::isfinite(suboptimalityFactor_) && doesImproveReverseTree(edge, edgeCost)) ||
660 (!std::isfinite(suboptimalityFactor_) && doesDecreaseEffort))))
663 auto parentVertex = source->asReverseVertex();
664 auto childVertex = target->asReverseVertex();
667 assert(!isClosed(childVertex));
670 childVertex->updateParent(parentVertex);
673 parentVertex->addChild(childVertex);
676 target->setAdmissibleCostToGo(objective_->betterCost(
677 combine(source->getAdmissibleCostToGo(), edgeCost), edge.target->getAdmissibleCostToGo()));
680 target->setEstimatedCostToGo(
681 objective_->betterCost(estimateCostToTarget(edge), target->getEstimatedCostToGo()));
684 target->setEstimatedEffortToGo(std::min(effort, target->getEstimatedEffortToGo()));
687 if (graph_.isStart(target) && isBetter(target->getAdmissibleCostToGo(), reverseCost_))
689 reverseCost_ = target->getAdmissibleCostToGo();
693 for (
const auto &queueSource : target->getSourcesOfIncomingEdgesInForwardQueue())
695 forwardQueue_->updateIfExists({queueSource.lock(), target});
699 auto outgoingEdges = expand(target);
702 std::remove_if(outgoingEdges.begin(), outgoingEdges.end(),
703 [&source,
this](
const auto &e)
705 if (e.target->getId() == source->getId())
709 if (objective_->isFinite(solutionCost_) &&
710 isBetter(solutionCost_, reverseQueue_->computeAdmissibleSolutionCost(e)))
717 outgoingEdges.end());
720 if (outgoingEdges.empty())
722 target->asReverseVertex()->registerExpansionInReverseSearch(reverseSearchTag_);
726 reverseQueue_->insertOrUpdate(outgoingEdges);
732 void EITstar::improveApproximation(
const ompl::base::PlannerTerminationCondition &terminationCondition)
735 if (graph_.addStates(batchSize_, terminationCondition))
738 numSparseCollisionChecksCurrentLevel_ = initialNumSparseCollisionChecks_;
739 numSparseCollisionChecksPreviousLevel_ = 0u;
742 restartReverseSearch();
745 forwardQueue_->clear();
746 expandStartVerticesIntoForwardQueue();
759 OMPL_ERROR(
"%s: Called solve without setting up the planner first.", name_.c_str());
764 if (!spaceInfo_->isSetup())
766 OMPL_ERROR(
"%s: Called solve without setting up the state space first.", name_.c_str());
774 EITstar::ensureStartAndGoalStates(
const ompl::base::PlannerTerminationCondition &terminationCondition)
777 if (!graph_.hasStartState())
779 graph_.updateStartAndGoalStates(terminationCondition, &pis_);
782 if (!graph_.hasStartState())
784 OMPL_ERROR(
"%s: No solution can be found as no start states are available", name_.c_str());
790 if (!graph_.hasGoalState())
792 graph_.updateStartAndGoalStates(terminationCondition, &pis_);
795 if (!graph_.hasGoalState())
797 OMPL_ERROR(
"%s: No solution can be found as no goal states are available", name_.c_str());
806 std::shared_ptr<ompl::geometric::PathGeometric>
807 EITstar::getPathToState(
const std::shared_ptr<eitstar::State> &state)
const
811 std::vector<std::shared_ptr<State>> states;
812 auto current = state;
815 while (!graph_.isStart(current))
817 assert(current->asForwardVertex()->getParent().lock());
818 states.emplace_back(current);
819 current = current->asForwardVertex()->getParent().lock()->getState();
821 states.emplace_back(current);
824 auto path = std::make_shared<ompl::geometric::PathGeometric>(spaceInfo_);
825 for (
auto it = states.crbegin(); it != states.crend(); ++it)
828 assert((*it)->raw());
829 path->append((*it)->raw());
835 bool EITstar::continueSolving(
const ompl::base::PlannerTerminationCondition &terminationCondition)
const
843 return !(terminationCondition || objective_->isSatisfied(solutionCost_) ||
844 (!isBetter(graph_.minPossibleCost(), solutionCost_) && !pis_.haveMoreStartStates() &&
845 !pis_.haveMoreGoalStates()));
850 if (forwardQueue_->size() != 0u)
852 const auto forwardEdge = forwardQueue_->peek(suboptimalityFactor_);
853 const auto forwardEffort = forwardQueue_->estimateEffort(forwardEdge);
855 return forwardEffort;
858 return std::numeric_limits<unsigned int>::infinity();
861 bool EITstar::continueReverseSearch()
const
864 if (reverseQueue_->empty())
869 else if (forwardQueue_->empty())
898 const auto forwardEdge = forwardQueue_->peek(suboptimalityFactor_);
900 if (!std::isfinite(suboptimalityFactor_) && isMultiqueryEnabled_)
902 if (!forwardEdge.target->hasReverseVertex())
907 const auto forwardEffort = forwardQueue_->estimateEffort(forwardEdge);
908 const auto reverseEffort = reverseQueue_->peekEffort();
909 unsigned int minEffortToCome = 0u;
911 const auto reverseEdge = reverseQueue_->peek();
912 if (!reverseEdge.target->hasForwardVertex())
914 minEffortToCome = forwardQueue_->getMinEffortToCome();
917 return reverseEffort + minEffortToCome < forwardEffort;
920 const bool condition1 = isClosed(forwardEdge.target->asReverseVertex()) &&
921 isBetter(forwardQueue_->getLowerBoundOnOptimalSolutionCost(),
922 reverseQueue_->getLowerBoundOnOptimalSolutionCost());
924 const bool condition2 = !forwardQueue_->containsOpenTargets(reverseSearchTag_);
926 const bool condition3 = !std::isfinite(suboptimalityFactor_) && forwardEdge.target->hasReverseVertex();
929 return !(condition1 || condition2 || condition3);
932 bool EITstar::continueForwardSearch()
const
935 if (forwardQueue_->empty())
942 return isBetter(forwardQueue_->getLowerBoundOnOptimalSolutionCost(), solutionCost_);
945 void EITstar::updateExactSolution()
947 for (
const auto &goal : graph_.getGoalStates())
949 if (goal->hasForwardVertex())
951 updateExactSolution(goal);
958 updateExactSolution();
959 if (objective_->isFinite(solutionCost_))
963 else if (trackApproximateSolutions_)
965 updateApproximateSolution();
974 void EITstar::restartReverseSearch()
976 reverseQueue_->clear();
978 if (isMultiqueryEnabled_)
980 reverseQueue_->setCostQueueOrder(std::isfinite(suboptimalityFactor_));
984 reverseQueue_->setCostQueueOrder(
true);
987 goalVertices_.clear();
988 reverseCost_ = objective_->infiniteCost();
989 for (
const auto &goal : graph_.getGoalStates())
991 goalVertices_.emplace_back(goal->asReverseVertex());
992 goal->setAdmissibleCostToGo(objective_->identityCost());
993 goal->setEstimatedCostToGo(objective_->identityCost());
994 goal->setEstimatedEffortToGo(0u);
996 expandGoalVerticesIntoReverseQueue();
1000 void EITstar::updateApproximateSolution()
1002 for (
const auto &start : graph_.getStartStates())
1004 start->asForwardVertex()->callOnBranch([
this](
const std::shared_ptr<eitstar::State> &state) ->
void
1005 { updateApproximateSolution(state); });
1009 void EITstar::updateCurrentCostToCome(
const std::shared_ptr<eitstar::State> &state)
1012 if (graph_.isStart(state))
1018 if (!state->hasForwardVertex())
1020 state->setCurrentCostToCome(objective_->infiniteCost());
1025 auto forwardVertex = state->asForwardVertex();
1026 state->setCurrentCostToCome(combine(forwardVertex->getParent().lock()->getState()->getCurrentCostToCome(),
1027 forwardVertex->getEdgeCost()));
1030 void EITstar::updateExactSolution(
const std::shared_ptr<eitstar::State> &goal)
1035 if (isBetter(goal->getCurrentCostToCome(), solutionCost_) || !problem_->hasExactSolution())
1038 solutionCost_ = goal->getCurrentCostToCome();
1041 ompl::base::PlannerSolution solution(getPathToState(goal));
1042 solution.setPlannerName(name_);
1043 solution.setOptimized(objective_, solutionCost_, objective_->isSatisfied(solutionCost_));
1044 problem_->addSolutionPath(solution);
1046 if (!std::isfinite(suboptimalityFactor_))
1050 suboptimalityFactor_ = 1.0;
1052 if (isMultiqueryEnabled_)
1054 restartReverseSearch();
1056 forwardQueue_->clear();
1057 expandStartVerticesIntoForwardQueue();
1062 if (
static_cast<bool>(pdef_->getIntermediateSolutionCallback()))
1064 const auto &path = solution.path_->as<ompl::geometric::PathGeometric>()->getStates();
1066 std::vector<const base::State *> const_path(path.begin(), path.end());
1067 pdef_->getIntermediateSolutionCallback()(
this, const_path, solutionCost_);
1071 informAboutNewSolution();
1075 void EITstar::updateApproximateSolution(
const std::shared_ptr<eitstar::State> &state)
1077 assert(trackApproximateSolutions_);
1078 if ((state->hasForwardVertex() || graph_.isStart(state)) && !graph_.isGoal(state))
1080 const auto costToGoal = computeCostToGoToGoal(state);
1081 if (isBetter(costToGoal, approximateSolutionCostToGoal_) || !problem_->hasSolution())
1083 approximateSolutionCost_ = state->getCurrentCostToCome();
1084 approximateSolutionCostToGoal_ = costToGoal;
1085 ompl::base::PlannerSolution solution(getPathToState(state));
1086 solution.setPlannerName(name_);
1089 solution.setApproximate(costToGoal.value());
1092 solution.setOptimized(objective_, approximateSolutionCost_,
false);
1095 pdef_->addSolutionPath(solution);
1100 ompl::base::Cost EITstar::computeCostToGoToGoal(
const std::shared_ptr<eitstar::State> &state)
const
1102 auto bestCost = objective_->infiniteCost();
1103 for (
const auto &goal : graph_.getGoalStates())
1105 bestCost = objective_->betterCost(bestCost, objective_->motionCost(state->raw(), goal->raw()));
1110 void EITstar::informAboutNewSolution()
const
1112 OMPL_INFORM(
"%s (%u iterations): Found a new exact solution of cost %.4f. Sampled a total of %u states, %u "
1113 "of which were valid samples (%.1f \%). Processed %u edges, %u of which were collision checked "
1114 "(%.1f \%). The forward search tree has %u vertices. The reverse search tree has %u vertices.",
1115 name_.c_str(), iteration_, solutionCost_.value(), graph_.getNumberOfSampledStates(),
1116 graph_.getNumberOfValidSamples(),
1117 graph_.getNumberOfSampledStates() == 0u ?
1119 100.0 * (
static_cast<double>(graph_.getNumberOfValidSamples()) /
1120 static_cast<double>(graph_.getNumberOfSampledStates())),
1121 numProcessedEdges_, numCollisionCheckedEdges_,
1122 numProcessedEdges_ == 0u ? 0.0 :
1123 100.0 * (
static_cast<float>(numCollisionCheckedEdges_) /
1124 static_cast<float>(numProcessedEdges_)),
1125 countNumVerticesInForwardTree(), countNumVerticesInReverseTree());
1134 OMPL_INFORM(
"%s (%u iterations): Found an exact solution of cost %.4f.", name_.c_str(), iteration_,
1135 solutionCost_.value());
1140 OMPL_INFORM(
"%s (%u iterations): Did not find an exact solution, but found an approximate solution "
1141 "of cost %.4f which is %.4f away from a goal (in cost space).",
1142 name_.c_str(), iteration_, approximateSolutionCost_.value(),
1143 approximateSolutionCostToGoal_.value());
1148 if (trackApproximateSolutions_)
1150 OMPL_INFORM(
"%s (%u iterations): Did not find any solution.", name_.c_str(), iteration_);
1154 OMPL_INFORM(
"%s (%u iterations): Did not find an exact solution, and tracking approximate "
1155 "solutions is disabled.",
1156 name_.c_str(), iteration_);
1169 OMPL_INFORM(
"%s (%u iterations): Unable to solve the given planning problem.", name_.c_str(),
1175 unsigned int EITstar::countNumVerticesInForwardTree()
const
1177 const auto states = graph_.getStates();
1178 return std::count_if(states.cbegin(), states.cend(),
1179 [](
const auto &state) { return state->hasForwardVertex(); });
1182 unsigned int EITstar::countNumVerticesInReverseTree()
const
1184 const auto states = graph_.getStates();
1185 return std::count_if(states.cbegin(), states.cend(),
1186 [](
const auto &state) { return state->hasReverseVertex(); });
1189 bool EITstar::couldImproveForwardPath(
const Edge &edge)
const
1192 if (!objective_->isFinite(solutionCost_))
1195 const auto heuristicPathCost =
1196 combine(edge.
source->getCurrentCostToCome(),
1197 objective_->motionCostHeuristic(edge.
source->raw(), edge.
target->raw()),
1198 objective_->costToGo(edge.
target->raw(), problem_->getGoal().get()));
1199 if (isBetter(heuristicPathCost, solutionCost_))
1214 bool EITstar::couldImproveForwardTree(
const Edge &edge)
const
1216 const auto heuristicCostToCome =
1217 combine(edge.
source->getCurrentCostToCome(),
1218 objective_->motionCostHeuristic(edge.
source->raw(), edge.
target->raw()));
1219 return isBetter(heuristicCostToCome, edge.
target->getCurrentCostToCome());
1222 bool EITstar::doesImproveForwardPath(
const Edge &edge,
const ompl::base::Cost &edgeCost)
const
1225 if (!objective_->isFinite(solutionCost_))
1232 combine(edge.
source->getCurrentCostToCome(), edgeCost, edge.
target->getLowerBoundCostToGo()),
1236 bool EITstar::doesImproveForwardTree(
const Edge &edge,
const ompl::base::Cost &edgeCost)
const
1238 return isBetter(combine(edge.
source->getCurrentCostToCome(), edgeCost),
1239 edge.
target->getCurrentCostToCome());
1242 ompl::base::Cost EITstar::estimateCostToTarget(
const eitstar::Edge &edge)
const
1244 return combine(edge.
source->getEstimatedCostToGo(),
1245 objective_->motionCostBestEstimate(edge.
source->raw(), edge.
target->raw()));
1248 unsigned int EITstar::estimateEffortToTarget(
const eitstar::Edge &edge)
const
1252 std::size_t checksToCome = 0u;
1260 const std::size_t fullSegmentCount = space_->validSegmentCount(edge.
source->raw(), edge.
target->raw());
1262 const std::size_t performedChecks = edge.
target->getIncomingCollisionCheckResolution(edge.
source);
1264 checksToCome = fullSegmentCount - performedChecks;
1267 return edge.
source->getEstimatedEffortToGo() + checksToCome;
1270 bool EITstar::isValid(
const Edge &edge)
const
1274 const std::size_t numChecks = space_->validSegmentCount(edge.
source->raw(), edge.
target->raw()) - 1u;
1276 return isValidAtResolution(edge, numChecks);
1279 bool EITstar::couldBeValid(
const Edge &edge)
const
1281 return isValidAtResolution(edge, numSparseCollisionChecksCurrentLevel_);
1284 bool EITstar::isValidAtResolution(
const Edge &edge, std::size_t numChecks)
const
1299 const std::size_t fullSegmentCount = space_->validSegmentCount(edge.
source->raw(), edge.
target->raw());
1303 const auto segmentCount = std::min(numChecks + 1u, fullSegmentCount);
1339 std::size_t currentCheck = 1u;
1342 const std::size_t performedChecks = edge.
target->getIncomingCollisionCheckResolution(edge.
source);
1345 std::queue<std::pair<std::size_t, std::size_t>> indices;
1346 indices.emplace(1u, numChecks);
1349 while (!indices.empty())
1352 const auto current = indices.front();
1355 auto mid = (current.first + current.second) / 2;
1358 if (currentCheck > performedChecks)
1360 space_->interpolate(edge.
source->raw(), edge.
target->raw(),
1361 static_cast<double>(mid) /
static_cast<double>(segmentCount), detectionState_);
1363 if (!spaceInfo_->isValid(detectionState_))
1370 graph_.registerInvalidEdge(edge);
1379 if (current.first < mid)
1381 indices.emplace(current.first, mid - 1u);
1383 if (current.second > mid)
1385 indices.emplace(mid + 1u, current.second);
1394 edge.
source->setIncomingCollisionCheckResolution(edge.
target, currentCheck - 1u);
1395 edge.
target->setIncomingCollisionCheckResolution(edge.
source, currentCheck - 1u);
1398 if (segmentCount == fullSegmentCount)
1400 ++numCollisionCheckedEdges_;
1404 graph_.registerWhitelistedState(edge.
source);
1405 graph_.registerWhitelistedState(edge.
target);
1411 bool EITstar::isBetter(
const ompl::base::Cost &lhs,
const ompl::base::Cost &rhs)
const
1413 return objective_->isCostBetterThan(lhs, rhs);
1416 ompl::base::Cost EITstar::combine(
const ompl::base::Cost &lhs,
const ompl::base::Cost &rhs)
const
1418 return objective_->combineCosts(lhs, rhs);
1421 void EITstar::expandStartVerticesIntoForwardQueue()
1423 for (
auto &vertex : startVertices_)
1425 forwardQueue_->insertOrUpdate(expand(vertex->getState()));
1429 void EITstar::expandGoalVerticesIntoReverseQueue()
1431 for (
auto &vertex : goalVertices_)
1433 reverseQueue_->insertOrUpdate(expand(vertex->getState()));
1437 bool EITstar::isClosed(
const std::shared_ptr<Vertex> &vertex)
const
1439 return vertex->getExpandTag() == reverseSearchTag_;
1442 bool EITstar::isInForwardTree(
const Edge &edge)
const
1444 if (!edge.
source->hasForwardVertex() || !edge.
target->hasForwardVertex())
1449 return edge.
target->asForwardVertex()->isParent(edge.
source->asForwardVertex());
1452 bool EITstar::isInReverseTree(
const Edge &edge)
const
1454 if (!edge.
source->hasReverseVertex() || !edge.
target->hasReverseVertex())
1459 return edge.
target->asReverseVertex()->isParent(edge.
source->asReverseVertex());
1462 bool EITstar::doesImproveReversePath(
const Edge &edge)
const
1465 if (!objective_->isFinite(reverseCost_))
1471 const auto heuristicPathCost =
1472 combine(edge.
source->getAdmissibleCostToGo(),
1473 objective_->motionCostHeuristic(edge.
source->raw(), edge.
target->raw()),
1474 edge.
target->getLowerBoundCostToCome());
1476 return isBetter(heuristicPathCost, reverseCost_);
1479 bool EITstar::doesImproveReverseTree(
const Edge &edge,
const ompl::base::Cost &admissibleEdgeCost)
const
1481 return isBetter(combine(edge.
source->getAdmissibleCostToGo(), admissibleEdgeCost),
1482 edge.
target->getAdmissibleCostToGo());
1485 std::vector<Edge> EITstar::expandUnlessGoal(
const std::shared_ptr<State> &state)
const
1487 if (graph_.isGoal(state))
1492 return expand(state);
1495 std::vector<Edge> EITstar::expand(
const std::shared_ptr<State> &state)
const
1498 assert(state->hasForwardVertex() || state->hasReverseVertex());
1501 std::vector<Edge> outgoingEdges;
1504 for (
const auto &neighborState : graph_.getNeighbors(state))
1506 outgoingEdges.emplace_back(state, neighborState.lock());
1510 if (state->hasForwardVertex())
1513 auto forwardVertex = state->asForwardVertex();
1516 if (!graph_.isStart(state))
1519 assert(forwardVertex->getParent().lock());
1522 auto forwardParentState = forwardVertex->getParent().lock()->getState();
1526 outgoingEdges.cbegin(), outgoingEdges.cend(), [&forwardParentState](
const auto &edge)
1527 { return edge.target->getId() == forwardParentState->getId(); }) == outgoingEdges.cend())
1529 outgoingEdges.emplace_back(state, forwardParentState);
1534 for (
const auto &child : forwardVertex->getChildren())
1537 auto forwardChildState = child->getState();
1541 outgoingEdges.cbegin(), outgoingEdges.cend(), [&forwardChildState](
const auto &edge)
1542 { return edge.target->getId() == forwardChildState->getId(); }) == outgoingEdges.cend())
1544 outgoingEdges.emplace_back(state, forwardChildState);
1550 if (state->hasReverseVertex())
1553 auto reverseVertex = state->asReverseVertex();
1556 if (!graph_.isGoal(state))
1559 assert(reverseVertex->getParent().lock());
1562 auto reverseParentState = reverseVertex->getParent().lock()->getState();
1566 outgoingEdges.cbegin(), outgoingEdges.cend(), [&reverseParentState](
const auto &edge)
1567 { return edge.target->getId() == reverseParentState->getId(); }) == outgoingEdges.cend())
1569 outgoingEdges.emplace_back(state, reverseParentState);
1574 for (
const auto &child : reverseVertex->getChildren())
1577 auto reverseChildState = child->getState();
1581 outgoingEdges.cbegin(), outgoingEdges.cend(), [&reverseChildState](
const auto &edge)
1582 { return edge.target->getId() == reverseChildState->getId(); }) == outgoingEdges.cend())
1584 outgoingEdges.emplace_back(state, reverseChildState);
1589 return outgoingEdges;
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique,...
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...
unsigned int addVertex(const PlannerDataVertex &st)
Adds the given vertex to the graph data. The vertex index is returned. Duplicates are not added....
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
PlannerInputStates pis_
Utility class to extract valid input states.
void addPlannerProgressProperty(const std::string &progressPropertyName, const PlannerProgressProperty &prop)
Add a planner progress property called progressPropertyName with a property querying function prop to...
PlannerSpecs specs_
The specifications of the planner (its capabilities).
void declareParam(const std::string &name, const PlannerType &planner, const SetterType &setter, const GetterType &getter, const std::string &rangeSuggestion="")
This function declares a parameter for this planner instance, and specifies the setter and getter fun...
std::string name_
The name of this planner.
bool setup_
Flag indicating whether setup() has been called.
bool areApproximateSolutionsTracked() const
Returns whether approximate solutions are tracked or not.
bool isReverseQueueEmpty() const
Returns true if the reverse queue is empty.
unsigned int getStartGoalPruningThreshold() const
Get threshold at which we prune starts/goals.
void setStartGoalPruningThreshold(unsigned int threshold)
Set start/goal pruning threshold.
ompl::base::Cost bestCost() const
Returns the cost of the current best solution.
double getRadiusFactor() const
Returns the radius factor.
bool isMultiqueryEnabled() const
Get wheter multiquery is enabled or not.
void clear() override
Clears all internal planner structures but retains settings. Subsequent calls to solve() will start f...
void enableMultiquery(bool multiquery)
Set wheter multiquery is enabled or not.
void setBatchSize(unsigned int numSamples)
Sets the number of samples per batch.
void setup() override
Setup the parts of the planner that rely on the problem definition being set.
void setRadiusFactor(double factor)
Sets the radius factor.
~EITstar()
Destructs this instance of EIT*.
void setMaxNumberOfGoals(unsigned int numberOfGoals)
Set the maximum number of goals EIT* will sample from sampleable goal regions.
eitstar::Edge getNextReverseEdge() const
Returns the next edge in the reverse queue.
void trackApproximateSolutions(bool track)
Sets whether to track approximate solutions or not.
std::vector< eitstar::Edge > getReverseQueue() const
Returns a copy of the reverse queue.
std::vector< eitstar::Edge > getForwardQueue() const
Returns a copy of the forward queue.
void setInitialNumberOfSparseCollisionChecks(std::size_t numChecks)
Sets the initial number of collision checks on the reverse search.
eitstar::Edge getNextForwardEdge() const
Returns the next edge in the forward queue.
unsigned int getForwardEffort() const
Returns the effort of the edge at the top of the forward queue.
ompl::base::PlannerStatus solve(const ompl::base::PlannerTerminationCondition &terminationCondition) override
Solves the provided motion planning problem, respecting the given termination condition.
void setSuboptimalityFactor(double factor)
Sets the (initial) suboptimality factor.
void enablePruning(bool prune)
Set whether pruning is enabled or not.
EITstar(const std::shared_ptr< ompl::base::SpaceInformation > &spaceInfo)
Constructs an instance of EIT* using the provided space information.
void getPlannerData(base::PlannerData &data) const override
Returns the planner data.
bool isForwardQueueEmpty() const
Returns true if the forward queue is empty.
unsigned int getMaxNumberOfGoals() const
Returns the maximum number of goals EIT* will sample from sampleable goal regions.
std::vector< eitstar::Edge > getReverseTree() const
Returns copies of the edges in the reverse tree.
void setUseKNearest(bool useKNearest)
Set whether to use a k-nearest RGG connection model. If false, EIT* uses an r-disc model.
unsigned int getBatchSize() const
Returns the number of samples per batch.
bool getUseKNearest() const
Returns whether to use a k-nearest RGG connection model. If false, EIT* uses an r-disc model.
void clearQuery() override
Clears all query-specific information, such as start and goal states and search trees....
bool isPruningEnabled() const
Returns whether pruning is enabled or not.
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
This namespace contains sampling based planning routines shared by both planning under geometric cons...
@ GOAL_SAMPLEABLE_REGION
This bit is set if casting to sampleable goal regions (ompl::base::GoalSampleableRegion) is possible.
This namespace contains code that is specific to planning under geometric constraints.
Main namespace. Contains everything in this library.
A class to store the exit status of Planner::solve().
StatusType
The possible values of the status returned by a planner.
@ ABORT
The planner did not find a solution for some other reason.
@ INVALID_START
Invalid start state or no start state specified.
@ EXACT_SOLUTION
The planner found an exact solution.
@ INVALID_GOAL
Invalid goal state.
@ UNRECOGNIZED_GOAL_TYPE
The goal is of a type that a planner does not recognize.
@ APPROXIMATE_SOLUTION
The planner found an approximate solution.
@ TIMEOUT
The planner failed to find a solution.
@ UNKNOWN
Uninitialized status.
@ TYPE_COUNT
The number of possible status values.
@ INFEASIBLE
The planner decided that problem is infeasible.
@ CRASH
The planner crashed.
A struct for basic edge data.
std::shared_ptr< State > source
The parent state of this edge.
std::shared_ptr< State > target
The child state of this edge.