Research-Stack/4-Infrastructure/shim/spherion_twin_prime.py
allaun 4da68e1a19 docs: update AGENTS.md for SpherionTwinPrime module + add spherion_twin_prime.py shim
AGENTS.md: added SpherionTwinPrime architecture section, updated Burgers energy dissipation to parametric form.

spherion_twin_prime.py (20KB): priority-queue walk with polarity energy tuning.

Build: 8598 jobs, 0 errors.
2026-06-16 23:38:51 -05:00

518 lines
20 KiB
Python
Raw 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.

#!/usr/bin/env python3
"""
Spherion 16D Multi-Polar Transition Domain Twin-Prime Walk.
Extends the classic twin-prime priority-queue enumeration of the 4 obstruction
sheets 6ab ┬▒ a ┬▒ b with a per-sheet polarity parameter that tunes the energy
of each obstruction, controlling the density of twin-prime witnesses.
Theory:
Twin primes (p, p+2) are characterized by the polynomial
n = 6ab ┬▒ a ┬▒ b. An integer n is a *witness* (twin-prime candidate)
iff no positive integers a,b and signs ┬▒1 satisfy the obstruction:
n = 6ab + σ₁·a + σ₂·b (σ₁, σ₂ ∈ {+1, -1})
The 4 obstruction sheets are:
Sheet (+1, +1): 6ab + a + b
Sheet (+1, -1): 6ab + a - b
Sheet (-1, +1): 6ab - a + b
Sheet (-1, -1): 6ab - a - b
Polarity scales the obstruction energy:
E = p ┬À (6ab + σ₁┬Àa + σ₂┬Àb)
p = 1.0 → standard algorithm (OEIS A002822)
p < 1.0 → shed energy (lower barrier, more obstructions → fewer witnesses)
p > 1.0 → accumulate energy (higher barrier, fewer obstructions → more witnesses)
p = 0 → no obstructions (false positives: all integers are witnesses)
p → ∞ → obstructions at infinity (false negatives: no finite witnesses)
Energy = polarity ┬À raw_value defines the peak position. Integer n is
obstructed iff there exists (a,b,σ₁,σ₂) such that n = p ┬À (6ab + σ₁┬Àa + σ₂┬Àb).
References:
- OEIS A002822: Numbers n such that 6n-1 and 6n+1 are twin primes.
- "Twin-prime generating polynomials" via 6ab ┬▒ a ┬▒ b.
"""
from __future__ import annotations
import argparse
import hashlib
import heapq
import json
import sys
from datetime import datetime, timezone
from typing import Dict, List, Optional, Set, Tuple
# ---------------------------------------------------------------------------
# Sheet-generator ── lazy priority-queue enumeration of one obstruction sheet
# ---------------------------------------------------------------------------
class SheetGenerator:
"""Lazily yield values from one obstruction sheet in increasing order.
F(a,b) = polarity ┬À (6┬Àa┬Àb + σ₁┬Àa + σ₂┬Àb) for a,b ≥ 1.
Uses a priority-queue frontier (standard sorted-matrix traversal).
When *max_value* is given, stops as soon as the popped value exceeds it,
enabling bounded scans that terminate even for extreme polarities.
"""
def __init__(
self,
σ1: int,
σ2: int,
polarity: float,
max_value: Optional[float] = None,
) -> None:
if polarity < 0:
raise ValueError(f"polarity must be ≥ 0, got {polarity}")
self.σ1 = σ1
self.σ2 = σ2
self.polarity = polarity
self.max_value = max_value
self._heap: List[Tuple[float, int, int]] = []
self._visited: Set[Tuple[int, int]] = set()
self._push(1, 1)
def _row(self, a: int, b: int) -> float:
raw = 6 * a * b + self.σ1 * a + self.σ2 * b
return self.polarity * raw
def _push(self, a: int, b: int) -> None:
if self.max_value is not None:
lo = self._row(a, b)
if lo > self.max_value:
return
key = (a, b)
if key not in self._visited:
self._visited.add(key)
heapq.heappush(self._heap, (self._row(a, b), a, b))
def __iter__(self) -> SheetGenerator:
return self
def __next__(self) -> float:
while self._heap:
v, a, b = heapq.heappop(self._heap)
if self.max_value is not None and v > self.max_value:
self._heap.clear()
raise StopIteration
self._push(a + 1, b)
self._push(a, b + 1)
return v
raise StopIteration
# ---------------------------------------------------------------------------
# Spherion 16D twin-prime walk
# ---------------------------------------------------------------------------
SIGNS: List[Tuple[int, int]] = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
class SpherionTwinPrimeWalk:
"""Priority-queue walk over the 4 obstruction sheets with energy tuning.
Parameters
----------
polarities : dict, optional
Per-sheet energy tuning. Keys are (σ₁, σ₂) tuples, values are floats.
Missing sheets default to 1.0.
"""
def __init__(
self, polarities: Optional[Dict[Tuple[int, int], float]] = None
) -> None:
if polarities is None:
polarities = {s: 1.0 for s in SIGNS}
self.polarities = polarities
# ── Public API ──────────────────────────────────────────────────────
def obstruction(self, a: int, b: int, σ1: int, σ2: int) -> float:
"""Obstruction energy at (a, b, σ₁, σ₂)."""
raw = 6 * a * b + σ1 * a + σ2 * b
p = self.polarities.get((σ1, σ2), 1.0)
return p * raw
def _merged(self, max_value: Optional[float] = None) -> heapq.merge:
"""Merge all 4 sheet streams into one sorted obstruction stream."""
gens = [
SheetGenerator(
σ1,
σ2,
self.polarities.get((σ1, σ2), 1.0),
max_value=max_value,
)
for σ1, σ2 in SIGNS
]
return heapq.merge(*gens)
def energy_spectrum(self, limit: int = 1000) -> List[float]:
"""First *limit* obstruction energies from the merged stream."""
out: List[float] = []
for i, v in enumerate(self._merged()):
if i >= limit:
break
out.append(v)
return out
def _enumerate_bounded(self, limit: int) -> Set[int]:
"""Enumerate all obstructed integers ≤ *limit* via direct nested loops.
For bounded enumeration this is faster and terminates reliably even for
extreme polarities (p=0, p→∞) where the PQ-based generator would loop
indefinitely or never reach the threshold.
"""
covered: Set[int] = set()
limit_f = float(limit)
for σ1, σ2 in SIGNS:
p = self.polarities.get((σ1, σ2), 1.0)
if p == 0.0:
continue
# a,b ≥ 1, raw = 6ab + σ1·a + σ2·b ≥ 4 for a=b=1, (-1,-1) sheet
# bound: p * (6ab - a - b) ≤ limit ⇒ ab ≤ limit/p/4 (rough bound)
max_ab = max(1, int(limit_f / p / 4) + 2)
for a in range(1, max_ab + 1):
for b in range(1, max_ab + 1):
raw = 6 * a * b + σ1 * a + σ2 * b
v = p * raw
if v > limit_f:
break
iv = int(v)
if v == iv and iv >= 1:
covered.add(iv)
return covered
def obstructions_up_to(self, limit: int) -> Set[int]:
"""Set of integers n ≤ *limit* that are obstructed (energy lands on n)."""
return self._enumerate_bounded(limit)
def witnesses(self, limit: int = 500) -> List[int]:
"""Integers 1..limit NOT obstructed at the current polarities."""
obs = self.obstructions_up_to(limit)
return [i for i in range(1, limit + 1) if i not in obs]
def witness_density(self, limit: int = 500) -> float:
"""Fraction of integers ≤ *limit* that are witnesses."""
return len(self.witnesses(limit)) / max(limit, 1)
def betti_gaps(self, limit: int = 500) -> List[int]:
"""Witness numbers as Betti scars — the uncovered (gap) region."""
return self.witnesses(limit)
def per_sheet_coverage(
self, limit: int = 500
) -> Dict[Tuple[int, int], List[int]]:
"""Which integers each sheet obstructs individually."""
result: Dict[Tuple[int, int], List[int]] = {}
for σ1, σ2 in SIGNS:
p = self.polarities.get((σ1, σ2), 1.0)
hits: Set[int] = set()
if p > 0.0:
max_ab = max(1, int(float(limit) / p / 4) + 2)
for a in range(1, max_ab + 1):
for b in range(1, max_ab + 1):
raw = 6 * a * b + σ1 * a + σ2 * b
v = p * raw
if v > limit:
break
iv = int(v)
if v == iv and iv >= 1:
hits.add(iv)
result[(σ1, σ2)] = sorted(hits)
return result
def report(self, limit: int = 500) -> dict:
"""Full JSON-serialisible report for the current polarity configuration."""
energy = self.energy_spectrum(min(limit, 200))
w = self.witnesses(limit)
psc = self.per_sheet_coverage(limit)
psc_serial = {f"({s1},{s2})": vals for (s1, s2), vals in psc.items()}
return {
"schema": "spherion_twin_prime_report_v1",
"polarities": {
f"({s1},{s2})": self.polarities[(s1, s2)]
for s1, s2 in SIGNS
},
"limit": limit,
"witness_count": len(w),
"witness_density": len(w) / max(limit, 1),
"first_20_witnesses": w[:20],
"first_20_energies": [round(e, 6) for e in energy[:20]],
"per_sheet_coverage": {k: v[:10] for k, v in psc_serial.items()},
}
# ---------------------------------------------------------------------------
# Analysis helpers
# ---------------------------------------------------------------------------
def witness_density_vs_polarity(
polarities: List[float], limit: int = 500
) -> List[Tuple[float, float, int]]:
"""Compute witness density for each uniform polarity in *polarities*."""
results: List[Tuple[float, float, int]] = []
for p in polarities:
walk = SpherionTwinPrimeWalk({s: p for s in SIGNS})
w = walk.witnesses(limit)
density = len(w) / max(limit, 1)
results.append((p, density, len(w)))
return results
def standard_oeis_check(limit: int = 200) -> Tuple[int, List[int]]:
"""Check that polarity=1.0 gives OEIS A002822 (twin-prime witnesses)."""
walk = SpherionTwinPrimeWalk()
w = walk.witnesses(limit)
# OEIS A002822 starts: 1, 2, 3, 5, 7, 10, 12, 15, 17, 18, 23, 25, 30, ...
return (len(w), w)
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def build_arg_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(
description="Spherion 16D twin-prime walk with polarity tuning"
)
p.add_argument("--test", action="store_true", help="Run test suite")
p.add_argument(
"--limit", type=int, default=500, help="Search limit (default 500)"
)
p.add_argument(
"--polarity",
type=float,
default=None,
help="Uniform polarity override (omit for per-sheet defaults)",
)
p.add_argument("--json", action="store_true", help="Output JSON report")
return p
def run_tests(limit: int = 500) -> dict:
"""Execute the full test matrix and return a summary dict."""
results: dict = {
"schema": "spherion_twin_prime_test_v1",
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
"limit": limit,
"tests": {},
}
do_small = min(limit, 300)
# ── 1. polarity = 0: no obstructions → all witnesses ────────────────
walk0 = SpherionTwinPrimeWalk({s: 0.0 for s in SIGNS})
w0 = walk0.witnesses(do_small)
results["tests"]["polarity_0"] = {
"description": "p=0 → no obstructions, all witnesses",
"witness_count": len(w0),
"expected_count": do_small,
"all_witnesses": len(w0) == do_small,
}
# ── 2. polarity = 1.0: standard OEIS A002822 ────────────────────────
walk1 = SpherionTwinPrimeWalk()
w1 = walk1.witnesses(do_small)
results["tests"]["polarity_1_0"] = {
"description": "p=1.0 → standard OEIS A002822",
"witness_count": len(w1),
"witness_density": len(w1) / do_small,
"first_20": w1[:20],
}
# ── 3. polarity → ∞: very large → obstructions drift to infinity ────
walk_inf = SpherionTwinPrimeWalk({s: 1e9 for s in SIGNS})
w_inf = walk_inf.witnesses(do_small)
results["tests"]["polarity_inf"] = {
"description": "p=1e9 → obstructions at ≈1e9×raw, no finite hits",
"witness_count": len(w_inf),
"expected_count": do_small,
"all_witnesses": len(w_inf) == do_small,
}
# ── 4. shed energy (p < 1.0) ────────────────────────────────────────
walk_low = SpherionTwinPrimeWalk({s: 0.5 for s in SIGNS}) # p = 0.5
w_low = walk_low.witnesses(do_small)
results["tests"]["polarity_shed"] = {
"description": "p=0.5 → shed energy, more obstructions, fewer witnesses",
"witness_count": len(w_low),
"density": len(w_low) / do_small,
"vs_nominal_density": (
round(len(w_low) / do_small, 4),
round(len(w1) / do_small, 4),
),
}
# ── 5. accumulate energy (p > 1.0) ──────────────────────────────────
walk_high = SpherionTwinPrimeWalk({s: 3.0 for s in SIGNS})
w_high = walk_high.witnesses(do_small)
results["tests"]["polarity_accumulate"] = {
"description": "p=3.0 → accumulate energy, fewer obstructions, more witnesses",
"witness_count": len(w_high),
"density": len(w_high) / do_small,
"vs_nominal_density": (
round(len(w_high) / do_small, 4),
round(len(w1) / do_small, 4),
),
}
# ── 6. per-sheet tuning ─────────────────────────────────────────────
per_sheet_polarities = {
(1, 1): 1.0,
(1, -1): 0.5,
(-1, 1): 2.0,
(-1, -1): 1.0,
}
walk_ps = SpherionTwinPrimeWalk(per_sheet_polarities)
w_ps = walk_ps.witnesses(do_small)
psc = walk_ps.per_sheet_coverage(do_small)
results["tests"]["per_sheet_tuning"] = {
"description": "Per-sheet polarities (1,1)=1.0 (1,-1)=0.5 (-1,1)=2.0 (-1,-1)=1.0",
"polarities": {
f"({s1},{s2})": p for (s1, s2), p in per_sheet_polarities.items()
},
"witness_count": len(w_ps),
"density": len(w_ps) / do_small,
"per_sheet_obstruction_counts": {
f"({s1},{s2})": len(vals) for (s1, s2), vals in psc.items()
},
}
# ── 7. Density sweep ────────────────────────────────────────────────
sweep_points = [0.0, 0.25, 0.5, 0.75, 1.0, 2.0, 5.0, 10.0]
sweep = witness_density_vs_polarity(sweep_points, limit=do_small)
results["tests"]["density_sweep"] = {
"description": "Witness density vs uniform polarity",
"sweep": [
{"polarity": p, "density": round(d, 4), "witnesses": n}
for p, d, n in sweep
],
}
# ── 8. Betti-style gap analysis ─────────────────────────────────────
gaps = walk1.betti_gaps(do_small)
max_run = 0
cur = 0
for i in range(1, do_small + 1):
if i in gaps:
cur += 1
if cur > max_run:
max_run = cur
else:
cur = 0
results["tests"]["betti_gaps"] = {
"description": "Betti-style gap analysis at p=1.0",
"gap_count": len(gaps),
"longest_witness_run": max_run,
"first_20_gaps": gaps[:20],
}
return results
def main() -> None:
args = build_arg_parser().parse_args()
if args.test:
results = run_tests(limit=args.limit)
if args.json:
print(json.dumps(results, indent=2))
else:
tests = results["tests"]
print(f"╔══ Spherion 16D Twin-Prime Walk — Test Results ═══╗")
print(f" Limit: {results['limit']}\n")
t = tests["polarity_0"]
print(
f"[polarity=0] {t['witness_count']}/{results['limit']} "
f"witnesses — {'' if t['all_witnesses'] else ''} all witnesses"
)
t = tests["polarity_1_0"]
print(
f"[polarity=1.0] {t['witness_count']}/{results['limit']} "
f"witnesses — density {t['witness_density']:.4f}"
)
print(f" First 20 witnesses: {t['first_20']}")
t = tests["polarity_shed"]
d_nom = tests["polarity_1_0"]["witness_density"]
print(
f"[polarity=1/3 — shed] {t['witness_count']}/{results['limit']} "
f"witnesses — density {t['density']:.4f} "
f"(nominal {d_nom:.4f}) {'✓ shed < nominal' if t['density'] < d_nom else ''}"
)
t = tests["polarity_accumulate"]
print(
f"[polarity=3.0 — accumulate] {t['witness_count']}/{results['limit']} "
f"witnesses — density {t['density']:.4f} "
f"(nominal {d_nom:.4f}) {'✓ accumulate > nominal' if t['density'] > d_nom else ''}"
)
t = tests["polarity_inf"]
print(
f"[polarity=1e9 — ∞ limit] {t['witness_count']}/{results['limit']} "
f"witnesses — {'' if t['all_witnesses'] else ''} all finite witnesses"
)
t = tests["per_sheet_tuning"]
print(f"\n[per-sheet tuning] {t['witness_count']}/{results['limit']} witnesses")
print(f" Sheet obstructions: {t['per_sheet_obstruction_counts']}")
print(f" Polarities: {t['polarities']}")
t = tests["density_sweep"]
print(f"\n[Density sweep]")
for pt in t["sweep"]:
marker = " ← nominal" if pt["polarity"] == 1.0 else ""
print(
f" p={pt['polarity']:<8} → density {pt['density']:.4f} "
f"({pt['witnesses']} witnesses)" + marker
)
t = tests["betti_gaps"]
print(
f"\n[Betti gaps] {t['gap_count']} gaps, longest run = "
f"{t['longest_witness_run']}"
)
print(f" First 20 gaps (witnesses): {t['first_20_gaps']}")
print(f"\n Key finding: gaps = twin-prime candidate scars.")
print(f" The uncovered integers are the Betti-0 homology of")
print(f" the obstruction complex.")
# Generate SHA256 of results for audit trail
h = hashlib.sha256(json.dumps(results, sort_keys=True).encode()).hexdigest()
print(f"\n receipt_hash: {h}")
print(f"{'' * 50}")
else:
walk = SpherionTwinPrimeWalk()
limit = args.limit
if args.polarity is not None:
walk = SpherionTwinPrimeWalk(
{s: args.polarity for s in SIGNS}
)
rep = walk.report(limit)
if args.json:
print(json.dumps(rep, indent=2))
else:
print(f"Spherion Twin-Prime Walk — limit={limit}")
print(f" Polarities: {rep['polarities']}")
print(f" Witnesses: {rep['witness_count']}/{limit} "
f"(density {rep['witness_density']:.4f})")
print(f" First 20: {rep['first_20_witnesses']}")
print(f" First 20 energies: {rep['first_20_energies']}")
if __name__ == "__main__":
main()