S2 — Numerical-contract catalog (precondition vs caveat sweep)#
The decision record that designed safe mode, preserved as approved (2026-06-19). The
current-state statement of these contracts — present tense, migration arrows resolved — is the
user page ../numerical_contracts.md.
The make-or-break input to dev/archive/safe_unsafe_mode_plan.md §5. Sweep of the
verified modules (tucker_tensor_train, frame_variations_format, manifold, corewise, fitting +
backend, probing) classifying each op’s numerical assumptions as an enforceable precondition or a
non-enforced caveat.
APPROVED by Nick, 2026-06-19, with these decisions:
retractprecondition = ORTH only (not GAUGE — retract is gauge-invariant). ✓
MANIFOLD.innerchecks all of SF + ORTH + GAUGE (+ structural-minimal, below), the frame ones cached on the frozen objects. ✓ — the minimal-rank parenthetical was superseded the same day; see the note under this banner.Frontend-only enforcement for now; a backend mirror is deferred and needs careful discussion (current lean: no backend numerical checks). ✓
No reclassifications. ✓
Minimal ranks: do NOT retire — keep this catalog as the answer to the long-standing “which ops need minimal ranks” TBD (a reference that does not exist in the literature). In safe mode, check ranks are structurally minimal (
has_minimal_ranks, cheap rank arithmetic); never run the numerical (SVD) check; document the requirement on each op. See the revised “Minimal ranks” section. The structurally-but-not-numerically-minimal gap is an adversarial edge case (failure mode: NaN / wrong result) we accept. — superseded the same day; see the note below.
Superseded (same session, 2026-06-19). Decisions 2 and 5 approved a safe-mode structural
minimal-rank check. The op-by-op experiment run about an hour later — the “Minimal ranks” section
below — disproved its premise: minimal rank is a correctness precondition for nothing. The check was
never wired, and the banner above is kept as written only because it records what was approved at the
time. What stands is the verdict in that section and the user page
../numerical_contracts.md.
The mechanism behind the result was worked out later and is written up in
../frame_variations.md: a frame carries four rank stores
(up/down, left/right) and absorbs an over-ranked request as slack between them, so an
orthonormal frame need not be minimal — T3Frame.random_orthogonal returns exactly such a frame for any
over-ranked request, and every tangent operation on it is exact. Orthonormality plus the gauge is the
whole precondition; a minimal-rank gate would reject legitimate frames.
The classification rule#
Precondition — the op is undefined or numerically wrong without it. Safe mode checks it (and raises); unsafe mode / under-jit skips it.
Caveat — the op is valid and correct as computed; the property only governs what the result means (e.g. “this equals Hilbert–Schmidt”). Never enforced — it would reject legitimate use.
The classic trap: orthogonality/gaugedness for inner/norm is a caveat (they’re valid on any frame;
those properties only make them equal HS), so it moves to the geometry’s inner/norm, not the raw op.
The numerical properties (and their checkers / cost)#
property |
meaning |
checker (exists) |
cost |
notes |
|---|---|---|---|---|
same-frame |
two tangents share one frame (= same tangent space) |
new |
O(1) common case |
|
orthogonal |
the frame is orthonormal (U/O/L/R conditions) |
|
contractions |
a |
gauged |
variations satisfy the gauge conditions (48)–(49) |
|
contractions |
per (frame,variations) pair; cacheable. |
minimal rank |
structurally-and-numerically minimal ranks |
|
SVD (numerical) |
numerical check intentionally skipped (§ “Minimal ranks”). |
Checkers are per-stack-element. Every checker/residual above returns one verdict per stack element (shape
stack_shape, scalar when unstacked) — seedocs/batching_and_stacking.md§9. So a safe-mode precondition reduces with.all()at the call site (safety.require(frame.is_orthogonal(atol).all(), …)): it requires all stack elements to pass;safety.requireitself stays a scalar gate. (The structuralhas_minimal_ranksis the one scalar-in-ragged exception — see that §9 note.)
Master table (by surface)#
SF = same-frame, ORTH = orthogonal frame, GAUGE = variations gauged. “—” = no numerical precondition
(structural checks like shapes/ranks/check_fv_pair still apply, always, in both modes).
Read the
minimalentries in the caveat columns below as pre-experiment. The “Minimal ranks” section further down measured every one of them and found none to hold:inner/normare exactly HS without minimality, and onlyretract’s strict rank preservation survives as a real caveat. The rows are left as written because this is the record of the sweep as approved.
T3Tangent (after the §S3 rename)#
op |
precondition (checked in safe mode) |
caveat (never checked) |
note |
|---|---|---|---|
|
SF |
— |
today an |
|
— |
— |
|
|
SF |
“= HS iff ORTH+GAUGE+minimal” |
renamed from |
|
— (unary) |
“= HS iff ORTH+GAUGE+minimal” |
renamed from |
|
|
— |
|
|
— |
— |
realization is gauge-invariant, valid on any frame |
|
— |
— |
bare 𝒥/𝒥ᵀ — gauge-invariant, any frame; the Riemannian |
|
— |
— |
structural / constructors |
|
SF (all leaves) |
— |
today identity |
|
— |
— |
|
|
— |
— |
checkers — they are the checks; keep non-enforcing |
Geometries (the semantic inner/norm live here — Nick’s refinement)#
op |
precondition |
caveat |
note |
|---|---|---|---|
|
SF + ORTH + GAUGE(both) |
minimal (for exact HS) |
the HS inner product; checks ORTH+GAUGE, can’t cheaply check minimal |
|
ORTH + GAUGE |
minimal |
unary (no SF) |
|
SF |
— |
Euclidean; no ORTH/GAUGE (the corewise frame is non-orthonormal by design) |
|
— |
— |
Euclidean, unary |
|
ORTH |
minimal (for oblique’s HS-matching purpose) |
the orthogonal-gauge projection needs an orthonormal frame to be the HS-orthogonal one |
|
ORTH |
minimal (rank preservation) |
precondition implied, not currently documented — confirm |
|
ORTH |
— |
docstring already states “Requires orthogonal; minimal NOT required” ✓ |
|
ORTH (new_frame) |
— |
= |
|
ORTH (via |
minimal (for a true Gaussian on |
docstring already careful: “for a non-orthogonal frame it is merely gauged” |
|
— |
— |
|
GaussNewtonModel (fitting)#
op |
precondition |
note |
|---|---|---|
|
SF ( |
today |
TuckerTensorTrain, corewise, probing — precondition-free#
surface |
precondition |
why |
|---|---|---|
|
— |
exact HS for any cores ( |
|
— |
exact for any cores; only structural shape/rank checks |
|
— |
the raw coordinate (“basic types”) layer; structural shape-match only |
|
— |
bare 𝒥/𝒥ᵀ contractions; gauge/frame-agnostic |
|
— (structural) |
|
The blurs this fixes (current code conflations)#
The same-frame guard is labelled “structural” but is numerical (
fitting._require_at_framedocstring “Structural guard”;T3Tangent._check_same_tangent_spaceviais). The root cause. →same_frame(identity fast-path +frames_equal), safe-mode, eager-only. This is what unblocks frame-as-leaf.T3Tangent.inner/normfold the HS caveat into the op (.. warning:: equals HS only when orthogonal and gauged). → split:MANIFOLD.inner/norm(HS, checks ORTH+GAUGE+SF) vscorewise_inner/corewise_norm(raw, checks SF). The op no longer pretends to be HS.retract/MANIFOLD.projectORTH precondition is silent (not in the docstrings). → state + check ORTH. (Confirmretractneeds only ORTH, not GAUGE — gauge is a redundancy retract is invariant to.)“some tangent ops only correct when minimal ranks — which exactly is TBD” (
manifold.py/bvf). → resolved as a caveat everywhere (see below); the TBD note can be replaced with the table above.
Minimal ranks — the resolution of the long-standing TBD (EMPIRICALLY verified — this is the reference)#
Minimal rank splits into structural (has_minimal_ranks — ranks equal the structural minimum; cheap
integer arithmetic) and numerical (has_numerically_minimal_ranks — no stored rank numerically
redundant; needs an SVD for a tensor, free for an orthonormal frame). An experiment settled which ops
actually need it (tests/-style script run 2026-06-19; each op compared on a minimal vs a non-minimal
orthogonal frame against the dense oracle):
op |
needs minimal? |
evidence |
|---|---|---|
|
NO |
|
|
NO |
the formula matches the true SVD rank (103) on the non-minimal frame. Correct for any ranks. |
|
soft caveat only |
still a valid first-order retraction on a non-minimal frame (rel.err 6e-6); it just drops the numerically-redundant rank (tucker 4→3) — desirable cleanup, not an error. Minimal buys only strict rank preservation. |
|
NO (correctness) |
gauged direction is valid on any orthonormal frame; “true Gaussian / HS-matching” is on whatever the stored-rank tangent space is, which is correct. |
|
NO |
orthogonal suffices (already known). |
Verdict: minimal rank is NOT a correctness precondition for any verified op. So we do not wire it as
a checked precondition — a structural-minimal check would raise on legitimate rank-redundant bases for
no correctness reason. (Also corrects an earlier claim: t3_orthogonal_representations does not
guarantee structural minimality — e.g. randn((10,11,12),(4,5,4),(1,2,3,1)) → has_minimal_ranks=False.)
Minimal rank lives on as a caveat (retract strict rank-preservation) and as diagnostic checkers
(built, not wired into any op): structural has_minimal_ranks (existing); numerical
TuckerTensorTrain.has_numerically_minimal_ranks(rtol) (structural-first → t3svd compare) and
T3Frame.has_numerically_minimal_ranks(atol) (orthogonal + structurally-minimal ⟹ numerically-minimal, no
SVD; non-orthogonal frames return False — the SVD path for them is deferred, “maybe we don’t need it”).
Super-safe mode was considered and dropped (no op needs it; it would be a ~no-op for orthogonal
frames). Naming convention: bare minimal_ranks = structural; numerically_minimal = numerical.
Implementation notes (for S3–S5, not decisions here)#
same_frame(b1, b2)=b1 is b2 or safety.frames_equal_or_skip(b1.data, b2.data)— theisfast-path keeps the common eager case O(1); the value compare only runs (and only matters) when objects differ but values match (jit round-trip) or genuinely differ. The tolerance is jax-aware (rtol_jaxif any input is a jax array, elsertol_numpy); under a trace it skips (returns pass). Mechanism int3toolbox/safety.py(S1, done).Where checks live (razor): to serve raw-
.datausers, the ORTH/GAUGE checks belong at the backend functions that consume raw data (tv_operations.*, which already haveis_orthogonal-style residual helpers), with the frontend methods inheriting them.same_frameis a frontend concept (it needs the twoT3Frameobjects); the backend’s analogue is “the caller passed one shared frame”, so the same-frame check is naturally frontend-only.Cost mitigation (done in S5): cache the atol-independent residual, not the atol-bool —
T3Frame.orthogonality_residualandT3Tangent.gauge_residualare@cached_propertys, andis_orthogonal(atol)/is_gauged(atol)compare against them. A fixed frame/tangent in an inner loop is contracted once; the atol stays a free parameter.Trace detection (done in S5): the eager-only skip must fire even when the checked operand is a closed-over concrete array (not a tracer) while globally inside a trace — a jnp op then still yields a constant tracer.
safety.is_tracingdetects the global trace state (jax.core.trace_state_clean, with a committed-array-probe fallback), not just whether the passed arrays are tracers.
Sign-off resolutions (Nick, 2026-06-19 — recorded here so the questions don’t look open)#
retractprecondition = ORTH only — confirmed. Retract is gauge-invariant (gauge relabels the variations, not the represented step); GAUGE is not checked there.MANIFOLD.inner/normcheck all three (same-frame + both operands GAUGE + frame ORTH), with the frame/tangent residuals cached (orthogonality_residual/gauge_residual) so a fixed frame in an inner loop is contracted once.Frontend-only enforcement — the backend stays check-free; a backend mirror for raw-
.datausers is deferred (the checkers themselves are public, so a backend user self-guards with the same tools).No reclassifications. The shipped state is the user page
../numerical_contracts.md.