By: ValentinHirschi <valentin.hirschi@gmail.com>
cli: numerator templates in positional slots The CLI's prepare bound the external carriers of the numerator template to fresh symbols (ninjars_cli_components::p<generation>_<index>). Plans over that template (export-bench, `reduce`/`bench --numerator-evaluator symjit-o2[-factored]`, the fast runtime) therefore paid the positional renaming in PolynomialCoefficientPlan::exact_evaluator, which re-normalizes every coefficient head. Their exact factoring (`export-bench --factor`, symjit-o2-factored) also still depended on the process history, because Symbolica orders polynomial variables by symbol: after 300 unrelated symbols and two other fixtures, 6 of 684 values of the gg -> hh top-box-2 heads differed. prepare now binds the carrier components to ninjars_positional::slots, as PhysicalTensorNumerator does since 561117c, so the template is expanded directly in the evaluators' positional parameters. Fresh names, as before, take their place if the slots are functions (after tens of thousands of registrations) or occur in the bound integrand. Parameter names appear only in `reduce --diagnostics` (`numerator_template`, `numerator_parameters`), now as ninjars_slot::s<n>. src/determinism_tests.rs (a unit test of the binary, so it can call prepare) evaluates the gg -> hh top-box-2 pool fixture's heads, plain and exactly factored, in Float(256) and binary64 at its exact samples. It does so in a fresh child process, then in a process that first registers 300 symbols and prepares two other fixtures, in this thread and in two concurrent threads, and requires bitwise-equal results. It fails without this change (6 of 684 values, all from factoring). Results, `reduce` against 561117c on 50 configurations (generic engine in f64, double-float and Float; SymJIT plain and factored; fast engine; FDH; scalar, parameterized, rank-8 heptagon and all seven physical pool fixtures): bitwise identical except the factored four-photon top box, whose factors now come out in positional order: - generic engine: 22 of 30 components move by <= 1.9e-14 of the lane's largest component; errors against Float(256) go from 6e-15/2e-14/2.4e-14 to 1.2e-14/3e-14/2.4e-14 (unfactored: 1.1e-14 to 9.9e-14); - fast engine: same components, <= 8.4e-13 of the lane maximum; distance to the unfactored fast result from <= 9.7e-13 to <= 5.8e-13. The committed bench cases are byte-identical (export_bench.rs), and neither the rank-n2-s0 bitwise fixture's inputs nor ninjars-symbolica change. Timing: - Same-core interleaved A/B against 561117c (8 rounds, medians): SymJIT coefficient compilation (evaluator construction and JIT) -4.4% for the gg -> hhh top pentagon (843 -> 806 ms), -4.8% factored, -6.2% for the factored gg -> hh top box; export-bench Float(256) evaluation -3% and -5% (--factor). Coefficient planning and factoring are unchanged. - export-bench's prepare stage takes 1253 ms instead of 1208 ms. The slot pool, previously registered by the first evaluator, now registers there. In a full CLI process, its ~4100 symbols cost ~90M instructions and grow Symbolica's symbol table by ~10^4 page faults (~35 ms of system time). A build with the pool but fresh names prepares in 1255 ms; expanding in slot order adds ~40M instructions. - Whole processes: user-space instructions -0.1% to -1.2% (pentagon symjit-o2 -1.2%, export-bench -0.6%); task-clock +0.3% to +1.1% (export- bench: user +0.4%, system +10 ms), generic hgg -6.8%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>