Extends generate/math_versor_arithmetic.py with one new function:
def subtract(addend: float) -> np.ndarray:
return translator(-float(addend))
Single-line delegate to translator(); no new algebra.
Adds tests/test_arithmetic_subtract_and_group.py covering all nine
ADR-0140 acceptance families:
Families 1-6 (ADR-0139 families applied to subtract):
1. Embedding well-formedness — null cone preserved for subtract cases
2. Translator-of-negative well-formedness — versor_condition < 1e-6
3. Closure — sandwich result stays on null cone
4. Arithmetic correctness — decoded value == a − b within 1e-9
5. Replay determinism — byte-identical across runs
6. Composability — subtract(c) ∘ subtract(b) decodes to a − b − c
New group-property families (structural verification of ADR-0139 claim):
7. Inverse composition — T_{-b} * T_b = identity (max residual: 0.000e+00)
8. Round-trip closure — versor_apply(T_{-b}, versor_apply(T_b, X)) → (a, u)
9a. Sum composition — T_a * T_b = T_{a+b} (max residual: 0.000e+00)
9b. Commutativity — T_a * T_b byte-equals T_b * T_a (all 10 cases)
All 96 tests pass. Group residuals are exactly 0.0 in float64.
The additive subgroup of Cl(4,1) translators along e1 is abelian and
closed; ADR-0139's algebraic claim holds at the group level.
11 KiB
ADR-0140 — subtract as Inverse Translator + Additive Group Closure
Status: Draft
Date: 2026-05-24
Author: CORE agents
Parent: ADR-0139
Engine target: CGA cognitive engine (algebra/versor.py, algebra/cga.py)
Context
ADR-0139 proved one operation — add — can be represented as a closed
unit versor in Cl(4,1) with all residuals exactly 0.0 in float64. The
construction T_t = 1 - 0.5·(t·n_inf) produces an exactly-closed
translator because (t·n_inf)² = 0 algebraically before any float
arithmetic occurs.
That spike proved the algebraic substrate can host one operation. It did not yet prove anything about the structure the operations should form. Subtract is the smallest follow-on that:
- Demonstrates the family generalizes —
subtractis the same construction with a negated addend, so it should inherit the exact-closure property for free. - Surfaces the additive group structure. Add + subtract together form an abelian group on the e1 axis. The structural identities (inverse, identity, associativity, commutativity) are the actual thing being decoded — not just "two operations work."
The thesis (thesis-decoding-not-generating) is sharper here: the engine
isn't being given subtract as a new capability; it's being shown that
the additive group was already there in the algebra, and CORE is
decoding the relationships that already hold between the operations.
This ADR makes that decoding visible by testing the group axioms directly.
Decision
Construction
subtract(addend) is implemented as translator(-addend). No new
algebra; the existing translator() from ADR-0139 is reused with a
negated argument.
def subtract(addend: float) -> np.ndarray:
return translator(-float(addend))
Group-property tests
Beyond the six assertion families inherited from ADR-0139, this ADR introduces three new families that test the additive group structure:
-
Family 7 — Inverse composition.
T_{-b} · T_b = identity. Specifically, the geometric product oftranslator(-b)andtranslator(b)equals the scalar1(component 0 = 1, all others 0) within machine epsilon. -
Family 8 — Round-trip closure.
versor_apply(T_{-b}, versor_apply(T_b, X)) = X. An additive shift followed by its inverse recovers the original embedded quantity byte-equal at the chosen tolerance. -
Family 9 — Commutativity of translators.
T_a · T_b = T_b · T_a = T_{a+b}. Additive translations commute and compose into a single translator by the sum. This is the abelian property of the group; if it fails, the algebra is decoding something other than scalar addition.
Acceptance
A single test module — tests/test_arithmetic_subtract_and_group.py —
passes with the following assertions on a small fixed set of (a, b) pairs.
Inherited from ADR-0139 (applied to subtract)
The same six families ADR-0139 used for add, applied to subtract:
- Embedding well-formedness (re-verified on subtract cases)
- Translator-of-negative well-formedness —
versor_condition(subtract(b)) < 1e-6 - Closure under sandwich —
cga_inner(R, R) < 1e-5 - Arithmetic correctness —
decode_quantity(R, u) == (a − b, u)within1e-9 - Replay determinism — byte-identical across runs
- Composability —
subtract(c) ∘ subtract(b)decodes toa − b − c
New group-property families
-
Inverse composition. For each
bin the test set:geometric_product(translator(-b), translator(b))equals the scalar versor[1, 0, 0, ..., 0]within1e-9component-wise. -
Round-trip closure. For each
(a, b)in the test set:versor_apply(translator(-b), versor_apply(translator(b), embed_quantity(a, "u")))decodes to(a, "u")with error< 1e-9. Includes the caseb = 0(degenerate — should be identity in the algebra). -
Commutativity / composition into sum. For each
(a, b):geometric_product(translator(a), translator(b))equalstranslator(a + b)component-wise within1e-9.geometric_product(translator(a), translator(b))equalsgeometric_product(translator(b), translator(a))byte-equal.
Fixed test cases
Subtract cases (a, b):
(0, 0), (5, 0), (0, 5),
(10, 3), (3, 10),
(1.5, 0.5), (0.25, 0.75),
(-5, 3), (5, -3),
(-2, -3), (100, 1)
Group cases (a, b) for families 7-9:
(0, 0), (1, 0), (0, 1),
(1, 1), (-1, 1), (3, 4),
(0.5, 0.5), (-2.5, 2.5),
(100, 1), (1, 100)
Non-goals
Out of scope for this ADR (every item below is for a follow-on):
- No
multiply,divide, or any non-additive operation.multiplyis ADR-0141 territory — the dilator construction is structurally different and concentrates the next risk. - No
MathProblemGraphconsumer. NoPropositionGraphconstruction. NoCognitiveTurnPipelineintegration. - No GSM8K case routed.
- No pack changes.
- No proof of associativity beyond what binary-composition tests implicitly
cover. (Three-element associativity
T_a · (T_b · T_c) = (T_a · T_b) · T_cwould be a clean addition but is redundant given commutativity + closure into the sum.) - No "inverse element" exposed as a separate primitive.
subtract(b)is the inverse ofadd(b); the engine does not need a named "inverse" function until ADR-0143 (compare) or later.
Engine B (math_solver.py, candidate-graph parser, S.x corridor) remains
unchanged. The 3/50 GSM8K admission set is preserved.
Rationale
Why test the group axioms here rather than later?
The thesis says the engine decodes what is already there. The additive
group on the real line is already there — it's a mathematical fact
independent of CORE. If translator() faithfully decodes addition, then
the group axioms must hold automatically. Testing them isn't "adding a
feature"; it's verifying that what we think we decoded is what we
actually decoded.
If the inverse composition test (family 7) fails, the construction is not decoding addition — it's decoding something that looks like addition on small cases but doesn't form a group. That would invalidate ADR-0139 retroactively and pause the lift program.
If commutativity (family 9) fails, the algebra is not decoding scalar addition — it's decoding some non-abelian operation, which means scalar arithmetic can't be lifted onto this construction as we assumed.
So families 7-9 are not nice-to-haves. They are the structural verification that ADR-0139's algebraic claim is actually true at the group level, not just at the point-pair level.
Why subtract, not multiply, as the next step?
Multiply is structurally different — it's a dilator, not a translator,
and the dilator construction in CGA (D_s = cosh(α/2) + sinh(α/2)·(n_o ∧ n_inf))
sits on a different versor manifold. The closure properties have to be
re-derived. That's the next big risk; doing subtract first locks down
the additive subgroup so multiply has a clean foundation to extend from.
Subtract is also the smallest possible follow-on — same construction, same module, three new test families. If subtract's spike fails, we catch the inverse-element failure with a one-line change rather than a multi-module multiply implementation.
Why no MathProblemGraph wiring yet?
Same reason as ADR-0139: the substrate must be proven before integration.
We don't yet know whether multiply (the next risk) closes; if it
doesn't, the integration plan changes shape. Wiring add and subtract
into MathProblemGraph before multiply is tested would couple two
unrelated unknowns.
Risks
Materially smaller than ADR-0139 because most of the load-bearing algebra is already discharged:
-
The inverse-composition test (family 7) may not hit exact zero. In ADR-0139,
T_t · reverse(T_t) = 1was exact because of an algebraic cancellationB² = 0. The compositionT_{-b} · T_bis a different product (reverseis not the same as negate). The expected residual is bounded by(geometric_product cancellation precision)at float64. If it lands between1e-9and1e-6, the test passes the versor-condition threshold but suggests the algebra isn't exactly the additive group. Worth measuring honestly. -
Commutativity is non-trivial at the multivector level. Two bivectors don't generally commute.
translator(a) · translator(b)multiplied out involves cross-terms; whether those cancel depends on the structure ofB_a = a·e1·n_infandB_b = b·e1·n_inf. They do (because both bivectors live in the same 2D subspace spanned bye14ande15, where the algebra reduces to a commuting plane). But this is the kind of property that's true by structure, not by accident — and family 9 is exactly the test that confirms it. -
b = 0edge case.translator(0)should be the scalar 1 exactly. The construction1 - 0.5 · (0 · n_inf)simplifies to1symbolically, and float arithmetic should reach the same result, but family 8'sb = 0case verifies it explicitly.
Replay & invariants
Same invariants as ADR-0139:
versor_condition(T) < 1e-6for all constructed translators (now including negative addends).- Null inputs to
versor_applystay null. - No new normalization is introduced.
- Float64 end-to-end where precision matters.
- Determinism: same
(a, b)→ identical multivector bytes across runs.
New cross-cutting invariant introduced by this ADR (worth pinning in the test module): the additive subgroup of Cl(4,1) translators along e1 is abelian and closed under composition. Families 7-9 are the CI-enforced statement of this invariant.
Sequencing for follow-on
Only if every assertion in this ADR passes:
- ADR-0141:
multiplyas dilator. Concentrates the next risk. - ADR-0142:
Rateas bivector;apply_rateas combined translator-dilator. - ADR-0143:
compare_*at the proposition layer, not the versor layer. - ADR-0144:
PropositionGraphfromMathProblemGraph. - ADR-0145: One GSM8K case routed end-to-end through Engine A.
If any assertion fails — particularly family 7 (inverse) or family 9 (commutativity) — ADR-0139's algebraic claim is invalidated retroactively. The lift program pauses until the failure mode is documented and a revised construction is proposed.
Decision summary
Extend generate/math_versor_arithmetic.py with one new function
(subtract, a one-line delegate to translator(-b)). Add one test
module verifying the six ADR-0139 acceptance families against subtract,
plus three new families that test the additive group structure
(inverse, round-trip, commutativity).
Acceptance is binary: every test passes, or the ADR is withdrawn and ADR-0139's claim is re-examined.