Covariance-Adaptive Hermite Latent Bottleneck / verify.py
Mechanism confirmed, baseline not beaten
1import json, math
2import numpy as np
3from scipy.special import roots_hermitenorm, eval_hermitenorm
4from hermite_bottleneck import multi_indices, heat_identity_check
5
6
7def one_dim_coeffs(var, maxdeg, nodes=80):
8 # E_{N(0,var)}[He_k(X)/sqrt(k!)] by Gaussian quadrature.
9 x, wt = roots_hermitenorm(nodes)
10 wt = wt / math.sqrt(2 * math.pi)
11 y = math.sqrt(var) * x
12 return np.array([np.sum(wt * eval_hermitenorm(k, y)) / math.sqrt(math.factorial(k))
13 for k in range(maxdeg + 1)])
14
15
16def exact_report(vars_, maxdeg=12):
17 d = len(vars_)
18 one = [one_dim_coeffs(v, maxdeg) for v in vars_]
19 allidx = multi_indices(d, maxdeg)
20 coeff = np.array([np.prod([one[j][a[j]] for j in range(d)]) for a in allidx])
21 # Parseval norm of the density ratio, computed independently in closed form.
22 S = np.diag(vars_)
23 norm2 = np.linalg.det(S) ** -1 * np.linalg.det(2*np.linalg.inv(S)-np.eye(d)) ** -.5
24 rows = []
25 for N in range(maxdeg + 1):
26 keep = np.array([sum(a) <= N for a in allidx])
27 err = math.sqrt(max(0., norm2 - float(np.sum(coeff[keep]**2)))) / math.sqrt(norm2)
28 rows.append((N, int(keep.sum()), err))
29 q = max(abs(v - 1) for v in vars_)
30 return q, norm2, rows
31
32
33def run():
34 rng = np.random.default_rng(11)
35 # The semigroup formula is checked independently by Monte Carlo.
36 heat = heat_identity_check(rng, n=12, nz=12)
37 cases = [[1.04, .97, 1.01, .99], [1.20, .82, 1.08, .94],
38 [1.55, .62, 1.18, .88]]
39 reports = []
40 for v in cases:
41 q, norm2, rows = exact_report(v)
42 reports.append({'variances': v, 'q': q, 'norm2': norm2,
43 'curve': [{'degree': n, 'coefficients': k, 'relative_tail': e}
44 for n,k,e in rows]})
45 # Fit the observed geometric envelope on degrees 2..8; report ratios rather than
46 # asserting a universal constant (the statement allows C(Sigma,u,d)).
47 ratios = []
48 for r in reports:
49 q = r['q']
50 for row in r['curve']:
51 if row['relative_tail'] > 1e-12 and q > 0:
52 ratios.append(row['relative_tail'] / q**((row['degree']+1)/2))
53 # Practical degree choice using a conservative empirical C from all cases.
54 C = max(ratios)
55 target = .08
56 for r in reports:
57 q = r['q']
58 chosen = next((x['degree'] for x in r['curve'] if C*q**((x['degree']+1)/2) <= target), 12)
59 r['chosen_degree'] = chosen
60 r['chosen_coefficients'] = next(x['coefficients'] for x in r['curve'] if x['degree']==chosen)
61 r['chosen_tail'] = next(x['relative_tail'] for x in r['curve'] if x['degree']==chosen)
62 fixed = next(x for x in r['curve'] if x['degree']==4)
63 r['fixed_degree_4_tail'] = fixed['relative_tail']
64 r['fixed_degree_4_coefficients'] = fixed['coefficients']
65 return {'heat_relative_error': heat, 'empirical_envelope_C': C,
66 'target': target, 'reports': reports}
67
68if __name__ == '__main__':
69 print(json.dumps(run(), indent=2))