Repository navigation
Add saturation study: error vs N, N_saturation and Pareto value data - #133
Merged
Merged
Conversation
…130) * Add Pareto distribution to datagen and --dataset pareto DataDistribution::Pareto(ParetoParameter { alpha, scale, seed }) samples rand_distr::Pareto. Like Normal it is unbounded, so it has no domain and refuses a cardinality or string rendering. The CLI adds --pareto-alpha and --pareto-scale (default 1.0) and requires --dtype f64. Includes an MLE test for alpha and the regenerated merged_record schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add saturation study script scripts/study_saturation.py sweeps stream length N per sketch, config and distribution point, averages the error over seeds, and reports N_sat: the smallest checkpoint from which the error stays within a relative tolerance of its tail plateau. A final-N run records insert/merge/query CPU and memory_bytes. scripts/test_study_saturation.py covers N_sat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Widen the saturation band by seed standard error A checkpoint is in band when it is within max(10% of the plateau, 2 SE) of the plateau, so seed noise alone no longer breaks a small plateau. The curve CSV gains a seed_se column, and child runs read stdin from /dev/null so a detached study is never stopped for terminal input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Document the saturation study and add its plotting scripts The doc gives the N_sat definition, the reduced-run results, a theoretical bound per sketch with how the empirical curves relate to it, and what is not covered yet (accuracy after merging, config scaling). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Allow --dataset pareto --dtype i64 (floored draws) The datagen renderer already truncates each f64 draw into an i64 column, and Pareto draws are >= scale > 0, so truncation is a floor; only the CLI refused i64. Allowing it lets the i64-only polars exact quantile baseline score a Pareto stream (e.g. --pareto-scale 1000 keeps three digits). Adds a datagen test that the i64 column is the floored f64 draws. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Saturation study: config grid, exact-baseline crossover, phase split - Configs step 4x: CMS/CountSketch/CMS-heap cols 256..16384 x rows 3,5; HLL lg_k 12,14,16 (asap HLL has no lg_k 10); KLL k 50,200,800; DDSketch alpha 0.005..0.05. - Quantile points use Pareto(alpha, scale 1000) floored to i64. - --phase accuracy|cost|all: cost reads saturation_curve.csv from --out and runs only the serial cost runs, so CPU can be timed separately. - The cost phase also runs each family's exact polars baseline at every checkpoint and writes crossover.csv: the smallest N where exact memory_bytes (and insert+prepare+query CPU) reach 10x/100x the sketch's. - --points-from CSV selects a subset of the grid (for the 1e9 runs). - Tests for n_star, read_curve, --points-from and the cost phase against a fake approxbench. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Saturation study: --resume and --cost-rows - --resume (accuracy): keep the points whose curve over the requested sizes is already in saturation_curve.csv, write them back first, and run only the rest; a point cut off mid-write is dropped and rerun. Raw records are appended. - --cost-rows N (cost): time only the rows=N configs of the Vector2D sketches; other rows keep blank cost columns and get no crossover row. - Tests for both against the fake approxbench. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Saturation plots: draw one config per sketch from grid output The curve and cost files now hold the whole config grid; each figure keeps the config its bound is written for (rows=3 cols=1024, lg_k=12, k=200, alpha=0.01). The caption no longer hard-codes the seed count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Saturation study: config-grid and 1e9 results Document the 595-point config grid to 1e7 (N_sat per config, plateau scaling against theory) and the 185-point 1e9 subset: which unsaturated points saturate by 1e9, which keep growing (uniform data at K=1e7, top-k miss rate), and how far 1e7 N_sat verdicts move with a longer curve. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Saturation study: recommend a sketch config per query from worst-case data parameters scripts/recommend_config.py reads ASAPQuery's skew_summary.csv (new worst_* / min_N / max_N / target_* schema, or the older per-window one), rounds each query's worst case to the measured grid toward the harder side (theta down, K up, rank alpha up), reads the error at max_N from the grid (or 1e9) saturation curves, optionally from the merged curve for top-k and KLL, and writes the smallest config per family that meets the target to out/recommendations.csv, with n_sat, flags and cost columns once the cost phase exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add saturation study figures with reading guides Error-vs-N figures with theoretical bounds and the serial cost figure for the reduced run, plus the 1e9-subset figures, each with a README. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Saturation study: grid cost results and a per-query crossover N* N* is now the size from which exact stays >= f x the sketch, so polars' fixed start-up cost no longer marks N = 1e3 as a crossover, and both sides are charged one query instead of their differently sized probe sets. --phase crossover recomputes crossover.csv from the saved cost JSONL. Adds the grid cost and exact-vs-sketch figures, the crossover and recommendation CSVs, and the results to the doc. The recommender's query column is renamed query_phase_us, since it is the whole query phase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add the grid crossover and recommendation tables Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Document the saturation study's conclusions and the math behind them Conclusions across the trace analysis, the sketch study and merging, plus derivations: why KLL's rank error is distribution-free, why DDSketch's rank error grows and its memory shrinks with the Pareto index, and why merging is exact for linear sketches but adds variance for KLL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Update merge conclusions with the full top-k and KLL grids Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Key saved cost records and keep out-of-grid curves on resume --phase crossover matched saved cost records to points by position, so a different --cost-rows than the cost phase used gave silently wrong numbers or a StopIteration. Cost and exact records now carry their key and are looked up by it; a missing one exits with a clear message. --resume rewrote saturation_curve.csv with only the current grid's curves, so a narrower resume deleted finished curves. Rows outside the grid are now written back unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Cancel queued accuracy runs when one fails A failed approxbench run (or Ctrl-C) used to surface only after every queued run finished, and those results were discarded anyway. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Match cardinality as a number in point_key A saturation CSV filtered with pandas writes Zipf cardinalities as 1000.0 (the Pareto rows' empty cells make the column float), which never matched the grid's "1000". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Milind Srivastava <milindsrivastava1997@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Conclusions (task 3: sketch accuracy, saturation and cost)
No sketch's theoretical error bound depends on N. Error that still moves with N comes from two small-N effects: a noisy ground truth when N is small, and a tail of keys still arriving while N < K. Past N_sat, error is set by the config alone, so a profile measured on a small window extrapolates to larger (merged) windows.
N_sat is mostly 1e3–1e6, with two exceptions:
So an N_sat measured only up to 1e7 is a lower bound when K is large.
Error scales with config size as theory predicts, so configs can be interpolated:
The data distribution decides which sketch to use:
Merging (Measure accuracy after merging m shards #131):
So single-sketch curves are optimistic for top-k and KLL in merged windows.
Cost:
Sketch vs exact computation (exact = buffer the samples, compute at query time):
Worst-case parameters → configuration is automated (
scripts/recommend_config.py). Examples:by (user)by (service)Limits:
Summary
Measures, for each sketch type, configuration and data distribution:
Full method and results:
docs/saturation_study.md. Figures, each folder with a README:docs/figures/saturation/.What's added
--dataset pareto(--pareto-alpha,--pareto-scale, f64 or floored i64)scripts/study_saturation.py--phase accuracy|cost|crossover|all. Supports--resume,--cost-rows 3,--points-fromscripts/recommend_config.pyscripts/plot_saturation_{curves,cost,crossover}.pyN_sat is the first checkpoint after which every later seed-mean error stays within max(10% of the plateau, 2 standard errors) of the mean of the last 3 points.
N*(f) is the first N from which exact cost stays ≥ f × sketch cost at every larger N. CPU is counted as "ingest N items + answer one query" on both sides.
Grid
Key results
Every theoretical bound is N-independent. Error that still changes with N comes from small-N effects: a noisy ground truth, or a tail of keys still filling in while N < K.
Plateau error vs sketch size (log-log slope against each sketch's size parameter: width w for CMS/CountSketch/top-k, register count m = 2^lg_k for HLL, k for KLL, α for DDSketch):
Run to 1e9, 67 of the 108 points not saturated by 1e7 saturate:
Cost per item at N = 1e7, flat in N and in the distribution unless noted:
DDSketch memory shrinks from 6.3 KB to 2.3 KB as the Pareto α grows from 1.1 to 3.
Crossover vs exact (exact = buffer the samples, compute at query time):
Recommendations, with the cost data:
by (user)by (service)by (msname)Known limits
cpu_rate) is clamped to the edge of the grid.Validation
cargo test -p aqpbm-datagenpasses, including a Pareto α recovery test.-D warningsis clean on the touched crates.python3 -m unittest scripts/test_study_saturation.py scripts/test_recommend_config.py: 22 + 11 tests pass.🤖 Generated with Claude Code
🤖 Generated with Claude Code