SilverSight/python/full_chiral_dag.py
allaun 3362d554d1 feat(braid/dag): land untracked research WIP + register 4 formal libs; ignore build artifacts
- 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>
2026-07-03 15:11:37 -05:00

695 lines
25 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""full_chiral_dag.py — CRT Torus Braid DAG with Coprimality Guard.
Combines axis-swap (topology, YB ✓) and adjustment (resource, FA-changing)
into a unified DAG traversal. The Coprimality Guard ensures all 16 moduli
remain pairwise coprime after every crossing.
References:
- docs/crt-torus-embedding.md (core CRT Torus embedding)
- docs/research/unified_crt_torus_dag.md (graded Sidon energy + hierarchy)
- docs/research/braid_group_action.md (dual-model framework)
"""
import math
from typing import List, Optional, Tuple
# ═══════════════════════════════════════════════════════════════
# §1 SIDON CHECK VIA WRAPPING CRITERION
# ═══════════════════════════════════════════════════════════════
# The Sidon creation theorem (docs/research/sidon_preservation_creation.md):
# For A0 ⊆ and CRT embedding F, F(A0) is Sidon iff for EVERY sum
# collision a+b = c+d in A0, the CRT lifts wrap M differently:
# F(a)+F(b) = T + r₁·M, F(c)+F(d) = T + r₂·M, r₁ ≠ r₂
# where wrap indicator r = 1 if F(x)+F(y) ≥ M, else 0.
#
# With L_id-only adjustment and M > 2·max(A0), new collisions cannot
# form (M-difference condition is vacuous). The only question is
# whether the existing collisions break.
def crt_sum(a: int, b: int, pairs: List[Tuple[int, int]], S: int) -> Tuple[int, int]:
"""Compute F(a)+F(b) and its wrap indicator.
Returns (sum, wrap) where wrap = 1 if sum ≥ M, 0 otherwise.
"""
Fa = crt_embed(a, pairs, S)
Fb = crt_embed(b, pairs, S)
total = Fa + Fb
M = math.prod(m for pair in pairs for m in pair)
return (total, 1 if total >= M else 0)
def find_collisions(A0: List[int]) -> List[Tuple[int, int, int, int]]:
"""Find all sum collisions in A0.
Returns list of ((a,b), (c,d), T) where a+b = c+d = T and (a,b) ≠ (c,d).
"""
n = len(A0)
sum_map = {}
collisions = []
for i in range(n):
for j in range(i, n):
s = A0[i] + A0[j]
if s in sum_map:
ci, cj = sum_map[s]
if ci != i or cj != j:
collisions.append((A0[ci], A0[cj], A0[i], A0[j], s))
else:
sum_map[s] = (i, j)
return collisions
def sidon_check(
A0: List[int],
pairs: List[Tuple[int, int]],
S: int,
) -> Tuple[bool, int, float]:
"""Check if F(A0) is Sidon under current moduli.
Returns (is_sidon, broken_count, score).
- is_sidon: True if all collisions broken
- broken_count: how many collisions are broken
- score: 0 if Sidon, else graded residual (lower = closer to Sidon)
"""
collisions = find_collisions(A0)
if not collisions:
return (True, 0, 0.0)
broken = 0
for a, b, c, d, T in collisions:
_, wrap1 = crt_sum(a, b, pairs, S)
_, wrap2 = crt_sum(c, d, pairs, S)
if wrap1 != wrap2:
broken += 1
if broken == len(collisions):
return (True, broken, 0.0)
# Score: fraction of unbroken collisions, scaled to (0, 4].
total = len(collisions)
score = 4.0 * (1.0 - broken / total)
return (False, broken, max(0.0, score))
def sidon_energy(
A0: List[int],
pairs: List[Tuple[int, int]],
S: int,
) -> float:
"""Graded Sidon energy: 0 if Sidon, else ∈ (0, 4] for non-Sidon."""
_, _, score = sidon_check(A0, pairs, S)
return score
# ═══════════════════════════════════════════════════════════════
# §2 CRT EMBEDDING
# ═══════════════════════════════════════════════════════════════
def crt_embed(
a: int,
pairs: List[Tuple[int, int]],
S: int,
) -> int:
"""CRT Torus Embedding F: /M.
Axis 1: a ↦ a mod L₁ (identity)
Axes 2…k: a ↦ S a mod Lᵢ (reflection)
Reconstructs via CRT to produce a unique integer lift in [0, M).
"""
residues = []
moduli = []
for i, (L_id, L_ref) in enumerate(pairs):
moduli.append(L_id)
if i == 0:
residues.append(a % L_id)
else:
residues.append((S - a) % L_id)
moduli.append(L_ref)
residues.append((S - a) % L_ref)
# Iterative CRT
x = residues[0]
M = moduli[0]
for i in range(1, len(moduli)):
m_i = moduli[i]
r_i = residues[i]
# Find k such that x + k·M ≡ r_i (mod m_i)
# k ≡ (r_i x) · M⁻¹ (mod m_i)
inv = pow(M, -1, m_i)
k = ((r_i - x) * inv) % m_i
x = x + k * M
M = M * m_i
return x
def crt_embed_set(
A: List[int],
pairs: List[Tuple[int, int]],
S: int,
) -> List[int]:
"""Apply CRT Torus Embedding F to every element of A."""
return sorted([crt_embed(a, pairs, S) for a in A])
# ═══════════════════════════════════════════════════════════════
# §3 COPRIMALITY GUARD
# ═══════════════════════════════════════════════════════════════
def pairwise_coprime(moduli: List[int]) -> bool:
"""Coprimality Guard: check all moduli are pairwise coprime.
Returns True iff gcd(m_i, m_j) = 1 for all i ≠ j.
This is the CRITICAL invariant: CRT requires pairwise coprime moduli
to guarantee injectivity of the torus embedding F.
Failure mode: adjusting a modulus by ±2 can make it share a factor
with another modulus (e.g., one hits 7, another was already 14).
The guard catches this before it corrupts the node.
"""
n = len(moduli)
for i in range(n):
for j in range(i + 1, n):
if math.gcd(moduli[i], moduli[j]) != 1:
return False
return True
# ═══════════════════════════════════════════════════════════════
# §3 CHIRAL PAIRS — INITIALIZATION
# ═══════════════════════════════════════════════════════════════
def _nth_prime(n: int) -> int:
"""Return the n-th prime (0-indexed), generating on the fly."""
known = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113]
while len(known) <= n:
candidate = known[-1] + 2
while any(candidate % p == 0 for p in known):
candidate += 2
known.append(candidate)
return known[n]
def chiral_pairs(
n_strands: int = 8,
band_gap: int = 30,
base_prime_offset: int = 0,
) -> List[Tuple[int, int]]:
"""Initialize chiral pairs with distinct primes.
Each strand gets an (L_id, L_ref) pair where both are prime.
All 2·n_strands moduli are pairwise coprime by construction.
With L_id-only adjustment (L_ref fixed), the spacing between
L_id and L_ref doesn't restrict capacity — only the Q16_16
bound (32767) and L_id > 1 matter.
Args:
n_strands: number of braid strands
band_gap: (unused with L_id-only adjustment, kept for API compat)
base_prime_offset: starting index into prime sequence
Returns:
List of (L_id, L_ref) pairs, one per strand
"""
pairs = []
idx = base_prime_offset
for _ in range(n_strands):
L_id = _nth_prime(idx); idx += 1
L_ref = _nth_prime(idx); idx += 1
pairs.append((L_id, L_ref))
return pairs
# ═══════════════════════════════════════════════════════════════
# §4 AXIS-SWAP (TOPOLOGY, YB-COMPLIANT)
# ═══════════════════════════════════════════════════════════════
def axis_swap(
pairs: List[Tuple[int, int]],
s: int,
) -> List[Tuple[int, int]]:
"""Swap reflection moduli of adjacent strands s and s+1.
This is the braid generator σ_s acting on the reflection axis only.
The identity moduli are untouched. This is FA-invariant (CRT symmetry)
and satisfies YB, σ²=id, and far commutativity.
Args:
pairs: current list of (L_id, L_ref) per strand
s: strand index (0 ≤ s < len(pairs) 1)
Returns a NEW list with the reflection moduli swapped.
"""
if s < 0 or s >= len(pairs) - 1:
return pairs[:]
new_pairs = list(pairs)
L_id_s, L_ref_s = new_pairs[s]
L_id_s1, L_ref_s1 = new_pairs[s + 1]
new_pairs[s] = (L_id_s, L_ref_s1)
new_pairs[s + 1] = (L_id_s1, L_ref_s)
return new_pairs
# ═══════════════════════════════════════════════════════════════
# §5 ADJUSTMENT (RESOURCE, FA-CHANGING)
# ═══════════════════════════════════════════════════════════════
def adjust(
pairs: List[Tuple[int, int]],
s: int,
direction: str,
) -> Optional[List[Tuple[int, int]]]:
"""Adjust modulus values for strand s — L_id only.
Design finding from Coprimality Guard (full_chiral_dag.py §3):
The original ±2/∓1 adjustment on BOTH moduli breaks within-pair
coprimality after ≤1 crossing (e.g., (13,41)→(15,40) shares
factor 5). Fix: adjust only L_id, keeping L_ref fixed at its
initial prime. This guarantees within-pair coprimality since
gcd(L_id ± 2k, L_ref) = 1 when L_ref is a distinct prime and
doesn't divide the adjusted L_id.
Over: L_id += 2
Under: L_id = 2
Returns a new list of pairs, or None if:
- New modulus ≤ 1 (invalid for CRT)
- Fails the Coprimality Guard (shares factor with another modulus)
"""
if direction not in ('over', 'under'):
raise ValueError(f"Invalid direction: {direction}")
new_pairs = [(a, b) for a, b in pairs]
L_id, L_ref = new_pairs[s]
if direction == 'over':
new_id = L_id + 2
else:
new_id = L_id - 2
if new_id <= 1:
return None # modulus invalid
new_pairs[s] = (new_id, L_ref)
moduli = [m for pair in new_pairs for m in pair]
if not pairwise_coprime(moduli):
return None
return new_pairs
# ═══════════════════════════════════════════════════════════════
# §6 COUPLED CROSSING
# ═══════════════════════════════════════════════════════════════
def coupled_crossing(
pairs: List[Tuple[int, int]],
s: int,
direction: str,
A0: List[int],
S: int,
) -> Optional[Tuple[List[Tuple[int, int]], float]]:
"""One coupled crossing: axis-swap → adjust → verify.
Returns (new_pairs, new_energy) if successful, None if coprimality fails.
"""
swapped = axis_swap(pairs, s)
adjusted = adjust(swapped, s, direction)
if adjusted is None:
return None
E_new = sidon_energy(A0, adjusted, S)
if not pairwise_coprime([m for pair in adjusted for m in pair]):
return None
return (adjusted, E_new)
# ═══════════════════════════════════════════════════════════════
# §7 DIRECTIONAL CAPACITY
# ═══════════════════════════════════════════════════════════════
def compute_directional_capacities(
pairs: List[Tuple[int, int]],
max_across: int = 15,
) -> List[int]:
"""Compute directional capacities per strand, packed into 4-bit word.
L_id-only adjustment: 2 directions (over/under).
Bits 0-1: cap_over (over-crossings, limited by Q16_16 bound 32767)
Bits 2-3: cap_under (under-crossings, limited by L_id > 1)
Each capacity capped at 3 (2-bit range).
Args:
pairs: current chiral pairs
max_across: maximum crossings used for normalization
Returns:
Packed capacities per strand, as list of ints
"""
Q16_BOUND = 32767
capacities = []
for L_id, L_ref in pairs:
cap_over = min(3, (Q16_BOUND - L_id) // 2)
cap_under = min(3, (L_id - 3) // 2) if L_id > 3 else 0
packed = cap_over | (cap_under << 2)
capacities.append(packed)
return capacities
def dag_capacity(capacities: List[int], direction: str) -> int:
"""DAG-level capacity: min of strand capacities in this direction."""
shift = 0 if direction == 'over' else 2
vals = [(c >> shift) & 3 for c in capacities]
return min(vals)
# ═══════════════════════════════════════════════════════════════
# §8 DAG NODE
# ═══════════════════════════════════════════════════════════════
class DAGNode:
"""A node in the CRT torus braid DAG.
Attributes:
pairs: chiral pairs (L_id, L_ref) per strand
A: current integer set (CRT lifts)
M: product of all moduli
energy: SidonEnergy of this state
capacities: 4-directional capacities (8-bit per strand)
braid_word: list of (strand, direction) crossings from root
depth: number of crossings from root
children: child node references (by moduli hash)
"""
__slots__ = (
'pairs', 'A0', 'S', 'M', 'energy', 'capacities',
'braid_word', 'depth', 'children', 'is_sidon', 'broken',
)
def __init__(
self,
pairs: List[Tuple[int, int]],
A0: List[int],
S: int,
braid_word: Optional[List[Tuple[int, str]]] = None,
depth: int = 0,
):
self.pairs = pairs
self.A0 = A0
self.S = S
self.M = math.prod(m for pair in pairs for m in pair)
sidon_ok, self.broken, self.energy = sidon_check(A0, pairs, S)
self.is_sidon = sidon_ok
self.capacities = compute_directional_capacities(pairs)
self.braid_word = braid_word or []
self.depth = depth
self.children = []
@property
def moduli(self) -> List[int]:
return [m for pair in self.pairs for m in pair]
def modulus_hash(self) -> int:
h = 0
for m in self.moduli:
h = h * 31 + m
return h
def __repr__(self) -> str:
return (
f"DAGNode(depth={self.depth}, M={self.M}, "
f"={self.energy:.4f}, "
f"braid={self.braid_word})"
)
# ═══════════════════════════════════════════════════════════════
# §9 CHIRAL DAG TRAVERSAL
# ═══════════════════════════════════════════════════════════════
EPSILON = 1e-9
class ChiralDAG:
"""CRT Torus Braid DAG with unified axis-swap × adjustment traversal.
Usage:
dag = ChiralDAG(A0=[1, 2, 5, 6], S=7, n_strands=3)
dag.build(max_steps=8)
print(dag.summary())
"""
def __init__(
self,
A0: List[int],
S: int,
n_strands: int = 8,
band_gap: int = 60,
):
self.A0 = sorted(A0)
self.S = S
self.n_strands = n_strands
self.band_gap = band_gap
self.root: Optional[DAGNode] = None
self.visited: dict = {}
self.stats = {
'nodes_created': 0,
'sidon_nodes': 0,
'pruned_coprimality': 0,
'pruned_energy': 0,
'pruned_exhausted': 0,
'deduped': 0,
'phases': [0, 0, 0],
}
def _make_root(self) -> DAGNode:
pairs = chiral_pairs(
n_strands=self.n_strands,
band_gap=self.band_gap,
base_prime_offset=10,
)
node = DAGNode(pairs, self.A0, self.S, depth=0)
self.visited[node.modulus_hash()] = node
self.stats['nodes_created'] += 1
return node
def _maybe_prune(
self,
parent: DAGNode,
child: DAGNode,
) -> bool:
"""Check if child should be pruned. Returns True if pruned."""
# 1. Coprimality invariant: already checked in coupled_crossing,
# but re-check for safety.
moduli = child.moduli
if not pairwise_coprime(moduli):
self.stats['pruned_coprimality'] += 1
return True
# 2. Monotonicity: SidonEnergy must not increase
if child.energy > parent.energy + EPSILON:
self.stats['pruned_energy'] += 1
return True
# 3. Sidon reached: accept but don't expand further
if child.is_sidon:
self.stats['sidon_nodes'] += 1
return False # accept, mark as terminal
# 4. Capacity exhaustion: DAG-level check
for d in ['over', 'under']:
if dag_capacity(child.capacities, d) <= 0:
self.stats['pruned_exhausted'] += 1
return True
return False
def build(
self,
max_steps: int = 30,
max_nodes: int = 10000,
use_axis_swap: bool = True,
use_adjustment: bool = True,
) -> None:
"""Build the DAG using BFS with three-phase traversal.
Phase 1: Graded Sidon search (small bands)
Phase 2: DAG topology expansion (wide bands)
Phase 3: Content-addressable dedup (hash-based)
"""
self.root = self._make_root()
queue = [self.root]
self.stats['phases'][0] += 1
while queue and self.stats['nodes_created'] < max_nodes:
node = queue.pop(0)
if node.depth >= max_steps:
continue
# Phase transition: when energy is low, widen bands
if node.energy < 0.5 and self.stats['phases'][1] == 0:
self.stats['phases'][1] = 1
self.band_gap = 500
if node.is_sidon:
continue # terminal
for s in range(self.n_strands):
for direction in ['over', 'under']:
# DAG-level capacity check (fast prune)
if dag_capacity(node.capacities, direction) <= 0:
self.stats['pruned_exhausted'] += 1
continue
result = None
if use_axis_swap and use_adjustment:
result = coupled_crossing(
node.pairs, s, direction, self.A0, self.S,
)
elif use_axis_swap:
new_pairs = axis_swap(node.pairs, s)
new_E = sidon_energy(self.A0, new_pairs, self.S)
if pairwise_coprime([m for pair in new_pairs for m in pair]):
result = (new_pairs, new_E)
elif use_adjustment:
new_pairs = adjust(node.pairs, s, direction)
if new_pairs is not None:
new_E = sidon_energy(self.A0, new_pairs, self.S)
result = (new_pairs, new_E)
else:
self.stats['pruned_coprimality'] += 1
else:
continue
if result is None:
self.stats['pruned_coprimality'] += 1
continue
new_pairs, new_energy = result
child = DAGNode(
pairs=new_pairs,
A0=self.A0,
S=self.S,
braid_word=node.braid_word + [(s, direction)],
depth=node.depth + 1,
)
child.energy = new_energy
# Pruning gates
if self._maybe_prune(node, child):
continue
# Content-addressable dedup
h = child.modulus_hash()
if h in self.visited:
existing = self.visited[h]
if existing.energy <= child.energy:
self.stats['deduped'] += 1
node.children.append(existing)
continue
self.visited[h] = child
self.stats['nodes_created'] += 1
node.children.append(child)
queue.append(child)
self.stats['phases'][2] = 1
def summary(self) -> str:
"""Return a text summary of the DAG build."""
sidon_nodes = [
n for n in self.visited.values()
if n.is_sidon
]
if sidon_nodes:
shortest = min(sidon_nodes, key=lambda n: n.depth)
sidon_str = (
f"Sidon paths found: {len(sidon_nodes)}\n"
f"Shortest path: depth={shortest.depth}, "
f"braid={shortest.braid_word}, "
f"={shortest.energy:.4f}\n"
f"Final moduli: {shortest.moduli}"
)
else:
sidon_str = "No Sidon paths found."
return (
f"── ChiralDAG Summary ──\n"
f"Strands: {self.n_strands}, Band gap: {self.band_gap}\n"
f"Nodes created: {self.stats['nodes_created']}\n"
f"Deduped: {self.stats['deduped']}\n"
f"Pruned — coprimality: {self.stats['pruned_coprimality']}\n"
f"Pruned — energy: {self.stats['pruned_energy']}\n"
f"Pruned — exhausted: {self.stats['pruned_exhausted']}\n"
f"Phases: {self.stats['phases']}\n"
f"Sidon nodes: {self.stats['sidon_nodes']}\n"
f"{sidon_str}"
)
def to_json(self, path: str) -> None:
"""Export DAG to JSON for visualization."""
import json
def _node_to_dict(n: DAGNode) -> dict:
return {
'depth': n.depth,
'pairs': n.pairs,
'moduli': n.moduli,
'M': n.M,
'energy': round(n.energy, 6),
'is_sidon': n.is_sidon,
'braid_word': n.braid_word,
'children': [
c.modulus_hash() for c in n.children
],
}
data = {
'n_strands': self.n_strands,
'band_gap': self.band_gap,
'A0': self.A0,
'stats': self.stats,
'nodes': {str(h): _node_to_dict(n)
for h, n in self.visited.items()},
}
with open(path, 'w') as f:
json.dump(data, f, indent=2)
# ═══════════════════════════════════════════════════════════════
# §10 MAIN / SELF-TEST
# ═══════════════════════════════════════════════════════════════
if __name__ == '__main__':
# Working test case (collision 3+13=8+8=16 is breakable via CRT wrapping)
A0 = [0, 1, 3, 8, 13]
S = 27
print("=== 2-strand test ===")
dag = ChiralDAG(A0=A0, S=S, n_strands=2)
dag.build(max_steps=15, max_nodes=500)
print(dag.summary())
print()
print("=== 8-strand test ===")
dag8 = ChiralDAG(A0=A0, S=S, n_strands=8)
dag8.build(max_steps=15, max_nodes=5000)
print(dag8.summary())
print()
# Q16_16 bound check
all_mods = [m for n in dag8.visited.values() for m in n.moduli]
max_m = max(all_mods) if all_mods else 0
print(f"Max modulus (8-strand): {max_m} {'' if max_m < 32767 else '✗ > 32767!'}")
# Depth distribution of Sidon paths
sidon_nodes = [n for n in dag8.visited.values() if n.is_sidon]
if sidon_nodes:
depths = {}
for n in sidon_nodes:
depths[n.depth] = depths.get(n.depth, 0) + 1
print(f"Sidon depth distribution: {dict(sorted(depths.items()))}")