FSO-Genesis-Space / fiber.py
LOOFYYLO's picture
Upload folder using huggingface_hub
2c54126 verified
Raw
History Blame Contribute Delete
8.55 kB
"""
fiber.py — Fiber decomposition of the Claude's Cycles problem.
KEY INSIGHT: The map f(i,j,k) = (i+j+k) mod m stratifies the digraph
into m "fiber" layers F_0, …, F_{m-1}, each of size m².
Every arc goes from F_s to F_{s+1 mod m}.
In fiber coordinates (i,j) with k = (s-i-j) mod m, the 3 arc types become:
arc 0: (i,j) in F_s → (i+1, j) in F_{s+1} [shift (1,0)]
arc 1: (i,j) in F_s → (i, j+1) in F_{s+1} [shift (0,1)]
arc 2: (i,j) in F_s → (i, j) in F_{s+1} [shift (0,0) — identity]
A "column-uniform" sigma depends only on (s, j) — not on i.
At each level s, column j gets a fixed permutation: perm[j] = [arc→cycle].
The COMPOSED permutation after all m levels:
Q_c(i,j) = (i + b_c(j), j + r_c) mod m
where r_c = total j-increment for cycle c, b_c(j) = total i-increment.
Single m²-cycle condition: gcd(r_c, m) = 1 AND gcd(Σ b_c(j), m) = 1
"""
from __future__ import annotations
from typing import Dict, List, Optional, Tuple, Callable
from math import gcd
from itertools import permutations as _iperms
# 2D arc shifts in fiber space
FIBER_SHIFTS: Tuple[Tuple[int,int],...] = (
(1, 0), # arc 0: incr i
(0, 1), # arc 1: incr j
(0, 0), # arc 2: identity
)
FiberPos = Tuple[int, int] # (i, j) in fiber space
LevelTable = Dict[int, List[int]] # j → perm (for one fiber level)
SigmaTable = List[LevelTable] # indexed by s=0..m-1
QFunc = Dict[FiberPos, FiberPos] # composed permutation
# --------------------------------------------------------------------------- #
# Level table validity
# --------------------------------------------------------------------------- #
def is_bijective_level(level: LevelTable, m: int) -> bool:
"""
Check that at level s, each cycle c induces a bijection on Z_m².
For cycle c: the set of targets {(i+di, j+dj) : j in Z_m, i in Z_m}
must be exactly Z_m² (all m² positions hit).
"""
for c in range(3):
targets = set()
for j in range(m):
arc_type = level[j].index(c)
di, dj = FIBER_SHIFTS[arc_type]
for i in range(m):
targets.add(((i+di) % m, (j+dj) % m))
if len(targets) != m * m:
return False
return True
def all_valid_levels(m: int) -> List[LevelTable]:
"""Enumerate all column-uniform level assignments that are bijective."""
result = []
for combo in _product(_ALL_PERMS, repeat=m):
level = {j: list(combo[j]) for j in range(m)}
if is_bijective_level(level, m):
result.append(level)
return result
# Lazy import helper
from itertools import product as _product
_ALL_PERMS = list(_iperms(range(3)))
# --------------------------------------------------------------------------- #
# Q composition
# --------------------------------------------------------------------------- #
def compose_levels(sigma_table: SigmaTable, m: int) -> List[QFunc]:
"""
Compose all m fiber-level functions to get Q_0, Q_1, Q_2.
Returns 3 permutations on Z_m² (as dicts).
"""
Qs: List[QFunc] = [{} for _ in range(3)]
for i0 in range(m):
for j0 in range(m):
pos = [[i0, j0], [i0, j0], [i0, j0]] # pos[c] = current (i,j)
for s in range(m):
level = sigma_table[s]
for c in range(3):
cj = pos[c][1]
perm = level[cj]
arc_type = perm.index(c)
di, dj = FIBER_SHIFTS[arc_type]
pos[c][0] = (pos[c][0] + di) % m
pos[c][1] = (pos[c][1] + dj) % m
for c in range(3):
Qs[c][(i0, j0)] = (pos[c][0], pos[c][1])
return Qs
def is_single_q_cycle(Q: QFunc, m: int) -> bool:
"""Check that permutation Q on Z_m² is a single m²-cycle."""
n = m * m
visited: set = set()
cur: FiberPos = (0, 0)
while cur not in visited:
visited.add(cur)
cur = Q[cur]
return len(visited) == n and cur == (0, 0)
# --------------------------------------------------------------------------- #
# Lift sigma_table → SigmaFn (3D)
# --------------------------------------------------------------------------- #
def table_to_sigma_fn(sigma_table: SigmaTable, m: int):
"""
Convert a SigmaTable (indexed by [s][j]) into a 3D sigma function
sigma(i, j, k) that can be used with core.verify_sigma.
The key: depends only on s=(i+j+k)%m and j.
"""
def sigma(i: int, j: int, k: int) -> List[int]:
s = (i + j + k) % m
return list(sigma_table[s][j])
return sigma
# --------------------------------------------------------------------------- #
# Q structure analysis
# --------------------------------------------------------------------------- #
def analyze_Q_structure(Qs: List[QFunc], m: int) -> dict:
"""
Analyze whether Q_c has the twisted translation form:
Q_c(i,j) = (i + b_c(j), j + r_c) mod m
Returns a dict with r_c, b_c, is_twisted, single_cycle per cycle.
"""
result = {"cycles": [], "all_twisted": True, "all_single": True}
for c in range(3):
Q = Qs[c]
# Detect r_c: j-increment should be constant across all starting positions
r_c_vals = set((Q[(i,j)][1] - j) % m for i in range(m) for j in range(m))
is_uniform_r = (len(r_c_vals) == 1)
r_c = r_c_vals.pop() if is_uniform_r else None
# Detect b_c(j): i-offset at fixed starting i=0
if is_uniform_r:
b_c = [(Q[(0,j)][0] - 0) % m for j in range(m)]
# Verify b_c is shift-invariant: Q(i,j)[0] = i + b_c(j) mod m
is_twisted = all(Q[(i,j)][0] == (i + b_c[j]) % m
for i in range(m) for j in range(m))
else:
b_c = None
is_twisted = False
single = is_single_q_cycle(Q, m)
cycle_info = {
"cycle": c,
"r_c": r_c,
"b_c": b_c,
"is_twisted": is_twisted,
"is_single_cycle": single,
"sum_b": (sum(b_c) % m) if b_c else None,
"gcd_r_m": gcd(r_c, m) if r_c is not None else None,
"gcd_sumb_m": gcd(sum(b_c) % m, m) if b_c else None,
}
result["cycles"].append(cycle_info)
if not is_twisted:
result["all_twisted"] = False
if not single:
result["all_single"] = False
if result["all_twisted"]:
r_vals = [info["r_c"] for info in result["cycles"]]
result["sum_r"] = sum(r_vals) % m
result["r_values"] = r_vals
return result
# --------------------------------------------------------------------------- #
# Theorem verification helpers
# --------------------------------------------------------------------------- #
def verify_single_cycle_conditions(r_c: int, b_c: List[int], m: int) -> dict:
"""
Verify the two necessary and sufficient conditions for Q_c to be a
single m²-Hamiltonian cycle.
"""
s_b = sum(b_c) % m
return {
"gcd_r_m": gcd(r_c, m),
"gcd_sumb_m": gcd(s_b, m),
"condition_a": gcd(r_c, m) == 1,
"condition_b": gcd(s_b, m) == 1,
"both_satisfied": gcd(r_c, m) == 1 and gcd(s_b, m) == 1,
}
def even_m_impossibility_check(m: int) -> dict:
"""
Verify the impossibility theorem for even m:
No (r_0,r_1,r_2) with gcd(r_c,m)=1 can sum to m when m is even.
"""
if m % 2 == 0:
# Coprime to even m means ODD
# Sum of 3 odd numbers is ODD ≠ EVEN = m
example_coprime = [r for r in range(m) if gcd(r, m) == 1]
min_sum = sum(sorted(example_coprime)[:3])
return {
"m": m,
"m_is_even": True,
"coprime_elements": example_coprime,
"all_coprime_are_odd": all(r % 2 == 1 for r in example_coprime),
"three_odds_sum_is_odd": True,
"needed_sum": m,
"impossibility_proved": True,
"proof": "All r coprime to even m are odd. Sum of 3 odds is odd ≠ m (even).",
}
else:
# For odd m: show valid (r_0,r_1,r_2) exists
valid = [(r0,r1,r2) for r0 in range(m) for r1 in range(m) for r2 in range(m)
if gcd(r0,m)==1 and gcd(r1,m)==1 and gcd(r2,m)==1 and r0+r1+r2==m]
return {
"m": m,
"m_is_even": False,
"impossibility_proved": False,
"valid_r_triples_count": len(valid),
"example": valid[0] if valid else None,
}