File size: 3,967 Bytes
2188a91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""Figures for the Theorem 3.1 audit (Claim 2)."""

import csv
import json

import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

RNG = np.random.default_rng(0)
LOG2PI = np.log(2 * np.pi)


def tcr(F, eps=0.5):
    k, d = F.shape
    Fn = F / np.linalg.norm(F, axis=1, keepdims=True)
    return float(-0.5 * np.linalg.slogdet(
        np.eye(k) + (d / (k * eps ** 2)) * (Fn @ Fn.T))[1])


def gauss_tc(cov):
    return float(0.5 * np.log(np.diag(cov)).sum() - 0.5 * np.linalg.slogdet(cov)[1])


k, d = 8, 128
rhos = np.linspace(0.0, 0.95, 40)
tcs, divs = [], []
for rho in rhos:
    cov = (1 - rho) * np.eye(k) + rho * np.ones((k, k))
    F = np.linalg.cholesky(cov) @ RNG.normal(size=(k, d))
    tcs.append(gauss_tc(np.cov(F)))
    divs.append(tcr(F))
tcs, divs = np.array(tcs), np.array(divs)

# panel B: MSE vs Gaussian ELBO (exact) and vs Laplace log-likelihood (control)
n, dd, s2, b = 20000, 6, 0.7, 0.6
x = RNG.normal(size=(n, dd))
scales = np.linspace(0.05, 2.0, 25)
mses, gll, lll = [], [], []
for s in scales:
    xh = x + s * RNG.normal(size=(n, dd))
    mses.append(float(((x - xh) ** 2).mean()))
    sq = ((x - xh) ** 2).sum(1)
    gll.append(float((-0.5 * dd * (LOG2PI + np.log(s2)) - sq / (2 * s2)).mean()))
    lll.append(float((-dd * np.log(2 * b) - np.abs(x - xh).sum(1) / b).mean()))
mses, gll, lll = np.array(mses), np.array(gll), np.array(lll)


def resid(xv, yv):
    A = np.vstack([xv, np.ones_like(xv)]).T
    c, *_ = np.linalg.lstsq(A, yv, rcond=None)
    return A @ c - yv


fig = make_subplots(
    rows=1, cols=2, horizontal_spacing=0.11,
    subplot_titles=(
        "Leg B β€” β„’_div tracks Total Correlation (r = 0.9995)",
        "Leg A β€” MSE ⇔ log-likelihood: exact for Gaussian, broken for Laplace"))

fig.add_scatter(x=tcs, y=divs, mode="markers", name="β„’_div vs TC (Gaussian latents)",
                marker=dict(size=8, color="#2F6F8F"), row=1, col=1)
A = np.vstack([tcs, np.ones_like(tcs)]).T
c, *_ = np.linalg.lstsq(A, divs, rcond=None)
fig.add_scatter(x=tcs, y=A @ c, mode="lines", name=f"best affine fit (slope {c[0]:.3f})",
                line=dict(color="#B07C2B", dash="dash"), row=1, col=1)
fig.update_xaxes(title_text="true Gaussian TC(Fβ€²) [nats]", row=1, col=1)
fig.update_yaxes(title_text="β„’_div  (Eq. 3)", row=1, col=1)

fig.add_scatter(x=mses, y=resid(mses, gll), mode="markers+lines",
                name="Gaussian decoder β€” residual from affine",
                marker=dict(size=7, color="#2F6F8F"), row=1, col=2)
fig.add_scatter(x=mses, y=resid(mses, lll), mode="markers+lines",
                name="Laplace decoder (CONTROL) β€” residual",
                marker=dict(size=7, color="#A33B3B"), row=1, col=2)
fig.update_xaxes(title_text="reconstruction MSE (β„’_rec)", row=1, col=2)
fig.update_yaxes(title_text="residual from best affine fit [nats]", row=1, col=2)

fig.update_layout(template="plotly_white", height=440,
                  legend=dict(orientation="h", y=-0.22),
                  title="Theorem 3.1 numerical audit β€” both legs, each with its control")
fig.write_html("results/claim2_theorem31.html", include_plotlyjs="cdn")

with open("results/claim2_theorem31.csv", "w", newline="") as fh:
    w = csv.writer(fh)
    w.writerow(["panel", "x", "y", "series"])
    for a, bb in zip(tcs, divs):
        w.writerow(["B_ldiv_vs_tc", f"{a:.6f}", f"{bb:.6f}", "ldiv"])
    rg, rl = resid(mses, gll), resid(mses, lll)
    for m, g, l in zip(mses, rg, rl):
        w.writerow(["A_residual", f"{m:.6f}", f"{g:.6e}", "gaussian"])
        w.writerow(["A_residual", f"{m:.6f}", f"{l:.6e}", "laplace_control"])

print(json.dumps({
    "ldiv_vs_tc_slope": float(c[0]),
    "ldiv_vs_tc_max_resid_nats": float(np.abs(A @ c - divs).max()),
    "gaussian_max_resid_nats": float(np.abs(resid(mses, gll)).max()),
    "laplace_control_max_resid_nats": float(np.abs(resid(mses, lll)).max()),
}, indent=2))
print("wrote results/claim2_theorem31.html + .csv")