mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-07-31 01:25:21 +00:00
- lakefile.lean: register SilverSight.{AngrySphinx,CollatzBraid,GoldenSpiral,GCCL}
- docs/research/: braid group action, iteration DAG/regime, Sidon
preservation/creation, unified CRT-torus DAG notes
- docs/diagrams/: DAG + heatmap + 8-strand search JSON/dot outputs
- formal/CoreFormalism/StrandCapacityBound.lean: capacity bound (passes
hardened anti-smuggle --ci)
- scripts/, python/: braid word solver, collapse/DAG search + tuning,
heatmap gen, YB search/verification, wrapping verifier
- .gitignore: exclude rust/**/target and coq compiled artifacts
(*.vo/*.vok/*.vos/*.glob/*.aux) that were polluting the tree
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
202 lines
6.5 KiB
Python
202 lines
6.5 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Multi-Strand Braid Word Solver.
|
||
|
||
Full 16-modulus chiral torus: up to 8 strands, each with (L_id, L_ref).
|
||
Generates multi-strand braid words with coprimality constraints.
|
||
"""
|
||
import sys, math, itertools, random
|
||
from typing import List, Tuple
|
||
sys.path.insert(0, '/home/allaun/SilverSight/scripts')
|
||
from verify_wrapping import is_sidon
|
||
|
||
# ---------- Coprime CRT ----------
|
||
|
||
def pairwise_coprime(mods: List[int]) -> bool:
|
||
for i in range(len(mods)):
|
||
for j in range(i+1, len(mods)):
|
||
if math.gcd(mods[i], mods[j]) != 1:
|
||
return False
|
||
return True
|
||
|
||
def crt_lift(residues: List[int], moduli: List[int]) -> int:
|
||
assert pairwise_coprime(moduli), f"not coprime: {moduli}"
|
||
x = residues[0]
|
||
m = moduli[0]
|
||
for i in range(1, len(moduli)):
|
||
inv = pow(m % moduli[i], -1, moduli[i])
|
||
t = ((residues[i] - x) * inv) % moduli[i]
|
||
x += t * m
|
||
m *= moduli[i]
|
||
return x
|
||
|
||
def F_multi(a: int, S: int, moduli: List[int]) -> int:
|
||
residues = [a % moduli[0]] + [(S - a) % Li for Li in moduli[1:]]
|
||
return crt_lift(residues, moduli)
|
||
|
||
def moduli_from_pairs(pairs: List[Tuple[int,int]]) -> List[int]:
|
||
return [v for p in pairs for v in p]
|
||
|
||
# ---------- Generate valid coprime configurations ----------
|
||
|
||
PRIME_POOL = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53]
|
||
|
||
def coprime_pairs(count: int, pool: List[int] = None) -> List[Tuple[int,int]]:
|
||
"""Generate `count` coprime pairs using distinct primes."""
|
||
if pool is None:
|
||
pool = PRIME_POOL
|
||
used = set()
|
||
pairs = []
|
||
p_idx = 0
|
||
for _ in range(count):
|
||
p1, p2 = pool[p_idx], pool[p_idx+1]
|
||
pairs.append((p1, p2))
|
||
p_idx += 2
|
||
return pairs
|
||
|
||
def cross(pairs: List[Tuple[int,int]], strand: int, over: bool) -> List[Tuple]:
|
||
"""Cross strand `strand` (over or under), return new config or None."""
|
||
new = [p for p in pairs]
|
||
Li, Lr = new[strand]
|
||
if over:
|
||
new[strand] = (Li + 2, max(Lr - 1, 2))
|
||
else:
|
||
new[strand] = (max(Li - 1, 2), Lr + 2)
|
||
mods = moduli_from_pairs(new)
|
||
return new if pairwise_coprime(mods) else None
|
||
|
||
def braid_word(pairs_seq: List[List[Tuple]]) -> str:
|
||
"""Build braid word from a sequence of configurations."""
|
||
parts = []
|
||
for i in range(1, len(pairs_seq)):
|
||
prev, curr = pairs_seq[i-1], pairs_seq[i]
|
||
for s in range(len(curr)):
|
||
if curr[s] == prev[s]:
|
||
continue
|
||
Li, Lr = curr[s]
|
||
typ = "⁺" if Li > Lr else "⁻"
|
||
parts.append(f"σ_{s+1}{typ}")
|
||
return " · ".join(parts) if parts else "1"
|
||
|
||
# ---------- Multi-strand Sidon search ----------
|
||
|
||
def multi_search(A0: List[int], S: int, num_strands: int = 2, max_steps: int = 3):
|
||
"""BFS for multi-strand braid words to Sidon."""
|
||
init = coprime_pairs(num_strands)
|
||
queue = [(init, 0, A0, [init])]
|
||
visited = set()
|
||
results = []
|
||
|
||
while queue and len(results) < 20:
|
||
pairs, depth, A, path = queue.pop(0)
|
||
key = (tuple(pairs), tuple(A))
|
||
if key in visited: continue
|
||
visited.add(key)
|
||
|
||
mods = moduli_from_pairs(pairs)
|
||
M = 1
|
||
for m in mods: M *= m
|
||
maxA = max(A)
|
||
|
||
if M > maxA:
|
||
FA = [F_multi(a, S, mods) for a in A]
|
||
if is_sidon(FA):
|
||
results.append({
|
||
'word': braid_word(path),
|
||
'steps': depth, 'FA': FA, 'M': M,
|
||
'path': path
|
||
})
|
||
continue
|
||
|
||
if depth >= max_steps:
|
||
continue
|
||
|
||
for s in range(num_strands):
|
||
for over in [True, False]:
|
||
crossed = cross(pairs, s, over)
|
||
if crossed is None:
|
||
continue
|
||
mods2 = moduli_from_pairs(crossed)
|
||
new_A = [F_multi(a, S, mods2) for a in A]
|
||
queue.append((crossed, depth+1, new_A, path + [crossed]))
|
||
|
||
return results
|
||
|
||
# ---------- Braid axiom tests ----------
|
||
|
||
def test_involution():
|
||
"""σᵢ² = id: two over-crossings should return to original."""
|
||
print("=" * 60)
|
||
print("BRAID AXIOM TESTS")
|
||
print("=" * 60)
|
||
|
||
A0, S = [1, 2, 5, 6], 7
|
||
init = coprime_pairs(2) # [(2,3), (5,7)]
|
||
|
||
# σ₁ over then σ₁ over
|
||
s1 = cross(init, 0, True)
|
||
s1a = cross(s1, 0, True) if s1 else None
|
||
print(f"\n σ₁²: {(2,3)} → over→ {s1[0] if s1 else '? ()'}"
|
||
f" → over→ {s1a[0] if s1a else '? ()'}"
|
||
f" back to initial: {s1a == init if s1a else False}")
|
||
|
||
def test_far_commute():
|
||
"""σᵢσⱼ = σⱼσᵢ for |i−j| ≥ 2: strand 1 and 3 commute."""
|
||
A0, S = [1, 2, 5, 6], 7
|
||
init = coprime_pairs(3)
|
||
print(f"\n σ₁σ₃ vs σ₃σ₁ on {init}:")
|
||
|
||
# σ₁ then σ₃
|
||
s1 = cross(init, 0, True)
|
||
s1s3 = cross(s1, 2, False) if s1 else None
|
||
# σ₃ then σ₁
|
||
s3 = cross(init, 2, False)
|
||
s3s1 = cross(s3, 0, True) if s3 else None
|
||
|
||
if s1s3 and s3s1:
|
||
# Same final configuration?
|
||
same = s1s3 == s3s1
|
||
w1 = braid_word([init, s1, s1s3])
|
||
w2 = braid_word([init, s3, s3s1])
|
||
print(f" σ₁σ₃: {w1} → {s1s3}")
|
||
print(f" σ₃σ₁: {w2} → {s3s1}")
|
||
print(f" Same: {same}")
|
||
|
||
def test_single_sidon():
|
||
"""Find single-step Sidon paths for each strand."""
|
||
print("\n" + "=" * 60)
|
||
print("MULTI-STRAND SIDON SEARCH (2 strands)")
|
||
print("=" * 60)
|
||
A0, S = [1, 2, 5, 6], 7
|
||
results = multi_search(A0, S, num_strands=2, max_steps=2)
|
||
print(f" Results: {len(results)}")
|
||
for r in sorted(results, key=lambda x: x['steps'])[:5]:
|
||
print(f" Word: {r['word']:20s} Steps={r['steps']} M={r['M']:4d} FA={r['FA']}")
|
||
|
||
def test_strand_interaction():
|
||
"""Test 2-strand configurations produce distinct results."""
|
||
print("\n" + "=" * 60)
|
||
print("STRAND INTERACTION")
|
||
print("=" * 60)
|
||
|
||
A0, S = [1, 2, 5, 6], 7
|
||
configs = [
|
||
([(2, 3), (5, 7)], "under, under"),
|
||
([(4, 2), (5, 7)], "over on 1, under on 2"), # but gcd(4,2)=2!
|
||
]
|
||
|
||
for pairs, desc in configs:
|
||
mods = moduli_from_pairs(pairs)
|
||
if not pairwise_coprime(mods):
|
||
continue
|
||
FA = [F_multi(a, S, mods) for a in A0]
|
||
M = 1
|
||
for m in mods: M *= m
|
||
sidon = is_sidon(FA)
|
||
print(f" {desc:30s} mods={mods} M={M:3d} Sidon={sidon} FA={FA}")
|
||
|
||
if __name__ == "__main__":
|
||
test_involution()
|
||
test_far_commute()
|
||
test_single_sidon()
|
||
test_strand_interaction()
|