Gazebo Math

API Reference

7.6.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 gz::math
33 {
34 // Inline bracket to help doxygen filtering.
35 inline namespace GZ_MATH_VERSION_NAMESPACE {
36 namespace graph
37 {
42 
50  template<typename V, typename E, typename EdgeType>
52  const VertexId &_from)
53  {
54  if (!_graph.VertexFromId(_from).Valid())
55  return {};
56 
57  std::vector<VertexId> visited;
59  std::queue<VertexId> pending;
60 
61  // Mark-on-enqueue: each vertex enters the queue at most once.
62  pending.push(_from);
63  seen.insert(_from);
64 
65  while (!pending.empty())
66  {
67  const VertexId u = pending.front();
68  pending.pop();
69  visited.push_back(u);
70 
71  for (auto const &adj : _graph.AdjacentsFrom(u))
72  {
73  const VertexId next = adj.first;
74  if (seen.insert(next).second)
75  pending.push(next);
76  }
77  }
78  return visited;
79  }
80 
88  template<typename V, typename E, typename EdgeType>
90  const VertexId &_from)
91  {
92  if (!_graph.VertexFromId(_from).Valid())
93  return {};
94 
95  std::vector<VertexId> visited;
97  std::stack<VertexId> pending;
98  pending.push(_from);
99 
100  // Mark-on-pop: matches the textbook DFS visitation order. Children are
101  // pushed unconditionally and duplicate entries are skipped at pop time.
102  while (!pending.empty())
103  {
104  const VertexId u = pending.top();
105  pending.pop();
106 
107  if (!seen.insert(u).second)
108  continue;
109  visited.push_back(u);
110 
111  for (auto const &adj : _graph.AdjacentsFrom(u))
112  {
113  const VertexId next = adj.first;
114  if (!seen.count(next))
115  pending.push(next);
116  }
117  }
118  return visited;
119  }
120 
184  template<typename V, typename E, typename EdgeType>
186  const VertexId &_from,
187  const VertexId &_to = kNullId)
188  {
189  auto allVertices = _graph.Vertices();
190 
191  // Sanity check: The source vertex should exist.
192  if (allVertices.find(_from) == allVertices.end())
193  {
194  std::cerr << "Vertex [" << _from << "] Not found" << std::endl;
195  return {};
196  }
197 
198  // Sanity check: The destination vertex should exist (if used).
199  if (_to != kNullId &&
200  allVertices.find(_to) == allVertices.end())
201  {
202  std::cerr << "Vertex [" << _to << "] Not found" << std::endl;
203  return {};
204  }
205 
206  // Store vertices that are being preprocessed.
209 
210  // Create a map for distances and next neighbor and initialize all
211  // distances as infinite.
213  for (auto const &v : allVertices)
214  {
215  auto id = v.first;
216  dist[id] = std::make_pair(MAX_D, kNullId);
217  }
218 
219  // Insert _from in the priority queue and initialize its distance as 0.
220  pq.push(std::make_pair(0.0, _from));
221  dist[_from] = std::make_pair(0.0, _from);
222 
223  while (!pq.empty())
224  {
225  // This is the minimum distance vertex.
226  const double poppedCost = pq.top().first;
227  VertexId u = pq.top().second;
228 
229  // Shortcut: Destination vertex found, exiting.
230  if (_to != kNullId && _to == u)
231  break;
232 
233  pq.pop();
234 
235  // Skip stale priority-queue entries left behind by relaxation
236  // updates: dist[u] is the authoritative cost; if the popped cost is
237  // greater, this entry was queued before u was settled.
238  if (poppedCost > dist[u].first)
239  continue;
240 
241  for (auto const &edgePair : _graph.IncidentsFrom(u))
242  {
243  const auto &edge = edgePair.second.get();
244  const auto &v = edge.From(u);
245  double weight = edge.Weight();
246 
247  // If there is a shorter path to v through u.
248  if (dist[v].first > dist[u].first + weight)
249  {
250  // Update distance of v.
251  dist[v] = std::make_pair(dist[u].first + weight, u);
252  pq.push(std::make_pair(dist[v].first, v));
253  }
254  }
255  }
256 
257  return dist;
258  }
259 
268  template<typename V, typename E>
270  const UndirectedGraph<V, E> &_graph)
271  {
273  unsigned int componentCount = 0;
274 
275  for (auto const &v : _graph.Vertices())
276  {
277  if (visited.find(v.first) == visited.end())
278  {
279  auto component = BreadthFirstSort(_graph, v.first);
280  for (auto const &vId : component)
281  visited[vId] = componentCount;
282  ++componentCount;
283  }
284  }
285 
286  std::vector<UndirectedGraph<V, E>> res(componentCount);
287 
288  // Create the vertices.
289  for (auto const &vPair : _graph.Vertices())
290  {
291  const auto &v = vPair.second.get();
292  const auto &componentId = visited[v.Id()];
293  res[componentId].AddVertex(v.Name(), v.Data(), v.Id());
294  }
295 
296  // Create the edges.
297  for (auto const &ePair : _graph.Edges())
298  {
299  const auto &e = ePair.second.get();
300  const auto &vertices = e.Vertices();
301  const auto &componentId = visited[vertices.first];
302  res[componentId].AddEdge(vertices, e.Data(), e.Weight());
303  }
304 
305  return res;
306  }
307 
313  template<typename V, typename E>
315  {
316  std::vector<Vertex<V>> vertices;
318 
319  // Add all vertices.
320  for (auto const &vPair : _graph.Vertices())
321  {
322  // cppcheck-suppress useStlAlgorithm
323  vertices.push_back(vPair.second.get());
324  }
325 
326  // Add all edges.
327  for (auto const &ePair : _graph.Edges())
328  {
329  auto const &e = ePair.second.get();
330  edges.push_back({e.Vertices(), e.Data(), e.Weight()});
331  }
332 
333  return UndirectedGraph<V, E>(vertices, edges);
334  }
335 
358  template<typename V, typename E, typename EdgeType>
360  const Graph<V, E, EdgeType> &_graph, const VertexId &_vertex)
361  {
362  std::vector<VertexId> chain;
363  if (!_graph.VertexFromId(_vertex).Valid())
364  return {chain, false};
365 
367  seen.insert(_vertex);
368  VertexId cur = _vertex;
369  while (true)
370  {
371  auto parents = _graph.AdjacentsTo(cur);
372  if (parents.empty())
373  return {chain, true};
374  const VertexId next = parents.begin()->first;
375  // Cycle guard: stop if we revisit a vertex.
376  if (!seen.insert(next).second)
377  return {chain, false};
378  chain.push_back(next);
379  cur = next;
380  }
381  }
382 
391  template<typename V, typename E, typename EdgeType>
393  const Graph<V, E, EdgeType> &_graph,
394  const VertexId &_ancestor,
395  const VertexId &_descendant)
396  {
397  if (_ancestor == _descendant)
398  return false;
399  if (!_graph.VertexFromId(_ancestor).Valid() ||
400  !_graph.VertexFromId(_descendant).Valid())
401  {
402  return false;
403  }
404 
406  seen.insert(_descendant);
407  VertexId cur = _descendant;
408  while (true)
409  {
410  auto parents = _graph.AdjacentsTo(cur);
411  if (parents.empty())
412  return false;
413  const VertexId next = parents.begin()->first;
414  if (next == _ancestor)
415  return true;
416  // Cycle guard.
417  if (!seen.insert(next).second)
418  return false;
419  cur = next;
420  }
421  }
422 
437  template<typename V, typename E, typename EdgeType>
439  const Graph<V, E, EdgeType> &_graph,
440  const VertexId &_a, const VertexId &_b)
441  {
442  if (!_graph.VertexFromId(_a).Valid() ||
443  !_graph.VertexFromId(_b).Valid())
444  {
445  return kNullId;
446  }
447  if (_a == _b)
448  return _a;
449 
450  std::unordered_set<VertexId> ancestorsA;
451  ancestorsA.insert(_a);
452  for (auto v : Ancestors(_graph, _a).first)
453  ancestorsA.insert(v);
454 
455  if (ancestorsA.count(_b))
456  return _b;
457  for (auto v : Ancestors(_graph, _b).first)
458  {
459  if (ancestorsA.count(v))
460  return v;
461  }
462  return kNullId;
463  }
464 
478  template<typename V, typename E, typename EdgeType>
480  const Graph<V, E, EdgeType> &_graph, const VertexId &_root)
481  {
483  if (!_graph.VertexFromId(_root).Valid())
484  return out;
485 
486  auto descendants = BreadthFirstSort(_graph, _root);
487  std::unordered_set<VertexId> set(descendants.begin(), descendants.end());
488 
489  // Copy vertices preserving ids.
490  for (auto id : descendants)
491  {
492  const auto &v = _graph.VertexFromId(id);
493  out.AddVertex(v.Name(), v.Data(), v.Id());
494  }
495  // Copy edges whose endpoints both lie in the reachable set.
496  for (auto const &ePair : _graph.Edges())
497  {
498  auto const &e = ePair.second.get();
499  auto vs = e.Vertices();
500  if (set.count(vs.first) && set.count(vs.second))
501  out.AddEdge(vs, e.Data(), e.Weight());
502  }
503  return out;
504  }
505 
513  template<typename V, typename E, typename EdgeType>
515  const Graph<V, E, EdgeType> &_graph, const VertexId &_vertex)
516  {
518  if (!_graph.VertexFromId(_vertex).Valid())
519  return out;
520 
521  std::queue<VertexId> pending;
522  pending.push(_vertex);
523  out.insert(_vertex);
524  while (!pending.empty())
525  {
526  const VertexId u = pending.front();
527  pending.pop();
528  for (auto const &adj : _graph.AdjacentsFrom(u))
529  {
530  if (out.insert(adj.first).second)
531  pending.push(adj.first);
532  }
533  }
534  return out;
535  }
536 } // namespace graph
537 } // namespace GZ_MATH_VERSION_NAMESPACE
538 } // namespace gz::math
539 #endif // GZ_MATH_GRAPH_GRAPHALGORITHMS_HH_