Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions research/right-vector-extension-fields/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# #4334's sharp right-vector threshold over extension fields

**Claim type: an independent finite check over six non-prime fields. No new
κ.** It adds the extension-field software coverage that #4334 explicitly does
not claim.

## Object

[PR #4334](https://github.com/CrocSwap/integer-mult-bounds/pull/4334) (ToikY)
works in the right-vector model:

- paid factors `I + u·yᵀ`, with `u ∈ R²` and `y ∈ K²`;
- `R = K^k`, where `u` may vary by component but `y` and the free `GL_2(K)`
maps are common to all components.

It proves a sharp component threshold for every finite field `K = F_q`. For
`k ≤ q`, every invertible target has `cost = δ ≤ 2`. For `k ≥ q+1`, there is a
target with `cost = 3` and `δ = 2`.

The sharp example comes from a quadratic extension `L = K[X]/(h)`: the
components are multiplication by one representative of each of the `q+1`
`K`-lines of `L`. #4334 writes the proof for every finite field, but its
software witnesses cover only prime fields. Its README says it does not
"claim an extension-field software census".

## Results

For `F_4`, `F_8`, `F_9`, `F_16`, `F_25` and `F_27`, built from irreducible
polynomials found by search, this package builds #4334's target with `q+1`
components and checks:

| Check | Result, every field |
| --- | --- |
| Each input line `t` is sent onto every line of `P¹(K)` exactly once | holds |
| No common pivot: every `(φ, t)` pair is killed by some component, over all `(q+1)²` pairs | holds, so `cost > 2` by #4334's criterion |
| #4334's Section 3 word `[[1,0],[r,1]]·[[1,b],[0,D]]·[[e,0],[f,1]]` reproduces each component | holds, so `cost ≤ 3` |
| `δ = min_T dim((MT − I)K²)` over every free `T ∈ GL_2(K)` | `δ = 2` |
| `k = q` side: 300 random invertible targets with `q` components have a common pivot | holds |

**F4 without the criterion.** An exhaustive search over every free `S`, every
pair of right-vector lines and every left vector finds **no word with two
paid factors** for the five-component target. It does not use #4334's pivot
criterion.

**Control.** The same search finds a two-factor word once one component is
dropped, which is the `k = q` case.

## Method and independence

- Field arithmetic is built here: `F_(p^k)` as `F_p[x]/(f)`, with `f` found
by search and field tables checked.
- The irreducible quadratic `h` over `K` is also found by search.
- Nothing is imported from #4334. Its prime-field oracle and BFS are not used.

## Not covered

- The written proof for every finite field, which this corroborates on six
fields and does not replace.
- Singular targets and general commutative algebras.
- Any native caller or invoice.

## Reproduce

```sh
python3.12 -B research/right-vector-extension-fields/verify.py
```

It prints `PASS_RIGHT_VECTOR_EXTENSION_FIELDS` in about 90 seconds, using only
the standard library. Most of the time goes to the `δ` check over `GL_2(F_27)`,
which has 511,056 elements.

## Open next questions

None from this check.

## Credit

The theorem, the construction and the three-factor word are ToikY's (#4334),
answering Nick Petalas's #4276 and building on Wentao Li's #4099 and #2513.
Prepared by Ryanson Jonathan with substantial Claude Code (Claude Opus 5.5)
assistance. Apache-2.0.
18 changes: 18 additions & 0 deletions research/right-vector-extension-fields/SOURCES.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"schema_version": 1,
"base_commit": "12fa8c5c844be21bfefb38a19503fbd867a11244",
"files": [
{
"path": "certificates/selected-result.json",
"usage": "provenance",
"git_blob": "b1fea0c94436b236cc2b7d41a7be032811b94c81",
"sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129"
},
{
"path": "docs/research/agent-task-catalog.json",
"usage": "provenance",
"git_blob": "64bfc5af6709ed9811171e0a2108f05e1219cb65",
"sha256": "352a6184713b8843d96fd2c2071eb7aeaa655906b7c51d45ad444912666c8a96"
}
]
}
58 changes: 58 additions & 0 deletions research/right-vector-extension-fields/TASK.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"schema_version": 1,
"task_id": "bit-new-register-model",
"priority_revision": 7,
"base_commit": "12fa8c5c844be21bfefb38a19503fbd867a11244",
"original_card": {
"id": "bit-new-register-model",
"question": "Can an explicitly larger or nonabelian register model escape the scoped three-register obstruction?",
"starting_points": [
"docs/research/research-family-status.md",
"research/bit-three-register-lower-bound/README.md",
"certificates/selected-result.json",
"research/bit-gl3-mixed-targets-length10/README.md",
"docs/research/community-efficient1000-review.md"
],
"methods": [
"Construct the smallest exact identity in a newly specified legal operation alphabet.",
"Derive a target-specific relaxation bound for that same explicit alphabet."
],
"acceptance_gate": "Name the changed hypothesis, all counted roles and a uniform identity; finite column tests alone do not certify it. A scoped local result may be retained without a complete supplier. Expanding it into further construction rounds requires the family-level budget and obligation gate in research-family-status.md; an optimistic passing relaxation alone is not acceptance.",
"first_step": {
"command": [
"python3",
"-B",
"scripts/research_baseline.py"
],
"expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY",
"inspect": "Read Model section 1 of the three-register bound and identify the exact excluded free operations.",
"scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay."
},
"first_experiment": "First compare the alphabet, role count and length with the fully replayed #1974 census and #2027 mixed-root tariff. Identify a changed premise and a legal native implementation; then price one smallest completed instance before searching larger words.",
"bottleneck_link": "A small-width completed saving changes the bit primitive; a finite-address identity alone is insufficient.",
"allowed_variations": [
"Choose a fixed larger register count or a specified nonabelian operation family."
],
"scope_change_triggers": [
"Remaining inside the already-excluded three-register abelian model.",
"Repeating the two-register GL3 census or a covered three-register length without changing a hypothesis; a formal group-algebra word without native conversion is a partial result."
],
"overlap_terms": [
"three-register",
"nonabelian",
"group algebra"
]
},
"scope_status": "refined",
"actual_scope": "Independently check #4334's quadratic-extension sharpness construction over six non-prime fields, which its software does not cover, and over F4 confirm cost > 2 by exhaustive search without its criterion.",
"scope_change_reason": "#4334 proves the all-finite-field threshold in writing but states that its software covers only prime fields; extension-field coverage is the explicit gap.",
"bottleneck_link": "The right-vector model's threshold decides when commutative products can avoid a third paid factor in the new register model.",
"budget_minutes": 25,
"stop_rule": "Stop once every listed field passes or one fails.",
"outcome": "completed",
"evidence": "verify.py: over F4, F8, F9, F16, F25, F27 the q+1 Singer components map every line onto P^1 once; no common pivot over all (q+1)^2 pairs; #4334's three-factor word reproduces every component; delta = 2 over every free T; k = q random targets have a common pivot; over F4 an exhaustive two-factor search finds no word, and finds one when a component is dropped.",
"author": "Ryanson Jonathan, with Claude Code (Claude Opus 5.5) assistance",
"ai_assistance": "Substantial Claude Code (Claude Opus 5.5) assistance in reading, verifier implementation and writing; no independent human or proof-kernel review.",
"open_questions": [],
"no_open_questions_reason": "Every field passes; the all-field statement rests on #4334's written proof."
}
18 changes: 18 additions & 0 deletions research/right-vector-extension-fields/VERIFY.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"schema_version": 1,
"status": "ready",
"python": "3.12",
"requirements": [],
"inputs": [],
"commands": [
{
"argv": [
"{python}",
"-B",
"{package}/verify.py"
],
"timeout_seconds": 300,
"checks": "GF(p^k) construction and field tables; irreducible quadratic by search; Singer components invertible and line-transitive; no common pivot; three-factor word per component; delta = 2 over GL_2(K); k = q random common-pivot corroboration; F4 exhaustive two-factor search with a dropped-component control."
}
]
}
207 changes: 207 additions & 0 deletions research/right-vector-extension-fields/verify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
"""#4334's sharp right-vector threshold, checked over extension fields F_4, F_8, F_9, F_16, F_25, F_27.

Model (#4334): paid factors I + u y^T with u in R^2, R = K^k, and y in K^2 common to all components;
GL_2(K) free and common. For each q this builds #4334's quadratic-extension target (multiplication by
one representative of each K-line of L = K[X]/(h), h irreducible) and checks: no common pivot phi, t;
#4334's explicit three-factor word reproduces every component; delta = 2 over all free T. Over F_4 it
also shows by exhaustive search that no word with two paid factors exists, without the criterion.
Standard library only; no code from #4334.
Ryanson Jonathan with Claude Code (Claude Opus 5.5) assistance. Apache-2.0.
"""
from itertools import product
import json
import random
import sys

FIELDS = [(2, 2), (2, 3), (3, 2), (2, 4), (5, 2), (3, 3)]


def need(condition, message):
if not condition:
raise AssertionError(message)


class GF:
"""F_(p^k) as F_p[x]/(f), elements encoded as integers in base p"""

def __init__(self, p, k):
self.p, self.k, self.q = p, k, p ** k
for tail in product(range(p), repeat=k):
f = list(tail) + [1]
self.f = f
table = [[self._mul(a, b) for b in range(self.q)] for a in range(self.q)]
if all(any(table[a][b] == 1 for b in range(1, self.q)) for a in range(1, self.q)):
self.M = table
break
self.A = [[self._enc([(x + y) % p for x, y in zip(self._dec(a), self._dec(b))]) for b in range(self.q)] for a in range(self.q)]
self.neg = [next(b for b in range(self.q) if self.A[a][b] == 0) for a in range(self.q)]
self.inv = [None] + [next(b for b in range(1, self.q) if self.M[a][b] == 1) for a in range(1, self.q)]

def _dec(self, a):
return [(a // self.p ** i) % self.p for i in range(self.k)]

def _enc(self, v):
return sum(c * self.p ** i for i, c in enumerate(v))

def _mul(self, a, b):
x, y, k, p = self._dec(a), self._dec(b), self.k, self.p
r = [0] * (2 * k - 1)
for i in range(k):
for j in range(k):
r[i + j] = (r[i + j] + x[i] * y[j]) % p
for d in range(2 * k - 2, k - 1, -1):
c = r[d]
if c:
for i in range(k + 1):
r[d - k + i] = (r[d - k + i] - c * self.f[i]) % p
return self._enc(r[:k])

def add(self, a, b):
return self.A[a][b]

def mul(self, a, b):
return self.M[a][b]

def sub(self, a, b):
return self.A[a][self.neg[b]]


def mm(K, x, y):
return tuple(tuple(K.add(K.mul(x[i][0], y[0][j]), K.mul(x[i][1], y[1][j])) for j in range(2)) for i in range(2))


def mv(K, x, v):
return tuple(K.add(K.mul(x[i][0], v[0]), K.mul(x[i][1], v[1])) for i in range(2))


def det(K, x):
return K.sub(K.mul(x[0][0], x[1][1]), K.mul(x[0][1], x[1][0]))


def singer_target(K):
"""components A_l: multiplication by (1, x) and (0, 1) in L = K[X]/(X^2 + bX + c), basis (1, X)"""
q = K.q
b, c = next((b, c) for b in range(q) for c in range(q)
if all(K.add(K.add(K.mul(x, x), K.mul(b, x)), c) for x in range(q)))
# X * X = -bX - c; multiplication by u0 + u1 X sends 1 -> (u0, u1), X -> (-c u1, u0 - b u1)
comps = []
for u0, u1 in [(1, x) for x in range(q)] + [(0, 1)]:
comps.append(((u0, K.neg[K.mul(c, u1)]), (u1, K.sub(u0, K.mul(b, u1)))))
return comps


def points(K):
return [(1, x) for x in range(K.q)] + [(0, 1)]


def line(K, v):
"""normalized representative of the K-line through a nonzero vector"""
s = K.inv[v[0]] if v[0] else K.inv[v[1]]
return (K.mul(s, v[0]), K.mul(s, v[1]))


def three_factor_word(K, M):
"""#4334 Section 3, componentwise: M = [[1,0],[r,1]] [[1,b],[0,D]] [[e,0],[f,1]]"""
(a, b), (c, d) = M
r = 0 if d else 1
D = K.sub(d, K.mul(r, b))
f = K.mul(K.inv[D], K.sub(c, K.mul(r, a)))
e = K.sub(a, K.mul(b, f))
return mm(K, mm(K, ((1, 0), (r, 1)), ((1, b), (0, D))), ((e, 0), (f, 1)))


def rank_stack(K, rows):
rows, rank = [list(r) for r in rows], 0
for col in range(2):
piv = next((i for i in range(rank, len(rows)) if rows[i][col]), None)
if piv is None:
continue
rows[rank], rows[piv] = rows[piv], rows[rank]
iv = K.inv[rows[rank][col]]
for i in range(len(rows)):
if i != rank and rows[i][col]:
fct = K.mul(rows[i][col], iv)
rows[i] = [K.sub(x, K.mul(fct, y)) for x, y in zip(rows[i], rows[rank])]
rank += 1
return rank


def gl2(K):
rng = range(K.q)
return [((a, b), (c, d)) for a, b, c, d in product(rng, rng, rng, rng) if det(K, ((a, b), (c, d)))]


def two_factor_exists(K, comps):
"""exhaustive: M_i S^-1 = (I + u1_i y1^T)(I + u2_i y2^T) for one S, y1, y2 and some u1_i, u2_i"""
I = ((1, 0), (0, 1))
vecs = list(product(range(K.q), repeat=2))
ys = points(K)
for S in gl2(K):
dS = K.inv[det(K, S)]
Sinv = ((K.mul(S[1][1], dS), K.neg[K.mul(S[0][1], dS)]), (K.neg[K.mul(S[1][0], dS)], K.mul(S[0][0], dS)))
targets = [mm(K, Mi, Sinv) for Mi in comps]
for y1 in ys:
for y2 in ys:
def ok(X):
for u2 in vecs:
F2 = ((K.add(1, K.mul(u2[0], y2[0])), K.mul(u2[0], y2[1])), (K.mul(u2[1], y2[0]), K.add(1, K.mul(u2[1], y2[1]))))
# need X F2^-1 - I = u1 y1^T, a rank <= 1 matrix with row space in span(y1)
dF = det(K, F2)
if not dF:
continue
iv = K.inv[dF]
F2i = ((K.mul(F2[1][1], iv), K.neg[K.mul(F2[0][1], iv)]), (K.neg[K.mul(F2[1][0], iv)], K.mul(F2[0][0], iv)))
Z = mm(K, X, F2i)
Z = ((K.sub(Z[0][0], 1), Z[0][1]), (Z[1][0], K.sub(Z[1][1], 1)))
if all(K.sub(K.mul(Z[i][0], y1[1]), K.mul(Z[i][1], y1[0])) == 0 for i in range(2)):
return True
return False
if all(ok(X) for X in targets):
return True
return False


def main():
out = {}
rng = random.Random(4334)
for p, k in FIELDS:
K = GF(p, k)
q = K.q
comps = singer_target(K)
need(len(comps) == q + 1 and all(det(K, A) for A in comps), f"q={q}: q+1 invertible components")
P = points(K)
# each input line is sent onto every line exactly once
for t in P:
need(sorted(line(K, mv(K, A, t)) for A in comps) == sorted(P), f"q={q}: images of t={t} cover P^1")
# hence no common pivot: every (phi, t) is killed by some component
for phi in P:
for t in P:
need(any(K.add(K.mul(phi[0], v[0]), K.mul(phi[1], v[1])) == 0 for v in (mv(K, A, t) for A in comps)),
f"q={q}: common pivot at phi={phi}, t={t}")
# #4334's three-factor word, every component
need(all(three_factor_word(K, A) == A for A in comps), f"q={q}: three-factor word")
# delta = 2: min over free T of dim((M T - I) K^2) on the stacked components
G = gl2(K)
need(min(rank_stack(K, [row for A in comps for row in ((lambda X: ((K.sub(X[0][0], 1), X[0][1]), (X[1][0], K.sub(X[1][1], 1))))(mm(K, A, T)))])
for T in G) == 2, f"q={q}: delta = 2")
# the other side of the threshold: k = q random invertible components always share a pivot
for _ in range(300):
sample = [rng.choice(G) for _ in range(q)]
need(any(all(K.add(K.mul(phi[0], v[0]), K.mul(phi[1], v[1])) for v in (mv(K, A, t) for A in sample))
for phi in P for t in P), f"q={q}: k = q sample has a common pivot")
out[str(q)] = {"components": q + 1, "gl2": len(G)}
# direct exhaustive confirmation over F_4, without the pivot criterion: cost > 2
K4 = GF(2, 2)
need(not two_factor_exists(K4, singer_target(K4)), "F_4: no two-paid-factor word exists")
need(two_factor_exists(K4, singer_target(K4)[:4]), "control: dropping one component makes two factors suffice")
print(json.dumps({
"status": "PASS_RIGHT_VECTOR_EXTENSION_FIELDS",
"fields": out,
"f4_two_factor_exhaustive": "no word",
"new_kappa_claimed": False,
}, indent=1))


if __name__ == "__main__":
sys.exit(main())