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]
|
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
|
# PEG Base Matrix Constructor
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -904,13 +937,46 @@ def main():
|
|||||||
p_val.add_argument('--n-frames', type=int, default=200)
|
p_val.add_argument('--n-frames', type=int, default=200)
|
||||||
p_val.add_argument('--seed', type=int, default=42)
|
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
|
# full
|
||||||
p_full = subparsers.add_parser('full', help='Full pipeline')
|
p_full = subparsers.add_parser('full', help='Full pipeline')
|
||||||
p_full.add_argument('--seed', type=int, default=42)
|
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()
|
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)
|
np.random.seed(args.seed)
|
||||||
from ldpc_analysis import build_peg_matrix
|
from ldpc_analysis import build_peg_matrix
|
||||||
matrices = {
|
matrices = {
|
||||||
|
|||||||
@@ -281,3 +281,31 @@ class TestNormalizedMinSumDE:
|
|||||||
assert thresh_norm != thresh_offset, (
|
assert thresh_norm != thresh_offset, (
|
||||||
f"Thresholds should differ: offset={thresh_offset}, normalized={thresh_norm}"
|
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