Gazebo Math

API Reference

9.2.0
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/detail/Error.hh"
31#include "gz/math/Helpers.hh"
32
33namespace gz::math
34{
35// Inline bracket to help doxygen filtering.
36inline namespace GZ_MATH_VERSION_NAMESPACE {
37namespace graph
38{
43
51 template<typename V, typename E, typename EdgeType>
53 const VertexId &_from)
54 {
55 if (!_graph.VertexFromId(_from).Valid())
56 return {};
57
61
62 // Mark-on-enqueue: each vertex enters the queue at most once.
63 pending.push(_from);
64 seen.insert(_from);
65
66 while (!pending.empty())
67 {
68 const VertexId u = pending.front();
69 pending.pop();
70 visited.push_back(u);
71
72 for (auto const &adj : _graph.AdjacentsFrom(u))
73 {
74 const VertexId next = adj.first;
75 if (seen.insert(next).second)
76 pending.push(next);
77 }
78 }
79 return visited;
80 }
81
89 template<typename V, typename E, typename EdgeType>
91 const VertexId &_from)
92 {
93 if (!_graph.VertexFromId(_from).Valid())
94 return {};
95
99 pending.push(_from);
100
101 // Mark-on-pop: matches the textbook DFS visitation order. Children are
102 // pushed unconditionally and duplicate entries are skipped at pop time.
103 while (!pending.empty())
104 {
105 const VertexId u = pending.top();
106 pending.pop();
107
108 if (!seen.insert(u).second)
109 continue;
110 visited.push_back(u);
111
112 for (auto const &adj : _graph.AdjacentsFrom(u))
113 {
114 const VertexId next = adj.first;
115 if (!seen.count(next))
116 pending.push(next);
117 }
118 }
119 return visited;
120 }
121
185 template<typename V, typename E, typename EdgeType>
187 const VertexId &_from,
188 const VertexId &_to = kNullId)
189 {
190 auto allVertices = _graph.Vertices();
191
192 // Sanity check: The source vertex should exist.
193 if (allVertices.find(_from) == allVertices.end())
194 {
196 errStream << "Vertex [" << _from << "] Not found";
197 detail::LogErrorMessage(errStream.str());
198 return {};
199 }
200
201 // Sanity check: The destination vertex should exist (if used).
202 if (_to != kNullId &&
203 allVertices.find(_to) == allVertices.end())
204 {
206 errStream << "Vertex [" << _to << "] Not found";
207 detail::LogErrorMessage(errStream.str());
208 return {};
209 }
210
211 // Store vertices that are being preprocessed.
214
215 // Create a map for distances and next neighbor and initialize all
216 // distances as infinite.
218 for (auto const &v : allVertices)
219 {
220 auto id = v.first;
221 dist[id] = std::make_pair(MAX_D, kNullId);
222 }
223
224 // Insert _from in the priority queue and initialize its distance as 0.
225 pq.push(std::make_pair(0.0, _from));
227
228 while (!pq.empty())
229 {
230 // This is the minimum distance vertex.
231 const double poppedCost = pq.top().first;
232 VertexId u = pq.top().second;
233
234 // Shortcut: Destination vertex found, exiting.
235 if (_to != kNullId && _to == u)
236 break;
237
238 pq.pop();
239
240 // Skip stale priority-queue entries left behind by relaxation
241 // updates: dist[u] is the authoritative cost; if the popped cost is
242 // greater, this entry was queued before u was settled.
243 if (poppedCost > dist[u].first)
244 continue;
245
246 for (auto const &edgePair : _graph.IncidentsFrom(u))
247 {
248 const auto &edge = edgePair.second.get();
249 const auto &v = edge.From(u);
250 double weight = edge.Weight();
251
252 // If there is a shorter path to v through u.
253 if (dist[v].first > dist[u].first + weight)
254 {
255 // Update distance of v.
256 dist[v] = std::make_pair(dist[u].first + weight, u);
257 pq.push(std::make_pair(dist[v].first, v));
258 }
259 }
260 }
261
262 return dist;
263 }
264
273 template<typename V, typename E>
276 {
278 unsigned int componentCount = 0;
279
280 for (auto const &v : _graph.Vertices())
281 {
282 if (visited.find(v.first) == visited.end())
283 {
284 auto component = BreadthFirstSort(_graph, v.first);
285 for (auto const &vId : component)
288 }
289 }
290
292
293 // Create the vertices.
294 for (auto const &vPair : _graph.Vertices())
295 {
296 const auto &v = vPair.second.get();
297 const auto &componentId = visited[v.Id()];
298 res[componentId].AddVertex(v.Name(), v.Data(), v.Id());
299 }
300
301 // Create the edges.
302 for (auto const &ePair : _graph.Edges())
303 {
304 const auto &e = ePair.second.get();
305 const auto &vertices = e.Vertices();
306 const auto &componentId = visited[vertices.first];
307 res[componentId].AddEdge(vertices, e.Data(), e.Weight());
308 }
309
310 return res;
311 }
312
318 template<typename V, typename E>
320 {
321 std::vector<Vertex<V>> vertices;
323
324 // Add all vertices.
325 for (auto const &vPair : _graph.Vertices())
326 {
327 // cppcheck-suppress useStlAlgorithm
328 vertices.push_back(vPair.second.get());
329 }
330
331 // Add all edges.
332 for (auto const &ePair : _graph.Edges())
333 {
334 auto const &e = ePair.second.get();
335 edges.push_back({e.Vertices(), e.Data(), e.Weight()});
336 }
337
338 return UndirectedGraph<V, E>(vertices, edges);
339 }
340
363 template<typename V, typename E, typename EdgeType>
366 {
368 if (!_graph.VertexFromId(_vertex).Valid())
369 return {chain, false};
370
372 seen.insert(_vertex);
374 while (true)
375 {
376 auto parents = _graph.AdjacentsTo(cur);
377 if (parents.empty())
378 return {chain, true};
379 const VertexId next = parents.begin()->first;
380 // Cycle guard: stop if we revisit a vertex.
381 if (!seen.insert(next).second)
382 return {chain, false};
383 chain.push_back(next);
384 cur = next;
385 }
386 }
387
396 template<typename V, typename E, typename EdgeType>
399 const VertexId &_ancestor,
400 const VertexId &_descendant)
401 {
402 if (_ancestor == _descendant)
403 return false;
404 if (!_graph.VertexFromId(_ancestor).Valid() ||
405 !_graph.VertexFromId(_descendant).Valid())
406 {
407 return false;
408 }
409
411 seen.insert(_descendant);
413 while (true)
414 {
415 auto parents = _graph.AdjacentsTo(cur);
416 if (parents.empty())
417 return false;
418 const VertexId next = parents.begin()->first;
419 if (next == _ancestor)
420 return true;
421 // Cycle guard.
422 if (!seen.insert(next).second)
423 return false;
424 cur = next;
425 }
426 }
427
442 template<typename V, typename E, typename EdgeType>
445 const VertexId &_a, const VertexId &_b)
446 {
447 if (!_graph.VertexFromId(_a).Valid() ||
448 !_graph.VertexFromId(_b).Valid())
449 {
450 return kNullId;
451 }
452 if (_a == _b)
453 return _a;
454
456 ancestorsA.insert(_a);
457 for (auto v : Ancestors(_graph, _a).first)
458 ancestorsA.insert(v);
459
460 if (ancestorsA.count(_b))
461 return _b;
462 for (auto v : Ancestors(_graph, _b).first)
463 {
464 if (ancestorsA.count(v))
465 return v;
466 }
467 return kNullId;
468 }
469
483 template<typename V, typename E, typename EdgeType>
486 {
488 if (!_graph.VertexFromId(_root).Valid())
489 return out;
490
493
494 // Copy vertices preserving ids.
495 for (auto id : descendants)
496 {
497 const auto &v = _graph.VertexFromId(id);
498 out.AddVertex(v.Name(), v.Data(), v.Id());
499 }
500 // Copy edges whose endpoints both lie in the reachable set.
501 for (auto const &ePair : _graph.Edges())
502 {
503 auto const &e = ePair.second.get();
504 auto vs = e.Vertices();
505 if (set.count(vs.first) && set.count(vs.second))
506 out.AddEdge(vs, e.Data(), e.Weight());
507 }
508 return out;
509 }
510
518 template<typename V, typename E, typename EdgeType>
521 {
523 if (!_graph.VertexFromId(_vertex).Valid())
524 return out;
525
527 pending.push(_vertex);
528 out.insert(_vertex);
529 while (!pending.empty())
530 {
531 const VertexId u = pending.front();
532 pending.pop();
533 for (auto const &adj : _graph.AdjacentsFrom(u))
534 {
535 if (out.insert(adj.first).second)
536 pending.push(adj.first);
537 }
538 }
539 return out;
540 }
541} // namespace graph
542} // namespace GZ_MATH_VERSION_NAMESPACE
543} // namespace gz::math
544#endif // GZ_MATH_GRAPH_GRAPHALGORITHMS_HH_