Skip to content

perf(bz): speed up normalizeForFactor square-free-core extraction (~5% of the classical tier) #8701

Description

@kim-em

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.

Metadata

Metadata

Assignees

Labels

featurePlanner-dispatched implementation work

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions