Teleporting Simplicial Diffusion Layer / verify_and_report.py

Failed on benchmark

Raw ⬇ ZIP
 1import json
 2import numpy as np
 3from teleport_simplicial import (
 4    cyclic_triangle_incidence, local_operator, teleport, nonprincipal_radius,
 5    mfpt_to_target, run_experiment,
 6)
 7
 8
 9def main():
10    out = run_experiment(seed=7)
11    n = out['n']
12    A = cyclic_triangle_incidence(n)
13    P0 = local_operator(A, self_loop=0.1)
14    alphas = np.array([x[0] for x in out['spectral']])
15
16    # Structural checks: incidence has three faces per triangle and P is stochastic.
17    assert np.all(A.sum(axis=0) == 3)
18    assert np.allclose(P0.sum(axis=1), 1.0)
19    assert np.min(P0) >= 0
20
21    # Prediction 1: uniform teleportation gives rho(P_alpha)=rho(P0)*(1-alpha).
22    rho0 = out['rho0']
23    observed = np.array([x[1] for x in out['spectral']])
24    predicted = rho0 * (1 - alphas)
25    spectral_max_error = float(np.max(np.abs(observed - predicted)))
26    assert spectral_max_error < 1e-10
27
28    # Prediction 2: global teleportation monotonically reduces target MFPT.
29    mfpt = np.array([x[1] for x in out['mfpt']])
30    assert np.all(np.diff(mfpt) < 0)
31
32    # A direct mixing prediction: on any mean-zero eigenmode, m-step norm scales
33    # as [rho(P0)*(1-alpha)]^m.  Numerically use the slowest eigenvector.
34    vals, vecs = np.linalg.eig(P0)
35    k = np.argsort(np.abs(vals - 1))[-1]  # not used; select largest nonprincipal below
36    order = np.argsort(-np.abs(vals))
37    k = next(i for i in order if abs(vals[i] - 1) > 1e-8)
38    v = np.real(vecs[:, k]); v -= v.mean(); v /= np.linalg.norm(v)
39    m = 12
40    mixing_rows = []
41    for a in alphas:
42        P = teleport(P0, float(a))
43        actual = np.linalg.norm(np.linalg.matrix_power(P, m) @ v)
44        pred = (rho0 * (1-a)) ** m
45        mixing_rows.append([float(a), float(actual), float(pred)])
46    mixing_max_error = float(max(abs(x[1]-x[2]) for x in mixing_rows))
47    assert mixing_max_error < 1e-8
48
49    report = {
50        'spectral_prediction': {
51            'prediction': 'rho_alpha / rho_0 = 1-alpha',
52            'max_abs_error': spectral_max_error,
53            'rows_alpha_observed_predicted': [
54                [float(a), float(o), float(p)] for a, o, p in zip(alphas, observed, predicted)
55            ],
56        },
57        'mfpt_prediction': {
58            'prediction': 'mean MFPT to target decreases with alpha',
59            'rows_alpha_mean_mfpt': [[float(a), float(t)] for a, t in zip(alphas, mfpt)],
60        },
61        'mixing_prediction': {
62            'prediction': 'm-step slow-mode norm = [rho_0(1-alpha)]^m, m=12',
63            'max_abs_error': mixing_max_error,
64            'rows_alpha_observed_predicted': mixing_rows,
65        },
66        'classification': {
67            'prediction': 'teleportation can improve delayed global classification but oversmooths features',
68            'rows_alpha_accuracy_feature_std': out['classification'],
69        },
70    }
71    with open('results.json', 'w') as f:
72        json.dump(report, f, indent=2)
73    print(json.dumps(report, indent=2))
74
75
76if __name__ == '__main__':
77    main()