""" Real-data validation v2 (self-contained; no heavy import). sklearn digits (8x8=64-dim REAL images) -> mean-centered, unit-normalized embeddings. Mean removal decorrelates the shared ink/DC structure so the LOW scenario attains genuinely low inter-user relevance. Adds the downstream task-accuracy metric (nearest class-prototype) alongside SER and mean cosine, and reports the empirical beta_uv per scenario. """ import numpy as np from sklearn.datasets import load_digits RNG = np.random.default_rng(7) U, D = 4, 64 DPU = D // U MASKS = np.zeros((U, D)) for u in range(U): MASKS[u, u*DPU:(u+1)*DPU] = 1.0 NOMA_POWER = np.array([0.40, 0.30, 0.20, 0.10]) TAU = 0.45 X, y = load_digits(return_X_y=True) X = X.astype(np.float64) X = X - X.mean(0, keepdims=True) # remove shared DC structure X = X / (np.linalg.norm(X, axis=1, keepdims=True) + 1e-8) by_class = {c: X[y == c] for c in range(10)} # class prototypes (gallery) for the downstream nearest-prototype classifier PROTO = np.stack([by_class[c].mean(0) for c in range(10)]) PROTO = PROTO / (np.linalg.norm(PROTO, axis=1, keepdims=True) + 1e-8) def _norm(E): return E / (np.linalg.norm(E, axis=-1, keepdims=True) + 1e-8) def cos_sim(Eh, Eg): return (Eh * Eg).sum(-1) def se_channel(E, snr_db): n = E.shape[0] X_ = E * MASKS[None]; Ytx = X_.sum(1) h = np.sqrt(RNG.standard_normal((n, U, 1))**2 + RNG.standard_normal((n, U, 1))**2) * np.sqrt(0.5) nstd = np.sqrt(float(np.mean(Ytx**2)) / (10**(snr_db/10))) return h * Ytx[:, None, :] + RNG.standard_normal((n, U, D)) * nstd def ofdma_decode(Yrx): return np.stack([_norm(Yrx[:, u, :] * MASKS[u]) for u in range(U)], 1) def noma_channel(E, snr_db): n = E.shape[0] h = np.sqrt(RNG.standard_normal((n, U, 1))**2 + RNG.standard_normal((n, U, 1))**2) * np.sqrt(0.5) w = E * np.sqrt(NOMA_POWER)[None, :, None] * h yv = w.sum(1) nstd = np.sqrt(float(np.mean(yv**2)) / (10**(snr_db/10))) return yv + RNG.standard_normal((n, D)) * nstd, h def noma_sic(yv, h): n = yv.shape[0]; Eh = np.zeros((n, U, D)); res = yv.copy() for u in range(U): z = res / (h[:, u, :] + 1e-8); Eh[:, u, :] = _norm(z) res -= h[:, u, :] * np.sqrt(NOMA_POWER[u]) * Eh[:, u, :] return Eh def uwca_decode(Yrx, beta_mat): R = Yrx[:, :, None, :] * MASKS[None, None] a = beta_mat.copy(); np.fill_diagonal(a, 1.0); a /= a.sum(1, keepdims=True) + 1e-8 ctx = np.einsum('ui,buid->bud', a, R) return np.stack([_norm(ctx[:, u, :]) for u in range(U)], 1) SCEN = {'HIGH': [3, 3, 3, 3], 'LOW': [0, 1, 7, 4], 'MIX': [3, 3, 8, 1]} def sample_users(n, ca): return np.stack([by_class[ca[u]][RNG.integers(0, len(by_class[ca[u]]), n)] for u in range(U)], 1) def empirical_beta(ca, n=4000): E = sample_users(n, ca) B = np.einsum('nud,nvd->uv', E, E) / n return B def downstream_acc(Eh, labels): # labels: (U,) true class per user; Eh: (n,U,D) sims = np.einsum('nud,cd->nuc', _norm(Eh), PROTO) # (n,U,10) pred = sims.argmax(-1) # (n,U) return (pred == np.array(labels)[None, :]).mean() def run(scen, snr, n_mc=400): ca = SCEN[scen]; bm = empirical_beta(ca); bmc = bm.copy(); np.fill_diagonal(bmc, 0.0); bmc = np.clip(bmc, 0, None) M = {'OFDMA': [0,0,0], 'NOMA-SIC': [0,0,0], 'UWCA': [0,0,0]} # ser, cos, acc for _ in range(n_mc): E = sample_users(64, ca) Y = se_channel(E, snr); Eh = ofdma_decode(Y) M['OFDMA'][0]+=(cos_sim(Eh,E)