Gazebo Math

API Reference

6.16.0
gz/math/graph/GraphAlgorithms.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_GRAPHALGORITHMS_HH_
18 #define GZ_MATH_GRAPH_GRAPHALGORITHMS_HH_
19 
20 #include <functional>
21 #include <map>
22 #include <queue>
23 #include <stack>
24 #include <unordered_set>
25 #include <utility>
26 #include <vector>
27 
28 #include <gz/math/config.hh>
29 #include "gz/math/graph/Graph.hh"
30 #include "gz/math/Helpers.hh"
31 
32 namespace ignition
33 {
34 namespace math
35 {
36 // Inline bracket to help doxygen filtering.
37 inline namespace IGNITION_MATH_VERSION_NAMESPACE {
38 namespace graph
39 {
44 
52  template<typename V, typename E, typename EdgeType>
54  const VertexId &_from)
55  {
56  if (!_graph.VertexFromId(_from).Valid())
57  return {};
58 
59  std::vector<VertexId> visited;
61  std::queue<VertexId> pending;
62 
63  // Mark-on-enqueue: each vertex enters the queue at most once.
64  pending.push(_from);
65  seen.insert(_from);
66 
67  while (!pending.empty())
68  {
69  const VertexId u = pending.front();
70  pending.pop();
71  visited.push_back(u);
72 
73  for (auto const &adj : _graph.AdjacentsFrom(u))
74  {
75  const VertexId next = adj.first;
76  if (seen.insert(next).second)
77  pending.push(next);
78  }
79  }
80  return visited;
81  }
82 
90  template<typename V, typename E, typename EdgeType>
92  const VertexId &_from)
93  {
94  if (!_graph.VertexFromId(_from).Valid())
95  return {};
96 
97  std::vector<VertexId> visited;
99  std::stack<VertexId> pending;
100  pending.push(_from);
101 
102  // Mark-on-pop: matches the textbook DFS visitation order. Children are
103  // pushed unconditionally and duplicate entries are skipped at pop time.
104  while (!pending.empty())
105  {
106  const VertexId u = pending.top();
107  pending.pop();
108 
109  if (!seen.insert(u).second)
110  continue;
111  visited.push_back(u);
112 
113  for (auto const &adj : _graph.AdjacentsFrom(u))
114  {
115  const VertexId next = adj.first;
116  if (!seen.count(next))
117  pending.push(next);
118  }
119  }
120  return visited;
121  }
122 
186  template<typename V, typename E, typename EdgeType>
188  const VertexId &_from,
189  const VertexId &_to = kNullId)
190  {
191  auto allVertices = _graph.Vertices();
192 
193  // Sanity check: The source vertex should exist.
194  if (allVertices.find(_from) == allVertices.end())
195  {
196  std::cerr << "Vertex [" << _from << "] Not found" << std::endl;
197  return {};
198  }
199 
200  // Sanity check: The destination vertex should exist (if used).
201  if (_to != kNullId &&
202  allVertices.find(_to) == allVertices.end())
203  {
204  std::cerr << "Vertex [" << _to << "] Not found" << std::endl;
205  return {};
206  }
207 
208  // Store vertices that are being preprocessed.
211 
212  // Create a map for distances and next neightbor and initialize all
213  // distances as infinite.
215  for (auto const &v : allVertices)
216  {
217  auto id = v.first;
218  dist[id] = std::make_pair(MAX_D, kNullId);
219  }
220 
221  // Insert _from in the priority queue and initialize its distance as 0.
222  pq.push(std::make_pair(0.0, _from));
223  dist[_from] = std::make_pair(0.0, _from);
224 
225  while (!pq.empty())
226  {
227  // This is the minimum distance vertex.
228  const double poppedCost = pq.top().first;
229  VertexId u = pq.top().second;
230 
231  // Shortcut: Destination vertex found, exiting.
232  if (_to != kNullId && _to == u)
233  break;
234 
235  pq.pop();
236 
237  // Skip stale priority-queue entries left behind by relaxation
238  // updates: dist[u] is the authoritative cost; if the popped cost is
239  // greater, this entry was queued before u was settled.
240  if (poppedCost > dist[u].first)
241  continue;
242 
243  for (auto const &edgePair : _graph.IncidentsFrom(u))
244  {
245  const auto &edge = edgePair.second.get();
246  const auto &v = edge.From(u);
247  double weight = edge.Weight();
248 
249  // If there is a shorter path to v through u.
250  if (dist[v].first > dist[u].first + weight)
251  {
252  // Update distance of v.
253  dist[v] = std::make_pair(dist[u].first + weight, u);
254  pq.push(std::make_pair(dist[v].first, v));
255  }
256  }
257  }
258 
259  return dist;
260  }
261 
270  template<typename V, typename E>
272  const UndirectedGraph<V, E> &_graph)
273  {
275  unsigned int componentCount = 0;
276 
277  for (auto const &v : _graph.Vertices())
278  {
279  if (visited.find(v.first) == visited.end())
280  {
281  auto component = BreadthFirstSort(_graph, v.first);
282  for (auto const &vId : component)
283  visited[vId] = componentCount;
284  ++componentCount;
285  }
286  }
287 
288  std::vector<UndirectedGraph<V, E>> res(componentCount);
289 
290  // Create the vertices.
291  for (auto const &vPair : _graph.Vertices())
292  {
293  const auto &v = vPair.second.get();
294  const auto &componentId = visited[v.Id()];
295  res[componentId].AddVertex(v.Name(), v.Data(), v.Id());
296  }
297 
298  // Create the edges.
299  for (auto const &ePair : _graph.Edges())
300  {
301  const auto &e = ePair.second.get();
302  const auto &vertices = e.Vertices();
303  const auto &componentId = visited[vertices.first];
304  res[componentId].AddEdge(vertices, e.Data(), e.Weight());
305  }
306 
307  return res;
308  }
309 
315  template<typename V, typename E>
317  {
318  std::vector<Vertex<V>> vertices;
320 
321  // Add all vertices.
322  for (auto const &vPair : _graph.Vertices())
323  {
324  vertices.push_back(vPair.second.get());
325  }
326 
327  // Add all edges.
328  for (auto const &ePair : _graph.Edges())
329  {
330  auto const &e = ePair.second.get();
331  edges.push_back({e.Vertices(), e.Data(), e.Weight()});
332  }
333 
334  return UndirectedGraph<V, E>(vertices, edges);
335  }
336 
359  template<typename V, typename E, typename EdgeType>
361  const Graph<V, E, EdgeType> &_graph, const VertexId &_vertex)
362  {
363  std::vector<VertexId> chain;
364  if (!_graph.VertexFromId(_vertex).Valid())
365  return {chain, false};
366 
368  seen.insert(_vertex);
369  VertexId cur = _vertex;
370  while (true)
371  {
372  auto parents = _graph.AdjacentsTo(cur);
373  if (parents.empty())
374  return {chain, true};
375  const VertexId next = parents.begin()->first;
376  // Cycle guard: stop if we revisit a vertex.
377  if (!seen.insert(next).second)
378  return {chain, false};
379  chain.push_back(next);
380  cur = next;
381  }
382  }
383 
392  template<typename V, typename E, typename EdgeType>
394  const Graph<V, E, EdgeType> &_graph,
395  const VertexId &_ancestor,
396  const VertexId &_descendant)
397  {
398  if (_ancestor == _descendant)
399  return false;
400  if (!_graph.VertexFromId(_ancestor).Valid() ||
401  !_graph.VertexFromId(_descendant).Valid())
402  {
403  return false;
404  }
405 
407  seen.insert(_descendant);
408  VertexId cur = _descendant;
409  while (true)
410  {
411  auto parents = _graph.AdjacentsTo(cur);
412  if (parents.empty())
413  return false;
414  const VertexId next = parents.begin()->first;
415  if (next == _ancestor)
416  return true;
417  // Cycle guard.
418  if (!seen.insert(next).second)
419  return false;
420  cur = next;
421  }
422  }
423 
438  template<typename V, typename E, typename EdgeType>
440  const Graph<V, E, EdgeType> &_graph,
441  const VertexId &_a, const VertexId &_b)
442  {
443  if (!_graph.VertexFromId(_a).Valid() ||
444  !_graph.VertexFromId(_b).Valid())
445  {
446  return kNullId;
447  }
448  if (_a == _b)
449  return _a;
450 
451  std::unordered_set<VertexId> ancestorsA;
452  ancestorsA.insert(_a);
453  for (auto v : Ancestors(_graph, _a).first)
454  ancestorsA.insert(v);
455 
456  if (ancestorsA.count(_b))
457  return _b;
458  for (auto v : Ancestors(_graph, _b).first)
459  {
460  if (ancestorsA.count(v))
461  return v;
462  }
463  return kNullId;
464  }
465 
479  template<typename V, typename E, typename EdgeType>
481  const Graph<V, E, EdgeType> &_graph, const VertexId &_root)
482  {
484  if (!_graph.VertexFromId(_root).Valid())
485  return out;
486 
487  auto descendants = BreadthFirstSort(_graph, _root);
488  std::unordered_set<VertexId> set(descendants.begin(), descendants.end());
489 
490  // Copy vertices preserving ids.
491  for (auto id : descendants)
492  {
493  const auto &v = _graph.VertexFromId(id);
494  out.AddVertex(v.Name(), v.Data(), v.Id());
495  }
496  // Copy edges whose endpoints both lie in the reachable set.
497  for (auto const &ePair : _graph.Edges())
498  {
499  auto const &e = ePair.second.get();
500  auto vs = e.Vertices();
501  if (set.count(vs.first) && set.count(vs.second))
502  out.AddEdge(vs, e.Data(), e.Weight());
503  }
504  return out;
505  }
506 
514  template<typename V, typename E, typename EdgeType>
516  const Graph<V, E, EdgeType> &_graph, const VertexId &_vertex)
517  {
519  if (!_graph.VertexFromId(_vertex).Valid())
520  return out;
521 
522  std::queue<VertexId> pending;
523  pending.push(_vertex);
524  out.insert(_vertex);
525  while (!pending.empty())
526  {
527  const VertexId u = pending.front();
528  pending.pop();
529  for (auto const &adj : _graph.AdjacentsFrom(u))
530  {
531  if (out.insert(adj.first).second)
532  pending.push(adj.first);
533  }
534  }
535  return out;
536  }
537 } // namespace graph
538 } // namespace IGNITION_MATH_VERSION_NAMESPACE
539 } // namespace math
540 } // namespace ignition
541 #endif // GZ_MATH_GRAPH_GRAPHALGORITHMS_HH_
A generic graph class. Both vertices and edges can store user information. A vertex could be created ...
Definition: gz/math/graph/Graph.hh:110
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
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 Vertex< V > & VertexFromId(const VertexId &_id) const
Get a reference to a vertex using its Id.
Definition: gz/math/graph/Graph.hh:605
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 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
const VertexRef_M< V > Vertices() const
The collection of all vertices in the graph.
Definition: gz/math/graph/Graph.hh:185
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
T count(T... args)
T empty(T... args)
T end(T... args)
T endl(T... args)
T find(T... args)
T front(T... args)
T insert(T... args)
T make_pair(T... args)
std::pair< std::vector< VertexId >, bool > Ancestors(const Graph< V, E, EdgeType > &_graph, const VertexId &_vertex)
Walk parent edges from _vertex up to a root and return the chain of ancestors in walk order (immediat...
Definition: gz/math/graph/GraphAlgorithms.hh:360
uint64_t VertexId
The unique Id of each vertex.
Definition: gz/math/graph/Vertex.hh:41
Graph< V, E, EdgeType > Subgraph(const Graph< V, E, EdgeType > &_graph, const VertexId &_root)
Extract the subgraph induced by _root and all descendants reachable from it. Vertices and edges are c...
Definition: gz/math/graph/GraphAlgorithms.hh:480
static const VertexId kNullId
Represents an invalid Id.
Definition: gz/math/graph/Vertex.hh:48
std::vector< VertexId > DepthFirstSort(const Graph< V, E, EdgeType > &_graph, const VertexId &_from)
Depth first sort (DFS). Starting from the vertex == _from, it visits the graph as far as possible alo...
Definition: gz/math/graph/GraphAlgorithms.hh:91
std::map< VertexId, CostInfo > Dijkstra(const Graph< V, E, EdgeType > &_graph, const VertexId &_from, const VertexId &_to=kNullId)
Dijkstra algorithm. Find the shortest path between the vertices in a graph. If only a graph and a sou...
Definition: gz/math/graph/GraphAlgorithms.hh:187
std::unordered_set< VertexId > DescendantsSet(const Graph< V, E, EdgeType > &_graph, const VertexId &_vertex)
Set of all descendants of _vertex (including _vertex itself). Equivalent to BreadthFirstSort + insert...
Definition: gz/math/graph/GraphAlgorithms.hh:515
VertexId LowestCommonAncestor(const Graph< V, E, EdgeType > &_graph, const VertexId &_a, const VertexId &_b)
Lowest common ancestor of two vertices in a directed forest. Walks _a up to root collecting ancestors...
Definition: gz/math/graph/GraphAlgorithms.hh:439
std::pair< double, VertexId > CostInfo
Used in Dijkstra. For a given source vertex, this pair represents the cost (first element) to reach a...
Definition: gz/math/graph/GraphAlgorithms.hh:43
bool IsAncestor(const Graph< V, E, EdgeType > &_graph, const VertexId &_ancestor, const VertexId &_descendant)
Test whether _ancestor lies on the parent chain above _descendant. O(depth) – walks _descendant up vi...
Definition: gz/math/graph/GraphAlgorithms.hh:393
std::vector< UndirectedGraph< V, E > > ConnectedComponents(const UndirectedGraph< V, E > &_graph)
Calculate the connected components of an undirected graph. A connected component of an undirected gra...
Definition: gz/math/graph/GraphAlgorithms.hh:271
std::vector< VertexId > BreadthFirstSort(const Graph< V, E, EdgeType > &_graph, const VertexId &_from)
Breadth first sort (BFS). Starting from the vertex == _from, it traverses the graph exploring the nei...
Definition: gz/math/graph/GraphAlgorithms.hh:53
UndirectedGraph< V, E > ToUndirectedGraph(const DirectedGraph< V, E > &_graph)
Copy a DirectedGraph to an UndirectedGraph with the same vertices and edges.
Definition: gz/math/graph/GraphAlgorithms.hh:316
static const double MAX_D
Double maximum value. This value will be similar to 1.79769e+308.
Definition: gz/math/Helpers.hh:257
Definition: gz/math/AdditivelySeparableScalarField3.hh:28
T pop(T... args)
T push_back(T... args)
T push(T... args)
T top(T... args)