"""Check (i) of 06-ilang-source/04-profile. Second-order mutual cost M2 computed numerically from the single-object contract C1 = -t_f * (adjacency of the graph) via (4.3): M2 = -2 N_f g1 g2 phi(x1) phi(x2) R(x1, x2), R = reduced resolvent of C1 at the eigenvalue of phi, compared with the ring closed form (4.5) and the leading torus forms (4.6), (4.7). Also: lowest + highest state on even rings (sum over the two ends, (4.13)). """ from pathlib import Path from math import lgamma, log, pi import numpy as np import scipy.sparse as sp from scipy.sparse.linalg import cg, LinearOperator OUT = Path(__file__).parent / "output" OUT.mkdir(exist_ok=True) LOG = [] def out(s=""): print(s) LOG.append(s) def torus_contract(L, D, t=1.0): """C1 = -t * sum over nearest-neighbour edges of the L^D torus (L >= 3).""" n = L**D idx = np.arange(n).reshape((L,) * D) r = np.concatenate([idx.ravel()] * D) c = np.concatenate([np.roll(idx, -1, axis=ax).ravel() for ax in range(D)]) A = sp.coo_matrix((np.ones(len(r)), (r, c)), shape=(n, n)).tocsr() return -t * (A + A.T), idx def phi_and_R(C1, which): """Eigenvector phi (which = 0: lowest, -1: highest) and reduced resolvent R of C1 at its eigenvalue.""" e, v = np.linalg.eigh(C1) j = which % len(e) w = np.array([0.0 if k == j else 1.0 / (e[k] - e[j]) for k in range(len(e))]) return v[:, j], (v * w) @ v.T def m2_dense(C1, x1, x2, which, Nf=1, g1=1.0, g2=1.0, pr=None): """(4.3): M2 = -2 N_f g1 g2 phi(x1) phi(x2) R(x1, x2).""" phi, R = pr if pr is not None else phi_and_R(C1, which) return -2 * Nf * g1 * g2 * phi[x1] * phi[x2] * R[x1, x2] def resolvent_column_cg(C1, phi, eps, x2, t=1.0): """R(., x2) from (C1 - eps + t |phi>0 (Perron)") out(" d vector |d| m_num m_lead m_num-m_lead") maxdev = 0.0 for dv in dirs: for r in rs: d = tuple(r * a for a in dv) if max(d) > L // 4: continue x1 = idx[d] M2 = -2 * phi[x1] * phi[x2] * y[x1] # N_f = g1 = g2 = t_f = 1 m_num = M2 * n # M2 * t_f / (n g1 g2) dist = float(np.linalg.norm(d)) m_lead = lead(dist, L) out(f" {str(d):15s} {dist:6.2f} {m_num: .6f} {m_lead: .6f} {m_num - m_lead: .2e}") if 4 <= dist <= L / 8: maxdev = max(maxdev, abs(m_num - m_lead)) out(f" max |m_num - m_lead| over 4 <= |d| <= L/8: {maxdev:.2e}") out("") out("== Square torus: m = M2 t_f/(n g1 g2) vs leading form (4.6): m_lead = -(1/pi)[ln(L/|d|) - kappa_2] ==") torus_table(2, [64, 128, 256], [2, 4, 8, 16, 32], [(1, 0), (1, 1), (2, 1)], lambda r, L: -(log(L / r) - kappa2) / pi) out("") out("== Cubic torus: m vs leading form (4.7): m_lead = -2[1/(4 pi |d|) + xi_3/L] ==") torus_table(3, [32, 48, 64], [2, 3, 4, 6, 8], [(1, 0, 0), (1, 1, 0), (1, 1, 1)], lambda r, L: -2 * (1 / (4 * pi * r) + xi3 / L)) (OUT / "second_order.txt").write_text("\n".join(LOG) + "\n", encoding="utf-8")