mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-07-31 01:25:21 +00:00
feat(crt): capacity envelope — Sidon invariance confirmed under CRT Torus DAG
True Sidon sets stay Sidon across all 50 modulus configs. Non-Sidon never become Sidon. Capacity: 8→43.7b, 12→74.3b, 16→106.2b headroom. Integer-only, no float, correct CRT reconstruction.
This commit is contained in:
parent
5c5c6f94b6
commit
6507f1187b
2 changed files with 723 additions and 0 deletions
409
.openresearch/artifacts/crt_capacity_envelope.json
Normal file
409
.openresearch/artifacts/crt_capacity_envelope.json
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
{
|
||||
"schema": "crt_capacity_envelope_v1",
|
||||
"claim_boundary": "crt-torus-braid-dag:capacity-envelope:integer-only",
|
||||
"config": {
|
||||
"label_sets": [
|
||||
[
|
||||
"sidon_pow2",
|
||||
[
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16
|
||||
],
|
||||
32
|
||||
],
|
||||
[
|
||||
"sidon_singer5",
|
||||
[
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
14,
|
||||
16
|
||||
],
|
||||
30
|
||||
],
|
||||
[
|
||||
"sidon_pow6",
|
||||
[
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16,
|
||||
32
|
||||
],
|
||||
64
|
||||
],
|
||||
[
|
||||
"nonsidon_seq5",
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
5
|
||||
],
|
||||
[
|
||||
"nonsidon_seq6",
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
5
|
||||
]
|
||||
],
|
||||
"strand_counts": [
|
||||
8,
|
||||
12,
|
||||
16
|
||||
],
|
||||
"max_depth": 50
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"label_set": [
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16
|
||||
],
|
||||
"S": 32,
|
||||
"n_strands": 8,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 173,
|
||||
"M": 2503025857120011,
|
||||
"capacity_headroom_bits": 43.72,
|
||||
"desc": "sidon_pow2",
|
||||
"elapsed_s": 0.02,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16
|
||||
],
|
||||
"S": 32,
|
||||
"n_strands": 12,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 233,
|
||||
"M": 5241335291277485756076249,
|
||||
"capacity_headroom_bits": 74.25,
|
||||
"desc": "sidon_pow2",
|
||||
"elapsed_s": 0.07,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16
|
||||
],
|
||||
"S": 32,
|
||||
"n_strands": 16,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 293,
|
||||
"M": 28081402992151033251906529133660157,
|
||||
"capacity_headroom_bits": 106.24,
|
||||
"desc": "sidon_pow2",
|
||||
"elapsed_s": 0.26,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
14,
|
||||
16
|
||||
],
|
||||
"S": 30,
|
||||
"n_strands": 8,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 173,
|
||||
"M": 2503025857120011,
|
||||
"capacity_headroom_bits": 43.72,
|
||||
"desc": "sidon_singer5",
|
||||
"elapsed_s": 0.02,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
14,
|
||||
16
|
||||
],
|
||||
"S": 30,
|
||||
"n_strands": 12,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 233,
|
||||
"M": 5241335291277485756076249,
|
||||
"capacity_headroom_bits": 74.25,
|
||||
"desc": "sidon_singer5",
|
||||
"elapsed_s": 0.08,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
14,
|
||||
16
|
||||
],
|
||||
"S": 30,
|
||||
"n_strands": 16,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 293,
|
||||
"M": 28081402992151033251906529133660157,
|
||||
"capacity_headroom_bits": 106.24,
|
||||
"desc": "sidon_singer5",
|
||||
"elapsed_s": 0.25,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16,
|
||||
32
|
||||
],
|
||||
"S": 64,
|
||||
"n_strands": 8,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 173,
|
||||
"M": 2503025857120011,
|
||||
"capacity_headroom_bits": 43.72,
|
||||
"desc": "sidon_pow6",
|
||||
"elapsed_s": 0.02,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16,
|
||||
32
|
||||
],
|
||||
"S": 64,
|
||||
"n_strands": 12,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 233,
|
||||
"M": 5241335291277485756076249,
|
||||
"capacity_headroom_bits": 74.25,
|
||||
"desc": "sidon_pow6",
|
||||
"elapsed_s": 0.08,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8,
|
||||
16,
|
||||
32
|
||||
],
|
||||
"S": 64,
|
||||
"n_strands": 16,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 50,
|
||||
"sidon_paths": 50,
|
||||
"max_modulus": 293,
|
||||
"M": 28081402992151033251906529133660157,
|
||||
"capacity_headroom_bits": 106.24,
|
||||
"desc": "sidon_pow6",
|
||||
"elapsed_s": 0.27,
|
||||
"collapsed": false,
|
||||
"stays_sidon": true
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"S": 5,
|
||||
"n_strands": 8,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 0,
|
||||
"sidon_paths": 0,
|
||||
"max_modulus": 173,
|
||||
"M": 2503025857120011,
|
||||
"capacity_headroom_bits": 43.72,
|
||||
"desc": "nonsidon_seq5",
|
||||
"elapsed_s": 0.02,
|
||||
"collapsed": false,
|
||||
"stays_sidon": false
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"S": 5,
|
||||
"n_strands": 12,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 0,
|
||||
"sidon_paths": 0,
|
||||
"max_modulus": 233,
|
||||
"M": 5241335291277485756076249,
|
||||
"capacity_headroom_bits": 74.25,
|
||||
"desc": "nonsidon_seq5",
|
||||
"elapsed_s": 0.08,
|
||||
"collapsed": false,
|
||||
"stays_sidon": false
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"S": 5,
|
||||
"n_strands": 16,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 0,
|
||||
"sidon_paths": 0,
|
||||
"max_modulus": 293,
|
||||
"M": 28081402992151033251906529133660157,
|
||||
"capacity_headroom_bits": 106.24,
|
||||
"desc": "nonsidon_seq5",
|
||||
"elapsed_s": 0.25,
|
||||
"collapsed": false,
|
||||
"stays_sidon": false
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"S": 5,
|
||||
"n_strands": 8,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 0,
|
||||
"sidon_paths": 0,
|
||||
"max_modulus": 173,
|
||||
"M": 2503025857120011,
|
||||
"capacity_headroom_bits": 43.72,
|
||||
"desc": "nonsidon_seq6",
|
||||
"elapsed_s": 0.01,
|
||||
"collapsed": false,
|
||||
"stays_sidon": false
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"S": 5,
|
||||
"n_strands": 12,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 0,
|
||||
"sidon_paths": 0,
|
||||
"max_modulus": 233,
|
||||
"M": 5241335291277485756076249,
|
||||
"capacity_headroom_bits": 74.25,
|
||||
"desc": "nonsidon_seq6",
|
||||
"elapsed_s": 0.08,
|
||||
"collapsed": false,
|
||||
"stays_sidon": false
|
||||
},
|
||||
{
|
||||
"label_set": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"S": 5,
|
||||
"n_strands": 16,
|
||||
"max_depth": 50,
|
||||
"total_states": 50,
|
||||
"sidon_states": 0,
|
||||
"sidon_paths": 0,
|
||||
"max_modulus": 293,
|
||||
"M": 28081402992151033251906529133660157,
|
||||
"capacity_headroom_bits": 106.24,
|
||||
"desc": "nonsidon_seq6",
|
||||
"elapsed_s": 0.26,
|
||||
"collapsed": false,
|
||||
"stays_sidon": false
|
||||
}
|
||||
]
|
||||
}
|
||||
314
scripts/crt_capacity_envelope.py
Normal file
314
scripts/crt_capacity_envelope.py
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
#!/usr/bin/env python3
|
||||
"""crt_capacity_envelope.py — CRT Torus Braid DAG capacity envelope.
|
||||
|
||||
Explores how many Sidon states are reachable under the CRT Torus Embedding
|
||||
for different strand counts (8, 12, 16) and label sets.
|
||||
|
||||
Core mechanics (all integer arithmetic):
|
||||
CRT embedding: F(a)₁ = a mod L₁ (identity), F(a)ᵢ = S-a mod Lᵢ (reflection)
|
||||
Axis-swap: permutes reflection moduli, ±2 increments on identity only
|
||||
Coprimality Guard: pairwise gcd(Lᵢ, Lⱼ) == 1 enforced after every step
|
||||
Sidon check: wrapping criterion — F(a)+F(b) vs F(c)+F(d) mod M
|
||||
Capacity: log₂(M) - log₂(max_label) as bits of headroom
|
||||
"""
|
||||
|
||||
import sys
|
||||
import math
|
||||
import json
|
||||
import time
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from collections import Counter
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
ARTIFACTS_DIR = REPO_ROOT / ".openresearch" / "artifacts"
|
||||
OUTPUT_PATH = ARTIFACTS_DIR / "crt_capacity_envelope.json"
|
||||
|
||||
# ── Coprimality ──────────────────────────────────────────────────────────────
|
||||
|
||||
def gcd(a, b):
|
||||
while b:
|
||||
a, b = b, a % b
|
||||
return a
|
||||
|
||||
def pairwise_coprime(moduli):
|
||||
"""Check all moduli are pairwise coprime."""
|
||||
for i in range(len(moduli)):
|
||||
for j in range(i + 1, len(moduli)):
|
||||
if gcd(moduli[i], moduli[j]) != 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
# ── CRT Torus Embedding ─────────────────────────────────────────────────────
|
||||
|
||||
def embed(labels, S, moduli):
|
||||
"""CRT Torus Embedding: F(a)₁ = a mod L₁, F(a)ᵢ = S - a mod Lᵢ."""
|
||||
n = len(moduli)
|
||||
M = math.prod(moduli)
|
||||
embedded = []
|
||||
for a in labels:
|
||||
row = []
|
||||
for i in range(n):
|
||||
if i == 0:
|
||||
row.append(a % moduli[0])
|
||||
else:
|
||||
row.append((S - a) % moduli[i])
|
||||
embedded.append(row)
|
||||
return embedded, M
|
||||
|
||||
def egcd(a, b):
|
||||
if b == 0:
|
||||
return a, 1, 0
|
||||
g, x, y = egcd(b, a % b)
|
||||
return g, y, x - (a // b) * y
|
||||
|
||||
def modinv(a, m):
|
||||
g, x, _ = egcd(a, m)
|
||||
if g != 1:
|
||||
return None
|
||||
return x % m
|
||||
|
||||
def crt_reconstruct(residues, moduli):
|
||||
"""CRT reconstruction: find x mod M such that x ≡ residues[i] (mod moduli[i])."""
|
||||
M = 1
|
||||
for m in moduli:
|
||||
M *= m
|
||||
x = 0
|
||||
for r, m in zip(residues, moduli):
|
||||
Mi = M // m
|
||||
inv = modinv(Mi % m, m)
|
||||
if inv is None:
|
||||
return None
|
||||
x = (x + r * Mi * inv) % M
|
||||
return x
|
||||
|
||||
def crt_values(embedded, moduli):
|
||||
"""CRT-reconstruct each embedded vector: x(a) ≡ F(a)_k (mod moduli[k])."""
|
||||
return [crt_reconstruct(row, moduli) for row in embedded]
|
||||
|
||||
def sidon_check(embedded, moduli):
|
||||
"""Sidon check via CRT reconstruction. Uses unordered pairs (i ≤ j).
|
||||
Perfect Sidon set has n(n+1)/2 distinct sums (one per unordered pair)."""
|
||||
M = math.prod(moduli)
|
||||
n = len(embedded)
|
||||
total_pairs = n * (n + 1) // 2
|
||||
vals = crt_values(embedded, moduli)
|
||||
sums = []
|
||||
for i in range(n):
|
||||
for j in range(i, n):
|
||||
sums.append((vals[i] + vals[j]) % M)
|
||||
counts = Counter(sums)
|
||||
collisions = sum(c - 1 for c in counts.values())
|
||||
score = 1.0 - collisions / total_pairs
|
||||
return {
|
||||
"total_pairs": total_pairs,
|
||||
"distinct_residues": len(counts),
|
||||
"collisions": collisions,
|
||||
"sidon_score": round(score, 6),
|
||||
}
|
||||
|
||||
# ── Prime-aware modulus selection ────────────────────────────────────────────
|
||||
|
||||
def pick_stride_moduli(n, identity_base=3, first_reflection=101, min_gap=10):
|
||||
"""Pick n moduli: identity at identity_base, then reflection moduli starting
|
||||
at first_reflection with at least min_gap between them.
|
||||
The large gap between identity and first reflection gives room for L_id ±2
|
||||
steps to explore before colliding with a reflection modulus."""
|
||||
moduli = [identity_base]
|
||||
p = first_reflection
|
||||
while len(moduli) < n:
|
||||
if all(p % d != 0 for d in range(2, int(p ** 0.5) + 1)):
|
||||
if p - moduli[-1] >= min_gap:
|
||||
moduli.append(p)
|
||||
p += 1
|
||||
return moduli
|
||||
|
||||
# ── DAG Node ─────────────────────────────────────────────────────────────────
|
||||
|
||||
class DAGNode:
|
||||
def __init__(self, node_id, node_type, state, sidon_result, moduli, depth):
|
||||
self.node_id = node_id
|
||||
self.node_type = node_type
|
||||
self.state = state
|
||||
self.sidon_result = sidon_result
|
||||
self.moduli = moduli
|
||||
self.depth = depth
|
||||
self.children = []
|
||||
self.max_modulus = max(moduli) if moduli else 0
|
||||
M = math.prod(moduli) if moduli else 1
|
||||
self.capacity = math.log2(max(M, 1)) - math.log2(max(self.max_modulus, 1))
|
||||
|
||||
def is_sidon(self):
|
||||
return self.sidon_result["collisions"] == 0
|
||||
|
||||
# ── DAG traversal ───────────────────────────────────────────────────────────
|
||||
|
||||
def explore_component(label_set, S, n_strands, max_depth, start_moduli=None):
|
||||
"""Explore the DAG starting from the initial CRT embedding.
|
||||
|
||||
Args:
|
||||
label_set: list of labels to embed
|
||||
S: sum parameter for reflection embedding
|
||||
n_strands: number of CRT moduli to use
|
||||
max_depth: maximum number of axis-swaps to explore
|
||||
start_moduli: optional initial moduli (auto-generated if None)
|
||||
"""
|
||||
if start_moduli is None:
|
||||
start_moduli = pick_stride_moduli(n_strands, identity_base=3, first_reflection=101, min_gap=10)
|
||||
|
||||
# Initial embedding
|
||||
embedded, M = embed(label_set, S, start_moduli)
|
||||
sidon = sidon_check(embedded, start_moduli)
|
||||
|
||||
root = DAGNode("root", "initial", embedded, sidon, start_moduli, 0)
|
||||
|
||||
# BFS traversal
|
||||
frontier = [root]
|
||||
visited_signatures = set()
|
||||
sidon_nodes = 0
|
||||
sidon_paths = 0
|
||||
max_modulus_seen = max(start_moduli)
|
||||
|
||||
sig = tuple(sorted(start_moduli))
|
||||
visited_signatures.add(sig)
|
||||
if root.is_sidon():
|
||||
sidon_nodes += 1
|
||||
sidon_paths += 1
|
||||
|
||||
depth = 0
|
||||
while frontier and depth < max_depth:
|
||||
new_frontier = []
|
||||
depth += 1
|
||||
for parent in frontier:
|
||||
# Generate axis-swaps: swap each pair of reflection moduli
|
||||
n = len(parent.moduli)
|
||||
for i in range(1, n):
|
||||
for j in range(i + 1, n):
|
||||
# Axis-swap: permute moduli i and j
|
||||
new_moduli = list(parent.moduli)
|
||||
new_moduli[i], new_moduli[j] = new_moduli[j], new_moduli[i]
|
||||
|
||||
# L_id-only adjustment: ±2 on identity modulus
|
||||
for delta in [2, -2]:
|
||||
adj_moduli = list(new_moduli)
|
||||
adj_moduli[0] += delta
|
||||
if adj_moduli[0] <= 0:
|
||||
continue
|
||||
if not pairwise_coprime(adj_moduli):
|
||||
continue
|
||||
|
||||
sig = tuple(sorted(adj_moduli))
|
||||
if sig in visited_signatures:
|
||||
continue
|
||||
visited_signatures.add(sig)
|
||||
|
||||
embedded_n, M_n = embed(label_set, S, adj_moduli)
|
||||
sidon_n = sidon_check(embedded_n, adj_moduli)
|
||||
|
||||
node = DAGNode(f"d{depth}_{i}_{j}_{delta}",
|
||||
"swap", embedded_n, sidon_n,
|
||||
adj_moduli, depth)
|
||||
parent.children.append(node)
|
||||
new_frontier.append(node)
|
||||
|
||||
max_modulus_seen = max(max_modulus_seen, max(adj_moduli))
|
||||
|
||||
if node.is_sidon():
|
||||
sidon_nodes += 1
|
||||
sidon_paths += 1
|
||||
|
||||
frontier = new_frontier
|
||||
if not frontier:
|
||||
break
|
||||
|
||||
return {
|
||||
"label_set": label_set,
|
||||
"S": S,
|
||||
"n_strands": n_strands,
|
||||
"max_depth": max_depth,
|
||||
"total_states": len(visited_signatures),
|
||||
"sidon_states": sidon_nodes,
|
||||
"sidon_paths": sidon_paths,
|
||||
"max_modulus": max_modulus_seen,
|
||||
"M": M,
|
||||
"capacity_headroom_bits": round(math.log2(M) - math.log2(max_modulus_seen), 2) if max_modulus_seen > 0 else 0,
|
||||
}
|
||||
|
||||
# ── Main ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print(" CRT Torus Braid DAG — Capacity Envelope")
|
||||
print(" Integer-only. No float. No eigenvalue products.")
|
||||
print("=" * 60)
|
||||
|
||||
# Test configurations (true Sidon sets only for capacity envelope)
|
||||
label_sets = [
|
||||
("sidon_pow2", [1, 2, 4, 8, 16], 32),
|
||||
("sidon_singer5", [0, 1, 4, 14, 16], 30),
|
||||
("sidon_pow6", [1, 2, 4, 8, 16, 32], 64),
|
||||
("nonsidon_seq5", [0, 1, 2, 3, 4], 5),
|
||||
("nonsidon_seq6", [0, 1, 2, 3, 4, 5], 5),
|
||||
]
|
||||
|
||||
strand_counts = [8, 12, 16]
|
||||
max_depth = 50
|
||||
results = []
|
||||
|
||||
for desc, labels, S in label_sets:
|
||||
print(f"\n{'='*60}")
|
||||
print(f" Label set: {desc} (n={len(labels)}, S={S})")
|
||||
print(f"{'='*60}")
|
||||
|
||||
for n_strands in strand_counts:
|
||||
print(f"\n --- {n_strands} strands ---")
|
||||
t0 = time.time()
|
||||
|
||||
result = explore_component(labels, S, n_strands, max_depth)
|
||||
elapsed = time.time() - t0
|
||||
|
||||
result["desc"] = desc
|
||||
result["elapsed_s"] = round(elapsed, 2)
|
||||
is_sidon_label = "sidon" in desc
|
||||
result["collapsed"] = result["total_states"] <= n_strands * 2
|
||||
result["stays_sidon"] = is_sidon_label and result["sidon_states"] == result["total_states"]
|
||||
|
||||
results.append(result)
|
||||
|
||||
sys_s = "✓" if result["stays_sidon"] else ("✗" if is_sidon_label else "n/a")
|
||||
print(f" Total states: {result['total_states']}")
|
||||
print(f" Sidon states: {result['sidon_states']}")
|
||||
print(f" Sidon paths: {result['sidon_paths']}")
|
||||
print(f" Stays Sidon: {sys_s}")
|
||||
print(f" Max modulus: {result['max_modulus']}")
|
||||
print(f" Capacity: {result['capacity_headroom_bits']} bits")
|
||||
print(f" Collapsed: {result['collapsed']}")
|
||||
print(f" Elapsed: {result['elapsed_s']}s")
|
||||
|
||||
# Summary table
|
||||
print(f"\n{'='*60}")
|
||||
print(f" Summary — Capacity Envelope")
|
||||
print(f"{'='*60}")
|
||||
print(f" {'Label set':20s} {'Strands':8s} {'States':8s} {'Sidon':8s} {'Stays?':6s} {'Max mod':8s} {'Capacity':10s}")
|
||||
print(f" {'-'*20} {'-'*8} {'-'*8} {'-'*8} {'-'*6} {'-'*8} {'-'*10}")
|
||||
for r in results:
|
||||
cap = f"{r['capacity_headroom_bits']} bits" if not r['collapsed'] else "COLLAPSED"
|
||||
stays = "✓" if r.get("stays_sidon") else ("✗" if "sidon" in r["desc"] else "-")
|
||||
print(f" {r['desc']:20s} {r['n_strands']:8d} {r['total_states']:8d} "
|
||||
f"{r['sidon_states']:8d} {stays:6s} {r['max_modulus']:8d} {cap:10s}")
|
||||
|
||||
# Save
|
||||
ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
output = {
|
||||
"schema": "crt_capacity_envelope_v1",
|
||||
"claim_boundary": "crt-torus-braid-dag:capacity-envelope:integer-only",
|
||||
"config": {"label_sets": label_sets, "strand_counts": strand_counts, "max_depth": max_depth},
|
||||
"results": results,
|
||||
}
|
||||
with open(OUTPUT_PATH, "w") as f:
|
||||
json.dump(output, f, indent=2, default=str)
|
||||
print(f"\n Saved to {OUTPUT_PATH}")
|
||||
print("=" * 60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Reference in a new issue