Repository navigation
Conversation
ahrazzle
left a comment
There was a problem hiding this comment.
Review: gfq checker
Verdict: the code is correct. Fix three small issues and settle where it lives before merging.
What I checked
- Tests and CLI. Ran the suite on this head (Python 3.13):
Ran 24 tests … OK.python3 -m gfq --q 3 examples/golay11.txtprints[11,6,5]with a checked certificate. - Independent cross-check. 384 random full-rank codes over q ∈ {2,3,4,5,7,8,9} (k ≤ 5, n ≤ 14). I compared
brute_force_min_distanceandbz_min_distanceagainst a separate naive enumerator over all q^k messages: 0 mismatches, and BZ returnedcomplete=Trueevery time. - BZ lower bound. Re-derived the argument in
distance.py. With g disjoint information sets, a codeword of weight < g(s+1) has at most s nonzeros on one of them, so it is enumerated at message weight ≤ s in that systematic form.lb = min(ub, g·(s+1))and thes > kexit are both sound. The budget exit reports the previous level's bounds, so it never claims more than it proved.
Inline (minor)
- GF(9) uses x²+1, not the Conway polynomial x²+2x+2 that Magma/GAP/Sage use. Integer-encoded matrices from those tools would be read as a different code without any warning.
- The
q k n/k nheader heuristic can drop or reject a real first row (n ≤ 3 only). - A one-line compact matrix (
20121) fails to parse, which contradicts the README.
Before merging: where should this live?
- Foundation-0/gfq-codes exists, was pushed as recently as 25 Oct, and #6's README lists it as the home for exactly this question. #6 also says that once work has code and certificates, it gets its own repository. This PR adds a Python package (
pyproject.tomlat the math0 root) to the hub repo. Please confirm with the maintainers whethergfq/belongs here or in gfq-codes. If gfq-codes already has it, close this PR and #4. - Merge conflicts with other open PRs.
README.mdconflicts with #1 and #6, and.gitignoreis add/add with #1. - This branch has no CI (no check runs), so the 24 tests only run by hand.
Generated by Claude Code
| _IRREDUCIBLE = { | ||
| 4: (2, [1, 1, 1]), # x^2 + x + 1 over GF(2) | ||
| 8: (2, [1, 1, 0, 1]), # x^3 + x + 1 over GF(2) | ||
| 9: (3, [1, 0, 1]), # x^2 + 1 over GF(3) (no root mod 3) |
There was a problem hiding this comment.
GF(9) encoding differs from Conway / Magma / GAP / Sage. x²+1 is irreducible over GF(3), so this is a valid GF(9). But x isn't primitive here (x⁴ = 1; primitive_element() returns 4, i.e. x+1). The Conway polynomial for GF(9) is x²+2x+2, and Magma, GAP and Sage use it by default. A matrix integer-encoded by one of those tools (e.g. Sage's integer_representation(), base-3 digits of the coefficients) has the same additive encoding but a different multiplication table. gfq would read it as a different code and report that code's d without any error.
GF(4) and GF(8) already match the Conway choices (x²+x+1, x³+x+1). Suggest switching GF(9) to x²+2x+2 now, while no GF(9) data is committed anywhere (#4 has none), and adding a test that pins the encoding. With x²+2x+2 you get x² = x+1, so GF(9).mul(3, 3) == 4; today it returns 2.
Generated by Claude Code
| consistent = ( | ||
| (len(hdr) == 3 and hdr[1] == len(lines) - 1 and hdr[2] == width2) | ||
| or (len(hdr) == 2 and hdr[0] == len(lines) - 1 and hdr[1] == width2)) | ||
| if consistent: | ||
| if len(hdr) == 3 and hdr[0] != F.q: | ||
| raise ValueError( | ||
| f"header says q={hdr[0]} but --q is {F.q}") | ||
| continue |
There was a problem hiding this comment.
The header heuristic can drop or reject a real first row. Repro on this head:
parse_matrix("1 2\n0 1\n", GF(3)) # -> [[0, 1]] first row silently read as "k n"
parse_matrix("1 2 3\n0 1 0\n0 0 1\n", GF(4)) # -> ValueError: header says q=1 but --q is 4The first gives a [2,1] code instead of [2,2] with no warning. The second rejects a valid full-rank matrix. Only n ≤ 3 can trigger this, so codetables-size inputs are safe. But silently misreading input is exactly what this tool is meant to rule out. Suggest never treating a line as a header when all its values are valid field elements, which fixes both repros and keeps the 3 2 3 test passing (3 ∉ GF(3)). Or require an explicit marker such as # q k n.
Generated by Claude Code
| rows: Matrix = [] | ||
| for idx, line in enumerate(lines): | ||
| s = line.strip().strip("[]") | ||
| if re.fullmatch(r"[0-9]+", s) and len(s) > 1 and (rows or len(lines) > 1): |
There was a problem hiding this comment.
A one-line compact matrix doesn't parse. For one-line input, (rows or len(lines) > 1) is false, so "20121" falls through to the token branch and becomes the integer 20121:
parse_matrix("20121\n", GF(3)) # ValueError: 20121 is not an element of GF(3) (0..2)The README says compact strings such as 20121 work, and the comment on lines 52-53 says a single compact line is kept as a row. This only affects k = 1 inputs. Dropping the (rows or len(lines) > 1) clause fixes it: the header branch only handles lines with 2 or 3 space-separated tokens, so it never sees a no-space line anyway.
Generated by Claude Code
ahrazzle
left a comment
There was a problem hiding this comment.
The matrix parser silently removes valid input. In GF(3), parse_matrix('[1,2]\n[0,1]\n', GF(3)) returns [[0, 1]], so the checker reports [2,1,1] for a rank-two generator. Brackets do not disambiguate a matrix row from the optional header. A single compact row, 102, also raises an out-of-field error despite the documented format. The 24 existing tests pass without covering these inputs.
What was done
gfq/package (stdlib only, Python >=3.10): GF(q) arithmetic for q in {2,3,4,5,7,8,9} (GF(4)/GF(8)/GF(9) via explicit polynomial tables; q=6 rejected), generator-matrix parsing (space/comma/bracketed/compact-digit rows, optionalq k nheader), exact minimum distance by brute force and by a Brouwer-Zimmermann-style disjoint-information-set enumeration with an explicit budget, and classical constructions (Hamming, Reed-Solomon, ternary Golay) for validation.python -m gfq --q Q [--method auto|brute|bz] [--json] FILE|-, console scriptgfq-checkviapyproject.toml) printing[n,k,d], a minimum-weight codeword certificate (checked to lie in the row space with the claimed weight), and honest exit codes (0 exact, 2 budget exhausted with only bounds claimed, 1 input error).tests/, 24 tests, stdlibunittest) andexamples/golay11.txt; README section with use, limits, and next steps for the smallest open codetables entries.Exact reproduction commands
Observed on this branch (Python 3.14.6):
Ran 24 tests in 1.369s OK; CLI prints[11,6,5], a weight-5 certificate,certificate in row space with claimed weight: True; BZ stress: GF(3) Hamming r=4 ->[40,36,3](1296 enumerations), GF(4) Hamming r=3 ->[21,18,3]where brute force (4^18) is infeasible.Claim labels
gfq/distance.py.What was NOT done