Skip to content

[WIP – ignore until reviewed by @ChrisRackauckas] Add islinear/isquadratic: polynomial-degree certification by tracer types#66

Draft
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:islinear-isquadratic
Draft

[WIP – ignore until reviewed by @ChrisRackauckas] Add islinear/isquadratic: polynomial-degree certification by tracer types#66
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:islinear-isquadratic

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Please ignore until reviewed by @ChrisRackauckas. Draft opened by an agent. Closes #1. Rebased onto the v1.0.0 main (after #64 merged); additive 1.0.01.1.0.

Is it possible to reliably know if a function is linear or quadratic?

Not unconditionally: linearity is a non-trivial semantic property of programs, so Rice's theorem rules out a total decision procedure. What is achievable — and what solver dispatch actually needs — is one-sided reliability: true is a proof, false is only "not proven." That is the contract implemented here, mirroring hasbranching's conservatism.

API

islinear(f, x...; wrt = 1) / isquadratic(f, x...; wrt = 1) — prove polynomial degree ≤ 1 (affine) / ≤ 2 in the arguments selected by wrt (index, indices, or :), holding the others fixed. Both exported, docstring'd, and on the API docs page.

Mechanism — the tracer approach of the issue's reference, applied to degrees

Per the linked Sparsity Programming paper's methodology (abstract interpretation via tracer number types), a PolyDegree <: Real tracer propagates a sound upper bound on real-arithmetic polynomial degree: +/- → max, * → sum, /const and integer ^ scale, transcendentals on non-constants poison. Three design points give the certificate its teeth:

  1. Every value-needing predicate throws. Comparisons, isnan, rounding, conversions on a tracer abort the trace — so value-dependent branching is caught dynamically even inside Base broadcast machinery, where the hasbranching library-leaf policy is blind: u -> max.(u, 0.0) is correctly rejected.
  2. hasbranching is also required, statically proving the traced path is the only path. The two guards cover each other's blind spots. A branch on an untracked argument also (conservatively) withholds the certificate — documented with a test.
  3. wrt gives the SciML semantics: (u,p,t) -> p[1]*u[1] is certified linear in u for fixed p; with wrt = : it correctly refuses (bilinear). u -> A*u certifies through the generic matmul. In-place RHS via a closure (tested).

Conservatism is explicit: no cancellation modeling (x^2 - x^2 + x is genuinely linear but not certified — false means fall back, never "proven nonlinear").

Ground-truth validation

Every issued linear certificate is cross-checked in the tests against exactly vanishing second finite differences over Rational{BigInt} arithmetic at random points — an independent real-arithmetic soundness oracle. A known-nonlinear corpus is asserted never-certified.

Code organization

Split by concern: src/hasbranching.jl (branch analysis), src/polydegree.jl (degree tracer + certificates), module file only includes/exports.

Verification

  • Suites 70/70 (lts) · 72/72 (1.12.6) · 72/72 (1.13-rc1) — the tracer is pure dispatch, fully functional on lts, and runs together with the v1.0 constant-refutation machinery.
  • QA 18/18 (Aqua ambiguities against Base's cross-family Number constructors resolved with explicit disambiguators; one allow-list entry, TwicePrecision, exists solely for that disambiguation and is documented).
  • Docs build clean; Runic and typos clean.

…ypes

Implements the islinear/isquadratic proofs requested in SciML#1, using the
tracer-type abstract-interpretation approach of the referenced Sparsity
Programming paper, applied to polynomial degree instead of sparsity.

`islinear(f, x...; wrt = 1)` and `isquadratic(f, x...; wrt = 1)` attempt to
PROVE that `f` is a polynomial of degree <= 1 (affine) or <= 2 in the tracked
arguments, holding the others fixed. `true` is a certificate under real
arithmetic; `false` only means "not proven" -- the safe polarity for choosing
an LP/QP path. Deciding this for arbitrary programs is impossible (Rice's
theorem), so the design gives one-sided reliability:

  - The tracked arguments are seeded with `PolyDegree` tracer numbers and `f`
    is executed on them: `+`/`-` take the max degree, `*` adds, division by a
    constant and integer powers scale, and any non-polynomial operation on a
    non-constant poisons the result. Conservative by construction: the bound
    does not model cancellation (`x^2 - x^2 + x` is not certified).
  - Every predicate or conversion that would need the traced VALUE
    (comparisons, `isnan`, rounding, conversion) throws, aborting the trace --
    this catches value-dependent branching dynamically even inside Base
    broadcast machinery, where `hasbranching`'s library-leaf policy is blind
    (`max.(u, 0)` is correctly rejected).
  - `hasbranching` is additionally required, proving statically that the
    traced path is the only path. The two guards cover each other's blind
    spots; a branch on an UNTRACKED argument also withholds the certificate
    (conservative, documented).

The `wrt` selection gives the semantics SciML needs: an ODE right-hand side
`(u, p, t) -> p[1]*u[1]` is certified linear in `u` for fixed `p`, while
tracking everything (`wrt = :`) correctly refuses. Generic matrix code
certifies: `u -> A*u` proves linear through the generic matmul. In-place
right-hand sides work through a closure, shown in the tests.

Tests include a ground-truth cross-validation: every issued linear certificate
must have exactly vanishing second finite differences over exact
Rational{BigInt} arithmetic at random points -- soundness is checked against
real arithmetic, not against the tracer's own rules.

The source is split by concern: `src/hasbranching.jl` holds the branch
analysis, `src/polydegree.jl` the degree tracer and certificates, and the
module file only exports and includes.

Suites 70/70 on 1.10.11 and 72/72 on 1.12.6 and 1.13.0-rc1 (the tracer is pure
dispatch, fully functional on lts); QA 18/18 (constructor disambiguators added
for Base's cross-family Number constructors); docs build clean; Runic and
typos clean. Additive on the 1.0.0 release: 1.0.0 -> 1.1.0.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.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.

islinear / isquadratic proofs

2 participants