autodiff: AD-OPERATOR-1 — operator tangents + the H3 well-posedness certificate - #597
Conversation
…ertificate OperatorTangent (autodiff/operator.py) promotes implicit.py's local matvec pattern to a type: a matrix-free linear map with composition as the operator product, .T as an involution, and solve-consumption — instances are callable, so cg_solve/gmres_solve take an operator anywhere they took a bare closure. A forward-only operator REFUSES .T rather than silently finite-differencing an adjoint. The Decision #31 relationship to the materialized @f__bwd ABI (one production lowering, one declared unmaterialized twin) is recorded in the module docstring. implicit.py is refactored onto the type behavior-identically: ihvp (declared-self-adjoint Hessian operator into CG), root_vjp (A.T solve, parameter pullback -(B.T @ r) — the (−Bᵀ)∘A⁻ᵀ chain), root_jvp, adjoint_state_grad (∂₁cᵀ through the type's transpose), and the dense oracle through operator.materialize(). All 54 pre-existing implicit/solver-IFT tests pass unchanged. H3 (CORE_SUBSTRATE_VIEW S8, the previously unowned one-fix-three- consumers item): certify_root measures the IFT hypothesis at a claimed root instead of assuming it — residual within tolerance AND σ_min > tol·σ_max of ∂ₓF (for KKT residuals, the strict-complementarity condition). custom_root gates differentiation on it by default in both convenience methods and the tape path: a degenerate root rejects with the measured numbers, a non-root rejects on the residual, an unevaluable check fails closed, and certify=False is an explicit opt-out. The certificate itself is exposed (solver.certificate) in the S4 numbers-not-booleans discipline. Acceptance (tests/unit/test_operator_tangent.py, 13 tests): the operator-level adjoint law incl. a falsifiability control (a wrong adjoint fails the pairing), transpose involution + (AB)ᵀ = BᵀAᵀ, fail-closed edges, solve consumption, certificate positive/negative fixtures, and tape-backward rejection at a degenerate root. Gauss–Newton / Newton–Krylov compositions are the named future consumers; no such op exists in-tree yet and inventing one would be Decision #29 in reverse. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 06bb92fa96
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Both review findings were real — reproduced exactly as described (wide Jacobian: |
AD-OPERATOR-1 — operator tangents + the H3 well-posedness certificate
The next AUTODIFF_NEXTGEN slice (§7, ~2w item, independent of the jet lane). One commit, three pieces:
OperatorTangent(autodiff/operator.py)implicit.py's local matvec pattern promoted to a type (plan §3.5): a matrix-free linear map with composition as the operator product,.Tas an involution, and solve-consumption — instances are callable, socg_solve/gmres_solvetake an operator anywhere they took a bare closure. A forward-only operator refuses.Trather than silently finite-differencing an adjoint. The Decision #31 relationship to the materialized@f__bwdABI (one production lowering, one declared unmaterialized twin) is recorded in the module docstring, next to the type.implicit.pyrefactored, behavior-identicalihvp(declared-self-adjoint Hessian operator into CG),root_vjp(the(−Bᵀ)∘A⁻ᵀchain through the type's own transpose),root_jvp,adjoint_state_grad, and the dense oracle viaoperator.materialize(). All 54 pre-existing implicit/solver-IFT tests pass unchanged — they are the regression net the plan names.H3: the strict-complementarity / well-posedness certificate
CORE_SUBSTRATE_VIEW.mdS8's previously unowned "one fix, three consumers" item (game theory, Riemannian-OT, S-series).certify_rootmeasures the IFT hypothesis at a claimed root instead of assuming it: the point is actually a root (scaled residual tolerance) and∂ₓFis non-degenerate (σ_min > tol·σ_max— for KKT-form residuals, exactly what strict complementarity guarantees).custom_rootgates differentiation on it by default, in both the convenience methods and the tape path:certify=Falseis an explicit opt-out, andsolver.certificate(x*, params)exposes the record itself (S4: numbers, not booleans).Acceptance (
tests/unit/test_operator_tangent.py, 13 tests)Operator-level adjoint law
⟨Av,u⟩=⟨v,Aᵀu⟩through the type's own transpose including a falsifiability control (an operator with a wrong declared adjoint fails the pairing); involution +(AB)ᵀ = BᵀAᵀ; fail-closed edges; solve consumption; certificate positive/negative fixtures (clean √θ root with measured σ_min = 2√2; degeneratex²−θat θ=0; singular 2×2 system); tape-backward rejection at a degenerate root.Gauss–Newton / Newton–Krylov compositions are the named future consumers — no such op exists in-tree yet, and inventing one would be Decision #29 in reverse.
Verification (Strix Halo box)
27 implicit+operator tests, 571-test autodiff regression net, ruff + mypy clean, generated docs in sync. Full CI-equivalent suite: 16,161 pass; the failing set is file-for-file the known pre-existing environmental baseline (Apple-lane tests vs this box's non-Apple
tessera-opt, which CI skips + the pre-existing gfx1151 provenance assert), with the two known xdist-flaky dashboard tests re-verified green in isolation.🤖 Generated with Claude Code