Main MRPT website > C++ reference for MRPT 1.9.9
CDirectedGraph.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-2017, 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_DIRECTEDGRAPH_H
10 #define MRPT_DIRECTEDGRAPH_H
11 
12 #include <mrpt/utils/utils_defs.h>
13 #include <mrpt/utils/TTypeName.h>
15 #include <set>
16 #include <map>
17 #include <fstream>
18 
19 namespace mrpt
20 {
21 namespace graphs
22 {
23 /** Make available this typedef in this namespace too */
25 /** Make available this typedef in this namespace too */
27 
28 /** \addtogroup mrpt_graphs_grp
29  @{ */
30 
31 /** Used in mrpt::graphs export functions to .dot files \sa
32  * mrpt::graphs::CDirectedGraph::saveAsDot */
34 {
35  /** If true (default=false), an "[constraint=false]" will be added to all
36  * edges (see Graphviz docs). */
38  /** If provided, these textual names will be used for naming the nodes
39  * instead of their numeric IDs given in the edges. */
40  std::map<TNodeID, std::string> node_names;
41  /** If provided, an extra line will be added setting Graphviz properties for
42  * each node, e.g. to set a node position, use the string "pos = \"x,y\"" */
43  std::map<TNodeID, std::string> node_props;
44 
46 };
47 
48 namespace detail
49 {
50 /** An empty structure */
52 {
53 };
54 }
55 
56 /** A directed graph with the argument of the template specifying the type of
57  * the annotations in the edges.
58  * This class only keeps a list of edges (in the member \a edges), so there is
59  * no information stored for each node but its existence referred by a node_ID.
60  *
61  * Note that edges are stored as a std::multimap<> to allow <b>multiple
62  * edges</b> between the same pair of nodes.
63  *
64  * \sa mrpt::graphs::CDijkstra, mrpt::graphs::CNetworkOfPoses,
65  * mrpt::graphs::CDirectedTree
66  * \ingroup mrpt_graphs_grp
67  */
68 template <class TYPE_EDGES,
69  class EDGE_ANNOTATIONS = detail::edge_annotations_empty>
71 {
72  public:
73  /** The type of each global pose in \a nodes: an extension of the \a
74  * TYPE_EDGES pose with any optional user-defined data */
75  struct edge_t : public TYPE_EDGES, public EDGE_ANNOTATIONS
76  {
77  // Replicate possible constructors:
78  inline edge_t() : TYPE_EDGES() {}
79  template <typename ARG1>
80  inline edge_t(const ARG1& a1) : TYPE_EDGES(a1)
81  {
82  }
83  template <typename ARG1, typename ARG2>
84  inline edge_t(const ARG1& a1, const ARG2& a2) : TYPE_EDGES(a1, a2)
85  {
86  }
87  };
88 
89  /** The type of the member \a edges */
92  typedef typename edges_map_t::iterator iterator;
93  typedef typename edges_map_t::reverse_iterator reverse_iterator;
95  typedef typename edges_map_t::const_reverse_iterator const_reverse_iterator;
96  /**\brief Handy self type */
98 
99  /** The public member with the directed edges in the graph */
101 
102  /** Copy constructor from a multimap<pair< >, > */
103  inline CDirectedGraph(const edges_map_t& obj) : edges(obj) {}
104  /** Default constructor */
105  inline CDirectedGraph() : edges() {}
106  inline iterator begin() { return edges.begin(); }
107  inline iterator rbegin() { return edges.rbegin(); }
108  inline iterator end() { return edges.end(); }
109  inline iterator rend() { return edges.rend(); }
110  inline const_iterator begin() const { return edges.begin(); }
111  inline const_iterator rbegin() const { return edges.rbegin(); }
112  inline const_iterator end() const { return edges.end(); }
113  inline const_iterator rend() const { return edges.rend(); }
114  /** @name Edges/nodes utility methods
115  @{ */
116 
117  /** The number of edges in the graph */
118  inline size_t edgeCount() const { return edges.size(); }
119  /** Erase all edges */
120  inline void clearEdges() { edges.clear(); }
121  /** Insert an edge (from -> to) with the given edge value. \sa
122  * insertEdgeAtEnd */
123  inline void insertEdge(
124  TNodeID from_nodeID, TNodeID to_nodeID, const edge_t& edge_value)
125  {
126  alignas(16) typename edges_map_t::value_type entry(
127  std::make_pair(from_nodeID, to_nodeID), edge_value);
128  edges.insert(entry);
129  }
130 
131  /** Insert an edge (from -> to) with the given edge value (more efficient
132  * version to be called if you know that the end will go at the end of the
133  * sorted std::multimap). \sa insertEdge */
134  inline void insertEdgeAtEnd(
135  TNodeID from_nodeID, TNodeID to_nodeID, const edge_t& edge_value)
136  {
137  alignas(16) typename edges_map_t::value_type entry(
138  std::make_pair(from_nodeID, to_nodeID), edge_value);
139  edges.insert(edges.end(), entry);
140  }
141 
142  /** Test if the given directed edge exists. */
143  inline bool edgeExists(TNodeID from_nodeID, TNodeID to_nodeID) const
144  {
145  return edges.find(std::make_pair(from_nodeID, to_nodeID)) !=
146  edges.end();
147  }
148 
149  /** Return a reference to the content of a given edge.
150  * If several edges exist between the given nodes, the first one is
151  * returned.
152  * \exception std::exception if the given edge does not exist
153  * \sa getEdges
154  */
155  edge_t& getEdge(TNodeID from_nodeID, TNodeID to_nodeID)
156  {
157  iterator it = edges.find(std::make_pair(from_nodeID, to_nodeID));
158  if (it == edges.end())
160  format(
161  "Edge %u->%u does not exist", (unsigned)from_nodeID,
162  (unsigned)to_nodeID))
163  else
164  return it->second;
165  }
166 
167  /** Return a reference to the content of a given edge.
168  * If several edges exist between the given nodes, the first one is
169  * returned.
170  * \exception std::exception if the given edge does not exist
171  * \sa getEdges
172  */
173  const edge_t& getEdge(TNodeID from_nodeID, TNodeID to_nodeID) const
174  {
175  const_iterator it = edges.find(std::make_pair(from_nodeID, to_nodeID));
176  if (it == edges.end())
178  format(
179  "Edge %u->%u does not exist", (unsigned)from_nodeID,
180  (unsigned)to_nodeID))
181  else
182  return it->second;
183  }
184 
185  /** Return a pair<first,last> of iterators to the range of edges between two
186  * given nodes. \sa getEdge */
187  std::pair<iterator, iterator> getEdges(
188  TNodeID from_nodeID, TNodeID to_nodeID)
189  {
190  return edges.equal_range(std::make_pair(from_nodeID, to_nodeID));
191  }
192  /** Return a pair<first,last> of const iterators to the range of edges
193  * between two given nodes. \sa getEdge */
194  std::pair<const_iterator, const_iterator> getEdges(
195  TNodeID from_nodeID, TNodeID to_nodeID) const
196  {
197  return edges.equal_range(std::make_pair(from_nodeID, to_nodeID));
198  }
199 
200  /** Erase all edges between the given nodes (it has no effect if no edge
201  * existed)
202  */
203  inline void eraseEdge(TNodeID from_nodeID, TNodeID to_nodeID)
204  {
205  edges.erase(std::make_pair(from_nodeID, to_nodeID));
206  }
207 
208  /** Return a list of all the node_ID's of the graph, generated from all the
209  * nodes that appear in the list of edges
210  */
211  void getAllNodes(std::set<TNodeID>& lstNode_IDs) const
212  {
213  lstNode_IDs.clear();
214  for (typename edges_map_t::const_iterator it = edges.begin();
215  it != edges.end(); ++it)
216  {
217  lstNode_IDs.insert(it->first.first);
218  lstNode_IDs.insert(it->first.second);
219  }
220  }
221 
222  /** Less efficient way to get all nodes that returns a copy of the set
223  * object \sa getAllNodes( std::set<TNodeID> &lstNode_IDs) */
224  inline std::set<TNodeID> getAllNodes() const
225  {
226  std::set<TNodeID> lst;
227  getAllNodes(lst);
228  return lst;
229  }
230 
231  /** Count how many different node IDs appear in the graph edges.
232  */
234  {
235  std::set<TNodeID> aux;
236  for (typename edges_map_t::const_iterator it = edges.begin();
237  it != edges.end(); ++it)
238  {
239  aux.insert(it->first.first);
240  aux.insert(it->first.second);
241  }
242  return aux.size();
243  }
244 
245  /** Return the list of all neighbors of "nodeID", by creating a list of
246  * their node IDs. \sa getAdjacencyMatrix */
248  const TNodeID nodeID, std::set<TNodeID>& neighborIDs) const
249  {
250  neighborIDs.clear();
251  for (typename edges_map_t::const_iterator it = edges.begin();
252  it != edges.end(); ++it)
253  {
254  if (it->first.first == nodeID)
255  neighborIDs.insert(it->first.second);
256  else if (it->first.second == nodeID)
257  neighborIDs.insert(it->first.first);
258  }
259  }
260  /** Return the list of all neighbors of "nodeID", by creating a list of
261  * their node IDs. \sa getAdjacencyMatrix */
262  std::set<TNodeID> getNeighborsOf(const TNodeID nodeID) const
263  {
264  std::set<TNodeID> neighborIDs;
265  this->getNeighborsOf(nodeID, neighborIDs);
266  return neighborIDs;
267  }
268 
269  /** Return a map from node IDs to all its neighbors (that is, connected
270  * nodes, regardless of the edge direction)
271  * This is a much more efficient method than calling getNeighborsOf() for
272  * each node in the graph.
273  * Possible values for the template argument MAP_NODEID_SET_NODEIDS are:
274  * - std::map<TNodeID, std::set<TNodeID> >
275  * - mrpt::utils::map_as_vector<TNodeID, std::set<TNodeID> >
276  * \sa getNeighborsOf
277  */
278  template <class MAP_NODEID_SET_NODEIDS>
279  void getAdjacencyMatrix(MAP_NODEID_SET_NODEIDS& outAdjacency) const
280  {
281  outAdjacency.clear();
282  for (typename edges_map_t::const_iterator it = edges.begin();
283  it != edges.end(); ++it)
284  {
285  outAdjacency[it->first.first].insert(it->first.second);
286  outAdjacency[it->first.second].insert(it->first.first);
287  }
288  }
289 
290  /** Just like \a getAdjacencyMatrix but return only the adjacency for those
291  * node_ids in the set \a onlyForTheseNodes
292  * (both endings nodes of an edge must be within the set for it to be
293  * returned) */
294  template <class MAP_NODEID_SET_NODEIDS, class SET_NODEIDS>
296  MAP_NODEID_SET_NODEIDS& outAdjacency,
297  const SET_NODEIDS& onlyForTheseNodes) const
298  {
299  outAdjacency.clear();
300  const typename SET_NODEIDS::const_iterator setEnd =
301  onlyForTheseNodes.end();
302  for (typename edges_map_t::const_iterator it = edges.begin();
303  it != edges.end(); ++it)
304  {
305  if (onlyForTheseNodes.find(it->first.first) == setEnd ||
306  onlyForTheseNodes.find(it->first.second) == setEnd)
307  continue;
308  outAdjacency[it->first.first].insert(it->first.second);
309  outAdjacency[it->first.second].insert(it->first.first);
310  }
311  }
312 
313  /** @} */ // end of edge/nodes utilities
314 
315  /** @name I/O utilities
316  @{ */
317 
318  /** Save the graph in a Graphviz (.dot files) text format; useful for
319  * quickly rendering the graph with "dot"
320  * \return false on any error */
321  bool saveAsDot(
322  std::ostream& o,
324  {
325  o << "digraph G {\n";
326  for (const_iterator it = begin(); it != end(); ++it)
327  {
328  const TNodeID id1 = it->first.first;
329  const TNodeID id2 = it->first.second;
330  std::string s1, s2;
331  if (!p.node_names.empty())
332  {
334  p.node_names.find(id1);
335  if (itNam1 != p.node_names.end()) s1 = itNam1->second;
337  p.node_names.find(id2);
338  if (itNam2 != p.node_names.end()) s2 = itNam2->second;
339  }
340  if (s1.empty())
341  s1 = mrpt::format("%u", static_cast<unsigned int>(id1));
342  if (s2.empty())
343  s2 = mrpt::format("%u", static_cast<unsigned int>(id2));
344  if (p.node_props.empty())
345  {
347  p.node_props.find(id1);
348  if (itP1 != p.node_props.end())
349  o << "\"" << s1 << "\""
350  << " [" << itP1->second << "];\n";
352  p.node_props.find(id2);
353  if (itP2 != p.node_props.end())
354  o << "\"" << s2 << "\""
355  << " [" << itP2->second << "];\n";
356  }
357  o << " \"" << s1 << "\" -> \"" << s2 << "\"";
358  if (p.mark_edges_as_not_constraint) o << " [constraint=false]";
359  o << ";\n";
360  }
361  return !((o << "}\n").fail());
362  }
363 
364  /** \overload */
365  bool saveAsDot(
366  const std::string& fileName,
368  {
369  std::ofstream f(fileName.c_str());
370  if (!f.is_open()) return false;
371  return saveAsDot(f, p);
372  }
373  /** @} */
374 
375 }; // end class CDirectedGraph
376 
377 /** @} */
378 } // End of namespace
379 
380 // Specialization of TTypeName must occur in the same namespace:
381 namespace utils
382 {
384 }
385 
386 } // End of namespace
387 #endif
std::pair< const_iterator, const_iterator > getEdges(TNodeID from_nodeID, TNodeID to_nodeID) const
Return a pair<first,last> of const iterators to the range of edges between two given nodes...
A directed graph with the argument of the template specifying the type of the annotations in the edge...
std::multimap< TYPE1, TYPE2, std::less< TYPE1 >, Eigen::aligned_allocator< std::pair< const TYPE1, TYPE2 > > > multimap_t
The type of each global pose in nodes: an extension of the TYPE_EDGES pose with any optional user-def...
const edge_t & getEdge(TNodeID from_nodeID, TNodeID to_nodeID) const
Return a reference to the content of a given edge.
std::pair< TNodeID, TNodeID > TPairNodeIDs
A pair of node IDs.
const_iterator rbegin() const
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
std::map< TNodeID, std::string > node_names
If provided, these textual names will be used for naming the nodes instead of their numeric IDs given...
edges_map_t edges
The public member with the directed edges in the graph.
#define THROW_EXCEPTION(msg)
void getNeighborsOf(const TNodeID nodeID, std::set< TNodeID > &neighborIDs) const
Return the list of all neighbors of "nodeID", by creating a list of their node IDs.
Scalar * iterator
Definition: eigen_plugins.h:26
void getAdjacencyMatrix(MAP_NODEID_SET_NODEIDS &outAdjacency, const SET_NODEIDS &onlyForTheseNodes) const
Just like getAdjacencyMatrix but return only the adjacency for those node_ids in the set onlyForThese...
std::set< TNodeID > getAllNodes() const
Less efficient way to get all nodes that returns a copy of the set object.
std::map< TNodeID, std::string > node_props
If provided, an extra line will be added setting Graphviz properties for each node, e.g.
const_iterator end() const
const Scalar * const_iterator
Definition: eigen_plugins.h:27
GLsizei GLsizei GLuint * obj
Definition: glext.h:4070
std::pair< iterator, iterator > getEdges(TNodeID from_nodeID, TNodeID to_nodeID)
Return a pair<first,last> of iterators to the range of edges between two given nodes.
void clearEdges()
Erase all edges.
bool edgeExists(TNodeID from_nodeID, TNodeID to_nodeID) const
Test if the given directed edge exists.
const_iterator begin() const
CDirectedGraph(const edges_map_t &obj)
Copy constructor from a multimap<pair< >, >
edges_map_t::iterator iterator
CDirectedGraph()
Default constructor.
void getAdjacencyMatrix(MAP_NODEID_SET_NODEIDS &outAdjacency) const
Return a map from node IDs to all its neighbors (that is, connected nodes, regardless of the edge dir...
uint64_t TNodeID
The type for node IDs in graphs of different types.
const_iterator rend() const
edges_map_t::const_reverse_iterator const_reverse_iterator
void insertEdge(TNodeID from_nodeID, TNodeID to_nodeID, const edge_t &edge_value)
Insert an edge (from -> to) with the given edge value.
CDirectedGraph< TYPE_EDGES, EDGE_ANNOTATIONS > self_t
Handy self type.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
bool saveAsDot(const std::string &fileName, const TGraphvizExportParams &p=TGraphvizExportParams()) const
uint64_t TNodeID
The type for node IDs in graphs of different types.
Definition: types_simple.h:49
edge_t(const ARG1 &a1, const ARG2 &a2)
GLsizei const GLchar ** string
Definition: glext.h:4101
mrpt::aligned_containers< TPairNodeIDs, edge_t >::multimap_t edges_map_t
The type of the member edges.
size_t countDifferentNodesInEdges() const
Count how many different node IDs appear in the graph edges.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void getAllNodes(std::set< TNodeID > &lstNode_IDs) const
Return a list of all the node_ID&#39;s of the graph, generated from all the nodes that appear in the list...
Used in mrpt::graphs export functions to .dot files.
edge_t & getEdge(TNodeID from_nodeID, TNodeID to_nodeID)
Return a reference to the content of a given edge.
edges_map_t::reverse_iterator reverse_iterator
bool mark_edges_as_not_constraint
If true (default=false), an "[constraint=false]" will be added to all edges (see Graphviz docs)...
size_t edgeCount() const
The number of edges in the graph.
void eraseEdge(TNodeID from_nodeID, TNodeID to_nodeID)
Erase all edges between the given nodes (it has no effect if no edge existed)
void insertEdgeAtEnd(TNodeID from_nodeID, TNodeID to_nodeID, const edge_t &edge_value)
Insert an edge (from -> to) with the given edge value (more efficient version to be called if you kno...
GLfloat GLfloat p
Definition: glext.h:6305
edges_map_t::const_iterator const_iterator
std::set< TNodeID > getNeighborsOf(const TNodeID nodeID) const
Return the list of all neighbors of "nodeID", by creating a list of their node IDs.
bool saveAsDot(std::ostream &o, const TGraphvizExportParams &p=TGraphvizExportParams()) const
Save the graph in a Graphviz (.dot files) text format; useful for quickly rendering the graph with "d...
#define MRPT_DECLARE_TTYPENAME(_TYPE)
Definition: TTypeName.h:72



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019