Research source · python
check_b3_hurwitz_obstruction.py
site/public/research-artifacts/planar-factorization-receipts/check_b3_hurwitz_obstruction.py
125 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: c0165498060cbd478afedad6288c0b52edff3235e5a7fbcac1f3b4e53709fcb7
#!/usr/bin/env python3
"""Replay the exact B3 finite-quotient Hurwitz obstruction.
This verifier checks the displayed witness. It does not search for examples or
decide Hurwitz equivalence in B3.
"""
from collections import deque
import json
I = (1, 0, 0, 1)
X = (1, 1, 0, 1)
Y = (1, 0, -1, 1)
def mm(a, b):
return (
a[0] * b[0] + a[1] * b[2],
a[0] * b[1] + a[1] * b[3],
a[2] * b[0] + a[3] * b[2],
a[2] * b[1] + a[3] * b[3],
)
def inverse(a):
return (a[3], -a[1], -a[2], a[0])
def power(a, n):
if n < 0:
return power(inverse(a), -n)
result = I
while n:
if n & 1:
result = mm(result, a)
a = mm(a, a)
n //= 2
return result
def conjugate(g, a):
return mm(mm(g, a), inverse(g))
def product(items):
result = I
for item in items:
result = mm(result, item)
return result
def mod2(a):
return tuple(entry % 2 for entry in a)
def generated_subgroup(generators):
generators = [mod2(g) for g in generators]
seen = {I}
queue = deque([I])
while queue:
current = queue.popleft()
for generator in generators:
nxt = mod2(mm(current, generator))
if nxt not in seen:
seen.add(nxt)
queue.append(nxt)
return seen
def hurwitz(items, index):
items = list(items)
a, b = items[index], items[index + 1]
items[index : index + 2] = [b, mm(mm(inverse(b), a), b)]
return tuple(items)
def inverse_hurwitz(items, index):
items = list(items)
a, b = items[index], items[index + 1]
items[index : index + 2] = [mm(mm(a, b), inverse(a)), a]
return tuple(items)
def finite_orbit(items):
start = tuple(mod2(g) for g in items)
seen = {start}
queue = deque([start])
while queue:
current = queue.popleft()
for index in range(len(current) - 1):
for nxt in (hurwitz(current, index), inverse_hurwitz(current, index)):
nxt = tuple(mod2(g) for g in nxt)
if nxt not in seen:
seen.add(nxt)
queue.append(nxt)
return seen
def main():
alpha = conjugate(power(X, 2), Y)
beta = conjugate(mm(inverse(Y), X), Y)
a = (alpha, Y, Y)
b = (X, beta, Y)
assert product(a) == product(b)
subgroup_a = generated_subgroup(a)
subgroup_b = generated_subgroup(b)
assert (len(subgroup_a), len(subgroup_b)) == (2, 6)
orbit_a = finite_orbit(a)
orbit_b = finite_orbit(b)
assert (len(orbit_a), len(orbit_b)) == (1, 8)
assert orbit_a.isdisjoint(orbit_b)
print(json.dumps({
"result": "pass",
"common_product_matrix": list(product(a)),
"permutation_subgroup_orders": {"A": 2, "B": 6},
"finite_hurwitz_orbit_sizes": {"A": 1, "B": 8},
"finite_orbits_disjoint": True,
}, indent=2, sort_keys=True))
if __name__ == "__main__":
main()