Coverage Report

Created: 2026-03-12 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/petgraph-0.8.3/src/visit/traversal.rs
Line
Count
Source
1
use alloc::{collections::VecDeque, vec::Vec};
2
3
use super::{
4
    GraphRef, IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, Reversed, VisitMap,
5
    Visitable,
6
};
7
use crate::Incoming;
8
9
/// Visit nodes of a graph in a depth-first-search (DFS) emitting nodes in
10
/// preorder (when they are first discovered).
11
///
12
/// The traversal starts at a given node and only traverses nodes reachable
13
/// from it.
14
///
15
/// `Dfs` is not recursive.
16
///
17
/// `Dfs` does not itself borrow the graph, and because of this you can run
18
/// a traversal over a graph while still retaining mutable access to it, if you
19
/// use it like the following example:
20
///
21
/// ```
22
/// use petgraph::Graph;
23
/// use petgraph::visit::Dfs;
24
///
25
/// let mut graph = Graph::<_,()>::new();
26
/// let a = graph.add_node(0);
27
///
28
/// let mut dfs = Dfs::new(&graph, a);
29
/// while let Some(nx) = dfs.next(&graph) {
30
///     // we can access `graph` mutably here still
31
///     graph[nx] += 1;
32
/// }
33
///
34
/// assert_eq!(graph[a], 1);
35
/// ```
36
///
37
/// **Note:** The algorithm may not behave correctly if nodes are removed
38
/// during iteration. It may not necessarily visit added nodes or edges.
39
#[derive(Clone, Debug)]
40
pub struct Dfs<N, VM> {
41
    /// The stack of nodes to visit
42
    pub stack: Vec<N>,
43
    /// The map of discovered nodes
44
    pub discovered: VM,
45
}
46
47
impl<N, VM> Default for Dfs<N, VM>
48
where
49
    VM: Default,
50
{
51
0
    fn default() -> Self {
52
0
        Dfs {
53
0
            stack: Vec::new(),
54
0
            discovered: VM::default(),
55
0
        }
56
0
    }
57
}
58
59
impl<N, VM> Dfs<N, VM>
60
where
61
    N: Copy + PartialEq,
62
    VM: VisitMap<N>,
63
{
64
    /// Create a new **Dfs**, using the graph's visitor map, and put **start**
65
    /// in the stack of nodes to visit.
66
0
    pub fn new<G>(graph: G, start: N) -> Self
67
0
    where
68
0
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
69
    {
70
0
        let mut dfs = Dfs::empty(graph);
71
0
        dfs.move_to(start);
72
0
        dfs
73
0
    }
74
75
    /// Create a `Dfs` from a vector and a visit map
76
0
    pub fn from_parts(stack: Vec<N>, discovered: VM) -> Self {
77
0
        Dfs { stack, discovered }
78
0
    }
79
80
    /// Clear the visit state
81
2
    pub fn reset<G>(&mut self, graph: G)
82
2
    where
83
2
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
84
    {
85
2
        graph.reset_map(&mut self.discovered);
86
2
        self.stack.clear();
87
2
    }
<petgraph::visit::traversal::Dfs<u32, hashbrown::set::HashSet<u32>>>::reset::<&petgraph::graphmap::GraphMap<u32, (), petgraph::Directed, core::hash::BuildHasherDefault<rustc_hash::FxHasher>>>
Line
Count
Source
81
2
    pub fn reset<G>(&mut self, graph: G)
82
2
    where
83
2
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
84
    {
85
2
        graph.reset_map(&mut self.discovered);
86
2
        self.stack.clear();
87
2
    }
Unexecuted instantiation: <petgraph::visit::traversal::Dfs<_, _>>::reset::<_>
88
89
    /// Create a new **Dfs** using the graph's visitor map, and no stack.
90
1
    pub fn empty<G>(graph: G) -> Self
91
1
    where
92
1
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
93
    {
94
1
        Dfs {
95
1
            stack: Vec::new(),
96
1
            discovered: graph.visit_map(),
97
1
        }
98
1
    }
<petgraph::visit::traversal::Dfs<u32, hashbrown::set::HashSet<u32>>>::empty::<&petgraph::graphmap::GraphMap<u32, (), petgraph::Directed, core::hash::BuildHasherDefault<rustc_hash::FxHasher>>>
Line
Count
Source
90
1
    pub fn empty<G>(graph: G) -> Self
91
1
    where
92
1
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
93
    {
94
1
        Dfs {
95
1
            stack: Vec::new(),
96
1
            discovered: graph.visit_map(),
97
1
        }
98
1
    }
Unexecuted instantiation: <petgraph::visit::traversal::Dfs<_, _>>::empty::<_>
99
100
    /// Keep the discovered map, but clear the visit stack and restart
101
    /// the dfs from a particular node.
102
0
    pub fn move_to(&mut self, start: N) {
103
0
        self.stack.clear();
104
0
        self.stack.push(start);
105
0
    }
Unexecuted instantiation: <petgraph::visit::traversal::Dfs<u32, hashbrown::set::HashSet<u32>>>::move_to
Unexecuted instantiation: <petgraph::visit::traversal::Dfs<_, _>>::move_to
106
107
    /// Return the next node in the dfs, or **None** if the traversal is done.
108
0
    pub fn next<G>(&mut self, graph: G) -> Option<N>
109
0
    where
110
0
        G: IntoNeighbors<NodeId = N>,
111
    {
112
0
        while let Some(node) = self.stack.pop() {
113
0
            if self.discovered.visit(node) {
114
0
                for succ in graph.neighbors(node) {
115
0
                    if !self.discovered.is_visited(&succ) {
116
0
                        self.stack.push(succ);
117
0
                    }
118
                }
119
0
                return Some(node);
120
0
            }
121
        }
122
0
        None
123
0
    }
Unexecuted instantiation: <petgraph::visit::traversal::Dfs<u32, hashbrown::set::HashSet<u32>>>::next::<petgraph::visit::reversed::Reversed<&petgraph::graphmap::GraphMap<u32, (), petgraph::Directed, core::hash::BuildHasherDefault<rustc_hash::FxHasher>>>>
Unexecuted instantiation: <petgraph::visit::traversal::Dfs<_, _>>::next::<_>
124
}
125
126
/// Visit nodes in a depth-first-search (DFS) emitting nodes in postorder
127
/// (each node after all its descendants have been emitted).
128
///
129
/// `DfsPostOrder` is not recursive.
130
///
131
/// The traversal starts at a given node and only traverses nodes reachable
132
/// from it.
133
#[derive(Clone, Debug)]
134
pub struct DfsPostOrder<N, VM> {
135
    /// The stack of nodes to visit
136
    pub stack: Vec<N>,
137
    /// The map of discovered nodes
138
    pub discovered: VM,
139
    /// The map of finished nodes
140
    pub finished: VM,
141
}
142
143
impl<N, VM> Default for DfsPostOrder<N, VM>
144
where
145
    VM: Default,
146
{
147
0
    fn default() -> Self {
148
0
        DfsPostOrder {
149
0
            stack: Vec::new(),
150
0
            discovered: VM::default(),
151
0
            finished: VM::default(),
152
0
        }
153
0
    }
154
}
155
156
impl<N, VM> DfsPostOrder<N, VM>
157
where
158
    N: Copy + PartialEq,
159
    VM: VisitMap<N>,
160
{
161
    /// Create a new `DfsPostOrder` using the graph's visitor map, and put
162
    /// `start` in the stack of nodes to visit.
163
0
    pub fn new<G>(graph: G, start: N) -> Self
164
0
    where
165
0
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
166
    {
167
0
        let mut dfs = Self::empty(graph);
168
0
        dfs.move_to(start);
169
0
        dfs
170
0
    }
171
172
    /// Create a new `DfsPostOrder` using the graph's visitor map, and no stack.
173
0
    pub fn empty<G>(graph: G) -> Self
174
0
    where
175
0
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
176
    {
177
0
        DfsPostOrder {
178
0
            stack: Vec::new(),
179
0
            discovered: graph.visit_map(),
180
0
            finished: graph.visit_map(),
181
0
        }
182
0
    }
183
184
    /// Clear the visit state
185
0
    pub fn reset<G>(&mut self, graph: G)
186
0
    where
187
0
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
188
    {
189
0
        graph.reset_map(&mut self.discovered);
190
0
        graph.reset_map(&mut self.finished);
191
0
        self.stack.clear();
192
0
    }
193
194
    /// Keep the discovered and finished map, but clear the visit stack and restart
195
    /// the dfs from a particular node.
196
0
    pub fn move_to(&mut self, start: N) {
197
0
        self.stack.clear();
198
0
        self.stack.push(start);
199
0
    }
200
201
    /// Return the next node in the traversal, or `None` if the traversal is done.
202
0
    pub fn next<G>(&mut self, graph: G) -> Option<N>
203
0
    where
204
0
        G: IntoNeighbors<NodeId = N>,
205
    {
206
0
        while let Some(&nx) = self.stack.last() {
207
0
            if self.discovered.visit(nx) {
208
                // First time visiting `nx`: Push neighbors, don't pop `nx`
209
0
                for succ in graph.neighbors(nx) {
210
0
                    if !self.discovered.is_visited(&succ) {
211
0
                        self.stack.push(succ);
212
0
                    }
213
                }
214
            } else {
215
0
                self.stack.pop();
216
0
                if self.finished.visit(nx) {
217
                    // Second time: All reachable nodes must have been finished
218
0
                    return Some(nx);
219
0
                }
220
            }
221
        }
222
0
        None
223
0
    }
224
}
225
226
/// A breadth first search (BFS) of a graph.
227
///
228
/// The traversal starts at a given node and only traverses nodes reachable
229
/// from it.
230
///
231
/// `Bfs` is not recursive.
232
///
233
/// `Bfs` does not itself borrow the graph, and because of this you can run
234
/// a traversal over a graph while still retaining mutable access to it, if you
235
/// use it like the following example:
236
///
237
/// ```
238
/// use petgraph::Graph;
239
/// use petgraph::visit::Bfs;
240
///
241
/// let mut graph = Graph::<_,()>::new();
242
/// let a = graph.add_node(0);
243
///
244
/// let mut bfs = Bfs::new(&graph, a);
245
/// while let Some(nx) = bfs.next(&graph) {
246
///     // we can access `graph` mutably here still
247
///     graph[nx] += 1;
248
/// }
249
///
250
/// assert_eq!(graph[a], 1);
251
/// ```
252
///
253
/// **Note:** The algorithm may not behave correctly if nodes are removed
254
/// during iteration. It may not necessarily visit added nodes or edges.
255
#[derive(Clone)]
256
pub struct Bfs<N, VM> {
257
    /// The queue of nodes to visit
258
    pub stack: VecDeque<N>,
259
    /// The map of discovered nodes
260
    pub discovered: VM,
261
}
262
263
impl<N, VM> Default for Bfs<N, VM>
264
where
265
    VM: Default,
266
{
267
0
    fn default() -> Self {
268
0
        Bfs {
269
0
            stack: VecDeque::new(),
270
0
            discovered: VM::default(),
271
0
        }
272
0
    }
273
}
274
275
impl<N, VM> Bfs<N, VM>
276
where
277
    N: Copy + PartialEq,
278
    VM: VisitMap<N>,
279
{
280
    /// Create a new **Bfs**, using the graph's visitor map, and put **start**
281
    /// in the stack of nodes to visit.
282
0
    pub fn new<G>(graph: G, start: N) -> Self
283
0
    where
284
0
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
285
    {
286
0
        let mut discovered = graph.visit_map();
287
0
        discovered.visit(start);
288
0
        let mut stack = VecDeque::new();
289
0
        stack.push_front(start);
290
0
        Bfs { stack, discovered }
291
0
    }
292
293
    /// Return the next node in the bfs, or **None** if the traversal is done.
294
0
    pub fn next<G>(&mut self, graph: G) -> Option<N>
295
0
    where
296
0
        G: IntoNeighbors<NodeId = N>,
297
    {
298
0
        if let Some(node) = self.stack.pop_front() {
299
0
            for succ in graph.neighbors(node) {
300
0
                if self.discovered.visit(succ) {
301
0
                    self.stack.push_back(succ);
302
0
                }
303
            }
304
305
0
            return Some(node);
306
0
        }
307
0
        None
308
0
    }
309
}
310
311
/// A topological order traversal for a graph.
312
///
313
/// **Note** that `Topo` only visits nodes that are not part of cycles,
314
/// i.e. nodes in a true DAG. Use other visitors like [`DfsPostOrder`] or
315
/// algorithms like [`kosaraju_scc`][crate::algo::kosaraju_scc()] to handle
316
/// graphs with possible cycles.
317
#[derive(Clone)]
318
pub struct Topo<N, VM> {
319
    tovisit: Vec<N>,
320
    ordered: VM,
321
}
322
323
impl<N, VM> Default for Topo<N, VM>
324
where
325
    VM: Default,
326
{
327
0
    fn default() -> Self {
328
0
        Topo {
329
0
            tovisit: Vec::new(),
330
0
            ordered: VM::default(),
331
0
        }
332
0
    }
333
}
334
335
impl<N, VM> Topo<N, VM>
336
where
337
    N: Copy + PartialEq,
338
    VM: VisitMap<N>,
339
{
340
    /// Create a new `Topo`, using the graph's visitor map, and put all
341
    /// initial nodes in the to visit list.
342
0
    pub fn new<G>(graph: G) -> Self
343
0
    where
344
0
        G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
345
    {
346
0
        let mut topo = Self::empty(graph);
347
0
        topo.extend_with_initials(graph);
348
0
        topo
349
0
    }
350
351
    /// Create a new `Topo` with initial nodes.
352
    ///
353
    /// Nodes with incoming edges are ignored.
354
0
    pub fn with_initials<G, I>(graph: G, initials: I) -> Self
355
0
    where
356
0
        G: IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
357
0
        I: IntoIterator<Item = N>,
358
    {
359
        Topo {
360
0
            tovisit: initials
361
0
                .into_iter()
362
0
                .filter(|&n| graph.neighbors_directed(n, Incoming).next().is_none())
363
0
                .collect(),
364
0
            ordered: graph.visit_map(),
365
        }
366
0
    }
367
368
0
    fn extend_with_initials<G>(&mut self, g: G)
369
0
    where
370
0
        G: IntoNodeIdentifiers + IntoNeighborsDirected<NodeId = N>,
371
    {
372
        // find all initial nodes (nodes without incoming edges)
373
0
        self.tovisit.extend(
374
0
            g.node_identifiers()
375
0
                .filter(move |&a| g.neighbors_directed(a, Incoming).next().is_none()),
376
        );
377
0
    }
378
379
    /* Private until it has a use */
380
    /// Create a new `Topo`, using the graph's visitor map with *no* starting
381
    /// index specified.
382
0
    fn empty<G>(graph: G) -> Self
383
0
    where
384
0
        G: GraphRef + Visitable<NodeId = N, Map = VM>,
385
    {
386
0
        Topo {
387
0
            ordered: graph.visit_map(),
388
0
            tovisit: Vec::new(),
389
0
        }
390
0
    }
391
392
    /// Clear visited state, and put all initial nodes in the to visit list.
393
0
    pub fn reset<G>(&mut self, graph: G)
394
0
    where
395
0
        G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
396
    {
397
0
        graph.reset_map(&mut self.ordered);
398
0
        self.tovisit.clear();
399
0
        self.extend_with_initials(graph);
400
0
    }
401
402
    /// Return the next node in the current topological order traversal, or
403
    /// `None` if the traversal is at the end.
404
    ///
405
    /// *Note:* The graph may not have a complete topological order, and the only
406
    /// way to know is to run the whole traversal and make sure it visits every node.
407
0
    pub fn next<G>(&mut self, g: G) -> Option<N>
408
0
    where
409
0
        G: IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
410
    {
411
        // Take an unvisited element and find which of its neighbors are next
412
0
        while let Some(nix) = self.tovisit.pop() {
413
0
            if self.ordered.is_visited(&nix) {
414
0
                continue;
415
0
            }
416
0
            self.ordered.visit(nix);
417
0
            for neigh in g.neighbors(nix) {
418
                // Look at each neighbor, and those that only have incoming edges
419
                // from the already ordered list, they are the next to visit.
420
0
                if Reversed(g)
421
0
                    .neighbors(neigh)
422
0
                    .all(|b| self.ordered.is_visited(&b))
423
0
                {
424
0
                    self.tovisit.push(neigh);
425
0
                }
426
            }
427
0
            return Some(nix);
428
        }
429
0
        None
430
0
    }
431
}
432
433
/// A walker is a traversal state, but where part of the traversal
434
/// information is supplied manually to each next call.
435
///
436
/// This for example allows graph traversals that don't hold a borrow of the
437
/// graph they are traversing.
438
pub trait Walker<Context> {
439
    type Item;
440
    /// Advance to the next item
441
    fn walk_next(&mut self, context: Context) -> Option<Self::Item>;
442
443
    /// Create an iterator out of the walker and given `context`.
444
0
    fn iter(self, context: Context) -> WalkerIter<Self, Context>
445
0
    where
446
0
        Self: Sized,
447
0
        Context: Clone,
448
    {
449
0
        WalkerIter {
450
0
            walker: self,
451
0
            context,
452
0
        }
453
0
    }
454
}
455
456
/// A walker and its context wrapped into an iterator.
457
#[derive(Clone, Debug)]
458
pub struct WalkerIter<W, C> {
459
    walker: W,
460
    context: C,
461
}
462
463
impl<W, C> WalkerIter<W, C>
464
where
465
    W: Walker<C>,
466
    C: Clone,
467
{
468
0
    pub fn context(&self) -> C {
469
0
        self.context.clone()
470
0
    }
471
472
0
    pub fn inner_ref(&self) -> &W {
473
0
        &self.walker
474
0
    }
475
476
0
    pub fn inner_mut(&mut self) -> &mut W {
477
0
        &mut self.walker
478
0
    }
479
}
480
481
impl<W, C> Iterator for WalkerIter<W, C>
482
where
483
    W: Walker<C>,
484
    C: Clone,
485
{
486
    type Item = W::Item;
487
0
    fn next(&mut self) -> Option<Self::Item> {
488
0
        self.walker.walk_next(self.context.clone())
489
0
    }
490
}
491
492
impl<C, W: ?Sized> Walker<C> for &mut W
493
where
494
    W: Walker<C>,
495
{
496
    type Item = W::Item;
497
0
    fn walk_next(&mut self, context: C) -> Option<Self::Item> {
498
0
        (**self).walk_next(context)
499
0
    }
500
}
501
502
impl<G> Walker<G> for Dfs<G::NodeId, G::Map>
503
where
504
    G: IntoNeighbors + Visitable,
505
{
506
    type Item = G::NodeId;
507
0
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
508
0
        self.next(context)
509
0
    }
510
}
511
512
impl<G> Walker<G> for DfsPostOrder<G::NodeId, G::Map>
513
where
514
    G: IntoNeighbors + Visitable,
515
{
516
    type Item = G::NodeId;
517
0
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
518
0
        self.next(context)
519
0
    }
520
}
521
522
impl<G> Walker<G> for Bfs<G::NodeId, G::Map>
523
where
524
    G: IntoNeighbors + Visitable,
525
{
526
    type Item = G::NodeId;
527
0
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
528
0
        self.next(context)
529
0
    }
530
}
531
532
impl<G> Walker<G> for Topo<G::NodeId, G::Map>
533
where
534
    G: IntoNeighborsDirected + Visitable,
535
{
536
    type Item = G::NodeId;
537
0
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
538
0
        self.next(context)
539
0
    }
540
}