summaryrefslogtreecommitdiff
path: root/logs
diff options
context:
space:
mode:
Diffstat (limited to 'logs')
-rw-r--r--logs/battery2.log6
-rw-r--r--logs/control.log4
-rw-r--r--logs/control_probe.py93
-rw-r--r--logs/fgw_alpha_control.log4
-rw-r--r--logs/fgw_alpha_lean.log71
-rw-r--r--logs/fgw_alpha_mech.log12
-rw-r--r--logs/lean.log71
-rw-r--r--logs/lean_probe.py84
-rw-r--r--logs/mech.log11
-rw-r--r--logs/mech.py51
-rw-r--r--logs/verify.py59
11 files changed, 466 insertions, 0 deletions
diff --git a/logs/battery2.log b/logs/battery2.log
index bfde59c..a0b3a2a 100644
--- a/logs/battery2.log
+++ b/logs/battery2.log
@@ -22,3 +22,9 @@
GW kl-loss raw=0.2161 refined=0.2513 (0.1s)
/home/yurenh2/.local/lib/python3.13/site-packages/ot/bregman/_sinkhorn.py:642: UserWarning: Warning: numerical errors at iteration 24
warnings.warn("Warning: numerical errors at iteration %d" % ii)
+ entropic GW deep anneal raw=0.0078 refined=0.0130 (554.8s)
+ semirelaxed GW raw=0.0156 refined=0.0443 (38.9s)
+
+=== synth-full-BOUND0.99 (N=256, chance=0.0039)
+ GW x12 restarts raw=0.3698 refined=0.3971 (12.3s)
+ GW kl-loss raw=0.0846 refined=0.0885 (13.9s)
diff --git a/logs/control.log b/logs/control.log
new file mode 100644
index 0000000..de41a42
--- /dev/null
+++ b/logs/control.log
@@ -0,0 +1,4 @@
+{"trial": 0, "cost": "tlb", "mode": "cold", "E_truth": 0.339629709924146, "blind_refined": 0.0234375, "blind_alpha": 1.0, "blind_E": 0.6228801020056084, "oracle_refined": 0.08203125, "curve": [0.0781, 0.0234, 0.0117, 0.0273, 0.0742, 0.0352, 0.0664, 0.0352, 0.082, 0.0, 0.0547, 0.0234]}
+{"trial": 0, "cost": "tlb", "mode": "warm", "E_truth": 0.339629709924146, "blind_refined": 0.84765625, "blind_alpha": 0.2, "blind_E": 0.339629709924146, "oracle_refined": 0.84765625, "curve": [0.0781, 0.8281, 0.8477, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398]}
+{"trial": 0, "cost": "tlbperm", "mode": "cold", "E_truth": 0.339629709924146, "blind_refined": 0.02734375, "blind_alpha": 0.95, "blind_E": 0.6074469738905559, "oracle_refined": 0.078125, "curve": [0.0117, 0.0117, 0.043, 0.0781, 0.0078, 0.0352, 0.0156, 0.0156, 0.0039, 0.0078, 0.0273, 0.0234]}
+{"trial": 0, "cost": "tlbperm", "mode": "warm", "E_truth": 0.339629709924146, "blind_refined": 0.03125, "blind_alpha": 1.0, "blind_E": 0.7038378812415739, "oracle_refined": 0.04296875, "curve": [0.0117, 0.043, 0.0234, 0.0234, 0.043, 0.0391, 0.0391, 0.0391, 0.0312, 0.0312, 0.0312, 0.0312]}
diff --git a/logs/control_probe.py b/logs/control_probe.py
new file mode 100644
index 0000000..170d731
--- /dev/null
+++ b/logs/control_probe.py
@@ -0,0 +1,93 @@
+"""Control: is the FGW warm-homotopy win driven by TLB *information*, or by any
+linear term at all (generic symmetry-breaking)? Three linear costs:
+
+ tlb -- the proposed distance-profile cost
+ tlbperm -- the same matrix with its columns randomly permuted: identical
+ value distribution, correspondence information destroyed
+ rand -- iid uniform noise cost
+
+Plus 3 trials, cold and warm sweeps, blind selection by E(P).
+"""
+from __future__ import annotations
+import json, sys, time
+sys.path.insert(0, "/home/yurenh2/emm")
+import numpy as np, ot, torch
+from scipy.optimize import linear_sum_assignment
+from worldalign.synth_fast_gate import ClosedFormEnergy, fast_pair_descent
+from worldalign.synth_triangle_gate import standardized
+
+DEV = torch.device("cuda:1")
+ALPHAS = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 1.0]
+
+
+def standardise(m):
+ mask = ~np.eye(len(m), dtype=bool); v = m[mask]
+ o = (m - v.mean()) / v.std(); np.fill_diagonal(o, 0.0); return o
+
+
+def tlb(V, S):
+ n = len(V); a = np.sort(V, 1); b = np.sort(S, 1)
+ return (a * a).sum(1)[:, None] / n + (b * b).sum(1)[None, :] / n - 2 * (a @ b.T) / n
+
+
+def main():
+ path = "/home/yurenh2/emm/artifacts/synth_v1/omit_size.pt"
+ st = torch.load(path, map_location="cpu", weights_only=False)
+ V = standardise(st["visual_field"].double().numpy())
+ T = standardise(st["text_field"].double().numpy())
+ n = len(V); w = ot.unif(n)
+ rows = []
+ for trial in range(3):
+ rng = np.random.default_rng(trial); hid = rng.permutation(n)
+ S = T[np.ix_(hid, hid)]
+ Vg = standardized(torch.from_numpy(V).to(DEV)).double()
+ Sg = standardized(torch.from_numpy(S).to(DEV)).double()
+ en = ClosedFormEnergy(Sg, Vg, 1.0, 0.0, 64)
+ et = float(en.energy(torch.from_numpy(
+ np.ascontiguousarray(np.argsort(hid))).to(DEV)[None])[0])
+
+ def acc(c): return float((hid[c] == np.arange(n)).mean())
+
+ def refine(c):
+ f = fast_pair_descent(Sg, Vg,
+ torch.from_numpy(np.ascontiguousarray(c)).to(DEV),
+ 600).cpu().numpy()
+ e = float(en.energy(torch.from_numpy(np.ascontiguousarray(f)).to(DEV)[None])[0])
+ return e, acc(f)
+
+ base = tlb(V, S)
+ shuf = np.random.default_rng(100 + trial).permutation(n)
+ variants = {
+ "tlb": base / base.max(),
+ "tlbperm": base[:, shuf] / base.max(),
+ "rand": np.random.default_rng(200 + trial).random((n, n)),
+ }
+ for vname, M in variants.items():
+ for mode in ("cold", "warm"):
+ G = np.outer(w, w); recs = []
+ for a in ALPHAS:
+ g0 = None if mode == "cold" else G
+ G2 = ot.gromov.fused_gromov_wasserstein(
+ M, V, S, w, w, "square_loss", alpha=a, G0=g0,
+ max_iter=200, tol_rel=1e-9)
+ if mode == "warm":
+ G = G2
+ _, cols = linear_sum_assignment(-G2)
+ e, ar = refine(cols)
+ recs.append({"alpha": a, "raw": acc(cols), "refined": ar, "E": e})
+ best = min(recs, key=lambda x: x["E"])
+ row = {"trial": trial, "cost": vname, "mode": mode,
+ "E_truth": et, "blind_refined": best["refined"],
+ "blind_alpha": best["alpha"], "blind_E": best["E"],
+ "oracle_refined": max(x["refined"] for x in recs),
+ "curve": [round(x["refined"], 4) for x in recs]}
+ rows.append(row)
+ print(json.dumps(row), flush=True)
+ scratch = ("/tmp/claude-1273071/-home-yurenh2-emm/"
+ "bb97201d-d9b5-46e6-82fc-981d37e7ab98/scratchpad/")
+ json.dump(rows, open(scratch + "control.json", "w"))
+ print(json.dumps({"done": True}))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/logs/fgw_alpha_control.log b/logs/fgw_alpha_control.log
new file mode 100644
index 0000000..de41a42
--- /dev/null
+++ b/logs/fgw_alpha_control.log
@@ -0,0 +1,4 @@
+{"trial": 0, "cost": "tlb", "mode": "cold", "E_truth": 0.339629709924146, "blind_refined": 0.0234375, "blind_alpha": 1.0, "blind_E": 0.6228801020056084, "oracle_refined": 0.08203125, "curve": [0.0781, 0.0234, 0.0117, 0.0273, 0.0742, 0.0352, 0.0664, 0.0352, 0.082, 0.0, 0.0547, 0.0234]}
+{"trial": 0, "cost": "tlb", "mode": "warm", "E_truth": 0.339629709924146, "blind_refined": 0.84765625, "blind_alpha": 0.2, "blind_E": 0.339629709924146, "oracle_refined": 0.84765625, "curve": [0.0781, 0.8281, 0.8477, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398, 0.8398]}
+{"trial": 0, "cost": "tlbperm", "mode": "cold", "E_truth": 0.339629709924146, "blind_refined": 0.02734375, "blind_alpha": 0.95, "blind_E": 0.6074469738905559, "oracle_refined": 0.078125, "curve": [0.0117, 0.0117, 0.043, 0.0781, 0.0078, 0.0352, 0.0156, 0.0156, 0.0039, 0.0078, 0.0273, 0.0234]}
+{"trial": 0, "cost": "tlbperm", "mode": "warm", "E_truth": 0.339629709924146, "blind_refined": 0.03125, "blind_alpha": 1.0, "blind_E": 0.7038378812415739, "oracle_refined": 0.04296875, "curve": [0.0117, 0.043, 0.0234, 0.0234, 0.043, 0.0391, 0.0391, 0.0391, 0.0312, 0.0312, 0.0312, 0.0312]}
diff --git a/logs/fgw_alpha_lean.log b/logs/fgw_alpha_lean.log
new file mode 100644
index 0000000..0787289
--- /dev/null
+++ b/logs/fgw_alpha_lean.log
@@ -0,0 +1,71 @@
+# omit-size trial0 E_truth=0.3396
+ cold a=0.0 raw=0.0625 ref=0.0781 E=0.6734 (8.4s)
+ cold a=0.2 raw=0.0117 ref=0.0117 E=0.6397 (9.5s)
+ cold a=0.4 raw=0.0703 ref=0.0742 E=0.6363 (2.8s)
+ cold a=0.6 raw=0.0586 ref=0.0664 E=0.6366 (1.2s)
+ cold a=0.75 raw=0.0508 ref=0.0430 E=0.6678 (5.7s)
+ cold a=0.85 raw=0.0312 ref=0.0234 E=0.6678 (1.6s)
+ cold a=0.88 raw=0.0586 ref=0.0508 E=0.6401 (2.4s)
+ cold a=0.9 raw=0.0000 ref=0.0000 E=0.6654 (2.2s)
+ cold a=0.92 raw=0.0352 ref=0.0312 E=0.7672 (0.5s)
+ cold a=0.94 raw=0.1680 ref=0.1875 E=0.6087 (0.5s)
+ cold a=0.95 raw=0.0625 ref=0.0547 E=0.6642 (2.1s)
+ cold a=0.96 raw=0.0664 ref=0.0664 E=0.6551 (0.3s)
+ cold a=0.97 raw=0.8203 ref=0.8203 E=0.3396 (0.4s)
+ cold a=0.98 raw=0.0039 ref=0.0039 E=0.6459 (1.0s)
+ cold a=0.99 raw=0.0156 ref=0.0156 E=0.6409 (1.0s)
+ cold a=1.0 raw=0.0195 ref=0.0234 E=0.6229 (0.7s)
+ == cold: blind-by-E refined=0.8203 (alpha=0.97), oracle-best=0.8203
+ warm a=0.0 raw=0.0625 ref=0.0781 E=0.6734 (0.6s)
+ warm a=0.2 raw=0.8242 ref=0.8320 E=0.3396 (1.2s)
+ warm a=0.4 raw=0.8281 ref=0.8320 E=0.3396 (0.4s)
+ warm a=0.6 raw=0.8320 ref=0.8320 E=0.3396 (0.3s)
+ warm a=0.75 raw=0.8320 ref=0.8320 E=0.3396 (0.2s)
+ warm a=0.85 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.88 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.2s)
+ warm a=0.9 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.2s)
+ warm a=0.92 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.94 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.95 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.3s)
+ warm a=0.96 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.2s)
+ warm a=0.97 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.98 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.3s)
+ warm a=0.99 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=1.0 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.0s)
+ == warm: blind-by-E refined=0.8320 (alpha=0.2), oracle-best=0.8320
+# synth-full trial0 E_truth=0.1430
+ cold a=0.0 raw=0.2578 ref=0.8633 E=0.2199 (2.1s)
+ cold a=0.2 raw=0.9531 ref=0.9609 E=0.1425 (2.6s)
+ cold a=0.4 raw=0.9531 ref=0.9688 E=0.1425 (1.7s)
+ cold a=0.6 raw=0.9570 ref=0.9766 E=0.1425 (2.2s)
+ cold a=0.75 raw=0.9375 ref=0.9609 E=0.1425 (3.0s)
+ cold a=0.85 raw=0.9531 ref=0.9609 E=0.1425 (4.3s)
+ cold a=0.88 raw=0.9453 ref=0.9609 E=0.1425 (3.8s)
+ cold a=0.9 raw=0.9766 ref=0.9844 E=0.1425 (3.5s)
+ cold a=0.92 raw=0.9453 ref=0.9531 E=0.1425 (0.9s)
+ cold a=0.94 raw=0.9531 ref=0.9766 E=0.1425 (2.0s)
+ cold a=0.95 raw=0.9453 ref=0.9531 E=0.1425 (1.1s)
+ cold a=0.96 raw=0.9453 ref=0.9531 E=0.1425 (0.8s)
+ cold a=0.97 raw=0.9375 ref=0.9531 E=0.1425 (6.2s)
+ cold a=0.98 raw=0.3789 ref=0.3789 E=0.5018 (7.1s)
+ cold a=0.99 raw=0.4219 ref=0.4141 E=0.4734 (10.8s)
+ cold a=1.0 raw=0.3633 ref=0.3906 E=0.5082 (12.6s)
+ == cold: blind-by-E refined=0.9609 (alpha=0.2), oracle-best=0.9844
+ warm a=0.0 raw=0.2578 ref=0.8633 E=0.2199 (4.5s)
+ warm a=0.2 raw=0.9375 ref=0.9453 E=0.1425 (1.9s)
+ warm a=0.4 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (2.5s)
+ warm a=0.6 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.3s)
+ warm a=0.75 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (1.4s)
+ warm a=0.85 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.9s)
+ warm a=0.88 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.6s)
+ warm a=0.9 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.8s)
+ warm a=0.92 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (1.2s)
+ warm a=0.94 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.8s)
+ warm a=0.95 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.4s)
+ warm a=0.96 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.6s)
+ warm a=0.97 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.7s)
+ warm a=0.98 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.4s)
+ warm a=0.99 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.1s)
+ warm a=1.0 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.2s)
+ == warm: blind-by-E refined=0.9453 (alpha=0.2), oracle-best=0.9453
+{"done": true}
diff --git a/logs/fgw_alpha_mech.log b/logs/fgw_alpha_mech.log
new file mode 100644
index 0000000..0c3f85f
--- /dev/null
+++ b/logs/fgw_alpha_mech.log
@@ -0,0 +1,12 @@
+--- trial 0 E_truth=0.339630
+ tlb-vertex start=0.0586 | 1 power step ->0.0312 (E=0.7114) | 5 steps ->0.1719 (E=0.6409) | warm FGW ->0.8555 (E=0.3396)
+ random-vertex start=0.0000 | 1 power step ->0.0312 (E=0.7279) | 5 steps ->0.0781 (E=0.6819) | warm FGW ->0.8125 (E=0.3396)
+ grampa-vertex start=0.0156 | 1 power step ->0.0938 (E=0.7821) | 5 steps ->0.0469 (E=0.7049) | warm FGW ->0.8203 (E=0.3396)
+--- trial 1 E_truth=0.339630
+ tlb-vertex start=0.0508 | 1 power step ->0.0352 (E=0.7114) | 5 steps ->0.1836 (E=0.6409) | warm FGW ->0.8164 (E=0.3396)
+ random-vertex start=0.0039 | 1 power step ->0.0156 (E=0.7051) | 5 steps ->0.0195 (E=0.6692) | warm FGW ->0.0195 (E=0.6554)
+ grampa-vertex start=0.0195 | 1 power step ->0.0742 (E=0.7821) | 5 steps ->0.0547 (E=0.7049) | warm FGW ->0.8164 (E=0.3396)
+--- trial 2 E_truth=0.339630
+ tlb-vertex start=0.0430 | 1 power step ->0.0312 (E=0.7114) | 5 steps ->0.1797 (E=0.6409) | warm FGW ->0.8359 (E=0.3396)
+ random-vertex start=0.0000 | 1 power step ->0.0195 (E=0.7149) | 5 steps ->0.0117 (E=0.6700) | warm FGW ->0.0391 (E=0.6387)
+ grampa-vertex start=0.0156 | 1 power step ->0.0820 (E=0.7821) | 5 steps ->0.0508 (E=0.7049) | warm FGW ->0.8203 (E=0.3396)
diff --git a/logs/lean.log b/logs/lean.log
new file mode 100644
index 0000000..0787289
--- /dev/null
+++ b/logs/lean.log
@@ -0,0 +1,71 @@
+# omit-size trial0 E_truth=0.3396
+ cold a=0.0 raw=0.0625 ref=0.0781 E=0.6734 (8.4s)
+ cold a=0.2 raw=0.0117 ref=0.0117 E=0.6397 (9.5s)
+ cold a=0.4 raw=0.0703 ref=0.0742 E=0.6363 (2.8s)
+ cold a=0.6 raw=0.0586 ref=0.0664 E=0.6366 (1.2s)
+ cold a=0.75 raw=0.0508 ref=0.0430 E=0.6678 (5.7s)
+ cold a=0.85 raw=0.0312 ref=0.0234 E=0.6678 (1.6s)
+ cold a=0.88 raw=0.0586 ref=0.0508 E=0.6401 (2.4s)
+ cold a=0.9 raw=0.0000 ref=0.0000 E=0.6654 (2.2s)
+ cold a=0.92 raw=0.0352 ref=0.0312 E=0.7672 (0.5s)
+ cold a=0.94 raw=0.1680 ref=0.1875 E=0.6087 (0.5s)
+ cold a=0.95 raw=0.0625 ref=0.0547 E=0.6642 (2.1s)
+ cold a=0.96 raw=0.0664 ref=0.0664 E=0.6551 (0.3s)
+ cold a=0.97 raw=0.8203 ref=0.8203 E=0.3396 (0.4s)
+ cold a=0.98 raw=0.0039 ref=0.0039 E=0.6459 (1.0s)
+ cold a=0.99 raw=0.0156 ref=0.0156 E=0.6409 (1.0s)
+ cold a=1.0 raw=0.0195 ref=0.0234 E=0.6229 (0.7s)
+ == cold: blind-by-E refined=0.8203 (alpha=0.97), oracle-best=0.8203
+ warm a=0.0 raw=0.0625 ref=0.0781 E=0.6734 (0.6s)
+ warm a=0.2 raw=0.8242 ref=0.8320 E=0.3396 (1.2s)
+ warm a=0.4 raw=0.8281 ref=0.8320 E=0.3396 (0.4s)
+ warm a=0.6 raw=0.8320 ref=0.8320 E=0.3396 (0.3s)
+ warm a=0.75 raw=0.8320 ref=0.8320 E=0.3396 (0.2s)
+ warm a=0.85 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.88 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.2s)
+ warm a=0.9 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.2s)
+ warm a=0.92 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.94 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.95 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.3s)
+ warm a=0.96 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.2s)
+ warm a=0.97 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=0.98 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.3s)
+ warm a=0.99 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.1s)
+ warm a=1.0 raw=0.8320 ref=0.8320 E=0.3396 FROZEN (0.0s)
+ == warm: blind-by-E refined=0.8320 (alpha=0.2), oracle-best=0.8320
+# synth-full trial0 E_truth=0.1430
+ cold a=0.0 raw=0.2578 ref=0.8633 E=0.2199 (2.1s)
+ cold a=0.2 raw=0.9531 ref=0.9609 E=0.1425 (2.6s)
+ cold a=0.4 raw=0.9531 ref=0.9688 E=0.1425 (1.7s)
+ cold a=0.6 raw=0.9570 ref=0.9766 E=0.1425 (2.2s)
+ cold a=0.75 raw=0.9375 ref=0.9609 E=0.1425 (3.0s)
+ cold a=0.85 raw=0.9531 ref=0.9609 E=0.1425 (4.3s)
+ cold a=0.88 raw=0.9453 ref=0.9609 E=0.1425 (3.8s)
+ cold a=0.9 raw=0.9766 ref=0.9844 E=0.1425 (3.5s)
+ cold a=0.92 raw=0.9453 ref=0.9531 E=0.1425 (0.9s)
+ cold a=0.94 raw=0.9531 ref=0.9766 E=0.1425 (2.0s)
+ cold a=0.95 raw=0.9453 ref=0.9531 E=0.1425 (1.1s)
+ cold a=0.96 raw=0.9453 ref=0.9531 E=0.1425 (0.8s)
+ cold a=0.97 raw=0.9375 ref=0.9531 E=0.1425 (6.2s)
+ cold a=0.98 raw=0.3789 ref=0.3789 E=0.5018 (7.1s)
+ cold a=0.99 raw=0.4219 ref=0.4141 E=0.4734 (10.8s)
+ cold a=1.0 raw=0.3633 ref=0.3906 E=0.5082 (12.6s)
+ == cold: blind-by-E refined=0.9609 (alpha=0.2), oracle-best=0.9844
+ warm a=0.0 raw=0.2578 ref=0.8633 E=0.2199 (4.5s)
+ warm a=0.2 raw=0.9375 ref=0.9453 E=0.1425 (1.9s)
+ warm a=0.4 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (2.5s)
+ warm a=0.6 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.3s)
+ warm a=0.75 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (1.4s)
+ warm a=0.85 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.9s)
+ warm a=0.88 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.6s)
+ warm a=0.9 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.8s)
+ warm a=0.92 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (1.2s)
+ warm a=0.94 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.8s)
+ warm a=0.95 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.4s)
+ warm a=0.96 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.6s)
+ warm a=0.97 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.7s)
+ warm a=0.98 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.4s)
+ warm a=0.99 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.1s)
+ warm a=1.0 raw=0.9375 ref=0.9453 E=0.1425 FROZEN (0.2s)
+ == warm: blind-by-E refined=0.9453 (alpha=0.2), oracle-best=0.9453
+{"done": true}
diff --git a/logs/lean_probe.py b/logs/lean_probe.py
new file mode 100644
index 0000000..f3b394c
--- /dev/null
+++ b/logs/lean_probe.py
@@ -0,0 +1,84 @@
+"""Lean version: 15-alpha grid, TLB cost, cold vs warm, omit-size then synth-full."""
+from __future__ import annotations
+import json, sys, time
+sys.path.insert(0, "/home/yurenh2/emm")
+import numpy as np, ot, torch
+from scipy.optimize import linear_sum_assignment
+from worldalign.synth_fast_gate import ClosedFormEnergy, fast_pair_descent
+from worldalign.synth_triangle_gate import standardized
+
+DEV = torch.device("cuda:1")
+ALPHAS = [0.0, 0.2, 0.4, 0.6, 0.75, 0.85, 0.88, 0.90, 0.92, 0.94, 0.95,
+ 0.96, 0.97, 0.98, 0.99, 1.0]
+
+
+def standardise(m):
+ mask = ~np.eye(len(m), dtype=bool); v = m[mask]
+ o = (m - v.mean()) / v.std(); np.fill_diagonal(o, 0.0); return o
+
+
+def tlb(V, S):
+ n = len(V); a = np.sort(V, 1); b = np.sort(S, 1)
+ return (a * a).sum(1)[:, None] / n + (b * b).sum(1)[None, :] / n - 2 * (a @ b.T) / n
+
+
+def run(path, label, trial=0):
+ st = torch.load(path, map_location="cpu", weights_only=False)
+ V = standardise(st["visual_field"].double().numpy())
+ T = standardise(st["text_field"].double().numpy())
+ n = len(V); w = ot.unif(n)
+ rng = np.random.default_rng(trial); hid = rng.permutation(n)
+ S = T[np.ix_(hid, hid)]
+ Vg = standardized(torch.from_numpy(V).to(DEV)).double()
+ Sg = standardized(torch.from_numpy(S).to(DEV)).double()
+ en = ClosedFormEnergy(Sg, Vg, 1.0, 0.0, 64)
+ M = tlb(V, S); M = M / M.max()
+
+ def acc(c): return float((hid[c] == np.arange(n)).mean())
+
+ def refine(c):
+ f = fast_pair_descent(Sg, Vg, torch.from_numpy(np.ascontiguousarray(c)).to(DEV),
+ 600).cpu().numpy()
+ e = float(en.energy(torch.from_numpy(np.ascontiguousarray(f)).to(DEV)[None])[0])
+ return e, acc(f)
+
+ et = float(en.energy(torch.from_numpy(np.ascontiguousarray(np.argsort(hid))).to(DEV)[None])[0])
+ print(f"# {label} trial{trial} E_truth={et:.4f}", flush=True)
+
+ out = {"label": label, "E_truth": et, "cold": [], "warm": []}
+ for mode in ("cold", "warm"):
+ G = np.outer(w, w)
+ prev = None
+ for a in ALPHAS:
+ t0 = time.time()
+ g0 = None if mode == "cold" else G
+ G2 = ot.gromov.fused_gromov_wasserstein(M, V, S, w, w, "square_loss",
+ alpha=a, G0=g0, max_iter=200,
+ tol_rel=1e-9)
+ if mode == "warm":
+ G = G2
+ _, cols = linear_sum_assignment(-G2)
+ e, ar = refine(cols)
+ same = (prev is not None and np.array_equal(cols, prev))
+ prev = cols
+ rec = {"alpha": a, "raw": acc(cols), "refined": ar, "E": e,
+ "sec": round(time.time() - t0, 1), "same_as_prev": bool(same)}
+ out[mode].append(rec)
+ print(f" {mode} a={a:<5} raw={rec['raw']:.4f} ref={ar:.4f} E={e:.4f}"
+ f" {'FROZEN' if same else ''} ({rec['sec']}s)", flush=True)
+ good = out[mode]
+ best = min(good, key=lambda x: x["E"])
+ print(f" == {mode}: blind-by-E refined={best['refined']:.4f} (alpha={best['alpha']}),"
+ f" oracle-best={max(x['refined'] for x in good):.4f}", flush=True)
+ return out
+
+
+if __name__ == "__main__":
+ base = "/home/yurenh2/emm/artifacts/synth_v1/"
+ res = []
+ for p, l in [("omit_size.pt", "omit-size"), ("omit_none.pt", "synth-full")]:
+ res.append(run(base + p, l))
+ scratch = ("/tmp/claude-1273071/-home-yurenh2-emm/"
+ "bb97201d-d9b5-46e6-82fc-981d37e7ab98/scratchpad/")
+ json.dump(res, open(scratch + "lean.json", "w"))
+ print(json.dumps({"done": True}))
diff --git a/logs/mech.log b/logs/mech.log
new file mode 100644
index 0000000..817501a
--- /dev/null
+++ b/logs/mech.log
@@ -0,0 +1,11 @@
+--- trial 0 E_truth=0.339630
+ tlb-vertex start=0.0586 | 1 power step ->0.0312 (E=0.7114) | 5 steps ->0.1719 (E=0.6409) | warm FGW ->0.8555 (E=0.3396)
+ random-vertex start=0.0000 | 1 power step ->0.0312 (E=0.7279) | 5 steps ->0.0781 (E=0.6819) | warm FGW ->0.8125 (E=0.3396)
+ grampa-vertex start=0.0156 | 1 power step ->0.0938 (E=0.7821) | 5 steps ->0.0469 (E=0.7049) | warm FGW ->0.8203 (E=0.3396)
+--- trial 1 E_truth=0.339630
+ tlb-vertex start=0.0508 | 1 power step ->0.0352 (E=0.7114) | 5 steps ->0.1836 (E=0.6409) | warm FGW ->0.8164 (E=0.3396)
+ random-vertex start=0.0039 | 1 power step ->0.0156 (E=0.7051) | 5 steps ->0.0195 (E=0.6692) | warm FGW ->0.0195 (E=0.6554)
+ grampa-vertex start=0.0195 | 1 power step ->0.0742 (E=0.7821) | 5 steps ->0.0547 (E=0.7049) | warm FGW ->0.8164 (E=0.3396)
+--- trial 2 E_truth=0.339630
+ tlb-vertex start=0.0430 | 1 power step ->0.0312 (E=0.7114) | 5 steps ->0.1797 (E=0.6409) | warm FGW ->0.8359 (E=0.3396)
+ random-vertex start=0.0000 | 1 power step ->0.0195 (E=0.7149) | 5 steps ->0.0117 (E=0.6700) | warm FGW ->0.0391 (E=0.6387)
diff --git a/logs/mech.py b/logs/mech.py
new file mode 100644
index 0000000..6762777
--- /dev/null
+++ b/logs/mech.py
@@ -0,0 +1,51 @@
+import sys, numpy as np, ot, torch
+sys.path.insert(0,'/home/yurenh2/emm')
+from scipy.optimize import linear_sum_assignment
+from worldalign.synth_fast_gate import ClosedFormEnergy, fast_pair_descent
+from worldalign.synth_triangle_gate import standardized
+DEV=torch.device("cuda:1")
+def standardise(m):
+ mask=~np.eye(len(m),dtype=bool); v=m[mask]
+ o=(m-v.mean())/v.std(); np.fill_diagonal(o,0.0); return o
+def tlb(V,S):
+ n=len(V); a=np.sort(V,1); b=np.sort(S,1)
+ return (a*a).sum(1)[:,None]/n+(b*b).sum(1)[None,:]/n-2*(a@b.T)/n
+st=torch.load("/home/yurenh2/emm/artifacts/synth_v1/omit_size.pt",map_location='cpu',weights_only=False)
+V=standardise(st["visual_field"].double().numpy()); T=standardise(st["text_field"].double().numpy())
+n=len(V); w=ot.unif(n)
+for trial in range(3):
+ rng=np.random.default_rng(trial); hid=rng.permutation(n); S=T[np.ix_(hid,hid)]
+ Vg=standardized(torch.from_numpy(V).to(DEV)).double(); Sg=standardized(torch.from_numpy(S).to(DEV)).double()
+ en=ClosedFormEnergy(Sg,Vg,1.0,0.0,64)
+ Et=float(en.energy(torch.from_numpy(np.ascontiguousarray(np.argsort(hid))).to(DEV)[None])[0])
+ acc=lambda c: float((hid[c]==np.arange(n)).mean())
+ def refine(c,it=2000):
+ f=fast_pair_descent(Sg,Vg,torch.from_numpy(np.ascontiguousarray(c)).to(DEV),it).cpu().numpy()
+ return float(en.energy(torch.from_numpy(np.ascontiguousarray(f)).to(DEV)[None])[0]), acc(f)
+ M=tlb(V,S); M=M/M.max()
+ _,tlbcols=linear_sum_assignment(M)
+ def vert(cols):
+ P=np.zeros((n,n)); P[np.arange(n),cols]=1.0/n; return P
+ starts={"tlb-vertex":tlbcols,
+ "random-vertex":np.random.default_rng(50+trial).permutation(n),
+ "grampa-vertex":None}
+ from worldalign.spectral_match import grampa
+ starts["grampa-vertex"]=grampa(V,S,1.0)
+ print(f"--- trial {trial} E_truth={Et:.6f}")
+ for name,cols in starts.items():
+ # (i) pure power step: LSAP on gradient V P S (anchor-propagation, one round)
+ P=vert(cols); grad=V@P@S
+ _,c1=linear_sum_assignment(-grad)
+ e1,a1=refine(c1)
+ # (ii) 5 rounds of power step
+ c=cols.copy()
+ for _ in range(5):
+ P=vert(c); _,c=linear_sum_assignment(-(V@P@S))
+ e2,a2=refine(c)
+ # (iii) warm FGW at alpha=0.1 then 0.2 from this vertex
+ G=vert(cols)
+ for a in (0.1,0.2,0.5):
+ G=ot.gromov.fused_gromov_wasserstein(M,V,S,w,w,"square_loss",alpha=a,G0=G,max_iter=200,tol_rel=1e-9)
+ _,c3=linear_sum_assignment(-G); e3,a3=refine(c3)
+ print(" %-14s start=%.4f | 1 power step ->%.4f (E=%.4f) | 5 steps ->%.4f (E=%.4f) | warm FGW ->%.4f (E=%.4f)"
+ %(name,acc(cols),a1,e1,a2,e2,a3,e3), flush=True)
diff --git a/logs/verify.py b/logs/verify.py
new file mode 100644
index 0000000..17fd643
--- /dev/null
+++ b/logs/verify.py
@@ -0,0 +1,59 @@
+import sys, numpy as np, ot, torch
+sys.path.insert(0,'/home/yurenh2/emm')
+from scipy.optimize import linear_sum_assignment
+from worldalign.synth_fast_gate import ClosedFormEnergy, fast_pair_descent
+from worldalign.synth_triangle_gate import standardized
+DEV=torch.device("cuda:1")
+def standardise(m):
+ mask=~np.eye(len(m),dtype=bool); v=m[mask]
+ o=(m-v.mean())/v.std(); np.fill_diagonal(o,0.0); return o
+def tlb(V,S):
+ n=len(V); a=np.sort(V,1); b=np.sort(S,1)
+ return (a*a).sum(1)[:,None]/n+(b*b).sum(1)[None,:]/n-2*(a@b.T)/n
+st=torch.load("/home/yurenh2/emm/artifacts/synth_v1/omit_size.pt",map_location='cpu',weights_only=False)
+V=standardise(st["visual_field"].double().numpy()); T=standardise(st["text_field"].double().numpy())
+n=len(V); w=ot.unif(n)
+rng=np.random.default_rng(0); hid=rng.permutation(n); S=T[np.ix_(hid,hid)]
+Vg=standardized(torch.from_numpy(V).to(DEV)).double(); Sg=standardized(torch.from_numpy(S).to(DEV)).double()
+en=ClosedFormEnergy(Sg,Vg,1.0,0.0,64)
+M=tlb(V,S); M=M/M.max()
+G=np.outer(w,w)
+for a in (0.0,0.2):
+ G=ot.gromov.fused_gromov_wasserstein(M,V,S,w,w,"square_loss",alpha=a,G0=G,max_iter=200,tol_rel=1e-9)
+_,cols=linear_sum_assignment(-G)
+fin=fast_pair_descent(Sg,Vg,torch.from_numpy(np.ascontiguousarray(cols)).to(DEV),2000).cpu().numpy()
+truth=np.argsort(hid)
+Ef=float(en.energy(torch.from_numpy(np.ascontiguousarray(fin)).to(DEV)[None])[0])
+Et=float(en.energy(torch.from_numpy(np.ascontiguousarray(truth)).to(DEV)[None])[0])
+acc=float((hid[fin]==np.arange(n)).mean())
+print("accuracy=%.4f E_found=%.10f E_truth=%.10f diff=%.3e"%(acc,Ef,Et,Ef-Et))
+wrong=np.where(hid[fin]!=np.arange(n))[0]
+print("n_wrong=%d"%len(wrong))
+# for each wrong scene i: correlation between S-row of assigned node and S-row of true node
+Sal=S # in shuffled index space
+corr=[]
+vcorr=[]
+for i in wrong:
+ a_idx=fin[i]; t_idx=truth[i]
+ x=np.delete(Sal[a_idx],[a_idx,t_idx]); y=np.delete(Sal[t_idx],[a_idx,t_idx])
+ corr.append(np.corrcoef(x,y)[0,1])
+ u=np.delete(V[i],[i]);
+ # visual side: is the visually-assigned scene similar to i? compare V rows of i and of the scene truly at a_idx
+ j=hid[a_idx]
+ v1=np.delete(V[i],[i,j]); v2=np.delete(V[j],[i,j])
+ vcorr.append(np.corrcoef(v1,v2)[0,1])
+rng2=np.random.default_rng(7); pairs=rng2.integers(0,n,(len(wrong),2))
+base=[np.corrcoef(np.delete(Sal[p],[p,q]),np.delete(Sal[q],[p,q]))[0,1] for p,q in pairs if p!=q]
+print("text-row corr of confused partners: median=%.3f mean=%.3f | random pair baseline median=%.3f"%(np.median(corr),np.mean(corr),np.median(base)))
+print("visual-row corr of confused partners: median=%.3f"%np.median(vcorr))
+# cycle structure of the error
+perm=hid[fin]
+seen=set(); cyc=[]
+for i in range(n):
+ if i in seen or perm[i]==i: continue
+ c=0; j=i
+ while j not in seen:
+ seen.add(j); j=perm[j]; c+=1
+ cyc.append(c)
+import collections
+print("error cycle lengths:", dict(collections.Counter(cyc)))