@@ -141,9 +141,128 @@ use webgraph::utils::Granularity;
141141
142142/// A builder for [`HyperBall`].
143143///
144- /// After creating a builder with [`HyperBallBuilder::new`] you can configure it
145- /// using setters such as [`HyperBallBuilder`] its methods, then call
146- /// [`HyperBallBuilder::build`] on it to create a [`HyperBall`] instance.
144+ /// # Creating a Builder
145+ ///
146+ /// There are three constructors, depending on the type of graph and
147+ /// cardinality estimator:
148+ ///
149+ /// - [`with_hyper_log_log`](Self::with_hyper_log_log): the most common entry
150+ /// point—it creates a builder using [`HyperLogLog`] counters, requiring
151+ /// only the base-2 logarithm of the number of registers per counter
152+ /// (`log2m`). Higher values of `log2m` give more precise estimates at the
153+ /// cost of more memory;
154+ /// - [`new`](Self::new): creates a builder from two pre-built estimator
155+ /// arrays and a graph (without its transpose);
156+ /// - [`with_transpose`](Self::with_transpose): same, but also accepts the
157+ /// transpose of the graph, enabling [systolic
158+ /// computation](super::hyperball#systolic-computation).
159+ ///
160+ /// # Configuration
161+ ///
162+ /// After creation, the builder can be configured using the following
163+ /// methods:
164+ ///
165+ /// - [`sum_of_distances`](Self::sum_of_distances): enables the computation
166+ /// of the sum of distances from each node (needed for closeness, Lin, and
167+ /// Nieminen centrality);
168+ /// - [`sum_of_inverse_distances`](Self::sum_of_inverse_distances): enables
169+ /// the computation of harmonic centrality;
170+ /// - [`discount_function`](Self::discount_function): adds a custom discount
171+ /// function;
172+ /// - [`granularity`](Self::granularity): sets the arc granularity for the
173+ /// parallel iterations;
174+ /// - [`weights`](Self::weights): sets optional nonnegative integer node
175+ /// weights.
176+ ///
177+ /// Finally, call [`build`](Self::build) to obtain a [`HyperBall`] instance,
178+ /// and then [`run`](HyperBall::run) or
179+ /// [`run_until_done`](HyperBall::run_until_done) to perform the actual
180+ /// computation.
181+ ///
182+ /// # Examples
183+ ///
184+ /// ```
185+ /// use webgraph::graphs::vec_graph::VecGraph;
186+ /// use webgraph::graphs::bvgraph::DCF;
187+ /// use webgraph::traits::{RandomAccessLabeling, SequentialLabeling};
188+ /// use webgraph_algo::distances::hyperball::*;
189+ /// use dsi_progress_logger::no_logging;
190+ /// use sux::prelude::*;
191+ /// use rand::SeedableRng;
192+ /// use lender::prelude::*;
193+ ///
194+ /// // A small graph: 0 → 1 → 2 → 0, 1 → 3
195+ /// let graph = VecGraph::from_arcs([(0, 1), (1, 2), (2, 0), (1, 3)]);
196+ ///
197+ /// // Build the degree cumulative function (DCF)
198+ /// let mut efb = EliasFanoBuilder::new(
199+ /// graph.num_nodes() + 1,
200+ /// graph.num_arcs() as usize,
201+ /// );
202+ /// efb.push(0);
203+ /// let mut cumul = 0;
204+ /// let mut lender = graph.iter();
205+ /// while let Some((_, succs)) = lender.next() {
206+ /// cumul += succs.into_iter().count();
207+ /// efb.push(cumul);
208+ /// }
209+ /// let dcf: DCF = unsafe {
210+ /// efb.build().map_high_bits(|high_bits| {
211+ /// SelectZeroAdaptConst::<_, _, 12, 4>::new(
212+ /// SelectAdaptConst::<_, _, 12, 4>::new(high_bits),
213+ /// )
214+ /// })
215+ /// };
216+ ///
217+ /// // Build and run HyperBall (neighborhood function only)
218+ /// let rng = rand::rngs::SmallRng::seed_from_u64(0);
219+ /// let mut hyperball = HyperBallBuilder::with_hyper_log_log(
220+ /// &graph, None::<&VecGraph>, &dcf, 6, None,
221+ /// )?.build(no_logging![]);
222+ /// hyperball.run_until_done(rng, no_logging![])?;
223+ ///
224+ /// let nf = hyperball.neighborhood_function()?;
225+ /// assert!(nf.len() >= 4);
226+ /// # Ok::<(), anyhow::Error>(())
227+ /// ```
228+ ///
229+ /// To compute harmonic centrality, enable it on the builder:
230+ ///
231+ /// ```
232+ /// # use webgraph::graphs::vec_graph::VecGraph;
233+ /// # use webgraph::graphs::bvgraph::DCF;
234+ /// # use webgraph::traits::{RandomAccessLabeling, SequentialLabeling};
235+ /// # use webgraph_algo::distances::hyperball::*;
236+ /// # use dsi_progress_logger::no_logging;
237+ /// # use sux::prelude::*;
238+ /// # use rand::SeedableRng;
239+ /// # use lender::prelude::*;
240+ /// # let graph = VecGraph::from_arcs([(0, 1), (1, 2), (2, 0), (1, 3)]);
241+ /// # let mut efb = EliasFanoBuilder::new(
242+ /// # graph.num_nodes() + 1, graph.num_arcs() as usize);
243+ /// # efb.push(0);
244+ /// # let mut cumul = 0;
245+ /// # let mut lender = graph.iter();
246+ /// # while let Some((_, succs)) = lender.next() {
247+ /// # cumul += succs.into_iter().count();
248+ /// # efb.push(cumul);
249+ /// # }
250+ /// # let dcf: DCF = unsafe {
251+ /// # efb.build().map_high_bits(|high_bits| {
252+ /// # SelectZeroAdaptConst::<_, _, 12, 4>::new(
253+ /// # SelectAdaptConst::<_, _, 12, 4>::new(high_bits))})};
254+ /// let rng = rand::rngs::SmallRng::seed_from_u64(0);
255+ /// let mut hyperball = HyperBallBuilder::with_hyper_log_log(
256+ /// &graph, None::<&VecGraph>, &dcf, 6, None,
257+ /// )?
258+ /// .sum_of_inverse_distances(true)
259+ /// .build(no_logging![]);
260+ /// hyperball.run_until_done(rng, no_logging![])?;
261+ ///
262+ /// let centralities = hyperball.harmonic_centralities()?;
263+ /// assert_eq!(centralities.len(), graph.num_nodes());
264+ /// # Ok::<(), anyhow::Error>(())
265+ /// ```
147266pub struct HyperBallBuilder <
148267 ' a ,
149268 G1 : RandomAccessGraph + Sync ,
@@ -261,7 +380,7 @@ impl<
261380 /// * `graph`: the graph to analyze.
262381 /// * `cumul_outdeg`: the outdegree cumulative function of the graph.
263382 /// * `array_0`: a first array of estimators.
264- /// * `array_1`: A second array of estimators of the same length and with the same logic of
383+ /// * `array_1`: a second array of estimators of the same length and with the same logic of
265384 /// `array_0`.
266385 pub fn new ( graph : & ' a G , cumul_outdeg : & ' a D , array_0 : A , array_1 : A ) -> Self {
267386 assert ! ( array_0. logic( ) == array_1. logic( ) , "Incompatible logic" ) ;
0 commit comments