petgraph/visit/
filter.rs

1use core::marker::PhantomData;
2
3use fixedbitset::FixedBitSet;
4use hashbrown::HashSet;
5
6use crate::{
7    data::DataMap,
8    prelude::*,
9    visit::{
10        Data, EdgeIndexable, GraphBase, GraphProp, IntoEdgeReferences, IntoEdges,
11        IntoEdgesDirected, IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers,
12        IntoNodeReferences, NodeCompactIndexable, NodeCount, NodeIndexable, NodeRef, VisitMap,
13        Visitable,
14    },
15};
16
17/// A graph filter for nodes.
18pub trait FilterNode<N> {
19    /// Return true to have the node be part of the graph
20    fn include_node(&self, node: N) -> bool;
21}
22
23impl<F, N> FilterNode<N> for F
24where
25    F: Fn(N) -> bool,
26{
27    fn include_node(&self, n: N) -> bool {
28        (*self)(n)
29    }
30}
31
32/// This filter includes the nodes that are contained in the set.
33impl<N> FilterNode<N> for FixedBitSet
34where
35    FixedBitSet: VisitMap<N>,
36{
37    fn include_node(&self, n: N) -> bool {
38        self.is_visited(&n)
39    }
40}
41
42/// This filter includes the nodes that are contained in the set.
43impl<N, S> FilterNode<N> for HashSet<N, S>
44where
45    HashSet<N, S>: VisitMap<N>,
46{
47    fn include_node(&self, n: N) -> bool {
48        self.is_visited(&n)
49    }
50}
51
52// Can't express these as a generic impl over all references since that would conflict with the
53// impl for Fn.
54impl<N> FilterNode<N> for &FixedBitSet
55where
56    FixedBitSet: VisitMap<N>,
57{
58    fn include_node(&self, n: N) -> bool {
59        self.is_visited(&n)
60    }
61}
62
63impl<N, S> FilterNode<N> for &HashSet<N, S>
64where
65    HashSet<N, S>: VisitMap<N>,
66{
67    fn include_node(&self, n: N) -> bool {
68        self.is_visited(&n)
69    }
70}
71
72/// A node-filtering graph adaptor.
73#[derive(Copy, Clone, Debug)]
74pub struct NodeFiltered<G, F>(pub G, pub F);
75
76impl<F, G> NodeFiltered<G, F>
77where
78    G: GraphBase,
79    F: Fn(G::NodeId) -> bool,
80{
81    /// Create an `NodeFiltered` adaptor from the closure `filter`.
82    pub fn from_fn(graph: G, filter: F) -> Self {
83        NodeFiltered(graph, filter)
84    }
85}
86
87impl<G, F> GraphBase for NodeFiltered<G, F>
88where
89    G: GraphBase,
90{
91    type NodeId = G::NodeId;
92    type EdgeId = G::EdgeId;
93}
94
95impl<'a, G, F> IntoNeighbors for &'a NodeFiltered<G, F>
96where
97    G: IntoNeighbors,
98    F: FilterNode<G::NodeId>,
99{
100    type Neighbors = NodeFilteredNeighbors<'a, G::Neighbors, F>;
101    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
102        NodeFilteredNeighbors {
103            include_source: self.1.include_node(n),
104            iter: self.0.neighbors(n),
105            f: &self.1,
106        }
107    }
108}
109
110/// A filtered neighbors iterator.
111#[derive(Debug, Clone)]
112pub struct NodeFilteredNeighbors<'a, I, F: 'a> {
113    include_source: bool,
114    iter: I,
115    f: &'a F,
116}
117
118impl<I, F> Iterator for NodeFilteredNeighbors<'_, I, F>
119where
120    I: Iterator,
121    I::Item: Copy,
122    F: FilterNode<I::Item>,
123{
124    type Item = I::Item;
125    fn next(&mut self) -> Option<Self::Item> {
126        let f = self.f;
127        if !self.include_source {
128            None
129        } else {
130            self.iter.find(move |&target| f.include_node(target))
131        }
132    }
133    fn size_hint(&self) -> (usize, Option<usize>) {
134        let (_, upper) = self.iter.size_hint();
135        (0, upper)
136    }
137}
138
139impl<'a, G, F> IntoNeighborsDirected for &'a NodeFiltered<G, F>
140where
141    G: IntoNeighborsDirected,
142    F: FilterNode<G::NodeId>,
143{
144    type NeighborsDirected = NodeFilteredNeighbors<'a, G::NeighborsDirected, F>;
145    fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
146        NodeFilteredNeighbors {
147            include_source: self.1.include_node(n),
148            iter: self.0.neighbors_directed(n, dir),
149            f: &self.1,
150        }
151    }
152}
153
154impl<'a, G, F> IntoNodeIdentifiers for &'a NodeFiltered<G, F>
155where
156    G: IntoNodeIdentifiers,
157    F: FilterNode<G::NodeId>,
158{
159    type NodeIdentifiers = NodeFilteredNeighbors<'a, G::NodeIdentifiers, F>;
160    fn node_identifiers(self) -> Self::NodeIdentifiers {
161        NodeFilteredNeighbors {
162            include_source: true,
163            iter: self.0.node_identifiers(),
164            f: &self.1,
165        }
166    }
167}
168
169impl<'a, G, F> IntoNodeReferences for &'a NodeFiltered<G, F>
170where
171    G: IntoNodeReferences,
172    F: FilterNode<G::NodeId>,
173{
174    type NodeRef = G::NodeRef;
175    type NodeReferences = NodeFilteredNodes<'a, G::NodeReferences, F>;
176    fn node_references(self) -> Self::NodeReferences {
177        NodeFilteredNodes {
178            include_source: true,
179            iter: self.0.node_references(),
180            f: &self.1,
181        }
182    }
183}
184
185/// A filtered node references iterator.
186#[derive(Debug, Clone)]
187pub struct NodeFilteredNodes<'a, I, F: 'a> {
188    include_source: bool,
189    iter: I,
190    f: &'a F,
191}
192
193impl<I, F> Iterator for NodeFilteredNodes<'_, I, F>
194where
195    I: Iterator,
196    I::Item: Copy + NodeRef,
197    F: FilterNode<<I::Item as NodeRef>::NodeId>,
198{
199    type Item = I::Item;
200    fn next(&mut self) -> Option<Self::Item> {
201        let f = self.f;
202        if !self.include_source {
203            None
204        } else {
205            self.iter.find(move |&target| f.include_node(target.id()))
206        }
207    }
208    fn size_hint(&self) -> (usize, Option<usize>) {
209        let (_, upper) = self.iter.size_hint();
210        (0, upper)
211    }
212}
213
214impl<'a, G, F> IntoEdgeReferences for &'a NodeFiltered<G, F>
215where
216    G: IntoEdgeReferences,
217    F: FilterNode<G::NodeId>,
218{
219    type EdgeRef = G::EdgeRef;
220    type EdgeReferences = NodeFilteredEdgeReferences<'a, G, G::EdgeReferences, F>;
221    fn edge_references(self) -> Self::EdgeReferences {
222        NodeFilteredEdgeReferences {
223            graph: PhantomData,
224            iter: self.0.edge_references(),
225            f: &self.1,
226        }
227    }
228}
229
230/// A filtered edges iterator.
231#[derive(Debug, Clone)]
232pub struct NodeFilteredEdgeReferences<'a, G, I, F: 'a> {
233    graph: PhantomData<G>,
234    iter: I,
235    f: &'a F,
236}
237
238impl<G, I, F> Iterator for NodeFilteredEdgeReferences<'_, G, I, F>
239where
240    F: FilterNode<G::NodeId>,
241    G: IntoEdgeReferences,
242    I: Iterator<Item = G::EdgeRef>,
243{
244    type Item = I::Item;
245    fn next(&mut self) -> Option<Self::Item> {
246        let f = self.f;
247        self.iter
248            .find(move |&edge| f.include_node(edge.source()) && f.include_node(edge.target()))
249    }
250    fn size_hint(&self) -> (usize, Option<usize>) {
251        let (_, upper) = self.iter.size_hint();
252        (0, upper)
253    }
254}
255
256impl<'a, G, F> IntoEdges for &'a NodeFiltered<G, F>
257where
258    G: IntoEdges,
259    F: FilterNode<G::NodeId>,
260{
261    type Edges = NodeFilteredEdges<'a, G, G::Edges, F>;
262    fn edges(self, a: G::NodeId) -> Self::Edges {
263        NodeFilteredEdges {
264            graph: PhantomData,
265            include_source: self.1.include_node(a),
266            iter: self.0.edges(a),
267            f: &self.1,
268            dir: Direction::Outgoing,
269        }
270    }
271}
272
273impl<'a, G, F> IntoEdgesDirected for &'a NodeFiltered<G, F>
274where
275    G: IntoEdgesDirected,
276    F: FilterNode<G::NodeId>,
277{
278    type EdgesDirected = NodeFilteredEdges<'a, G, G::EdgesDirected, F>;
279    fn edges_directed(self, a: G::NodeId, dir: Direction) -> Self::EdgesDirected {
280        NodeFilteredEdges {
281            graph: PhantomData,
282            include_source: self.1.include_node(a),
283            iter: self.0.edges_directed(a, dir),
284            f: &self.1,
285            dir,
286        }
287    }
288}
289
290/// A filtered edges iterator.
291#[derive(Debug, Clone)]
292pub struct NodeFilteredEdges<'a, G, I, F: 'a> {
293    graph: PhantomData<G>,
294    include_source: bool,
295    iter: I,
296    f: &'a F,
297    dir: Direction,
298}
299
300impl<G, I, F> Iterator for NodeFilteredEdges<'_, G, I, F>
301where
302    F: FilterNode<G::NodeId>,
303    G: IntoEdges,
304    I: Iterator<Item = G::EdgeRef>,
305{
306    type Item = I::Item;
307    fn next(&mut self) -> Option<Self::Item> {
308        if !self.include_source {
309            None
310        } else {
311            let dir = self.dir;
312            let f = self.f;
313            self.iter.find(move |&edge| {
314                f.include_node(match dir {
315                    Direction::Outgoing => edge.target(),
316                    Direction::Incoming => edge.source(),
317                })
318            })
319        }
320    }
321    fn size_hint(&self) -> (usize, Option<usize>) {
322        let (_, upper) = self.iter.size_hint();
323        (0, upper)
324    }
325}
326
327impl<G, F> DataMap for NodeFiltered<G, F>
328where
329    G: DataMap,
330    F: FilterNode<G::NodeId>,
331{
332    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
333        if self.1.include_node(id) {
334            self.0.node_weight(id)
335        } else {
336            None
337        }
338    }
339
340    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
341        self.0.edge_weight(id)
342    }
343}
344
345macro_rules! access0 {
346    ($e:expr) => {
347        $e.0
348    };
349}
350
351Data! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
352NodeIndexable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
353EdgeIndexable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
354GraphProp! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
355Visitable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
356
357/// A graph filter for edges
358pub trait FilterEdge<Edge> {
359    /// Return true to have the edge be part of the graph
360    fn include_edge(&self, edge: Edge) -> bool;
361}
362
363impl<F, N> FilterEdge<N> for F
364where
365    F: Fn(N) -> bool,
366{
367    fn include_edge(&self, n: N) -> bool {
368        (*self)(n)
369    }
370}
371
372/// An edge-filtering graph adaptor.
373///
374/// The adaptor may filter out edges. The filter implements the trait
375/// `FilterEdge`. Closures of type `Fn(G::EdgeRef) -> bool` already
376/// implement this trait.
377///
378/// The filter may use edge source, target, id, and weight to select whether to
379/// include the edge or not.
380#[derive(Copy, Clone, Debug)]
381pub struct EdgeFiltered<G, F>(pub G, pub F);
382
383impl<F, G> EdgeFiltered<G, F>
384where
385    G: IntoEdgeReferences,
386    F: Fn(G::EdgeRef) -> bool,
387{
388    /// Create an `EdgeFiltered` adaptor from the closure `filter`.
389    pub fn from_fn(graph: G, filter: F) -> Self {
390        EdgeFiltered(graph, filter)
391    }
392}
393
394impl<G, F> GraphBase for EdgeFiltered<G, F>
395where
396    G: GraphBase,
397{
398    type NodeId = G::NodeId;
399    type EdgeId = G::EdgeId;
400}
401
402impl<'a, G, F> IntoNeighbors for &'a EdgeFiltered<G, F>
403where
404    G: IntoEdges,
405    F: FilterEdge<G::EdgeRef>,
406{
407    type Neighbors = EdgeFilteredNeighbors<'a, G, F>;
408    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
409        EdgeFilteredNeighbors {
410            iter: self.0.edges(n),
411            f: &self.1,
412        }
413    }
414}
415
416impl<'a, G, F> IntoNeighborsDirected for &'a EdgeFiltered<G, F>
417where
418    G: IntoEdgesDirected,
419    F: FilterEdge<G::EdgeRef>,
420{
421    type NeighborsDirected = EdgeFilteredNeighborsDirected<'a, G, F>;
422    fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
423        EdgeFilteredNeighborsDirected {
424            iter: self.0.edges_directed(n, dir),
425            f: &self.1,
426            from: n,
427        }
428    }
429}
430
431/// A filtered neighbors iterator.
432#[derive(Debug, Clone)]
433pub struct EdgeFilteredNeighbors<'a, G, F: 'a>
434where
435    G: IntoEdges,
436{
437    iter: G::Edges,
438    f: &'a F,
439}
440
441impl<G, F> Iterator for EdgeFilteredNeighbors<'_, G, F>
442where
443    F: FilterEdge<G::EdgeRef>,
444    G: IntoEdges,
445{
446    type Item = G::NodeId;
447    fn next(&mut self) -> Option<Self::Item> {
448        let f = self.f;
449        (&mut self.iter)
450            .filter_map(move |edge| {
451                if f.include_edge(edge) {
452                    Some(edge.target())
453                } else {
454                    None
455                }
456            })
457            .next()
458    }
459    fn size_hint(&self) -> (usize, Option<usize>) {
460        let (_, upper) = self.iter.size_hint();
461        (0, upper)
462    }
463}
464
465impl<'a, G, F> IntoEdgeReferences for &'a EdgeFiltered<G, F>
466where
467    G: IntoEdgeReferences,
468    F: FilterEdge<G::EdgeRef>,
469{
470    type EdgeRef = G::EdgeRef;
471    type EdgeReferences = EdgeFilteredEdges<'a, G, G::EdgeReferences, F>;
472    fn edge_references(self) -> Self::EdgeReferences {
473        EdgeFilteredEdges {
474            graph: PhantomData,
475            iter: self.0.edge_references(),
476            f: &self.1,
477        }
478    }
479}
480
481impl<'a, G, F> IntoEdges for &'a EdgeFiltered<G, F>
482where
483    G: IntoEdges,
484    F: FilterEdge<G::EdgeRef>,
485{
486    type Edges = EdgeFilteredEdges<'a, G, G::Edges, F>;
487    fn edges(self, n: G::NodeId) -> Self::Edges {
488        EdgeFilteredEdges {
489            graph: PhantomData,
490            iter: self.0.edges(n),
491            f: &self.1,
492        }
493    }
494}
495
496impl<'a, G, F> IntoEdgesDirected for &'a EdgeFiltered<G, F>
497where
498    G: IntoEdgesDirected,
499    F: FilterEdge<G::EdgeRef>,
500{
501    type EdgesDirected = EdgeFilteredEdges<'a, G, G::EdgesDirected, F>;
502
503    fn edges_directed(self, n: G::NodeId, dir: Direction) -> Self::EdgesDirected {
504        EdgeFilteredEdges {
505            graph: PhantomData,
506            iter: self.0.edges_directed(n, dir),
507            f: &self.1,
508        }
509    }
510}
511
512/// A filtered edges iterator.
513#[derive(Debug, Clone)]
514pub struct EdgeFilteredEdges<'a, G, I, F: 'a> {
515    graph: PhantomData<G>,
516    iter: I,
517    f: &'a F,
518}
519
520impl<G, I, F> Iterator for EdgeFilteredEdges<'_, G, I, F>
521where
522    F: FilterEdge<G::EdgeRef>,
523    G: IntoEdgeReferences,
524    I: Iterator<Item = G::EdgeRef>,
525{
526    type Item = I::Item;
527    fn next(&mut self) -> Option<Self::Item> {
528        let f = self.f;
529        self.iter.find(move |&edge| f.include_edge(edge))
530    }
531    fn size_hint(&self) -> (usize, Option<usize>) {
532        let (_, upper) = self.iter.size_hint();
533        (0, upper)
534    }
535}
536
537/// A filtered neighbors-directed iterator.
538#[derive(Debug, Clone)]
539pub struct EdgeFilteredNeighborsDirected<'a, G, F: 'a>
540where
541    G: IntoEdgesDirected,
542{
543    iter: G::EdgesDirected,
544    f: &'a F,
545    from: G::NodeId,
546}
547
548impl<G, F> Iterator for EdgeFilteredNeighborsDirected<'_, G, F>
549where
550    F: FilterEdge<G::EdgeRef>,
551    G: IntoEdgesDirected,
552{
553    type Item = G::NodeId;
554    fn next(&mut self) -> Option<Self::Item> {
555        let f = self.f;
556        let from = self.from;
557        (&mut self.iter)
558            .filter_map(move |edge| {
559                if f.include_edge(edge) {
560                    if edge.source() != from {
561                        Some(edge.source())
562                    } else {
563                        Some(edge.target()) // includes case where from == source == target
564                    }
565                } else {
566                    None
567                }
568            })
569            .next()
570    }
571    fn size_hint(&self) -> (usize, Option<usize>) {
572        let (_, upper) = self.iter.size_hint();
573        (0, upper)
574    }
575}
576
577Data! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
578GraphProp! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
579IntoNodeIdentifiers! {delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
580IntoNodeReferences! {delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
581NodeCompactIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
582NodeCount! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
583NodeIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
584EdgeIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
585Visitable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}