Skip to main content

petgraph/visit/
filter.rs

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