Skip to content

Add TaylorHomotopyContinuationJL: Taylor polynomialization + homotopy continuation + Newton polish for non-polynomial systems - #1094

Merged
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:taylor-homotopy-polynomialize
Jul 20, 2026
Merged

Add TaylorHomotopyContinuationJL: Taylor polynomialization + homotopy continuation + Newton polish for non-polynomial systems#1094
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:taylor-homotopy-polynomialize

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member

Note

This PR should be ignored until reviewed by @ChrisRackauckas.

Summary

Adds TaylorHomotopyContinuationJL{AllRoots} to NonlinearSolveHomotopyContinuation: a solver for general (non-polynomial) nonlinear systems that

  1. Taylor-expands the system around the initial guess into a polynomial surrogate of total degree degree (default 3), via TaylorSeries.jl jet transport — works on any generic Julia function, same operator-overloading requirement as ForwardDiff duals;
  2. finds all roots of the surrogate with HomotopyContinuation.jl (no initial-guess dependence);
  3. polishes every (near-)real path endpoint with a Newton iteration on the original system, reporting the distinct converged roots.

If the system is polynomial of total degree ≤ degree, the surrogate is exact and all roots are found. AllRoots = true returns an EnsembleSolution of every root (mirroring HomotopyContinuationJL{true}); the default single-root form returns the converged root closest to the initial guess. Supports oop/iip/scalar problems, explicit jacobians, and HomotopyNonlinearFunction transformations.

This complements the existing algorithm: HomotopyContinuationJL{true} requires a genuinely polynomial (HC-traceable) system; this works on transcendental ones at the cost of approximation, with the Newton polish recovering exactness of the reported roots.

Motivation / prototype results

Prototyped and benchmarked before this PR (details: https://github.com/ChrisRackauckas/InternalJunk/pull/69). On an 8-problem hard suite × 20 random starts (success = ‖f‖∞ < 1e-8): 100% success on every problem, including Freudenstein–Roth where TrustRegion stalls at the classic local-min of ‖f‖ (8/20), exp–sin where plain Newton scores 11/20, Bratu n=6 (returns both solution branches; Newton 17/20), Powell singular (multiplicity-4 root), and Kearfott's badly-scaled problem. Median solve times after tuning: 3–50 ms for n ≤ 5, ~0.4 s for n = 6 with 729 paths. The degree^n path count limits the method to roughly n ≤ 12 at degree 2, n ≤ 8 at degree 3 (documented in the docstring).

Implementation notes (perf/correctness findings baked in)

  • compile = false for the HC solve — every call builds a System with fresh numeric coefficients, so HC's compiled straight-line programs never get cache hits; without this each solve costs ~3.5 s of codegen (700× slowdown at these sizes).
  • All finite path endpoints are harvested, not just HC.solutions() — multiplicity-k roots (e.g. Powell singular) are classified as "excess" endpoints and dropped by the default accessors under every flag combination. As Newton guesses every finite endpoint is fair game; the polish filters junk.
  • Polish success is judged by achieved residual, not step convergence — at singular roots Newton converges only linearly and would report MaxIters despite an excellent iterate.
  • Total-degree start system for small path counts — dense Taylor truncations have mixed volume = Bézout number, so polyhedral mixed-cell computation is pure overhead (measured 47× on a trigexp system); polyhedral is used automatically above 200 paths.
  • TaylorSeries jet spaces are cached per (numvars, order) behind a lock (variables! rebuilds multiplication tables on every call).

Tests

New test/taylor_polynomialize.jl wired into the Core group: scalar transcendental (all 3 roots of u = 2sin(u) + closest-root variant), exact recovery of all 9 Himmelblau critical points, transcendental oop (exp–sin) and iip (Bratu, both branches), explicit-jacobian path, no-real-roots retcodes, multiplicity-4 singular root, and HomotopyNonlinearFunction polynomialize/unpolynomialize round-trip.

Ran locally with Pkg.test() on Julia 1.11:

Test Summary: | Pass  Total     Time
AllRoots      |  169    169  3m52.6s
Test Summary: | Pass  Total     Time
Single Root   |   50     50  1m47.4s
Test Summary:        | Pass  Total     Time
Taylor Polynomialize |   40     40  8m50.0s
     Testing NonlinearSolveHomotopyContinuation tests passed

Runic has been run on all changed files. Version bumped 0.1.10 → 0.1.11; TaylorSeries (0.22.4+) added as a dependency; docstring added to the docs API page in the same PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AYuTWSRDz6kE8Bn8vAKh57

…-polynomial systems

Taylor-expands a general nonlinear system around the initial guess into a
polynomial surrogate (via TaylorSeries.jl jet transport), finds all roots
of the surrogate with HomotopyContinuation.jl, and polishes every
(near-)real path endpoint with a Newton iteration on the original system.
If the system is polynomial of total degree <= `degree` the surrogate is
exact and all roots are recovered.

Implementation notes:
- `compile = false` for HC solves: each call builds a system with fresh
  numeric coefficients, so compiled straight-line programs never get cache
  hits and would cost seconds of codegen per solve.
- All finite path endpoints are harvested (not just `HC.solutions`), since
  multiplicity-k roots are classified as "excess" endpoints and dropped by
  the default accessors; the Newton polish filters junk endpoints.
- Newton polish success is judged by achieved residual, not step
  convergence, so singular roots (where Newton is only linear) still count.
- Total-degree start systems are preferred for small path counts: dense
  Taylor truncations have mixed volume equal to the Bezout number, making
  polyhedral mixed-cell computation pure overhead.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AYuTWSRDz6kE8Bn8vAKh57
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

CI analysis after first full run:

Everything exercising this PR's change is greensublibraries / lib/NonlinearSolveHomotopyContinuation Core tests on Julia 1 / lts / pre, QA (Aqua/ExplicitImports), downgrade-sublibraries for this sublib (validates the TaylorSeries 0.22.4 compat floor), Runic format check, spell check, and all downstream tests (ModelingToolkit, OrdinaryDiffEq, BoundaryValueDiffEq, DiffEqCallbacks).

The two failing jobs are pre-existing master failures, unrelated to this diff:

  • Documentation: fails with ERROR: LoadError: Duplicate BibTeX entry key detected: 'yuan2015recent' — fails identically on the 2026-07-19 master push and all recent PRs; the build dies while loading the bibliography, before reaching this PR's added @docs entry.
  • Downgrade / Downgrade Tests - Core (main package): fails on the 2026-07-19 master push and nearly all PRs since 2026-07-17. This PR does not touch the root project.

Both master failures are being investigated separately (bisect + fix PRs to follow).

🤖 Generated with Claude Code

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

Follow-up on the two pre-existing master CI failures noted above — both are now root-caused with fixes up:

🤖 Generated with Claude Code

@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review July 20, 2026 15:01
@ChrisRackauckas
ChrisRackauckas merged commit 23c7218 into SciML:master Jul 20, 2026
29 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants