Add the diagnostics behind the no-interference claim

This commit is contained in:
KiHoLee
2026-08-18 13:40:34 +09:00
parent f828018160
commit fef629a218
2 changed files with 193 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
"""Does an orthogonal unit codebook recover the shortfall?
diag_interference shows the gap to the ideal M-ary receiver is not
multi-user interference but the geometry of the trained unit codebook,
whose Gram matrix carries a root-mean-square off-diagonal of 0.45 where
an orthogonal set would carry zero. Vu = L = 16 admits an exactly
orthogonal set, so this measures what installing one buys.
Two orthogonal sets are tried, because the choice is not free. The
Walsh-Hadamard set collides with the keys: the rows are closed under the
elementwise product, so masking a Hadamard codeword by a Hadamard key
returns another Hadamard codeword and every user ends up with the same
candidate set. A random orthogonal set carries no such group structure,
and masking by a unit-modulus key preserves its orthogonality exactly.
"""
import sys
from pathlib import Path
import torch
sys.path.insert(0, str(Path(__file__).resolve().parent))
import sse_lib as L
from sse_lib import DEVICE, SSE
from exp_full import hadamard, base_keys
from diag_interference import ser
SNR = [0.0, 10.0, 20.0]
FRAMES = 400_000
def fixed_model(B, P=4, vu=16, d=64, U=4):
L.set_seed(1)
m = SSE(P=P, vu=vu, d=d, users=U).to(DEVICE)
with torch.no_grad():
m.B.copy_(B.to(DEVICE))
m.W.copy_(base_keys(U, d // P).to(DEVICE))
m.calibrate_power()
return m
def hadamard_book(vu=16, Lp=16):
B = torch.zeros(vu, Lp)
B[:, :vu] = torch.tensor(hadamard(vu).copy(), dtype=torch.float32)
return B
def random_ortho_book(vu=16, Lp=16, seed=7):
g = torch.Generator().manual_seed(seed)
A = torch.randn(Lp, Lp, generator=g)
Q, _ = torch.linalg.qr(A)
return Q[:vu].contiguous()
def report(name, m):
with torch.no_grad():
Bn = m.unit_codebook()
G = Bn @ Bn.T
off = (G - torch.diag(torch.diag(G))).abs().max()
row = [name, "%.2e" % off]
for s in SNR:
row.append("%.4f" % ser(m, s, FRAMES))
print("%-22s %-10s %-9s %-9s %-9s" % tuple(row))
def main():
print("%-22s %-10s %-9s %-9s %-9s"
% ("unit codebook", "max|off|", "0 dB", "10 dB", "20 dB"))
report("Walsh-Hadamard", fixed_model(hadamard_book()))
report("random orthogonal", fixed_model(random_ortho_book()))
print("%-22s %-10s %-9s %-9s %-9s"
% ("trained (paper)", "0.887", "0.8822", "0.2576", "0.0307"))
print("%-22s %-10s %-9s %-9s %-9s"
% ("OMA, resource matched", "-",
"%.4f" % L.oma_ser([0.0])[0],
"%.4f" % L.oma_ser([10.0])[0],
"%.4f" % L.oma_ser([20.0])[0]))
def solo_check():
"""Splitting each candidate set from the superposition it must live
in. Orthogonal codewords are ideal for one user alone and are what
the single-user bound assumes, but the masked sets of different users
are then far from orthogonal to each other."""
print()
print("%-22s %-12s %-12s" % ("unit codebook", "solo 10 dB", "4-user 10 dB"))
for name, B in (("random orthogonal", random_ortho_book()),
("trained (retrain)", None)):
if B is None:
from exp_full import main_model
m = main_model()
else:
m = fixed_model(B)
print("%-22s %-12.4f %-12.4f"
% (name, ser(m, 10.0, FRAMES, solo=True),
ser(m, 10.0, FRAMES, solo=False)))
print("single-user ideal M-ary bound (separate MC): 0.1986")
if __name__ == "__main__":
main()
solo_check()