Repository navigation
benchmark: factor task (Pollard rho + Miller-Rabin), run.py report pipeline, malachite-float backend - #124
Merged
Conversation
…'s rho The task deterministically grows two ~n-bit primes from a fixed decimal seed (Miller-Rabin over the first 12 prime bases), multiplies them into a semiprime, then recovers the factors with Brent's variant of Pollard's rho, batching 128 modular-multiply differences between GCDs. This exercises modular multiplication/exponentiation, GCD and division on every library, with identical output across implementations. The Natural trait gains gcd/is_odd/is_zero/mul_mod/pow_mod (with generic defaults from the existing ops); libraries with native modular or gcd primitives (num, malachite, ibig, rust-gmp, ramp) override them.
pow_mod was composed from mul_mod via square-and-multiply on those two libraries, benchmarking the wrong kernel. Bind it to dashu-int's modular::Reduced (the Barrett reducer, favored over Montgomery for moduli below ~256 bits) and to rug::Integer::pow_mod (mpz_powm). Every Natural impl now overrides pow_mod with a native call, so the composed default is removed from the trait: the method is required and a library without a powmod must state its fallback explicitly. The now-unused is_zero default goes with it.
Bind dashu's pow_mod to the Montgomery reducer, which beats Barrett in the multi-kilobit regime this benchmark folder targets. Restructure the factor task to actually reach that regime: the previous shape (two n-bit factors) capped rho at ~48-bit inputs, since its cost is 2^(n/2) modular multiplications. The semiprime is now an n-bit prime times a ~31-bit prime, so the rho walk stays at ~2^16 steps while every modular multiplication, GCD and division runs at width n, and the Miller-Rabin verification contributes 12 n-bit modular exponentiations per iteration. The n-bit prime search is expensive at kilobit sizes, so its result is generated once with dashu and cached as a decimal string shared by all libraries; is_probable_prime also gains a trial-division pre-filter so the search rejects most composites before any modexp. Verified up to n=10000 (dashu and malachite agree on the 10031-bit semiprime); n=1024 runs in 0.37 s including generation.
Replace the table of 50 small primes (one division per prime) with five u64 constants, each the product of a run of consecutive primes written out as const expressions. A single gcd between the candidate and each run now decides whether any prime in the run divides it, so the Miller-Rabin scan exercises gcd between huge numbers and small ones (dashu-int's gcd-with-small-operand path) instead of many divisions. The Natural trait gains from_u64 to build those packed values. Answers are unchanged: the filter accepts exactly the same candidates as the trial division it replaces.
Calibrated against the other tasks' per-iteration costs (dashu, single run): e@1M 0.6 s, fib@10M 0.7 s, e@10M 13.4 s, fib@100M 18.1 s. The factor task measures 0.63 s at n=2048, 2.4 s at 4096 and 7.4 s at 8192, extrapolating to ~25 s at 16384 (~3.3x per doubling). The three recommended points span the same envelope, with the one-time prime search documented (~0.1 s / ~1 min / ~10 min).
Each task gets three n values whose single-iteration dashu time lands in the same ~0.05 s / ~0.2 s / ~3 s envelope as factor at 200/1000/5000, measured on the reference machine; e_decimal is excluded because bigdecimal's precision (and thus workload) is environment-controlled.
Combines the timing sweep (one cell per task x size x library, min of 3 runs for sub-second cells, factor generation cost measured at runtime and subtracted) with the grouped-bar chart generator (log time axis, task selector, per-library toggles). Results accumulate resumably in results.json; --results re-plots an existing sweep.
Bump malachite to 0.14 (integer trait paths unchanged), astro-float to 0.9.6 and bigdecimal to 0.4.11; num, rug, rust-gmp, ibig and ramp were already at their latest versions. malachite::Float joins the pi task via its precision-aware primitives (from_unsigned_prec, sqrt_prec_ref, atan_prec_ref): it agrees with dashu, astro-float and rug within the ulp tolerance up to 50k bits, rendering decimal scientific output that the tolerance check parses. Its atan is FLINT-derived and runs at GMP-class speed (~10 ms at 50k bits), making it the pure-Rust reference for transcendental throughput.
REPORT.md records the test environment (OS, kernel, CPU, memory, rustc, GMP), a table per task with the fastest library per size in bold, and a static per-task bar chart (chart_<task>.svg) embedded as a markdown image — GitHub strips <script> tags, so the interactive chart.html is linked instead of inlined.
run.py writes results.json, chart.html and the per-task SVGs into benchmark/report/ while REPORT.md stays at benchmark/; the raw json is git-ignored, the visualizations are tracked. The committed charts were regenerated after re-measuring every malachite cell (0.9 -> 0.14 is up to 14x faster on the integer tasks), bigdecimal (0.4.11) and astro-float (0.9.6), and now include malachite_float in the pi panel.
chart.html embeds its data inline and does not read the json, but the raw timings are the data behind the committed charts and let a fresh clone re-plot or resume the sweep without re-running it, so the file joins the tracked report artifacts.
…rts" This reverts commit 7d11d81.
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.
Summary
Extends the benchmark crate with a GCD/modular-arithmetic workload, a one-command sweep & report pipeline, and refreshes every tested library to its latest version (adding
malachite::Floatas a float backend).New
factortaskOne workload combining both classic algorithms, exercising modular multiplication/exponentiation, gcd and division at every width:
The task scales from 16 bits to 10k+ bits: the semiprime is an n-bit prime (searched once, cached as a decimal string shared by all libraries, absorbed by the median-of-5 sampling in
exec) times a ~31-bit prime, so the rho walk stays at ~2^16 steps while every operation runs at width n, and the Miller-Rabin verification contributes 12 n-bit modular exponentiations per iteration. Output is byte-identical across libraries (verified up to n=10000 against malachite, and for rug/rust-gmp where GMP is available).Natural/Floattrait extensionsgcd,is_odd,from_u64, and modularmul_mod/pow_mod— required methods bound to each library's native kernels (dashu montypow, rugInteger::pow_mod, nummodpow, malachiteModPow/ModMul, ibigModuloRing, rust-gmppowm, ramppow_mod), so no library silently benchmarks a composed fallback.pow_moduses the Montgomery reducer, matching the large-bit regime this folder targets.run.pysweep + report pipelinepython3 run.pytimes the recommended three-size ladder across every task/library (min of 3 runs for sub-second cells, factor's one-time prime generation measured and subtracted, resumable viaresults.json) and writes:REPORT.md— environment (OS, kernel, CPU, memory, rustc, GMP), per-task tables with the fastest library in bold, embedded static charts;report/chart.html— interactive comparison (task switching, library toggles, tooltips);report/chart_<task>.svg+report/results.json.All cells share the parameter ladder calibrated so one iteration costs roughly the same across tasks (~0.05 s / ~0.2 s / ~3 s), matching
factorat 200/1000/5000.Dependency updates
malachite 0.9.2 → 0.14.0 (integer trait paths unchanged, but dramatically faster — e.g. e@4M digits 8.8 s → 0.6 s, now GMP-class), astro-float 0.9.6, bigdecimal 0.4.11; num, rug, rust-gmp, ibig and ramp were already latest.
malachite::Floatjoins the pi task via its precision-aware primitives and agrees with dashu/astro-float/rug within the ulp tolerance up to 50k bits (~0.014 s at 50k bits — FLINT-derived atan).Testing
factor(dashu/ibig/num/malachite at n=16..40, rug/rust-gmp with system GMP at n=64/256, dashu/malachite at n=10000) and for pi with the new backend.cargo fmtandcargo clippy --all-targets --release --features gmpclean for the new code; full sweep reproduced within ~1% across runs.