import logging
import numpy as np
logging.basicConfig(level=logging.INFO, format="%(message)s")
log = logging.getLogger("floor")
def unitary_keys(m, d, rng):
half = d // 2 + 1
ph = rng.uniform(0, 2 * np.pi, size=(m, half))
ph[:, 0] = 0.0
if d % 2 == 0:
ph[:, -1] = 0.0
return np.fft.irfft(np.exp(1j * ph), n=d, axis=1)
def build(d, m, ell, seed):
rng = np.random.default_rng(seed)
keys = unitary_keys(m, d, rng)
codebook = rng.standard_normal((ell, d))
codebook /= np.linalg.norm(codebook, axis=1, keepdims=True)
labels = rng.integers(0, ell, size=m) phi = np.empty((d, m * ell))
cb_f = np.fft.rfft(codebook, axis=1)
for i in range(m):
cols = np.fft.irfft(np.fft.rfft(keys[i])[None, :] * cb_f, n=d, axis=1)
phi[:, i * ell : (i + 1) * ell] = cols.T
s = phi[:, labels + ell * np.arange(m)].sum(axis=1)
return keys, codebook, labels, s, phi
def naive_recover(keys, codebook, s):
m, d = keys.shape
s_f = np.fft.rfft(s)
cbn = codebook / np.linalg.norm(codebook, axis=1, keepdims=True)
est = np.empty(m, dtype=int)
for i in range(m):
kinv = np.roll(keys[i][::-1], 1) v = np.fft.irfft(s_f * np.fft.rfft(kinv), n=d)
est[i] = np.argmax(cbn @ (v / (np.linalg.norm(v) + 1e-12)))
return est
def amp_recover(phi, s, m, ell, n_iter=200, damp=0.3):
d, n = phi.shape
x = np.zeros(n)
z = s.copy()
last_p = np.ones((m, ell)) / ell
for _ in range(n_iter):
tau2 = max(np.sum(z * z) / d, 1e-12)
r = (phi.T @ z + x).reshape(m, ell) / tau2
r -= r.max(axis=1, keepdims=True)
p = np.exp(r)
p /= p.sum(axis=1, keepdims=True)
x_new = p.reshape(-1)
div = np.sum(p - p * p) / tau2
z_new = s - phi @ x_new + (1.0 / d) * div * z
z = damp * z + (1 - damp) * z_new
x = damp * x + (1 - damp) * x_new
last_p = p
return np.argmax(last_p, axis=1), last_p
def hard_solve(phi, s, m, ell, init, n_iter=300):
est = init.copy()
recon = phi[:, est + ell * np.arange(m)].sum(axis=1)
order = np.arange(m)
for it in range(n_iter):
changed = 0
np.random.default_rng(it).shuffle(order)
for i in order:
recon -= phi[:, i * ell + est[i]]
sims = phi[:, i * ell : (i + 1) * ell].T @ (s - recon)
best = int(np.argmax(sims))
changed += best != est[i]
est[i] = best
recon += phi[:, i * ell + est[i]]
if changed == 0:
break
return est
def floor_table(dims, ell, ratios, seeds):
log.info("(1) BLIND RECOVERY FLOOR | naive HRR vs AMP, mean+-std over seeds")
for d in dims:
log.info(f"\n D={d} L={ell}")
log.info(f" {'M/D':>5} {'naive':>14} {'amp':>14} {'amp_soft':>9}")
for ratio in ratios:
m = max(1, round(ratio * d))
nv, ap, sf = [], [], []
for sd in seeds:
keys, cb, labels, s, phi = build(d, m, ell, sd)
nv.append(np.mean(naive_recover(keys, cb, s) == labels))
est, p = amp_recover(phi, s, m, ell)
ap.append(np.mean(est == labels))
sf.append(np.mean(p[np.arange(m), labels]))
nv, ap, sf = map(np.array, (nv, ap, sf))
log.info(
f" {ratio:>5.2f} {nv.mean():>6.3f}+-{nv.std():<5.3f} "
f"{ap.mean():>6.3f}+-{ap.std():<5.3f} {sf.mean():>7.3f}"
)
def gap_table(d, ell, ratios, seeds):
log.info(
"\n(2) THE GAP IS COMPUTATIONAL | genie-init stays; random-init never finds it"
)
log.info(f"\n D={d} L={ell}")
log.info(f" {'M/D':>5} {'genie_stay':>12} {'rand_best_of_8':>16}")
for ratio in ratios:
m = max(1, round(ratio * d))
gs, hb = [], []
for sd in seeds:
keys, cb, labels, s, phi = build(d, m, ell, sd)
gs.append(np.mean(hard_solve(phi, s, m, ell, labels.copy()) == labels))
rng = np.random.default_rng(1000 + sd)
best_res, best_acc = np.inf, 0.0
for _ in range(8):
est = hard_solve(phi, s, m, ell, rng.integers(0, ell, size=m))
res = np.linalg.norm(s - phi[:, est + ell * np.arange(m)].sum(axis=1))
if res < best_res:
best_res, best_acc = res, np.mean(est == labels)
hb.append(best_acc)
gs, hb = np.array(gs), np.array(hb)
log.info(
f" {ratio:>5.2f} {gs.mean():>12.3f} {hb.mean():>10.3f}+-{hb.std():<5.3f}"
)
def main():
ell = 64
seeds = range(5)
floor_table([256, 512], ell, [0.10, 0.20, 0.25, 0.30, 0.40], seeds)
gap_table(256, ell, [0.20, 0.30, 0.40, 0.50, 0.60, 0.75], seeds)
log.info(
"\nRead: AMP holds ~100% to M/D~0.25 then falls (the floor); genie_stay=1.0 to "
"0.75\nwhile random-init collapses -> the true solution is stable/verifiable far "
"past the\nfloor but unfindable blindly. Computational hard phase, not an "
"information wall."
)
if __name__ == "__main__":
main()