graph TD P["๐ ginger\npure Python"] --> A["Aberth-Ehrlich\nsimultaneous roots"] C["โ๏ธ ginger-cpp\nCMake / xmake"] --> A R["๐ฆ ginger-rs\ncargo / rayon"] --> A P --> B["Bairstow\nquadratic factors"] C --> B R --> B A --> F["One convergence test\nOne scaling bug"] B --> F style P fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style C fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px style R fill:#ffcdd2,stroke:#b71c1c,stroke-width:3px style F fill:#fff9c4,stroke:#f57f17,stroke-width:4px
aberth, degree 32 โ cumulative time (before) horner_eval 3.51 s ยท 70% ใโ accumulate lambda 1.58 s ยท 31% aberth_job 1.26 s 4,032,000 lambda invocations โ one per polynomial coefficient, per root, per sweep. The arithmetic is O(n^2). The dispatch is the bottleneck.
flowchart LR Z["root estimate z_i"] --> E["evaluate P at z_i"] E --> T{"residual below tolerance?"} T -->|yes| D["converged"] T -->|no| U["Newton update"] U --> Z style Z fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style E fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style T fill:#fff9c4,stroke:#f57f17,stroke-width:4px style D fill:#a3be8c,stroke:#2e7d32,stroke-width:4px style U fill:#5e81ac,stroke:#2e3440,stroke-width:3px,color:#ffffff
Achievable residual floor vs the fixed 1e-12 threshold (log scale) 1e-10 1e-12 1e-14 1e-16 tolerance = 1e-12 โ never reached โ deg 8 converges โ deg 16 floor above threshold โ deg 32 hopeless โ Bar length is proportional to the floating-point floor. It grows with the coefficients; the threshold does not. An absolute tolerance on a scale-dependent quantity is a bug waiting for a scale. ๐ฃ
Iterations to converge โ bar length โ niter (log scale) deg 16 ยท before ๐ 2000 ยท FAILED ๐ฌ deg 16 ยท after ๐ 7 iters ยท 285ร โ deg 8 ยท before ๐ pbairstow 186 ms deg 8 ยท after ๐ 0.43 ms ยท 432ร โ Degree-8 pbairstow was also silently running to 2000 โ its floor was just above the line.
pbairstow_even, degree 32 โ object churn in the hot loop Vector2.x / .y getters 1.80 s ยท 18% Vector2.__sub__ 1.32 s ยท 13% Vector2.__init__ 0.20 s 704,000 object constructions ยท 5,056,000 property calls โ for ~35% of total runtime. Fix: private _suppress_old_step / _delta_step float cores, one source of truth. 1.95ร
flowchart LR C["candidate optimization"] --> M["measure its share"] M --> B{"a real share of runtime?"} B -->|yes| D["implement and verify"] B -->|no| S["skip it - it is noise"] D --> D1["Robin neighbours 13 percent"] S --> S1["coeffs.copy 0.7 percent"] style C fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style M fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style B fill:#fff9c4,stroke:#f57f17,stroke-width:4px style D fill:#a3be8c,stroke:#2e7d32,stroke-width:4px style S fill:#bf616a,stroke:#8b2c3a,stroke-width:3px,color:#ffffff style D1 fill:#a3be8c,stroke:#2e7d32,stroke-width:3px style S1 fill:#bf616a,stroke:#8b2c3a,stroke-width:3px,color:#ffffff
leja_order โ bar length โ speedup (log scale) n = 50 ๐ 16ร ยท 10.9 โ 0.66 ms n = 100 ๐ 33ร ยท 80.7 โ 2.45 ms n = 200 ๐ 56ร ยท 588 โ 10.4 ms n = 200 โ๏ธ๐ฆ 39ร / 41ร โ same order Validated bit-identical against the naive reference at n = 2, 3, 10, 37, 100 in all three languages. โ
flowchart LR F["finding from the profile"] --> K{"mathematical or runtime?"} K -->|mathematics| All["port to all three"] K -->|runtime| One["language specific"] All --> A1["unreachable tolerance"] All --> A2["leja_order complexity"] One --> O1["GIL threading - Python only"] One --> O2["lambda dispatch - Python only"] style F fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style K fill:#fff9c4,stroke:#f57f17,stroke-width:4px style All fill:#a3be8c,stroke:#2e7d32,stroke-width:4px style One fill:#d1c4e9,stroke:#6a1b9a,stroke-width:4px style A1 fill:#a3be8c,stroke:#2e7d32,stroke-width:3px style A2 fill:#a3be8c,stroke:#2e7d32,stroke-width:3px style O1 fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px style O2 fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px
Speedup โ bar width โ speedup; iteration counts are the real evidence aberth deg 16 ๐ 362ร ยท niter 2000 โ 7 pbairstow deg 8 ๐ 432ร ยท niter 2000 โ 6 aberth deg 16 โ๏ธ๐ฆ ~197ร / ~166ร leja_order n=200 ๐ 56ร leja_order n=400 ๐ฆ 90ร