feat: add alpha optimization for normalized min-sum
Add optimize_alpha() function that sweeps hardware-friendly alpha values to find the best DE threshold with normalized min-sum. Add alpha-sweep CLI subcommand and --z/--cn-mode/--alpha options to the full pipeline. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -531,6 +531,39 @@ def optimize_degree_distribution(m_base=7, lam_b=0.1, top_k=10,
|
||||
return results[:top_k]
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Alpha Optimization for Normalized Min-Sum
|
||||
# =============================================================================
|
||||
|
||||
def optimize_alpha(vn_degrees, alpha_range=None, m_base=7, lam_b=0.1,
|
||||
z_pop=20000, tol=0.25):
|
||||
"""
|
||||
Sweep alpha values for normalized min-sum and find the best threshold.
|
||||
|
||||
Args:
|
||||
vn_degrees: VN degree list
|
||||
alpha_range: list of alpha values to try (hardware-friendly fractions)
|
||||
m_base: number of base matrix rows
|
||||
lam_b: background photon rate
|
||||
z_pop: DE population size
|
||||
tol: threshold tolerance
|
||||
|
||||
Returns:
|
||||
(best_alpha, best_threshold)
|
||||
"""
|
||||
if alpha_range is None:
|
||||
alpha_range = [0.5, 0.625, 0.6875, 0.75, 0.8125, 0.875, 1.0]
|
||||
profile = build_de_profile(vn_degrees, m_base=m_base)
|
||||
best_alpha, best_threshold = None, float('inf')
|
||||
for alpha in alpha_range:
|
||||
t = compute_threshold(profile, lam_b=lam_b, z_pop=z_pop, tol=tol,
|
||||
cn_mode='normalized', alpha=alpha)
|
||||
print(f" alpha={alpha:.4f}: threshold = {t:.2f} photons/slot")
|
||||
if t < best_threshold:
|
||||
best_alpha, best_threshold = alpha, t
|
||||
return best_alpha, best_threshold
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PEG Base Matrix Constructor
|
||||
# =============================================================================
|
||||
@@ -904,13 +937,46 @@ def main():
|
||||
p_val.add_argument('--n-frames', type=int, default=200)
|
||||
p_val.add_argument('--seed', type=int, default=42)
|
||||
|
||||
# alpha-sweep
|
||||
p_alpha = subparsers.add_parser('alpha-sweep', help='Optimize alpha for normalized min-sum')
|
||||
p_alpha.add_argument('--degrees', type=str, default='7,4,4,4,4,3,3,3',
|
||||
help='Comma-separated VN degrees')
|
||||
p_alpha.add_argument('--z-pop', type=int, default=20000)
|
||||
p_alpha.add_argument('--tol', type=float, default=0.25)
|
||||
p_alpha.add_argument('--seed', type=int, default=42)
|
||||
|
||||
# full
|
||||
p_full = subparsers.add_parser('full', help='Full pipeline')
|
||||
p_full.add_argument('--seed', type=int, default=42)
|
||||
p_full.add_argument('--z', type=int, default=32, help='Lifting factor')
|
||||
p_full.add_argument('--cn-mode', type=str, default='offset',
|
||||
choices=['offset', 'normalized'])
|
||||
p_full.add_argument('--alpha', type=float, default=0.75)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == 'threshold':
|
||||
if args.command == 'alpha-sweep':
|
||||
np.random.seed(args.seed)
|
||||
degrees = [int(x) for x in args.degrees.split(',')]
|
||||
print(f"Alpha Optimization for degrees {degrees}")
|
||||
print("-" * 50)
|
||||
best_alpha, best_threshold = optimize_alpha(
|
||||
degrees, m_base=len(degrees) - 1, lam_b=0.1,
|
||||
z_pop=args.z_pop, tol=args.tol
|
||||
)
|
||||
print(f"\nBest alpha: {best_alpha:.4f}")
|
||||
print(f"Best threshold: {best_threshold:.2f} photons/slot")
|
||||
|
||||
# Compare with offset mode
|
||||
profile = build_de_profile(degrees, m_base=len(degrees) - 1)
|
||||
thresh_offset = compute_threshold(profile, lam_b=0.1, z_pop=args.z_pop,
|
||||
tol=args.tol, cn_mode='offset')
|
||||
print(f"Offset min-sum threshold: {thresh_offset:.2f} photons/slot")
|
||||
if best_threshold < thresh_offset:
|
||||
gain_db = 10 * np.log10(thresh_offset / best_threshold)
|
||||
print(f"Normalized gain: {gain_db:.2f} dB")
|
||||
|
||||
elif args.command == 'threshold':
|
||||
np.random.seed(args.seed)
|
||||
from ldpc_analysis import build_peg_matrix
|
||||
matrices = {
|
||||
|
||||
@@ -281,3 +281,31 @@ class TestNormalizedMinSumDE:
|
||||
assert thresh_norm != thresh_offset, (
|
||||
f"Thresholds should differ: offset={thresh_offset}, normalized={thresh_norm}"
|
||||
)
|
||||
|
||||
|
||||
class TestAlphaOptimization:
|
||||
"""Tests for alpha sweep optimization."""
|
||||
|
||||
def test_optimize_alpha_returns_best(self):
|
||||
"""Alpha sweep for optimized degrees should find threshold < 3.5."""
|
||||
from density_evolution import optimize_alpha
|
||||
np.random.seed(42)
|
||||
best_alpha, best_threshold = optimize_alpha(
|
||||
[7, 4, 4, 4, 4, 3, 3, 3], m_base=7, lam_b=0.1,
|
||||
z_pop=10000, tol=0.5
|
||||
)
|
||||
assert best_alpha is not None, "Should find a best alpha"
|
||||
assert 0.5 <= best_alpha <= 1.0, f"Alpha {best_alpha} out of range"
|
||||
# Normalized should be competitive with offset threshold (3.05)
|
||||
assert best_threshold < 4.0, f"Best threshold {best_threshold} too high"
|
||||
|
||||
def test_alpha_sweep_range(self):
|
||||
"""All alpha values in range should produce valid thresholds."""
|
||||
from density_evolution import optimize_alpha, build_de_profile, compute_threshold
|
||||
np.random.seed(42)
|
||||
profile = build_de_profile([7, 4, 4, 4, 4, 3, 3, 3], m_base=7)
|
||||
alpha_range = [0.5, 0.75, 1.0]
|
||||
for alpha in alpha_range:
|
||||
t = compute_threshold(profile, lam_b=0.1, z_pop=5000, tol=1.0,
|
||||
cn_mode='normalized', alpha=alpha)
|
||||
assert 0.1 < t < 20.0, f"alpha={alpha}: threshold {t} out of valid range"
|
||||
|
||||
Reference in New Issue
Block a user