"""R-grid: trainless learnability ratio over size x contrast, both bgs. Same R as compute_R.py (pooled object-toggle signal / temporal+spatial clutter), just vectorized over a grid and dumped to JSON. Purpose: test whether R measured AT THE TARGET CONTRAST already flags double-deficit (small AND low-contrast) cells that compiler v1's single-axis router mis-handled. """ import json, numpy as np, cv2, sys B = np.load("simreal/frames64.npy").astype(np.float32) / 255.0 rng = np.random.default_rng(0) def pool(img): return cv2.resize(img, (8, 8), interpolation=cv2.INTER_AREA).ravel() def draw(img, pos, c, size, ct): img = img.copy(); x, y = pos img[y:y+size, x:x+size] = c*ct + img[y:y+size, x:x+size].mean(axis=(0, 1))*(1-ct) return img def R(mode, size, ct, n=80): sig, den = [], [] for _ in range(n): if mode == "static": frames = [B[rng.integers(len(B))]]*9 else: frames = [B[rng.integers(len(B))] for _ in range(9)] pos = (int(rng.integers(2, 60-size)), int(rng.integers(2, 60-size))) c = rng.uniform(0.15, 0.95, 3).astype(np.float32) sig.append(np.sum((pool(draw(frames[0], pos, c, size, ct)) - pool(draw(frames[0], pos, 1-c, size, ct)))**2)/4) P = np.array([pool(f) for f in frames]) probes = [pool(np.roll(np.roll(frames[0], int(rng.integers(64)), 0), int(rng.integers(64)), 1)) for _ in range(6)] den.append(P.var(axis=0).sum() + np.array(probes).var(axis=0).sum()) return float(np.mean(sig)/(np.mean(den)+1e-9)) SIZES = [5, 6, 8, 10, 12, 14, 16] CTS = [1.0, 0.4] TH = 0.02 grid = {} for mode in ["static", "moving"]: for ct in CTS: for s in SIZES: r = R(mode, s, ct) grid[f"{mode}_o{s}_ct{ct:g}"] = round(r, 4) flag = "DIRECT" if r >= TH else "floor" print(f"{mode:6s} {s:2d}px ct{ct:<3g} R={r:.4f} {flag}", flush=True) json.dump(grid, open("results_compiler_v2/R_grid.json", "w"), indent=2) print("\nwrote results_compiler_v2/R_grid.json")