From 30b4d95be25b30de765e5d24ca61166945feb5bd Mon Sep 17 00:00:00 2001 From: cah Date: Tue, 24 Feb 2026 16:41:58 -0700 Subject: [PATCH] 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 --- model/density_evolution.py | 68 ++++++++++++++++++++++++++++++++- model/test_density_evolution.py | 28 ++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/model/density_evolution.py b/model/density_evolution.py index ef63afe..1ed7d22 100644 --- a/model/density_evolution.py +++ b/model/density_evolution.py @@ -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 = { diff --git a/model/test_density_evolution.py b/model/test_density_evolution.py index 6c7be36..4abfd66 100644 --- a/model/test_density_evolution.py +++ b/model/test_density_evolution.py @@ -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"