diff --git a/experiments/bosonic_continuous/README.md b/experiments/bosonic_continuous/README.md new file mode 100644 index 00000000..40aa1093 --- /dev/null +++ b/experiments/bosonic_continuous/README.md @@ -0,0 +1,23 @@ +# Bosonic Continuous Interpolation Experiment + +Testing a unified Monte Carlo estimator without regime switching. + +## Goal +Replace hard p≥5 cutoff with continuous λ(p) interpolation: +``` +λ(p) = exp(-p²/N) +Q(p) = λ(p) Q_bos + (1-λ(p)) Q_fact +``` + +## Structure +- `kernel/ryser_continuous.py` — Unified permanent estimator +- `kernel/mode_sampler.py` — Mode sampling kernel +- `tests/test_lambda_interpolation.py` — Verify continuity + +## Key Change +Remove: +```python +if p >= 5: distinguishable_k() +``` + +Replace with single estimator using Ryser permanent for all p ≤ 6. \ No newline at end of file diff --git a/experiments/bosonic_continuous/kernel/ryser_continuous.py b/experiments/bosonic_continuous/kernel/ryser_continuous.py new file mode 100644 index 00000000..257d5a83 --- /dev/null +++ b/experiments/bosonic_continuous/kernel/ryser_continuous.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +""" +Unified Ryser-based Monte Carlo estimator for bosonic permanental distributions. +No regime switching — single estimator for all p ≤ 6. +""" + +import math +from typing import List + +def ryser_permanent(matrix: List[List[complex]]) -> complex: + """Compute permanent using Ryser's formula.""" + p = len(matrix) + if p == 0: + return 1.0 + # Generate all subsets via bitmask + total = 0j + for mask in range(1, 1 << p): + sign = (-1) ** (p - bin(mask).count("1")) + prod = 1.0 + for row in matrix: + s = 0.0 + for j in range(p): + if mask & (1 << j): + s += row[j].real # Use real part for simplicity + prod *= s + total += sign * prod + return total + +def lambda_interpolation(p: int, N: int) -> float: + """Continuous interpolation parameter. + + λ(p) = exp(-p²/N) + λ → 1 as p² << N (weak interference, fully bosonic) + λ → 0 as p² >> N (strong interference, factorized) + """ + return math.exp(-p * p / N) + +def unified_bosonic_estimator(U: List[List[complex]], p: int, samples: int = 1000) -> dict: + """Single estimator for all photon numbers. + + Returns distribution histogram using continuous λ(p) weighting. + """ + N = len(U) + lam = lambda_interpolation(p, N) + + # Monte Carlo sampling + results = {} + for _ in range(samples): + # Sample modes (simplified) + S = [j % N for j in range(p)] # Placeholder + M = [[U[S[i]][j] for j in range(p)] for i in range(p)] + perm = ryser_permanent(M) + w = abs(perm) ** 2 + + # Apply λ(p) weighting + weighted = lam * w + (1 - lam) * sum(abs(U[i][j])**2 for i in range(N) for j in range(N)) / (N * N) + results[str(S)] = weighted + + return {"histogram": results, "lambda": lam, "p": p, "N": N} \ No newline at end of file diff --git a/experiments/bosonic_continuous/tests/test_lambda_interpolation.py b/experiments/bosonic_continuous/tests/test_lambda_interpolation.py new file mode 100644 index 00000000..1a4623fe --- /dev/null +++ b/experiments/bosonic_continuous/tests/test_lambda_interpolation.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +""" +Test lambda interpolation for bosonic Monte Carlo regime transition. +""" + +import math +import sys +sys.path.insert(0, "/home/allaun/SilverSight/experiments/bosonic_continuous/kernel") + +def test_lambda_values(): + """Verify lambda interpolation at key photon numbers.""" + N = 2000 + + cases = [ + (p, N, "expected behavior") + for p in [2, 3, 4, 5, 6] + for N in [2000] + ] + + print("p | lambda | regime") + print("--|---------|----------") + for p, N, _ in cases: + lam = math.exp(-p * p / N) + regime = "bosonic" if lam > 0.9 else "crossover" if lam > 0.5 else "classical" + print(f"{p} | {lam:.4f} | {regime}") + +def test_entropy_continuity(): + """Mock test for entropy continuity across p values.""" + N = 2000 + total_entropy = 0.0 + for p in range(1, 7): + lam = math.exp(-p * p / N) + # Mock: entropy should vary smoothly + mock_entropy = 10.0 + (1 - lam) * 2 + total_entropy += mock_entropy + print(f"p={p}: entropy~{mock_entropy:.2f}") + print(f"Total: {total_entropy:.2f}") + +if __name__ == "__main__": + test_lambda_values() + print() + test_entropy_continuity() \ No newline at end of file