37#include <ompl/base/SpaceInformation.h>
38#include <ompl/base/objectives/PathLengthOptimizationObjective.h>
39#include <ompl/base/objectives/StateCostIntegralObjective.h>
40#include <ompl/base/objectives/MaximizeMinClearanceObjective.h>
41#include <ompl/base/spaces/RealVectorStateSpace.h>
42#include <ompl/base/spaces/RealVectorStateSpace.h>
45#include "ompl/geometric/planners/lazyinformedtrees/BLITstar.h"
51#include <boost/range/adaptor/reversed.hpp>
53#include "ompl/base/objectives/PathLengthOptimizationObjective.h"
56using namespace std::string_literals;
57using namespace ompl::geometric::blitstar;
65 :
ompl::
base::Planner(spaceInformation,
"BLITstar")
66 , detectionState_(spaceInformation->allocState())
68 , graph_(solutionCost_)
69 , forwardVertexQueue_([this](const auto &lhs, const auto &rhs) {
return isVertexBetter(lhs, rhs); })
70 , reverseVertexQueue_([
this](
const auto &lhs,
const auto &rhs) {
return isVertexBetter(lhs, rhs); })
71 , space_(spaceInformation->getStateSpace())
75 specs_.multithreaded =
false;
76 specs_.approximateSolutions =
true;
77 specs_.optimizingPaths =
true;
78 specs_.directed =
true;
79 specs_.provingSolutionNonExistence =
false;
80 specs_.canReportIntermediateSolutions =
true;
81 spaceInformation_ = spaceInformation;
93 addPlannerProgressProperty(
"iterations INTEGER", [
this]() {
return std::to_string(numIterations_); });
94 addPlannerProgressProperty(
"best cost DOUBLE", [
this]() {
return std::to_string(solutionCost_.value()); });
95 addPlannerProgressProperty(
"state collision checks INTEGER",
96 [
this]() {
return std::to_string(graph_.getNumberOfStateCollisionChecks()); });
97 addPlannerProgressProperty(
"edge collision checks INTEGER",
98 [
this]() {
return std::to_string(numEdgeCollisionChecks_); });
99 addPlannerProgressProperty(
"nearest neighbour calls INTEGER",
100 [
this]() {
return std::to_string(graph_.getNumberOfNearestNeighborCalls()); });
105 si_->freeState(detectionState_);
114 if (
static_cast<bool>(Planner::pdef_))
117 if (!
pdef_->hasOptimizationObjective())
119 OMPL_WARN(
"%s: No optimization objective has been specified. Defaulting to path length.",
120 Planner::getName().c_str());
121 Planner::pdef_->setOptimizationObjective(
122 std::make_shared<ompl::base::PathLengthOptimizationObjective>(Planner::si_));
125 if (
static_cast<bool>(
pdef_->getGoal()))
130 OMPL_ERROR(
"BLIT* is currently only implemented for goals that can be cast to "
131 "ompl::base::GOAL_SAMPLEABLE_GOAL_REGION.");
138 objective_ =
pdef_->getOptimizationObjective();
141 solutionCost_ = objective_->infiniteCost();
145 C_curr = objective_->infiniteCost();
146 approximateSolutionCostToGoal_ = objective_->infiniteCost();
149 motionValidator_ =
si_->getMotionValidator();
158 OMPL_WARN(
"BLIT*: Unable to setup without a problem definition.");
189 if (!graph_.hasAStartState())
191 graph_.updateStartAndGoalStates(terminationCondition, &
pis_);
194 if (!graph_.hasAStartState())
196 OMPL_WARN(
"%s: No solution can be found as no start states are available",
name_.c_str());
202 if (!graph_.hasAGoalState())
204 graph_.updateStartAndGoalStates(terminationCondition, &
pis_);
207 if (!graph_.hasAGoalState())
209 OMPL_WARN(
"%s: No solution can be found as no goal states are available",
name_.c_str());
222 approximateSolutionCostToGoal_ = approximateSolutionCost_ = solutionCost_ = objective_->infiniteCost();
247 OMPL_INFORM(
"%s: Solving the given planning problem. The current best solution cost is %.4f",
name_.c_str(),
248 solutionCost_.value());
251 while (!terminationCondition && !objective_->isSatisfied(solutionCost_))
253 iterate(terminationCondition);
257 status = updateSolution();
260 informAboutPlannerStatus(status);
268 static std::set<std::shared_ptr<Vertex>,
269 std::function<bool(
const std::shared_ptr<Vertex> &,
const std::shared_ptr<Vertex> &)>>
270 liveStates([](
const auto &lhs,
const auto &rhs) {
return lhs->getId() < rhs->getId(); });
273 Planner::getPlannerData(data);
276 auto vertices = graph_.getVertices();
279 for (
const auto &vertex : vertices)
282 liveStates.insert(vertex);
285 if (graph_.isStart(vertex))
289 else if (graph_.isGoal(vertex))
299 if (vertex->hasForwardParent())
303 vertex->getForwardParent()->getId()));
310 batchSize_ = batchSize;
320 graph_.setRewireFactor(rewireFactor);
325 return graph_.getRewireFactor();
330 isPruningEnabled_ = prune;
335 return isPruningEnabled_;
340 graph_.setUseKNearest(useKNearest);
345 return graph_.getUseKNearest();
350 graph_.setMaxNumberOfGoals(numberOfGoals);
355 return graph_.getMaxNumberOfGoals();
360 std::vector<blitstar::KeyVertexPair> reverseQueue;
361 reverseVertexQueue_.getContent(reverseQueue);
362 for (
const auto &element : reverseQueue)
364 element.second->resetReverseVertexQueuePointer();
366 reverseVertexQueue_.clear();
369 void BLITstar::clearForwardVertexQueue()
371 std::vector<blitstar::KeyVertexPair> forwardQueue;
373 for (
const auto &element : forwardQueue)
375 element.second->resetForwardVertexQueuePointer();
377 forwardVertexQueue_.
clear();
379 void BLITstar::informAboutNewSolution()
const
381 OMPL_INFORM(
"%s (%u iterations): Found a new exact solution of cost %.4f. Sampled a total of %u states, %u "
382 "of which were valid samples (%.1f \%). Processed %u edges, %u of which were collision checked "
383 "(%.1f \%). The forward search tree has %u vertices, %u of which are start states. The reverse "
384 "search tree has %u vertices, %u of which are goal states.",
385 name_.c_str(), numIterations_, solutionCost_.
value(), graph_.getNumberOfSampledStates(),
386 graph_.getNumberOfValidSamples(),
387 graph_.getNumberOfSampledStates() == 0u ?
389 100.0 * (
static_cast<double>(graph_.getNumberOfValidSamples()) /
390 static_cast<double>(graph_.getNumberOfSampledStates())),
391 numProcessedEdges_, numEdgeCollisionChecks_,
392 numProcessedEdges_ == 0u ? 0.0 :
393 100.0 * (
static_cast<float>(numEdgeCollisionChecks_) /
394 static_cast<float>(numProcessedEdges_)),
395 countNumVerticesInForwardTree(), graph_.getStartVertices().size(),
396 countNumVerticesInReverseTree(), graph_.getGoalVertices().size());
405 OMPL_INFORM(
"%s (%u iterations): Found an exact solution of cost %.4f.",
name_.c_str(),
406 numIterations_, solutionCost_.value());
411 OMPL_INFORM(
"%s (%u iterations): Did not find an exact solution, but found an approximate "
413 "of cost %.4f which is %.4f away from a goal (in cost space).",
414 name_.c_str(), numIterations_, approximateSolutionCost_.value(),
415 approximateSolutionCostToGoal_.value());
420 if (trackApproximateSolutions_)
422 OMPL_INFORM(
"%s (%u iterations): Did not find any solution.",
name_.c_str(), numIterations_);
426 OMPL_INFORM(
"%s (%u iterations): Did not find an exact solution, and tracking approximate "
427 "solutions is disabled.",
428 name_.c_str(), numIterations_);
441 OMPL_INFORM(
"%s (%u iterations): Unable to solve the given planning problem.",
name_.c_str(),
447 "%s (%u iterations): Sampled a total of %u states, %u of which were valid samples (%.1f \%). "
448 "Processed %u edges, %u of which were collision checked (%.1f \%). The forward search tree "
449 "has %u vertices. The reverse search tree has %u vertices.",
450 name_.c_str(), numIterations_, graph_.getNumberOfSampledStates(), graph_.getNumberOfValidSamples(),
451 graph_.getNumberOfSampledStates() == 0u ?
453 100.0 * (
static_cast<double>(graph_.getNumberOfValidSamples()) /
454 static_cast<double>(graph_.getNumberOfSampledStates())),
455 numProcessedEdges_, numEdgeCollisionChecks_,
456 numProcessedEdges_ == 0u ?
458 100.0 * (
static_cast<float>(numEdgeCollisionChecks_) /
static_cast<float>(numProcessedEdges_)),
459 countNumVerticesInForwardTree(), countNumVerticesInReverseTree());
462 std::size_t BLITstar::countNumVerticesInReverseTree()
const
464 std::size_t numVerticesInReverseTree = 0u;
465 auto vertices = graph_.getVertices();
466 for (
const auto &vertex : vertices)
468 if (graph_.isGoal(vertex) || vertex->hasReverseParent())
470 ++numVerticesInReverseTree;
473 return numVerticesInReverseTree;
476 std::size_t BLITstar::countNumVerticesInForwardTree()
const
478 std::size_t numVerticesInForwardTree = 0u;
479 auto vertices = graph_.getVertices();
480 for (
const auto &vertex : vertices)
482 if (graph_.isStart(vertex) || vertex->hasForwardParent())
484 ++numVerticesInForwardTree;
487 return numVerticesInForwardTree;
490 void BLITstar::insertStartVerticesInForWardVertexQueue()
492 for (
const auto &start : graph_.getStartVertices())
495 start->setCostToComeFromStart(objective_->identityCost());
496 start->setCostToComeFromGoal(objective_->infiniteCost());
498 start->setLowerCostBoundToStart(objective_->identityCost());
499 start->setLowerCostBoundToGoal(lowerboundToGoal(start));
501 start->setStartVertex();
502 start->resetForwardExpanded();
503 start->setForwardId(forwardId_);
505 blitstar::KeyVertexPair element({start->getLowerCostBoundToGoal(), objective_->identityCost()}, start);
507 auto forwardQueuePointer = forwardVertexQueue_.insert(element);
508 start->setForwardVertexQueuePointer(forwardQueuePointer);
514 for (
const auto &goal : graph_.getGoalVertices())
517 goal->setCostToComeFromGoal(objective_->identityCost());
518 goal->setCostToComeFromStart(objective_->infiniteCost());
519 goal->setLowerCostBoundToGoal(objective_->identityCost());
520 goal->setLowerCostBoundToStart(lowerboundToStart(goal));
521 goal->resetReverseExpanded();
522 goal->setGoalVertex();
523 goal->setReverseId(reverseId_);
525 blitstar::KeyVertexPair element({goal->getLowerCostBoundToStart(), objective_->identityCost()}, goal);
527 auto reverseQueuePointer = reverseVertexQueue_.insert(element);
528 goal->setReverseVertexQueuePointer(reverseQueuePointer);
534 if (betterThan(curMin_, minimalneighbor_))
536 minimalneighbor_ = curMin_;
537 bestNeighbor_ = neighbor;
542 ompl::base::Cost f_value = objective_->combineCosts(costToCome, costToGoal);
546 void BLITstar::insertOrUpdateInReverseVertexQueue(
const std::shared_ptr<blitstar::Vertex> &vertex,
550 auto element = vertex->getReverseVertexQueuePointer();
554 element->data.first = computeEstimatedPathCosts(CostToCome, CostToGoal);
555 reverseVertexQueue_.
update(element);
559 std::pair<std::array<ompl::base::Cost, 2u>, std::shared_ptr<Vertex>> element(
560 computeEstimatedPathCosts(CostToCome, CostToGoal), vertex);
562 auto backwardQueuePointer = reverseVertexQueue_.
insert(element);
563 vertex->setReverseVertexQueuePointer(backwardQueuePointer);
566 bestNeighbor(CostToCome, CostToGoal, vertex->getId());
569 bool BLITstar::NeedMoreSamples()
571 return isVertexEmpty_ ? true :
false;
576 bool found_validity =
true;
577 forwardInvalid_ =
false;
578 ForwardPathValidityChecking(vertex, found_validity);
579 reverseInvalid_ =
false;
580 ReversePathValidityChecking(vertex, found_validity);
584 clearForwardVertexQueue();
585 insertStartVerticesInForWardVertexQueue();
593 return found_validity;
595 void BLITstar::ForwardPathValidityChecking(std::shared_ptr<Vertex> &vertex,
bool &validity)
597 std::shared_ptr<Vertex> tar_ = vertex;
598 std::vector<std::shared_ptr<Vertex>> reversePath;
599 while (!graph_.isStart(tar_))
601 std::shared_ptr<Vertex> src_ = tar_->getForwardParent();
602 reversePath.emplace_back(tar_);
603 bool valid_edge =
false;
604 if (!tar_->hasForwardParent())
606 forwardInvalid_ = !(validity =
false);
610 if (!(valid_edge = CCD(make_pair(src_, tar_))))
612 forwardInvalid_ = !(validity =
false);
613 resetForwardParentAndRemeberTheVertex(tar_, src_);
614 tar_->resetReverseEdgeParent();
618 src_->setReverseValidParent(tar_, tar_->getEdgeCostFromForwardParent());
624 void BLITstar::ReversePathValidityChecking(std::shared_ptr<Vertex> &vertex,
bool &validity)
626 std::shared_ptr<Vertex> tar_ = vertex;
627 std::vector<std::shared_ptr<Vertex>> reversePath;
628 while (!graph_.isGoal(tar_))
630 reversePath.emplace_back(tar_);
631 std::shared_ptr<Vertex> src_ = tar_->getReverseParent();
632 bool valid_edge =
false;
633 if (!tar_->hasReverseParent())
635 reverseInvalid_ = !(validity =
false);
638 if (!(valid_edge = CCD(make_pair(tar_, src_))))
640 reverseInvalid_ = !(validity =
false);
641 resetReverseParentAndRemeberTheVertex(tar_, src_);
642 tar_->resetForwardEdgeParent();
646 src_->setForwardValidParent(tar_, tar_->getEdgeCostFromReverseParent());
654 vertex->resetForwardParent();
655 resetForwardValue(vertex);
658 void BLITstar::resetForwardValue(
const std::shared_ptr<Vertex> &vertex)
660 vertex->resetForwardExpanded();
661 vertex->resetForwardVertexQueuePointer();
662 vertex->setCostToComeFromStart(objective_->infiniteCost());
665 void BLITstar::resetForwardParentAndRemeberTheVertex(
const std::shared_ptr<Vertex> &child,
666 const std::shared_ptr<Vertex> &parent)
668 child->setNearObstacle();
669 parent->setNearObstacle();
671 child->setForwardInvalid();
672 parent->removeFromForwardChildren(child->getId());
675 void BLITstar::resetReverseParentInformation(
const std::shared_ptr<blitstar::Vertex> &vertex)
677 vertex->resetReverseParent();
683 vertex->resetReverseExpanded();
684 vertex->resetReverseVertexQueuePointer();
685 vertex->setCostToComeFromGoal(objective_->infiniteCost());
688 void BLITstar::resetReverseParentAndRemeberTheVertex(
const std::shared_ptr<Vertex> &child,
689 const std::shared_ptr<Vertex> &parent)
691 child->setNearObstacle();
692 parent->setNearObstacle();
693 child->setReverseInvalid();
694 resetReverseParentInformation(child);
695 parent->removeFromReverseChildren(child->getId());
703 if (!found_meeting_ && betterThan(fmin_, C_curr))
708 if (betterThan(C_curr, solutionCost_) && !
PathValidity(V_meet.second))
710 C_curr = solutionCost_;
711 BestVertex_->resetMeet();
712 V_meet.second->resetMeet();
713 start_scratch_ =
true;
714 return (found_meeting_ =
false);
716 return (find_solution_ =
true);
722 if (NeedMoreSamples() && graph_.addSamples(batchSize_, terminationCondition, need_Prune_))
725 insertStartVerticesInForWardVertexQueue();
729 forwardId_ = reverseId_ = 0u;
730 isVertexEmpty_ = find_solution_ =
false;
733 bool forwardDirection_ =
false;
746 if (!terminateSearch_)
748 if (forwardDirection_)
750 BestVertex_->setForwardExpanded();
755 BestVertex_->setReverseExpanded();
756 ReverseLazySearch(BestVertex_);
761 if (find_solution_ && betterThan(C_curr, solutionCost_))
764 solutionCost_ = C_curr;
765 path_ = getPathToVertex(V_meet.second);
768 clearForwardVertexQueue();
769 need_Prune_ = !searchExhausted_;
770 found_meeting_ = !(isVertexEmpty_ =
true);
776 bool BLITstar::betterThan(
const ompl::base::Cost &cost1,
const ompl::base::Cost &cost2)
778 return cost1.
value() + 0.000001 < cost2.
value();
781 bool BLITstar::largerThan(
const ompl::base::Cost &cost1,
const ompl::base::Cost &cost2)
783 return cost1.
value() > cost2.
value() + 0.000001;
786 bool BLITstar::isVertexBetter(
const blitstar::KeyVertexPair &lhs,
const blitstar::KeyVertexPair &rhs)
const
789 return std::lexicographical_compare(lhs.first.cbegin(), lhs.first.cend(), rhs.first.cbegin(),
790 rhs.first.cend(), [
this](
const auto &a,
const auto &b)
791 { return objective_->isCostBetterThan(a, b); });
797 minimalneighbor_ = objective_->infiniteCost();
799 for (
const auto &child : vertex->getForwardChildren())
803 if ((!iSolution_ || vertex->nearObstacle() || child->nearObstacle()) && !
SCD(make_pair(vertex, child)))
805 resetForwardParentAndRemeberTheVertex(child, vertex);
810 auto edgeCost = child->getEdgeCostFromForwardParent();
811 auto gValue = objective_->combineCosts(vertex->getCostToComeFromStart(), edgeCost);
812 if (iSolution_ && !child->hasReverseParent() &&
813 largerThan(objective_->combineCosts(gValue, gValue), solutionCost_))
818 auto hValue = child->getLowerCostBoundToGoal();
819 child->setCostToComeFromStart(gValue);
820 gValue = child->getCostToComeFromStart();
822 updateForwardCost(child, gValue, hValue);
827 bool Potential_collide_ =
false;
828 for (
const auto &neighbor : graph_.getNeighbors(vertex))
830 if (neighbor->getId() == vertex->getId())
832 if (iSolution_ && !vertex->nearObstacle() && neighbor->nearObstacle())
834 Potential_collide_ =
true;
838 if (forwardInvalid_ && neighbor->getForwardId() != forwardId_)
840 neighbor->setCostToComeFromStart(objective_->infiniteCost());
841 neighbor->resetForwardExpanded();
843 if (!neighbor->isForwardExpanded())
846 if (iSolution_ && vertex->hasReverseEdgeParent() &&
847 vertex->getReverseEdgeParent()->getId() == neighbor->getId())
852 if (neighbor->hasForwardParent() && neighbor->getForwardParent()->getId() == vertex->getId())
857 if (neighbor->isBlacklistedAsChild(vertex) || vertex->isBlacklistedAsChild(neighbor))
862 if (vertex->isStart() && neighbor->isGoal())
869 auto gValue = (neighbor->hasForwardParent()) ? neighbor->getCostToComeFromStart() :
870 objective_->infiniteCost();
871 auto edgeCost = objective_->motionCostHeuristic(neighbor->getState(), vertex->getState());
872 auto est_gValue = objective_->combineCosts(vertex->getCostToComeFromStart(), edgeCost);
876 if (betterThan(est_gValue, gValue) && !neighbor->isGoal())
878 neighbor->setForwardId(forwardId_);
879 bool fValid_ =
false, rValid_ =
false, supposeMeet =
false;
882 if (!iSolution_ && !
SCD(make_pair(vertex, neighbor)))
884 vertex->setNearObstacle();
885 neighbor->setNearObstacle();
886 neighbor->setForwardInvalid();
887 neighbor->resetForwardExpanded();
891 bool startCollid_ = goalCloseToStart_ && vertex->isStart();
892 if (startCollid_ || Potential_collide_ || vertex->nearObstacle() || neighbor->nearObstacle())
894 if (!(fValid_ =
SCD(make_pair(vertex, neighbor))) ||
895 (neighbor->forwardInvalid() && !CCD(make_pair(vertex, neighbor))))
897 neighbor->setNearObstacle();
898 vertex->setNearObstacle();
899 neighbor->setForwardInvalid();
900 neighbor->resetForwardExpanded();
905 neighbor->setNearObstacle();
910 neighbor->setCostToComeFromStart(est_gValue);
911 neighbor->setForwardVertexParent(vertex, edgeCost);
912 vertex->addToForwardChildren(neighbor);
913 auto hValue = neighbor->getLowerCostBoundToGoal();
914 auto getReversepointer = neighbor->getReverseVertexQueuePointer();
916 bool onReverseTree = !(neighbor->hasReverseParent() && neighbor->getReverseId() != reverseId_);
923 if (onReverseTree && (getReversepointer || (neighbor->hasReverseParent())))
925 keyEdgePair fEdge = make_pair(vertex, neighbor);
926 keyEdgePair rEdge = make_pair(neighbor, neighbor->getReverseParent());
931 fValid_ =
SCD(fEdge);
933 rValid_ =
SCD(rEdge);
938 if ((fValid_ && rValid_) || iSolution_)
941 objective_->combineCosts(est_gValue, neighbor->getCostToComeFromGoal());
944 if (betterThan(Totalcost, C_curr) &&
945 (iSolution_ || ((fValid_ = CCD(fEdge)) && (rValid_ = CCD(rEdge)))))
948 neighbor->getCostToComeFromGoal());
950 vertex->meetVertex());
956 if (!iSolution_ && (!fValid_ || !rValid_))
958 neighbor->setNearObstacle();
959 auto backwardParent = neighbor->getReverseParent();
962 resetForwardParentAndRemeberTheVertex(neighbor, vertex);
966 updateCostToGo(est_gValue, hValue, hValue,
false);
968 vertex->meetVertex());
972 resetReverseParentAndRemeberTheVertex(neighbor, backwardParent);
979 updateCostToGo(est_gValue, hValue, hValue,
false);
980 if (iSolution_ && !neighbor->hasReverseParent() && largerThan(hValue, solutionCost_))
985 vertex->meetVertex() && !supposeMeet);
991 found_meeting_ = (vertex->meetVertex() && betterThan(minimalneighbor_, C_curr)) ? true :
false;
994 if (iSolution_ && vertex->hasReverseEdgeParent())
996 auto reverseParent = vertex->getReverseEdgeParent();
997 auto edgeCost = vertex->getValidReverseEdgeCost();
998 auto curValue = objective_->combineCosts(vertex->getCostToComeFromStart(), edgeCost);
999 auto hValue = reverseParent->getLowerCostBoundToGoal();
1000 if (betterThan(curValue, reverseParent->getCostToComeFromStart()))
1002 reverseParent->setCostToComeFromStart(curValue);
1003 reverseParent->setForwardVertexParent(vertex, edgeCost);
1004 vertex->resetReverseEdgeParent();
1005 vertex->addToForwardChildren(reverseParent);
1007 updateForwardCost(reverseParent, reverseParent->getCostToComeFromStart(), hValue);
1009 vertex->meetVertex());
1019 V_meet.second->resetMeet();
1022 V_meet = make_pair(C_curr = meetCost, vertex);
1023 updateCostToGo(costToCome, costToGo, costFromOriginal,
true);
1028 if (betterThan(costToGo, costToCome))
1030 costToGo = costToCome;
1032 if (meetOnPath && betterThan(costFromOriginal, costToGo))
1034 costToGo = costFromOriginal;
1038 void BLITstar::updateForwardCost(
const std::shared_ptr<blitstar::Vertex> &vertex, ompl::base::Cost costToCome,
1039 ompl::base::Cost &costToGo)
1041 vertex->resetForwardExpanded();
1042 vertex->setForwardId(forwardId_);
1043 if (vertex->hasReverseParent() && vertex->getReverseId() == reverseId_)
1045 auto bettersolution_ =
1046 objective_->combineCosts(vertex->getCostToComeFromGoal(), vertex->getCostToComeFromStart());
1047 if (betterThan(bettersolution_, C_curr))
1050 vertex->getCostToComeFromGoal());
1054 updateCostToGo(costToCome, costToGo, vertex->getCostToComeFromGoal(),
true);
1059 updateCostToGo(costToCome, costToGo, costToGo,
false);
1066 vertex->resetReverseExpanded();
1067 vertex->setReverseId(reverseId_);
1068 if (vertex->hasForwardParent() && vertex->getForwardId() == forwardId_)
1070 auto bettersolution_ =
1071 objective_->combineCosts(vertex->getCostToComeFromGoal(), vertex->getCostToComeFromStart());
1072 if (betterThan(bettersolution_, C_curr))
1075 vertex->getCostToComeFromStart());
1079 updateCostToGo(costToCome, costToGo, vertex->getCostToComeFromStart(),
true);
1084 updateCostToGo(costToCome, costToGo, costToGo,
false);
1089 const std::shared_ptr<Vertex> &goal)
1091 goalCloseToStart_ =
true;
1092 if (CCD(make_pair(start, goal)))
1094 solutionCost_ = objective_->motionCost(start->getState(), goal->getState());
1095 start->setReverseVertexParent(goal, solutionCost_);
1096 goal->setForwardVertexParent(start, solutionCost_);
1100 void BLITstar::ReverseLazySearch(
const std::shared_ptr<blitstar::Vertex> &vertex)
1102 minimalneighbor_ = objective_->infiniteCost();
1103 for (
const auto &child : vertex->getReverseChildren())
1105 if ((!iSolution_ || vertex->nearObstacle() || child->nearObstacle()) && !
SCD(make_pair(child, vertex)))
1107 resetReverseParentAndRemeberTheVertex(child, vertex);
1110 auto edgeCost = child->getEdgeCostFromReverseParent();
1111 auto gValue = objective_->combineCosts(vertex->getCostToComeFromGoal(), edgeCost);
1112 if (iSolution_ && !child->hasForwardParent() &&
1113 largerThan(objective_->combineCosts(gValue, gValue), solutionCost_))
1117 auto hValue = child->getLowerCostBoundToStart();
1118 child->setCostToComeFromGoal(gValue);
1119 gValue = child->getCostToComeFromGoal();
1121 insertOrUpdateInReverseVertexQueue(child, gValue, hValue, vertex->meetVertex());
1123 bool Potential_collide_ =
false;
1124 for (
const auto &neighbor : graph_.getNeighbors(vertex))
1126 if (neighbor->getId() == vertex->getId())
1130 if (iSolution_ && !vertex->nearObstacle() && neighbor->nearObstacle())
1132 Potential_collide_ =
true;
1134 if (reverseInvalid_ && neighbor->getReverseId() != reverseId_)
1136 neighbor->resetReverseExpanded();
1137 neighbor->setCostToComeFromGoal(objective_->infiniteCost());
1139 if (!neighbor->isReverseExpanded())
1141 if (iSolution_ && vertex->hasForwardEdgeParent() &&
1142 neighbor->getId() == vertex->getForwardEdgeParent()->getId())
1146 if (vertex->isGoal() && neighbor->isStart())
1151 if (neighbor->hasReverseParent() && neighbor->getReverseParent()->getId() == vertex->getId())
1156 if (neighbor->isBlacklistedAsChild(vertex) || vertex->isBlacklistedAsChild(neighbor))
1161 neighbor->hasReverseParent() ? neighbor->getCostToComeFromGoal() : objective_->infiniteCost();
1162 auto edgeCost = objective_->motionCostHeuristic(neighbor->getState(), vertex->getState());
1163 auto est_gValue = objective_->combineCosts(vertex->getCostToComeFromGoal(), edgeCost);
1164 if (betterThan(est_gValue, gValue) && !neighbor->isStart())
1166 neighbor->setReverseId(reverseId_);
1167 if (!iSolution_ && !
SCD(make_pair(neighbor, vertex)))
1169 vertex->setNearObstacle();
1170 neighbor->setNearObstacle();
1171 neighbor->setReverseInvalid();
1172 neighbor->resetReverseExpanded();
1175 bool fValid_ =
false, rValid_ =
false, supposeMeet =
false;
1176 bool goalCollid_ = goalCloseToStart_ && vertex->isGoal();
1177 if (goalCollid_ || Potential_collide_ || vertex->nearObstacle() || neighbor->nearObstacle())
1179 if (!(rValid_ =
SCD(make_pair(neighbor, vertex))) ||
1180 (neighbor->reverseInvalid() && !CCD(make_pair(neighbor, vertex))))
1182 neighbor->setNearObstacle();
1183 vertex->setNearObstacle();
1184 neighbor->setReverseInvalid();
1185 neighbor->resetReverseExpanded();
1190 neighbor->setNearObstacle();
1193 neighbor->setCostToComeFromGoal(est_gValue);
1194 neighbor->setReverseVertexParent(vertex, edgeCost);
1195 vertex->addToReverseChildren(neighbor);
1196 auto hValue = neighbor->getLowerCostBoundToStart();
1197 auto getForwardpointer = neighbor->getForwardVertexQueuePointer();
1198 bool onForwardTree = !(neighbor->hasForwardParent() && neighbor->getForwardId() != forwardId_);
1201 resetForwardValue(neighbor);
1204 if (onForwardTree && (getForwardpointer || neighbor->hasForwardParent()))
1206 keyEdgePair rEdge = make_pair(neighbor, vertex);
1207 keyEdgePair fEdge = make_pair(neighbor->getForwardParent(), neighbor);
1212 rValid_ =
SCD(rEdge);
1214 fValid_ =
SCD(fEdge);
1216 if (iSolution_ || (fValid_ && rValid_))
1219 objective_->combineCosts(est_gValue, neighbor->getCostToComeFromStart());
1222 if (betterThan(Totalcost, C_curr) &&
1223 (iSolution_ || ((fValid_ = CCD(fEdge)) && (rValid_ = CCD(rEdge)))))
1226 neighbor->getCostToComeFromStart());
1227 insertOrUpdateInReverseVertexQueue(neighbor, est_gValue, hValue,
1228 vertex->meetVertex());
1232 if (!iSolution_ && (!fValid_ || !rValid_))
1234 neighbor->setNearObstacle();
1235 auto forwardParent = neighbor->getForwardParent();
1238 resetForwardParentAndRemeberTheVertex(neighbor, forwardParent);
1243 resetReverseParentAndRemeberTheVertex(neighbor, vertex);
1247 updateCostToGo(est_gValue, hValue, hValue,
false);
1248 insertOrUpdateInReverseVertexQueue(neighbor, est_gValue, hValue,
1249 vertex->meetVertex());
1254 updateCostToGo(est_gValue, hValue, hValue,
false);
1255 if (iSolution_ && !neighbor->hasForwardParent() && largerThan(hValue, solutionCost_))
1259 insertOrUpdateInReverseVertexQueue(neighbor, est_gValue, hValue,
1260 vertex->meetVertex() && !supposeMeet);
1264 found_meeting_ = (vertex->meetVertex() && betterThan(minimalneighbor_, C_curr)) ? true :
false;
1265 if (iSolution_ && vertex->hasForwardEdgeParent())
1267 auto forwardParent = vertex->getForwardEdgeParent();
1268 auto edgeCost = vertex->getValidForwardEdgeCost();
1269 auto curValue = objective_->combineCosts(vertex->getCostToComeFromGoal(), edgeCost);
1270 auto hValue = forwardParent->getLowerCostBoundToStart();
1271 if (betterThan(curValue, forwardParent->getCostToComeFromGoal()))
1273 forwardParent->setCostToComeFromGoal(curValue);
1274 vertex->resetForwardEdgeParent();
1275 forwardParent->setReverseVertexParent(vertex, edgeCost);
1276 vertex->addToReverseChildren(forwardParent);
1278 updateReverseCost(forwardParent, forwardParent->getCostToComeFromGoal(), hValue);
1279 insertOrUpdateInReverseVertexQueue(forwardParent, forwardParent->getCostToComeFromGoal(), hValue,
1280 vertex->meetVertex());
1289 auto element = vertex->getForwardVertexQueuePointer();
1293 element->data.first = computeEstimatedPathCosts(CostToCome, CostToGoal);
1294 forwardVertexQueue_.update(element);
1298 std::pair<std::array<ompl::base::Cost, 2u>, std::shared_ptr<Vertex>> element(
1299 computeEstimatedPathCosts(CostToCome, CostToGoal), vertex);
1301 auto forwardQueuePointer = forwardVertexQueue_.insert(element);
1302 vertex->setForwardVertexQueuePointer(forwardQueuePointer);
1305 bestNeighbor(CostToCome, CostToGoal, vertex->getId());
1308 std::shared_ptr<ompl::geometric::PathGeometric>
1309 BLITstar::getPathToVertex(
const std::shared_ptr<Vertex> &vertex)
const
1312 std::vector<std::shared_ptr<Vertex>> reversePath;
1313 auto current = vertex;
1314 while (!graph_.isStart(current))
1316 reversePath.emplace_back(current);
1317 current = current->getForwardParent();
1319 reversePath.emplace_back(current);
1322 auto path = std::make_shared<ompl::geometric::PathGeometric>(Planner::si_);
1323 for (
const auto &vertex_ : boost::adaptors::reverse(reversePath))
1325 path->append(vertex_->getState());
1327 reversePath.clear();
1330 while (!graph_.isGoal(current))
1332 reversePath.emplace_back(current);
1333 current = current->getReverseParent();
1335 reversePath.emplace_back(current);
1336 for (
const auto &vertex_ : reversePath)
1338 if (vertex_->getId() != vertex->getId())
1340 path->append(vertex_->getState());
1346 std::array<ompl::base::Cost, 3u> BLITstar::computeEstimatedPathCosts(ompl::base::Cost CostToStart,
1347 ompl::base::Cost CostToGoal,
1348 ompl::base::Cost motionCost)
const
1351 return {objective_->combineCosts(CostToStart, CostToGoal), CostToStart, motionCost};
1354 std::array<ompl::base::Cost, 2u> BLITstar::computeEstimatedPathCosts(ompl::base::Cost CostToStart,
1355 ompl::base::Cost CostToGoal)
const
1358 return {objective_->combineCosts(CostToStart, CostToGoal), CostToStart};
1361 void BLITstar::updateExactSolution()
1364 ompl::base::PlannerSolution solution(path_);
1365 solution.setPlannerName(
name_);
1368 solution.setOptimized(objective_, solutionCost_, objective_->isSatisfied(solutionCost_));
1371 pdef_->addSolutionPath(solution);
1374 informAboutNewSolution();
1379 updateExactSolution();
1381 if (objective_->isFinite(solutionCost_))
1385 else if (trackApproximateSolutions_)
1395 ompl::base::Cost BLITstar::lowerboundToStart(
const std::shared_ptr<Vertex> &vertex)
const
1397 const auto &start = graph_.getStartVertices()[0u];
1398 return objective_->motionCostHeuristic(vertex->getState(), start->getState());
1401 ompl::base::Cost BLITstar::lowerboundToGoal(
const std::shared_ptr<Vertex> &vertex)
const
1403 const auto &goal = graph_.getGoalVertices()[0u];
1404 return objective_->motionCostHeuristic(vertex->getState(), goal->getState());
1409 searchExhausted_ = start_scratch_ = found_meeting_ =
false;
1416 if (forwardVertexQueue_.empty() || reverseVertexQueue_.empty())
1418 C_curr = solutionCost_;
1419 return (isVertexEmpty_ = (searchExhausted_ =
true));
1422 auto forwardVertex_ = forwardVertexQueue_.top()->data.second;
1423 auto backwardVertex_ = reverseVertexQueue_.top()->data.second;
1424 ForwardCost = forwardVertexQueue_.top()->data.first[0u];
1425 ReverseCost = reverseVertexQueue_.top()->data.first[0u];
1428 if (forwardInvalid_ && forwardVertex_->getForwardId() != forwardId_)
1430 forwardVertexQueue_.pop();
1431 resetForwardValue(forwardVertex_);
1435 if (reverseInvalid_ && backwardVertex_->getReverseId() != reverseId_)
1437 reverseVertexQueue_.pop();
1443 if (betterThan(ForwardCost, ReverseCost))
1445 BestVertex_ = forwardVertexQueue_.top()->data.second;
1446 forwardVertexQueue_.pop();
1447 BestVertex_->resetForwardVertexQueuePointer();
1448 fmin_ = ForwardCost;
1449 if (BestVertex_->isForwardExpanded())
1453 forwardDirection_ =
true;
1457 BestVertex_ = reverseVertexQueue_.top()->data.second;
1458 reverseVertexQueue_.pop();
1459 BestVertex_->resetReverseVertexQueuePointer();
1460 fmin_ = ReverseCost;
1461 if (BestVertex_->isReverseExpanded())
1474 bool BLITstar::CCD(
const keyEdgePair &edge)
1482 auto parent = edge.first;
1483 auto child = edge.second;
1485 if (parent->isWhitelistedAsChild(child))
1491 if (child->isBlacklistedAsChild(parent))
1497 const std::size_t fullSegmentCount = space_->validSegmentCount(parent->getState(), child->getState());
1501 const auto segmentCount = std::min(numChecks + 1u, fullSegmentCount);
1504 std::size_t currentCheck = 1u;
1507 const std::size_t performedChecks = child->getIncomingCollisionCheckResolution(parent->getId());
1509 std::queue<std::pair<std::size_t, std::size_t>> indices;
1510 indices.emplace(1u, numChecks);
1513 while (!indices.empty())
1516 const auto current = indices.front();
1519 auto mid = (current.first + current.second) / 2;
1521 if (currentCheck > performedChecks)
1523 space_->interpolate(parent->getState(), child->getState(),
1524 static_cast<double>(mid) /
static_cast<double>(segmentCount), detectionState_);
1525 if (!spaceInformation_->isValid(detectionState_))
1528 parent->blacklistAsChild(child);
1529 child->blacklistAsChild(parent);
1532 if (!sparseCheck && currentCheck > numSparseCollisionChecksCurrentLevel_)
1534 numSparseCollisionChecksCurrentLevel_ = currentCheck + 1u;
1544 if (current.first < mid)
1546 indices.emplace(current.first, mid - 1u);
1549 if (current.second > mid)
1551 indices.emplace(mid + 1u, current.second);
1560 parent->setIncomingCollisionCheckResolution(child->getId(), currentCheck - 1u);
1561 child->setIncomingCollisionCheckResolution(parent->getId(), currentCheck - 1u);
1564 if (segmentCount == fullSegmentCount)
1566 ++numCollisionCheckedEdges_;
1567 parent->whitelistAsChild(child);
1568 child->whitelistAsChild(parent);
Element * insert(const _T &data)
Add a new element.
void update(Element *element)
Update an element in the heap.
void getContent(std::vector< _T > &content) const
Get the data stored in this heap.
void clear()
Clear the heap.
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
double value() const
The value of the cost.
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,...
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...
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...
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.
ProblemDefinitionPtr pdef_
The user set problem definition.
std::string name_
The name of this planner.
SpaceInformationPtr si_
The space information for which planning is done.
virtual void checkValidity()
Check to see if the planner is in a working state (setup has been called, a goal was set,...
bool setup_
Flag indicating whether setup() has been called.
virtual unsigned int validSegmentCount(const State *state1, const State *state2) const
Count how many segments of the "longest valid length" fit on the motion from state1 to state2.
bool getUseKNearest() const
Get whether to use a k-nearest RGG connection model. If false, BLIT* uses an r-disc model.
ompl::base::PlannerStatus solve(const ompl::base::PlannerTerminationCondition &terminationCondition) override
Solves a motion planning problem.
void enablePruning(bool prune)
Set whether pruning is enabled or not.
void setup() override
Additional setup that can only be done once a problem definition is set.
void EvaluateValidityStartAndToGoal(const std::shared_ptr< blitstar::Vertex > &start, const std::shared_ptr< blitstar::Vertex > &goal)
Checking the collision detection between start and goal vertices.
void resetReverseValue(const std::shared_ptr< blitstar::Vertex > &vertex)
Reset a vertex's value.
bool PathValidity(std::shared_ptr< blitstar::Vertex > &vertex)
Checking the validity of a path from each direction.
bool isPruningEnabled() const
Get whether pruning is enabled or not.
void ForwardLazySearch(const std::shared_ptr< blitstar::Vertex > &vertex)
Forward and Reverse Search.
void updateReverseCost(const std::shared_ptr< blitstar::Vertex > &vertex, ompl::base::Cost costToCome, ompl::base::Cost &costToGo)
Refine heuristics on-the-fly.
void setUseKNearest(bool useKNearest)
Set whether to use a k-nearest RGG connection model. If false, BLIT* uses an r-disc model.
void clear() override
Clears the algorithm's internal state.
void resetForwardParentInformation(const std::shared_ptr< blitstar::Vertex > &vertex)
Reset parent vertex's information.
bool SelectExpandState(bool &forward)
Select the vertex with minimal priority on both trees.
unsigned int getMaxNumberOfGoals() const
Get the maximum number of goals BLIT* will sample from sampleable goal regions.
void insertGoalVerticesInReverseVertexQueue()
Insert start and goal vertices into the queues.
bool isValidAtResolution(const blitstar::keyEdgePair &edge, std::size_t numChecks, bool sparseCheck)
Checking the collision detection.
ompl::base::PlannerStatus::StatusType ensureStartAndGoalStates(const ompl::base::PlannerTerminationCondition &terminationCondition)
Checks whether the problem is successfully setup.
void lookingForBestNeighbor(ompl::base::Cost curMin_, size_t neighbor)
Look for a neighbor with the minimal priority.
std::size_t getBatchSize() const
Get the batch size.
void setBatchSize(std::size_t batchSize)
Set the batch size.
BLITstar(const ompl::base::SpaceInformationPtr &spaceInformation)
Constructs a BLIT*.
bool SCD(const blitstar::keyEdgePair &edge)
Above references inherit from BLIT*.
void clearReverseVertexQueue()
Empty the queues.
double getRewireFactor() const
Get the rewire factor of the RGG graph.
void getPlannerData(base::PlannerData &data) const override
Get the planner data.
void setMaxNumberOfGoals(unsigned int numberOfGoals)
Set the maximum number of goals BLIT* will sample from sampleable goal regions.
void setRewireFactor(double rewireFactor)
Set the rewire factor of the RGG graph.
ompl::base::PlannerStatus::StatusType ensureSetup()
Checks whether the planner is successfully setup.
void insertOrUpdateInForwardVertexQueue(const std::shared_ptr< blitstar::Vertex > &vertex, ompl::base::Cost CostToCome, ompl::base::Cost CostToGoal, bool couldMeet)
Inserts or updates a vertex in the reverse queue.
bool terminateSearch()
Ensuring meet-in-the-middle and optimality to terminate the current search.
~BLITstar()
Destructs a BLIT*.
void updateBestSolutionFoundSoFar(const std::shared_ptr< blitstar::Vertex > &vertex, ompl::base::Cost meetCost, ompl::base::Cost costToCome, ompl::base::Cost &costToGo, ompl::base::Cost costFromOri)
Improve the current solution.
#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.