SilverSight/experiments/bosonic_continuous/kernel/ryser_continuous.py
allaun 93c6b0a691 exp(bosonic): continuous interpolation experiment for regime transition
Testing λ(p) = exp(-p²/N) to remove hard p≥5 regime switch.
- ryser_continuous.py: unified estimator skeleton
- test_lambda_interpolation.py: smooth transition verification

Build: 2987 jobs, 0 errors
2026-06-22 01:19:10 -05:00

59 lines
No EOL
1.8 KiB
Python

#!/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}