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



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020