Main MRPT website > C++ reference
MRPT logo
dijkstra.h
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2014, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +---------------------------------------------------------------------------+ */
9 #ifndef MRPT_DIJKSTRA_H
10 #define MRPT_DIJKSTRA_H
11 
14 #include <mrpt/utils/traits_map.h>
15 #include <limits>
16 
17 namespace mrpt
18 {
19  namespace graphs
20  {
21  using namespace std;
22  using namespace mrpt::utils;
23 
24  /** The Dijkstra algorithm for finding the shortest path between a given source node in a (weighted) directed graph and all other nodes in the form of a tree.
25  * The constructor takes as input the graph (the set of directed edges) computes all the needed data, then
26  * successive calls to \a getShortestPathTo return the paths efficiently from the root.
27  * The entire generated tree can be also retrieved with \a getTreeGraph.
28  *
29  * Input graphs are represented by instances of (or classes derived from) mrpt::graphs::CDirectedGraph, and node's IDs are uint64_t values,
30  * although the type mrpt::utils::TNodeID is also provided for clarity in the code.
31  *
32  * The second template argument MAPS_IMPLEMENTATION allows choosing between a sparse std::map<> representation (using mrpt::utils::map_traits_stdmap)
33  * for several intermediary and final results, and an alternative (using mrpt::utils::map_traits_map_as_vector as argument)
34  * dense implementation which is much faster, but can be only used if the TNodeID's start in 0 or a low value.
35  *
36  * See <a href="http://www.mrpt.org/Example:Dijkstra_optimal_path_search_in_graphs" > this page </a> for a complete example.
37  * \ingroup mrpt_graphs_grp
38  */
39  template<class TYPE_GRAPH, class MAPS_IMPLEMENTATION = mrpt::utils::map_traits_stdmap >
40  class CDijkstra
41  {
42  protected:
43  /** Auxiliary struct for topological distances from root node */
44  struct TDistance
45  {
46  double dist;
47  inline TDistance() : dist( std::numeric_limits<double>::max() ) { }
48  inline TDistance(const double D) : dist(D) { }
49  inline const TDistance & operator =(const double D) { dist = D; return *this;}
50  };
51 
52  /** Auxiliary struct for backward paths */
53  struct TPrevious
54  {
55  inline TPrevious() : id( INVALID_NODEID ) { }
57  };
58 
59  // Cached input data:
60  const TYPE_GRAPH & m_cached_graph;
62 
63  // Private typedefs:
64  typedef typename MAPS_IMPLEMENTATION::template map<TNodeID, std::set<TNodeID> > list_all_neighbors_t; //!< A std::map (or a similar container according to MAPS_IMPLEMENTATION) with all the neighbors of every node.
65  typedef typename MAPS_IMPLEMENTATION::template map<TNodeID,TPairNodeIDs> id2pairIDs_map_t;
66  typedef typename MAPS_IMPLEMENTATION::template map<TNodeID,TDistance> id2dist_map_t;
67  typedef typename MAPS_IMPLEMENTATION::template map<TNodeID,TPrevious> id2id_map_t;
68 
69  // Intermediary and final results:
70  id2dist_map_t m_distances; //!< All the distances
71  std::map<TNodeID,TDistance> m_distances_non_visited; // Use a std::map here in all cases.
72  id2id_map_t m_prev_node;
73  id2pairIDs_map_t m_prev_arc;
74  std::set<TNodeID> m_lstNode_IDs;
75  list_all_neighbors_t m_allNeighbors;
76 
77  public:
78  /** @name Useful typedefs
79  @{ */
80 
81  typedef TYPE_GRAPH graph_t; //!< The type of the graph, typically a mrpt::graphs::CDirectedGraph<> or any other derived class
82  typedef typename graph_t::edge_t edge_t; //!< The type of edge data in graph_t
83  typedef std::list<TPairNodeIDs> edge_list_t; //!< A list of edges used to describe a path on the graph
84 
85  /** @} */
86 
87  /** Constructor, which takes the input graph and executes the entire Dijkstra algorithm from the given root node ID.
88  *
89  * The graph is given by the set of directed edges, stored in a mrpt::graphs::CDirectedGraph class.
90  *
91  * If a function \a functor_edge_weight is provided, it will be used to compute the weight of edges.
92  * Otherwise, all edges weight the unity.
93  *
94  * After construction, call \a getShortestPathTo to get the shortest path to a node or \a getTreeGraph for the tree representation.
95  *
96  * \sa getShortestPathTo, getTreeGraph
97  * \exception std::exception If the source nodeID is not found in the graph
98  */
100  const graph_t &graph,
101  const TNodeID source_node_ID,
102  double (*functor_edge_weight)(const graph_t& graph, const TNodeID id_from, const TNodeID id_to, const edge_t &edge) = NULL,
103  void (*functor_on_progress)(const graph_t& graph, size_t visitedCount) = NULL
104  )
105  : m_cached_graph(graph), m_source_node_ID(source_node_ID)
106  {
107  MRPT_START
108  /*
109  1 function Dijkstra(G, w, s)
110  2 for each vertex v in V[G] // Initializations
111  3 m_distances[v] := infinity
112  4 m_prev_node[v] := undefined
113  5 m_distances[s] := 0
114  6 S := empty set
115  7 Q := V[G]
116  8 while Q is not an empty set // The algorithm itself
117  9 u := Extract_Min(Q)
118  10 S := S union {u}
119  11 for each edge (u,v) outgoing from u
120  12 if m_distances[u] + w(u,v) < m_distances[v] // Relax (u,v)
121  13 m_distances[v] := m_distances[u] + w(u,v)
122  14 m_prev_node[v] := u
123  */
124 
125  // Makea list of all the nodes in the graph:
126  graph.getAllNodes( m_lstNode_IDs );
127  const size_t nNodes = m_lstNode_IDs.size();
128 
129  if ( m_lstNode_IDs.find(source_node_ID)==m_lstNode_IDs.end() )
130  THROW_EXCEPTION_CUSTOM_MSG1("Cannot find the source node_ID=%u in the graph",static_cast<unsigned int>(source_node_ID));
131 
132  // Init:
133  // m_distances: already initialized to infinity by default.
134  // m_prev_node: idem
135  // m_prev_arc: idem
136  // m_visited: idem
137  size_t visitedCount = 0;
138  m_distances [source_node_ID] = 0;
139  m_distances_non_visited[source_node_ID] = 0;
140 
141  // Precompute all neighbors:
142  graph.getAdjacencyMatrix(m_allNeighbors);
143 
144  TNodeID u;
145  do // The algorithm:
146  {
147  // Find the nodeID with the minimum known distance so far considered:
148  double min_d = std::numeric_limits<double>::max();
149  u = INVALID_NODEID;
150 
151  // No need to check if the min. distance node is not visited yet, since we
152  // keep two lists: m_distances_non_visited & m_distances
153  for (typename std::map<TNodeID,TDistance>::const_iterator itDist=m_distances_non_visited.begin();itDist!=m_distances_non_visited.end();++itDist)
154  {
155  if (itDist->second.dist < min_d)
156  {
157  u = itDist->first;
158  min_d = itDist->second.dist;
159  }
160  }
161  ASSERTMSG_(u!=INVALID_NODEID, "Graph is not fully connected!")
162 
163  // Save distance (for possible future reference...) and remove this node from "non-visited":
164  m_distances[u]=m_distances_non_visited[u];
165  m_distances_non_visited.erase(u);
166 
167  visitedCount++;
168 
169  // Let the user know about our progress...
170  if (functor_on_progress) (*functor_on_progress)(graph,visitedCount);
171 
172  // For each arc from "u":
173  const std::set<TNodeID> & neighborsOfU = m_allNeighbors[u]; //graph.getNeighborsOf(u,neighborsOfU);
174  for (std::set<TNodeID>::const_iterator itNei=neighborsOfU.begin();itNei!=neighborsOfU.end();++itNei)
175  {
176  const TNodeID i = *itNei;
177  if (i==u) continue; // ignore self-loops...
178 
179  // the "edge_ui" may be searched here or a bit later, so the "bool" var will tell us.
180  typename graph_t::const_iterator edge_ui;
181  bool edge_ui_reverse = false;
182  bool edge_ui_found = false;
183 
184  // Get weight of edge u<->i
185  double edge_ui_weight;
186  if (!functor_edge_weight)
187  edge_ui_weight = 1.;
188  else
189  { // edge may be i->u or u->i:
190  edge_ui = graph.edges.find( make_pair(u,i) );
191  if ( edge_ui==graph.edges.end() )
192  {
193  edge_ui = graph.edges.find( make_pair(i,u));
194  edge_ui_reverse = true;
195  }
196  ASSERT_(edge_ui!=graph.edges.end());
197  edge_ui_weight = (*functor_edge_weight)( graph, edge_ui->first.first,edge_ui->first.second, edge_ui->second );
198  edge_ui_found = true;
199  }
200 
201  if ( (min_d+edge_ui_weight) < m_distances[i].dist) // the [] creates the entry if needed
202  {
203  m_distances[i].dist = m_distances_non_visited[i].dist = min_d+edge_ui_weight;
204  m_prev_node[i].id = u;
205  // If still not done above, detect the direction of the arc now:
206  if (!edge_ui_found)
207  {
208  edge_ui = graph.edges.find( make_pair(u,i) );
209  if ( edge_ui==graph.edges.end() ) {
210  edge_ui = graph.edges.find( make_pair(i,u));
211  edge_ui_reverse = true;
212  }
213  ASSERT_(edge_ui!=graph.edges.end());
214  }
215 
216  if ( !edge_ui_reverse )
217  m_prev_arc[i] = make_pair(u,i); // *u -> *i
218  else m_prev_arc[i] = make_pair(i,u); // *i -> *u
219  }
220  }
221  } while ( visitedCount<nNodes );
222 
223  MRPT_END
224  } // end Dijkstra
225 
226 
227  /** @name Query Dijkstra results
228  @{ */
229 
230  /** Return the distance from the root node to any other node using the Dijkstra-generated tree \exception std::exception On unknown node ID
231  */
232  inline double getNodeDistanceToRoot(const TNodeID id) const {
233  typename id2dist_map_t::const_iterator it=m_distances.find(id);
234  if (it==m_distances.end()) THROW_EXCEPTION("Node was not found in the graph when running Dijkstra");
235  return it->second.dist;
236  }
237 
238  /** Return the set of all known node IDs (actually, a const ref to the internal set object). */
239  inline const std::set<TNodeID> & getListOfAllNodes() const {return m_lstNode_IDs;}
240 
241  /** Return the node ID of the tree root, as passed in the constructor */
242  inline TNodeID getRootNodeID() const { return m_source_node_ID; }
243 
244  /** Return the adjacency matrix of the input graph, which is cached at construction so if needed later just use this copy to avoid recomputing it \sa mrpt::graphs::CDirectedGraph::getAdjacencyMatrix */
245  inline const list_all_neighbors_t & getCachedAdjacencyMatrix() const { return m_allNeighbors; }
246 
247  /** Returns the shortest path between the source node passed in the constructor and the given target node.
248  * The reconstructed path contains a list of arcs (all of them exist in the graph with the given direction), such as the
249  * the first edge starts at the origin passed in the constructor, and the last one contains the given target.
250  *
251  * \note An empty list of edges is returned when target equals the source node.
252  * \sa getTreeGraph
253  */
255  const TNodeID target_node_ID,
256  edge_list_t &out_path
257  ) const
258  {
259  out_path.clear();
260  if (target_node_ID==m_source_node_ID) return;
261 
262  TNodeID nod = target_node_ID;
263  do
264  {
265  typename id2pairIDs_map_t::const_iterator it = m_prev_arc.find(nod);
266  ASSERT_(it!=m_prev_arc.end())
267 
268  out_path.push_front( it->second );
269  nod = m_prev_node.find(nod)->second.id;
270  } while (nod!=m_source_node_ID);
271 
272  } // end of getShortestPathTo
273 
274 
275  /** Type for graph returned by \a getTreeGraph: a graph like the original input graph, but with edge data being pointers to the original data (to save copy time & memory)
276  */
278 
279  /** Returns a tree representation of the graph, as determined by the Dijkstra shortest paths from the root node.
280  * Note that the annotations on each edge in the tree are "const pointers" to the original graph edge data, so
281  * it's mandatory for the original input graph not to be deleted as long as this tree is used.
282  * \sa getShortestPathTo
283  */
284  void getTreeGraph( tree_graph_t &out_tree ) const
285  {
286  typedef typename tree_graph_t::TEdgeInfo TreeEdgeInfo;
287 
288  out_tree.clear();
289  out_tree.root = m_source_node_ID;
290  for (typename id2pairIDs_map_t::const_iterator itArcs=m_prev_arc.begin();itArcs!=m_prev_arc.end();++itArcs)
291  { // For each saved arc in "m_prev_arc", recover the original data in the input graph and save it to the output tree structure.
292  const TNodeID id = itArcs->first;
293  const TNodeID id_from = itArcs->second.first;
294  const TNodeID id_to = itArcs->second.second;
295 
296  std::list<TreeEdgeInfo> &edges = out_tree.edges_to_children[id==id_from ? id_to : id_from];
297  TreeEdgeInfo newEdge;
298  newEdge.reverse = (id==id_from); // true: root towards leafs.
299  newEdge.id = id;
300  typename graph_t::edges_map_t::const_iterator itEdgeData = m_cached_graph.edges.find(make_pair(id_from,id_to));
301  ASSERTMSG_(itEdgeData!=m_cached_graph.edges.end(),format("Edge %u->%u is in Dijkstra paths but not in original graph!",static_cast<unsigned int>(id_from),static_cast<unsigned int>(id_to) ))
302  newEdge.data = & itEdgeData->second;
303  edges.push_back( newEdge );
304  }
305 
306  }// end getTreeGraph
307 
308 
309 
310  /** @} */
311 
312  }; // end class
313 
314  } // End of namespace
315 } // End of namespace
316 #endif
TNodeID getRootNodeID() const
Return the node ID of the tree root, as passed in the constructor.
Definition: dijkstra.h:242
MAPS_IMPLEMENTATION::template map< TNodeID, TDistance > id2dist_map_t
Definition: dijkstra.h:66
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
Definition: zip.h:16
Auxiliary struct for topological distances from root node.
Definition: dijkstra.h:44
TMapNode2ListEdges edges_to_children
The edges of each node.
Definition: CDirectedTree.h:50
A special kind of graph in the form of a tree with directed edges and optional edge annotations of te...
Definition: CDirectedTree.h:35
TYPE_GRAPH graph_t
The type of the graph, typically a mrpt::graphs::CDirectedGraph<> or any other derived class...
Definition: dijkstra.h:81
std::map< TNodeID, TDistance > m_distances_non_visited
Definition: dijkstra.h:71
void getTreeGraph(tree_graph_t &out_tree) const
Returns a tree representation of the graph, as determined by the Dijkstra shortest paths from the roo...
Definition: dijkstra.h:284
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
#define THROW_EXCEPTION(msg)
const std::set< TNodeID > & getListOfAllNodes() const
Return the set of all known node IDs (actually, a const ref to the internal set object).
Definition: dijkstra.h:239
STL namespace.
const Scalar * const_iterator
Definition: eigen_plugins.h:24
CDijkstra(const graph_t &graph, const TNodeID source_node_ID, double(*functor_edge_weight)(const graph_t &graph, const TNodeID id_from, const TNodeID id_to, const edge_t &edge)=NULL, void(*functor_on_progress)(const graph_t &graph, size_t visitedCount)=NULL)
Constructor, which takes the input graph and executes the entire Dijkstra algorithm from the given ro...
Definition: dijkstra.h:99
id2dist_map_t m_distances
All the distances.
Definition: dijkstra.h:70
const list_all_neighbors_t & getCachedAdjacencyMatrix() const
Return the adjacency matrix of the input graph, which is cached at construction so if needed later ju...
Definition: dijkstra.h:245
MAPS_IMPLEMENTATION::template map< TNodeID, TPairNodeIDs > id2pairIDs_map_t
Definition: dijkstra.h:65
const TNodeID m_source_node_ID
Definition: dijkstra.h:61
#define MRPT_END
void getShortestPathTo(const TNodeID target_node_ID, edge_list_t &out_path) const
Returns the shortest path between the source node passed in the constructor and the given target node...
Definition: dijkstra.h:254
id2pairIDs_map_t m_prev_arc
Definition: dijkstra.h:73
TNodeID root
The root of the tree.
Definition: CDirectedTree.h:49
MAPS_IMPLEMENTATION::template map< TNodeID, std::set< TNodeID > > list_all_neighbors_t
A std::map (or a similar container according to MAPS_IMPLEMENTATION) with all the neighbors of every ...
Definition: dijkstra.h:64
double getNodeDistanceToRoot(const TNodeID id) const
Return the distance from the root node to any other node using the Dijkstra-generated tree On unknown...
Definition: dijkstra.h:232
MAPS_IMPLEMENTATION::template map< TNodeID, TPrevious > id2id_map_t
Definition: dijkstra.h:67
list_all_neighbors_t m_allNeighbors
Definition: dijkstra.h:75
#define MRPT_START
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
uint64_t TNodeID
The type for node IDs in graphs of different types.
id2id_map_t m_prev_node
Definition: dijkstra.h:72
std::list< TPairNodeIDs > edge_list_t
A list of edges used to describe a path on the graph.
Definition: dijkstra.h:83
#define ASSERT_(f)
CDirectedTree< const edge_t * > tree_graph_t
Type for graph returned by getTreeGraph: a graph like the original input graph, but with edge data be...
Definition: dijkstra.h:277
std::set< TNodeID > m_lstNode_IDs
Definition: dijkstra.h:74
The Dijkstra algorithm for finding the shortest path between a given source node in a (weighted) dire...
Definition: dijkstra.h:40
const TYPE_GRAPH & m_cached_graph
Definition: dijkstra.h:60
Auxiliary struct for backward paths.
Definition: dijkstra.h:53
void clear()
Empty all edge data and set "root" to INVALID_NODEID.
Definition: CDirectedTree.h:57
graph_t::edge_t edge_t
The type of edge data in graph_t.
Definition: dijkstra.h:82
#define ASSERTMSG_(f, __ERROR_MSG)
#define THROW_EXCEPTION_CUSTOM_MSG1(msg, param1)
#define INVALID_NODEID



Page generated by Doxygen 1.8.8 for MRPT 1.2.2 SVN:Unversioned directory at Tue Oct 14 02:14:08 UTC 2014