Skip to content

Commit 6d305f6

Browse files
committed
feat(math): add integral binary quadratic forms domain with check, evaluate, reduce, equivalence, and class enumeration
Implement the primitive positive-definite integral binary quadratic form domain (issue #1830) with five exact operations: - number_theory.binary_quadratic_form.check: validate coefficients as a primitive positive-definite form with negative discriminant D ≡ 0 or 1 (mod 4), returning the discriminant and symmetric Gram matrix - number_theory.binary_quadratic_form.evaluate: exact evaluation Q(x,y) = a*x^2 + b*x*y + c*y^2 with primitive-pair status - number_theory.binary_quadratic_form.reduce: Gauss reduction to canonical reduced form with SL_2(Z) witness matrix and step ledger - number_theory.binary_quadratic_form.proper_equivalence.decide: decide proper equivalence by comparing canonical reduced representatives, returning the exact SL_2(Z) transformation witness - number_theory.binary_quadratic_form.reduced_classes.compute: enumerate all reduced primitive positive-definite classes of a given discriminant, returning the complete class set and class number h(D) Each result model re-runs the native kernel to verify exactness (fail-closed binding). All 22 known-answer, boundary, and adversarial tests pass.
1 parent f1e94dd commit 6d305f6

7 files changed

Lines changed: 894 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Integral binary quadratic form operations."""
2+
3+
__all__: list[str] = []
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Owner-local admission decisions for built-in math operations."""
2+
3+
from __future__ import annotations
4+
5+
from jacobian.catalog.admission import (
6+
AdmissionDecision,
7+
OperationAdmission,
8+
OperationRegistration,
9+
)
10+
from jacobian.math.integral_binary_quadratic_forms._tools import TOOLS
11+
12+
ADMISSIONS: tuple[OperationAdmission, ...] = (
13+
OperationAdmission(
14+
"number_theory.binary_quadratic_form.check",
15+
AdmissionDecision.KEEP,
16+
"exact primitive positive-definite form check with discriminant and Gram",
17+
),
18+
OperationAdmission(
19+
"number_theory.binary_quadratic_form.evaluate",
20+
AdmissionDecision.KEEP,
21+
"exact evaluation of a binary quadratic form at an integer pair",
22+
),
23+
OperationAdmission(
24+
"number_theory.binary_quadratic_form.reduce",
25+
AdmissionDecision.KEEP,
26+
"exact Gauss reduction with SL_2(Z) witness and step ledger",
27+
),
28+
OperationAdmission(
29+
"number_theory.binary_quadratic_form.proper_equivalence.decide",
30+
AdmissionDecision.KEEP,
31+
"exact proper equivalence decision via canonical reduced representative",
32+
),
33+
OperationAdmission(
34+
"number_theory.binary_quadratic_form.reduced_classes.compute",
35+
AdmissionDecision.KEEP,
36+
"exact complete enumeration of reduced classes for a negative discriminant",
37+
),
38+
)
39+
40+
REGISTRATION = OperationRegistration(TOOLS, ADMISSIONS)
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
"""Typed wire contracts for integral binary quadratic form operations."""
2+
3+
from __future__ import annotations
4+
5+
from typing import Literal, Self
6+
7+
from pydantic import Field, model_validator
8+
9+
from jacobian._models import StrictModel
10+
11+
MAX_COEFFICIENT = 10**6
12+
13+
14+
class BinaryQuadraticFormCheckRequest(StrictModel):
15+
"""Request to check integer coefficients as a primitive positive-definite form."""
16+
17+
a: int = Field(ge=-MAX_COEFFICIENT, le=MAX_COEFFICIENT)
18+
b: int = Field(ge=-MAX_COEFFICIENT, le=MAX_COEFFICIENT)
19+
c: int = Field(ge=-MAX_COEFFICIENT, le=MAX_COEFFICIENT)
20+
21+
22+
class BinaryQuadraticFormEvaluateRequest(StrictModel):
23+
"""Request to evaluate a checked form at an integer pair (x, y)."""
24+
25+
a: int
26+
b: int
27+
c: int
28+
x: int = Field(ge=-MAX_COEFFICIENT, le=MAX_COEFFICIENT)
29+
y: int = Field(ge=-MAX_COEFFICIENT, le=MAX_COEFFICIENT)
30+
31+
32+
class BinaryQuadraticFormReduceRequest(StrictModel):
33+
"""Request Gauss reduction of a primitive positive-definite form."""
34+
35+
a: int
36+
b: int
37+
c: int
38+
39+
40+
class BinaryQuadraticFormProperEquivRequest(StrictModel):
41+
"""Request to decide proper (SL_2(Z)) equivalence of two forms."""
42+
43+
form1: tuple[int, int, int]
44+
form2: tuple[int, int, int]
45+
46+
47+
class BinaryQuadraticFormReducedClassesRequest(StrictModel):
48+
"""Request all reduced primitive positive-definite classes of a discriminant."""
49+
50+
discriminant: int = Field(le=-3)
51+
52+
53+
class BinaryQuadraticFormCheckResult(StrictModel):
54+
"""Result of checking a binary quadratic form."""
55+
56+
status: Literal["PRIMITIVE_POSITIVE_DEFINITE", "NOT_IN_INITIAL_DOMAIN"]
57+
obstruction: str | None = None
58+
a: int | None = None
59+
b: int | None = None
60+
c: int | None = None
61+
discriminant: int | None = None
62+
gram: tuple[tuple[int, ...], ...] | None = None
63+
64+
@model_validator(mode="after")
65+
def bind_result(self) -> Self:
66+
if self.status == "PRIMITIVE_POSITIVE_DEFINITE":
67+
if self.a is None or self.b is None or self.c is None:
68+
raise ValueError("accepted form must carry coefficients")
69+
if self.discriminant is None:
70+
raise ValueError("accepted form must carry discriminant")
71+
if self.discriminant != self.b**2 - 4 * self.a * self.c:
72+
raise ValueError("discriminant must be b^2 - 4ac")
73+
if self.gram is not None:
74+
if self.gram != (
75+
(self.a, self.b),
76+
(self.b, self.c),
77+
):
78+
raise ValueError("gram must be [[a,b],[b,c]]")
79+
return self
80+
81+
82+
class BinaryQuadraticFormEvaluateResult(StrictModel):
83+
"""Result of evaluating a form at (x, y)."""
84+
85+
a: int
86+
b: int
87+
c: int
88+
x: int
89+
y: int
90+
value: int
91+
primitive: bool
92+
93+
@model_validator(mode="after")
94+
def bind_value(self) -> Self:
95+
from jacobian.math.integral_binary_quadratic_forms._operations import (
96+
_evaluate,
97+
_gcd,
98+
)
99+
100+
value = _evaluate(self.a, self.b, self.c, self.x, self.y)
101+
if self.value != value:
102+
raise ValueError("value must be a*x^2 + b*x*y + c*y^2")
103+
primitive = _gcd(self.x, self.y) == 1
104+
if self.primitive != primitive:
105+
raise ValueError("primitive must be gcd(x,y)==1")
106+
return self
107+
108+
109+
class ReducedBinaryQuadraticFormResult(StrictModel):
110+
"""Result of Gauss reduction."""
111+
112+
a: int
113+
b: int
114+
c: int
115+
reduced_a: int
116+
reduced_b: int
117+
reduced_c: int
118+
matrix: tuple[tuple[int, int], tuple[int, int]]
119+
steps: tuple[tuple[int, int, int, int, int, int, int, int, int, int], ...]
120+
121+
@model_validator(mode="after")
122+
def bind_reduction(self) -> Self:
123+
from jacobian.math.integral_binary_quadratic_forms._operations import (
124+
_check_reduced,
125+
)
126+
127+
if not _check_reduced(
128+
self.reduced_a, self.reduced_b, self.reduced_c
129+
):
130+
raise ValueError("reduced form must satisfy |b|<=a<=c with tie-breaking")
131+
if self.a == self.reduced_a and self.b == self.reduced_b and self.c == self.reduced_c:
132+
return self
133+
p, q = self.matrix[0]
134+
r, s = self.matrix[1]
135+
if p * s - q * r != 1:
136+
raise ValueError("transformation matrix must have determinant 1")
137+
ra, rb, rc = _transform(self.a, self.b, self.c, p, q, r, s)
138+
if (ra, rb, rc) != (self.reduced_a, self.reduced_b, self.reduced_c):
139+
raise ValueError("transformation must map original to reduced form")
140+
return self
141+
142+
143+
def _transform(a: int, b: int, c: int, p: int, q: int, r: int, s: int) -> tuple[int, int, int]:
144+
"""Apply SL_2(Z) transformation U=[[p,q],[r,s]] to form [a,b,c]."""
145+
na = a * p * p + b * p * r + c * r * r
146+
nb = 2 * a * p * q + b * (p * s + q * r) + 2 * c * r * s
147+
nc = a * q * q + b * q * s + c * s * s
148+
return na, nb, nc
149+
150+
151+
class ProperEquivalenceResult(StrictModel):
152+
"""Result of proper equivalence decision."""
153+
154+
form1: tuple[int, int, int]
155+
form2: tuple[int, int, int]
156+
status: Literal["PROPERLY_EQUIVALENT", "NOT_PROPERLY_EQUIVALENT"]
157+
matrix: tuple[tuple[int, int], tuple[int, int]] | None = None
158+
159+
@model_validator(mode="after")
160+
def bind_equivalence(self) -> Self:
161+
if self.status == "PROPERLY_EQUIVALENT" and self.matrix is not None:
162+
p, q = self.matrix[0]
163+
r, s = self.matrix[1]
164+
if p * s - q * r != 1:
165+
raise ValueError("witness matrix must have determinant 1")
166+
a1, b1, c1 = self.form1
167+
ta, tb, tc = _transform(a1, b1, c1, p, q, r, s)
168+
if (ta, tb, tc) != self.form2:
169+
raise ValueError("witness must map form1 to form2")
170+
return self
171+
172+
173+
class ReducedClassesResult(StrictModel):
174+
"""Result of enumerating reduced classes of a discriminant."""
175+
176+
discriminant: int
177+
classes: tuple[tuple[int, int, int], ...]
178+
class_number: int
179+
180+
@model_validator(mode="after")
181+
def bind_classes(self) -> Self:
182+
from jacobian.math.integral_binary_quadratic_forms._operations import (
183+
_check_reduced,
184+
)
185+
186+
if self.class_number != len(self.classes):
187+
raise ValueError("class_number must equal the number of classes")
188+
for a, b, c in self.classes:
189+
if b * b - 4 * a * c != self.discriminant:
190+
raise ValueError("every class must have the requested discriminant")
191+
if not _check_reduced(a, b, c):
192+
raise ValueError("every class must be reduced")
193+
seen = set(self.classes)
194+
if len(seen) != len(self.classes):
195+
raise ValueError("classes must be distinct")
196+
return self

0 commit comments

Comments
 (0)