Speed up normalizeForFactor's square-free-core extraction, which measured at ~5–11% of every classical Berlekamp-Zassenhaus factorization — the largest single common-path cost surfaced while investigating #8690 ("thread the shared coefficient bound").
normalizeForFactor f computes the primitive part and the square-free core (gcd(f, f') over ℤ). Unlike defaultFactorCoeffBound (<1% of the tier, and the subject of #8690), this is a genuine, non-redundant common-path cost: on the classical-success path it is computed exactly once (HexBerlekampZassenhaus/FactorEntryPoints.lean:220), and the classical tier answers the whole corpus, so ZPoly.factorize cost tracks factorClassical cost almost exactly.
Measurement
Distinct-input shift families, chungus2-class box, timing (normalizeForFactor f).squareFreeCore against the whole classical tier factorClassical f:
| input |
normalizeForFactor (µs) |
classical tier (µs) |
share |
| split deg8 height0 |
40 |
547 |
7.3% |
| split deg12 height0 |
111 |
1966 |
5.7% |
| split deg16 height0 |
267 |
5106 |
5.2% |
| split deg20 height0 |
594 |
10327 |
5.7% |
| split deg24 height0 |
998 |
18802 |
5.3% |
| split deg6 height32 |
31 |
638 |
4.9% |
| phi15 (deg 8) |
34 |
314 |
11% |
| SD3 (deg 8) |
28 |
517 |
5.4% |
| SD4 (deg 16) |
137 |
4894 |
2.8% |
So this is the only common-path lever with real upside (defaultFactorCoeffBound by contrast is <1%, e.g. deg24 0.16%). This is an algorithmic speedup, not a deduplication: there is nothing to thread away — the cost is a single necessary call per factorization.
Directions to sanity-check before committing to one
Treat these as hypotheses, not a spec — profile normalizeForFactor first to confirm where the time goes (content GCD vs derivative vs the gcd(f, f') subresultant remainder sequence, and the big-integer cost of the intermediate coefficients):
- The dominant cost is likely coefficient blow-up in the ℤ subresultant PRS for
gcd(f, f'). A modular (mod-p, CRT / rational-reconstruction or a chosen good prime) square-free split, or the standard Yun square-free factorization done modularly, would avoid the big-integer intermediate swell that grows with degree (the deg8→deg24 curve above, 40 µs → ~1 ms, is consistent with super-linear coefficient growth, not just degree).
- Check whether
normalizeForFactor recomputes content / primitive part in a way that duplicates the derivative or a GCD already available.
- Any change must keep the square-free core output bit-identical (it feeds prime selection, lifting, and the whole recombination pipeline); verify with the
bench/HexBerlekampZassenhaus/Bench.lean degree/height grid and FLINT conformance unchanged.
Scope: HexPolyZ (wherever normalizeForFactor / the square-free-core extraction lives) and its BZ callers. Low-to-moderate priority: ~5% of the classical tier is a real but modest win, and it is uniform across the corpus.
Context: this was split out of #8690, whose bound-threading premise did not survive re-measurement.
Speed up
normalizeForFactor's square-free-core extraction, which measured at ~5–11% of every classical Berlekamp-Zassenhaus factorization — the largest single common-path cost surfaced while investigating #8690 ("thread the shared coefficient bound").normalizeForFactor fcomputes the primitive part and the square-free core (gcd(f, f')over ℤ). UnlikedefaultFactorCoeffBound(<1% of the tier, and the subject of #8690), this is a genuine, non-redundant common-path cost: on the classical-success path it is computed exactly once (HexBerlekampZassenhaus/FactorEntryPoints.lean:220), and the classical tier answers the whole corpus, soZPoly.factorizecost tracksfactorClassicalcost almost exactly.Measurement
Distinct-input shift families, chungus2-class box, timing
(normalizeForFactor f).squareFreeCoreagainst the whole classical tierfactorClassical f:normalizeForFactor(µs)So this is the only common-path lever with real upside (
defaultFactorCoeffBoundby contrast is <1%, e.g. deg24 0.16%). This is an algorithmic speedup, not a deduplication: there is nothing to thread away — the cost is a single necessary call per factorization.Directions to sanity-check before committing to one
Treat these as hypotheses, not a spec — profile
normalizeForFactorfirst to confirm where the time goes (content GCD vs derivative vs thegcd(f, f')subresultant remainder sequence, and the big-integer cost of the intermediate coefficients):gcd(f, f'). A modular (mod-p, CRT / rational-reconstruction or a chosen good prime) square-free split, or the standard Yun square-free factorization done modularly, would avoid the big-integer intermediate swell that grows with degree (the deg8→deg24 curve above, 40 µs → ~1 ms, is consistent with super-linear coefficient growth, not just degree).normalizeForFactorrecomputes content / primitive part in a way that duplicates the derivative or a GCD already available.bench/HexBerlekampZassenhaus/Bench.leandegree/height grid and FLINT conformance unchanged.Scope:
HexPolyZ(wherevernormalizeForFactor/ the square-free-core extraction lives) and its BZ callers. Low-to-moderate priority: ~5% of the classical tier is a real but modest win, and it is uniform across the corpus.Context: this was split out of #8690, whose bound-threading premise did not survive re-measurement.