petgraph/visit/
filter.rs

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