@@ -83,10 +83,10 @@ const CLUSTERED_SIGNAL_FRAC: f64 = 0.3;
8383enum TermLayout {
8484 /// Each doc is independently "a" with probability `p_a`: the "a" docs are scattered uniformly.
8585 Uniform ,
86- /// The "a" docs arrive in bursts (see [`TitleField::next_token`]). Real attributes rarely sprinkle
87- /// evenly — a log level spikes, a topic is ingested together — so their matching docs cluster.
88- /// Bursts are statistically denser regions, not solid runs, and a background floor keeps some
89- /// "a" docs scattered in between.
86+ /// The "a" docs arrive in bursts (see [`TitleField::next_token`]). Real attributes rarely
87+ /// sprinkle evenly — a log level spikes, a topic is ingested together — so their matching
88+ /// docs cluster. Bursts are statistically denser regions, not solid runs, and a background
89+ /// floor keeps some "a" docs scattered in between.
9090 Clustered ,
9191}
9292
@@ -100,9 +100,10 @@ impl TermLayout {
100100 }
101101}
102102
103- /// Derives a schema-safe title field name from a term probability and layout, e.g. `(0.001, Uniform)`
104- /// -> `title_0_1pct` and `(0.001, Clustered)` -> `title_clustered_0_1pct`. A title field is populated
105- /// with token "a" for a `p_a` fraction of documents, so `<name>:a` matches ~`p_a` of them.
103+ /// Derives a schema-safe title field name from a term probability and layout, e.g. `(0.001,
104+ /// Uniform)` -> `title_0_1pct` and `(0.001, Clustered)` -> `title_clustered_0_1pct`. A title field
105+ /// is populated with token "a" for a `p_a` fraction of documents, so `<name>:a` matches ~`p_a` of
106+ /// them.
106107fn title_field_name ( p_a : f64 , layout : TermLayout ) -> String {
107108 let pct = format_pct ( p_a) . replace ( '.' , "_" ) . replace ( '%' , "pct" ) ;
108109 match layout {
@@ -131,19 +132,22 @@ struct TitleField {
131132 /// Latent-field value a doc must exceed to be "a". Set to `Φ⁻¹(1 - p_a)` for the unit-variance
132133 /// field below, so `P(exceed) = p_a` and the marginal is `p_a` however bursty the drift is.
133134 threshold : f64 ,
134- /// Amplitude per octave, so the summed drift carries `CLUSTERED_SIGNAL_FRAC` of the unit variance.
135+ /// Amplitude per octave, so the summed drift carries `CLUSTERED_SIGNAL_FRAC` of the unit
136+ /// variance.
135137 octave_weight : f64 ,
136- /// s.d. of the per-doc noise carrying the remaining `1 - CLUSTERED_SIGNAL_FRAC` of the variance.
138+ /// s.d. of the per-doc noise carrying the remaining `1 - CLUSTERED_SIGNAL_FRAC` of the
139+ /// variance.
137140 noise_sd : f64 ,
138141 octaves : Vec < Ar1Octave > ,
139142}
140143
141144impl TitleField {
142145 fn new ( p_a : f64 , layout : TermLayout , field : Field , num_docs : usize ) -> Self {
143- // Octave j has correlation length CLUSTERED_DRIFT_SCALE * num_docs / 4^j; rho = e^(-1/len) is
144- // the per-doc retention producing that length. Splitting the signal variance equally across
145- // octaves (weight = sqrt(signal/octaves)) plus noise variance (1 - signal) makes the latent
146- // field unit-variance, so the threshold is a plain standard-normal quantile.
146+ // Octave j has correlation length CLUSTERED_DRIFT_SCALE * num_docs / 4^j; rho = e^(-1/len)
147+ // is the per-doc retention producing that length. Splitting the signal variance
148+ // equally across octaves (weight = sqrt(signal/octaves)) plus noise variance (1 -
149+ // signal) makes the latent field unit-variance, so the threshold is a plain
150+ // standard-normal quantile.
147151 let octaves = ( 0 ..CLUSTERED_OCTAVES )
148152 . map ( |j| {
149153 let len = ( CLUSTERED_DRIFT_SCALE * num_docs as f64 / 4f64 . powi ( j as i32 ) ) . max ( 1.0 ) ;
@@ -165,10 +169,11 @@ impl TitleField {
165169 }
166170
167171 /// Draws this document's token. Uniform: independently "a" with probability `p_a`. Clustered:
168- /// advance the drift, add per-doc noise to get a unit-variance latent value, and emit "a" when it
169- /// clears `threshold`. Because the drift moves slowly, neighbouring docs land on the same side of
170- /// the threshold together — that is the clustering; the noise softens the boundary and scatters a
171- /// background of "a" docs through the cold stretches (and "b" docs through the hot ones).
172+ /// advance the drift, add per-doc noise to get a unit-variance latent value, and emit "a" when
173+ /// it clears `threshold`. Because the drift moves slowly, neighbouring docs land on the
174+ /// same side of the threshold together — that is the clustering; the noise softens the
175+ /// boundary and scatters a background of "a" docs through the cold stretches (and "b" docs
176+ /// through the hot ones).
172177 fn next_token ( & mut self , rng : & mut StdRng ) -> & ' static str {
173178 match self . layout {
174179 TermLayout :: Uniform => {
@@ -202,25 +207,38 @@ fn standard_normal(rng: &mut StdRng) -> f64 {
202207 ( -2.0 * u1. ln ( ) ) . sqrt ( ) * ( 2.0 * std:: f64:: consts:: PI * u2) . cos ( )
203208}
204209
205- /// Inverse standard-normal CDF (the probit / quantile function) via Acklam's rational approximation,
206- /// accurate to ~1e-9 over `p ∈ (0, 1)` — enough to place the clustered-layout threshold. Only called
207- /// once per field, so speed is irrelevant.
210+ /// Inverse standard-normal CDF (the probit / quantile function) via Acklam's rational
211+ /// approximation, accurate to ~1e-9 over `p ∈ (0, 1)` — enough to place the clustered-layout
212+ /// threshold. Only called once per field, so speed is irrelevant.
208213fn inverse_normal_cdf ( p : f64 ) -> f64 {
209214 // Coefficients for the central and tail regions of the approximation.
210215 const A : [ f64 ; 6 ] = [
211- -3.969683028665376e+01 , 2.209460984245205e+02 , -2.759285104469687e+02 ,
212- 1.383577518672690e+02 , -3.066479806614716e+01 , 2.506628277459239e+00 ,
216+ -3.969683028665376e+01 ,
217+ 2.209460984245205e+02 ,
218+ -2.759285104469687e+02 ,
219+ 1.383577518672690e+02 ,
220+ -3.066479806614716e+01 ,
221+ 2.506628277459239e+00 ,
213222 ] ;
214223 const B : [ f64 ; 5 ] = [
215- -5.447609879822406e+01 , 1.615858368580409e+02 , -1.556989798598866e+02 ,
216- 6.680131188771972e+01 , -1.328068155288572e+01 ,
224+ -5.447609879822406e+01 ,
225+ 1.615858368580409e+02 ,
226+ -1.556989798598866e+02 ,
227+ 6.680131188771972e+01 ,
228+ -1.328068155288572e+01 ,
217229 ] ;
218230 const C : [ f64 ; 6 ] = [
219- -7.784894002430293e-03 , -3.223964580411365e-01 , -2.400758277161838e+00 ,
220- -2.549732539343734e+00 , 4.374664141464968e+00 , 2.938163982698783e+00 ,
231+ -7.784894002430293e-03 ,
232+ -3.223964580411365e-01 ,
233+ -2.400758277161838e+00 ,
234+ -2.549732539343734e+00 ,
235+ 4.374664141464968e+00 ,
236+ 2.938163982698783e+00 ,
221237 ] ;
222238 const D : [ f64 ; 4 ] = [
223- 7.784695709041462e-03 , 3.224671290700398e-01 , 2.445134137142996e+00 ,
239+ 7.784695709041462e-03 ,
240+ 3.224671290700398e-01 ,
241+ 2.445134137142996e+00 ,
224242 3.754408661907416e+00 ,
225243 ] ;
226244 const P_LOW : f64 = 0.02425 ;
@@ -283,7 +301,8 @@ impl NumericFields {
283301/// rebuilding a near-identical index.
284302fn build_shared_index ( num_docs : usize , term_specs : & [ ( f64 , TermLayout ) ] ) -> BenchIndex {
285303 let mut schema_builder = Schema :: builder ( ) ;
286- // One title field per distinct (probability, layout); querying `<name>:a` matches ~p of documents.
304+ // One title field per distinct (probability, layout); querying `<name>:a` matches ~p of
305+ // documents.
287306 let mut title_fields: Vec < TitleField > = Vec :: new ( ) ;
288307 for & ( p_a, layout) in term_specs {
289308 if title_fields
@@ -362,9 +381,10 @@ fn main() {
362381 ( 0.7 , 0.1 ) ,
363382 ] ;
364383
365- // Each scenario is run under both term layouts: `uniform` ("a" scattered evenly) and `clustered`
366- // ("a" arriving in organic bursts, same marginal `p(a)`). Real corpora look like the latter, and
367- // where the matching docs land is exactly what an intersection's block-skipping sees.
384+ // Each scenario is run under both term layouts: `uniform` ("a" scattered evenly) and
385+ // `clustered` ("a" arriving in organic bursts, same marginal `p(a)`). Real corpora look
386+ // like the latter, and where the matching docs land is exactly what an intersection's
387+ // block-skipping sees.
368388 let layouts = [ TermLayout :: Uniform , TermLayout :: Clustered ] ;
369389
370390 // Build a single shared corpus with a title field for each (probability, layout).
@@ -382,9 +402,9 @@ fn main() {
382402 term_specs. push ( ( regression_term_p, TermLayout :: Uniform ) ) ;
383403 let bench_index = build_shared_index ( 5_000_000 , & term_specs) ;
384404
385- // Precompute each group's name and queries once; every collector runner reuses them. Layouts are
386- // interleaved per scenario so a scenario's `uniform` and `clustered` groups sit next to each
387- // other in the output for easy comparison.
405+ // Precompute each group's name and queries once; every collector runner reuses them. Layouts
406+ // are interleaved per scenario so a scenario's `uniform` and `clustered` groups sit next to
407+ // each other in the output for easy comparison.
388408 let mut prepared: Vec < ( String , Vec < Query3 > ) > = Vec :: new ( ) ;
389409 for & ( p_a, range_sel) in & scenarios {
390410 for & layout in & layouts {
@@ -394,7 +414,10 @@ fn main() {
394414 layout. tag( ) ,
395415 format_pct( range_sel)
396416 ) ;
397- prepared. push ( ( group_name, build_term_and_range_queries ( p_a, range_sel, layout) ) ) ;
417+ prepared. push ( (
418+ group_name,
419+ build_term_and_range_queries ( p_a, range_sel, layout) ,
420+ ) ) ;
398421 }
399422 }
400423
@@ -434,9 +457,13 @@ fn main() {
434457
435458 // A separate runner per collector type: the collector heads the output section (via the runner
436459 // name) instead of being repeated in every task name.
437- run_collector ( BenchRunner :: with_name ( "count" ) , & bench_index, & prepared, false , |_| {
438- Count
439- } ) ;
460+ run_collector (
461+ BenchRunner :: with_name ( "count" ) ,
462+ & bench_index,
463+ & prepared,
464+ false ,
465+ |_| Count ,
466+ ) ;
440467 run_collector (
441468 BenchRunner :: with_name ( "cnt+top_score" ) ,
442469 & bench_index,
@@ -473,8 +500,7 @@ fn build_term_and_range_queries(p_a: f64, range_sel: f64, layout: TermLayout) ->
473500 . iter ( )
474501 . map ( |& ( field_name, dist) | {
475502 let ( low, high) = dist. bounds_for ( range_sel) ;
476- let query_str =
477- format ! ( "{}:a AND {}:[{} TO {}]" , title_field, field_name, low, high) ;
503+ let query_str = format ! ( "{}:a AND {}:[{} TO {}]" , title_field, field_name, low, high) ;
478504 let label = format ! ( "a_AND_{}" , field_name) ;
479505 ( query_str, label, field_name. to_string ( ) )
480506 } )
0 commit comments