Gazebo Math

API Reference

6.16.0
gz/math/graph/Graph.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 #ifndef GZ_MATH_GRAPH_GRAPH_HH_
18 #define GZ_MATH_GRAPH_GRAPH_HH_
19 
20 #include <cassert>
21 #include <iostream>
22 #include <iterator>
23 #include <map>
24 #include <set>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include <gz/math/config.hh>
30 #include "gz/math/graph/Edge.hh"
31 #include "gz/math/graph/Vertex.hh"
32 
33 namespace ignition
34 {
35 namespace math
36 {
37 // Inline bracket to help doxygen filtering.
38 inline namespace IGNITION_MATH_VERSION_NAMESPACE {
39 namespace graph
40 {
55  //
108  template<typename V, typename E, typename EdgeType>
109  class Graph
110  {
112  public: Graph() = default;
113 
117  public: Graph(const std::vector<Vertex<V>> &_vertices,
118  const std::vector<EdgeInitializer<E>> &_edges)
119  {
120  // Add all vertices.
121  for (auto const &v : _vertices)
122  {
123  if (!this->AddVertex(v.Name(), v.Data(), v.Id()).Valid())
124  {
125  std::cerr << "Invalid vertex with Id [" << v.Id() << "]. Ignoring."
126  << std::endl;
127  }
128  }
129 
130  // Add all edges.
131  for (auto const &e : _edges)
132  {
133  if (!this->AddEdge(e.vertices, e.data, e.weight).Valid())
134  std::cerr << "Ignoring edge" << std::endl;
135  }
136  }
137 
144  public: Vertex<V> &AddVertex(const std::string &_name,
145  const V &_data,
146  const VertexId &_id = kNullId)
147  {
148  auto id = _id;
149 
150  // The user didn't provide an Id, we generate it.
151  if (id == kNullId)
152  {
153  id = this->NextVertexId();
154 
155  // No space for new Ids.
156  if (id == kNullId)
157  {
158  std::cerr << "[Graph::AddVertex()] The limit of vertices has been "
159  << "reached. Ignoring vertex." << std::endl;
160  return Vertex<V>::NullVertex;
161  }
162  }
163 
164  // Create the vertex.
165  auto ret = this->vertices.insert(
166  std::make_pair(id, Vertex<V>(_name, _data, id)));
167 
168  // The Id already exists.
169  if (!ret.second)
170  {
171  std::cerr << "[Graph::AddVertex()] Repeated vertex [" << id << "]"
172  << std::endl;
173  return Vertex<V>::NullVertex;
174  }
175 
176  // Link the vertex with an empty list of edges.
177  this->adjList[id] = EdgeId_S();
178 
179  return ret.first->second;
180  }
181 
185  public: const VertexRef_M<V> Vertices() const
186  {
187  VertexRef_M<V> res;
188  for (auto const &v : this->vertices)
189  res.emplace(std::make_pair(v.first, std::cref(v.second)));
190 
191  return res;
192  }
193 
197  public: const VertexRef_M<V> Vertices(const std::string &_name) const
198  {
199  VertexRef_M<V> res;
200  for (auto const &vertex : this->vertices)
201  {
202  if (vertex.second.Name() == _name)
203  res.emplace(std::make_pair(vertex.first, std::cref(vertex.second)));
204  }
205 
206  return res;
207  }
208 
215  public: EdgeType &AddEdge(const VertexId_P &_vertices,
216  const E &_data,
217  const double _weight = 1.0)
218  {
219  auto id = this->NextEdgeId();
220 
221  // No space for new Ids.
222  if (id == kNullId)
223  {
224  std::cerr << "[Graph::AddEdge()] The limit of edges has been reached. "
225  << "Ignoring edge." << std::endl;
226  return EdgeType::NullEdge;
227  }
228 
229  EdgeType newEdge(_vertices, _data, _weight, id);
230  return this->LinkEdge(std::move(newEdge));
231  }
232 
239  public: EdgeType &LinkEdge(const EdgeType &_edge)
240  {
241  auto edgeVertices = _edge.Vertices();
242 
243  // Sanity check: Both vertices should exist.
244  for (auto const &v : {edgeVertices.first, edgeVertices.second})
245  {
246  if (this->vertices.find(v) == this->vertices.end())
247  return EdgeType::NullEdge;
248  }
249 
250  // Link the new edge.
251  for (auto const &v : {edgeVertices.first, edgeVertices.second})
252  {
253  if (v != kNullId)
254  {
255  auto vertexIt = this->adjList.find(v);
256  assert(vertexIt != this->adjList.end());
257  vertexIt->second.insert(_edge.Id());
258  }
259  }
260 
261  auto ret = this->edges.insert(std::make_pair(_edge.Id(), _edge));
262 
263  // Return the new edge.
264  return ret.first->second;
265  }
266 
270  public: const EdgeRef_M<EdgeType> Edges() const
271  {
273  for (auto const &edge : this->edges)
274  {
275  res.emplace(std::make_pair(edge.first, std::cref(edge.second)));
276  }
277 
278  return res;
279  }
280 
296  public: VertexRef_M<V> AdjacentsFrom(const VertexId &_vertex) const
297  {
298  VertexRef_M<V> res;
299 
300  // Make sure the vertex exists
301  auto vertexIt = this->adjList.find(_vertex);
302  if (vertexIt == this->adjList.end())
303  return res;
304 
305  for (auto const &edgeId : vertexIt->second)
306  {
307  const auto &edge = this->EdgeFromId(edgeId);
308  auto neighborVertexId = edge.From(_vertex);
309  if (neighborVertexId != kNullId)
310  {
311  const auto &neighborVertex = this->VertexFromId(neighborVertexId);
312  res.emplace(
313  std::make_pair(neighborVertexId, std::cref(neighborVertex)));
314  }
315  }
316 
317  return res;
318  }
319 
335  public: VertexRef_M<V> AdjacentsFrom(const Vertex<V> &_vertex) const
336  {
337  return this->AdjacentsFrom(_vertex.Id());
338  }
339 
355  public: VertexRef_M<V> AdjacentsTo(const VertexId &_vertex) const
356  {
357  auto incidentEdges = this->IncidentsTo(_vertex);
358 
359  VertexRef_M<V> res;
360  for (auto const &incidentEdgeRef : incidentEdges)
361  {
362  const auto &incidentEdgeId = incidentEdgeRef.first;
363  const auto &incidentEdge = this->EdgeFromId(incidentEdgeId);
364  const auto &neighborVertexId = incidentEdge.To(_vertex);
365  const auto &neighborVertex = this->VertexFromId(neighborVertexId);
366  res.emplace(
367  std::make_pair(neighborVertexId, std::cref(neighborVertex)));
368  }
369 
370  return res;
371  }
372 
388  public: VertexRef_M<V> AdjacentsTo(const Vertex<V> &_vertex) const
389  {
390  return this->AdjacentsTo(_vertex.Id());
391  }
392 
396  public: size_t InDegree(const VertexId &_vertex) const
397  {
398  return this->IncidentsTo(_vertex).size();
399  }
400 
404  public: size_t InDegree(const Vertex<V> &_vertex) const
405  {
406  return this->IncidentsTo(this->VertexFromId(_vertex.Id())).size();
407  }
408 
412  public: size_t OutDegree(const VertexId &_vertex) const
413  {
414  return this->IncidentsFrom(_vertex).size();
415  }
416 
420  public: size_t OutDegree(const Vertex<V> &_vertex) const
421  {
422  return this->IncidentsFrom(this->VertexFromId(_vertex.Id())).size();
423  }
424 
430  public: const EdgeRef_M<EdgeType> IncidentsFrom(const VertexId &_vertex)
431  const
432  {
434 
435  const auto &adjIt = this->adjList.find(_vertex);
436  if (adjIt == this->adjList.end())
437  return res;
438 
439  const auto &edgeIds = adjIt->second;
440  for (auto const &edgeId : edgeIds)
441  {
442  const auto &edge = this->EdgeFromId(edgeId);
443  if (edge.From(_vertex) != kNullId)
444  res.emplace(std::make_pair(edge.Id(), std::cref(edge)));
445  }
446 
447  return res;
448  }
449 
456  const Vertex<V> &_vertex) const
457  {
458  return this->IncidentsFrom(_vertex.Id());
459  }
460 
467  const VertexId &_vertex) const
468  {
470 
471  const auto &adjIt = this->adjList.find(_vertex);
472  if (adjIt == this->adjList.end())
473  return res;
474 
475  const auto &edgeIds = adjIt->second;
476  for (auto const &edgeId : edgeIds)
477  {
478  const auto &edge = this->EdgeFromId(edgeId);
479  if (edge.To(_vertex) != kNullId)
480  res.emplace(std::make_pair(edge.Id(), std::cref(edge)));
481  }
482 
483  return res;
484  }
485 
491  public: const EdgeRef_M<EdgeType> IncidentsTo(const Vertex<V> &_vertex)
492  const
493  {
494  return this->IncidentsTo(_vertex.Id());
495  }
496 
500  public: bool Empty() const
501  {
502  return this->vertices.empty();
503  }
504 
508  public: bool RemoveVertex(const VertexId &_vertex)
509  {
510  auto vIt = this->vertices.find(_vertex);
511  if (vIt == this->vertices.end())
512  return false;
513 
514  // Remove incident edges.
515  auto incidents = this->IncidentsTo(_vertex);
516  for (auto edgePair : incidents)
517  this->RemoveEdge(edgePair.first);
518 
519  // Remove all outgoing edges.
520  incidents = this->IncidentsFrom(_vertex);
521  for (auto edgePair : incidents)
522  this->RemoveEdge(edgePair.first);
523 
524  // Remove the vertex (key) from the adjacency list.
525  this->adjList.erase(_vertex);
526 
527  // Remove the vertex.
528  this->vertices.erase(_vertex);
529 
530  return true;
531  }
532 
536  public: bool RemoveVertex(Vertex<V> &_vertex)
537  {
538  return this->RemoveVertex(_vertex.Id());
539  }
540 
544  public: size_t RemoveVertices(const std::string &_name)
545  {
546  std::vector<VertexId> toRemove;
547  for (auto const &[id, vertex] : this->vertices)
548  {
549  if (vertex.Name() == _name)
550  toRemove.push_back(id);
551  }
552 
553  size_t result = 0;
554  for (auto const &id : toRemove)
555  {
556  if (this->RemoveVertex(id))
557  ++result;
558  }
559  return result;
560  }
561 
567  public: bool RemoveEdge(const EdgeId &_edge)
568  {
569  auto edgeIt = this->edges.find(_edge);
570  if (edgeIt == this->edges.end())
571  return false;
572 
573  auto edgeVertices = edgeIt->second.Vertices();
574 
575  // Unlink the edge.
576  for (auto const &v : {edgeVertices.first, edgeVertices.second})
577  {
578  if (edgeIt->second.From(v) != kNullId)
579  {
580  auto vertex = this->adjList.find(v);
581  assert(vertex != this->adjList.end());
582  vertex->second.erase(_edge);
583  }
584  }
585 
586  this->edges.erase(_edge);
587 
588  return true;
589  }
590 
596  public: bool RemoveEdge(EdgeType &_edge)
597  {
598  return this->RemoveEdge(_edge.Id());
599  }
600 
605  public: const Vertex<V> &VertexFromId(const VertexId &_id) const
606  {
607  auto iter = this->vertices.find(_id);
608  if (iter == this->vertices.end())
609  return Vertex<V>::NullVertex;
610 
611  return iter->second;
612  }
613 
618  public: Vertex<V> &VertexFromId(const VertexId &_id)
619  {
620  auto iter = this->vertices.find(_id);
621  if (iter == this->vertices.end())
622  return Vertex<V>::NullVertex;
623 
624  return iter->second;
625  }
626 
635  public: const EdgeType &EdgeFromVertices(
636  const VertexId _sourceId, const VertexId _destId) const
637  {
638  // Get the adjacency iterator for the source vertex.
639  const typename std::map<VertexId, EdgeId_S>::const_iterator &adjIt =
640  this->adjList.find(_sourceId);
641 
642  // Quit early if there is no adjacency entry
643  if (adjIt == this->adjList.end())
644  return EdgeType::NullEdge;
645 
646  // Loop over the edges in the source vertex's adjacency list
647  for (std::set<EdgeId>::const_iterator edgIt = adjIt->second.begin();
648  edgIt != adjIt->second.end(); ++edgIt)
649  {
650  // Get an iterator to the actual edge
651  const typename std::map<EdgeId, EdgeType>::const_iterator edgeIter =
652  this->edges.find(*edgIt);
653 
654  // Check if the edge has the correct source and destination.
655  if (edgeIter != this->edges.end() &&
656  edgeIter->second.From(_sourceId) == _destId)
657  {
658  assert(edgeIter->second.To(_destId) == _sourceId);
659  return edgeIter->second;
660  }
661  }
662 
663  return EdgeType::NullEdge;
664  }
665 
670  public: const EdgeType &EdgeFromId(const EdgeId &_id) const
671  {
672  auto iter = this->edges.find(_id);
673  if (iter == this->edges.end())
674  return EdgeType::NullEdge;
675 
676  return iter->second;
677  }
678 
684  public: template<typename VV, typename EE, typename EEdgeType>
686  const Graph<VV, EE, EEdgeType> &_g);
687 
690  private: VertexId &NextVertexId()
691  {
692  while (this->vertices.find(this->nextVertexId) != this->vertices.end()
693  && this->nextVertexId < MAX_UI64)
694  {
695  ++this->nextVertexId;
696  }
697 
698  return this->nextVertexId;
699  }
700 
703  private: VertexId &NextEdgeId()
704  {
705  while (this->edges.find(this->nextEdgeId) != this->edges.end() &&
706  this->nextEdgeId < MAX_UI64)
707  {
708  ++this->nextEdgeId;
709  }
710 
711  return this->nextEdgeId;
712  }
713 
715  protected: VertexId nextVertexId = 0u;
716 
718  protected: VertexId nextEdgeId = 0u;
719 
721  private: std::map<VertexId, Vertex<V>> vertices;
722 
724  private: std::map<EdgeId, EdgeType> edges;
725 
731  private: std::map<VertexId, EdgeId_S> adjList;
732 
737  };
738 
741  template<typename VV, typename EE>
743  const Graph<VV, EE, UndirectedEdge<EE>> &_g)
744  {
745  _out << "graph {" << std::endl;
746 
747  // All vertices with the name and Id as a "label" attribute.
748  for (auto const &vertexMap : _g.Vertices())
749  {
750  auto vertex = vertexMap.second.get();
751  _out << vertex;
752  }
753 
754  // All edges.
755  for (auto const &edgeMap : _g.Edges())
756  {
757  auto edge = edgeMap.second.get();
758  _out << edge;
759  }
760 
761  _out << "}" << std::endl;
762 
763  return _out;
764  }
765 
768  template<typename VV, typename EE>
770  const Graph<VV, EE, DirectedEdge<EE>> &_g)
771  {
772  _out << "digraph {" << std::endl;
773 
774  // All vertices with the name and Id as a "label" attribute.
775  for (auto const &vertexMap : _g.Vertices())
776  {
777  auto vertex = vertexMap.second.get();
778  _out << vertex;
779  }
780 
781  // All edges.
782  for (auto const &edgeMap : _g.Edges())
783  {
784  auto edge = edgeMap.second.get();
785  _out << edge;
786  }
787 
788  _out << "}" << std::endl;
789 
790  return _out;
791  }
792 
795  template<typename V, typename E>
797 
800  template<typename V, typename E>
802 }
803 }
804 }
805 }
806 #endif
T begin(T... args)
A directed edge represents a connection between two vertices. The connection is unidirectional,...
Definition: gz/math/graph/Edge.hh:268
A generic graph class. Both vertices and edges can store user information. A vertex could be created ...
Definition: gz/math/graph/Graph.hh:110
Graph()=default
Default constructor.
Vertex< V > & AddVertex(const std::string &_name, const V &_data, const VertexId &_id=kNullId)
Add a new vertex to the graph.
Definition: gz/math/graph/Graph.hh:144
bool RemoveVertex(Vertex< V > &_vertex)
Remove an existing vertex from the graph.
Definition: gz/math/graph/Graph.hh:536
size_t OutDegree(const Vertex< V > &_vertex) const
Get the number of edges incident from a vertex.
Definition: gz/math/graph/Graph.hh:420
VertexRef_M< V > AdjacentsFrom(const VertexId &_vertex) const
Get all vertices that are directly connected with one edge from a given vertex. In other words,...
Definition: gz/math/graph/Graph.hh:296
const EdgeType & EdgeFromVertices(const VertexId _sourceId, const VertexId _destId) const
Get a reference to an edge based on two vertices. A NullEdge object reference is returned if an edge ...
Definition: gz/math/graph/Graph.hh:635
const Vertex< V > & VertexFromId(const VertexId &_id) const
Get a reference to a vertex using its Id.
Definition: gz/math/graph/Graph.hh:605
size_t OutDegree(const VertexId &_vertex) const
Get the number of edges incident from a vertex.
Definition: gz/math/graph/Graph.hh:412
EdgeType & AddEdge(const VertexId_P &_vertices, const E &_data, const double _weight=1.0)
Add a new edge to the graph.
Definition: gz/math/graph/Graph.hh:215
const EdgeType & EdgeFromId(const EdgeId &_id) const
Get a reference to an edge using its Id.
Definition: gz/math/graph/Graph.hh:670
bool RemoveVertex(const VertexId &_vertex)
Remove an existing vertex from the graph.
Definition: gz/math/graph/Graph.hh:508
const VertexRef_M< V > Vertices(const std::string &_name) const
The collection of all vertices in the graph with name == _name.
Definition: gz/math/graph/Graph.hh:197
bool RemoveEdge(EdgeType &_edge)
Remove an existing edge from the graph. After the removal, it won't be possible to reach any of the v...
Definition: gz/math/graph/Graph.hh:596
size_t InDegree(const Vertex< V > &_vertex) const
Get the number of edges incident to a vertex.
Definition: gz/math/graph/Graph.hh:404
const EdgeRef_M< EdgeType > IncidentsFrom(const Vertex< V > &_vertex) const
Get the set of outgoing edges from a given vertex.
Definition: gz/math/graph/Graph.hh:455
const EdgeRef_M< EdgeType > IncidentsTo(const Vertex< V > &_vertex) const
Get the set of incoming edges to a given vertex.
Definition: gz/math/graph/Graph.hh:491
const EdgeRef_M< EdgeType > IncidentsFrom(const VertexId &_vertex) const
Get the set of outgoing edges from a given vertex.
Definition: gz/math/graph/Graph.hh:430
const EdgeRef_M< EdgeType > Edges() const
The collection of all edges in the graph.
Definition: gz/math/graph/Graph.hh:270
friend std::ostream & operator<<(std::ostream &_out, const Graph< VV, EE, EEdgeType > &_g)
Stream insertion operator. The output uses DOT graph description language.
const VertexRef_M< V > Vertices() const
The collection of all vertices in the graph.
Definition: gz/math/graph/Graph.hh:185
size_t RemoveVertices(const std::string &_name)
Remove all vertices with name == _name.
Definition: gz/math/graph/Graph.hh:544
bool Empty() const
Get whether the graph is empty.
Definition: gz/math/graph/Graph.hh:500
const EdgeRef_M< EdgeType > IncidentsTo(const VertexId &_vertex) const
Get the set of incoming edges to a given vertex.
Definition: gz/math/graph/Graph.hh:466
VertexRef_M< V > AdjacentsTo(const VertexId &_vertex) const
Get all vertices that are directly connected with one edge to a given vertex. In other words,...
Definition: gz/math/graph/Graph.hh:355
bool RemoveEdge(const EdgeId &_edge)
Remove an existing edge from the graph. After the removal, it won't be possible to reach any of the v...
Definition: gz/math/graph/Graph.hh:567
Vertex< V > & VertexFromId(const VertexId &_id)
Get a mutable reference to a vertex using its Id.
Definition: gz/math/graph/Graph.hh:618
size_t InDegree(const VertexId &_vertex) const
Get the number of edges incident to a vertex.
Definition: gz/math/graph/Graph.hh:396
EdgeType & LinkEdge(const EdgeType &_edge)
Links an edge to the graph. This function verifies that the edge's two vertices exist in the graph,...
Definition: gz/math/graph/Graph.hh:239
Graph(const std::vector< Vertex< V >> &_vertices, const std::vector< EdgeInitializer< E >> &_edges)
Constructor.
Definition: gz/math/graph/Graph.hh:117
VertexRef_M< V > AdjacentsTo(const Vertex< V > &_vertex) const
Get all vertices that are directly connected with one edge to a given vertex. In other words,...
Definition: gz/math/graph/Graph.hh:388
VertexRef_M< V > AdjacentsFrom(const Vertex< V > &_vertex) const
Get all vertices that are directly connected with one edge from a given vertex. In other words,...
Definition: gz/math/graph/Graph.hh:335
An undirected edge represents a connection between two vertices. The connection is bidirectional,...
Definition: gz/math/graph/Edge.hh:205
A vertex of a graph. It stores user information, an optional name, and keeps an internal unique Id....
Definition: gz/math/graph/Vertex.hh:55
VertexId Id() const
Get the vertex Id.
Definition: gz/math/graph/Vertex.hh:88
T emplace(T... args)
T end(T... args)
T endl(T... args)
T find(T... args)
T make_pair(T... args)
T move(T... args)
uint64_t EdgeId
The unique Id for an edge.
Definition: gz/math/graph/Edge.hh:40
uint64_t VertexId
The unique Id of each vertex.
Definition: gz/math/graph/Vertex.hh:41
std::ostream & operator<<(std::ostream &_out, const Graph< VV, EE, DirectedEdge< EE >> &_g)
Partial template specification for directed edges.
Definition: gz/math/graph/Graph.hh:769
static const VertexId kNullId
Represents an invalid Id.
Definition: gz/math/graph/Vertex.hh:48
std::set< EdgeId > EdgeId_S
Definition: gz/math/graph/Edge.hh:192
static const uint64_t MAX_UI64
64bit unsigned integer maximum value
Definition: gz/math/Helpers.hh:339
Definition: gz/math/AdditivelySeparableScalarField3.hh:28
T push_back(T... args)
T cref(T... args)
Used in the Graph constructors for uniform initialization.
Definition: gz/math/graph/Edge.hh:45