IntegratedQueue.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2014, University of Toronto
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the University of Toronto nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 /* Authors: Jonathan Gammell */
36 
37 //My definition:
38 #include "ompl/geometric/planners/bitstar/datastructures/IntegratedQueue.h"
39 
40 //OMPL:
41 //For exceptions:
42 #include "ompl/util/Exception.h"
43 
44 namespace ompl
45 {
46  namespace geometric
47  {
49  //Public functions:
50  BITstar::IntegratedQueue::IntegratedQueue(const ompl::base::OptimizationObjectivePtr& opt, const DistanceFunc& distanceFunc, const NeighbourhoodFunc& nearSamplesFunc, const NeighbourhoodFunc& nearVerticesFunc, const VertexHeuristicFunc& lowerBoundHeuristicVertex, const VertexHeuristicFunc& currentHeuristicVertex, const EdgeHeuristicFunc& lowerBoundHeuristicEdge, const EdgeHeuristicFunc& currentHeuristicEdge, const EdgeHeuristicFunc& currentHeuristicEdgeTarget)
51  : opt_(opt),
52  distanceFunc_(distanceFunc),
53  nearSamplesFunc_(nearSamplesFunc),
54  nearVerticesFunc_(nearVerticesFunc),
55  lowerBoundHeuristicVertexFunc_(lowerBoundHeuristicVertex),
56  currentHeuristicVertexFunc_(currentHeuristicVertex),
57  lowerBoundHeuristicEdgeFunc_(lowerBoundHeuristicEdge),
58  currentHeuristicEdgeFunc_(currentHeuristicEdge),
59  currentHeuristicEdgeTargetFunc_(currentHeuristicEdgeTarget),
60  delayRewiring_(true),
61  outgoingLookupTables_(true),
62  incomingLookupTables_(true),
63  vertexQueue_( std::bind(&BITstar::IntegratedQueue::vertexQueueComparison, this,
64  std::placeholders::_1, std::placeholders::_2) ), //This tells the vertexQueue_ to use the vertexQueueComparison for sorting
65  vertexToExpand_( vertexQueue_.begin() ),
66  edgeQueue_( std::bind(&BITstar::IntegratedQueue::edgeQueueComparison, this,
67  std::placeholders::_1, std::placeholders::_2) ), //This tells the edgeQueue_ to use the edgeQueueComparison for sorting
68  vertexIterLookup_(),
69  outgoingEdges_(),
70  incomingEdges_(),
71  resortVertices_(),
72  costThreshold_( std::numeric_limits<double>::infinity() ), //Purposeful gibberish
73  hasSolution_(false)
74  {
75  //Set the the cost threshold to infinity to start:
76  costThreshold_ = opt_->infiniteCost();
77  }
78 
79 
80 
81  BITstar::IntegratedQueue::~IntegratedQueue()
82  {
83  }
84 
85 
86 
88  {
89  //Insert the vertex:
90  this->vertexInsertHelper(newVertex, true);
91  }
92 
93 
94 
96  {
97  //Call my helper function:
98  this->edgeInsertHelper(newEdge, edgeQueue_.end());
99  }
100 
101 
102 
103  void BITstar::IntegratedQueue::eraseVertex(const VertexPtr& oldVertex, bool disconnectParent, const VertexPtrNNPtr& vertexNN, const VertexPtrNNPtr& freeStateNN, std::vector<VertexPtr>* recycledVertices)
104  {
105  //If requested, disconnect from parent, cascading cost updates:
106  if (disconnectParent == true)
107  {
108  this->disconnectParent(oldVertex, true);
109  }
110 
111  //Remove it from vertex queue and lookup, and edge queues (as requested):
112  this->vertexRemoveHelper(oldVertex, vertexNN, freeStateNN, recycledVertices, true);
113  }
114 
115 
116 
118  {
119  if (this->isEmpty() == true)
120  {
121  throw ompl::Exception("Attempted to access the first element in an empty IntegratedQueue.");
122  }
123 
124  //Update the queue:
125  this->updateQueue();
126 
127  //Return the front edge
128  return vertexQueue_.begin()->second;
129  }
130 
131 
132 
134  {
135  if (this->isEmpty() == true)
136  {
137  throw ompl::Exception("Attempted to access the first element in an empty IntegratedQueue.");
138  }
139 
140  //Update the queue:
141  this->updateQueue();
142 
143  //Return the front edge
144  return edgeQueue_.begin()->second;
145  }
146 
147 
148 
150  {
151  if (this->isEmpty() == true)
152  {
153  throw ompl::Exception("Attempted to access the first element in an empty IntegratedQueue.");
154  }
155 
156  //Update the queue:
157  this->updateQueue();
158 
159  //Return the front value
160  return vertexQueue_.begin()->first;
161  }
162 
163 
164 
166  {
167  if (this->isEmpty() == true)
168  {
169  throw ompl::Exception("Attempted to access the first element in an empty IntegratedQueue.");
170  }
171 
172  //Update the queue:
173  this->updateQueue();
174 
175  //Return the front value
176  return edgeQueue_.begin()->first;
177  }
178 
179 
180 
182  {
183  if (this->isEmpty() == true)
184  {
185  throw ompl::Exception("Attempted to pop an empty IntegratedQueue.");
186  }
187 
188  //Update the queue:
189  this->updateQueue();
190 
191  //Return the front:
192  *bestEdge = edgeQueue_.begin()->second;
193 
194  //Erase the edge:
195  this->edgeRemoveHelper(edgeQueue_.begin(), true, true);
196  }
197 
198 
199 
201  {
202  VertexPtrPair rval;
203 
204  this->popFrontEdge(&rval);
205 
206  return rval;
207  }
208 
209 
210 
212  {
213  hasSolution_ = true;
214  }
215 
216 
217 
219  {
220  costThreshold_ = costThreshold;
221  }
222 
223 
224 
226  {
227  return costThreshold_;
228  }
229 
230 
231 
233  {
234  if (edgeQueue_.empty() == false)
235  {
236  if (incomingLookupTables_ == true)
237  {
238  //Variable:
239  //The iterator to the vector of edges to the child:
240  VertexIdToEdgeQueueIterListUMap::iterator toDeleteIter;
241 
242  //Get the vector of iterators
243  toDeleteIter = incomingEdges_.find(cVertex->getId());
244 
245  //Make sure it was found before we start dereferencing it:
246  if (toDeleteIter != incomingEdges_.end())
247  {
248  //Iterate over the vector removing them from queue
249  for (EdgeQueueIterList::iterator listIter = toDeleteIter->second.begin(); listIter != toDeleteIter->second.end(); ++listIter)
250  {
251  //Erase the edge, removing it from the *other* lookup. No need to remove from this lookup, as that's being cleared:
252  this->edgeRemoveHelper(*listIter, false, true);
253  }
254 
255  //Clear the list:
256  toDeleteIter->second = EdgeQueueIterList();
257  }
258  //No else, why was this called?
259  }
260  else
261  {
262  throw ompl::Exception("Child lookup is not enabled for this instance of the container.");
263  }
264  }
265  //No else, nothing to remove_to
266  }
267 
268 
269 
271  {
272  if (edgeQueue_.empty() == false)
273  {
274  if (outgoingLookupTables_ == true)
275  {
276  //Variable:
277  //The iterator to the vector of edges from the parent:
278  VertexIdToEdgeQueueIterListUMap::iterator toDeleteIter;
279 
280  //Get the vector of iterators
281  toDeleteIter = outgoingEdges_.find(pVertex->getId());
282 
283  //Make sure it was found before we start dereferencing it:
284  if (toDeleteIter != outgoingEdges_.end())
285  {
286  //Iterate over the vector removing them from queue
287  for (EdgeQueueIterList::iterator listIter = toDeleteIter->second.begin(); listIter != toDeleteIter->second.end(); ++listIter)
288  {
289  //Erase the edge, removing it from the *other* lookup. No need to remove from this lookup, as that's being cleared:
290  this->edgeRemoveHelper(*listIter, true, false);
291  }
292 
293  //Clear the list:
294  toDeleteIter->second = EdgeQueueIterList();
295  }
296  //No else, why was this called?
297  }
298  else
299  {
300  throw ompl::Exception("Removing edges in the queue coming from a vertex requires parent vertex lookup, which is not enabled for this instance of the container.");
301  }
302  }
303  //No else, nothing to remove_from
304  }
305 
306 
307 
309  {
310  if (edgeQueue_.empty() == false)
311  {
312  if (incomingLookupTables_ == true)
313  {
314  //Variable:
315  //The iterator to the key,value of the child-lookup map, i.e., an iterator to a pair whose second is a list of edges to the child (which are actually iterators to the queue):
316  VertexIdToEdgeQueueIterListUMap::iterator itersToVertex;
317 
318  //Get my incoming edges as a vector of iterators
319  itersToVertex = incomingEdges_.find(cVertex->getId());
320 
321  //Make sure it was found before we start dereferencing it:
322  if (itersToVertex != incomingEdges_.end())
323  {
324  //Variable
325  //The vector of edges to delete in the list:
326  std::vector<EdgeQueueIterList::iterator> listItersToDelete;
327 
328  //Iterate over the incoming edges and record those that are to be deleted
329  for (EdgeQueueIterList::iterator listIter = itersToVertex->second.begin(); listIter != itersToVertex->second.end(); ++listIter)
330  {
331  //Check if it is to be pruned
332  if ( this->edgePruneCondition((*listIter)->second) == true )
333  {
334  listItersToDelete.push_back(listIter);
335  }
336  //No else, we're not deleting this iterator
337  }
338 
339  //Now, iterate over the list of iterators to delete
340  for (unsigned int i = 0u; i < listItersToDelete.size(); ++i)
341  {
342  //Remove the edge and the edge iterator from the other lookup table:
343  this->edgeRemoveHelper( *listItersToDelete.at(i), false, true);
344 
345  //And finally erase the lookup iterator from the from lookup. If this was done first, the iterator would be invalidated for the above.
346  itersToVertex->second.erase( listItersToDelete.at(i) );
347  }
348  }
349  //No else, nothing to delete
350  }
351  else
352  {
353  throw ompl::Exception("Removing edges in the queue going to a vertex requires child vertex lookup, which is not enabled for this instance of the container.");
354  }
355  }
356  //No else, nothing to prune_to
357  }
358 
359 
360 
362  {
363  if (edgeQueue_.empty() == false)
364  {
365  if (outgoingLookupTables_ == true)
366  {
367  //Variable:
368  //The iterator to the key, value of the parent-lookup map, i.e., an iterator to a pair whose second is a list of edges from the child (which are actually iterators to the queue):
369  VertexIdToEdgeQueueIterListUMap::iterator itersFromVertex;
370 
371  //Get my outgoing edges as a vector of iterators
372  itersFromVertex = outgoingEdges_.find(pVertex->getId());
373 
374  //Make sure it was found before we start dereferencing it:
375  if (itersFromVertex != outgoingEdges_.end())
376  {
377  //Variable
378  //The vector of edges to delete in the list:
379  std::vector<EdgeQueueIterList::iterator> listItersToDelete;
380 
381  //Iterate over the incoming edges and record those that are to be deleted
382  for (EdgeQueueIterList::iterator listIter = itersFromVertex->second.begin(); listIter != itersFromVertex->second.end(); ++listIter)
383  {
384  //Check if it is to be pruned
385  if ( this->edgePruneCondition((*listIter)->second) == true )
386  {
387  listItersToDelete.push_back(listIter);
388  }
389  //No else, we're not deleting this iterator
390  }
391 
392  //Now, iterate over the list of iterators to delete
393  for (unsigned int i = 0u; i < listItersToDelete.size(); ++i)
394  {
395  //Remove the edge and the edge iterator from the other lookup table:
396  this->edgeRemoveHelper( *listItersToDelete.at(i), true, false );
397 
398  //And finally erase the lookup iterator from the from lookup. If this was done first, the iterator would be invalidated for the above.
399  itersFromVertex->second.erase( listItersToDelete.at(i) );
400 
401  }
402  }
403  //No else, nothing to delete
404  }
405  else
406  {
407  throw ompl::Exception("Parent lookup is not enabled for this instance of the container.");
408  }
409  }
410  //No else, nothing to prune_from
411  }
412 
413 
414 
416  {
417  resortVertices_.push_back(vertex);
418 
419  //This is the idea for a future assert:
420  /*
421  if (vertexIterLookup_.find(vertex->getId()) == vertexIterLookup_.end())
422  {
423  throw ompl::Exception("A vertex was marked that was not in the queue...");
424  }
425  */
426  }
427 
428 
429 
430  std::pair<unsigned int, unsigned int> BITstar::IntegratedQueue::prune(const VertexPtr& pruneStartPtr, const VertexPtrNNPtr& vertexNN, const VertexPtrNNPtr& freeStateNN, std::vector<VertexPtr>* recycledVertices)
431  {
432  if (this->isSorted() == false)
433  {
434  throw ompl::Exception("Prune cannot be called on an unsorted queue.");
435  }
436  //The vertex expansion queue is sorted on an estimated solution cost considering the *current* cost-to-come of the vertices, while we prune by considering the best-case cost-to-come.
437  //This means that the value of the vertices in the queue are an upper-bounding estimate of the value we will use to prune them.
438  //Therefore, we can start our pruning at the goal vertex and iterate forward through the queue from there.
439 
440  //Variables:
441  //The number of vertices and samples pruned:
442  std::pair<unsigned int, unsigned int> numPruned;
443  //The iterator into the lookup helper:
444  VertexIdToVertexQueueIterUMap::iterator lookupIter;
445  //The iterator into the queue:
446  VertexQueueIter queueIter;
447 
448  //Initialize the counters:
449  numPruned = std::make_pair(0u, 0u);
450 
451  //Get the iterator to the queue of the given starting point.
452  lookupIter = vertexIterLookup_.find(pruneStartPtr->getId());
453 
454  //Check that it was found
455  if (lookupIter == vertexIterLookup_.end())
456  {
457  //Complain
458  throw ompl::Exception("The provided starting point is not in the queue?");
459  }
460 
461  //Get the vertex queue iterator:
462  queueIter = lookupIter->second;
463 
464  //Iterate through to the end of the queue
465  while (queueIter != vertexQueue_.end())
466  {
467  //Check if it should be pruned (value) or has lost its parent.
468  if (this->vertexPruneCondition(queueIter->second) == true)
469  {
470  //The vertex should be pruned.
471  //Variables
472  //An iter to the vertex to prune:
473  VertexQueueIter pruneIter;
474 
475  //Copy the iterator to prune:
476  pruneIter = queueIter;
477 
478  //Move the queue iterator back one so we can step to the next *valid* vertex after pruning:
479  --queueIter;
480 
481  //Prune the branch:
482  numPruned = this->pruneBranch(pruneIter->second, vertexNN, freeStateNN, recycledVertices);
483  }
484  //No else, skip this vertex.
485 
486  //Iterate forward to the next value in the queue
487  ++queueIter;
488  }
489 
490  //Return the number of vertices and samples pruned.
491  return numPruned;
492  }
493 
494 
495 
496  std::pair<unsigned int, unsigned int> BITstar::IntegratedQueue::resort(const VertexPtrNNPtr& vertexNN, const VertexPtrNNPtr& freeStateNN, std::vector<VertexPtr>* recycledVertices)
497  {
498  //Variable:
499  typedef std::unordered_map<BITstar::VertexId, VertexPtr> VertexIdToVertexPtrUMap;
500  typedef std::map<unsigned int, VertexIdToVertexPtrUMap> DepthToUMapMap;
501  //The number of vertices and samples pruned, respectively:
502  std::pair<unsigned int, unsigned int> numPruned;
503 
504  //Initialize the counters:
505  numPruned = std::make_pair(0u, 0u);
506 
507  //Iterate through every vertex listed for resorting:
508  if (resortVertices_.empty() == false)
509  {
510  //Variable:
511  //The container ordered on vertex depth:
512  DepthToUMapMap uniqueResorts;
513 
514  //Iterate over the vector and place into the unique queue indexed on *depth*. This guarantees that we won't process a branch multiple times by being given different vertices down its chain
515  for (std::list<VertexPtr>::iterator vIter = resortVertices_.begin(); vIter != resortVertices_.end(); ++vIter)
516  {
517  //Add the vertex to the unordered map stored at the given depth.
518  //The [] return an reference to the existing entry, or create a new entry:
519  uniqueResorts[(*vIter)->getDepth()].emplace((*vIter)->getId(), *vIter);
520  }
521 
522  //Clear the list of vertices to resort from:
523  resortVertices_.clear();
524 
525  //Now process the vertices in order of depth.
526  for (DepthToUMapMap::iterator deepIter = uniqueResorts.begin(); deepIter != uniqueResorts.end(); ++deepIter)
527  {
528  for (VertexIdToVertexPtrUMap::iterator vIter = deepIter->second.begin(); vIter != deepIter->second.end(); ++vIter)
529  {
530  //Make sure it has not already been pruned:
531  if (vIter->second->isPruned() == false)
532  {
533  //Make sure it has not already been returned to the set of samples:
534  if (vIter->second->isInTree() == true)
535  {
536  //Are we pruning the vertex from the queue (and do we have "permission" to do so)?
537  if (this->vertexPruneCondition(vIter->second) == true && static_cast<bool>(vertexNN) == true && static_cast<bool>(freeStateNN) == true)
538  {
539  //The vertex should just be pruned and forgotten about.
540  //Prune the branch:
541  numPruned = this->pruneBranch(vIter->second, vertexNN, freeStateNN, recycledVertices);
542  }
543  else
544  {
545  //The vertex is going to be kept.
546 
547  //Does it have any children?
548  if (vIter->second->hasChildren() == true)
549  {
550  //Variables:
551  //The list of children:
552  std::vector<VertexPtr> resortChildren;
553 
554  //Put its children in the list to be resorted:
555  //Get the list of children:
556  vIter->second->getChildren(&resortChildren);
557 
558  //Get a reference to the container for the children, all children are 1 level deeper than their parent.:
559  //The [] return an reference to the existing entry, or create a new entry:
560  VertexIdToVertexPtrUMap& depthContainer = uniqueResorts[vIter->second->getDepth() + 1u];
561 
562  //Place the children into the container, as the container is a map, it will not allow the children to be entered twice.
563  for (unsigned int i = 0u; i < resortChildren.size(); ++i)
564  {
565  depthContainer.emplace(resortChildren.at(i)->getId(), resortChildren.at(i));
566  }
567  }
568 
569  //Reinsert the vertex:
570  this->reinsertVertex(vIter->second);
571  }
572  }
573  //No else, this vertex was a child of a vertex pruned during the resort. It has been returned to the set of free samples.
574  }
575  //No else, this vertex was a child of a vertex pruned during the resort. It has been deleted.
576  }
577  }
578  }
579 
580  //Return the number of vertices pruned.
581  return numPruned;
582  }
583 
584 
585 
587  {
588  //Clear the edge containers:
589  edgeQueue_.clear();
590  outgoingEdges_.clear();
591  incomingEdges_.clear();
592 
593  //Move the token to the end:
594  vertexToExpand_ = vertexQueue_.end();
595 
596  //Do NOT clear:
597  // - resortVertices_ (they may still need to be resorted)
598  // - vertexIterLookup_ (it's still valid)
599  }
600 
601 
602 
604  {
605  //Make sure the queue is "finished":
606  this->finish();
607 
608  //Restart the expansion queue:
609  vertexToExpand_ = vertexQueue_.begin();
610  }
611 
612 
613 
615  {
616  //Clear:
617  //The vertex queue:
618  vertexQueue_.clear();
619  vertexToExpand_ = vertexQueue_.begin();
620 
621  //The edge queue:
622  edgeQueue_.clear();
623 
624  //The lookups:
625  vertexIterLookup_.clear();
626  outgoingEdges_.clear();
627  incomingEdges_.clear();
628 
629  //The resort list:
630  resortVertices_.clear();
631 
632  //The cost threshold:
633  costThreshold_ = opt_->infiniteCost();
634 
635  //The existence of a solution:
636  hasSolution_ = false;
637  }
638 
639 
640 
641 
643  {
644  //Threshold should always be g_t(x_g)
645  //As the sample is in the graph (and therefore could be part of g_t), prune iff g^(v) + h^(v) > g_t(x_g)
646  //g^(v) + h^(v) >= g_t(x_g)
647  return this->isCostWorseThan(lowerBoundHeuristicVertexFunc_(state), costThreshold_);
648  }
649 
650 
651 
653  {
654  //Threshold should always be g_t(x_g)
655  //As the sample is not in the graph (and therefore not part of g_t), prune if g^(v) + h^(v) >= g_t(x_g)
656  return this->isCostWorseThanOrEquivalentTo(lowerBoundHeuristicVertexFunc_(state), costThreshold_);
657  }
658 
659 
660 
662  {
663  bool rval;
664  //Threshold should always be g_t(x_g)
665 
666  // g^(v) + c^(v,x) + h^(x) > g_t(x_g)?
667  rval = this->isCostWorseThan(lowerBoundHeuristicEdgeFunc_(edge), costThreshold_);
668 
669 
670  //If the child is connected already, we need to check if we could do better than it's current connection. But only if we're not pruning based on the first check
671  if (edge.second->hasParent() == true && rval == false)
672  {
673  //g^(v) + c^(v,x) > g_t(x)
674  //rval = this->isCostWorseThan(opt_->combineCosts(this->costToComeHeuristic(edge.first), this->edgeCostHeuristic(edge)), edge.second->getCost()); //Ever rewire?
675  //g_t(v) + c^(v,x) > g_t(x)
676  rval = this->isCostWorseThan(currentHeuristicEdgeTargetFunc_(edge), edge.second->getCost()); //Currently rewire?
677  }
678 
679  return rval;
680  }
681 
682 
683 
685  {
686  return edgeQueue_.size();
687  }
688 
689 
690 
692  {
693  //Variables:
694  //The number of vertices left to expand:
695  unsigned int numToExpand;
696 
697  //Start at 0:
698  numToExpand = 0u;
699 
700  //Iterate until the end:
701  for (CostToVertexMMap::const_iterator vIter = vertexToExpand_; vIter != vertexQueue_.end(); ++vIter)
702  {
703  //Increment counter:
704  ++numToExpand;
705  }
706 
707  //Return
708  return numToExpand;
709  }
710 
711 
712 
713  unsigned int BITstar::IntegratedQueue::numEdgesTo(const VertexPtr& cVertex) const
714  {
715  //Variables:
716  //The number of edges to:
717  unsigned int rval;
718 
719  //Start at 0:
720  rval = 0u;
721 
722  //Is there anything to count?
723  if (edgeQueue_.empty() == false)
724  {
725  if (incomingLookupTables_ == true)
726  {
727  //Variable:
728  //The iterator to the vector of edges to the child:
729  VertexIdToEdgeQueueIterListUMap::const_iterator toIter;
730 
731  //Get the vector of iterators
732  toIter = incomingEdges_.find(cVertex->getId());
733 
734  //Make sure it was found before we dereferencing it:
735  if (toIter != incomingEdges_.end())
736  {
737  rval = toIter->second.size();
738  }
739  //No else, there are none.
740  }
741  else
742  {
743  throw ompl::Exception("Parent lookup is not enabled for this instance of the container.");
744  }
745  }
746  //No else, there is nothing.
747 
748  //Return:
749  return rval;
750  }
751 
752 
753 
754  unsigned int BITstar::IntegratedQueue::numEdgesFrom(const VertexPtr& pVertex) const
755  {
756  //Variables:
757  //The number of edges to:
758  unsigned int rval;
759 
760  //Start at 0:
761  rval = 0u;
762 
763  //Is there anything to count?
764  if (edgeQueue_.empty() == false)
765  {
766  if (outgoingLookupTables_ == true)
767  {
768  //Variable:
769  //The iterator to the vector of edges from the parent:
770  VertexIdToEdgeQueueIterListUMap::const_iterator toIter;
771 
772  //Get the vector of iterators
773  toIter = outgoingEdges_.find(pVertex->getId());
774 
775  //Make sure it was found before we dereferencing it:
776  if (toIter != outgoingEdges_.end())
777  {
778  rval = toIter->second.size();
779  }
780  //No else, 0u.
781  }
782  else
783  {
784  throw ompl::Exception("Parent lookup is not enabled for this instance of the container.");
785  }
786  }
787  //No else, there is nothing.
788 
789  //Return
790  return rval;
791  }
792 
793 
794 
796  {
797  return resortVertices_.empty();
798  }
799 
800 
801 
803  {
804  return (vertexToExpand_ == vertexQueue_.begin() && edgeQueue_.empty());
805  }
806 
807 
808 
810  {
811  //Expand if the edge queue is empty but the vertex queue is not:
812  while (edgeQueue_.empty() && vertexToExpand_ != vertexQueue_.end())
813  {
814  //Expand the next vertex, this pushes the token:
815  this->expandNextVertex();
816  }
817 
818  //Return whether the edge queue is empty:
819  return edgeQueue_.empty();
820  }
821 
822 
823 
825  {
826  //Variable
827  //The vertex iterator
828  VertexIdToVertexQueueIterUMap::const_iterator lkupIter;
829 
830  //Get the lookup iterator for the provided vertex
831  lkupIter = vertexIterLookup_.find(vertex->getId());
832 
833  if (lkupIter == vertexIterLookup_.end())
834  {
835  throw ompl::Exception("Attempting to check the expansion status of a vertex not in the queue");
836  }
837 
838  //Compare the value used to currently sort the vertex in the queue to the value of the token.
839  if (vertexToExpand_ == vertexQueue_.end())
840  {
841  //If the token is at the end of the queue, obviously the vertex is expanded:
842  return true;
843  }
844  else
845  {
846  //By virtue of the vertex expansion rules, the token will always sit at the front of a group of equivalent cost vertices (that is to say, all vertices with the same cost get expanded at the same time)
847  //Therefore, the vertex is expanded if it's cost is strictly better than the token.
848  return opt_->isCostBetterThan(lkupIter->second->first, vertexToExpand_->first);
849  }
850  }
851 
852 
853 
854  void BITstar::IntegratedQueue::listVertices(std::vector<VertexConstPtr>* vertexQueue)
855  {
856  //Clear the given list:
857  vertexQueue->clear();
858 
859  //Iterate until the end, pushing back:
860  for (CostToVertexMMap::const_iterator vIter = vertexToExpand_; vIter != vertexQueue_.end(); ++vIter)
861  {
862  //Push back:
863  vertexQueue->push_back(vIter->second);
864  }
865  }
866 
867 
868 
869  void BITstar::IntegratedQueue::listEdges(std::vector<std::pair<VertexConstPtr, VertexConstPtr> >* edgeQueue)
870  {
871  //Clear the vector
872  edgeQueue->clear();
873 
874  //I don't think there's a std::copy way to do this, so just iterate
875  for( CostToVertexPtrPairMMap::const_iterator eIter = edgeQueue_.begin(); eIter != edgeQueue_.end(); ++eIter )
876  {
877  edgeQueue->push_back(eIter->second);
878  }
879  }
881 
882 
883 
885  //Private functions:
886  void BITstar::IntegratedQueue::updateQueue()
887  {
888  //Variables:
889  //Whether to expand:
890  bool expand;
891 
892  expand = true;
893  while ( expand == true )
894  {
895  //Check if there are any vertices to expand:
896  if (vertexToExpand_ != vertexQueue_.end())
897  {
898  //Expand a vertex if the edge queue is empty, or the vertex could place a better edge into it:
899  if (edgeQueue_.empty() == true)
900  {
901  //The edge queue is empty, any edge is better than this!
902  this->expandNextVertex();
903  }
904  //This is isCostBetterThanOrEquivalentTo because of the second ordering criteria. The vertex expanded could match the edge in queue on total cost, but have less cost-to-come.
905  else if (this->isCostBetterThanOrEquivalentTo( vertexToExpand_->first, edgeQueue_.begin()->first.first ) == true)
906  {
907  //The vertex *could* give a better edge than our current best edge:
908  this->expandNextVertex();
909  }
910  else
911  {
912  //We are done expanding for now:
913  expand = false;
914  }
915  }
916  else
917  {
918  //There are no vertices left to expand
919  expand = false;
920  }
921  }
922  }
923 
924 
925 
926  void BITstar::IntegratedQueue::expandNextVertex()
927  {
928  //Should we expand the next vertex? Will it be pruned?
929  if (this->vertexPruneCondition(vertexToExpand_->second) == false)
930  {
931  //Expand the vertex in the front:
932  this->expandVertex(vertexToExpand_->second);
933 
934  //Increment the vertex token:
935  ++vertexToExpand_;
936  }
937  else
938  {
939  //The next vertex would get pruned, so just jump to the end:
940  vertexToExpand_ = vertexQueue_.end();
941  }
942  }
943 
944 
945 
946  void BITstar::IntegratedQueue::expandVertex(const VertexPtr& vertex)
947  {
948  //Should we expand this vertex?
949  if (this->vertexPruneCondition(vertex) == false)
950  {
951  //Variables:
952  //The vector of nearby samples (either within r or the k-nearest)
953  std::vector<VertexPtr> neighbourSamples;
954  //The vector of nearby vertices
955  std::vector<VertexPtr> neighbourVertices;
956  //Are we using k-nearest?
957  bool usingKNearest;
958  //If we're using k-nearest, what number that is
959  unsigned int k;
960 
961  //Get the set of nearby free states, returns the number k if it's k nearest, 0u otherwise
962  k = nearSamplesFunc_(vertex, &neighbourSamples);
963 
964  //Decode if we're using k-nearest for readability
965  usingKNearest = (k > 0u);
966 
967  //If we're usjng k-nearest, we always have to also get the neighbourVertices and the do some post-processing
968  if (usingKNearest == true)
969  {
970  //Get the set of nearby vertices
971  nearVerticesFunc_(vertex, &neighbourVertices);
972 
973  //Post process them:
974  this->processKNearest(k, vertex, &neighbourSamples, &neighbourVertices);
975  }
976  //No else
977 
978  //Add edges to unconnected targets who could ever provide a better solution:
979  //Has the vertex been expanded into edges towards unconnected samples before?
980  if (vertex->hasBeenExpandedToSamples() == false)
981  {
982  //It has not, that means none of its outgoing edges have been considered. Add them all
983  for (unsigned int i = 0u; i < neighbourSamples.size(); ++i)
984  {
985  //Attempt to queue the edge.
986  this->queueupEdge(vertex, neighbourSamples.at(i));
987  }
988 
989  //Mark it as expanded
990  vertex->markExpandedToSamples();
991  }
992  else
993  {
994  //It has, which means that outgoing edges to old unconnected vertices have already been considered. Only add those that lead to new vertices
995  for (unsigned int i = 0u; i < neighbourSamples.size(); ++i)
996  {
997  //Is the target new?
998  if (neighbourSamples.at(i)->isNew() == true)
999  {
1000  //It is, attempt to queue the edge.
1001  this->queueupEdge(vertex, neighbourSamples.at(i));
1002  }
1003  //No else, we've considered this edge before.
1004  }
1005  }
1006 
1007  //If the vertex has never been expanded into possible rewiring edges *and* either we're not delaying rewiring or we have a solution, we add those rewiring candidates:
1008  if (vertex->hasBeenExpandedToVertices() == false && (delayRewiring_ == false || hasSolution_ == true))
1009  {
1010  //If we're not using k-nearest, we will not have gotten the neighbour vertices yet, get them now
1011  if (usingKNearest == false)
1012  {
1013  //Get the set of nearby vertices
1014  nearVerticesFunc_(vertex, &neighbourVertices);
1015  }
1016  //No else
1017 
1018  //Iterate over the vector of connected targets and add only those who could ever provide a better solution:
1019  for (unsigned int i = 0u; i < neighbourVertices.size(); ++i)
1020  {
1021  //Make sure it is not the root or myself.
1022  if (neighbourVertices.at(i)->isRoot() == false && neighbourVertices.at(i) != vertex)
1023  {
1024  //Make sure I am not already the parent
1025  if (neighbourVertices.at(i)->getParent() != vertex)
1026  {
1027  //Make sure the neighbour vertex is not already my parent:
1028  if (vertex->isRoot() == true)
1029  {
1030  //I am root, I have no parent, so attempt to queue the edge:
1031  this->queueupEdge(vertex, neighbourVertices.at(i));
1032  }
1033  else if (neighbourVertices.at(i) != vertex->getParent())
1034  {
1035  //The neighbour is not my parent, attempt to queue the edge:
1036  this->queueupEdge(vertex, neighbourVertices.at(i));
1037  }
1038  //No else, this vertex is my parent.
1039  }
1040  //No else
1041  }
1042  //No else
1043  }
1044 
1045  //Mark the vertex as expanded into rewirings
1046  vertex->markExpandedToVertices();
1047  }
1048  //No else
1049  }
1050  //No else
1051  }
1052 
1053 
1054 
1055  void BITstar::IntegratedQueue::queueupEdge(const VertexPtr& parent, const VertexPtr& child)
1056  {
1057  //Variable:
1058  //The edge:
1059  VertexPtrPair newEdge;
1060 
1061  //Make the edge
1062  newEdge = std::make_pair(parent, child);
1063 
1064  //Should this edge be in the queue? I.e., is it *not* due to be pruned:
1065  if (this->edgePruneCondition(newEdge) == false)
1066  {
1067  this->edgeInsertHelper(newEdge, edgeQueue_.end());
1068  }
1069  //No else, it can never provide a better solution
1070  }
1071 
1072 
1073 
1074  void BITstar::IntegratedQueue::processKNearest(unsigned int k, const VertexConstPtr& vertex, std::vector<VertexPtr>* kNearSamples, std::vector<VertexPtr>* kNearVertices)
1075  {
1076  //Variables
1077  //The position in the sample vector
1078  unsigned int samplePos;
1079  //The position in the vertex vector
1080  unsigned int vertexPos;
1081 
1082  //Iterate through the first k in the combined vectors
1083  samplePos = 0u;
1084  vertexPos = 0u;
1085  while (samplePos + vertexPos < k && (samplePos < kNearSamples->size() || vertexPos < kNearVertices->size()))
1086  {
1087  //Where along are we in the relative vectors?
1088  if (samplePos < kNearSamples->size() && vertexPos >= kNearVertices->size())
1089  {
1090  //There are just samples left. Easy, move the sample token:
1091  ++samplePos;
1092  }
1093  else if (samplePos >= kNearSamples->size() && vertexPos < kNearVertices->size())
1094  {
1095  //There are just vertices left. Easy, move the vertex token:
1096  ++vertexPos;
1097  }
1098  else
1099  {
1100  //Both are left, which is closest?
1101  if ( distanceFunc_(kNearVertices->at(vertexPos), vertex) < distanceFunc_(kNearSamples->at(samplePos), vertex) )
1102  {
1103  //The vertex is closer than the sample, move that token:
1104  ++vertexPos;
1105  }
1106  else
1107  {
1108  //The vertex is not closer than the sample, move the sample token:
1109  ++samplePos;
1110  }
1111  }
1112  }
1113 
1114  //Now erase the extra. Resize will truncate the extras
1115  kNearSamples->resize(samplePos);
1116  kNearVertices->resize(vertexPos);
1117  }
1118 
1119 
1120 
1121  void BITstar::IntegratedQueue::reinsertVertex(const VertexPtr& unorderedVertex)
1122  {
1123  //Variables:
1124  //Whether the vertex is expanded.
1125  bool alreadyExpanded;
1126  //My entry in the vertex lookup:
1127  VertexIdToVertexQueueIterUMap::iterator myLookup;
1128  //The list of edges from the vertex:
1129  VertexIdToEdgeQueueIterListUMap::iterator edgeItersFromVertex;
1130 
1131  //Get my iterator:
1132  myLookup = vertexIterLookup_.find(unorderedVertex->getId());
1133 
1134  //Assert
1135  if (myLookup == vertexIterLookup_.end())
1136  {
1137  throw ompl::Exception("Vertex to reinsert is not in the lookup. Something went wrong.");
1138  }
1139 
1140  //Test if it I am currently expanded.
1141  if (vertexToExpand_ == vertexQueue_.end())
1142  {
1143  //The token is at the end, therefore this vertex is in front of it:
1144  alreadyExpanded = true;
1145  }
1146  else if ( this->vertexQueueComparison(myLookup->second->first, vertexToExpand_->first) == true )
1147  {
1148  //The vertexQueueCondition says that this vertex was entered with a cost that is in front of the current token:
1149  alreadyExpanded = true;
1150  }
1151  else
1152  {
1153  //Otherwise I have not been expanded yet.
1154  alreadyExpanded = false;
1155  }
1156 
1157  //Remove myself, not touching my lookup entries
1158  this->vertexRemoveHelper(unorderedVertex, VertexPtrNNPtr(), VertexPtrNNPtr(), nullptr, false);
1159 
1160  //Reinsert myself, expanding if I cross the token if I am not already expanded
1161  this->vertexInsertHelper(unorderedVertex, alreadyExpanded == false);
1162 
1163  //Iterate over my outgoing edges and reinsert them in the queue:
1164  //Get my list of outgoing edges
1165  edgeItersFromVertex = outgoingEdges_.find(unorderedVertex->getId());
1166 
1167  //Reinsert the edges:
1168  if (edgeItersFromVertex != outgoingEdges_.end())
1169  {
1170  //Variables
1171  //The iterators to the edge queue from this vertex
1172  EdgeQueueIterList edgeItersToResort;
1173 
1174  //Copy the iters to resort
1175  edgeItersToResort = edgeItersFromVertex->second;
1176 
1177  //Clear the outgoing lookup
1178  edgeItersFromVertex->second = EdgeQueueIterList();
1179 
1180  //Iterate over the list of iters to resort, inserting each one as a new edge, and then removing it as an iterator from the edge queue and the incoming lookup
1181  for (EdgeQueueIterList::iterator resortIter = edgeItersToResort.begin(); resortIter != edgeItersToResort.end(); ++resortIter)
1182  {
1183  //Check if the edge should be reinserted
1184  if ( this->edgePruneCondition((*resortIter)->second) == false )
1185  {
1186  //Call helper to reinsert. Looks after lookups, hint at the location it's coming out of
1187  this->edgeInsertHelper( (*resortIter)->second, *resortIter );
1188  }
1189  //No else, prune.
1190 
1191  //Remove the old edge and its entry in the incoming lookup. No need to remove from this lookup, as that's been cleared:
1192  this->edgeRemoveHelper(*resortIter, true, false);
1193  }
1194  }
1195  //No else, no edges from this vertex to requeue
1196  }
1197 
1198 
1199 
1200  std::pair<unsigned int, unsigned int> BITstar::IntegratedQueue::pruneBranch(const VertexPtr& branchBase, const VertexPtrNNPtr& vertexNN, const VertexPtrNNPtr& freeStateNN, std::vector<VertexPtr>* recycledVertices)
1201  {
1202  //We must iterate over the children of this vertex and prune each one.
1203  //Then we must decide if this vertex (a) gets deleted or (b) placed back on the sample set.
1204  //(a) occurs if it has a lower-bound heuristic greater than the current solution
1205  //(b) occurs if it doesn't.
1206 
1207  //Some asserts:
1208  if (branchBase->isInTree() == false)
1209  {
1210  throw ompl::Exception("Trying to prune a disconnected vertex. Something went wrong.");
1211  }
1212 
1213  //Variables:
1214  //The counter of vertices and samples pruned:
1215  std::pair<unsigned int, unsigned int> numPruned;
1216  //The vector of my children:
1217  std::vector<VertexPtr> children;
1218 
1219  //Initialize the counter:
1220  numPruned = std::make_pair(1u, 0u);
1221 
1222  //Disconnect myself from my parent, not cascading costs as I know my children are also being disconnected:
1223  this->disconnectParent(branchBase, false);
1224 
1225  //Get the vector of children
1226  branchBase->getChildren(&children);
1227 
1228  //Remove myself from everything:
1229  numPruned.second = this->vertexRemoveHelper(branchBase, vertexNN, freeStateNN, recycledVertices, true);
1230 
1231  //Prune my children:
1232  for (unsigned int i = 0u; i < children.size(); ++i)
1233  {
1234  //Variable:
1235  //The number pruned by my children:
1236  std::pair<unsigned int, unsigned int> childNumPruned;
1237 
1238  //Prune my children:
1239  childNumPruned = this->pruneBranch(children.at(i), vertexNN, freeStateNN, recycledVertices);
1240 
1241  //Update my counter:
1242  numPruned.first = numPruned.first + childNumPruned.first;
1243  numPruned.second = numPruned.second + childNumPruned.second;
1244  }
1245 
1246  //Return the number pruned
1247  return numPruned;
1248  }
1249 
1250 
1251 
1252  void BITstar::IntegratedQueue::disconnectParent(const VertexPtr& oldVertex, bool cascadeCostUpdates)
1253  {
1254  if (oldVertex->hasParent() == false)
1255  {
1256  throw ompl::Exception("An orphaned vertex has been passed for disconnection. Something went wrong.");
1257  }
1258 
1259  //Check if my parent has already been pruned. This can occur if we're cascading vertex disconnections.
1260  if (oldVertex->getParent()->isPruned() == false)
1261  {
1262  //If not, remove myself from my parent's list of children, not updating down-stream costs
1263  oldVertex->getParent()->removeChild(oldVertex, false);
1264  }
1265 
1266  //Remove my parent link, cascading cost updates if requested:
1267  oldVertex->removeParent(cascadeCostUpdates);
1268  }
1269 
1270 
1271 
1272  void BITstar::IntegratedQueue::vertexInsertHelper(const VertexPtr& newVertex, bool expandIfBeforeToken)
1273  {
1274  //Variable:
1275  //The iterator to the new edge in the queue:
1276  VertexQueueIter vertexIter;
1277 
1278  //Insert into the order map, getting the interator
1279  vertexIter = vertexQueue_.insert( std::make_pair(this->vertexQueueValue(newVertex), newVertex) );
1280 
1281  //Store the iterator in the lookup. This will create insert if necessary and otherwise lookup
1282  vertexIterLookup_[newVertex->getId()] = vertexIter;
1283 
1284  //Check if we are in front of the token and expand if so:
1285  if (vertexQueue_.size() == 1u)
1286  {
1287  //If the vertex queue is now of size 1, that means that this was the first vertex. Set the token to it and don't even think of expanding anything:
1288  vertexToExpand_ = vertexQueue_.begin();
1289  }
1290  else if (expandIfBeforeToken == true)
1291  {
1292  /*
1293  There are 3ish cases:
1294  1 The new vertex is immediately before the token.
1295  a The token is not at the end: Don't expand and shift the token to the new vertex.
1296  b The token is at the end: Don't expand and shift the token to the new vertex.
1297  2 The new vertex is before the token, but *not* immediately (i.e., there are vertices between it):
1298  a The token is at the end: Expand the vertex
1299  b The token is not at the end: Expand the vertex
1300  3 The new vertex is after the token: Don't expand. It cleanly goes into the list of vertices to expand
1301  Note: By shifting the token, we assure that if the new vertex is better than the best edge, it will get expanded on the next pop.
1302 
1303  The cases look like this (-: expanded vertex, x: unexpanded vertex, X: token (next to expand), *: new vertex):
1304  We represent the token at the end with no X in the line:
1305 
1306  1a: ---*Xxx -> ---Xxxx
1307  1b: ------* -> ------X
1308  2a: ---*--- -> -------
1309  2b: --*-Xxx -> ----Xxx
1310  3: ---Xx*x -> ---Xxxx
1311  */
1312 
1313  //Variable:
1314  //The vertex before the token. Remember that since we have already added the new vertex, this could be ourselves:
1315  VertexQueueIter preToken;
1316 
1317  //Get the vertex before the current token:
1318  preToken = vertexToExpand_;
1319  --preToken;
1320 
1321  //Check if we are immediately before: (1a & 1b)
1322  if (preToken == vertexIter)
1323  {
1324  //The vertex before the token is the newly added vertex. Therefore we can just move the token up to the newly added vertex:
1325  vertexToExpand_ = vertexIter;
1326  }
1327  else
1328  {
1329  //We are not immediately before the token.
1330 
1331  //Check if the token is at the end (2a)
1332  if (vertexToExpand_ == vertexQueue_.end())
1333  {
1334  //It is. We've expanded the whole queue, and the new vertex isn't at the end of the queue. Expand!
1335  this->expandVertex(newVertex);
1336  }
1337  else
1338  {
1339  //The token is not at the end. That means we can safely dereference it:
1340  //Are we in front of it (2b)?
1341  if ( this->vertexQueueComparison(this->vertexQueueValue(newVertex), vertexToExpand_->first) == true )
1342  {
1343  //We're before it, so expand it:
1344  this->expandVertex(newVertex);
1345  }
1346  //No else, the vertex is behind the current token (3) and will get expanded as necessary.
1347  }
1348  }
1349  }
1350  }
1351 
1352 
1353 
1354  unsigned int BITstar::IntegratedQueue::vertexRemoveHelper(VertexPtr oldVertex, const VertexPtrNNPtr& vertexNN, const VertexPtrNNPtr& freeStateNN, std::vector<VertexPtr>* recycledVertices, bool removeLookups)
1355  {
1356  //Variable
1357  //The number of samples deleted (i.e., if this vertex is NOT moved to a sample, this is a 1)
1358  unsigned int deleted;
1359 
1360  //Check that the vertex is not connected to a parent:
1361  if (oldVertex->hasParent() == true && removeLookups == true)
1362  {
1363  throw ompl::Exception("Cannot delete a vertex connected to a parent unless the vertex is being immediately reinserted, in which case removeLookups should be false.");
1364  }
1365 
1366  //Start undeleted:
1367  deleted = 0u;
1368 
1369  //Check if there's anything to delete:
1370  if (vertexQueue_.empty() == false)
1371  {
1372  //Variable
1373  //The iterator into the lookup:
1374  VertexIdToVertexQueueIterUMap::iterator lookupIter;
1375 
1376  //Get my lookup iter:
1377  lookupIter = vertexIterLookup_.find(oldVertex->getId());
1378 
1379  //Assert
1380  if (lookupIter == vertexIterLookup_.end())
1381  {
1382  std::cout << std::endl << "vId: " << oldVertex->getId() << std::endl;
1383  throw ompl::Exception("Deleted vertex is not found in lookup. Something went wrong.");
1384  }
1385 
1386  //Check if we need to move the expansion token:
1387  if (lookupIter->second == vertexToExpand_)
1388  {
1389  //It is the token, move it to the next:
1390  ++vertexToExpand_;
1391  }
1392  //No else, not the token.
1393 
1394  //Remove myself from the vertex queue:
1395  vertexQueue_.erase(lookupIter->second);
1396 
1397  //Remove from lookups map as requested
1398  if (removeLookups == true)
1399  {
1400  vertexIterLookup_.erase(lookupIter);
1401  this->removeEdgesFrom(oldVertex);
1402  }
1403 
1404  //Check if I have been given permission to change sets:
1405  if (static_cast<bool>(vertexNN) == true && static_cast<bool>(freeStateNN) == true && static_cast<bool>(recycledVertices) == true)
1406  {
1407  //Check if I should be discarded completely:
1408  if (this->samplePruneCondition(oldVertex) == true)
1409  {
1410  //Yes, the vertex isn't even useful as a sample
1411  //Update the counter:
1412  deleted = 1u;
1413 
1414  //Remove from the incoming edge container if requested:
1415  if (removeLookups == true)
1416  {
1417  this->removeEdgesTo(oldVertex);
1418  }
1419 
1420  //Remove myself from the nearest neighbour structure:
1421  vertexNN->remove(oldVertex);
1422 
1423  //Finally, mark as pruned. This is a lock that prevents accessing anything about the vertex.
1424  oldVertex->markPruned();
1425  }
1426  else
1427  {
1428  //No, the vertex is still useful as a sample:
1429  //Remove myself from the nearest neighbour structure:
1430  vertexNN->remove(oldVertex);
1431 
1432  //Mark myself as a "new" sample. This assures that all possible incoming edges will be considered
1433  oldVertex->markNew();
1434 
1435  //Add myself to the list of recycled vertices:
1436  recycledVertices->push_back(oldVertex);
1437 
1438  //And add the vertex to the set of samples, keeping the incoming edges:
1439  freeStateNN->add(oldVertex);
1440  }
1441  }
1442  //Else, if I was given null pointers, that's because this sample is not allowed to change sets.
1443  }
1444  else
1445  {
1446  std::cout << std::endl << "vId: " << oldVertex->getId() << std::endl;
1447  throw ompl::Exception("Removing a nonexistent vertex. Something went wrong.");
1448  }
1449 
1450  //Return if the sample was deleted:
1451  return deleted;
1452  }
1453 
1454 
1455 
1456  void BITstar::IntegratedQueue::edgeInsertHelper(const VertexPtrPair& newEdge, EdgeQueueIter positionHint)
1457  {
1458  //Variable:
1459  //The iterator to the new edge in the queue:
1460  EdgeQueueIter edgeIter;
1461 
1462  //Insert into the edge queue, getting the iter
1463  if (positionHint == edgeQueue_.end())
1464  {
1465  //No hint, insert:
1466  edgeIter = edgeQueue_.insert(std::make_pair(this->edgeQueueValue(newEdge), newEdge));
1467  }
1468  else
1469  {
1470  //Insert with hint:
1471  edgeIter = edgeQueue_.insert(positionHint, std::make_pair(this->edgeQueueValue(newEdge), newEdge));
1472  }
1473 
1474  if (outgoingLookupTables_ == true)
1475  {
1476  //Push the newly created edge back on the list of edges from the parent.
1477  //The [] return an reference to the existing entry, or create a new entry:
1478  outgoingEdges_[newEdge.first->getId()].push_back(edgeIter);
1479  }
1480 
1481  if (incomingLookupTables_ == true)
1482  {
1483  //Push the newly created edge back on the list of edges from the child.
1484  //The [] return an reference to the existing entry, or create a new entry:
1485  incomingEdges_[newEdge.second->getId()].push_back(edgeIter);
1486  }
1487  }
1488 
1489 
1490 
1491  void BITstar::IntegratedQueue::edgeRemoveHelper(const EdgeQueueIter& oldEdgeIter, bool rmIncomingLookup, bool rmOutgoingLookup)
1492  {
1493  //Erase the lookup tables:
1494  if (rmIncomingLookup == true)
1495  {
1496  //Erase the entry in the outgoing lookup table:
1497  this->rmIncomingLookup(oldEdgeIter);
1498  }
1499  //No else
1500 
1501  if (rmOutgoingLookup == true)
1502  {
1503  //Erase the entry in the ingoing lookup table:
1504  this->rmOutgoingLookup(oldEdgeIter);
1505  }
1506  //No else
1507 
1508  //Finally erase from the queue:
1509  edgeQueue_.erase(oldEdgeIter);
1510  }
1511 
1512 
1513 
1514  void BITstar::IntegratedQueue::rmIncomingLookup(const EdgeQueueIter& mmapIterToRm)
1515  {
1516  if (incomingLookupTables_ == true)
1517  {
1518  this->rmEdgeLookupHelper(incomingEdges_, mmapIterToRm->second.second->getId(), mmapIterToRm);
1519  }
1520  //No else
1521  }
1522 
1523 
1524 
1525  void BITstar::IntegratedQueue::rmOutgoingLookup(const EdgeQueueIter& mmapIterToRm)
1526  {
1527  if (outgoingLookupTables_ == true)
1528  {
1529  this->rmEdgeLookupHelper(outgoingEdges_, mmapIterToRm->second.first->getId(), mmapIterToRm);
1530  }
1531  //No else
1532  }
1533 
1534 
1535 
1536  void BITstar::IntegratedQueue::rmEdgeLookupHelper(VertexIdToEdgeQueueIterListUMap& lookup, const BITstar::VertexId& idx, const EdgeQueueIter& mmapIterToRm)
1537  {
1538  //Variable:
1539  //An iterator to the vertex,list pair in the lookup
1540  VertexIdToEdgeQueueIterListUMap::iterator iterToVertexListPair;
1541 
1542  //Get the list in the lookup for the given index:
1543  iterToVertexListPair = lookup.find(idx);
1544 
1545  //Make sure it was actually found before derefencing it:
1546  if (iterToVertexListPair != lookup.end())
1547  {
1548  //Variable:
1549  //Whether I've found the mmapIterToRm in my list:
1550  bool found;
1551  //The iterator to the mmapIterToRm in my list:
1552  EdgeQueueIterList::iterator iterToList;
1553 
1554  //Start at the front:
1555  iterToList = iterToVertexListPair->second.begin();
1556 
1557  //Iterate through the list and find mmapIterToRm
1558  found = false;
1559  while (found == false && iterToList != iterToVertexListPair->second.end())
1560  {
1561  //Compare the value in the list to the target:
1562  if (*iterToList == mmapIterToRm)
1563  {
1564  //Mark as found:
1565  found = true;
1566  }
1567  else
1568  {
1569  //Increment the iterator:
1570  ++iterToList;
1571  }
1572  }
1573 
1574  if (found == true)
1575  {
1576  iterToVertexListPair->second.erase(iterToList);
1577  }
1578  else
1579  {
1580  throw ompl::Exception("Edge iterator not found under given index in lookup hash.");
1581  }
1582  }
1583  else
1584  {
1585  throw ompl::Exception("Indexing vertex not found in lookup hash.");
1586  }
1587  }
1588 
1589 
1590 
1591  ompl::base::Cost BITstar::IntegratedQueue::vertexQueueValue(const VertexPtr& vertex) const
1592  {
1593  return currentHeuristicVertexFunc_(vertex);
1594  }
1595 
1596 
1597 
1598  BITstar::IntegratedQueue::CostPair BITstar::IntegratedQueue::edgeQueueValue(const VertexPtrPair& edge) const
1599  {
1600  return std::make_pair(currentHeuristicEdgeFunc_(edge), edge.first->getCost());
1601  }
1602 
1603 
1604 
1605  bool BITstar::IntegratedQueue::vertexQueueComparison(const ompl::base::Cost& lhs, const ompl::base::Cost& rhs) const
1606  {
1607  //lhs < rhs?
1608  return opt_->isCostBetterThan(lhs, rhs);
1609  }
1610 
1611 
1612 
1613  bool BITstar::IntegratedQueue::edgeQueueComparison(const CostPair& lhs, const CostPair& rhs) const
1614  {
1615  bool lhsLTrhs;
1616 
1617  //Get if LHS is less than RHS.
1618  lhsLTrhs = opt_->isCostBetterThan(lhs.first, rhs.first);
1619 
1620  //If it's not, it could be equal
1621  if (lhsLTrhs == false)
1622  {
1623  //If RHS is also NOT less than LHS, than they're equal and we need to check the second key
1624  if (opt_->isCostBetterThan(rhs.first, lhs.first) == false)
1625  {
1626  //lhs == rhs
1627  //Compare their second values
1628  lhsLTrhs = opt_->isCostBetterThan( lhs.second, rhs.second );
1629  }
1630  //No else: lhs > rhs
1631  }
1632  //No else, lhs < rhs
1633 
1634  return lhsLTrhs;
1635  }
1636 
1637 
1638 
1639  bool BITstar::IntegratedQueue::isCostWorseThan(const ompl::base::Cost& a, const ompl::base::Cost& b) const
1640  {
1641  //If b is better than a, then a is worse than b
1642  return opt_->isCostBetterThan(b, a);
1643  }
1644 
1645 
1646 
1647  bool BITstar::IntegratedQueue::isCostNotEquivalentTo(const ompl::base::Cost& a, const ompl::base::Cost& b) const
1648  {
1649  //If a is better than b, or b is better than a, then they are not equal
1650  return opt_->isCostBetterThan(a,b) || opt_->isCostBetterThan(b,a);
1651  }
1652 
1653 
1654 
1655  bool BITstar::IntegratedQueue::isCostBetterThanOrEquivalentTo(const ompl::base::Cost& a, const ompl::base::Cost& b) const
1656  {
1657  //If b is not better than a, then a is better than, or equal to, b
1658  return !opt_->isCostBetterThan(b, a);
1659  }
1660 
1661 
1662 
1663  bool BITstar::IntegratedQueue::isCostWorseThanOrEquivalentTo(const ompl::base::Cost& a, const ompl::base::Cost& b) const
1664  {
1665  //If a is not better than b, than a is worse than, or equal to, b
1666  return !opt_->isCostBetterThan(a,b);
1667  }
1669 
1670 
1671 
1673  //Boring sets/gets (Public):
1675  {
1676  delayRewiring_ = delayRewiring;
1677  }
1678 
1679 
1680 
1682  {
1683  return delayRewiring_;
1684  }
1686  } // geometric
1687 } //ompl
std::function< ompl::base::Cost(const VertexConstPtr &)> VertexHeuristicFunc
A std::function definition of a heuristic function for a vertex.
void pruneEdgesTo(const VertexPtr &cVertex)
Prune edges in the edge queue that lead to the given vertex using the prune function.
void listVertices(std::vector< VertexConstPtr > *vertexQueue)
Get a copy of the vertices in the vertex queue that are left to be expanded. This is expensive and is...
ompl::base::OptimizationObjectivePtr opt_
Optimization objective copied from ProblemDefinition.
Definition: BITstar.h:525
void clear()
Clear the queue to the state of construction.
void setDelayedRewiring(bool delayRewiring)
Delay considering rewiring edges until an initial solution is found. This improves the time required ...
bool samplePruneCondition(const VertexPtr &vertex) const
The condition used to prune disconnected samples from the free set. Compares lowerBoundHeuristicVerte...
void markVertexUnsorted(const VertexPtr &vertex)
Mark the queue as requiring resorting downstream of the specified vertex.
std::pair< ompl::base::Cost, ompl::base::Cost > CostPair
A typedef for a pair of costs, i.e., the edge sorting key.
void eraseVertex(const VertexPtr &oldVertex, bool disconnectParent, const VertexPtrNNPtr &vertexNN, const VertexPtrNNPtr &freeStateNN, std::vector< VertexPtr > *recycledVertices)
Erase a vertex from the vertex expansion queue. Will disconnect the vertex from its parent and remove...
unsigned int numVertices() const
Returns the number of vertices left to expand. This has nontrivial cost, as the token must be moved t...
bool isCostWorseThanOrEquivalentTo(const ompl::base::Cost &a, const ompl::base::Cost &b) const
Compare whether cost a is worse or equivalent to cost b by checking that a is not better than b...
Definition: BITstar.cpp:1793
std::shared_ptr< NearestNeighbors< VertexPtr > > VertexPtrNNPtr
The OMPL::NearestNeighbors structure.
Definition: BITstar.h:137
bool edgePruneCondition(const VertexPtrPair &edge) const
The condition used to prune edge (i.e., vertex-pair) out of the queue. Compares lowerBoundHeuristicEd...
unsigned int numEdgesTo(const VertexPtr &cVertex) const
Get the number of edges in the queue pointing to a specific vertex.
std::function< ompl::base::Cost(const VertexConstPtrPair &)> EdgeHeuristicFunc
A std::function definition of a heuristic function for an edge.
bool hasSolution_
If we've found a solution yet.
Definition: BITstar.h:588
std::pair< unsigned int, unsigned int > resort(const VertexPtrNNPtr &vertexNN, const VertexPtrNNPtr &freeStateNN, std::vector< VertexPtr > *recycledVertices)
Resort the queue, only reinserting edges/vertices if their lower-bound heuristic is less then the thr...
unsigned int numEdges() const
Returns the number of edges in the queue.
bool isSorted() const
Return whether the queue is still sorted.
std::function< double(const VertexConstPtr &, const VertexConstPtr &)> DistanceFunc
A std::function definition for the distance between two vertices.
VertexPtr frontVertex()
Get the best vertex on the queue without incrementing the vertex queue.
void pruneEdgesFrom(const VertexPtr &pVertex)
Prune edges in the edge queue that leave from the given vertex using the prune function.
std::shared_ptr< const Vertex > VertexConstPtr
A constant vertex shared pointer.
Definition: BITstar.h:125
void insertEdge(const VertexPtrPair &newEdge)
Insert an edge into the edge processing queue. Edges are removed from the processing queue...
bool isCostBetterThanOrEquivalentTo(const ompl::base::Cost &a, const ompl::base::Cost &b) const
Compare whether cost a is better or equivalent to cost b by checking that b is not better than a...
Definition: BITstar.cpp:1785
bool isVertexExpanded(const VertexConstPtr &vertex) const
Returns whether a given vertex has been expanded or not.
CostPair frontEdgeValue()
Get the value of the best edge on the queue, leaving it on the edge queue.
VertexPtrPair frontEdge()
Get the best edge on the queue, leaving it on the edge queue.
bool isEmpty()
Returns true if the queue is empty. In the case where the edge queue is empty but the vertex queue is...
bool delayRewiring_
Whether to delay rewiring until a solution is found (param)
Definition: BITstar.h:661
Batch Informed Trees (BIT*)
Definition: BITstar.h:111
A queue of edges to be processed that integrates both the expansion of Vertices and the ordering of t...
void reset()
Reset the queue, clearing all the edge containers and moving the vertex expansion token to the start...
void setThreshold(const ompl::base::Cost &costThreshold)
Set the threshold of the queue.
unsigned int numEdgesFrom(const VertexPtr &pVertex) const
Get the number of edges in the queue coming from a specific vertex.
std::pair< VertexPtr, VertexPtr > VertexPtrPair
A pair of vertices, i.e., an edge.
Definition: BITstar.h:133
ompl::base::Cost getThreshold() const
Get the threshold of the queue.
VertexPtrPair popFrontEdge()
Pop the best edge off the queue, removing it from the edge queue in the process.
The exception type for ompl.
Definition: Exception.h:47
A shared pointer wrapper for ompl::base::OptimizationObjective.
IntegratedQueue(const ompl::base::OptimizationObjectivePtr &opt, const DistanceFunc &distanceFunc, const NeighbourhoodFunc &nearSamplesFunc, const NeighbourhoodFunc &nearVerticesFunc, const VertexHeuristicFunc &lowerBoundHeuristicVertex, const VertexHeuristicFunc &currentHeuristicVertex, const EdgeHeuristicFunc &lowerBoundHeuristicEdge, const EdgeHeuristicFunc &currentHeuristicEdge, const EdgeHeuristicFunc &currentHeuristicEdgeTarget)
Construct an integrated queue.
std::pair< unsigned int, unsigned int > prune(const VertexPtr &pruneStartPtr, const VertexPtrNNPtr &vertexNN, const VertexPtrNNPtr &freeStateNN, std::vector< VertexPtr > *recycledVertices)
Prune the vertex queue of vertices whose their lower-bound heuristic is greater then the threshold...
void removeEdgesFrom(const VertexPtr &pVertex)
Erase all edges in the edge queue that leave from the given vertex.
bool vertexPruneCondition(const VertexPtr &vertex) const
The condition used to prune vertices out of the queue. Compares lowerBoundHeuristicVertex to the give...
ompl::base::Cost frontVertexValue()
Get the value of the best vertex on the queue without incrementing the vertex queue.
void removeEdgesTo(const VertexPtr &cVertex)
Erase all edges in the edge queue that lead to the given vertex.
bool isCostWorseThan(const ompl::base::Cost &a, const ompl::base::Cost &b) const
Compare whether cost a is worse than cost b by checking whether b is better than a.
Definition: BITstar.cpp:1769
void listEdges(std::vector< std::pair< VertexConstPtr, VertexConstPtr > > *edgeQueue)
Get a copy of the edge queue. This is expensive and is only meant for animations/debugging.
void insertVertex(const VertexPtr &newVertex)
Insert a vertex into the vertex expansion queue. Vertices remain in the vertex queue until pruned or ...
std::function< unsigned int(const VertexPtr &, std::vector< VertexPtr > *)> NeighbourhoodFunc
A std::function definition for the neighbourhood of a vertex .
bool getDelayedRewiring() const
Get whether BIT* is delaying rewiring until a solution is found.
std::shared_ptr< Vertex > VertexPtr
A vertex shared pointer.
Definition: BITstar.h:120
bool isReset() const
Returns true if the queue is reset. This means that no edges have been expanded and the vertex expans...
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition: Cost.h:47
void hasSolution()
Mark that a solution has been found.
unsigned int VertexId
The vertex id type.
Definition: BITstar.h:131
void finish()
Finish the queue, clearing all the edge containers and moving the vertex expansion token to the end...