| """Theory verification. Offline, ~10 s, NumPy only. |
| |
| Six checks. Two of them exist to demonstrate that claims from an earlier draft |
| were tautological or scope-violating, which is why they test against |
| adversarial inputs rather than confirming ones. |
| """ |
| import numpy as np |
| np.set_printoptions(precision=6, suppress=True) |
|
|
| def rot(t): |
| return np.array([[np.cos(t), -np.sin(t)], [np.sin(t), np.cos(t)]]) |
|
|
| def d0_cycle(N, theta, c=None): |
| """Cellular sheaf coboundary on cycle C_N with R^2 stalks. |
| c: optional per-vertex stiffness weight.""" |
| if c is None: c = np.ones(N) |
| D = np.zeros((2*N, 2*N)); I = np.eye(2) |
| for i in range(N-1): |
| D[2*i:2*i+2, 2*i:2*i+2] = -np.sqrt(c[i])*I |
| D[2*i:2*i+2, 2*(i+1):2*(i+1)+2] = np.sqrt(c[i+1])*I |
| e = N-1 |
| D[2*e:2*e+2, 2*(N-1):2*(N-1)+2] = -np.sqrt(c[N-1])*I |
| D[2*e:2*e+2, 0:2] = np.sqrt(c[0])*rot(theta) |
| return D |
|
|
| def d0_path(N, theta): |
| """Open chain (tree). N-1 edges, no loop-closing bond.""" |
| D = np.zeros((2*(N-1), 2*N)); I = np.eye(2) |
| for i in range(N-1): |
| D[2*i:2*i+2, 2*i:2*i+2] = -I |
| D[2*i:2*i+2, 2*(i+1):2*(i+1)+2] = rot(theta) if i == 0 else I |
| return D |
|
|
| print("=" * 72) |
| print("CHECK 1 closed form lambda_k^pm = 2 - 2cos((2*pi*k +- theta)/N)") |
| print("=" * 72) |
| worst = 0.0 |
| for N in [5, 6, 8, 12]: |
| for th in [0.0, 0.3, np.pi/4, np.pi/2, 2.0, np.pi, 4.5]: |
| D = d0_cycle(N, th) |
| num = np.sort(np.linalg.eigvalsh(D.T @ D)) |
| ana = np.sort(np.concatenate([ |
| [2 - 2*np.cos((2*np.pi*k + th)/N) for k in range(N)], |
| [2 - 2*np.cos((2*np.pi*k - th)/N) for k in range(N)]])) |
| worst = max(worst, np.max(np.abs(num - ana))) |
| print(f" max |numeric - closed form|, N in 5..12, 7 angles : {worst:.3e}") |
| print(f" VERDICT: {'EXACT' if worst < 1e-9 else 'MISMATCH'}") |
|
|
| print("\n" + "=" * 72) |
| print("CHECK 2 strain floor lambda_min = 2 - 2cos(theta/N) -> theta^2/N^2") |
| print("=" * 72) |
| print(f" {'N':>3} {'theta':>7} {'lambda_min':>12} {'2-2cos(th/N)':>14} {'th^2/N^2':>12}") |
| for N in [5, 10, 20]: |
| for th in [0.1, 0.5, np.pi/2]: |
| lm = np.sort(np.linalg.eigvalsh(d0_cycle(N, th).T @ d0_cycle(N, th)))[0] |
| print(f" {N:>3} {th:>7.4f} {lm:>12.7f} {2-2*np.cos(th/N):>14.7f} {th**2/N**2:>12.7f}") |
|
|
| print("\n" + "=" * 72) |
| print("CHECK 3 residue stiffness does NOT change Betti numbers") |
| print("=" * 72) |
| for name, c in {"AAAAA": [1,1,1,1,1], "APPPA": [1,4,4,4,1], |
| "AGGGA": [1,.15,.15,.15,1], "random": [0.31,2.7,0.08,5.2,1.9]}.items(): |
| c = np.array(c, float); row = [] |
| for th in [0.0, 0.4, np.pi/2, np.pi]: |
| D = d0_cycle(5, th, c) |
| row.append((10 - np.linalg.matrix_rank(D, tol=1e-9), |
| np.sort(np.linalg.eigvalsh(D.T @ D))[0])) |
| print(f" {name:>7} h0 = {[x[0] for x in row]} lambda_min = " |
| + " ".join(f"{x[1]:.4f}" for x in row)) |
| print(" h0 identical across sequences. Only the energy scale moves.") |
|
|
| print("\n" + "=" * 72) |
| print("CHECK 4 chi = h0 - h1 = 0 is rank-nullity, not a conservation law") |
| print("=" * 72) |
| rng = np.random.default_rng(7); bad = 0 |
| for _ in range(2000): |
| N = rng.integers(3, 9) |
| D = rng.normal(size=(2*N, 2*N)) |
| if rng.random() < 0.3: D[:, rng.integers(0, 2*N)] = 0 |
| r = np.linalg.matrix_rank(D, tol=1e-9) |
| if (2*N - r) - (2*N - r) != 0: bad += 1 |
| print(f" chi != 0 in {bad} / 2000 random square coboundaries.") |
| print(" Holds for ANY square d0. Carries zero information about the peptide.") |
|
|
| print("\n" + "=" * 72) |
| print("CHECK 5 open backbones cannot frustrate (scope limit)") |
| print("=" * 72) |
| for th in [0.0, 0.7, np.pi/2, np.pi, 3.0]: |
| D = d0_path(6, th); r = np.linalg.matrix_rank(D, tol=1e-9) |
| print(f" theta={th:6.3f} rank={r:2d} h0={12-r} " |
| f"lambda_min={np.sort(np.linalg.eigvalsh(D.T@D))[0]:.2e}") |
| print(" h0=2 always. The mechanism REQUIRES the ring-closing bond.") |
|
|
| print("\n" + "=" * 72) |
| print("CHECK 6 sqrt(c) in restriction maps breaks the kernel interpretation") |
| print("=" * 72) |
| c = np.array([1, 4, 4, 4, 1], float) |
| D = d0_cycle(5, 0.0, c) |
| ns = np.linalg.svd(D)[2][np.linalg.matrix_rank(D, tol=1e-9):].T |
| s = ns[:, 0].reshape(5, 2) |
| print(" kernel section at theta=0, APPPA stiffness:") |
| for i, r in enumerate(s): |
| print(f" v{i}: ({r[0]:+.4f}, {r[1]:+.4f}) " |
| f"norm*sqrt(c) = {np.linalg.norm(r)*np.sqrt(c[i]):.4f}") |
| print(" Residues do not share a dihedral vector. The kernel means 'equal after") |
| print(" rescaling', which is not a conformation. Use edge weights instead:") |
| print(" Delta = d0^T W d0 with d0 isometric.") |
|
|