Skip to content

Standalone NewtonRefine: the deflated-system sharpening primitive (core + bindings + python) - #374

Open
ofloveandhate wants to merge 3 commits into
developfrom
feature/newton-refine
Open

Standalone NewtonRefine: the deflated-system sharpening primitive (core + bindings + python)#374
ofloveandhate wants to merge 3 commits into
developfrom
feature/newton-refine

Conversation

@ofloveandhate

Copy link
Copy Markdown
Contributor

Standalone NewtonRefine: tracker-free Newton against a (deflated) System

The sharpening primitive the cellular-decomposition reliability work needs: refine a point against a square autonomous system (or one with a path variable, at a supplied time) to a requested consecutive-step tolerance, at the precision of the inputs — with no tracker construction or configuration.

The tracker-owned Refine is already exposed to Python, but it refines against the tracker's own system. Sharpening singular points requires Newton on the point's deflation — a plain autonomous System no tracker is configured around — which is exactly what this free function serves. Overdetermined systems are refused with instructions to square by randomization, matching production practice. Closes #373 (with a correction to that issue's premise: tracker.refine was already exposed; the standalone is the genuinely missing piece).

What's here

  • core/include/bertini2/nag_algorithms/newton_refine.hppbertini::algorithm::NewtonRefine, returning (code, point, achieved step norm, iterations). Fully doxygen'd.
  • Bindings: newton_refine free function (both arities), following ADR-0001 (refined vector returned by value; scalar time by value).
  • bertini.newton_refine pure-Python wrapper (numpydoc; py_doclint at baseline).

Tests — the isosingular hierarchy, in miniature

C++ (core/test/nag_algorithms/newton_refine.cpp), each sub-millisecond:

  1. nonsingular root: quadratic convergence to 1e-40 in ≤10 iterations
  2. overdetermined refusal: friendly std::runtime_error with squaring instructions
  3. plain double root: provably stalls (linear halving cannot reach 1e-40 in 25 iterations) — the disease, isolated
  4. double cone singularity: one deflation ([f; ∇f], hand-randomized with small-prime matrices whose nonsingularity at the target is verified in comments) → lands ON the origin to 1e-40
  5. whitney umbrella, handle point (0,0,1): a smooth point of the singular curve — deflation + pinning slice, randomized → ON the point
  6. whitney umbrella, pinch point: a singular point OF the singular embedded curve — the stage-1 deflation is itself singular there and provably fails; stage 2 (appending 2×2 minors of the stage-1 Jacobian) succeeds → ON the origin

Python interface tests mirror 3 of these end-to-end (cone from bertini.newton_refine: 4 iterations, 1e-6 offset → <1e-40 from the singularity); full Python suite green (932 passed).

The one bug the tests caught

linalg::PartialPivLU is stateful and requires ChangeSize before Factor/Solve; without it both run over a 0-dimensional system and "succeed" without computing. Caught by test 3 demanding failure and getting a phantom success — skeptical tests earning their keep.

🤖 Generated with Claude Code

ofloveandhate and others added 3 commits July 25, 2026 13:28
…deflated) System

The sharpening primitive: refine a point against a square autonomous (or
path-variable) System to a requested consecutive-step tolerance, at the
precision of the inputs.  Overdetermined systems are refused with squaring
instructions (randomize, as the tracking layer does).

Tests walk the isosingular hierarchy on hand-deflated, hand-randomized
systems (small-prime R matrices, nonsingularity verified in comments):
- nonsingular root: quadratic convergence to 1e-40
- double root on the plain system: provably stalls (the disease, isolated)
- double cone singularity: one deflation ([f; grad f], randomized) -> 1e-45
- whitney handle at (0,0,1): deflation + pinning slice, randomized -> 1e-45
- whitney pinch point: stage-1 deflation FAILS (still singular there);
  stage-2 (gradient + 2x2 minors of its Jacobian, randomized) -> 1e-45

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…per for newton_refine

The stateful PartialPivLU requires ChangeSize before Factor/Solve -- without it
both run over a 0-dimensional system and 'succeed' without computing (caught by
the double-root stall test demanding failure and getting a phantom success).

All six core tests green: nonsingular quadratic convergence, overdetermined
refusal, double-root stall, and the three silviana specimens -- double cone
origin (one deflation), whitney handle point (deflation + pinning slice),
whitney pinch point (stage-2 deflation via Jacobian minors, after stage-1
provably fails).  Sub-millisecond each.

Bindings: newton_refine free function (ADR-0001 shape: vector returned, time by
value), registered in bertini_python.  Python: bertini.newton_refine wrapper
(numpydoc), deflated-system sharpening from the port next.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ne into the package

Interface-only per doctrine (correctness is gated in C++): the cone specimen
end-to-end (4 iterations, 1e-6 offset -> <1e-40 from the singularity), the
overdetermined refusal surfacing as a friendly RuntimeError, and the honest
FailedToConverge on a plain double root.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

Expose tracker Refine (core Newton) to Python

1 participant