LEMUR Packages: ompl_lemur or_lemur pr_bgl prpy_lemur
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Groups Pages
incbi.h
Go to the documentation of this file.
1 
9 namespace pr_bgl
10 {
11 
40 template <class Graph,
41  class StartPredecessorMap,
42  class StartDistanceMap, class StartDistanceLookaheadMap,
43  class GoalSuccessorMap,
44  class GoalDistanceMap, class GoalDistanceLookaheadMap,
45  class WeightMap,
46  class VertexIndexMap, class EdgeIndexMap,
47  typename CompareFunction, typename CombineFunction,
48  typename CostInf, typename CostZero,
49  class IncBiVisitor, class IncBiBalancer>
50 class incbi
51 {
52 public:
53 
54  typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
55  typedef typename boost::graph_traits<Graph>::vertex_iterator VertexIter;
56  typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
57  typedef typename boost::graph_traits<Graph>::out_edge_iterator OutEdgeIter;
58  typedef typename boost::graph_traits<Graph>::in_edge_iterator InEdgeIter;
59  typedef typename boost::property_traits<WeightMap>::value_type weight_type;
60 
61  struct conn_key
62  {
63  weight_type path_length;
64  weight_type start_dist;
65  weight_type goal_dist;
66  conn_key():
67  path_length(weight_type()), start_dist(weight_type()), goal_dist(weight_type())
68  {
69  }
70  conn_key(weight_type path_length, weight_type start_dist, weight_type goal_dist):
71  path_length(path_length), start_dist(start_dist), goal_dist(goal_dist)
72  {
73  }
74  bool operator<(const conn_key & rhs) const
75  {
76  return path_length < rhs.path_length;
77  }
78  bool operator>(const conn_key & rhs) const
79  {
80  return path_length > rhs.path_length;
81  }
82  bool operator<=(const conn_key & rhs) const
83  {
84  return path_length <= rhs.path_length;
85  }
86  };
87 
88  const Graph & g;
89  Vertex v_start;
90  Vertex v_goal;
91  StartPredecessorMap start_predecessor;
92  StartDistanceMap start_distance;
93  StartDistanceLookaheadMap start_distance_lookahead;
94  GoalSuccessorMap goal_successor;
95  GoalDistanceMap goal_distance;
96  GoalDistanceLookaheadMap goal_distance_lookahead;
97  WeightMap weight;
98  VertexIndexMap vertex_index_map;
99  EdgeIndexMap edge_index_map;
100  CompareFunction compare;
101  CombineFunction combine;
102  CostInf inf;
103  CostZero zero;
104  weight_type goal_margin;
105  IncBiVisitor vis;
106  IncBiBalancer balancer;
107 
108  // these contain all inconsistent vertices
109  heap_indexed< weight_type > start_queue;
110  heap_indexed< weight_type > goal_queue;
111 
112  // contains the indices of all edges connecting one start-tree vertex to one goal-tree vertex
113  // that are both consistent, sorted by start_distance + edge_weight + goal_distance
114  // infinite-length prospective paths are not in queue at all
115  heap_indexed< conn_key > conn_queue;
116 
117  incbi(
118  const Graph & g,
119  Vertex v_start, Vertex v_goal,
120  StartPredecessorMap start_predecessor,
121  StartDistanceMap start_distance, StartDistanceLookaheadMap start_distance_lookahead,
122  GoalSuccessorMap goal_successor,
123  GoalDistanceMap goal_distance, GoalDistanceLookaheadMap goal_distance_lookahead,
124  WeightMap weight,
125  VertexIndexMap vertex_index_map,
126  EdgeIndexMap edge_index_map,
127  CompareFunction compare, CombineFunction combine,
128  CostInf inf, CostZero zero,
129  weight_type goal_margin,
130  IncBiVisitor vis,
131  IncBiBalancer balancer):
132  g(g), v_start(v_start), v_goal(v_goal),
133  start_predecessor(start_predecessor),
134  start_distance(start_distance),
135  start_distance_lookahead(start_distance_lookahead),
136  goal_successor(goal_successor),
137  goal_distance(goal_distance),
138  goal_distance_lookahead(goal_distance_lookahead),
139  weight(weight),
140  vertex_index_map(vertex_index_map),
141  edge_index_map(edge_index_map),
142  compare(compare), combine(combine),
143  inf(inf), zero(zero),
144  goal_margin(goal_margin),
145  vis(vis), balancer(balancer)
146  {
147  reset();
148  }
149 
150  void reset()
151  {
152  VertexIter vi, vi_end;
153  for (boost::tie(vi,vi_end)=vertices(g); vi!=vi_end; ++vi)
154  {
155  put(start_distance_lookahead, *vi, inf);
156  put(start_distance, *vi, inf);
157  put(goal_distance_lookahead, *vi, inf);
158  put(goal_distance, *vi, inf);
159  }
160  put(start_distance_lookahead, v_start, zero);
161  put(goal_distance_lookahead, v_goal, zero);
162  start_queue.reset();
163  start_queue.insert(get(vertex_index_map,v_start), zero);
164  vis.start_queue_insert(v_start);
165  goal_queue.reset();
166  goal_queue.insert(get(vertex_index_map,v_goal), zero);
167  vis.goal_queue_insert(v_goal);
168  conn_queue.reset();
169  }
170 
171  inline weight_type start_calculate_key(Vertex u)
172  {
173  return std::min(get(start_distance,u), get(start_distance_lookahead,u));
174  }
175 
176  inline weight_type goal_calculate_key(Vertex u)
177  {
178  return std::min(get(goal_distance,u), get(goal_distance_lookahead,u));
179  }
180 
181  // this must be called when an edge's cost changes
182  // in case it should be added/removed from the connection queue
183  void update_edge(Edge e)
184  {
185  // should this edge be our connection queue?
186  size_t eidx = get(edge_index_map, e);
187  weight_type elen = get(weight, e);
188  Vertex va = source(e,g);
189  Vertex vb = target(e,g);
190  // should it be in the queue?
191  bool is_valid = false;
192  do
193  {
194  if (elen == inf) break;
195  if (start_queue.contains(get(vertex_index_map,va))) break;
196  if (goal_queue.contains(get(vertex_index_map,vb))) break;
197  if (get(start_distance,va) == inf) break;
198  if (get(goal_distance,vb) == inf) break;
199  is_valid = true;
200  }
201  while (0);
202  // should we remove it?
203  if (!is_valid)
204  {
205  if (conn_queue.contains(eidx))
206  {
207  conn_queue.remove(eidx);
208  vis.conn_queue_remove(e);
209  }
210  }
211  else
212  {
213  // ok, edge should be there!
214  weight_type pathlen = combine(combine(get(start_distance,va), elen), get(goal_distance,vb));
215  conn_key new_key(pathlen, get(start_distance,va), get(goal_distance,vb));
216  if (conn_queue.contains(eidx))
217  {
218  conn_queue.update(eidx, new_key);
219  vis.conn_queue_update(e);
220  }
221  else
222  {
223  conn_queue.insert(eidx, new_key);
224  vis.conn_queue_insert(e);
225  }
226  }
227  }
228 
229  // this is called to update vertex v due to either:
230  // - u_dist being updated OR
231  // - uv_weight being updated
232  // it will recalculate v's lookahead distance
233  // and return whether v's lookahead distance changed
234  // (if predecessor changed, but lookahead value didnt, return false)
235  inline bool start_update_predecessor(Vertex u, Vertex v, double uv_weight)
236  {
237  // start vertex dist lookahead is always zero
238  if (v == v_start)
239  return false;
240 
241  // current predecessor and lookahead value
242  Vertex v_pred = get(start_predecessor, v);
243  weight_type v_look_old = get(start_distance_lookahead, v);
244  weight_type v_look_u = combine(get(start_distance,u), uv_weight);
245 
246  if (v_pred == u) // u was previously relied upon
247  {
248  // if dist through u decreased, then u is still best; just update value
249  if (v_look_u == v_look_old)
250  {
251  return false;
252  }
253  else if (v_look_u < v_look_old)
254  {
255  put(start_distance_lookahead, v, v_look_u);
256  return true;
257  }
258  else // dist through u increased
259  {
260  // so we need to search for a potentially new best predecessessor
261  weight_type v_look_best = inf;
262  Vertex v_pred_best;
263  InEdgeIter ei, ei_end;
264  for (boost::tie(ei,ei_end)=in_edges(v,g); ei!=ei_end; ei++)
265  {
266  weight_type v_look_uu = combine(get(start_distance,source(*ei,g)), get(weight,*ei));
267  if (v_look_uu < v_look_best)
268  {
269  v_look_best = v_look_uu;
270  v_pred_best = source(*ei,g);
271  }
272  }
273  if (v_look_best != inf)
274  put(start_predecessor, v, v_pred_best);
275  if (v_look_best == v_look_old)
276  {
277  return false;
278  }
279  else
280  {
281  put(start_distance_lookahead, v, v_look_best);
282  return true;
283  }
284  }
285  }
286  else // some other (existing) predecessor was used by v
287  {
288  if (v_look_u < v_look_old) // dist through u is better
289  {
290  put(start_predecessor, v, u);
291  put(start_distance_lookahead, v, v_look_u);
292  return true;
293  }
294  else // u is not better
295  {
296  return false;
297  }
298  }
299  }
300 
301  // this must be called called when u's dist and/or lookahead dist
302  // (and therefore consistency) may have been changed
303  // this ensures u is in the right queues
304  inline void start_update_vertex(Vertex u)
305  {
306  weight_type u_dist = get(start_distance,u);
307  bool is_consistent = (u_dist == get(start_distance_lookahead,u));
308  size_t u_idx = get(vertex_index_map,u);
309  if (is_consistent)
310  {
311  if (start_queue.contains(u_idx))
312  {
313  start_queue.remove(u_idx);
314  vis.start_queue_remove(u);
315  // we're newly consistent, so insert any new conn_queue edges from us
316  if (u_dist != inf)
317  {
318  OutEdgeIter ei, ei_end;
319  for (boost::tie(ei,ei_end)=out_edges(u,g); ei!=ei_end; ei++)
320  {
321  Vertex v = target(*ei,g);
322  size_t v_idx = get(vertex_index_map, v);
323 
324  weight_type v_goaldist = get(goal_distance,v);
325  if (!goal_queue.contains(v_idx) && v_goaldist != inf && get(weight,*ei) != inf)
326  {
327  conn_key new_key(combine(combine(u_dist, get(weight,*ei)), v_goaldist),
328  u_dist, v_goaldist);
329  conn_queue.insert(get(edge_index_map,*ei), new_key);
330  vis.conn_queue_insert(*ei);
331  }
332  }
333  }
334  }
335  }
336  else // not consistent
337  {
338  if (start_queue.contains(u_idx))
339  {
340  start_queue.update(u_idx, start_calculate_key(u));
341  vis.start_queue_update(u);
342  }
343  else
344  {
345  start_queue.insert(u_idx, start_calculate_key(u));
346  vis.start_queue_insert(u);
347  // we're newly inconsistent, so remove any conn_queue edges from us
348  OutEdgeIter ei, ei_end;
349  for (boost::tie(ei,ei_end)=out_edges(u,g); ei!=ei_end; ei++)
350  {
351  size_t edge_index = get(edge_index_map,*ei);
352  if (conn_queue.contains(edge_index))
353  {
354  conn_queue.remove(edge_index);
355  vis.conn_queue_remove(*ei);
356  }
357  }
358  }
359  }
360  }
361 
362  // this is called to update vertex u due to either:
363  // - v_dist being updated OR
364  // - uv_weight being updated
365  // it will recalculate u's lookahead distance
366  // and return whether u's lookahead distance changed
367  // (if predecessor changed, but lookahead value didnt, return false)
368  inline bool goal_update_successor(Vertex u, Vertex v, double uv_weight)
369  {
370  // goal vertex dist lookahead is always zero
371  if (u == v_goal)
372  return false;
373 
374  // current successor and lookahead value
375  Vertex u_succ = get(goal_successor, u);
376  weight_type u_look_old = get(goal_distance_lookahead, u);
377  weight_type u_look_v = combine(uv_weight, get(goal_distance,v));
378 
379  if (u_succ == v) // v was previously relied upon
380  {
381  // if dist through v decreased, then v is still best; just update value
382  if (u_look_v == u_look_old)
383  {
384  return false;
385  }
386  else if (u_look_v < u_look_old)
387  {
388  put(goal_distance_lookahead, u, u_look_v);
389  return true;
390  }
391  else // dist through v increased
392  {
393  // so we need to search for a potentially new best successor
394  weight_type u_look_best = inf;
395  Vertex u_succ_best;
396  OutEdgeIter ei, ei_end;
397  for (boost::tie(ei,ei_end)=out_edges(u,g); ei!=ei_end; ei++)
398  {
399  weight_type u_look_vv = combine(get(weight,*ei), get(goal_distance,target(*ei,g)));
400  if (u_look_vv < u_look_best)
401  {
402  u_look_best = u_look_vv;
403  u_succ_best = target(*ei,g);
404  }
405  }
406  if (u_look_best != inf)
407  put(goal_successor, u, u_succ_best);
408  if (u_look_best == u_look_old)
409  {
410  return false;
411  }
412  else
413  {
414  put(goal_distance_lookahead, u, u_look_best);
415  return true;
416  }
417  }
418  }
419  else // some other (existing) successor was used by u
420  {
421  if (u_look_v < u_look_old) // dist through v is better
422  {
423  put(goal_successor, u, v);
424  put(goal_distance_lookahead, u, u_look_v);
425  return true;
426  }
427  else // v is not better
428  {
429  return false;
430  }
431  }
432  }
433 
434  // this must be called called when u's dist and/or lookahead dist
435  // (and therefore consistency) may have been changed
436  // this ensures v is in the right queues
437  inline void goal_update_vertex(Vertex v)
438  {
439  weight_type v_dist = get(goal_distance,v);
440  bool is_consistent = (v_dist == get(goal_distance_lookahead,v));
441  size_t v_idx = get(vertex_index_map,v);
442  if (is_consistent)
443  {
444  if (goal_queue.contains(v_idx))
445  {
446  goal_queue.remove(v_idx);
447  vis.goal_queue_remove(v);
448  // we're newly consistent, so insert any new conn_queue edges to us
449  if (v_dist != inf)
450  {
451  InEdgeIter ei, ei_end;
452  for (boost::tie(ei,ei_end)=in_edges(v,g); ei!=ei_end; ei++)
453  {
454  Vertex u = source(*ei,g);
455  size_t u_idx = get(vertex_index_map, u);
456 
457  weight_type u_startdist = get(start_distance,u);
458  if (!start_queue.contains(u_idx) && u_startdist != inf && get(weight,*ei) != inf)
459  {
460  conn_key new_key(combine(combine(u_startdist, get(weight,*ei)), v_dist),
461  u_startdist, v_dist);
462  conn_queue.insert(get(edge_index_map,*ei), new_key);
463  vis.conn_queue_insert(*ei);
464  }
465  }
466  }
467  }
468  }
469  else // not consistent
470  {
471  if (goal_queue.contains(v_idx))
472  {
473  goal_queue.update(v_idx, goal_calculate_key(v));
474  vis.goal_queue_update(v);
475  }
476  else
477  {
478  goal_queue.insert(v_idx, goal_calculate_key(v));
479  vis.goal_queue_insert(v);
480  // we're newly inconsistent, so remove any conn_queue edges to us
481  InEdgeIter ei, ei_end;
482  for (boost::tie(ei,ei_end)=in_edges(v,g); ei!=ei_end; ei++)
483  {
484  size_t edge_index = get(edge_index_map,*ei);
485  if (conn_queue.contains(edge_index))
486  {
487  conn_queue.remove(edge_index);
488  vis.conn_queue_remove(*ei);
489  }
490  }
491  }
492  }
493  }
494 
495  // returns index of middle edge, and bool for success
496  std::pair<size_t,bool> compute_shortest_path()
497  {
498  for (;;)
499  {
500  weight_type start_top = start_queue.size() ? start_queue.top_key() : inf;
501  weight_type goal_top = goal_queue.size() ? goal_queue.top_key() : inf;
502 
503  vis.begin_iteration();
504 
505  // no-path termination
506  if (!start_queue.size() && !goal_queue.size())
507  return std::make_pair(0, false);
508  if (!start_queue.size() && get(start_distance,v_goal) == inf)
509  return std::make_pair(0, false);
510  if (!goal_queue.size() && get(goal_distance,v_start) == inf)
511  return std::make_pair(0, false);
512 
513  // has-path termination condition is rather complicated!
514  do
515  {
516  if (!conn_queue.size()) break;
517  if (combine(conn_queue.top_key().path_length,goal_margin) > combine(start_top,goal_top)) break;
518  if (combine(conn_queue.top_key().start_dist,goal_margin) > start_top) break;
519  if (combine(conn_queue.top_key().goal_dist,goal_margin) > goal_top) break;
520  return std::make_pair(conn_queue.top_idx(), true);
521  }
522  while (0);
523 
524  bool do_goal =
525  start_queue.contains(v_start) ? false :
526  goal_queue.contains(v_goal) ? true :
527  balancer(start_top,goal_top,start_queue.size(),goal_queue.size());
528 
529  if (do_goal == false)
530  {
531  if (!start_queue.size())
532  return std::make_pair(0, false);
533 
534  Vertex u = vertex(start_queue.top_idx(), g);
535 
536  vis.examine_vertex_start(u);
537 
538  start_queue.remove_min();
539  vis.start_queue_remove(u);
540  if (get(start_distance,u) > get(start_distance_lookahead,u))
541  {
542  weight_type u_sdist = get(start_distance_lookahead,u);
543  put(start_distance, u, u_sdist);
544 
545  // vertex u is newly start-consistent
546 
547  // update any successors that they may now be inconsistent
548  // also, this start vertex just became consistent,
549  // so add any out_edges to consistent goal-tree vertices
550  // to conn queue
551  OutEdgeIter ei, ei_end;
552  for (boost::tie(ei,ei_end)=out_edges(u,g); ei!=ei_end; ei++)
553  {
554  Vertex v = target(*ei,g);
555  size_t v_idx = get(vertex_index_map, v);
556 
557  double uv_weight = get(weight,*ei);
558  bool lookahead_changed = start_update_predecessor(u, v, uv_weight);
559  if (lookahead_changed)
560  start_update_vertex(v);
561 
562  weight_type v_tdist = get(goal_distance,v);
563  if (u_sdist != inf && !goal_queue.contains(v_idx) && v_tdist != inf && uv_weight != inf)
564  {
565  conn_key new_key(combine(combine(u_sdist, uv_weight), v_tdist), u_sdist, v_tdist);
566  conn_queue.insert(get(edge_index_map,*ei), new_key);
567  vis.conn_queue_insert(*ei);
568  }
569  }
570  }
571  else
572  {
573  put(start_distance, u, inf);
574  start_update_vertex(u);
575  OutEdgeIter ei, ei_end;
576  for (boost::tie(ei,ei_end)=out_edges(u,g); ei!=ei_end; ei++)
577  {
578  Vertex v = target(*ei,g);
579 
580  double uv_weight = get(weight,*ei);
581  bool lookahead_changed = start_update_predecessor(u, v, uv_weight);
582  if (lookahead_changed)
583  start_update_vertex(v);
584  }
585  }
586  }
587  else
588  {
589  if (!goal_queue.size())
590  return std::make_pair(0, false);
591 
592  Vertex v = vertex(goal_queue.top_idx(), g);
593 
594  vis.examine_vertex_goal(v);
595 
596  goal_queue.remove_min();
597  vis.goal_queue_remove(v);
598  if (get(goal_distance,v) > get(goal_distance_lookahead,v))
599  {
600  weight_type v_tdist = get(goal_distance_lookahead,v);
601  put(goal_distance, v, v_tdist);
602 
603  // vertex v is newly goal-consistent
604 
605  // update any predecessors that they may now be inconsistent
606  // also, this goal vertex just became consistent,
607  // so add any in_edges from consistent start-tree vertices
608  InEdgeIter ei, ei_end;
609  for (boost::tie(ei,ei_end)=in_edges(v,g); ei!=ei_end; ei++)
610  {
611  Vertex u = source(*ei,g);
612  size_t u_idx = get(vertex_index_map, u);
613 
614  double uv_weight = get(weight,*ei);
615  bool lookahead_changed = goal_update_successor(u, v, uv_weight);
616  if (lookahead_changed)
617  goal_update_vertex(u);
618 
619  weight_type u_sdist = get(start_distance,u);
620  if (v_tdist != inf && !start_queue.contains(u_idx) && u_sdist != inf && uv_weight != inf)
621  {
622  conn_key new_key(combine(combine(u_sdist, uv_weight), v_tdist), u_sdist, v_tdist);
623  conn_queue.insert(get(edge_index_map,*ei), new_key);
624  vis.conn_queue_insert(*ei);
625  }
626  }
627  }
628  else
629  {
630  put(goal_distance, v, inf);
631  goal_update_vertex(v);
632  InEdgeIter ei, ei_end;
633  for (boost::tie(ei,ei_end)=in_edges(v,g); ei!=ei_end; ei++)
634  {
635  Vertex u = source(*ei,g);
636 
637  double uv_weight_new = get(weight,*ei);
638  bool lookahead_changed = goal_update_successor(u, v, uv_weight_new);
639  if (lookahead_changed)
640  goal_update_vertex(u);
641  }
642  }
643  }
644  }
645  }
646 
647 };
648 
649 template <class Graph>
651 {
652 public:
653  typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
654  typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
655  inline void begin_iteration() {}
656  inline void examine_vertex_start(Vertex v) {}
657  inline void examine_vertex_goal(Vertex v) {}
658  inline void start_queue_insert(Vertex v) {}
659  inline void start_queue_update(Vertex v) {}
660  inline void start_queue_remove(Vertex v) {}
661  inline void goal_queue_insert(Vertex v) {}
662  inline void goal_queue_update(Vertex v) {}
663  inline void goal_queue_remove(Vertex v) {}
664  inline void conn_queue_insert(Edge e) {}
665  inline void conn_queue_update(Edge e) {}
666  inline void conn_queue_remove(Edge e) {}
667 };
668 
672 template <typename Vertex, typename weight_type>
674 {
675  const double goalfrac;
676  incbi_balancer_distance(double goalfrac): goalfrac(goalfrac) {}
677  bool operator()(
678  weight_type start_top, weight_type goal_top,
679  size_t start_queuesize, size_t goal_queuesize) const
680  {
681  return ((1.0-goalfrac)*goal_top < (goalfrac)*start_top);
682  }
683 };
684 
689 template <typename Vertex, typename weight_type>
691 {
692  const double goalfrac;
693  incbi_balancer_cardinality(double goalfrac): goalfrac(goalfrac) {}
694  bool operator()(
695  weight_type start_top, weight_type goal_top,
696  size_t start_queuesize, size_t goal_queuesize) const
697  {
698  return ((1.0-goalfrac)*goal_queuesize < (goalfrac)*start_queuesize);
699  }
700 };
701 
702 } // namespace pr_bgl
Definition: incbi.h:650
Definition: incbi.h:61
This class implements incremental bidirectional Dijkstra's search for the single-pair shortest path p...
Definition: incbi.h:50
Balance expansions to the side with the smallest OPEN set cardinality.
Definition: incbi.h:690
Balance expansions to the side with the shortest distance.
Definition: incbi.h:673