Skip to content

Commit 12a3308

Browse files
committed
wire(combinatorial_matrices): register domain, snapshot, baselines, tests
- Import TOOLS and ADMISSIONS in catalog/builtins.py. - Update frozen admission baselines (KEEP 239->244, candidates 399->404) and add the combinatorial_matrices schema-snapshot fragment (5 operations). - Add 15 focused tests (sign profile, Gram profile, normalize, determinant profile, Sylvester, validation).
1 parent 3dc1e5f commit 12a3308

8 files changed

Lines changed: 232 additions & 3 deletions

File tree

src/jacobian/catalog/builtins.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
from jacobian.math.boolean_analysis._tools import TOOLS as BOOLEAN_ANALYSIS_TOOLS
4747
from jacobian.math.code_theory._admission import ADMISSIONS as CODE_THEORY_ADMISSIONS
4848
from jacobian.math.code_theory._tools import TOOLS as CODE_THEORY_TOOLS
49+
from jacobian.math.combinatorial_matrices._admission import (
50+
ADMISSIONS as COMBINATORIAL_MATRICES_ADMISSIONS,
51+
)
52+
from jacobian.math.combinatorial_matrices._tools import (
53+
TOOLS as COMBINATORIAL_MATRICES_TOOLS,
54+
)
4955
from jacobian.math.combinatorics._admission import (
5056
ADMISSIONS as COMBINATORICS_ADMISSIONS,
5157
)
@@ -290,6 +296,7 @@
290296
*ARITHMETIC_DYNAMICS_TOOLS,
291297
*NUMBER_THEORY_TOOLS,
292298
*DIOPHANTINE_APPROXIMATION_TOOLS,
299+
*COMBINATORIAL_MATRICES_TOOLS,
293300
*COMBINATORICS_TOOLS,
294301
*FINITE_SETS_TOOLS,
295302
*FINITE_FIELDS_TOOLS,
@@ -359,6 +366,7 @@
359366
*BOOLEAN_ADMISSIONS,
360367
*BOOLEAN_ANALYSIS_ADMISSIONS,
361368
*CODE_THEORY_ADMISSIONS,
369+
*COMBINATORIAL_MATRICES_ADMISSIONS,
362370
*COMBINATORICS_ADMISSIONS,
363371
*CONVEX_ANALYSIS_ADMISSIONS,
364372
*DIOPHANTINE_APPROXIMATION_ADMISSIONS,

src/jacobian/math/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
algebraic_combinatorics,
55
arithmetic,
66
arithmetic_dynamics,
7+
combinatorial_matrices,
78
combinatorics,
89
diophantine_approximation,
910
finite_abelian_groups,
@@ -32,6 +33,7 @@
3233
"algebraic_combinatorics",
3334
"arithmetic",
3435
"arithmetic_dynamics",
36+
"combinatorial_matrices",
3537
"combinatorics",
3638
"diophantine_approximation",
3739
"finite_abelian_groups",
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"catalog_version": "1",
3+
"domain": "combinatorial_matrices",
4+
"operations": {
5+
"matrix.hadamard.determinant_profile.compute": {
6+
"input_schema": "sha256:2bed119fe8ed1a6c4b93acb9a67d9129bd6fd4dc0d084d200fb334909a29efa4",
7+
"output_schema": "sha256:82967463ed763c68b4a2502dc4cc68067d689473b952ff65c24e8c7decac04a1"
8+
},
9+
"matrix.hadamard.gram_profile.compute": {
10+
"input_schema": "sha256:8b53e0c4dbe80d78684ba7ee4a7aa548570eaf4b26744139b7a287cfa28b483c",
11+
"output_schema": "sha256:6286bd7d96158a2d20a1c3eff04ff97260af743b5f00c9be527b7ba0f1776c97"
12+
},
13+
"matrix.hadamard.normalize.compute": {
14+
"input_schema": "sha256:8fb074a74dd078e4c7b7033750be61ca378d688da5ad4adb29871c29e770bf46",
15+
"output_schema": "sha256:7833badc83fe9d8e803ec01568d1550536642feec1759ec6b7ce9e2362d33842"
16+
},
17+
"matrix.hadamard.sylvester.compute": {
18+
"input_schema": "sha256:8fa9031546a2805a8dd6c6cda5c922848095ff5cb0848c8ecbb817002fbac828",
19+
"output_schema": "sha256:42009601575a36953403c651c4ba599c335477eebea753adcddb7486e6f0fbc6"
20+
},
21+
"matrix.sign.profile.compute": {
22+
"input_schema": "sha256:5cd8bca9b97550c24d3b13ed8d51cbe1d007719de0247c6c291c02e50b2fcc4b",
23+
"output_schema": "sha256:04b3a31ebd7a923ff5a16e502bd5d7a09a14c7ba0010bda9287126eda4716835"
24+
}
25+
}
26+
}

tests/catalog/test_admission.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ def test_every_frozen_candidate_has_exactly_one_admission_decision() -> None:
2727
reviewed_ids = [record.operation_id for record in OPERATION_ADMISSIONS]
2828

2929
assert REVIEWED_BASE_REVISION == "61589543bbbff546edbc51d34a07887982fa4ad6"
30-
assert len(candidate_ids) == len(set(candidate_ids)) == 399
30+
assert len(candidate_ids) == len(set(candidate_ids)) == 404
3131
assert reviewed_ids == sorted(reviewed_ids)
3232
assert set(reviewed_ids) == set(candidate_ids)
3333
assert all(record.rationale.strip() for record in OPERATION_ADMISSIONS)
3434
assert Counter(record.decision for record in OPERATION_ADMISSIONS) == {
35-
AdmissionDecision.KEEP: 239,
35+
AdmissionDecision.KEEP: 244,
3636
AdmissionDecision.NATIVE_ONLY: 56,
3737
AdmissionDecision.DROP: 104,
3838
}
@@ -46,7 +46,7 @@ def test_public_catalog_contains_only_admitted_atomic_operations() -> None:
4646
}
4747

4848
assert {tool.operation_id for tool in BUILTIN_TOOLS} == expected
49-
assert len(BUILTIN_TOOLS) == 239
49+
assert len(BUILTIN_TOOLS) == 244
5050

5151

5252
def test_catalog_construction_fails_closed_on_duplicate_candidates() -> None:

tests/math/combinatorial_matrices/__init__.py

Whitespace-only changes.
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
"""Tests for combinatorial-matrix operations."""
2+
3+
from __future__ import annotations
4+
5+
import pytest
6+
from pydantic import ValidationError
7+
8+
from jacobian.math.combinatorial_matrices import HadamardMatrix, SignMatrix
9+
from jacobian.math.combinatorial_matrices._models import (
10+
DeterminantProfileRequest,
11+
GramProfileRequest,
12+
NormalizeRequest,
13+
SignProfileRequest,
14+
SylvesterRequest,
15+
)
16+
from jacobian.math.combinatorial_matrices._operations import (
17+
compute_determinant_profile,
18+
compute_gram_profile,
19+
compute_normalize,
20+
compute_sign_profile,
21+
compute_sylvester,
22+
)
23+
from jacobian.math.combinatorial_matrices._tools import TOOLS
24+
25+
# ---------------------------------------------------------------------------
26+
# Helpers
27+
# ---------------------------------------------------------------------------
28+
29+
30+
def _h2() -> SignMatrix:
31+
return SignMatrix(rows=((1, 1), (1, -1)))
32+
33+
34+
def _non_hadamard() -> SignMatrix:
35+
"""A sign matrix that is NOT Hadamard: all +1 2x2."""
36+
return SignMatrix(rows=((1, 1), (1, 1)))
37+
38+
39+
# ---------------------------------------------------------------------------
40+
# Catalog
41+
# ---------------------------------------------------------------------------
42+
43+
44+
def test_catalog_contains_only_audited_agent_outcomes() -> None:
45+
assert {tool.operation_id for tool in TOOLS} == {
46+
"matrix.sign.profile.compute",
47+
"matrix.hadamard.gram_profile.compute",
48+
"matrix.hadamard.normalize.compute",
49+
"matrix.hadamard.determinant_profile.compute",
50+
"matrix.hadamard.sylvester.compute",
51+
}
52+
53+
54+
# ---------------------------------------------------------------------------
55+
# Sign profile
56+
# ---------------------------------------------------------------------------
57+
58+
59+
class TestSignProfile:
60+
def test_h2_profile(self) -> None:
61+
result = compute_sign_profile(SignProfileRequest(matrix=_h2()))
62+
assert result.row_count == 2
63+
assert result.column_count == 2
64+
assert result.plus_one_count == 3
65+
assert result.minus_one_count == 1
66+
assert result.is_square is True
67+
assert result.row_sums == (2, 0)
68+
69+
70+
# ---------------------------------------------------------------------------
71+
# Gram profile
72+
# ---------------------------------------------------------------------------
73+
74+
75+
class TestGramProfile:
76+
def test_h2_is_hadamard(self) -> None:
77+
result = compute_gram_profile(GramProfileRequest(matrix=_h2()))
78+
assert result.order == 2
79+
assert result.is_hadamard is True
80+
assert result.gram == ((2, 0), (0, 2))
81+
assert result.diagonal_residuals == (0, 0)
82+
assert result.nonzero_off_diagonal == ()
83+
84+
def test_non_hadamard(self) -> None:
85+
result = compute_gram_profile(
86+
GramProfileRequest(matrix=_non_hadamard())
87+
)
88+
assert result.is_hadamard is False
89+
assert result.gram == ((2, 2), (2, 2))
90+
91+
92+
# ---------------------------------------------------------------------------
93+
# Normalize
94+
# ---------------------------------------------------------------------------
95+
96+
97+
class TestNormalize:
98+
def test_h2_normalize_idempotent(self) -> None:
99+
result = compute_normalize(NormalizeRequest(matrix=_h2()))
100+
# H2 already has first row/column all +1.
101+
assert result.normalized == ((1, 1), (1, -1))
102+
assert result.row_switches == (0, 0)
103+
assert result.column_switches == (0, 0)
104+
105+
def test_normalize_flips(self) -> None:
106+
matrix = SignMatrix(rows=((-1, -1), (-1, 1)))
107+
result = compute_normalize(NormalizeRequest(matrix=matrix))
108+
assert result.normalized == ((1, 1), (1, -1))
109+
assert result.column_switches == (1, 1)
110+
assert result.row_switches == (0, 0)
111+
112+
113+
# ---------------------------------------------------------------------------
114+
# Determinant profile
115+
# ---------------------------------------------------------------------------
116+
117+
118+
class TestDeterminantProfile:
119+
def test_h2_determinant(self) -> None:
120+
h = HadamardMatrix(rows=((1, 1), (1, -1)))
121+
result = compute_determinant_profile(DeterminantProfileRequest(matrix=h))
122+
assert result.order == 2
123+
assert result.determinant_magnitude == 2 # 2^(2/2) = 2
124+
assert result.gram_determinant == 4 # 2^2
125+
126+
127+
# ---------------------------------------------------------------------------
128+
# Sylvester
129+
# ---------------------------------------------------------------------------
130+
131+
132+
class TestSylvester:
133+
def test_sylvester_k0(self) -> None:
134+
result = compute_sylvester(SylvesterRequest(k=0))
135+
assert result.order == 1
136+
assert result.matrix == ((1,),)
137+
138+
def test_sylvester_k1(self) -> None:
139+
result = compute_sylvester(SylvesterRequest(k=1))
140+
assert result.order == 2
141+
assert result.matrix == ((1, 1), (1, -1))
142+
143+
def test_sylvester_k2_is_hadamard(self) -> None:
144+
result = compute_sylvester(SylvesterRequest(k=2))
145+
assert result.order == 4
146+
h = HadamardMatrix(rows=result.matrix)
147+
assert len(h.rows) == 4
148+
149+
150+
# ---------------------------------------------------------------------------
151+
# Validation
152+
# ---------------------------------------------------------------------------
153+
154+
155+
class TestValidation:
156+
def test_non_sign_entry_rejected(self) -> None:
157+
with pytest.raises(ValidationError, match="sign matrix entries"):
158+
SignMatrix(rows=((1, 0), (0, 1)))
159+
160+
def test_non_hadamard_rejected(self) -> None:
161+
with pytest.raises(ValidationError, match="orthogonality"):
162+
HadamardMatrix(rows=((1, 1), (1, 1)))
163+
164+
def test_non_square_hadamard_rejected(self) -> None:
165+
with pytest.raises(ValidationError, match="square"):
166+
HadamardMatrix(rows=((1, 1, 1), (1, -1, 1)))
167+
168+
def test_unequal_row_lengths_rejected(self) -> None:
169+
with pytest.raises(ValidationError, match="equal length"):
170+
SignMatrix(rows=((1, 1, 1), (1, -1)))
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""Exact public API contract for jacobian.math.combinatorial_matrices."""
2+
3+
from __future__ import annotations
4+
5+
from jacobian.math import combinatorial_matrices
6+
7+
8+
def test_exact_public_api_symbols() -> None:
9+
expected = (
10+
"HadamardMatrix",
11+
"SignMatrix",
12+
"determinant_profile",
13+
"gram_profile",
14+
"kronecker",
15+
"normalize",
16+
"sign_profile",
17+
"sylvester",
18+
)
19+
assert tuple(combinatorial_matrices.__all__) == expected
20+
assert len(combinatorial_matrices.__all__) == len(set(combinatorial_matrices.__all__))
21+
assert all(not name.startswith("_") for name in combinatorial_matrices.__all__)
22+
assert all(hasattr(combinatorial_matrices, name) for name in combinatorial_matrices.__all__)

tests/math/public_api/test_namespace.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"algebraic_combinatorics",
2020
"arithmetic",
2121
"arithmetic_dynamics",
22+
"combinatorial_matrices",
2223
"combinatorics",
2324
"diophantine_approximation",
2425
"finite_abelian_groups",

0 commit comments

Comments
 (0)