feat: add code analysis tool with rate, matrix, quantization, and Shannon analyses
Implements four LDPC code analyses for photon-starved optical channels: - Rate sweep: compare FER across 1/2, 1/3, 1/4, 1/6, 1/8 IRA staircase codes - Matrix comparison: original staircase vs improved staircase vs PEG ring - Quantization sweep: 4-16 bit and float precision impact on FER - Shannon gap: binary-input Poisson channel capacity limits via binary search Core infrastructure includes generic IRA staircase builder, GF(2) Gaussian elimination encoder for non-triangular matrices, parameterized layered min-sum decoder with variable check degree, and BFS girth computation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
85
model/test_ldpc_analysis.py
Normal file
85
model/test_ldpc_analysis.py
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests for LDPC code analysis module (ldpc_analysis.py).
|
||||
|
||||
Covers IRA staircase code construction and rate sweep functionality.
|
||||
|
||||
Run:
|
||||
python3 -m pytest model/test_ldpc_analysis.py -v
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from ldpc_analysis import (
|
||||
build_ira_staircase,
|
||||
ira_encode,
|
||||
generic_decode,
|
||||
rate_sweep_single,
|
||||
)
|
||||
from ldpc_sim import poisson_channel, quantize_llr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TestIRAStaircase
|
||||
# =============================================================================
|
||||
|
||||
class TestIRAStaircase:
|
||||
"""Validate generic IRA staircase code construction for various rates."""
|
||||
|
||||
def test_rate_1_2(self):
|
||||
"""m_base=1 -> rate 1/2: (1,2) base matrix, (32,64) full matrix, rank=32."""
|
||||
H_base, H_full = build_ira_staircase(m_base=1, z=32)
|
||||
assert H_base.shape == (1, 2), f"Base shape: {H_base.shape}"
|
||||
assert H_full.shape == (32, 64), f"Full shape: {H_full.shape}"
|
||||
rank = np.linalg.matrix_rank(H_full.astype(float))
|
||||
assert rank == 32, f"Rank: {rank}, expected 32"
|
||||
|
||||
def test_rate_1_4(self):
|
||||
"""m_base=3 -> rate 1/4: (3,4) base matrix, (96,128) full matrix, rank=96."""
|
||||
H_base, H_full = build_ira_staircase(m_base=3, z=32)
|
||||
assert H_base.shape == (3, 4), f"Base shape: {H_base.shape}"
|
||||
assert H_full.shape == (96, 128), f"Full shape: {H_full.shape}"
|
||||
rank = np.linalg.matrix_rank(H_full.astype(float))
|
||||
assert rank == 96, f"Rank: {rank}, expected 96"
|
||||
|
||||
def test_rate_1_8_matches_existing(self):
|
||||
"""m_base=7 -> rate 1/8: (7,8) base matrix, (224,256) full matrix."""
|
||||
H_base, H_full = build_ira_staircase(m_base=7, z=32)
|
||||
assert H_base.shape == (7, 8), f"Base shape: {H_base.shape}"
|
||||
assert H_full.shape == (224, 256), f"Full shape: {H_full.shape}"
|
||||
|
||||
def test_encode_decode_roundtrip(self):
|
||||
"""For m_base in [1,2,3,5], encode random info, verify syndrome=0."""
|
||||
np.random.seed(42)
|
||||
for m_base in [1, 2, 3, 5]:
|
||||
H_base, H_full = build_ira_staircase(m_base=m_base, z=32)
|
||||
z = 32
|
||||
k = z # info bits = Z
|
||||
info = np.random.randint(0, 2, k).astype(np.int8)
|
||||
codeword = ira_encode(info, H_base, H_full, z=z)
|
||||
syndrome = H_full @ codeword % 2
|
||||
assert np.all(syndrome == 0), (
|
||||
f"m_base={m_base}: syndrome weight = {syndrome.sum()}"
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TestRateSweep
|
||||
# =============================================================================
|
||||
|
||||
class TestRateSweep:
|
||||
"""Validate rate sweep simulation."""
|
||||
|
||||
def test_high_snr_all_rates_decode(self):
|
||||
"""At lam_s=20, all rates should achieve FER=0 with 10 frames."""
|
||||
np.random.seed(42)
|
||||
for m_base in [1, 2, 3, 5, 7]:
|
||||
result = rate_sweep_single(
|
||||
m_base=m_base, z=32, lam_s=20.0, lam_b=0.1,
|
||||
n_frames=10, max_iter=30, q_bits=6,
|
||||
)
|
||||
assert result['fer'] == 0.0, (
|
||||
f"m_base={m_base} (rate 1/{m_base+1}): FER={result['fer']} at lam_s=20, "
|
||||
f"expected 0.0"
|
||||
)
|
||||
Reference in New Issue
Block a user