Skip to main content

webgraph/visits/
mod.rs

1/*
2 * SPDX-FileCopyrightText: 2024 Matteo Dell'Acqua
3 * SPDX-FileCopyrightText: 2025 Sebastiano Vigna
4 *
5 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6 */
7
8//! Visits on graphs.
9//!
10//! Implementation of [sequential](Sequential) and [parallel][Parallel] visits
11//! depend on a type parameter `A` implementing the trait [`Event`]; they
12//! provide visit methods accepting a callback function with argument `A` and
13//! returning a `ControlFlow<E, ()>`, where `E` is a type parameter of the visit
14//! method: for example, `E` might be [`StoppedWhenDone`] when completing early,
15//! [`Interrupted`] when interrupted or [`Infallible`](std::convert::Infallible)
16//! if the visit cannot be interrupted.
17//!
18//! If a callback returns a [`Break`](ControlFlow::Break), the visit will be
19//! interrupted, and the [`Break`](ControlFlow::Break) value will be the return
20//! value of the visit method; for uninterruptible visits we suggest to use the
21//! [`no-break`](https://crates.io/crates/no-break) crate and its
22//! [`continue_value_no_break`](no_break::NoBreak::continue_value_no_break)
23//! method on the result to let type inference run smoothly.
24//!
25//! Note that an interruption does not necessarily denote an error condition
26//! (see, e.g., [`StoppedWhenDone`]).
27//!
28//! [Sequential visits](Sequential) are visits that are executed in a single
29//! thread, whereas [parallel visits](Parallel) use multiple threads. The
30//! signature of callbacks reflects this difference ([`FnMut`] for the
31//! sequential case vs. [`Fn`] + [`Sync`] for the parallel case).
32//!
33//! In case of interruption sequential visits usually return immediately to the
34//! caller, whereas in general parallel visits might need to complete part of
35//! their subtasks before returning to the caller.
36//!
37//! Additionally, implementations might accept a filter function accepting a
38//! [`Event::FilterArgs`] that will be called when a new node is discovered. If
39//! the filter returns false, the node will be ignored, that is, not even marked
40//! as known. Note that in case of parallel visits the filter might be called
41//! multiple times on the same node (and with a different predecessor, if
42//! available) due to race conditions.
43//!
44//! All visits have also methods accepting an `init` item similarly to the
45//! [Rayon](rayon) [`map_with`](rayon::iter::ParallelIterator::map_with) method.
46//! For parallel visits, the item will be cloned.
47//!
48//! There is a blanket implementation of the [`Parallel`] trait for all types
49//! implementing the [`Sequential`] trait. This approach makes it possible to
50//! have structures that can use both sequential and parallel visits.
51//!
52//! Visit must provide a `reset` method that makes it possible to reuse the
53//! visit.
54//!
55//! # Examples
56//!
57//! There are examples of visits in
58//! [`SeqIter`](crate::visits::depth_first::SeqIter),
59//! [`ParFair`](crate::visits::breadth_first::ParFair) and
60//! [`ParLowMem`](crate::visits::breadth_first::ParLowMem).
61
62pub mod breadth_first;
63pub mod depth_first;
64
65use std::ops::ControlFlow;
66use thiserror::Error;
67
68#[derive(Error, Debug)]
69/// The visit was interrupted.
70#[error("The visit was interrupted")]
71pub struct Interrupted;
72
73#[derive(Error, Debug)]
74/// The result of the visit was computed without completing the visit; for
75/// example, during an acyclicity test a single arc pointing at the visit path
76/// is sufficient to compute the result.
77#[error("Stopped when done")]
78pub struct StoppedWhenDone;
79
80/// Types usable as arguments for the callbacks in visits.
81///
82/// Arguments are usually enums in which variants represent visit events
83/// (previsits, postvisits, etc.). Each variant then contains additional data
84/// related to the specific event.
85///
86/// The associated type [`Event::FilterArgs`] is the type of the arguments
87/// passed to the filter associated with the visit. It can be set to `()` if
88/// filtering is not supported
89pub trait Event {
90    /// The type passed as input to the filter.
91    type FilterArgs;
92}
93
94/// A convenience type alias for the filter arguments of an event.
95///
96/// It is useful to write match patterns using destructuring syntax.
97pub type FilterArgs<A> = <A as Event>::FilterArgs;
98
99/// A sequential visit.
100///
101/// Implementation of this trait must provide the
102/// [`visit_filtered_with`](Sequential::visit_filtered_with) method, which
103/// should perform a visit of a graph starting from a given set of nodes. Note
104/// that different visits types might interpret the set of nodes differently:
105/// for example, a [breadth-first visit](breadth_first) will interpret the set
106/// of nodes as the initial queue, whereas a [depth-first visit](depth_first)
107/// will interpret the set of nodes as a list of nodes from which to start
108/// visits.
109pub trait Sequential<A: Event> {
110    /// Visits the graph from the specified nodes with an initialization value
111    /// and a filter function.
112    ///
113    /// See the [module documentation](crate::visits) for more information on
114    /// the return value.
115    ///
116    /// # Arguments
117    ///
118    /// * `roots`: The nodes to start the visit from.
119    ///
120    /// * `init`: a value the will be passed to the callback function.
121    ///
122    /// * `callback`: The callback function.
123    ///
124    /// * `filter`: The filter function.
125    fn visit_filtered_with<
126        R: IntoIterator<Item = usize>,
127        T,
128        E,
129        C: FnMut(&mut T, A) -> ControlFlow<E, ()>,
130        F: FnMut(&mut T, A::FilterArgs) -> bool,
131    >(
132        &mut self,
133        roots: R,
134        init: T,
135        callback: C,
136        filter: F,
137    ) -> ControlFlow<E, ()>;
138
139    /// Visits the graph from the specified nodes with a filter function.
140    ///
141    /// See the [module documentation](crate::visits) for more information on
142    /// the return value.
143    ///
144    /// # Arguments
145    ///
146    /// * `roots`: The nodes to start the visit from.
147    ///
148    /// * `callback`: The callback function.
149    ///
150    /// * `filter`: The filter function.
151    fn visit_filtered<
152        R: IntoIterator<Item = usize>,
153        E,
154        C: FnMut(A) -> ControlFlow<E, ()>,
155        F: FnMut(A::FilterArgs) -> bool,
156    >(
157        &mut self,
158        roots: R,
159        mut callback: C,
160        mut filter: F,
161    ) -> ControlFlow<E, ()> {
162        self.visit_filtered_with(roots, (), |(), a| callback(a), |(), a| filter(a))
163    }
164
165    /// Visits the graph from the specified nodes with an initialization value.
166    ///
167    /// See the [module documentation](crate::visits) for more information on
168    /// the return value.
169    ///
170    /// # Arguments
171    ///
172    /// * `roots`: The nodes to start the visit from.
173    ///
174    /// * `init`: a value the will be passed to the callback function.
175    ///
176    /// * `callback`: The callback function.
177    fn visit_with<
178        R: IntoIterator<Item = usize>,
179        T,
180        E,
181        C: FnMut(&mut T, A) -> ControlFlow<E, ()>,
182    >(
183        &mut self,
184        roots: R,
185        init: T,
186        callback: C,
187    ) -> ControlFlow<E, ()> {
188        self.visit_filtered_with(roots, init, callback, |_, _| true)
189    }
190
191    /// Visits the graph from the specified nodes.
192    ///
193    /// See the [module documentation](crate::visits) for more information on
194    /// the return value.
195    ///
196    /// # Arguments
197    ///
198    /// * `roots`: The nodes to start the visit from.
199    ///
200    /// * `callback`: The callback function.
201    fn visit<R: IntoIterator<Item = usize>, E, C: FnMut(A) -> ControlFlow<E, ()>>(
202        &mut self,
203        roots: R,
204        callback: C,
205    ) -> ControlFlow<E, ()> {
206        self.visit_filtered(roots, callback, |_| true)
207    }
208
209    /// Resets the visit status, making it possible to reuse it.
210    fn reset(&mut self);
211}
212
213/// A parallel visit.
214///
215/// Implementation of this trait must provide the
216/// [`par_visit_filtered_with`](Parallel::par_visit_filtered_with) method, which
217/// should perform a parallel visit of a graph starting from a given set of
218/// nodes. Note that different visits types might interpret the set of nodes
219/// differently: for example, a [breadth-first visit](breadth_first) will
220/// interpret the set of nodes as the initial queue, whereas a [depth-first
221/// visit](depth_first) will interpret the set of nodes as a list of nodes from
222/// which to start visits.
223pub trait Parallel<A: Event> {
224    /// Visits the graph from the specified nodes with an initialization value
225    /// and a filter function.
226    ///
227    /// See the [module documentation](crate::visits) for more information on
228    /// the return value.
229    ///
230    /// # Arguments
231    ///
232    /// * `roots`: The nodes to start the visit from.
233    ///
234    /// * `init`: a value the will be cloned and passed to the callback
235    ///   function.
236    ///
237    /// * `callback`: The callback function.
238    ///
239    /// * `filter`: The filter function.
240    fn par_visit_filtered_with<
241        R: IntoIterator<Item = usize>,
242        T: Clone + Send + Sync,
243        E: Send,
244        C: Fn(&mut T, A) -> ControlFlow<E, ()> + Sync,
245        F: Fn(&mut T, A::FilterArgs) -> bool + Sync,
246    >(
247        &mut self,
248        roots: R,
249        init: T,
250        callback: C,
251        filter: F,
252    ) -> ControlFlow<E, ()>;
253
254    /// Visits the graph from the specified nodes with a filter function.
255    ///
256    /// See the [module documentation](crate::visits) for more information on
257    /// the return value.
258    ///
259    /// # Arguments
260    ///
261    /// * `roots`: The nodes to start the visit from.
262    ///
263    /// * `callback`: The callback function.
264    ///
265    /// * `filter`: The filter function.
266    fn par_visit_filtered<
267        R: IntoIterator<Item = usize>,
268        E: Send,
269        C: Fn(A) -> ControlFlow<E, ()> + Sync,
270        F: Fn(A::FilterArgs) -> bool + Sync,
271    >(
272        &mut self,
273        roots: R,
274        callback: C,
275        filter: F,
276    ) -> ControlFlow<E, ()> {
277        self.par_visit_filtered_with(roots, (), |(), a| callback(a), |(), a| filter(a))
278    }
279
280    /// Visits the graph from the specified nodes with an initialization value.
281    ///
282    /// See the [module documentation](crate::visits) for more information on
283    /// the return value.
284    ///
285    /// # Arguments
286    ///
287    /// * `roots`: The nodes to start the visit from.
288    ///
289    /// * `init`: a value the will be cloned and passed to the callback
290    ///   function.
291    ///
292    /// * `callback`: The callback function.
293    fn par_visit_with<
294        R: IntoIterator<Item = usize>,
295        T: Clone + Send + Sync,
296        E: Send,
297        C: Fn(&mut T, A) -> ControlFlow<E, ()> + Sync,
298    >(
299        &mut self,
300        roots: R,
301        init: T,
302        callback: C,
303    ) -> ControlFlow<E, ()> {
304        self.par_visit_filtered_with(roots, init, callback, |_, _| true)
305    }
306
307    /// Visits the graph from the specified nodes.
308    ///
309    /// See the [module documentation](crate::visits) for more information on
310    /// the return value.
311    ///
312    /// # Arguments
313    ///
314    /// * `roots`: The nodes to start the visit from.
315    ///
316    /// * `callback`: The callback function.
317    fn par_visit<R: IntoIterator<Item = usize>, E: Send, C: Fn(A) -> ControlFlow<E, ()> + Sync>(
318        &mut self,
319        roots: R,
320        callback: C,
321    ) -> ControlFlow<E, ()> {
322        self.par_visit_filtered(roots, callback, |_| true)
323    }
324
325    /// Resets the visit status, making it possible to reuse it.
326    fn reset(&mut self);
327}