Gazebo Math
API Reference
9.2.0
insert_drive_file
Tutorials
library_books
Classes
toc
Namespaces
insert_drive_file
Files
launch
Gazebo Website
Index
List
Hierarchy
Members: All
Members: Functions
Members: Variables
Members: Typedefs
Members: Enumerations
Members: Enumerator
List
Members
Functions
Typedefs
Variables
Enumerations
Enumerator
src
gz-math
include
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/detail/Error.hh"
30
#include "
gz/math/graph/Graph.hh
"
31
#include "
gz/math/Helpers.hh
"
32
33
namespace
gz::math
34
{
35
// Inline bracket to help doxygen filtering.
36
inline
namespace
GZ_MATH_VERSION_NAMESPACE {
37
namespace
graph
38
{
42
using
CostInfo
=
std::pair<double, VertexId>
;
43
51
template
<
typename
V,
typename
E,
typename
EdgeType>
52
std::vector<VertexId>
BreadthFirstSort
(
const
Graph<V, E, EdgeType>
&
_graph
,
53
const
VertexId
&
_from
)
54
{
55
if
(!
_graph
.VertexFromId(
_from
).Valid())
56
return
{};
57
58
std::vector<VertexId>
visited
;
59
std::unordered_set<VertexId>
seen
;
60
std::queue<VertexId>
pending
;
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>
90
std::vector<VertexId>
DepthFirstSort
(
const
Graph<V, E, EdgeType>
&
_graph
,
91
const
VertexId
&
_from
)
92
{
93
if
(!
_graph
.VertexFromId(
_from
).Valid())
94
return
{};
95
96
std::vector<VertexId>
visited
;
97
std::unordered_set<VertexId>
seen
;
98
std::stack<VertexId>
pending
;
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>
186
std::map<VertexId, CostInfo>
Dijkstra
(
const
Graph<V, E, EdgeType>
&
_graph
,
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
{
195
std::ostringstream
errStream
;
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
{
205
std::ostringstream
errStream
;
206
errStream
<<
"Vertex ["
<<
_to
<<
"] Not found"
;
207
detail::LogErrorMessage(
errStream
.str());
208
return
{};
209
}
210
211
// Store vertices that are being preprocessed.
212
std::priority_queue
<
CostInfo
,
213
std::vector<CostInfo>
,
std::greater<CostInfo>
>
pq
;
214
215
// Create a map for distances and next neighbor and initialize all
216
// distances as infinite.
217
std::map<VertexId, CostInfo>
dist
;
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
));
226
dist
[
_from
] =
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>
274
std::vector<UndirectedGraph<V, E>
>
ConnectedComponents
(
275
const
UndirectedGraph<V, E>
&
_graph
)
276
{
277
std::map<VertexId, unsigned int>
visited
;
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
)
286
visited
[
vId
] =
componentCount
;
287
++
componentCount
;
288
}
289
}
290
291
std::vector<UndirectedGraph<V, E>
>
res
(
componentCount
);
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>
319
UndirectedGraph<V, E>
ToUndirectedGraph
(
const
DirectedGraph<V, E>
&
_graph
)
320
{
321
std::vector<Vertex<V>
> vertices;
322
std::vector<EdgeInitializer<E>
> edges;
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>
364
std::pair<std::vector<VertexId>
,
bool
>
Ancestors
(
365
const
Graph<V, E, EdgeType>
&
_graph
,
const
VertexId
&
_vertex
)
366
{
367
std::vector<VertexId>
chain
;
368
if
(!
_graph
.VertexFromId(
_vertex
).Valid())
369
return
{
chain
,
false
};
370
371
std::unordered_set<VertexId>
seen
;
372
seen
.insert(
_vertex
);
373
VertexId
cur
=
_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>
397
bool
IsAncestor
(
398
const
Graph<V, E, EdgeType>
&
_graph
,
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
410
std::unordered_set<VertexId>
seen
;
411
seen
.insert(
_descendant
);
412
VertexId
cur
=
_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>
443
VertexId
LowestCommonAncestor
(
444
const
Graph<V, E, EdgeType>
&
_graph
,
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
455
std::unordered_set<VertexId>
ancestorsA
;
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>
484
Graph<V, E, EdgeType>
Subgraph
(
485
const
Graph<V, E, EdgeType>
&
_graph
,
const
VertexId
&
_root
)
486
{
487
Graph<V, E, EdgeType>
out;
488
if
(!
_graph
.VertexFromId(
_root
).Valid())
489
return
out;
490
491
auto
descendants
=
BreadthFirstSort
(
_graph
,
_root
);
492
std::unordered_set<VertexId>
set(
descendants
.begin(),
descendants
.end());
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>
519
std::unordered_set<VertexId>
DescendantsSet
(
520
const
Graph<V, E, EdgeType>
&
_graph
,
const
VertexId
&
_vertex
)
521
{
522
std::unordered_set<VertexId>
out;
523
if
(!
_graph
.VertexFromId(
_vertex
).Valid())
524
return
out;
525
526
std::queue<VertexId>
pending
;
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_