SabaPivot commited on
Commit
ea3a71e
·
verified ·
1 Parent(s): 5baae82

Upgrade canonical logbook from stronger peer evidence with attribution

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +3 -0
  2. BUNDLE_SHA256SUMS.txt +55 -0
  3. SOURCE_PIN.txt +19 -0
  4. build_manifest.py +25 -0
  5. code/dpo_exp.py +164 -0
  6. code/dpo_exp2.py +108 -0
  7. code/dpo_exp4.py +81 -0
  8. code/dpo_real.py +72 -0
  9. code/fed_real.py +195 -0
  10. code/fed_topo.py +48 -0
  11. index.html +1 -31
  12. logbook.css +270 -810
  13. logbook.js +664 -1364
  14. logbook.json +32 -50
  15. official_claims.json +8 -0
  16. outputs/SHA256SUMS.json +12 -0
  17. outputs/corollary_5_2_full_participation.csv +13 -0
  18. outputs/dec_dpo_topology.csv +5 -0
  19. outputs/distributed_dpo_audit.png +3 -0
  20. outputs/fed_dpo_shp_ablations.csv +10 -0
  21. outputs/results.json +56 -0
  22. outputs/shp_inventory.csv +601 -0
  23. outputs/source_claim_audit.csv +7 -0
  24. outputs/theorem_5_1_partial_bound.csv +37 -0
  25. outputs/theorem_5_4_staleness.csv +16 -0
  26. outputs/theorem_5_5_lower_bound.csv +21 -0
  27. outputs_distilgpt2_results.json +109 -0
  28. packaged_replay/SHA256SUMS.json +12 -0
  29. packaged_replay/corollary_5_2_full_participation.csv +13 -0
  30. packaged_replay/dec_dpo_topology.csv +5 -0
  31. packaged_replay/distributed_dpo_audit.png +3 -0
  32. packaged_replay/fed_dpo_shp_ablations.csv +10 -0
  33. packaged_replay/results.json +56 -0
  34. packaged_replay/shp_inventory.csv +601 -0
  35. packaged_replay/source_claim_audit.csv +7 -0
  36. packaged_replay/theorem_5_1_partial_bound.csv +37 -0
  37. packaged_replay/theorem_5_4_staleness.csv +16 -0
  38. packaged_replay/theorem_5_5_lower_bound.csv +21 -0
  39. pages/claim-1-feddpo-partial-participation-bound/page.md +0 -835
  40. pages/claim-1/page.md +16 -0
  41. pages/claim-2-full-participation-corollary/page.md +0 -21
  42. pages/claim-2/page.md +51 -0
  43. pages/claim-3-staleness-penalty/page.md +0 -19
  44. pages/claim-3/page.md +15 -0
  45. pages/claim-4-feddpo-lower-bound/page.md +0 -19
  46. pages/claim-4/page.md +17 -0
  47. pages/claim-5-decdpo-spectral-rate/page.md +0 -48
  48. pages/claim-5/page.md +58 -0
  49. pages/claim-6-shp-numerical-results/page.md +0 -2080
  50. pages/claim-6/page.md +18 -0
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ outputs/distributed_dpo_audit.png filter=lfs diff=lfs merge=lfs -text
37
+ packaged_replay/distributed_dpo_audit.png filter=lfs diff=lfs merge=lfs -text
38
+ source_paper_v1.pdf filter=lfs diff=lfs merge=lfs -text
BUNDLE_SHA256SUMS.txt ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 57fb181e40cfc722c6fb81d3f3fd1ce2bc3a29e3d60a2cb5fdaf9f9cfbbd2dde .gitattributes
2
+ c1b53249c4f7ce68a3693ea44c6238bb53a475841244718a7a66b8fc07cae677 README.md
3
+ f6cedefc0c2ca62164392c882a33752a3f6098771f652c2a4f21ff76271bb28d SOURCE_PIN.txt
4
+ d1c28fc0a4e07f2688d013f576cf76ffc422d278d56a52a82989e0b93b3b3964 bucket-icon.svg
5
+ fd58d689f2b3ead6c81790fdad30c60cea11168781ed7472db49b180511961aa build_manifest.py
6
+ c98b5fca6ca5fdeb2035e42cd8601273d6d7d7e32aa85edd1697192fd22d9423 index.html
7
+ 64e1de4358c79ec0d5f2697c56f98258c025e992c94ad7b3b7801739222ca41d logbook.css
8
+ 69d73869184f936613668569980f31984be65229e77c4df4ba9604d3de70c02b logbook.js
9
+ 3179eb3f236fb3de113177cd698c971fb01d492ce5c9579f6149cf6477d03f82 logbook.json
10
+ 0af23030e58c13d4b830c921071545c856841d08290fa9cedb9a5efdf8d3a9c8 official_claims.json
11
+ b04a57a18be1c38f89b91bf627addd888145768e2abc8d06d9cb512841d84b61 outputs/SHA256SUMS.json
12
+ ff2d4278b79e9fdf103a48f907d694a11e39eda0369daf6076f0e269da141b86 outputs/corollary_5_2_full_participation.csv
13
+ 691bdcc6ae25aa25d6598dbf87ad060255e9a0f802e03341da6a30eeb362b2ba outputs/dec_dpo_topology.csv
14
+ c08e9e3b7baf8e05e4a4190efd714a72d9122fd3cd4ecd645d640a9aea6ca1e4 outputs/distributed_dpo_audit.png
15
+ 31bfaabea77d3022b17e469b7b9f546a2fec8c40431b8177d1cf077ac06a9718 outputs/fed_dpo_shp_ablations.csv
16
+ bb7e2073a3d41e3c2fdb957ab423ee83a367d3fe1badcf5fbcb98e516a9b707b outputs/results.json
17
+ 6460bb569c5ac46a0509503168290bb4b2bb03a5e6f566f282d0fe5a183e7732 outputs/shp_inventory.csv
18
+ c8464ba0cf666528438250e6fd581271d770a4c136c6a55377ca3361fd42b8e4 outputs/source_claim_audit.csv
19
+ 9accf57701e23d9e172978f895d6faf38f2a12f150d968d2ead593d3304fb896 outputs/theorem_5_1_partial_bound.csv
20
+ be181a404639b2722e3a7905df2d4faf8bfb8e562ee42277b8e32652b724fdc1 outputs/theorem_5_4_staleness.csv
21
+ 8fc7b9c6775c5d7846a474089c727d0ae8a1de3bcf5db1abf76914e74878ad6d outputs/theorem_5_5_lower_bound.csv
22
+ b04a57a18be1c38f89b91bf627addd888145768e2abc8d06d9cb512841d84b61 packaged_replay/SHA256SUMS.json
23
+ ff2d4278b79e9fdf103a48f907d694a11e39eda0369daf6076f0e269da141b86 packaged_replay/corollary_5_2_full_participation.csv
24
+ 691bdcc6ae25aa25d6598dbf87ad060255e9a0f802e03341da6a30eeb362b2ba packaged_replay/dec_dpo_topology.csv
25
+ c08e9e3b7baf8e05e4a4190efd714a72d9122fd3cd4ecd645d640a9aea6ca1e4 packaged_replay/distributed_dpo_audit.png
26
+ 31bfaabea77d3022b17e469b7b9f546a2fec8c40431b8177d1cf077ac06a9718 packaged_replay/fed_dpo_shp_ablations.csv
27
+ bb7e2073a3d41e3c2fdb957ab423ee83a367d3fe1badcf5fbcb98e516a9b707b packaged_replay/results.json
28
+ 6460bb569c5ac46a0509503168290bb4b2bb03a5e6f566f282d0fe5a183e7732 packaged_replay/shp_inventory.csv
29
+ c8464ba0cf666528438250e6fd581271d770a4c136c6a55377ca3361fd42b8e4 packaged_replay/source_claim_audit.csv
30
+ 9accf57701e23d9e172978f895d6faf38f2a12f150d968d2ead593d3304fb896 packaged_replay/theorem_5_1_partial_bound.csv
31
+ be181a404639b2722e3a7905df2d4faf8bfb8e562ee42277b8e32652b724fdc1 packaged_replay/theorem_5_4_staleness.csv
32
+ 8fc7b9c6775c5d7846a474089c727d0ae8a1de3bcf5db1abf76914e74878ad6d packaged_replay/theorem_5_5_lower_bound.csv
33
+ 6379c8503f5c65d9e2b93470c536eca65c5e09226575fdd10271397e6b4564f0 pages/claim-1/page.md
34
+ 685ff891925636f2aa4be58f35a4d5c592d95f6032769a961eac84c33924780c pages/claim-2/page.md
35
+ 9aa313c243acadc5ef58ef9c2a25ec700901fc49838c62fde069fed204661f74 pages/claim-3/page.md
36
+ 8604f4459c68b2fec97507d5ba65d8233bea1b560aa80c792b3149a59ca64ff0 pages/claim-4/page.md
37
+ 738b622f53e7c74dbf4baa7df092781a762e1e756f80966d84c95d439db42a48 pages/claim-5/page.md
38
+ 8ae4a4cbda7ea4b592fad7c3e0d501b189622517e25f8deebc11ebf22f5be092 pages/claim-6/page.md
39
+ e6ebdd5af0f3a32ba8008ee547317cbbcb0d8106914ee0de3e90809b9ca18840 pages/conclusion/page.md
40
+ a3bc10f7407532aeb494acd7ca5b67e1ca1c6327cdcda0c92e985ec1ede203b7 pages/executive-summary/page.md
41
+ c1b9a6862a1aa5e83eab3ea0c531c9fcee4723f98ad10866a10451552d90c8bd pages/index.md
42
+ f12f45b28a79c2f5c45fbdfeadcfbbbba0235bc03bf07a5268df59231d4422c5 poster_embed.html
43
+ 3360c577746f955e3a1bc80846b47b564626fe9aae443734d9ccaaded82afd51 reproduce.py
44
+ 5bdf2ac2751a991c55ca60844df521b6cd2bf249fb68179624c684d4eb416988 requirements.txt
45
+ ba49c5332c94e438dfa575c84d8389f32464b941b973a96a0120052c05d676fe shp_rows_0.json
46
+ 3f4a7d7e1540b8b53ccf5f05d79de799de24a93fb0d4496fa2e9f842f2b28ac8 shp_rows_100.json
47
+ 57d07b51e1498f272feefcc9d9886d65e0730c47ad474537d58b633bf89ea52c shp_rows_200.json
48
+ 01fa42003ab85554ff3d55d6152ecebb6775a835df6cef10acf13ca2792fdf8d shp_rows_300.json
49
+ 31ada479d91a26ccc0ceadda09a1c2b3e97fa03ae1bc43784225dd3609cd4ea7 shp_rows_400.json
50
+ 17a8823add2699a4cbdcaab5e886926d37f9367b247a58534f9edcbed086ee39 shp_rows_500.json
51
+ 43d8384c31b601422addeba43f148391e8cf39f756a28a72fb9c4ec316b48ec4 source_archive_v1.tar
52
+ ce6faba012d2e862d59aa6d5a05fccf6f004e331d4769ae95607ec63483904c5 source_paper_v1.pdf
53
+ a6eb72253c0128ce79b526a86b7943eed37beec186b5f57ff6c1701d0e9ff596 trackio-logo-light.png
54
+ 3e3792061d4d095759da30d7cfe7f14b621901793cd4d677b61b2896f5bf472b trackio-logo.png
55
+ 71da94795855710d214801eb9b9b7b8898e9a8757abac0e22966a0531bbb2f4f trackio-wordmark-dark.png
SOURCE_PIN.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Paper: Distributed Direct Preference Optimization
2
+ OpenReview: ljNZyrAlaa
3
+ arXiv: 2605.20696v1 (only revision at audit time)
4
+ PDF SHA-256: ce6faba012d2e862d59aa6d5a05fccf6f004e331d4769ae95607ec63483904c5
5
+ source archive SHA-256: 43d8384c31b601422addeba43f148391e8cf39f756a28a72fb9c4ec316b48ec4
6
+
7
+ Stanford Human Preferences rows 0..599 from the Hugging Face datasets server:
8
+ rows 0-99 SHA-256: ba49c5332c94e438dfa575c84d8389f32464b941b973a96a0120052c05d676fe
9
+ rows 100-199 SHA-256: 3f4a7d7e1540b8b53ccf5f05d79de799de24a93fb0d4496fa2e9f842f2b28ac8
10
+ rows 200-299 SHA-256: 57d07b51e1498f272feefcc9d9886d65e0730c47ad474537d58b633bf89ea52c
11
+ rows 300-399 SHA-256: 01fa42003ab85554ff3d55d6152ecebb6775a835df6cef10acf13ca2792fdf8d
12
+ rows 400-499 SHA-256: 31ada479d91a26ccc0ceadda09a1c2b3e97fa03ae1bc43784225dd3609cd4ea7
13
+ rows 500-599 SHA-256: 17a8823add2699a4cbdcaab5e886926d37f9367b247a58534f9edcbed086ee39
14
+
15
+ The sole revision matches every live theorem number. Scope retained:
16
+ Corollary 5.2 removes partial-participation amplification but retains averaged-
17
+ client variance; Theorem 5.4 assumes bounded drift; Theorem 5.5 is a
18
+ constructed DPO-like family; and Theorem 6.1 assumes symmetric doubly
19
+ stochastic mixing.
build_manifest.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import hashlib
5
+ from pathlib import Path
6
+
7
+
8
+ ROOT = Path(__file__).resolve().parent
9
+ OUT = ROOT / "BUNDLE_SHA256SUMS.txt"
10
+
11
+
12
+ def digest(path: Path) -> str:
13
+ h = hashlib.sha256()
14
+ with path.open("rb") as handle:
15
+ for block in iter(lambda: handle.read(1 << 20), b""):
16
+ h.update(block)
17
+ return h.hexdigest()
18
+
19
+
20
+ rows = []
21
+ for path in sorted(ROOT.rglob("*")):
22
+ if path.is_file() and path != OUT and "__pycache__" not in path.parts:
23
+ rows.append(f"{digest(path)} {path.relative_to(ROOT).as_posix()}")
24
+ OUT.write_text("\n".join(rows) + "\n", encoding="utf-8")
25
+ print(f"wrote {len(rows)} entries to {OUT.name}")
code/dpo_exp.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Sharper tests for FedDPO / DecDPO convergence claims: fitted rate exponents
2
+ and parameter-free ratio checks, at larger scale than the first pass.
3
+
4
+ Log-linear DPO: reward r(x) = theta^T phi(x); on a preference pair (w, l) the
5
+ loss is -log sigmoid(beta (r_w - r_l)). Clients hold heterogeneous preference
6
+ data generated by client-specific ground-truth rewards.
7
+ """
8
+ import json
9
+ import numpy as np
10
+
11
+ RESULTS = {}
12
+ D, BETA = 32, 1.0
13
+
14
+
15
+ def make_clients(N, kappa, seed, n_per=200):
16
+ rng = np.random.default_rng(seed)
17
+ base = rng.normal(size=D); base /= np.linalg.norm(base)
18
+ cl = []
19
+ for i in range(N):
20
+ t = base + kappa * rng.normal(size=D) / np.sqrt(D)
21
+ t /= np.linalg.norm(t)
22
+ W = rng.normal(size=(n_per, D)); L = rng.normal(size=(n_per, D))
23
+ flip = (W - L) @ t < 0
24
+ W2 = np.where(flip[:, None], L, W); L2 = np.where(flip[:, None], W, L)
25
+ cl.append((W2, L2, t))
26
+ return cl, base
27
+
28
+
29
+ def grad(th, W, L):
30
+ z = BETA * ((W - L) @ th)
31
+ s = 1.0 / (1.0 + np.exp(z))
32
+ return -BETA * ((W - L) * s[:, None]).mean(axis=0)
33
+
34
+
35
+ def loss(th, cl):
36
+ tot = 0.0
37
+ for W, L, _ in cl:
38
+ z = BETA * ((W - L) @ th)
39
+ tot += float(np.mean(np.log1p(np.exp(-z))))
40
+ return tot / len(cl)
41
+
42
+
43
+ def fed_dpo(cl, R=200, E=5, S=None, lr=0.5, q_max=0, seed=0):
44
+ N = len(cl); S = S or N
45
+ rng = np.random.default_rng(seed)
46
+ th = np.zeros(D); buf = {}
47
+ hist = []
48
+ for r in range(R):
49
+ sel = rng.choice(N, size=S, replace=False)
50
+ deltas = []
51
+ for i in sel:
52
+ local = th.copy()
53
+ for _ in range(E):
54
+ local -= lr * grad(local, cl[i][0], cl[i][1])
55
+ d = local - th
56
+ delay = int(rng.integers(0, q_max + 1)) if q_max else 0
57
+ buf.setdefault(r + delay, []).append(d)
58
+ for d in buf.pop(r, []):
59
+ deltas.append(d)
60
+ if deltas:
61
+ th = th + np.mean(deltas, axis=0)
62
+ hist.append(loss(th, cl))
63
+ return np.array(hist)
64
+
65
+
66
+ def metropolis(adj):
67
+ n = adj.shape[0]; deg = adj.sum(1)
68
+ Wm = np.zeros((n, n))
69
+ for i in range(n):
70
+ for j in range(n):
71
+ if i != j and adj[i, j]:
72
+ Wm[i, j] = 1.0 / (1 + max(deg[i], deg[j]))
73
+ Wm[i, i] = 1 - Wm[i].sum()
74
+ ev = np.sort(np.abs(np.linalg.eigvals(Wm)))[::-1]
75
+ return Wm, float(ev[1])
76
+
77
+
78
+ def dec_dpo(cl, Wm, R=200, E=5, lr=0.5):
79
+ N = len(cl)
80
+ TH = np.zeros((N, D)); hist = []
81
+ for r in range(R):
82
+ for i in range(N):
83
+ for _ in range(E):
84
+ TH[i] -= lr * grad(TH[i], cl[i][0], cl[i][1])
85
+ TH = Wm @ TH
86
+ hist.append(float(np.mean(np.linalg.norm(TH - TH.mean(0), axis=1))))
87
+ return np.array(hist)
88
+
89
+
90
+ def claim2_participation():
91
+ rows = []
92
+ N = 20
93
+ cl, _ = make_clients(N, 0.8, seed=1)
94
+ for S in (2, 5, 10, 20):
95
+ finals = [fed_dpo(cl, R=150, S=S, seed=100 + s)[-20:].mean() for s in range(5)]
96
+ var = [np.var(fed_dpo(cl, R=150, S=S, seed=200 + s)[-20:]) for s in range(5)]
97
+ rows.append({"S": S, "N": N, "final_loss": float(np.mean(finals)),
98
+ "tail_variance": float(np.mean(var)),
99
+ "one_over_S": 1.0 / S})
100
+ print(" S=%-3d final loss=%.6f tail var=%.3e (1/S=%.3f)" %
101
+ (S, rows[-1]["final_loss"], rows[-1]["tail_variance"], 1.0 / S), flush=True)
102
+ ls = np.log([r["one_over_S"] for r in rows]); lv = np.log([max(r["tail_variance"], 1e-16) for r in rows])
103
+ RESULTS["claim2_participation"] = {
104
+ "rows": rows, "loglog_slope_var_vs_1_over_S": round(float(np.polyfit(ls, lv, 1)[0]), 4),
105
+ "var_ratio_S2_over_SN": round(rows[0]["tail_variance"] / max(rows[-1]["tail_variance"], 1e-16), 2)}
106
+ print(" variance slope vs 1/S = %.3f ; S=2 vs S=N ratio = %.1fx" %
107
+ (RESULTS["claim2_participation"]["loglog_slope_var_vs_1_over_S"],
108
+ RESULTS["claim2_participation"]["var_ratio_S2_over_SN"]), flush=True)
109
+
110
+
111
+ def claim3_staleness():
112
+ rows = []
113
+ cl, _ = make_clients(10, 0.8, seed=3)
114
+ for q in (0, 1, 2, 5, 10):
115
+ f = [fed_dpo(cl, R=150, q_max=q, seed=300 + s)[-20:].mean() for s in range(5)]
116
+ rows.append({"q_max": q, "final_loss": float(np.mean(f)),
117
+ "sd": float(np.std(f))})
118
+ print(" q_max=%-3d final loss=%.6f +- %.6f" % (q, rows[-1]["final_loss"], rows[-1]["sd"]), flush=True)
119
+ base = rows[0]["final_loss"]
120
+ RESULTS["claim3_staleness"] = {
121
+ "rows": rows, "monotone_in_q": all(rows[i+1]["final_loss"] >= rows[i]["final_loss"] - 1e-9
122
+ for i in range(len(rows) - 1)),
123
+ "penalty_at_qmax10": round(rows[-1]["final_loss"] - base, 6)}
124
+
125
+
126
+ def claim5_topology():
127
+ N = 8
128
+ cl, _ = make_clients(N, 0.8, seed=5)
129
+ tops = {}
130
+ ring = np.zeros((N, N), int)
131
+ for i in range(N):
132
+ ring[i, (i + 1) % N] = ring[(i + 1) % N, i] = 1
133
+ tops["ring"] = ring
134
+ star = np.zeros((N, N), int); star[0, 1:] = star[1:, 0] = 1
135
+ tops["star"] = star
136
+ full = np.ones((N, N), int) - np.eye(N, dtype=int)
137
+ tops["complete"] = full
138
+ path = np.zeros((N, N), int)
139
+ for i in range(N - 1):
140
+ path[i, i + 1] = path[i + 1, i] = 1
141
+ tops["path"] = path
142
+ rows = []
143
+ for name, adj in tops.items():
144
+ Wm, rho = metropolis(adj)
145
+ h = dec_dpo(cl, Wm, R=120)
146
+ rows.append({"topology": name, "rho": round(rho, 4),
147
+ "one_over_1_minus_rho2": round(1.0 / (1 - rho ** 2), 3),
148
+ "final_consensus_error": float(h[-1]),
149
+ "mean_tail_consensus": float(h[-20:].mean())})
150
+ print(" %-9s rho=%.4f 1/(1-rho^2)=%8.2f consensus err=%.4e" %
151
+ (name, rho, rows[-1]["one_over_1_minus_rho2"], rows[-1]["mean_tail_consensus"]), flush=True)
152
+ x = np.log([r["one_over_1_minus_rho2"] for r in rows])
153
+ y = np.log([max(r["mean_tail_consensus"], 1e-16) for r in rows])
154
+ sl, ic = np.polyfit(x, y, 1)
155
+ r2 = 1 - np.var(y - (sl * x + ic)) / np.var(y)
156
+ RESULTS["claim5_topology"] = {"rows": rows,
157
+ "loglog_slope_consensus_vs_1_over_1_minus_rho2": round(float(sl), 4),
158
+ "r2": round(float(r2), 4)}
159
+ print(" consensus error vs 1/(1-rho^2): slope %.3f, R2 %.3f" % (sl, r2), flush=True)
160
+
161
+
162
+ if __name__ == "__main__":
163
+ claim2_participation(); claim3_staleness(); claim5_topology()
164
+ json.dump(RESULTS, open("dpo_results.json", "w"), indent=1)
code/dpo_exp2.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Redesigned tests: remove the two confounds in the first pass.
2
+
3
+ Claim 2 (partial participation contributes a variance term that vanishes at S=N):
4
+ measure the variance of the ITERATE across seeds, not of the loss, and compare
5
+ against the finite-population correction (N-S)/(S(N-1)), which is the exact
6
+ sampling variance of a mean over S of N units drawn without replacement.
7
+ S=N is reported separately as an exact-zero check (no fit).
8
+
9
+ Claim 5 (DecDPO consensus error grows with the spectral gap):
10
+ sweep rho CONTINUOUSLY on a FIXED graph with a FIXED client assignment using
11
+ lazy mixing W_a = (1-a) I + a W, so the only thing that changes is rho.
12
+ Any confound from topology structure or heterogeneity layout is eliminated.
13
+ """
14
+ import json
15
+ import numpy as np
16
+ from dpo_exp import make_clients, grad, metropolis, D
17
+
18
+ RESULTS = {}
19
+
20
+
21
+ def fed_iterate(cl, R, S, lr=0.5, E=5, seed=0):
22
+ N = len(cl); rng = np.random.default_rng(seed)
23
+ th = np.zeros(D)
24
+ for _ in range(R):
25
+ sel = rng.choice(N, size=S, replace=False)
26
+ ds = []
27
+ for i in sel:
28
+ loc = th.copy()
29
+ for _ in range(E):
30
+ loc -= lr * grad(loc, cl[i][0], cl[i][1])
31
+ ds.append(loc - th)
32
+ th = th + np.mean(ds, axis=0)
33
+ return th
34
+
35
+
36
+ def claim2():
37
+ N, R = 20, 120
38
+ cl, _ = make_clients(N, 0.8, seed=1)
39
+ rows = []
40
+ for S in (2, 4, 5, 10, 20):
41
+ TH = np.array([fed_iterate(cl, R, S, seed=1000 + s) for s in range(24)])
42
+ var = float(np.trace(np.cov(TH.T)))
43
+ fpc = (N - S) / (S * (N - 1))
44
+ rows.append({"S": S, "N": N, "iterate_variance": var,
45
+ "finite_pop_correction_(N-S)/(S(N-1))": round(fpc, 6),
46
+ "ratio_var_over_fpc": round(var / fpc, 6) if fpc > 0 else None})
47
+ print(" S=%-3d Var(theta)=%.4e (N-S)/(S(N-1))=%.5f ratio=%s" %
48
+ (S, var, fpc, rows[-1]["ratio_var_over_fpc"]), flush=True)
49
+ part = [r for r in rows if r["S"] < N]
50
+ x = np.log([r["finite_pop_correction_(N-S)/(S(N-1))"] for r in part])
51
+ y = np.log([r["iterate_variance"] for r in part])
52
+ sl, ic = np.polyfit(x, y, 1)
53
+ r2 = 1 - np.var(y - (sl * x + ic)) / np.var(y)
54
+ ratios = [r["ratio_var_over_fpc"] for r in part]
55
+ RESULTS["claim2"] = {
56
+ "rows": rows, "seeds_per_cell": 24, "rounds": R,
57
+ "loglog_slope_vs_finite_pop_correction": round(float(sl), 4),
58
+ "predicted_slope": 1.0, "r2": round(float(r2), 4),
59
+ "proportionality_const_spread": round(max(ratios) / min(ratios), 3),
60
+ "variance_at_S_equals_N": rows[-1]["iterate_variance"],
61
+ "vanishes_at_full_participation": bool(rows[-1]["iterate_variance"] < 1e-20)}
62
+ print(" fit slope %.3f (predicted 1.0), R2 %.3f ; const spread %.2fx ; Var(S=N)=%.2e" %
63
+ (sl, r2, RESULTS["claim2"]["proportionality_const_spread"],
64
+ rows[-1]["iterate_variance"]), flush=True)
65
+
66
+
67
+ def dec_consensus(cl, Wm, R=200, E=5, lr=0.5):
68
+ N = len(cl); TH = np.zeros((N, D))
69
+ for _ in range(R):
70
+ for i in range(N):
71
+ for _ in range(E):
72
+ TH[i] -= lr * grad(TH[i], cl[i][0], cl[i][1])
73
+ TH = Wm @ TH
74
+ return float(np.mean(np.linalg.norm(TH - TH.mean(0), axis=1)))
75
+
76
+
77
+ def claim5():
78
+ N = 8
79
+ cl, _ = make_clients(N, 0.8, seed=5)
80
+ ring = np.zeros((N, N), int)
81
+ for i in range(N):
82
+ ring[i, (i + 1) % N] = ring[(i + 1) % N, i] = 1
83
+ W0, _ = metropolis(ring)
84
+ rows = []
85
+ for a in (1.0, 0.8, 0.6, 0.45, 0.3, 0.2, 0.12):
86
+ Wm = (1 - a) * np.eye(N) + a * W0
87
+ rho = float(np.sort(np.abs(np.linalg.eigvals(Wm)))[::-1][1])
88
+ err = dec_consensus(cl, Wm, R=250)
89
+ rows.append({"lazy_alpha": a, "rho": round(rho, 5),
90
+ "one_over_1_minus_rho": round(1 / (1 - rho), 3),
91
+ "steady_state_consensus_error": err})
92
+ print(" alpha=%.2f rho=%.5f 1/(1-rho)=%7.2f consensus err=%.5e" %
93
+ (a, rho, rows[-1]["one_over_1_minus_rho"], err), flush=True)
94
+ x = np.log([r["one_over_1_minus_rho"] for r in rows])
95
+ y = np.log([r["steady_state_consensus_error"] for r in rows])
96
+ sl, ic = np.polyfit(x, y, 1)
97
+ r2 = 1 - np.var(y - (sl * x + ic)) / np.var(y)
98
+ RESULTS["claim5"] = {
99
+ "graph": "8-node ring, fixed client assignment, lazy mixing sweeps rho",
100
+ "rows": rows, "rounds": 250,
101
+ "loglog_slope_vs_1_over_1_minus_rho": round(float(sl), 4),
102
+ "r2": round(float(r2), 4)}
103
+ print(" consensus error vs 1/(1-rho): slope %.3f, R2 %.4f" % (sl, r2), flush=True)
104
+
105
+
106
+ if __name__ == "__main__":
107
+ claim2(); claim5()
108
+ json.dump(RESULTS, open("dpo_results2.json", "w"), indent=1)
code/dpo_exp4.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Claim 5, corrected: constant step size + local steps gives a BIASED fixed
2
+ point, so the gap plateaus and the stated O(1/sqrt(R)) rate cannot appear.
3
+ Use the decaying schedule the rate assumes, lr_r = lr0/sqrt(r), and measure the
4
+ gap against the true pooled optimum (found by direct minimisation).
5
+ """
6
+ import json
7
+ import numpy as np
8
+ from dpo_exp import make_clients, grad, metropolis, loss, D, BETA
9
+
10
+ RESULTS = {}
11
+
12
+
13
+ def pooled_opt(cl, iters=8000):
14
+ th = np.zeros(D)
15
+ for t in range(1, iters + 1):
16
+ g = np.mean([grad(th, W, L) for W, L, _ in cl], axis=0)
17
+ th -= (2.0 / np.sqrt(t)) * g
18
+ return th, loss(th, cl)
19
+
20
+
21
+ def dec_gap(cl, Wm, marks, E=5, lr0=1.0):
22
+ N = len(cl); TH = np.zeros((N, D)); out = {}
23
+ ms = set(marks)
24
+ for r in range(1, max(marks) + 1):
25
+ lr = lr0 / np.sqrt(r)
26
+ for i in range(N):
27
+ for _ in range(E):
28
+ TH[i] -= lr * grad(TH[i], cl[i][0], cl[i][1])
29
+ TH = Wm @ TH
30
+ if r in ms:
31
+ out[r] = loss(TH.mean(0), cl)
32
+ return out
33
+
34
+
35
+ def run():
36
+ N = 8
37
+ cl, _ = make_clients(N, 0.8, seed=5)
38
+ _, star = pooled_opt(cl)
39
+ print(" pooled optimum loss = %.8f" % star, flush=True)
40
+ ring = np.zeros((N, N), int)
41
+ for i in range(N):
42
+ ring[i, (i + 1) % N] = ring[(i + 1) % N, i] = 1
43
+ W0, _ = metropolis(ring)
44
+ Rs = [25, 50, 100, 200, 400, 800]
45
+ rows = []
46
+ for a in (1.0, 0.6, 0.3, 0.15):
47
+ Wm = (1 - a) * np.eye(N) + a * W0
48
+ rho = float(np.sort(np.abs(np.linalg.eigvals(Wm)))[::-1][1])
49
+ g = dec_gap(cl, Wm, Rs)
50
+ gaps = np.array([max(g[r] - star, 1e-14) for r in Rs])
51
+ A = np.stack([1 / np.sqrt(Rs), 1 / (np.array(Rs) * (1 - rho ** 2))], axis=1)
52
+ coef, *_ = np.linalg.lstsq(A, gaps, rcond=None)
53
+ r2 = 1 - np.var(gaps - A @ coef) / np.var(gaps)
54
+ # also: pure 1/sqrt(R) slope, to show the sqrt term is the asymptote
55
+ sl = float(np.polyfit(np.log(Rs), np.log(gaps), 1)[0])
56
+ rows.append({"lazy_alpha": a, "rho": round(rho, 5),
57
+ "one_minus_rho2": round(1 - rho ** 2, 5),
58
+ "c1_sqrtR": round(float(coef[0]), 6),
59
+ "c2_transient": round(float(coef[1]), 6),
60
+ "two_term_fit_r2": round(float(r2), 5),
61
+ "raw_loglog_slope_gap_vs_R": round(sl, 4),
62
+ "gaps": {str(r): round(float(x), 8) for r, x in zip(Rs, gaps)}})
63
+ print(" alpha=%.2f rho=%.4f 1-rho^2=%.4f c1=%.5f c2=%.5f R2=%.4f raw slope=%.3f" %
64
+ (a, rho, 1 - rho ** 2, coef[0], coef[1], r2, sl), flush=True)
65
+ c2 = [r["c2_transient"] for r in rows]
66
+ pos = all(x > 0 for x in c2)
67
+ RESULTS["claim5_rate_decomposition"] = {
68
+ "pooled_optimum_loss": star, "R_grid": Rs, "step_size": "lr_r = 1/sqrt(r)",
69
+ "rows": rows,
70
+ "all_c2_positive": pos,
71
+ "c2_spread_max_over_min": round(max(c2) / min(c2), 3) if pos else None,
72
+ "all_fits_above_r2_0.99": all(r["two_term_fit_r2"] > 0.99 for r in rows),
73
+ "mean_raw_slope": round(float(np.mean([r["raw_loglog_slope_gap_vs_R"] for r in rows])), 4)}
74
+ print(" c2: %s ; all positive=%s ; mean raw slope %.3f (predicted -0.5)" %
75
+ ([round(x, 4) for x in c2], pos,
76
+ RESULTS["claim5_rate_decomposition"]["mean_raw_slope"]), flush=True)
77
+
78
+
79
+ if __name__ == "__main__":
80
+ run()
81
+ json.dump(RESULTS, open("dpo_results4.json", "w"), indent=1)
code/dpo_real.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Federated / decentralized DPO on the paper's actual setup: DistilGPT-2 (82M)
2
+ trained with the true DPO loss on Stanford Human Preferences pairs, split across
3
+ N=5 clients. This replaces the 64-dim log-linear proxy used previously.
4
+ """
5
+ import os, json, time, math, copy, argparse
6
+ import numpy as np, torch, torch.nn.functional as F
7
+ from transformers import AutoTokenizer, AutoModelForCausalLM
8
+
9
+ DEV = "mps" if torch.backends.mps.is_available() else "cpu"
10
+ BETA = 0.1
11
+ MODEL = "distilgpt2"
12
+
13
+
14
+ def load_pairs(n_pairs, maxlen=128, seed=0):
15
+ from datasets import load_dataset
16
+ ds = load_dataset("stanfordnlp/SHP", split="train", streaming=True)
17
+ tok = AutoTokenizer.from_pretrained(MODEL)
18
+ tok.pad_token = tok.eos_token
19
+ out, it = [], iter(ds)
20
+ while len(out) < n_pairs:
21
+ try: r = next(it)
22
+ except StopIteration: break
23
+ a, b = r["human_ref_A"], r["human_ref_B"]
24
+ w, l = (a, b) if r["labels"] == 1 else (b, a)
25
+ p = "Q: " + r["history"][:400] + "\nA:"
26
+ pw = tok(p + " " + w[:400], truncation=True, max_length=maxlen)["input_ids"]
27
+ pl = tok(p + " " + l[:400], truncation=True, max_length=maxlen)["input_ids"]
28
+ np_ = len(tok(p, truncation=True, max_length=maxlen)["input_ids"])
29
+ if len(pw) > np_ + 2 and len(pl) > np_ + 2:
30
+ out.append({"w": pw, "l": pl, "np": np_, "domain": r["domain"]})
31
+ return out, tok
32
+
33
+
34
+ def batch_logps(model, seqs, nps, pad):
35
+ L = max(len(s) for s in seqs)
36
+ ids = torch.full((len(seqs), L), pad, dtype=torch.long)
37
+ msk = torch.zeros((len(seqs), L), dtype=torch.bool)
38
+ for i, s in enumerate(seqs):
39
+ ids[i, :len(s)] = torch.tensor(s); msk[i, nps[i]:len(s)] = True
40
+ ids, msk = ids.to(DEV), msk.to(DEV)
41
+ logits = model(ids).logits[:, :-1]
42
+ tgt, m = ids[:, 1:], msk[:, 1:]
43
+ lp = torch.log_softmax(logits.float(), -1).gather(2, tgt.unsqueeze(-1)).squeeze(-1)
44
+ return (lp * m).sum(-1)
45
+
46
+
47
+ def dpo_loss(model, ref, batch, pad):
48
+ sw = [b["w"] for b in batch]; sl = [b["l"] for b in batch]
49
+ nw = [b["np"] for b in batch]; nl = [b["np"] for b in batch]
50
+ pw = batch_logps(model, sw, nw, pad); pl = batch_logps(model, sl, nl, pad)
51
+ with torch.no_grad():
52
+ rw = batch_logps(ref, sw, nw, pad); rl = batch_logps(ref, sl, nl, pad)
53
+ logits = BETA * ((pw - rw) - (pl - rl))
54
+ acc = (logits > 0).float().mean().item()
55
+ return -F.logsigmoid(logits).mean(), acc
56
+
57
+
58
+ if __name__ == "__main__":
59
+ t0 = time.time()
60
+ pairs, tok = load_pairs(40)
61
+ print("loaded %d pairs in %.1fs; domains=%s" % (len(pairs), time.time()-t0,
62
+ sorted({p['domain'] for p in pairs})[:5]), flush=True)
63
+ m = AutoModelForCausalLM.from_pretrained(MODEL).to(DEV)
64
+ ref = AutoModelForCausalLM.from_pretrained(MODEL).to(DEV).eval()
65
+ for p in ref.parameters(): p.requires_grad_(False)
66
+ opt = torch.optim.SGD(m.parameters(), lr=1e-4)
67
+ t0 = time.time()
68
+ for step in range(5):
69
+ loss, acc = dpo_loss(m, ref, pairs[step*4:(step+1)*4], tok.pad_token_id)
70
+ opt.zero_grad(); loss.backward(); opt.step()
71
+ print(" step %d loss=%.4f acc=%.2f (%.2fs)" % (step, loss.item(), acc, time.time()-t0), flush=True)
72
+ print("per-step: %.2fs on %s" % ((time.time()-t0)/5, DEV))
code/fed_real.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FedDPO / DecDPO on DistilGPT-2 (82M) with real SHP preference pairs,
2
+ non-IID split across N=5 clients by SHP domain (the paper's heterogeneity).
3
+
4
+ Design notes that make the theorems actually testable:
5
+ * Each client's batch sequence is fixed by its own seed, so with FULL
6
+ participation (S=N) the whole round is deterministic. Corollary 5.2 predicts
7
+ the partial-participation variance term vanishes at S=N -- here that becomes
8
+ an EXACT zero-variance check, not a noisy approximation.
9
+ * Client sampling uses a separate RNG, so S<N runs differ only in WHICH
10
+ clients are sampled -- isolating the 1/S term from data-order noise.
11
+ """
12
+ import json, time, copy, itertools
13
+ import numpy as np, torch, torch.nn.functional as F
14
+ from transformers import AutoTokenizer, AutoModelForCausalLM
15
+ from dpo_real import batch_logps, dpo_loss, DEV, MODEL, BETA
16
+
17
+ N_CLIENTS, E_DEF, R_DEF, BS = 5, 2, 40, 4
18
+ RES = {}
19
+
20
+
21
+ def build_clients(n_per_domain=90):
22
+ from datasets import load_dataset
23
+ ds = load_dataset("stanfordnlp/SHP", split="train", streaming=True)
24
+ tok = AutoTokenizer.from_pretrained(MODEL); tok.pad_token = tok.eos_token
25
+ doms, want = {}, N_CLIENTS
26
+ for r in itertools.islice(ds, 400000):
27
+ d = r["domain"]
28
+ if d not in doms and len(doms) >= want: continue
29
+ b = doms.setdefault(d, [])
30
+ if len(b) >= n_per_domain:
31
+ if all(len(v) >= n_per_domain for v in doms.values()) and len(doms) >= want: break
32
+ continue
33
+ a, bb = r["human_ref_A"], r["human_ref_B"]
34
+ w, l = (a, bb) if r["labels"] == 1 else (bb, a)
35
+ p = "Q: " + r["history"][:400] + "\nA:"
36
+ pw = tok(p + " " + w[:400], truncation=True, max_length=128)["input_ids"]
37
+ pl = tok(p + " " + l[:400], truncation=True, max_length=128)["input_ids"]
38
+ npr = len(tok(p, truncation=True, max_length=128)["input_ids"])
39
+ if len(pw) > npr + 2 and len(pl) > npr + 2:
40
+ b.append({"w": pw, "l": pl, "np": npr})
41
+ names = sorted(doms)[:N_CLIENTS]
42
+ return [doms[d] for d in names], names, tok
43
+
44
+
45
+ def flat(m): return torch.cat([p.detach().reshape(-1) for p in m.parameters()])
46
+ def setflat(m, v):
47
+ i = 0
48
+ for p in m.parameters():
49
+ n = p.numel(); p.data.copy_(v[i:i+n].view_as(p)); i += n
50
+
51
+
52
+ def local_train(model, ref, data, E, lr, pad, rng):
53
+ opt = torch.optim.SGD(model.parameters(), lr=lr)
54
+ for _ in range(E):
55
+ idx = rng.integers(0, len(data), size=BS)
56
+ loss, _ = dpo_loss(model, ref, [data[i] for i in idx], pad)
57
+ opt.zero_grad(); loss.backward(); opt.step()
58
+
59
+
60
+ def evaluate(model, ref, clients, pad, nb=3):
61
+ tot, acc, k = 0.0, 0.0, 0
62
+ with torch.no_grad():
63
+ for d in clients:
64
+ for j in range(nb):
65
+ l, a = dpo_loss(model, ref, d[j*BS:(j+1)*BS], pad)
66
+ tot += l.item(); acc += a; k += 1
67
+ return tot/k, acc/k
68
+
69
+
70
+ def fed_run(base, ref, clients, tok, S, R=R_DEF, E=E_DEF, lr=2e-5, q_max=0, seed=0):
71
+ m = copy.deepcopy(base).to(DEV)
72
+ th = flat(m).clone()
73
+ samp = np.random.default_rng(10_000 + seed)
74
+ crngs = [np.random.default_rng(777 + i) for i in range(len(clients))] # fixed per client
75
+ dly = np.random.default_rng(50_000 + seed)
76
+ buf = {}
77
+ for r in range(R):
78
+ sel = samp.choice(len(clients), size=S, replace=False) if S < len(clients) else np.arange(len(clients))
79
+ for i in sel:
80
+ setflat(m, th)
81
+ local_train(m, ref, clients[i], E, lr, tok.pad_token_id, crngs[i])
82
+ d = flat(m) - th
83
+ k = r + (int(dly.integers(0, q_max+1)) if q_max else 0)
84
+ buf.setdefault(k, []).append(d)
85
+ ds = buf.pop(r, [])
86
+ if ds: th = th + torch.stack(ds).mean(0)
87
+ setflat(m, th)
88
+ return m, th
89
+
90
+
91
+ def metropolis(adj):
92
+ n = adj.shape[0]; deg = adj.sum(1); W = np.zeros((n, n))
93
+ for i in range(n):
94
+ for j in range(n):
95
+ if i != j and adj[i, j]: W[i, j] = 1.0/(1+max(deg[i], deg[j]))
96
+ W[i, i] = 1 - W[i].sum()
97
+ return W, float(np.sort(np.abs(np.linalg.eigvals(W)))[::-1][1])
98
+
99
+
100
+ def dec_run(base, ref, clients, tok, W, R=R_DEF, E=E_DEF, lr=2e-5):
101
+ n = len(clients)
102
+ m = copy.deepcopy(base).to(DEV)
103
+ TH = torch.stack([flat(m).clone() for _ in range(n)])
104
+ crngs = [np.random.default_rng(777+i) for i in range(n)]
105
+ Wt = torch.tensor(W, dtype=TH.dtype, device=TH.device)
106
+ for r in range(R):
107
+ new = []
108
+ for i in range(n):
109
+ setflat(m, TH[i]); local_train(m, ref, clients[i], E, lr, tok.pad_token_id, crngs[i])
110
+ new.append(flat(m).clone())
111
+ TH = Wt @ torch.stack(new)
112
+ cons = float(torch.norm(TH - TH.mean(0, keepdim=True), dim=1).mean())
113
+ setflat(m, TH.mean(0))
114
+ return m, cons
115
+
116
+
117
+ def main():
118
+ t0 = time.time()
119
+ clients, names, tok = build_clients()
120
+ print("clients:", [(n, len(d)) for n, d in zip(names, clients)], flush=True)
121
+ base = AutoModelForCausalLM.from_pretrained(MODEL)
122
+ ref = AutoModelForCausalLM.from_pretrained(MODEL).to(DEV).eval()
123
+ for p in ref.parameters(): p.requires_grad_(False)
124
+ pad = tok.pad_token_id
125
+ l0, a0 = evaluate(base.to(DEV), ref, clients, pad)
126
+ RES["init"] = {"loss": l0, "acc": a0, "clients": dict(zip(names, [len(d) for d in clients]))}
127
+ print("init loss=%.4f acc=%.3f" % (l0, a0), flush=True)
128
+
129
+ # ---- Claim 2: participation sweep, variance of the global model ----
130
+ rows = []
131
+ for S in (1, 2, 3, 5):
132
+ ths, ls = [], []
133
+ for s in range(3):
134
+ m, th = fed_run(base, ref, clients, tok, S, seed=s)
135
+ l, a = evaluate(m, ref, clients, pad); ths.append(th); ls.append(l)
136
+ print(" S=%d seed=%d loss=%.4f acc=%.3f (%.0fs)" % (S, s, l, a, time.time()-t0), flush=True)
137
+ TH = torch.stack(ths)
138
+ var = float((TH - TH.mean(0, keepdim=True)).pow(2).sum(1).mean())
139
+ fpc = (N_CLIENTS-S)/(S*(N_CLIENTS-1))
140
+ rows.append({"S": S, "param_variance": var, "fpc": round(fpc, 5),
141
+ "ratio": (var/fpc if fpc > 0 else None),
142
+ "loss_mean": float(np.mean(ls)), "loss_sd": float(np.std(ls))})
143
+ print(" S=%d Var=%.4e fpc=%.4f loss=%.4f+-%.4f" % (S, var, fpc, np.mean(ls), np.std(ls)), flush=True)
144
+ RES["claim2_participation"] = {"rows": rows}
145
+ json.dump(RES, open("fed_real_results.json", "w"), indent=1)
146
+
147
+ # ---- Claim 3: staleness ----
148
+ rows = []
149
+ for q in (0, 2, 5):
150
+ ls = []
151
+ for s in range(2):
152
+ m, _ = fed_run(base, ref, clients, tok, N_CLIENTS, q_max=q, seed=s)
153
+ l, a = evaluate(m, ref, clients, pad); ls.append(l)
154
+ rows.append({"q_max": q, "loss_mean": float(np.mean(ls)), "loss_sd": float(np.std(ls))})
155
+ print(" q_max=%d loss=%.5f+-%.5f (%.0fs)" % (q, np.mean(ls), np.std(ls), time.time()-t0), flush=True)
156
+ RES["claim3_staleness"] = {"rows": rows,
157
+ "monotone": all(rows[i+1]["loss_mean"] >= rows[i]["loss_mean"]-1e-9 for i in range(len(rows)-1))}
158
+ json.dump(RES, open("fed_real_results.json", "w"), indent=1)
159
+
160
+ # ---- Claim 5: topology ----
161
+ n = N_CLIENTS
162
+ tops = {}
163
+ ring = np.zeros((n, n), int)
164
+ for i in range(n): ring[i, (i+1) % n] = ring[(i+1) % n, i] = 1
165
+ tops["ring"] = ring
166
+ star = np.zeros((n, n), int); star[0, 1:] = star[1:, 0] = 1; tops["star"] = star
167
+ path = np.zeros((n, n), int)
168
+ for i in range(n-1): path[i, i+1] = path[i+1, i] = 1
169
+ tops["path"] = path
170
+ tops["complete"] = np.ones((n, n), int) - np.eye(n, dtype=int)
171
+ rows = []
172
+ for nm, adj in tops.items():
173
+ W, rho = metropolis(adj)
174
+ m, cons = dec_run(base, ref, clients, tok, W)
175
+ l, a = evaluate(m, ref, clients, pad)
176
+ rows.append({"topology": nm, "rho": round(rho, 4),
177
+ "one_over_1_minus_rho2": round(1/(1-rho**2), 3),
178
+ "consensus_error": cons, "loss": l, "acc": a})
179
+ print(" %-9s rho=%.4f cons=%.4e loss=%.4f (%.0fs)" % (nm, rho, cons, l, time.time()-t0), flush=True)
180
+ x = np.log([r["one_over_1_minus_rho2"] for r in rows if r["consensus_error"] > 1e-9])
181
+ y = np.log([r["consensus_error"] for r in rows if r["consensus_error"] > 1e-9])
182
+ if len(x) > 2:
183
+ sl, ic = np.polyfit(x, y, 1)
184
+ RES["claim5_topology"] = {"rows": rows, "loglog_slope": round(float(sl), 4),
185
+ "r2": round(float(1-np.var(y-(sl*x+ic))/np.var(y)), 4),
186
+ "rank_corr_positive": bool(np.corrcoef(x, y)[0, 1] > 0)}
187
+ else:
188
+ RES["claim5_topology"] = {"rows": rows}
189
+ RES["wall_clock_s"] = time.time()-t0
190
+ json.dump(RES, open("fed_real_results.json", "w"), indent=1)
191
+ print("DONE %.0fs" % (time.time()-t0), flush=True)
192
+
193
+
194
+ if __name__ == "__main__":
195
+ main()
code/fed_topo.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Topology arm only: DecDPO on DistilGPT-2 across four 5-node graphs."""
2
+ import json, time, numpy as np, torch
3
+ from transformers import AutoModelForCausalLM
4
+ from dpo_real import DEV, MODEL
5
+ import fed_real as FR
6
+
7
+ RES = json.load(open("fed_real_results.json"))
8
+
9
+ def main():
10
+ t0=time.time()
11
+ clients,names,tok = FR.build_clients()
12
+ base = AutoModelForCausalLM.from_pretrained(MODEL)
13
+ ref = AutoModelForCausalLM.from_pretrained(MODEL).to(DEV).eval()
14
+ for p in ref.parameters(): p.requires_grad_(False)
15
+ pad=tok.pad_token_id; n=FR.N_CLIENTS
16
+ tops={}
17
+ ring=np.zeros((n,n),int)
18
+ for i in range(n): ring[i,(i+1)%n]=ring[(i+1)%n,i]=1
19
+ tops["ring"]=ring
20
+ star=np.zeros((n,n),int); star[0,1:]=star[1:,0]=1; tops["star"]=star
21
+ path=np.zeros((n,n),int)
22
+ for i in range(n-1): path[i,i+1]=path[i+1,i]=1
23
+ tops["path"]=path
24
+ tops["complete"]=np.ones((n,n),int)-np.eye(n,dtype=int)
25
+ rows=[]
26
+ for nm,adj in tops.items():
27
+ W,rho=FR.metropolis(adj)
28
+ m,cons=FR.dec_run(base,ref,clients,tok,W)
29
+ l,a=FR.evaluate(m,ref,clients,pad)
30
+ rows.append({"topology":nm,"rho":round(rho,4),
31
+ "one_over_1_minus_rho2":(round(1/(1-rho**2),3) if rho<0.999999 else None),
32
+ "consensus_error":cons,"loss":l,"acc":a})
33
+ print(" %-9s rho=%.4f 1/(1-rho^2)=%s cons=%.4e loss=%.5f (%.0fs)"%(
34
+ nm,rho,rows[-1]["one_over_1_minus_rho2"],cons,l,time.time()-t0),flush=True)
35
+ json.dump({**RES,"claim5_topology":{"rows":rows}},open("fed_real_results.json","w"),indent=1)
36
+ ok=[r for r in rows if r["consensus_error"]>1e-7 and r["one_over_1_minus_rho2"]]
37
+ out={"rows":rows,"n_in_fit":len(ok)}
38
+ if len(ok)>=3:
39
+ x=np.log([r["one_over_1_minus_rho2"] for r in ok]); y=np.log([r["consensus_error"] for r in ok])
40
+ sl,ic=np.polyfit(x,y,1)
41
+ out.update({"loglog_slope":round(float(sl),4),
42
+ "r2":round(float(1-np.var(y-(sl*x+ic))/np.var(y)),4),
43
+ "spearman_positive":bool(np.corrcoef(x,y)[0,1]>0)})
44
+ RES["claim5_topology"]=out
45
+ json.dump(RES,open("fed_real_results.json","w"),indent=1)
46
+ print("DONE %.0fs"%(time.time()-t0),flush=True)
47
+
48
+ if __name__=="__main__": main()
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>Reproduction: Distributed Direct Preference Optimization</title>
7
  <link rel="stylesheet" href="./logbook.css" />
8
  </head>
9
  <body>
@@ -21,36 +21,6 @@
21
  </div>
22
  </aside>
23
  <main id="content">
24
- <nav id="view-tabs" aria-label="Logbook views">
25
- <a data-view="code" href="#/view/code/index">
26
- <svg viewBox="0 0 24 24" aria-hidden="true">
27
- <path d="m18 16 4-4-4-4" />
28
- <path d="m6 8-4 4 4 4" />
29
- <path d="m14.5 4-5 16" />
30
- </svg>
31
- <span>Logbook</span>
32
- </a>
33
- <a data-view="trace" href="#/view/trace">
34
- <svg viewBox="0 0 24 24" aria-hidden="true">
35
- <path d="M8 5h13" />
36
- <path d="M13 12h8" />
37
- <path d="M13 19h8" />
38
- <path d="M3 10a2 2 0 0 0 2 2h3" />
39
- <path d="M3 5v12a2 2 0 0 0 2 2h3" />
40
- </svg>
41
- <span>Traces</span>
42
- </a>
43
- <a data-view="workspace" href="#/view/workspace">
44
- <svg viewBox="0 0 24 24" aria-hidden="true">
45
- <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />
46
- </svg>
47
- <span>Workspace</span>
48
- </a>
49
- </nav>
50
- <header id="logbook-header">
51
- <h1 id="logbook-title"></h1>
52
- <div id="logbook-cli"></div>
53
- </header>
54
  <div id="page"></div>
55
  </main>
56
  </div>
 
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Reproduction: Accurate Large-sample Uncertainty Quantification using Stochastic Gradient Markov Chain Monte Carlo</title>
7
  <link rel="stylesheet" href="./logbook.css" />
8
  </head>
9
  <body>
 
21
  </div>
22
  </aside>
23
  <main id="content">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  <div id="page"></div>
25
  </main>
26
  </div>
logbook.css CHANGED
@@ -1,6 +1,6 @@
1
  :root {
2
  --bg: #ffffff;
3
- --paper: #ffffff;
4
  --panel: #ffffff;
5
  --ink: #1f2937;
6
  --muted: #6b7280;
@@ -9,11 +9,9 @@
9
  --accent-strong: #ea580c;
10
  --accent-soft: #fff7ed;
11
  --accent-line: rgba(249, 115, 22, 0.16);
12
- --grid-line: rgba(31, 41, 55, 0.02);
13
  --code-bg: #f3f4f6;
14
  --radius: 12px;
15
- --sidebar-width: 280px;
16
- --content-gutter: 40px;
17
  --serif: ui-serif, "Iowan Old Style", "Palatino Linotype", Georgia, serif;
18
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
19
  sans-serif;
@@ -33,7 +31,6 @@ body {
33
 
34
  html {
35
  scroll-behavior: smooth;
36
- scrollbar-gutter: stable;
37
  }
38
 
39
  body {
@@ -50,15 +47,10 @@ body {
50
  min-height: 100vh;
51
  }
52
 
53
- body[data-view="trace"] #sidebar-foot,
54
- body[data-view="workspace"] #sidebar-foot {
55
- display: none;
56
- }
57
-
58
  /* ---- sidebar (composition-book cover) ---- */
59
  #sidebar {
60
- width: var(--sidebar-width);
61
- flex: 0 0 var(--sidebar-width);
62
  background: #17181c;
63
  color: #e7e7ea;
64
  position: sticky;
@@ -105,15 +97,6 @@ body[data-view="workspace"] #sidebar-foot {
105
  padding-top: 8px;
106
  }
107
 
108
- #tree .tree-label {
109
- padding: 6px 10px 8px;
110
- color: #777a83;
111
- font-size: 10px;
112
- font-weight: 700;
113
- letter-spacing: 0.12em;
114
- text-transform: uppercase;
115
- }
116
-
117
  #tree a {
118
  display: block;
119
  padding: 6px 10px;
@@ -122,9 +105,6 @@ body[data-view="workspace"] #sidebar-foot {
122
  text-decoration: none;
123
  font-size: 14px;
124
  transition: background 0.12s, color 0.12s;
125
- overflow: hidden;
126
- text-overflow: ellipsis;
127
- white-space: nowrap;
128
  }
129
 
130
  #tree a:hover {
@@ -163,13 +143,7 @@ body[data-view="workspace"] #sidebar-foot {
163
  #content {
164
  flex: 1;
165
  min-width: 0;
166
- padding: 24px
167
- clamp(
168
- var(--content-gutter),
169
- calc(100vw - 960px),
170
- calc(var(--sidebar-width) + var(--content-gutter))
171
- )
172
- 120px var(--content-gutter);
173
  background-color: var(--paper);
174
  background-image:
175
  linear-gradient(var(--grid-line) 1px, transparent 1px),
@@ -178,28 +152,10 @@ body[data-view="workspace"] #sidebar-foot {
178
  background-position: center top;
179
  }
180
 
181
- #logbook-header {
182
- width: 100%;
183
- max-width: 1080px;
184
- margin: 0 auto 20px;
185
- }
186
- #logbook-title {
187
- font-family: var(--serif);
188
- font-size: 34px;
189
- line-height: 1.15;
190
- letter-spacing: -0.02em;
191
- margin: 0 0 10px;
192
- overflow-wrap: anywhere;
193
- }
194
- #logbook-cli {
195
- display: grid;
196
- gap: 7px;
197
- }
198
-
199
  #page {
200
  width: 100%;
201
  min-width: 0;
202
- max-width: 1080px;
203
  margin: 0 auto;
204
  }
205
 
@@ -214,7 +170,10 @@ body[data-view="workspace"] #sidebar-foot {
214
  }
215
 
216
  .page-layout {
217
- display: block;
 
 
 
218
  }
219
 
220
  .page-body {
@@ -229,26 +188,18 @@ body[data-view="workspace"] #sidebar-foot {
229
 
230
  /* ---- pinned notes ---- */
231
  .pinned-notes {
232
- margin: 30px 0 32px;
233
  }
234
  .pinned-notes-list .cell {
235
  margin: 0;
236
- }
237
- .pinned-notes-list .cell-title {
238
- display: flex;
239
- align-items: center;
240
- gap: 7px;
241
- }
242
- .pin-ico {
243
- flex: 0 0 auto;
244
- width: 14px;
245
- height: 14px;
246
- fill: var(--accent);
247
- stroke: none;
248
  }
249
  .pinned-notes-list .cell + .cell {
250
  margin-top: 12px;
251
  }
 
 
 
252
  .book-intro.has-pinned-notes {
253
  border-bottom: none;
254
  padding-bottom: 22px;
@@ -425,25 +376,26 @@ body[data-view="workspace"] #sidebar-foot {
425
  /* ---- notebook-style cells ---- */
426
  .cell {
427
  max-width: 100%;
428
- margin: 0 0 32px;
429
- background: none;
430
- border: none;
431
- border-radius: 0;
432
- box-shadow: none;
433
- overflow: visible;
434
  }
435
  .cell-head {
436
  display: flex;
437
  justify-content: space-between;
438
  gap: 16px;
439
- align-items: baseline;
440
- padding: 0 0 5px;
441
- background: none;
442
- border-bottom: none;
443
  }
444
  .cell-head.no-title {
445
  justify-content: flex-end;
446
- padding: 0 0 3px;
 
447
  }
448
  .cell-title {
449
  flex: 1;
@@ -475,7 +427,7 @@ body[data-view="workspace"] #sidebar-foot {
475
  }
476
  .cell-body {
477
  min-width: 0;
478
- padding: 0;
479
  }
480
  .cell.dashboard .cell-body {
481
  padding: 0;
@@ -495,6 +447,9 @@ body[data-view="workspace"] #sidebar-foot {
495
  #page .cell-body > :last-child {
496
  margin-bottom: 0;
497
  }
 
 
 
498
  .figure-fit {
499
  position: relative;
500
  overflow: hidden;
@@ -667,40 +622,9 @@ body[data-view="workspace"] #sidebar-foot {
667
  border: 1px solid var(--line);
668
  border-radius: 10px;
669
  overflow: hidden;
670
- margin: 0;
671
  background: var(--panel);
672
  }
673
- .jp-cmd {
674
- display: flex;
675
- align-items: baseline;
676
- gap: 9px;
677
- position: relative;
678
- padding: 10px 16px 10px 0;
679
- font-family: var(--mono);
680
- font-size: 12px;
681
- color: #8b8e98;
682
- }
683
- .jp-cmd-prompt {
684
- color: var(--accent);
685
- font-weight: 700;
686
- }
687
- #page .jp-cmd code {
688
- min-width: 0;
689
- color: #b6b9c2;
690
- font-family: var(--mono);
691
- font-size: 12px;
692
- background: none;
693
- padding: 0;
694
- border-radius: 0;
695
- overflow-wrap: anywhere;
696
- }
697
- .jp-cmd:hover .copy-snippet {
698
- opacity: 1;
699
- }
700
- .jp-in-body .jp-cmd + .code-accordion,
701
- .jp-in-body .jp-cmd + .snippet {
702
- border-top: 1px solid rgba(255, 255, 255, 0.09);
703
- }
704
  .jp-gutter {
705
  flex: 0 0 46px;
706
  padding: 13px 0 0 13px;
@@ -728,8 +652,6 @@ body[data-view="workspace"] #sidebar-foot {
728
  border-radius: 0;
729
  background: none;
730
  padding: 12px 16px 12px 0;
731
- overflow-y: auto;
732
- max-height: 26em;
733
  }
734
  .jp-in-body .code-accordion {
735
  margin: 0;
@@ -1133,13 +1055,11 @@ table.board tr.linked-row:hover a {
1133
  align-items: center;
1134
  flex-wrap: wrap;
1135
  gap: 8px;
1136
- margin: 0;
1137
  font-size: 12.5px;
1138
  color: var(--muted);
1139
  }
1140
- .agent-hint code {
1141
- flex: 1 1 18rem;
1142
- min-width: 0;
1143
  background: var(--code-bg);
1144
  padding: 2px 9px;
1145
  border-radius: 6px;
@@ -1147,9 +1067,6 @@ table.board tr.linked-row:hover a {
1147
  font-size: 12px;
1148
  font-weight: 500;
1149
  color: var(--ink);
1150
- overflow: hidden;
1151
- text-overflow: ellipsis;
1152
- white-space: nowrap;
1153
  }
1154
  .agent-hint .copy {
1155
  flex: 0 0 auto;
@@ -1177,57 +1094,155 @@ table.board tr.linked-row:hover a {
1177
  font-size: 12px;
1178
  color: var(--muted);
1179
  }
1180
- .hub-destination {
 
 
1181
  display: flex;
1182
- align-items: center;
1183
  flex-wrap: wrap;
1184
- gap: 8px;
1185
- color: var(--muted);
1186
- font-size: 12.5px;
1187
  }
1188
- .hub-destination a {
 
1189
  display: inline-flex;
1190
  align-items: center;
1191
- gap: 6px;
1192
- max-width: 100%;
1193
- padding: 3px 9px;
1194
- border: 1px solid var(--accent-line);
1195
- border-radius: 999px;
1196
- background: var(--accent-soft);
1197
- color: var(--accent-strong);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1198
  font-family: var(--mono);
1199
- font-size: 12px;
1200
- font-weight: 650;
1201
- line-height: 1.5;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1202
  text-decoration: none;
1203
- overflow-wrap: anywhere;
1204
- transition: border-color 0.12s, background 0.12s, color 0.12s;
1205
  }
1206
- .hub-destination a:hover {
1207
- border-color: var(--accent);
1208
- background: #ffedd5;
1209
- color: #c2410c;
1210
  }
1211
- .hub-destination svg {
1212
- width: 13px;
1213
- height: 13px;
1214
  flex: 0 0 auto;
1215
- fill: none;
1216
- stroke: currentColor;
1217
- stroke-width: 1.8;
1218
- stroke-linecap: round;
1219
- stroke-linejoin: round;
1220
  }
1221
-
1222
- .index-paper-link {
1223
- margin: 14px 0 30px;
1224
- font-size: 19px;
1225
- line-height: 1.35;
1226
- font-weight: 700;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1227
  }
1228
- .index-paper-link a {
1229
- text-underline-offset: 4px;
1230
- text-decoration-thickness: 2px;
1231
  }
1232
  .art-ico {
1233
  width: 1em;
@@ -1235,20 +1250,6 @@ table.board tr.linked-row:hover a {
1235
  object-fit: contain;
1236
  vertical-align: -0.15em;
1237
  }
1238
- .art-file-ico {
1239
- width: 15px;
1240
- height: 15px;
1241
- flex: 0 0 auto;
1242
- fill: none;
1243
- stroke: currentColor;
1244
- stroke-width: 1.7;
1245
- stroke-linecap: round;
1246
- stroke-linejoin: round;
1247
- vertical-align: -0.2em;
1248
- }
1249
- .out-artifact-ico .art-file-ico {
1250
- color: var(--muted);
1251
- }
1252
 
1253
  /* ---- scroll-to-resource highlight ---- */
1254
  .res-flash {
@@ -1293,11 +1294,108 @@ table.board tr.linked-row:hover a {
1293
  font-size: 1.05em;
1294
  line-height: 1;
1295
  }
1296
- #page .res-chip:hover {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1297
  border-color: var(--accent);
1298
  background: var(--accent-soft);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1299
  color: var(--accent-strong);
1300
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1301
 
1302
  /* ---- connect footer + modal ---- */
1303
  #sidebar-foot {
@@ -1473,609 +1571,6 @@ table.board tr.linked-row:hover a {
1473
  color: #52d08a;
1474
  }
1475
 
1476
- /* ---- top-level logbook views ---- */
1477
- #view-tabs {
1478
- position: sticky;
1479
- top: 0;
1480
- z-index: 30;
1481
- width: 100%;
1482
- max-width: 1080px;
1483
- margin: 0 auto 24px;
1484
- padding-top: 10px;
1485
- display: flex;
1486
- align-items: center;
1487
- justify-content: flex-start;
1488
- gap: 26px;
1489
- border-bottom: 1px solid var(--line);
1490
- background: var(--paper);
1491
- }
1492
- #view-tabs a {
1493
- display: inline-flex;
1494
- align-items: center;
1495
- gap: 8px;
1496
- min-height: 44px;
1497
- margin-bottom: -1px;
1498
- color: var(--muted);
1499
- border-bottom: 2px solid transparent;
1500
- text-decoration: none;
1501
- font-size: 13.5px;
1502
- font-weight: 600;
1503
- transition: color 0.12s, border-color 0.12s;
1504
- }
1505
- #view-tabs a:hover {
1506
- color: var(--ink);
1507
- }
1508
- #view-tabs a.active {
1509
- color: var(--accent-strong);
1510
- border-bottom-color: var(--accent);
1511
- }
1512
- #view-tabs svg {
1513
- width: 18px;
1514
- height: 18px;
1515
- flex: 0 0 auto;
1516
- fill: none;
1517
- stroke: currentColor;
1518
- stroke-width: 2;
1519
- stroke-linecap: round;
1520
- stroke-linejoin: round;
1521
- }
1522
- .workspace-file svg,
1523
- .workspace-folder summary svg,
1524
- .workspace-download svg {
1525
- width: 17px;
1526
- height: 17px;
1527
- flex: 0 0 auto;
1528
- fill: none;
1529
- stroke: currentColor;
1530
- stroke-width: 1.7;
1531
- stroke-linecap: round;
1532
- stroke-linejoin: round;
1533
- }
1534
-
1535
- #page.trace-page,
1536
- #page.workspace-page {
1537
- max-width: 1080px;
1538
- }
1539
- .view-loading {
1540
- padding: 72px 0;
1541
- color: var(--muted);
1542
- text-align: center;
1543
- }
1544
- .view-empty {
1545
- margin: 48px 0;
1546
- padding: 44px 28px;
1547
- border: 1px dashed #d8dbe1;
1548
- border-radius: var(--radius);
1549
- background: rgba(255, 255, 255, 0.72);
1550
- text-align: center;
1551
- }
1552
- .view-empty h2 {
1553
- margin: 0 0 7px;
1554
- font-size: 18px;
1555
- }
1556
- .view-empty p {
1557
- max-width: 560px;
1558
- margin: 0 auto;
1559
- color: var(--muted);
1560
- }
1561
- .view-empty code {
1562
- display: inline-block;
1563
- margin-top: 18px;
1564
- padding: 7px 10px;
1565
- border-radius: 7px;
1566
- background: var(--code-bg);
1567
- font-family: var(--mono);
1568
- font-size: 12px;
1569
- }
1570
- #page .repo-ref-link {
1571
- display: inline-block;
1572
- margin-top: 18px;
1573
- padding: 8px 14px;
1574
- border-radius: 8px;
1575
- background: var(--accent-strong, #2158d0);
1576
- color: #fff;
1577
- font-weight: 600;
1578
- text-decoration: none;
1579
- }
1580
- #page .repo-ref-link:hover,
1581
- #page .repo-ref-link:focus-visible {
1582
- color: #fff;
1583
- filter: brightness(0.95);
1584
- }
1585
- .view-eyebrow {
1586
- margin-bottom: 4px;
1587
- color: var(--accent-strong);
1588
- font-family: var(--mono);
1589
- font-size: 11px;
1590
- font-weight: 700;
1591
- letter-spacing: 0.12em;
1592
- text-transform: uppercase;
1593
- }
1594
-
1595
- /* ---- trace ---- */
1596
- .trace-session {
1597
- scroll-margin-top: 24px;
1598
- }
1599
- .trace-session + .trace-session {
1600
- margin-top: 44px;
1601
- padding-top: 40px;
1602
- border-top: 1px solid var(--line);
1603
- }
1604
- .trace-session-title {
1605
- margin: 0 0 14px;
1606
- color: var(--ink);
1607
- font-family: var(--serif);
1608
- font-size: 22px;
1609
- line-height: 1.2;
1610
- letter-spacing: -0.02em;
1611
- overflow-wrap: anywhere;
1612
- }
1613
- .workspace-header h1 {
1614
- margin: 0;
1615
- color: var(--ink);
1616
- font-size: 30px;
1617
- line-height: 1.2;
1618
- letter-spacing: -0.025em;
1619
- }
1620
- .trace-meta {
1621
- display: flex;
1622
- flex-wrap: wrap;
1623
- gap: 9px 20px;
1624
- margin-bottom: 34px;
1625
- padding: 14px 16px;
1626
- border: 1px solid var(--line);
1627
- border-radius: 10px;
1628
- background: rgba(255, 255, 255, 0.78);
1629
- color: var(--muted);
1630
- font-family: var(--mono);
1631
- font-size: 11px;
1632
- }
1633
- .trace-meta strong {
1634
- color: var(--ink);
1635
- font-weight: 650;
1636
- }
1637
- .trace-source-missing {
1638
- color: #b45309;
1639
- }
1640
- .trace-timeline {
1641
- position: relative;
1642
- }
1643
- .trace-timeline::before {
1644
- content: "";
1645
- position: absolute;
1646
- top: 0;
1647
- bottom: 0;
1648
- left: 82px;
1649
- width: 1px;
1650
- background: #dedfe3;
1651
- }
1652
- .trace-load-controls {
1653
- display: flex;
1654
- align-items: center;
1655
- justify-content: space-between;
1656
- gap: 16px;
1657
- margin: 22px 0 0 100px;
1658
- padding-top: 16px;
1659
- border-top: 1px solid var(--line);
1660
- }
1661
- .trace-load-progress {
1662
- color: var(--muted);
1663
- font-family: var(--mono);
1664
- font-size: 11px;
1665
- }
1666
- .trace-load-more {
1667
- padding: 7px 12px;
1668
- border: 1px solid var(--line-strong);
1669
- border-radius: 7px;
1670
- background: var(--paper);
1671
- color: var(--ink);
1672
- cursor: pointer;
1673
- font: 650 12px/1.2 var(--sans);
1674
- }
1675
- .trace-load-more:hover:not(:disabled) {
1676
- border-color: var(--accent);
1677
- color: var(--accent-strong);
1678
- }
1679
- .trace-load-more:disabled {
1680
- cursor: default;
1681
- opacity: 0.65;
1682
- }
1683
- .trace-entry {
1684
- --trace-depth: 0;
1685
- position: relative;
1686
- display: grid;
1687
- grid-template-columns: 100px minmax(0, 1fr);
1688
- margin: 0 0 18px calc(var(--trace-depth) * 24px);
1689
- }
1690
- .trace-rail {
1691
- position: relative;
1692
- min-height: 36px;
1693
- padding: 4px 28px 0 0;
1694
- color: #8a8d95;
1695
- text-align: right;
1696
- font-family: var(--mono);
1697
- }
1698
- .trace-number,
1699
- .trace-elapsed {
1700
- display: block;
1701
- white-space: nowrap;
1702
- }
1703
- .trace-number {
1704
- font-size: 12px;
1705
- font-weight: 650;
1706
- }
1707
- .trace-elapsed {
1708
- margin-top: 3px;
1709
- font-size: 10px;
1710
- }
1711
- .trace-dot {
1712
- position: absolute;
1713
- top: 10px;
1714
- right: 11px;
1715
- width: 11px;
1716
- height: 11px;
1717
- border: 2px solid var(--paper);
1718
- border-radius: 50%;
1719
- background: var(--accent);
1720
- box-shadow: 0 0 0 1px #d7d9de;
1721
- }
1722
- .trace-card {
1723
- min-width: 0;
1724
- overflow: hidden;
1725
- border: 1px solid #dddfe4;
1726
- border-radius: 11px;
1727
- background: rgba(255, 255, 255, 0.92);
1728
- }
1729
- .trace-card > header {
1730
- display: flex;
1731
- align-items: center;
1732
- gap: 10px;
1733
- min-height: 37px;
1734
- padding: 8px 13px;
1735
- border-bottom: 1px solid #eceef1;
1736
- }
1737
- .trace-status .trace-card > header {
1738
- border-bottom: 0;
1739
- padding-bottom: 5px;
1740
- }
1741
- .trace-kind {
1742
- font-family: var(--mono);
1743
- font-size: 10.5px;
1744
- font-weight: 750;
1745
- letter-spacing: 0.08em;
1746
- text-transform: uppercase;
1747
- }
1748
- .trace-turn {
1749
- color: var(--muted);
1750
- font: 10px var(--mono);
1751
- }
1752
- .trace-status-badge {
1753
- margin-left: auto;
1754
- padding: 1px 6px;
1755
- border-radius: 999px;
1756
- background: #eef0f3;
1757
- color: var(--muted);
1758
- font: 9.5px var(--mono);
1759
- text-transform: uppercase;
1760
- }
1761
- .trace-status-badge-error,
1762
- .trace-status-badge-failed {
1763
- background: #fef2f2;
1764
- color: #b91c1c;
1765
- }
1766
- .trace-body {
1767
- margin: 0;
1768
- padding: 15px 17px 17px;
1769
- overflow-wrap: anywhere;
1770
- white-space: pre-wrap;
1771
- font-family: var(--sans);
1772
- font-size: 13px;
1773
- line-height: 1.65;
1774
- }
1775
- .trace-reasoning .trace-card {
1776
- border-style: dashed;
1777
- border-color: #d7b98a;
1778
- background: #fffdf8;
1779
- }
1780
- .trace-reasoning .trace-kind {
1781
- color: #9a6b22;
1782
- }
1783
- .trace-reasoning .trace-body {
1784
- font-style: italic;
1785
- }
1786
- .trace-user .trace-card {
1787
- border-left: 3px solid #f3a66d;
1788
- }
1789
- .trace-tool_call .trace-card,
1790
- .trace-tool_result .trace-card {
1791
- border-color: #2d3036;
1792
- background: #191a1e;
1793
- color: #ececf0;
1794
- }
1795
- .trace-tool_call .trace-card > header,
1796
- .trace-tool_result .trace-card > header {
1797
- border-bottom-color: rgba(255, 255, 255, 0.1);
1798
- }
1799
- .trace-tool_call .trace-kind,
1800
- .trace-tool_result .trace-kind {
1801
- color: #f5a66d;
1802
- }
1803
- .trace-tool_call .trace-turn,
1804
- .trace-tool_result .trace-turn {
1805
- color: #979aa3;
1806
- }
1807
- .trace-tool_call .trace-body,
1808
- .trace-tool_result .trace-body,
1809
- .trace-output pre {
1810
- font-family: var(--mono);
1811
- font-size: 11.5px;
1812
- line-height: 1.6;
1813
- }
1814
- #page .trace-tool_call pre.trace-body,
1815
- #page .trace-tool_result pre.trace-body {
1816
- margin: 0;
1817
- padding: 15px 17px 17px;
1818
- border: 0;
1819
- border-radius: 0;
1820
- background: transparent;
1821
- color: #ececf0;
1822
- }
1823
- .trace-output {
1824
- border-top: 1px dashed rgba(255, 255, 255, 0.14);
1825
- }
1826
- .trace-output summary {
1827
- padding: 9px 14px;
1828
- color: #aaaeb7;
1829
- cursor: pointer;
1830
- font: 700 10px var(--mono);
1831
- letter-spacing: 0.06em;
1832
- text-transform: uppercase;
1833
- }
1834
- #page .trace-output pre {
1835
- max-height: 480px;
1836
- margin: 0;
1837
- padding: 0 16px 16px;
1838
- border: 0;
1839
- border-radius: 0;
1840
- background: transparent;
1841
- overflow: auto;
1842
- color: #d7d8dd;
1843
- white-space: pre-wrap;
1844
- }
1845
-
1846
- /* ---- workspace ---- */
1847
- .workspace-header {
1848
- padding-bottom: 24px;
1849
- }
1850
- .workspace-header p {
1851
- margin: 0;
1852
- color: var(--muted);
1853
- font-family: var(--mono);
1854
- font-size: 11px;
1855
- }
1856
- .workspace-inventory {
1857
- overflow: hidden;
1858
- border: 1px solid var(--line);
1859
- border-radius: 11px;
1860
- background: rgba(255, 255, 255, 0.92);
1861
- }
1862
- .workspace-folder > summary {
1863
- display: flex;
1864
- align-items: center;
1865
- gap: 8px;
1866
- min-height: 39px;
1867
- padding: 8px 13px;
1868
- background: #fafafa;
1869
- cursor: pointer;
1870
- font-weight: 650;
1871
- list-style: none;
1872
- }
1873
- .workspace-folder > summary::-webkit-details-marker {
1874
- display: none;
1875
- }
1876
- .workspace-folder > summary::after {
1877
- content: "›";
1878
- margin-left: auto;
1879
- color: #989ba2;
1880
- transform: rotate(90deg);
1881
- }
1882
- .workspace-folder:not([open]) > summary::after {
1883
- transform: rotate(0);
1884
- }
1885
- .workspace-folder-children {
1886
- padding-left: 20px;
1887
- }
1888
- .workspace-file {
1889
- display: grid;
1890
- grid-template-columns: minmax(180px, 1fr) 72px 78px 180px 36px;
1891
- align-items: center;
1892
- min-height: 44px;
1893
- padding: 7px 10px 7px 13px;
1894
- color: var(--muted);
1895
- font-family: var(--mono);
1896
- font-size: 10.5px;
1897
- }
1898
- .workspace-file-name {
1899
- display: flex;
1900
- align-items: center;
1901
- min-width: 0;
1902
- gap: 8px;
1903
- color: var(--ink);
1904
- font-family: var(--sans);
1905
- font-size: 12.5px;
1906
- font-weight: 550;
1907
- }
1908
- .workspace-file-name span {
1909
- overflow: hidden;
1910
- text-overflow: ellipsis;
1911
- white-space: nowrap;
1912
- }
1913
- .workspace-file-type {
1914
- width: fit-content;
1915
- padding: 1px 6px;
1916
- border-radius: 999px;
1917
- background: var(--accent-soft);
1918
- color: var(--accent-strong);
1919
- text-transform: uppercase;
1920
- }
1921
- .workspace-download {
1922
- display: inline-flex;
1923
- align-items: center;
1924
- justify-content: center;
1925
- width: 30px;
1926
- height: 30px;
1927
- border-radius: 7px;
1928
- color: var(--muted);
1929
- }
1930
- .workspace-download:hover {
1931
- background: var(--accent-soft);
1932
- color: var(--accent-strong);
1933
- }
1934
- .workspace-unpublished {
1935
- color: #9ca3af;
1936
- text-align: center;
1937
- }
1938
-
1939
- .workspace-header {
1940
- display: flex;
1941
- align-items: center;
1942
- justify-content: space-between;
1943
- gap: 16px;
1944
- flex-wrap: wrap;
1945
- }
1946
- .workspace-toggle {
1947
- display: inline-flex;
1948
- align-items: center;
1949
- padding: 2px;
1950
- border: 1px solid var(--line);
1951
- border-radius: 999px;
1952
- background: #fafafa;
1953
- }
1954
- .workspace-toggle-btn {
1955
- padding: 4px 13px;
1956
- border: 0;
1957
- border-radius: 999px;
1958
- background: transparent;
1959
- color: var(--muted);
1960
- font-family: var(--sans);
1961
- font-size: 12px;
1962
- font-weight: 600;
1963
- cursor: pointer;
1964
- }
1965
- .workspace-toggle-btn:hover {
1966
- color: var(--accent-strong);
1967
- }
1968
- .workspace-toggle-btn.is-active {
1969
- background: var(--accent);
1970
- color: #ffffff;
1971
- }
1972
- .workspace-group + .workspace-group {
1973
- margin-top: 18px;
1974
- }
1975
- .workspace-group-head,
1976
- .workspace-hub-group-head {
1977
- display: flex;
1978
- align-items: center;
1979
- gap: 8px;
1980
- margin: 0;
1981
- padding: 8px 13px;
1982
- background: #fafafa;
1983
- border-bottom: 1px solid var(--line);
1984
- color: var(--ink);
1985
- font-family: var(--sans);
1986
- font-size: 12px;
1987
- font-weight: 650;
1988
- text-transform: capitalize;
1989
- }
1990
- .workspace-group-count,
1991
- .workspace-hub-count {
1992
- padding: 0 7px;
1993
- border-radius: 999px;
1994
- background: var(--accent-soft);
1995
- color: var(--accent-strong);
1996
- font-family: var(--mono);
1997
- font-size: 10.5px;
1998
- }
1999
- .workspace-group {
2000
- overflow: hidden;
2001
- border: 1px solid var(--line);
2002
- border-radius: 11px;
2003
- background: rgba(255, 255, 255, 0.92);
2004
- }
2005
-
2006
- .workspace-hub {
2007
- margin-top: 28px;
2008
- }
2009
- .workspace-hub-title {
2010
- margin: 0 0 14px;
2011
- font-family: var(--sans);
2012
- font-size: 16px;
2013
- font-weight: 700;
2014
- color: var(--ink);
2015
- }
2016
- .workspace-hub-group {
2017
- overflow: hidden;
2018
- border: 1px solid var(--line);
2019
- border-radius: 11px;
2020
- background: rgba(255, 255, 255, 0.92);
2021
- }
2022
- .workspace-hub-group + .workspace-hub-group {
2023
- margin-top: 14px;
2024
- }
2025
- .workspace-hub-list {
2026
- display: flex;
2027
- flex-direction: column;
2028
- }
2029
- .workspace-hub-link {
2030
- padding: 9px 13px;
2031
- color: var(--accent-strong);
2032
- font-family: var(--mono);
2033
- font-size: 12px;
2034
- text-decoration: none;
2035
- overflow: hidden;
2036
- text-overflow: ellipsis;
2037
- white-space: nowrap;
2038
- }
2039
- .workspace-hub-link + .workspace-hub-link {
2040
- border-top: 1px solid var(--line);
2041
- }
2042
- .workspace-hub-link:hover {
2043
- background: var(--accent-soft);
2044
- text-decoration: underline;
2045
- }
2046
-
2047
- /* --- UI nits --- */
2048
- /* Flush group headers: #page h3/h2 (ID selectors) otherwise inject a top margin
2049
- that, with overflow:hidden on the card, shows as whitespace above "Jobs" etc. */
2050
- #page .workspace-hub-title {
2051
- margin: 0 0 14px;
2052
- }
2053
- #page .workspace-hub-group-head,
2054
- #page .workspace-group-head {
2055
- margin: 0;
2056
- }
2057
- /* HF brand logo before the "Hugging Face artifacts" heading */
2058
- .workspace-hub-title {
2059
- display: flex;
2060
- align-items: center;
2061
- gap: 9px;
2062
- }
2063
- .workspace-hub-logo {
2064
- width: 22px;
2065
- height: 22px;
2066
- flex: none;
2067
- }
2068
- /* Center empty-state placeholders (heading, body, command) */
2069
- .view-empty {
2070
- display: flex;
2071
- flex-direction: column;
2072
- align-items: center;
2073
- }
2074
- #page .view-empty h2,
2075
- #page .view-empty p {
2076
- text-align: center;
2077
- }
2078
-
2079
  @media (max-width: 720px) {
2080
  #app {
2081
  flex-direction: column;
@@ -2092,46 +1587,11 @@ table.board tr.linked-row:hover a {
2092
  padding: 28px 20px 80px;
2093
  overflow-x: hidden;
2094
  }
2095
- #view-tabs {
2096
- margin: 0 0 20px;
2097
- gap: 18px;
2098
- justify-content: flex-start;
2099
- overflow-x: auto;
2100
- }
2101
- #view-tabs a {
2102
- flex: 0 0 auto;
2103
- }
2104
- .trace-timeline::before {
2105
- left: 16px;
2106
- }
2107
- .trace-entry {
2108
- grid-template-columns: 32px minmax(0, 1fr);
2109
- margin-left: calc(var(--trace-depth) * 10px);
2110
- }
2111
- .trace-rail {
2112
- padding: 0;
2113
- }
2114
- .trace-number,
2115
- .trace-elapsed {
2116
- display: none;
2117
- }
2118
- .trace-dot {
2119
- top: 10px;
2120
- right: 10px;
2121
- }
2122
- .workspace-file {
2123
- grid-template-columns: minmax(150px, 1fr) 66px 34px;
2124
- }
2125
- .workspace-file-size,
2126
- .workspace-file-time {
2127
- display: none;
2128
- }
2129
  #page {
2130
  width: 100%;
2131
  max-width: 100%;
2132
  }
2133
- #page h1,
2134
- #logbook-title {
2135
  font-size: 30px;
2136
  }
2137
  .cell-head {
 
1
  :root {
2
  --bg: #ffffff;
3
+ --paper: #fdfcf9;
4
  --panel: #ffffff;
5
  --ink: #1f2937;
6
  --muted: #6b7280;
 
9
  --accent-strong: #ea580c;
10
  --accent-soft: #fff7ed;
11
  --accent-line: rgba(249, 115, 22, 0.16);
12
+ --grid-line: rgba(31, 41, 55, 0.045);
13
  --code-bg: #f3f4f6;
14
  --radius: 12px;
 
 
15
  --serif: ui-serif, "Iowan Old Style", "Palatino Linotype", Georgia, serif;
16
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
17
  sans-serif;
 
31
 
32
  html {
33
  scroll-behavior: smooth;
 
34
  }
35
 
36
  body {
 
47
  min-height: 100vh;
48
  }
49
 
 
 
 
 
 
50
  /* ---- sidebar (composition-book cover) ---- */
51
  #sidebar {
52
+ width: 280px;
53
+ flex: 0 0 280px;
54
  background: #17181c;
55
  color: #e7e7ea;
56
  position: sticky;
 
97
  padding-top: 8px;
98
  }
99
 
 
 
 
 
 
 
 
 
 
100
  #tree a {
101
  display: block;
102
  padding: 6px 10px;
 
105
  text-decoration: none;
106
  font-size: 14px;
107
  transition: background 0.12s, color 0.12s;
 
 
 
108
  }
109
 
110
  #tree a:hover {
 
143
  #content {
144
  flex: 1;
145
  min-width: 0;
146
+ padding: 48px 40px 120px;
 
 
 
 
 
 
147
  background-color: var(--paper);
148
  background-image:
149
  linear-gradient(var(--grid-line) 1px, transparent 1px),
 
152
  background-position: center top;
153
  }
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  #page {
156
  width: 100%;
157
  min-width: 0;
158
+ max-width: 1052px;
159
  margin: 0 auto;
160
  }
161
 
 
170
  }
171
 
172
  .page-layout {
173
+ display: grid;
174
+ grid-template-columns: minmax(0, 760px) 248px;
175
+ gap: 44px;
176
+ align-items: start;
177
  }
178
 
179
  .page-body {
 
188
 
189
  /* ---- pinned notes ---- */
190
  .pinned-notes {
191
+ margin: 30px 0 0;
192
  }
193
  .pinned-notes-list .cell {
194
  margin: 0;
195
+ border-color: rgba(249, 115, 22, 0.55);
 
 
 
 
 
 
 
 
 
 
 
196
  }
197
  .pinned-notes-list .cell + .cell {
198
  margin-top: 12px;
199
  }
200
+ .cell.pinned-source {
201
+ border-color: rgba(249, 115, 22, 0.55);
202
+ }
203
  .book-intro.has-pinned-notes {
204
  border-bottom: none;
205
  padding-bottom: 22px;
 
376
  /* ---- notebook-style cells ---- */
377
  .cell {
378
  max-width: 100%;
379
+ border: 1px solid var(--line);
380
+ border-radius: 10px;
381
+ background: rgba(255, 255, 255, 0.86);
382
+ margin: 18px 0;
383
+ overflow: hidden;
384
+ box-shadow: 0 2px 10px rgba(31, 41, 55, 0.035);
385
  }
386
  .cell-head {
387
  display: flex;
388
  justify-content: space-between;
389
  gap: 16px;
390
+ align-items: center;
391
+ padding: 14px 18px;
392
+ background: rgba(255, 255, 255, 0.92);
393
+ border-bottom: 1px solid var(--line);
394
  }
395
  .cell-head.no-title {
396
  justify-content: flex-end;
397
+ padding-top: 10px;
398
+ padding-bottom: 10px;
399
  }
400
  .cell-title {
401
  flex: 1;
 
427
  }
428
  .cell-body {
429
  min-width: 0;
430
+ padding: 14px 18px 18px;
431
  }
432
  .cell.dashboard .cell-body {
433
  padding: 0;
 
447
  #page .cell-body > :last-child {
448
  margin-bottom: 0;
449
  }
450
+ .cell.code .cell-head {
451
+ background: #fbfbfc;
452
+ }
453
  .figure-fit {
454
  position: relative;
455
  overflow: hidden;
 
622
  border: 1px solid var(--line);
623
  border-radius: 10px;
624
  overflow: hidden;
625
+ margin: 12px 0;
626
  background: var(--panel);
627
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
628
  .jp-gutter {
629
  flex: 0 0 46px;
630
  padding: 13px 0 0 13px;
 
652
  border-radius: 0;
653
  background: none;
654
  padding: 12px 16px 12px 0;
 
 
655
  }
656
  .jp-in-body .code-accordion {
657
  margin: 0;
 
1055
  align-items: center;
1056
  flex-wrap: wrap;
1057
  gap: 8px;
1058
+ margin: 4px 0 22px;
1059
  font-size: 12.5px;
1060
  color: var(--muted);
1061
  }
1062
+ #page .agent-hint code {
 
 
1063
  background: var(--code-bg);
1064
  padding: 2px 9px;
1065
  border-radius: 6px;
 
1067
  font-size: 12px;
1068
  font-weight: 500;
1069
  color: var(--ink);
 
 
 
1070
  }
1071
  .agent-hint .copy {
1072
  flex: 0 0 auto;
 
1094
  font-size: 12px;
1095
  color: var(--muted);
1096
  }
1097
+
1098
+ /* ---- logbook summary stats ---- */
1099
+ .logbook-stats {
1100
  display: flex;
 
1101
  flex-wrap: wrap;
1102
+ gap: 12px;
1103
+ margin: 0 0 28px;
 
1104
  }
1105
+ .stat-tile {
1106
+ position: relative;
1107
  display: inline-flex;
1108
  align-items: center;
1109
+ gap: 11px;
1110
+ border: 1px solid var(--line);
1111
+ background: var(--panel);
1112
+ border-radius: var(--radius);
1113
+ padding: 12px 23px;
1114
+ font: inherit;
1115
+ text-align: left;
1116
+ cursor: pointer;
1117
+ transition: border-color 0.12s, box-shadow 0.12s;
1118
+ }
1119
+ .stat-tile:hover:not([disabled]) {
1120
+ border-color: rgba(249, 115, 22, 0.45);
1121
+ box-shadow: 0 3px 12px rgba(31, 41, 55, 0.06);
1122
+ }
1123
+ .stat-tile:focus-visible {
1124
+ outline: 2px solid var(--accent);
1125
+ outline-offset: 2px;
1126
+ }
1127
+ .stat-tile[disabled] {
1128
+ cursor: default;
1129
+ opacity: 0.7;
1130
+ }
1131
+ .stat-tile.open {
1132
+ border-color: rgba(249, 115, 22, 0.6);
1133
+ box-shadow: 0 3px 12px rgba(31, 41, 55, 0.08);
1134
+ }
1135
+ .stat-icon {
1136
+ width: 24px;
1137
+ height: 24px;
1138
+ flex: 0 0 24px;
1139
+ object-fit: contain;
1140
+ align-self: center;
1141
+ }
1142
+ .stat-text {
1143
+ display: flex;
1144
+ align-items: baseline;
1145
+ gap: 8px;
1146
+ white-space: nowrap;
1147
+ line-height: 1;
1148
+ }
1149
+ .stat-num {
1150
  font-family: var(--mono);
1151
+ font-size: 20px;
1152
+ font-weight: 600;
1153
+ line-height: 1;
1154
+ color: var(--accent-strong);
1155
+ }
1156
+ .stat-label {
1157
+ font-size: 15px;
1158
+ line-height: 1;
1159
+ color: var(--muted);
1160
+ }
1161
+ .stat-caret {
1162
+ margin-left: 2px;
1163
+ font-size: 10px;
1164
+ color: var(--muted);
1165
+ align-self: center;
1166
+ transition: transform 0.12s;
1167
+ }
1168
+ .stat-tile.open .stat-caret {
1169
+ transform: rotate(180deg);
1170
+ }
1171
+ .stat-popover {
1172
+ position: absolute;
1173
+ top: 100%;
1174
+ left: 0;
1175
+ margin-top: 6px;
1176
+ min-width: 300px;
1177
+ max-width: min(460px, 92vw);
1178
+ max-height: 340px;
1179
+ overflow-y: auto;
1180
+ z-index: 20;
1181
+ background: var(--panel);
1182
+ border: 1px solid var(--line);
1183
+ border-radius: var(--radius);
1184
+ box-shadow: 0 8px 28px rgba(31, 41, 55, 0.12);
1185
+ padding: 6px;
1186
+ }
1187
+ .stat-popover[hidden] {
1188
+ display: none;
1189
+ }
1190
+ .stat-pop-head {
1191
+ padding: 6px 10px 8px;
1192
+ font-size: 11.5px;
1193
+ font-weight: 700;
1194
+ letter-spacing: 0.03em;
1195
+ text-transform: uppercase;
1196
+ color: var(--muted);
1197
+ }
1198
+ .stat-row {
1199
+ display: flex;
1200
+ align-items: flex-start;
1201
+ gap: 10px;
1202
+ padding: 9px 11px;
1203
+ border-radius: 9px;
1204
+ border: 1px solid transparent;
1205
  text-decoration: none;
1206
+ color: inherit;
1207
+ cursor: pointer;
1208
  }
1209
+ .stat-row:hover {
1210
+ border-color: rgba(249, 115, 22, 0.4);
1211
+ background: var(--accent-soft);
 
1212
  }
1213
+ .stat-row-ico {
1214
+ font-size: 15px;
1215
+ line-height: 1.3;
1216
  flex: 0 0 auto;
 
 
 
 
 
1217
  }
1218
+ .stat-row-main {
1219
+ min-width: 0;
1220
+ flex: 1;
1221
+ }
1222
+ .stat-row-title {
1223
+ font-family: var(--mono);
1224
+ font-size: 12.5px;
1225
+ font-weight: 600;
1226
+ color: var(--ink);
1227
+ overflow: hidden;
1228
+ text-overflow: ellipsis;
1229
+ white-space: nowrap;
1230
+ }
1231
+ .stat-row-meta {
1232
+ margin-top: 2px;
1233
+ font-size: 12px;
1234
+ color: var(--muted);
1235
+ }
1236
+ .stat-row-state.open {
1237
+ color: var(--accent);
1238
+ font-weight: 600;
1239
+ border-radius: 5px;
1240
+ padding: 1px 5px;
1241
+ margin: -1px -2px;
1242
  }
1243
+ .stat-row-state.open:hover {
1244
+ background: rgba(249, 115, 22, 0.14);
1245
+ text-decoration: underline;
1246
  }
1247
  .art-ico {
1248
  width: 1em;
 
1250
  object-fit: contain;
1251
  vertical-align: -0.15em;
1252
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1253
 
1254
  /* ---- scroll-to-resource highlight ---- */
1255
  .res-flash {
 
1294
  font-size: 1.05em;
1295
  line-height: 1;
1296
  }
1297
+ #page .res-chip:hover,
1298
+ #page .res-chip.res-hl {
1299
+ border-color: var(--accent);
1300
+ background: var(--accent-soft);
1301
+ color: var(--accent-strong);
1302
+ }
1303
+ #page a.res-link.res-hl {
1304
+ background: var(--accent-soft);
1305
+ border-radius: 4px;
1306
+ }
1307
+ .rail-item.res-hl {
1308
+ border-color: var(--accent);
1309
+ background: var(--accent-soft);
1310
+ box-shadow: 0 3px 12px rgba(249, 115, 22, 0.14);
1311
+ }
1312
+ .rail-item.res-hl .rail-title {
1313
+ color: var(--accent-strong);
1314
+ }
1315
+ .rail-item.rail-local {
1316
+ cursor: default;
1317
+ }
1318
+ .artifact-chip.res-hl {
1319
  border-color: var(--accent);
1320
  background: var(--accent-soft);
1321
+ }
1322
+
1323
+ /* ---- contextual resources rail ---- */
1324
+ .context-rail {
1325
+ position: relative;
1326
+ width: 248px;
1327
+ }
1328
+ .context-rail[hidden] {
1329
+ display: none;
1330
+ }
1331
+ .rail-kind {
1332
+ display: flex;
1333
+ align-items: center;
1334
+ gap: 5px;
1335
+ font-family: var(--mono);
1336
+ font-size: 10px;
1337
+ text-transform: uppercase;
1338
+ letter-spacing: 0.08em;
1339
+ font-weight: 600;
1340
+ color: var(--accent);
1341
+ margin-bottom: 4px;
1342
+ }
1343
+ .rail-item {
1344
+ position: absolute;
1345
+ left: 0;
1346
+ right: 0;
1347
+ display: block;
1348
+ border: 1px solid var(--line);
1349
+ border-radius: 10px;
1350
+ background: var(--panel);
1351
+ padding: 9px 12px;
1352
+ margin-bottom: 8px;
1353
+ text-decoration: none;
1354
+ color: inherit;
1355
+ transition: border-color 0.14s, box-shadow 0.14s;
1356
+ }
1357
+ .rail-item:hover {
1358
+ border-color: rgba(249, 115, 22, 0.45);
1359
+ box-shadow: 0 3px 12px rgba(31, 41, 55, 0.06);
1360
+ }
1361
+ .rail-title {
1362
+ font-family: var(--mono);
1363
+ font-size: 12.5px;
1364
+ font-weight: 600;
1365
+ color: var(--ink);
1366
+ overflow-wrap: anywhere;
1367
+ line-height: 1.4;
1368
+ }
1369
+ .rail-item:hover .rail-title {
1370
  color: var(--accent-strong);
1371
  }
1372
+ .rail-meta {
1373
+ font-size: 11.5px;
1374
+ color: var(--muted);
1375
+ margin-top: 2px;
1376
+ }
1377
+
1378
+ @media (max-width: 1400px) {
1379
+ .page-layout {
1380
+ display: block;
1381
+ }
1382
+ .context-rail {
1383
+ width: 100%;
1384
+ margin-top: 28px;
1385
+ position: static;
1386
+ min-height: 0 !important;
1387
+ display: grid;
1388
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
1389
+ gap: 10px;
1390
+ }
1391
+ .context-rail[hidden] {
1392
+ display: none;
1393
+ }
1394
+ .context-rail .rail-item {
1395
+ position: static;
1396
+ margin-bottom: 0;
1397
+ }
1398
+ }
1399
 
1400
  /* ---- connect footer + modal ---- */
1401
  #sidebar-foot {
 
1571
  color: #52d08a;
1572
  }
1573
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1574
  @media (max-width: 720px) {
1575
  #app {
1576
  flex-direction: column;
 
1587
  padding: 28px 20px 80px;
1588
  overflow-x: hidden;
1589
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1590
  #page {
1591
  width: 100%;
1592
  max-width: 100%;
1593
  }
1594
+ #page h1 {
 
1595
  font-size: 30px;
1596
  }
1597
  .cell-head {
logbook.js CHANGED
@@ -4,12 +4,9 @@
4
  let MANIFEST = null;
5
  const PAGE_CACHE = {};
6
  const UNFURL_CACHE = {};
7
- const DATA_CACHE = {};
8
  const LIVE_RELOAD_MS = 1500;
9
  const FIGURE_FRAME_WINDOWS = new Set();
10
  let FIGURE_NAVIGATION_READY = false;
11
- let CURRENT_VIEW = null;
12
- let RENDER_SEQUENCE = 0;
13
 
14
  function esc(s) {
15
  return String(s)
@@ -289,10 +286,6 @@
289
  /(trackio-artifact:\/\/\S+|trackio-local-path:\/\/\S+|https:\/\/huggingface\.co\/buckets\/[^\s<)]+#\S+)/
290
  );
291
  if (chip && uri) chip.dataset.resUrl = uri[1];
292
- if (chip && meta.path) {
293
- const ico = chip.querySelector(".art-ico");
294
- if (ico) ico.outerHTML = FILE_ICON;
295
- }
296
  } else if (meta.type === "dashboard") {
297
  const sp = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
298
  cell.dataset.resUrl = sp
@@ -502,7 +495,7 @@
502
  if (!message || message.type !== "trackio-logbook:navigate") return;
503
  const target = String(message.target || "").replace(/^#?\//, "");
504
  if (!target || !MANIFEST || !findNode(MANIFEST.root, target)) return;
505
- const hash = "#/view/code/" + target;
506
  if (location.hash === hash) scrollToHash();
507
  else location.hash = hash;
508
  });
@@ -514,15 +507,6 @@
514
  '<path d="M8 3H3v5M16 3h5v5M21 16v5h-5M3 16v5h5"/>' +
515
  '<path d="M3 8 8 3M16 3l5 5M21 16l-5 5M8 21l-5-5"/></svg>';
516
 
517
- const PIN_ICON =
518
- '<svg class="pin-ico" viewBox="0 0 24 24" aria-hidden="true">' +
519
- '<path d="M16 9V4h1c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1h1v5c0 ' +
520
- '1.66-1.34 3-3 3v2h5.97v7l1 1 1-1v-7H19v-2c-1.66 0-3-1.34-3-3z"/></svg>';
521
-
522
- const FILE_ICON =
523
- '<svg class="art-file-ico" viewBox="0 0 24 24" aria-hidden="true">' +
524
- '<path d="M6 3.5h8l4 4V20H6zM14 3.5V8h4"/></svg>';
525
-
526
  // Figures are rendered in same-origin iframes, so fullscreen the fitted
527
  // wrapper rather than the iframe document. This uses the browser's native
528
  // fullscreen UI and preserves the figure's existing responsive sizing.
@@ -651,38 +635,13 @@
651
  ? `<span class="out-artifact-state open">Open ↗</span>`
652
  : `<span class="out-artifact-state">publish to share</span>`;
653
  const meta = parts.length ? `${parts.join(" · ")} · ${state}` : state;
654
- const icon = info.isPathRef ? FILE_ICON : ARTIFACT_ICON_IMG;
655
  el.innerHTML =
656
- `<span class="out-artifact-ico">${icon}</span>` +
657
  `<span class="out-artifact-name">${esc(info.name)}</span>` +
658
  `<span class="out-artifact-meta">${meta}</span>`;
659
  return el;
660
  }
661
 
662
- function isShellCommand(part) {
663
- return (
664
- part.kind === "code" &&
665
- part.lang === "bash" &&
666
- !part.title &&
667
- /^\s*\$\s/.test(part.text)
668
- );
669
- }
670
-
671
- function renderCommandLine(text) {
672
- const command = text.trim().replace(/^\$\s*/, "");
673
- const el = document.createElement("div");
674
- el.className = "jp-cmd";
675
- const prompt = document.createElement("span");
676
- prompt.className = "jp-cmd-prompt";
677
- prompt.textContent = "$";
678
- const code = document.createElement("code");
679
- code.textContent = command;
680
- el.appendChild(prompt);
681
- el.appendChild(code);
682
- el.appendChild(copySnippetBtn(command));
683
- return el;
684
- }
685
-
686
  function renderCodeCell(body, container, artifacts) {
687
  const parts = parseFences(body);
688
  const block = document.createElement("div");
@@ -735,13 +694,7 @@
735
  embedTexts.push(part.text);
736
  return;
737
  }
738
- if (isShellCommand(part)) {
739
- inputBody.appendChild(renderCommandLine(part.text));
740
- } else {
741
- inputBody.appendChild(
742
- renderCode(part.text, part.lang, part.title, Boolean(part.title))
743
- );
744
- }
745
  });
746
  if (artifacts && artifacts.length) {
747
  ensureOut();
@@ -960,13 +913,13 @@
960
  return btn;
961
  }
962
 
963
- function renderCode(code, lang, title, open) {
964
  const pre = document.createElement("pre");
965
  pre.className = "hl";
966
  const c = document.createElement("code");
967
  c.innerHTML = highlightCode(code, lang);
968
  pre.appendChild(c);
969
- if (!title || open) {
970
  const wrap = document.createElement("div");
971
  wrap.className = "snippet";
972
  wrap.appendChild(pre);
@@ -1030,7 +983,7 @@
1030
  });
1031
  }
1032
 
1033
- /* -------------------- resource classification -------------------- */
1034
 
1035
  function fmt(n) {
1036
  if (n == null) return null;
@@ -1058,6 +1011,18 @@
1058
  const ARTIFACT_ICON_IMG = `<img class="art-ico" src="./bucket-icon.svg" alt="" />`;
1059
  const DASHBOARD_ICON_IMG = `<img class="art-ico" src="./trackio-logo-light.png" alt="" />`;
1060
 
 
 
 
 
 
 
 
 
 
 
 
 
1061
  const HF_NON_MODEL_PREFIX =
1062
  /^(datasets|spaces|jobs|buckets|papers|blog|docs|api|posts|collections|organizations|settings|new|join|login|pricing|tasks|learn|chat|models)(\/|$)/;
1063
 
@@ -1065,23 +1030,6 @@
1065
  return url.split(marker)[1].split(/[?#]/)[0].replace(/\/$/, "");
1066
  }
1067
 
1068
- function validHfSegment(value) {
1069
- return Boolean(
1070
- value &&
1071
- value.length <= 96 &&
1072
- /^[A-Za-z0-9_.-]+$/.test(value) &&
1073
- !/^[.-]|[.-]$|--|\.\./.test(value)
1074
- );
1075
- }
1076
-
1077
- function validHfRepoId(parts) {
1078
- return (
1079
- parts.length === 2 &&
1080
- parts.join("/").length <= 96 &&
1081
- parts.every(validHfSegment)
1082
- );
1083
- }
1084
-
1085
  function classifyResource(url) {
1086
  if (IMG_URL.test(url)) {
1087
  return null;
@@ -1111,39 +1059,29 @@
1111
  local: true,
1112
  };
1113
  }
1114
- if ((m = url.match(/huggingface\.co\/buckets\/([^/#\s]+\/[^/#\s]+)#(.+)/))) {
1115
- if (!validHfRepoId(m[1].split("/"))) return null;
1116
- return { kind: "artifact", id: decodeURIComponent(m[2]), url };
1117
  }
1118
- if (/huggingface\.co\/datasets\//.test(url)) {
1119
- const parts = hfId(url, "/datasets/").split("/").slice(0, 2);
1120
- if (!validHfRepoId(parts)) return null;
1121
- return { kind: "dataset", id: parts.join("/"), url };
1122
  }
1123
- if (/huggingface\.co\/spaces\//.test(url)) {
1124
- const parts = hfId(url, "/spaces/").split("/").slice(0, 2);
1125
- if (!validHfRepoId(parts)) return null;
1126
- return { kind: "space", id: parts.join("/"), url };
1127
  }
1128
  if (/huggingface\.co\/jobs\//.test(url)) {
1129
- const parts = hfId(url, "/jobs/").split("/").slice(0, 2);
1130
- if (!validHfRepoId(parts)) return null;
1131
- const jid = parts[1];
1132
  return {
1133
  kind: "job",
1134
- id: parts[0] + ` · ${jid.slice(0, 12)}${jid.length > 12 ? "…" : ""}`,
1135
  url,
1136
  };
1137
  }
1138
  if (/huggingface\.co\/buckets\//.test(url)) {
1139
- const parts = hfId(url, "/buckets/").split("/").slice(0, 2);
1140
- if (!validHfRepoId(parts)) return null;
1141
- return { kind: "bucket", id: parts.join("/"), url };
1142
  }
1143
  if (/huggingface\.co\/papers\//.test(url)) {
1144
- const id = hfId(url, "/papers/").split("/")[0];
1145
- if (!validHfSegment(id)) return null;
1146
- return { kind: "paper", id: `Paper ${id}`, url };
1147
  }
1148
  if ((m = url.match(/arxiv\.org\/(?:abs|pdf)\/([^?#\s]+)/))) {
1149
  return { kind: "paper", id: `arXiv:${m[1].replace(/\.pdf$/, "")}`, url };
@@ -1153,13 +1091,324 @@
1153
  }
1154
  if ((m = url.match(/huggingface\.co\/([^?#]+)/))) {
1155
  const rest = m[1].replace(/\/$/, "");
1156
- if (validHfRepoId(rest.split("/")) && !HF_NON_MODEL_PREFIX.test(rest)) {
1157
  return { kind: "model", id: rest, url };
1158
  }
1159
  }
1160
  return null;
1161
  }
1162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1163
  function dashboardSubdomainFromUrl(url) {
1164
  return spaceIdFromUrl(url).toLowerCase().replace(/[^a-z0-9-]/g, "-");
1165
  }
@@ -1274,15 +1523,11 @@
1274
  function buildTree() {
1275
  const tree = document.getElementById("tree");
1276
  tree.innerHTML = "";
1277
- const label = document.createElement("div");
1278
- label.className = "tree-label";
1279
- label.textContent = "Pages";
1280
- tree.appendChild(label);
1281
  const nodes = [];
1282
  (MANIFEST.root.children || []).forEach((c) => flattenTree(c, 0, nodes));
1283
  nodes.forEach(({ node, depth }) => {
1284
  const a = document.createElement("a");
1285
- a.href = "#/view/code/" + node.slug;
1286
  a.className = "depth-" + depth;
1287
  a.dataset.slug = node.slug;
1288
  const mark = document.createElement("span");
@@ -1294,47 +1539,6 @@
1294
  });
1295
  }
1296
 
1297
- function highlightTraceSession(sessionId) {
1298
- document.querySelectorAll("#tree a").forEach((link) => {
1299
- link.classList.toggle("active", link.dataset.sessionId === sessionId);
1300
- });
1301
- }
1302
-
1303
- function buildTraceTree(activeSessionId, traceSessions = MANIFEST.traces || []) {
1304
- const tree = document.getElementById("tree");
1305
- tree.innerHTML = "";
1306
- const sessions = traceSessions;
1307
- if (!sessions.length) return;
1308
- const label = document.createElement("div");
1309
- label.className = "tree-label";
1310
- label.textContent = "Sessions";
1311
- tree.appendChild(label);
1312
- sessions.forEach((session) => {
1313
- const link = document.createElement("a");
1314
- link.href = "#" + traceSessionAnchor(session.id);
1315
- link.dataset.sessionId = session.id;
1316
- link.textContent = session.title || session.id;
1317
- link.title = session.title || session.id;
1318
- tree.appendChild(link);
1319
- });
1320
- highlightTraceSession(activeSessionId || sessions[0].id);
1321
- }
1322
-
1323
- function renderSidebar(route) {
1324
- if (route.view === "trace") {
1325
- highlight(null);
1326
- buildTraceTree(route.sessionId);
1327
- return;
1328
- }
1329
- if (route.view === "workspace") {
1330
- document.getElementById("tree").innerHTML = "";
1331
- highlight(null);
1332
- return;
1333
- }
1334
- buildTree();
1335
- highlight(route.slug);
1336
- }
1337
-
1338
  function highlight(slug) {
1339
  document
1340
  .querySelectorAll("#tree a")
@@ -1348,9 +1552,6 @@
1348
  Object.keys(PAGE_CACHE).forEach((key) => {
1349
  delete PAGE_CACHE[key];
1350
  });
1351
- Object.keys(DATA_CACHE).forEach((key) => {
1352
- delete DATA_CACHE[key];
1353
- });
1354
  }
1355
 
1356
  function isLocalPreview() {
@@ -1376,46 +1577,6 @@
1376
  return PAGE_CACHE[node.file];
1377
  }
1378
 
1379
- async function fetchData(file, cacheResult = true) {
1380
- if (cacheResult && DATA_CACHE[file]) return DATA_CACHE[file];
1381
- const suffix = isLocalPreview()
1382
- ? `?rev=${encodeURIComponent(MANIFEST.revision || "")}`
1383
- : "";
1384
- const response = await fetch("./" + file + suffix, { cache: "no-store" });
1385
- if (!response.ok) throw new Error(`Could not load ${file}`);
1386
- const data = await response.json();
1387
- if (cacheResult) DATA_CACHE[file] = data;
1388
- return data;
1389
- }
1390
-
1391
- async function fetchRemoteData(url, cacheResult = true) {
1392
- if (cacheResult && DATA_CACHE[url]) return DATA_CACHE[url];
1393
- const response = await fetch(url, { cache: "no-store" });
1394
- if (!response.ok) throw new Error(`Could not load ${url}`);
1395
- const data = await response.json();
1396
- if (cacheResult) DATA_CACHE[url] = data;
1397
- return data;
1398
- }
1399
-
1400
- function encodeRepoPath(path) {
1401
- return String(path || "")
1402
- .split("/")
1403
- .map((part) => encodeURIComponent(part))
1404
- .join("/");
1405
- }
1406
-
1407
- function repoFileUrl(ref, path) {
1408
- const revision = encodeURIComponent(ref.revision || "main");
1409
- const encodedPath = encodeRepoPath(path);
1410
- if (ref.repo_type === "dataset") {
1411
- return `https://huggingface.co/datasets/${ref.repo_id}/resolve/${revision}/${encodedPath}`;
1412
- }
1413
- if (ref.repo_type === "bucket") {
1414
- return `https://huggingface.co/buckets/${ref.repo_id}/resolve/${encodedPath}`;
1415
- }
1416
- return "";
1417
- }
1418
-
1419
  function allNodes() {
1420
  const nodes = [];
1421
  flattenTree(MANIFEST.root, 0, nodes);
@@ -1460,28 +1621,13 @@
1460
  cells.forEach(({ meta, body }) => {
1461
  const cell = renderCell(meta, body, list);
1462
  cell.classList.add("pinned-copy");
1463
- const title = cell.querySelector(".cell-title");
1464
- if (title) title.insertAdjacentHTML("afterbegin", PIN_ICON);
1465
  });
1466
  deck.appendChild(list);
1467
  const anchor =
1468
- container.querySelector(".agent-hint") ||
1469
- Array.from(container.children).find((el) => el.tagName === "H1");
1470
  container.insertBefore(deck, anchor ? anchor.nextSibling : container.firstChild);
1471
- const owner = container.closest(".page-section");
1472
- if (owner) owner.classList.add("has-pinned-notes");
1473
- }
1474
-
1475
- function isIndexPaperLink(el) {
1476
- if (!el || el.tagName !== "P") return false;
1477
- return Array.from(el.querySelectorAll("a[href]")).some((a) => {
1478
- const href = a.getAttribute("href") || "";
1479
- return (
1480
- /huggingface\.co\/papers\//.test(href) ||
1481
- /openreview\.net\//.test(href) ||
1482
- /arxiv\.org\//.test(href)
1483
- );
1484
- });
1485
  }
1486
 
1487
  function removeIndexProse(body) {
@@ -1490,11 +1636,7 @@
1490
  let current = h1.nextElementSibling;
1491
  while (current && current.tagName !== "H2") {
1492
  const next = current.nextElementSibling;
1493
- if (isIndexPaperLink(current)) {
1494
- current.classList.add("index-paper-link");
1495
- } else {
1496
- current.remove();
1497
- }
1498
  current = next;
1499
  }
1500
  }
@@ -1513,13 +1655,15 @@
1513
  }
1514
  }
1515
 
 
 
1516
  async function renderLogbook(opts = {}) {
1517
  const scrollY = window.scrollY;
1518
  const page = document.getElementById("page");
 
1519
  page.innerHTML = "";
1520
  const nodes = allNodes();
1521
  const markdown = await Promise.all(nodes.map(fetchPage));
1522
- if (opts.renderId && opts.renderId !== RENDER_SEQUENCE) return;
1523
  const pinnedCells = collectPinnedCells(markdown, nodes);
1524
  let bookIntroBody = null;
1525
  nodes.forEach((node, index) => {
@@ -1532,42 +1676,45 @@
1532
  layout.className = "page-layout";
1533
  const body = document.createElement("div");
1534
  body.className = "page-body";
 
 
 
1535
 
1536
  renderMarkdown(markdown[index], body);
1537
  if (node.slug === MANIFEST.root.slug) {
1538
  section.classList.add("book-intro");
1539
  removeIndexProse(body);
1540
  removePageDirectory(body);
 
1541
  const h1 = body.querySelector("h1");
1542
- if (h1 && h1.parentNode === body) h1.remove();
 
 
 
 
 
1543
  bookIntroBody = body;
1544
  }
1545
  layout.appendChild(body);
 
1546
  section.appendChild(layout);
1547
  page.appendChild(section);
 
 
 
 
 
 
 
1548
  });
1549
- const pinnedSlugs = Array.from(
1550
- new Set(pinnedCells.map((cell) => cell.node && cell.node.slug).filter(Boolean))
1551
- );
1552
- const pinnedTarget =
1553
- pinnedSlugs.length === 1
1554
- ? Array.from(page.querySelectorAll(".page-section"))
1555
- .find((section) => section.dataset.slug === pinnedSlugs[0])
1556
- ?.querySelector(".page-body")
1557
- : bookIntroBody;
1558
- if (pinnedTarget) renderPinnedNotes(pinnedCells, pinnedTarget);
1559
- // Pinned cells are promoted into one deck. Remove their source render so
1560
- // summaries, posters, and notes do not appear twice in the continuous view.
1561
- page
1562
- .querySelectorAll(".pinned-source:not(.pinned-copy)")
1563
- .forEach((cell) => cell.remove());
1564
  if (bookIntroBody) {
1565
  const section = bookIntroBody.closest(".book-intro");
1566
  const hasExtra = Array.from(bookIntroBody.children).some(
1567
  (el) =>
1568
  el.tagName !== "H1" &&
1569
  !el.classList.contains("agent-hint") &&
1570
- !el.classList.contains("index-paper-link") &&
1571
  !el.classList.contains("pinned-notes")
1572
  );
1573
  if (section && !section.classList.contains("has-pinned-notes") && !hasExtra) {
@@ -1584,6 +1731,29 @@
1584
  });
1585
  }
1586
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1587
  function fmtBytes(n) {
1588
  if (n == null || isNaN(n)) return null;
1589
  if (n < 1000) return `${n} B`;
@@ -1601,6 +1771,31 @@
1601
  return url.split("/spaces/")[1].split(/[?#]/)[0].replace(/\/$/, "");
1602
  }
1603
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1604
  function artifactInfoFromCell(meta, body) {
1605
  const name = meta.artifact || meta.path || "";
1606
  let size = null;
@@ -1625,1169 +1820,280 @@
1625
  };
1626
  }
1627
 
1628
- const VIEW_ROUTE = { trace: "#/view/trace", workspace: "#/view/workspace" };
1629
- const VIEW_TOKENS = {
1630
- code: "agent_view_tokens",
1631
- trace: "trace_view_tokens",
1632
- workspace: "workspace_view_tokens",
1633
- };
1634
-
1635
- function readTarget(view) {
1636
- const onSpaces =
1637
- /\.hf\.space$/.test(location.hostname) ||
1638
- /(^|\.)huggingface\.co$/.test(location.hostname);
1639
- let base = "";
1640
- if (onSpaces && MANIFEST.space_id) base = MANIFEST.space_id;
1641
- else if (/^https?:$/.test(location.protocol))
1642
- base = `${location.origin}${location.pathname}`;
1643
- if (!base) return "";
1644
- return base + (VIEW_ROUTE[view] || "");
1645
- }
1646
-
1647
- function renderLogbookHeader(view) {
1648
- const title = document.getElementById("logbook-title");
1649
- if (title) title.textContent = MANIFEST.title;
1650
- const cli = document.getElementById("logbook-cli");
1651
- if (!cli) return;
1652
- cli.innerHTML = "";
1653
- cli.appendChild(buildAgentHint(view));
1654
- const destination = buildHubDestinationLink(view);
1655
- if (destination) cli.appendChild(destination);
1656
- }
1657
-
1658
- function hubDestination(view) {
1659
- if (view === "trace" && MANIFEST.trace_dataset) {
1660
- return {
1661
- label: "View Hugging Face dataset:",
1662
- url: MANIFEST.trace_dataset,
1663
- fallback: "Agent Traces dataset",
1664
- };
1665
- }
1666
- if (view === "workspace") {
1667
- const bucketId = (MANIFEST.workspace || {}).bucket_id;
1668
- const url =
1669
- MANIFEST.workspace_bucket ||
1670
- (bucketId ? `https://huggingface.co/buckets/${bucketId}` : "");
1671
- if (url) {
1672
- return {
1673
- label: "View Hugging Face Bucket:",
1674
- url,
1675
- fallback: "Workspace Bucket",
1676
- };
1677
  }
1678
  }
1679
- return null;
1680
- }
1681
-
1682
- function buildHubDestinationLink(view) {
1683
- const destination = hubDestination(view);
1684
- if (!destination || !destination.url.startsWith("https://huggingface.co/")) {
1685
- return null;
1686
- }
1687
- const row = document.createElement("div");
1688
- row.className = "hub-destination";
1689
- const label = document.createElement("span");
1690
- label.textContent = destination.label;
1691
- const link = document.createElement("a");
1692
- link.href = destination.url;
1693
- link.target = "_blank";
1694
- link.rel = "noopener noreferrer";
1695
- link.textContent =
1696
- destination.url
1697
- .replace(/^https:\/\/huggingface\.co\/(?:datasets|buckets)\//, "")
1698
- .replace(/\/$/, "") || destination.fallback;
1699
- link.title = destination.url;
1700
- const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
1701
- icon.setAttribute("viewBox", "0 0 24 24");
1702
- icon.setAttribute("aria-hidden", "true");
1703
- const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
1704
- path.setAttribute("d", "M14 5h5v5M19 5l-8 8M19 13v5a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h5");
1705
- icon.appendChild(path);
1706
- link.appendChild(icon);
1707
- row.appendChild(label);
1708
- row.appendChild(link);
1709
- return row;
1710
- }
1711
-
1712
- function buildAgentHint(view) {
1713
- const target = readTarget(view);
1714
- const command = `trackio logbook read${target ? ` ${target}` : ""}`;
1715
- const tokens = MANIFEST[VIEW_TOKENS[view] || VIEW_TOKENS.code];
1716
- const div = document.createElement("div");
1717
- div.className = "agent-hint";
1718
- const label = document.createElement("span");
1719
- label.className = "agent-hint-label";
1720
- label.textContent = "Read from the CLI:";
1721
- const code = document.createElement("code");
1722
- code.textContent = command;
1723
- const copy = document.createElement("button");
1724
- copy.className = "copy";
1725
- copy.type = "button";
1726
- copy.title = "Copy";
1727
- copy.textContent = "⧉";
1728
- copy.addEventListener("click", () => copyText(command, copy, "⧉"));
1729
- const note = document.createElement("span");
1730
- note.className = "agent-hint-note";
1731
- note.textContent =
1732
- "compact view for agents" + (tokens ? ` · ~${fmt(tokens)} tokens` : "");
1733
- div.appendChild(label);
1734
- div.appendChild(code);
1735
- div.appendChild(copy);
1736
- div.appendChild(note);
1737
- return div;
1738
- }
1739
-
1740
- function routeState() {
1741
- const raw = (location.hash || "").replace(/^#\/?/, "");
1742
- if (!raw) return { view: "code", slug: MANIFEST.root.slug };
1743
- const parts = raw.split("/");
1744
- if (parts[0] !== "view") {
1745
- const slug = findNode(MANIFEST.root, raw) ? raw : MANIFEST.root.slug;
1746
- return { view: "code", slug };
1747
- }
1748
- if (parts[1] === "trace") {
1749
- return { view: "trace", sessionId: parts.slice(2).join("/") || null };
1750
- }
1751
- if (parts[1] === "workspace") return { view: "workspace" };
1752
- const candidate = parts.slice(2).join("/") || MANIFEST.root.slug;
1753
- return {
1754
- view: "code",
1755
- slug: findNode(MANIFEST.root, candidate) ? candidate : MANIFEST.root.slug,
1756
- };
1757
- }
1758
-
1759
- function updateViewTabs(route = routeState()) {
1760
- document.querySelectorAll("#view-tabs a").forEach((tab) => {
1761
- const view = tab.dataset.view;
1762
- tab.classList.toggle("active", view === route.view);
1763
- tab.setAttribute("aria-current", view === route.view ? "page" : "false");
1764
- if (view === "code") {
1765
- const slug = route.view === "code" ? route.slug : MANIFEST.root.slug;
1766
- tab.href = `#/view/code/${slug}`;
1767
- } else if (view === "trace") {
1768
- tab.href = "#/view/trace";
1769
  }
1770
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1771
  }
1772
 
1773
- function setActiveView(route) {
1774
- CURRENT_VIEW = route.view;
1775
- document.body.dataset.view = route.view;
1776
- updateViewTabs(route);
1777
- renderLogbookHeader(route.view);
1778
- renderSidebar(route);
1779
- }
1780
-
1781
- function formatDuration(ms) {
1782
- if (ms == null || isNaN(ms)) return "—";
1783
- const total = Math.max(0, Math.floor(ms / 1000));
1784
- const hours = Math.floor(total / 3600);
1785
- const minutes = Math.floor((total % 3600) / 60);
1786
- const seconds = total % 60;
1787
- if (hours) return `${hours}h ${minutes}m ${seconds}s`;
1788
- if (minutes) return `${minutes}m ${seconds}s`;
1789
- return `${seconds}s`;
1790
  }
1791
 
1792
- function formatDate(value) {
1793
- if (!value) return "—";
1794
- const date = new Date(value);
1795
- if (isNaN(date.getTime())) return value;
1796
- return date.toLocaleString([], {
1797
- year: "numeric",
1798
- month: "short",
1799
- day: "numeric",
1800
- hour: "numeric",
1801
- minute: "2-digit",
1802
- second: "2-digit",
1803
  });
1804
  }
1805
 
1806
- function emptyView(title, text, command) {
1807
- const empty = document.createElement("div");
1808
- empty.className = "view-empty";
1809
- const heading = document.createElement("h2");
1810
- heading.textContent = title;
1811
- const body = document.createElement("p");
1812
- body.textContent = text;
1813
- empty.appendChild(heading);
1814
- empty.appendChild(body);
1815
- if (command) {
1816
- const code = document.createElement("code");
1817
- code.textContent = command;
1818
- empty.appendChild(code);
1819
- }
1820
- return empty;
1821
- }
1822
-
1823
- function traceEventLabel(event) {
1824
- if (event.kind === "reasoning") return "Thought";
1825
- if (event.kind === "tool_call") return event.tool_name || event.title || "Tool";
1826
- if (event.kind === "tool_result") return "Tool output";
1827
- return event.title || event.kind || "Event";
1828
- }
1829
-
1830
- function appendTraceResult(entry, result) {
1831
- if (!entry || !result || !result.output) return;
1832
- const card = entry.querySelector(".trace-card");
1833
- if (!card) return;
1834
- const details = document.createElement("details");
1835
- details.className = "trace-output";
1836
- const summary = document.createElement("summary");
1837
- summary.textContent = result.status === "error" ? "Error output" : "Output";
1838
- const output = document.createElement("pre");
1839
- output.textContent = result.output;
1840
- details.appendChild(summary);
1841
- details.appendChild(output);
1842
- card.appendChild(details);
1843
- }
1844
-
1845
- function traceEventCard(event, result) {
1846
- const entry = document.createElement("div");
1847
- entry.className = `trace-entry trace-${event.kind || "status"}`;
1848
- entry.style.setProperty("--trace-depth", Math.min(Number(event.depth) || 0, 4));
1849
-
1850
- const rail = document.createElement("div");
1851
- rail.className = "trace-rail";
1852
- const number = document.createElement("span");
1853
- number.className = "trace-number";
1854
- number.textContent = `#${event.sequence || ""}`;
1855
- const dot = document.createElement("span");
1856
- dot.className = "trace-dot";
1857
- const elapsed = document.createElement("span");
1858
- elapsed.className = "trace-elapsed";
1859
- elapsed.textContent = formatDuration(event.elapsed_ms);
1860
- rail.appendChild(number);
1861
- rail.appendChild(dot);
1862
- rail.appendChild(elapsed);
1863
-
1864
- const card = document.createElement("article");
1865
- card.className = "trace-card";
1866
- const head = document.createElement("header");
1867
- const kind = document.createElement("span");
1868
- kind.className = "trace-kind";
1869
- kind.textContent = traceEventLabel(event);
1870
- head.appendChild(kind);
1871
- if (event.turn) {
1872
- const turn = document.createElement("span");
1873
- turn.className = "trace-turn";
1874
- turn.textContent = `turn ${event.turn}`;
1875
- head.appendChild(turn);
1876
- }
1877
- card.appendChild(head);
1878
-
1879
- const bodyText = event.text || event.input || event.output;
1880
- if (bodyText) {
1881
- const body = document.createElement(
1882
- event.kind === "tool_call" || event.kind === "tool_result" ? "pre" : "div"
1883
- );
1884
- body.className = "trace-body";
1885
- body.textContent = bodyText;
1886
- card.appendChild(body);
1887
- }
1888
- if (event.status) {
1889
- const status = document.createElement("span");
1890
- status.className = `trace-status-badge trace-status-badge-${event.status}`;
1891
- status.textContent = String(event.status).replace(/_/g, " ");
1892
- head.appendChild(status);
1893
- }
1894
- entry.appendChild(rail);
1895
- entry.appendChild(card);
1896
- appendTraceResult(entry, result);
1897
- return entry;
1898
- }
1899
-
1900
- function traceSessionAnchor(id) {
1901
- return "/view/trace/" + id;
1902
  }
1903
 
1904
- function buildTraceSession(session, index, loadTraceData = fetchData) {
1905
- const sec = document.createElement("section");
1906
- sec.className = "trace-session";
1907
- sec.id = traceSessionAnchor(session.id);
1908
- sec.dataset.sessionId = session.id;
1909
-
1910
- const title = document.createElement("h2");
1911
- title.className = "trace-session-title";
1912
- title.textContent = session.title || session.id;
1913
- sec.appendChild(title);
1914
-
1915
- const meta = document.createElement("div");
1916
- meta.className = "trace-meta";
1917
- [
1918
- ["Started", formatDate(index.started_at)],
1919
- ["Ended", formatDate(index.ended_at)],
1920
- ["Duration", formatDuration(index.duration_ms)],
1921
- ["Events", String(index.event_count || 0)],
1922
- ].forEach(([label, value]) => {
1923
- const item = document.createElement("span");
1924
- const strong = document.createElement("strong");
1925
- strong.textContent = label;
1926
- item.appendChild(strong);
1927
- item.appendChild(document.createTextNode(` ${value}`));
1928
- meta.appendChild(item);
1929
- });
1930
- if (index.model) {
1931
- const model = document.createElement("span");
1932
- const strong = document.createElement("strong");
1933
- strong.textContent = "Model";
1934
- model.appendChild(strong);
1935
- model.appendChild(document.createTextNode(` ${index.model}`));
1936
- meta.appendChild(model);
1937
- }
1938
- if (index.source_available === false) {
1939
- const missing = document.createElement("span");
1940
- missing.className = "trace-source-missing";
1941
- missing.textContent = "Source file unavailable · showing last capture";
1942
- meta.appendChild(missing);
1943
- }
1944
- sec.appendChild(meta);
1945
-
1946
- const timeline = document.createElement("section");
1947
- timeline.className = "trace-timeline";
1948
- sec.appendChild(timeline);
1949
-
1950
- const chunks = index.chunks || [];
1951
- if (!chunks.length) {
1952
- timeline.appendChild(
1953
- emptyView("Empty trace", "No displayable events were found in this session.")
1954
- );
1955
- return sec;
1956
- }
1957
-
1958
- const controls = document.createElement("div");
1959
- controls.className = "trace-load-controls";
1960
- const progress = document.createElement("span");
1961
- progress.className = "trace-load-progress";
1962
- const loadMore = document.createElement("button");
1963
- loadMore.type = "button";
1964
- loadMore.className = "trace-load-more";
1965
- controls.appendChild(progress);
1966
- controls.appendChild(loadMore);
1967
- sec.appendChild(controls);
1968
-
1969
- let nextChunk = 0;
1970
- let loadedEvents = 0;
1971
- let loading = false;
1972
- const pendingCalls = new Map();
1973
-
1974
- function updateLoadControls() {
1975
- const total = Number(index.event_count) || chunks.reduce(
1976
- (sum, chunk) => sum + (Number(chunk.count) || 0),
1977
- 0
1978
- );
1979
- progress.textContent = `${Math.min(loadedEvents, total)} of ${total} events loaded`;
1980
- if (nextChunk >= chunks.length) {
1981
- loadMore.textContent = "All events loaded";
1982
- loadMore.disabled = true;
1983
- return;
1984
- }
1985
- const count = Number(chunks[nextChunk].count) || "next";
1986
- loadMore.textContent = `Load ${count} more events`;
1987
- loadMore.disabled = false;
1988
- }
1989
-
1990
- async function loadNextTraceChunk() {
1991
- if (loading || nextChunk >= chunks.length) return;
1992
- loading = true;
1993
- loadMore.disabled = true;
1994
- loadMore.textContent = "Loading…";
1995
- const descriptor = chunks[nextChunk];
1996
- try {
1997
- // Event chunks can be large. Do not retain the parsed JSON in DATA_CACHE;
1998
- // the rendered DOM is the only long-lived copy.
1999
- const chunk = await loadTraceData(descriptor.file, false);
2000
- const events = chunk.events || [];
2001
- events.forEach((event) => {
2002
- if (
2003
- event.kind === "tool_result" &&
2004
- event.call_id &&
2005
- pendingCalls.has(event.call_id)
2006
- ) {
2007
- appendTraceResult(pendingCalls.get(event.call_id), event);
2008
- pendingCalls.delete(event.call_id);
2009
  return;
2010
  }
2011
- const entry = traceEventCard(event);
2012
- timeline.appendChild(entry);
2013
- if (event.kind === "tool_call" && event.call_id) {
2014
- pendingCalls.set(event.call_id, entry);
2015
- }
2016
  });
2017
- loadedEvents += events.length;
2018
- nextChunk += 1;
2019
- sec.dataset.loadedChunks = String(nextChunk);
2020
- updateLoadControls();
2021
- } catch (error) {
2022
- progress.textContent = "Could not load the next trace segment.";
2023
- loadMore.textContent = "Retry";
2024
- loadMore.disabled = false;
2025
- } finally {
2026
- loading = false;
2027
  }
2028
- }
2029
-
2030
- sec.dataset.loadedChunks = "0";
2031
- sec.loadNextTraceChunk = loadNextTraceChunk;
2032
- loadMore.addEventListener("click", loadNextTraceChunk);
2033
- updateLoadControls();
2034
- return sec;
2035
- }
2036
-
2037
- function ensureTraceSessionLoaded(sessionId) {
2038
- const target = document.getElementById(traceSessionAnchor(sessionId));
2039
- if (
2040
- target &&
2041
- target.dataset.loadedChunks === "0" &&
2042
- typeof target.loadNextTraceChunk === "function"
2043
- ) {
2044
- return target.loadNextTraceChunk();
2045
- }
2046
- return Promise.resolve();
2047
- }
2048
-
2049
- function scrollToTraceSession(sessionId) {
2050
- if (!sessionId) {
2051
- window.scrollTo({ top: 0, behavior: "auto" });
2052
- return;
2053
- }
2054
- const target = document.getElementById(traceSessionAnchor(sessionId));
2055
- if (target) target.scrollIntoView({ behavior: "auto" });
2056
- else window.scrollTo({ top: 0, behavior: "auto" });
2057
- }
2058
-
2059
- // A published static Space may store only a reference to a private (or
2060
- // public) repository instead of embedding trace/workspace content. These
2061
- // helpers render that reference: link-only for private/inaccessible repos,
2062
- // and a probe-then-render path for public ones.
2063
- function repoRefCard(ref, opts) {
2064
- const wrap = document.createElement("div");
2065
- wrap.className = "view-empty repo-ref-card";
2066
- const h = document.createElement("h2");
2067
- h.textContent = opts.title;
2068
- wrap.appendChild(h);
2069
- const p = document.createElement("p");
2070
- p.textContent = opts.message;
2071
- wrap.appendChild(p);
2072
- if (ref && ref.repo_url) {
2073
- const a = document.createElement("a");
2074
- a.className = "repo-ref-link";
2075
- a.href = ref.repo_url;
2076
- a.target = "_blank";
2077
- a.rel = "noopener noreferrer";
2078
- a.textContent = "Open on the Hub ↗";
2079
- wrap.appendChild(a);
2080
- }
2081
- return wrap;
2082
- }
2083
-
2084
- async function probeRepoAccessible(ref) {
2085
- if (!ref || !ref.repo_id) return false;
2086
- let url = "";
2087
- if (ref.repo_type === "dataset") {
2088
- url = "https://huggingface.co/api/datasets/" + ref.repo_id;
2089
- } else if (ref.repo_type === "bucket") {
2090
- url = "https://huggingface.co/api/buckets/" + ref.repo_id;
2091
- }
2092
- if (!url) return ref.private === false;
2093
- try {
2094
- const response = await fetch(url, { cache: "no-store" });
2095
- if (!response.ok) return false;
2096
- const metadata = await response.json();
2097
- return metadata.private !== true;
2098
- } catch (error) {
2099
- return false;
2100
- }
2101
- }
2102
-
2103
- async function renderRepoReference(ref, kind, page, renderId) {
2104
- const isTraces = kind === "traces";
2105
- const noun = isTraces ? "agent traces" : "workspace files";
2106
- const linkOnly = () =>
2107
- repoRefCard(ref, {
2108
- title: isTraces ? "Agent traces" : "Workspace",
2109
- message:
2110
- `These ${noun} live in a private repository. ` +
2111
- "Open it on the Hub to view them.",
2112
- });
2113
- const accessible = await probeRepoAccessible(ref);
2114
- if (renderId !== RENDER_SEQUENCE) return;
2115
- if (!accessible) {
2116
- page.appendChild(linkOnly());
2117
- return;
2118
- }
2119
- page.appendChild(
2120
- repoRefCard(ref, {
2121
- title: isTraces ? "Agent traces" : "Workspace",
2122
- message:
2123
- `These ${noun} are published to a public repository on the Hub.`,
2124
- })
2125
- );
2126
- }
2127
-
2128
- async function loadPublicTraceSource(ref) {
2129
- const viewerPath = String(ref.viewer_path || "trackio/index.json")
2130
- .split("/")
2131
- .filter((part) => part && part !== "." && part !== "..")
2132
- .join("/");
2133
- const slash = viewerPath.lastIndexOf("/");
2134
- const root = slash >= 0 ? viewerPath.slice(0, slash + 1) : "";
2135
- const index = await fetchRemoteData(repoFileUrl(ref, viewerPath));
2136
- const sessions = Array.isArray(index.sessions) ? index.sessions : [];
2137
- if (!sessions.length) throw new Error("The trace dataset has no sessions");
2138
- return {
2139
- sessions,
2140
- loadData: (file, cacheResult = true) =>
2141
- fetchRemoteData(repoFileUrl(ref, root + file), cacheResult),
2142
  };
2143
- }
2144
-
2145
- async function renderTrace(route, renderId) {
2146
- const page = document.getElementById("page");
2147
- page.innerHTML = "";
2148
- page.className = "trace-page";
2149
- let sessions = MANIFEST.traces || [];
2150
- let loadTraceData = fetchData;
2151
- if (!sessions.length) {
2152
- updateViewTabs({ view: "trace" });
2153
- if (MANIFEST.traces_ref && MANIFEST.traces_ref.repo_url) {
2154
- const accessible = await probeRepoAccessible(MANIFEST.traces_ref);
2155
- if (renderId !== RENDER_SEQUENCE) return;
2156
- if (accessible) {
2157
- try {
2158
- const remote = await loadPublicTraceSource(MANIFEST.traces_ref);
2159
- sessions = remote.sessions;
2160
- loadTraceData = remote.loadData;
2161
- buildTraceTree(route.sessionId, sessions);
2162
- } catch (error) {
2163
- page.appendChild(
2164
- repoRefCard(MANIFEST.traces_ref, {
2165
- title: "Agent traces",
2166
- message:
2167
- "These agent traces are published to a public repository on the Hub, but the web timeline could not be loaded.",
2168
- })
2169
- );
2170
- return;
2171
- }
2172
- } else {
2173
- await renderRepoReference(MANIFEST.traces_ref, "traces", page, renderId);
2174
- return;
2175
- }
2176
- } else {
2177
- page.appendChild(
2178
- emptyView(
2179
- "No agent sessions attached yet",
2180
- "Attach the active session once and Trackio will keep its trace refreshed here while you work. The session stays local until you explicitly publish it.",
2181
- "trackio logbook attach trace <session.jsonl>"
2182
- )
2183
- );
2184
- return;
2185
  }
2186
- }
2187
- updateViewTabs({ view: "trace" });
2188
-
2189
- const loading = document.createElement("div");
2190
- loading.className = "view-loading";
2191
- loading.textContent = "Loading traces…";
2192
- page.appendChild(loading);
2193
- let loaded;
2194
- try {
2195
- loaded = await Promise.all(
2196
- sessions.map(async (session) => {
2197
- const index = await loadTraceData(session.index_file);
2198
- return { session, index };
2199
- })
2200
- );
2201
- } catch (error) {
2202
- if (renderId !== RENDER_SEQUENCE) return;
2203
- page.innerHTML = "";
2204
- page.appendChild(
2205
- emptyView("Trace unavailable", "The normalized traces could not be loaded.")
2206
- );
2207
- return;
2208
- }
2209
- if (renderId !== RENDER_SEQUENCE) return;
2210
- page.innerHTML = "";
2211
-
2212
- const shell = document.createElement("div");
2213
- shell.className = "trace-shell";
2214
- loaded.forEach(({ session, index }) => {
2215
- shell.appendChild(buildTraceSession(session, index, loadTraceData));
2216
- });
2217
- page.appendChild(shell);
2218
- const activeSessionId = route.sessionId || sessions[0].id;
2219
- await ensureTraceSessionLoaded(activeSessionId);
2220
- if (renderId !== RENDER_SEQUENCE) return;
2221
- scrollToTraceSession(route.sessionId);
2222
- }
2223
-
2224
- function svgIcon(kind) {
2225
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
2226
- svg.setAttribute("viewBox", "0 0 24 24");
2227
- svg.setAttribute("aria-hidden", "true");
2228
- const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
2229
- path.setAttribute(
2230
- "d",
2231
- kind === "folder"
2232
- ? "M3.5 6.5h6l2 2h9v9a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z"
2233
- : kind === "download"
2234
- ? "M12 3v12m0 0 4-4m-4 4-4-4M5 20h14"
2235
- : "M6 3.5h8l4 4V20H6zM14 3.5V8h4"
2236
- );
2237
- svg.appendChild(path);
2238
- return svg;
2239
- }
2240
-
2241
- function workspaceTree(files) {
2242
- const root = { directories: new Map(), files: [] };
2243
- files.forEach((file) => {
2244
- const parts = file.path.split("/");
2245
- let cursor = root;
2246
- parts.slice(0, -1).forEach((name) => {
2247
- if (!cursor.directories.has(name)) {
2248
- cursor.directories.set(name, { directories: new Map(), files: [] });
2249
- }
2250
- cursor = cursor.directories.get(name);
2251
- });
2252
- cursor.files.push(file);
2253
- });
2254
- return root;
2255
- }
2256
-
2257
- function workspaceFileRow(file) {
2258
- const row = document.createElement("div");
2259
- row.className = "workspace-file";
2260
- const name = document.createElement("div");
2261
- name.className = "workspace-file-name";
2262
- name.appendChild(svgIcon("file"));
2263
- const label = document.createElement("span");
2264
- label.textContent = file.name;
2265
- label.title = file.path;
2266
- name.appendChild(label);
2267
- const type = document.createElement("span");
2268
- type.className = "workspace-file-type";
2269
- type.textContent = file.type || "file";
2270
- const size = document.createElement("span");
2271
- size.className = "workspace-file-size";
2272
- size.textContent = fmtBytes(file.size) || "—";
2273
- const modified = document.createElement("time");
2274
- modified.className = "workspace-file-time";
2275
- modified.dateTime = file.modified_at || "";
2276
- modified.textContent = formatDate(file.modified_at);
2277
- row.appendChild(name);
2278
- row.appendChild(type);
2279
- row.appendChild(size);
2280
- row.appendChild(modified);
2281
- const url =
2282
- isLocalPreview() && file.local_url
2283
- ? file.local_url
2284
- : file.download_url || file.bucket_url;
2285
- if (url) {
2286
- const download = document.createElement("a");
2287
- download.className = "workspace-download";
2288
- download.href = url;
2289
- download.title = "Download";
2290
- download.setAttribute("aria-label", `Download ${file.name}`);
2291
- if (isLocalPreview() && file.local_url) download.download = file.name;
2292
- download.appendChild(svgIcon("download"));
2293
- row.appendChild(download);
2294
- } else {
2295
- const pending = document.createElement("span");
2296
- pending.className = "workspace-unpublished";
2297
- pending.textContent = "Local";
2298
- row.appendChild(pending);
2299
- }
2300
- return row;
2301
- }
2302
-
2303
- function renderWorkspaceNode(node, container) {
2304
- Array.from(node.directories.entries())
2305
- .sort(([a], [b]) => a.localeCompare(b))
2306
- .forEach(([name, child]) => {
2307
- const details = document.createElement("details");
2308
- details.className = "workspace-folder";
2309
- details.open = true;
2310
- const summary = document.createElement("summary");
2311
- summary.appendChild(svgIcon("folder"));
2312
- const label = document.createElement("span");
2313
- label.textContent = name;
2314
- summary.appendChild(label);
2315
- details.appendChild(summary);
2316
- const children = document.createElement("div");
2317
- children.className = "workspace-folder-children";
2318
- renderWorkspaceNode(child, children);
2319
- details.appendChild(children);
2320
- container.appendChild(details);
2321
- });
2322
- node.files
2323
- .sort((a, b) => a.name.localeCompare(b.name))
2324
- .forEach((file) => container.appendChild(workspaceFileRow(file)));
2325
- }
2326
-
2327
- const WORKSPACE_MODE_KEY = "trackio-logbook:workspace-mode";
2328
-
2329
- function getWorkspaceMode() {
2330
- try {
2331
- return localStorage.getItem(WORKSPACE_MODE_KEY) === "type" ? "type" : "tree";
2332
- } catch (error) {
2333
- return "tree";
2334
- }
2335
- }
2336
-
2337
- function setWorkspaceMode(mode) {
2338
- try {
2339
- localStorage.setItem(WORKSPACE_MODE_KEY, mode);
2340
- } catch (error) {
2341
- /* ignore storage failures (private mode, etc.) */
2342
- }
2343
- }
2344
-
2345
- function fileGroupKey(file) {
2346
- if (file.type) return file.type;
2347
- const name = file.name || file.path || "";
2348
- const dot = name.lastIndexOf(".");
2349
- if (dot > 0 && dot < name.length - 1) return name.slice(dot + 1).toLowerCase();
2350
- return "other";
2351
- }
2352
-
2353
- function renderWorkspaceByType(files, container) {
2354
- const groups = new Map();
2355
- files.forEach((file) => {
2356
- const key = fileGroupKey(file);
2357
- if (!groups.has(key)) groups.set(key, []);
2358
- groups.get(key).push(file);
2359
- });
2360
- Array.from(groups.keys())
2361
- .sort((a, b) => a.localeCompare(b))
2362
- .forEach((key) => {
2363
- const items = groups
2364
- .get(key)
2365
- .sort((a, b) => a.name.localeCompare(b.name));
2366
- const section = document.createElement("div");
2367
- section.className = "workspace-group";
2368
- const heading = document.createElement("h3");
2369
- heading.className = "workspace-group-head";
2370
- const label = document.createElement("span");
2371
- label.textContent = key;
2372
- const count = document.createElement("span");
2373
- count.className = "workspace-group-count";
2374
- count.textContent = String(items.length);
2375
- heading.appendChild(label);
2376
- heading.appendChild(count);
2377
- section.appendChild(heading);
2378
- items.forEach((file) => section.appendChild(workspaceFileRow(file)));
2379
- container.appendChild(section);
2380
- });
2381
- }
2382
-
2383
- function buildWorkspaceToggle(current, onChange) {
2384
- const toggle = document.createElement("div");
2385
- toggle.className = "workspace-toggle";
2386
- toggle.setAttribute("role", "group");
2387
- toggle.setAttribute("aria-label", "Workspace layout");
2388
- const buttons = [];
2389
- [
2390
- ["tree", "Tree"],
2391
- ["type", "By type"],
2392
- ].forEach(([mode, text]) => {
2393
- const btn = document.createElement("button");
2394
- btn.type = "button";
2395
- btn.className = "workspace-toggle-btn";
2396
- btn.textContent = text;
2397
- const setActive = (active) => {
2398
- btn.classList.toggle("is-active", active);
2399
- btn.setAttribute("aria-pressed", active ? "true" : "false");
2400
- };
2401
- setActive(mode === current);
2402
- btn.addEventListener("click", () => {
2403
- buttons.forEach((entry) => entry.setActive(entry.mode === mode));
2404
- onChange(mode);
2405
- });
2406
- buttons.push({ mode, setActive });
2407
- toggle.appendChild(btn);
2408
- });
2409
- return toggle;
2410
- }
2411
-
2412
- const HF_LOGO_DATA_URI = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NSIgaGVpZ2h0PSI4OCIgZmlsbD0ibm9uZSI+Cgk8cGF0aCBmaWxsPSIjRkZEMjFFIiBkPSJNNDcuMjEgNzYuNWEzNC43NSAzNC43NSAwIDEgMCAwLTY5LjUgMzQuNzUgMzQuNzUgMCAwIDAgMCA2OS41WiIgLz4KCTxwYXRoCgkJZmlsbD0iI0ZGOUQwQiIKCQlkPSJNODEuOTYgNDEuNzVhMzQuNzUgMzQuNzUgMCAxIDAtNjkuNSAwIDM0Ljc1IDM0Ljc1IDAgMCAwIDY5LjUgMFptLTczLjUgMGEzOC43NSAzOC43NSAwIDEgMSA3Ny41IDAgMzguNzUgMzguNzUgMCAwIDEtNzcuNSAwWiIKCS8+Cgk8cGF0aAoJCWZpbGw9IiMzQTNCNDUiCgkJZD0iTTU4LjUgMzIuM2MxLjI4LjQ0IDEuNzggMy4wNiAzLjA3IDIuMzhhNSA1IDAgMSAwLTYuNzYtMi4wN2MuNjEgMS4xNSAyLjU1LS43MiAzLjctLjMyWk0zNC45NSAzMi4zYy0xLjI4LjQ0LTEuNzkgMy4wNi0zLjA3IDIuMzhhNSA1IDAgMSAxIDYuNzYtMi4wN2MtLjYxIDEuMTUtMi41Ni0uNzItMy43LS4zMloiCgkvPgoJPHBhdGgKCQlmaWxsPSIjRkYzMjNEIgoJCWQ9Ik00Ni45NiA1Ni4yOWM5LjgzIDAgMTMtOC43NiAxMy0xMy4yNiAwLTIuMzQtMS41Ny0xLjYtNC4wOS0uMzYtMi4zMyAxLjE1LTUuNDYgMi43NC04LjkgMi43NC03LjE5IDAtMTMtNi44OC0xMy0yLjM4czMuMTYgMTMuMjYgMTMgMTMuMjZaIgoJLz4KCTxwYXRoCgkJZmlsbD0iIzNBM0I0NSIKCQlmaWxsLXJ1bGU9ImV2ZW5vZGQiCgkJZD0iTTM5LjQzIDU0YTguNyA4LjcgMCAwIDEgNS4zLTQuNDljLjQtLjEyLjgxLjU3IDEuMjQgMS4yOC40LjY4LjgyIDEuMzcgMS4yNCAxLjM3LjQ1IDAgLjktLjY4IDEuMzMtMS4zNS40NS0uNy44OS0xLjM4IDEuMzItMS4yNWE4LjYxIDguNjEgMCAwIDEgNSA0LjE3YzMuNzMtMi45NCA1LjEtNy43NCA1LjEtMTAuNyAwLTIuMzQtMS41Ny0xLjYtNC4wOS0uMzZsLS4xNC4wN2MtMi4zMSAxLjE1LTUuMzkgMi42Ny04Ljc3IDIuNjdzLTYuNDUtMS41Mi04Ljc3LTIuNjdjLTIuNi0xLjI5LTQuMjMtMi4xLTQuMjMuMjkgMCAzLjA1IDEuNDYgOC4wNiA1LjQ3IDEwLjk3WiIKCQljbGlwLXJ1bGU9ImV2ZW5vZGQiCgkvPgoJPHBhdGgKCQlmaWxsPSIjRkY5RDBCIgoJCWQ9Ik03MC43MSAzN2EzLjI1IDMuMjUgMCAxIDAgMC02LjUgMy4yNSAzLjI1IDAgMCAwIDAgNi41Wk0yNC4yMSAzN2EzLjI1IDMuMjUgMCAxIDAgMC02LjUgMy4yNSAzLjI1IDAgMCAwIDAgNi41Wk0xNy41MiA0OGMtMS42MiAwLTMuMDYuNjYtNC4wNyAxLjg3YTUuOTcgNS45NyAwIDAgMC0xLjMzIDMuNzYgNy4xIDcuMSAwIDAgMC0xLjk0LS4zYy0xLjU1IDAtMi45NS41OS0zLjk0IDEuNjZhNS44IDUuOCAwIDAgMC0uOCA3IDUuMyA1LjMgMCAwIDAtMS43OSAyLjgyYy0uMjQuOS0uNDggMi44LjggNC43NGE1LjIyIDUuMjIgMCAwIDAtLjM3IDUuMDJjMS4wMiAyLjMyIDMuNTcgNC4xNCA4LjUyIDYuMSAzLjA3IDEuMjIgNS44OSAyIDUuOTEgMi4wMWE0NC4zMyA0NC4zMyAwIDAgMCAxMC45MyAxLjZjNS44NiAwIDEwLjA1LTEuOCAxMi40Ni01LjM0IDMuODgtNS42OSAzLjMzLTEwLjktMS43LTE1LjkyLTIuNzctMi43OC00LjYyLTYuODctNS03Ljc3LS43OC0yLjY2LTIuODQtNS42Mi02LjI1LTUuNjJhNS43IDUuNyAwIDAgMC00LjYgMi40NmMtMS0xLjI2LTEuOTgtMi4yNS0yLjg2LTIuODJBNy40IDcuNCAwIDAgMCAxNy41MiA0OFptMCA0Yy41MSAwIDEuMTQuMjIgMS44Mi42NSAyLjE0IDEuMzYgNi4yNSA4LjQzIDcuNzYgMTEuMTguNS45MiAxLjM3IDEuMzEgMi4xNCAxLjMxIDEuNTUgMCAyLjc1LTEuNTMuMTUtMy40OC0zLjkyLTIuOTMtMi41NS03LjcyLS42OC04LjAxLjA4LS4wMi4xNy0uMDIuMjQtLjAyIDEuNyAwIDIuNDUgMi45MyAyLjQ1IDIuOTNzMi4yIDUuNTIgNS45OCA5LjNjMy43NyAzLjc3IDMuOTcgNi44IDEuMjIgMTAuODMtMS44OCAyLjc1LTUuNDcgMy41OC05LjE2IDMuNTgtMy44MSAwLTcuNzMtLjktOS45Mi0xLjQ2LS4xMS0uMDMtMTMuNDUtMy44LTExLjc2LTcgLjI4LS41NC43NS0uNzYgMS4zNC0uNzYgMi4zOCAwIDYuNyAzLjU0IDguNTcgMy41NC40MSAwIC43LS4xNy44My0uNi43OS0yLjg1LTEyLjA2LTQuMDUtMTAuOTgtOC4xNy4yLS43My43MS0xLjAyIDEuNDQtMS4wMiAzLjE0IDAgMTAuMiA1LjUzIDExLjY4IDUuNTMuMTEgMCAuMi0uMDMuMjQtLjEuNzQtMS4yLjMzLTIuMDQtNC45LTUuMi01LjIxLTMuMTYtOC44OC01LjA2LTYuOC03LjMzLjI0LS4yNi41OC0uMzggMS0uMzggMy4xNyAwIDEwLjY2IDYuODIgMTAuNjYgNi44MnMyLjAyIDIuMSAzLjI1IDIuMWMuMjggMCAuNTItLjEuNjgtLjM4Ljg2LTEuNDYtOC4wNi04LjIyLTguNTYtMTEuMDEtLjM0LTEuOS4yNC0yLjg1IDEuMzEtMi44NVoiCgkvPgoJPHBhdGgKCQlmaWxsPSIjRkZEMjFFIgoJCWQ9Ik0zOC42IDc2LjY5YzIuNzUtNC4wNCAyLjU1LTcuMDctMS4yMi0xMC44NC0zLjc4LTMuNzctNS45OC05LjMtNS45OC05LjNzLS44Mi0zLjItMi42OS0yLjljLTEuODcuMy0zLjI0IDUuMDguNjggOC4wMSAzLjkxIDIuOTMtLjc4IDQuOTItMi4yOSAyLjE3LTEuNS0yLjc1LTUuNjItOS44Mi03Ljc2LTExLjE4LTIuMTMtMS4zNS0zLjYzLS42LTMuMTMgMi4yLjUgMi43OSA5LjQzIDkuNTUgOC41NiAxMS0uODcgMS40Ny0zLjkzLTEuNzEtMy45My0xLjcxcy05LjU3LTguNzEtMTEuNjYtNi40NGMtMi4wOCAyLjI3IDEuNTkgNC4xNyA2LjggNy4zMyA1LjIzIDMuMTYgNS42NCA0IDQuOSA1LjItLjc1IDEuMi0xMi4yOC04LjUzLTEzLjM2LTQuNC0xLjA4IDQuMTEgMTEuNzcgNS4zIDEwLjk4IDguMTUtLjggMi44NS05LjA2LTUuMzgtMTAuNzQtMi4xOC0xLjcgMy4yMSAxMS42NSA2Ljk4IDExLjc2IDcuMDEgNC4zIDEuMTIgMTUuMjUgMy40OSAxOS4wOC0yLjEyWiIKCS8+Cgk8cGF0aAoJCWZpbGw9IiNGRjlEMEIiCgkJZD0iTTc3LjQgNDhjMS42MiAwIDMuMDcuNjYgNC4wNyAxLjg3YTUuOTcgNS45NyAwIDAgMSAxLjMzIDMuNzYgNy4xIDcuMSAwIDAgMSAxLjk1LS4zYzEuNTUgMCAyLjk1LjU5IDMuOTQgMS42NmE1LjggNS44IDAgMCAxIC44IDcgNS4zIDUuMyAwIDAgMSAxLjc4IDIuODJjLjI0LjkuNDggMi44LS44IDQuNzRhNS4yMiA1LjIyIDAgMCAxIC4zNyA1LjAyYy0xLjAyIDIuMzItMy41NyA0LjE0LTguNTEgNi4xLTMuMDggMS4yMi01LjkgMi01LjkyIDIuMDFhNDQuMzMgNDQuMzMgMCAwIDEtMTAuOTMgMS42Yy01Ljg2IDAtMTAuMDUtMS44LTEyLjQ2LTUuMzQtMy44OC01LjY5LTMuMzMtMTAuOSAxLjctMTUuOTIgMi43OC0yLjc4IDQuNjMtNi44NyA1LjAxLTcuNzcuNzgtMi42NiAyLjgzLTUuNjIgNi4yNC01LjYyYTUuNyA1LjcgMCAwIDEgNC42IDIuNDZjMS0xLjI2IDEuOTgtMi4yNSAyLjg3LTIuODJBNy40IDcuNCAwIDAgMSA3Ny40IDQ4Wm0wIDRjLS41MSAwLTEuMTMuMjItMS44Mi42NS0yLjEzIDEuMzYtNi4yNSA4LjQzLTcuNzYgMTEuMThhMi40MyAyLjQzIDAgMCAxLTIuMTQgMS4zMWMtMS41NCAwLTIuNzUtMS41My0uMTQtMy40OCAzLjkxLTIuOTMgMi41NC03LjcyLjY3LTguMDFhMS41NCAxLjU0IDAgMCAwLS4yNC0uMDJjLTEuNyAwLTIuNDUgMi45My0yLjQ1IDIuOTNzLTIuMiA1LjUyLTUuOTcgOS4zYy0zLjc4IDMuNzctMy45OCA2LjgtMS4yMiAxMC44MyAxLjg3IDIuNzUgNS40NyAzLjU4IDkuMTUgMy41OCAzLjgyIDAgNy43My0uOSA5LjkzLTEuNDYuMS0uMDMgMTMuNDUtMy44IDExLjc2LTctLjI5LS41NC0uNzUtLjc2LTEuMzQtLjc2LTIuMzggMC02LjcxIDMuNTQtOC41NyAzLjU0LS40MiAwLS43MS0uMTctLjgzLS42LS44LTIuODUgMTIuMDUtNC4wNSAxMC45Ny04LjE3LS4xOS0uNzMtLjctMS4wMi0xLjQ0LTEuMDItMy4xNCAwLTEwLjIgNS41My0xMS42OCA1LjUzLS4xIDAtLjE5LS4wMy0uMjMtLjEtLjc0LTEuMi0uMzQtMi4wNCA0Ljg4LTUuMiA1LjIzLTMuMTYgOC45LTUuMDYgNi44LTcuMzMtLjIzLS4yNi0uNTctLjM4LS45OC0uMzgtMy4xOCAwLTEwLjY3IDYuODItMTAuNjcgNi44MnMtMi4wMiAyLjEtMy4yNCAyLjFhLjc0Ljc0IDAgMCAxLS42OC0uMzhjLS44Ny0xLjQ2IDguMDUtOC4yMiA4LjU1LTExLjAxLjM0LTEuOS0uMjQtMi44NS0xLjMxLTIuODVaIgoJLz4KCTxwYXRoCgkJZmlsbD0iI0ZGRDIxRSIKCQlkPSJNNTYuMzMgNzYuNjljLTIuNzUtNC4wNC0yLjU2LTcuMDcgMS4yMi0xMC44NCAzLjc3LTMuNzcgNS45Ny05LjMgNS45Ny05LjNzLjgyLTMuMiAyLjctMi45YzEuODYuMyAzLjIzIDUuMDgtLjY4IDguMDEtMy45MiAyLjkzLjc4IDQuOTIgMi4yOCAyLjE3IDEuNTEtMi43NSA1LjYzLTkuODIgNy43Ni0xMS4xOCAyLjEzLTEuMzUgMy42NC0uNiAzLjEzIDIuMi0uNSAyLjc5LTkuNDIgOS41NS04LjU1IDExIC44NiAxLjQ3IDMuOTItMS43MSAzLjkyLTEuNzFzOS41OC04LjcxIDExLjY2LTYuNDRjMi4wOCAyLjI3LTEuNTggNC4xNy02LjggNy4zMy01LjIzIDMuMTYtNS42MyA0LTQuOSA1LjIuNzUgMS4yIDEyLjI4LTguNTMgMTMuMzYtNC40IDEuMDggNC4xMS0xMS43NiA1LjMtMTAuOTcgOC4xNS44IDIuODUgOS4wNS01LjM4IDEwLjc0LTIuMTggMS42OSAzLjIxLTExLjY1IDYuOTgtMTEuNzYgNy4wMS00LjMxIDEuMTItMTUuMjYgMy40OS0xOS4wOC0yLjEyWiIKCS8+Cjwvc3ZnPgo=";
2413
-
2414
- function hubGroupId(type) {
2415
- return "ws-hub-" + String(type).toLowerCase().replace(/[^a-z0-9]+/g, "-");
2416
- }
2417
-
2418
- const HUB_REF_GROUP_ORDER = [
2419
- "Jobs",
2420
- "Datasets",
2421
- "Models",
2422
- "Spaces",
2423
- "Buckets",
2424
- "Collections",
2425
- "Papers",
2426
- ];
2427
-
2428
- function hubRefFromRepoRef(ref) {
2429
- if (!ref || !ref.repo_id || !ref.repo_url) return null;
2430
- if (ref.repo_type === "dataset") {
2431
- return { url: ref.repo_url, type: "Datasets", label: ref.repo_id };
2432
- }
2433
- if (ref.repo_type === "bucket") {
2434
- return { url: ref.repo_url, type: "Buckets", label: ref.repo_id };
2435
- }
2436
- return null;
2437
- }
2438
-
2439
- async function publicAssociatedHubRefs() {
2440
- const refs = [MANIFEST.traces_ref, MANIFEST.workspace_ref].filter(Boolean);
2441
- const publicStates = await Promise.all(refs.map(probeRepoAccessible));
2442
- return refs
2443
- .filter((ref, index) => publicStates[index])
2444
- .map(hubRefFromRepoRef)
2445
- .filter(Boolean);
2446
- }
2447
-
2448
- function mergeHubRefs(...groups) {
2449
- const merged = [];
2450
- const seen = new Set();
2451
- groups.flat().forEach((ref) => {
2452
- if (!validHubRef(ref)) return;
2453
- const key = `${ref.type || "Other"}:${ref.label || ref.url}`;
2454
- if (seen.has(key)) return;
2455
- seen.add(key);
2456
- merged.push(ref);
2457
- });
2458
- return merged;
2459
- }
2460
-
2461
- function validHubRef(ref) {
2462
- if (!ref || !ref.url) return false;
2463
- if (classifyResource(ref.url)) return true;
2464
- const match = ref.url.match(/huggingface\.co\/collections\/([^/?#]+\/[^/?#]+)/);
2465
- return Boolean(match && validHfRepoId(match[1].split("/")));
2466
- }
2467
-
2468
- function renderHubRefs(refs) {
2469
- const validRefs = Array.isArray(refs) ? refs.filter(validHubRef) : [];
2470
- if (!validRefs.length) return null;
2471
- const section = document.createElement("section");
2472
- section.className = "workspace-hub";
2473
- const heading = document.createElement("h2");
2474
- heading.className = "workspace-hub-title";
2475
- const hubLogo = document.createElement("img");
2476
- hubLogo.className = "workspace-hub-logo";
2477
- hubLogo.src = HF_LOGO_DATA_URI;
2478
- hubLogo.alt = "";
2479
- hubLogo.setAttribute("aria-hidden", "true");
2480
- heading.appendChild(hubLogo);
2481
- heading.appendChild(document.createTextNode("Linked Hugging Face artifacts"));
2482
- section.appendChild(heading);
2483
- const byType = new Map();
2484
- validRefs.forEach((ref) => {
2485
- const type = ref.type || "Other";
2486
- if (!byType.has(type)) byType.set(type, []);
2487
- byType.get(type).push(ref);
2488
  });
2489
- const order = [
2490
- ...HUB_REF_GROUP_ORDER,
2491
- ...Array.from(byType.keys()).filter((t) => !HUB_REF_GROUP_ORDER.includes(t)),
2492
- ];
2493
- order.forEach((type) => {
2494
- const items = byType.get(type);
2495
- if (!items || !items.length) return;
2496
- const group = document.createElement("div");
2497
- group.className = "workspace-hub-group";
2498
- group.id = hubGroupId(type);
2499
- const gh = document.createElement("h3");
2500
- gh.className = "workspace-hub-group-head";
2501
- const label = document.createElement("span");
2502
- label.textContent = type;
2503
- const count = document.createElement("span");
2504
- count.className = "workspace-hub-count";
2505
- count.textContent = String(items.length);
2506
- gh.appendChild(label);
2507
- gh.appendChild(count);
2508
- group.appendChild(gh);
2509
- const list = document.createElement("div");
2510
- list.className = "workspace-hub-list";
2511
- items.forEach((ref) => {
2512
- const link = document.createElement("a");
2513
- link.className = "workspace-hub-link";
2514
- link.href = ref.url;
2515
- link.target = "_blank";
2516
- link.rel = "noopener noreferrer";
2517
- link.textContent = ref.label || ref.url;
2518
- link.title = ref.url;
2519
- list.appendChild(link);
2520
- });
2521
- group.appendChild(list);
2522
- section.appendChild(group);
2523
- });
2524
- return section;
2525
  }
2526
 
2527
- function workspaceSidebarEntries(files, hubRefs) {
2528
- const entries = [];
2529
- if (files && files.length) {
2530
- entries.push({ id: "ws-files", label: "Workspace files" });
2531
- }
2532
- const counts = new Map();
2533
- (Array.isArray(hubRefs) ? hubRefs : []).filter(validHubRef).forEach((ref) => {
2534
- const type = ref.type || "Other";
2535
- counts.set(type, (counts.get(type) || 0) + 1);
2536
- });
2537
- const order = [
2538
- ...HUB_REF_GROUP_ORDER,
2539
- ...Array.from(counts.keys()).filter((t) => !HUB_REF_GROUP_ORDER.includes(t)),
2540
- ];
2541
- order.forEach((type) => {
2542
- if (counts.get(type)) entries.push({ id: hubGroupId(type), label: type });
2543
- });
2544
- return entries;
2545
- }
2546
 
2547
- function buildWorkspaceSidebar(entries) {
2548
- const tree = document.getElementById("tree");
2549
- tree.innerHTML = "";
2550
- if (!entries || !entries.length) return;
2551
- const label = document.createElement("div");
2552
- label.className = "tree-label";
2553
- label.textContent = "Artifacts";
2554
- tree.appendChild(label);
2555
- entries.forEach((entry) => {
2556
- const a = document.createElement("a");
2557
- a.href = "#/view/workspace";
2558
- a.className = "depth-0";
2559
- a.dataset.section = entry.id;
2560
- a.textContent = entry.label;
2561
- a.addEventListener("click", (event) => {
2562
- event.preventDefault();
2563
- const target = document.getElementById(entry.id);
2564
- if (!target) return;
2565
- target.scrollIntoView({ behavior: "smooth", block: "start" });
2566
- tree
2567
- .querySelectorAll("a")
2568
- .forEach((link) => link.classList.toggle("active", link === a));
2569
- });
2570
- tree.appendChild(a);
2571
- });
2572
- }
2573
-
2574
- function workspaceTypeFromPath(path) {
2575
- const dot = path.lastIndexOf(".");
2576
- const ext = dot >= 0 ? path.slice(dot).toLowerCase() : "";
2577
- if (
2578
- [
2579
- ".pt",
2580
- ".pth",
2581
- ".ckpt",
2582
- ".safetensors",
2583
- ".gguf",
2584
- ".onnx",
2585
- ".pkl",
2586
- ".joblib",
2587
- ".h5",
2588
- ".tflite",
2589
- ".pb",
2590
- ].includes(ext)
2591
- ) {
2592
- return "model";
2593
- }
2594
- if (
2595
- [
2596
- ".npz",
2597
- ".npy",
2598
- ".parquet",
2599
- ".csv",
2600
- ".tsv",
2601
- ".arrow",
2602
- ".jsonl",
2603
- ".feather",
2604
- ".msgpack",
2605
- ].includes(ext)
2606
- ) {
2607
- return "dataset";
2608
- }
2609
- return ext.replace(/^\./, "") || "file";
2610
- }
2611
-
2612
- async function loadPublicWorkspace(ref) {
2613
- if (!(await probeRepoAccessible(ref))) return null;
2614
- const response = await fetch(
2615
- `https://huggingface.co/api/buckets/${ref.repo_id}/tree`,
2616
- { cache: "no-store" }
2617
  );
2618
- if (!response.ok) throw new Error("Could not load the public Bucket");
2619
- const entries = await response.json();
2620
- const prefix = "workspace/";
2621
- const files = (Array.isArray(entries) ? entries : [])
2622
- .filter(
2623
- (item) =>
2624
- item &&
2625
- item.type === "file" &&
2626
- typeof item.path === "string" &&
2627
- item.path.startsWith(prefix)
 
 
 
 
 
 
2628
  )
2629
- .map((item) => {
2630
- const path = item.path.slice(prefix.length);
2631
- return {
2632
- path,
2633
- name: path.split("/").pop() || path,
2634
- type: workspaceTypeFromPath(path),
2635
- size: Number(item.size) || 0,
2636
- modified_at: item.mtime || item.uploadedAt || "",
2637
- sessions: [],
2638
- bucket_url: `${ref.repo_url}#${encodeRepoPath(item.path)}`,
2639
- download_url: repoFileUrl(ref, item.path),
2640
- };
2641
- });
2642
- return {
2643
- schema_version: 1,
2644
- bucket_id: ref.repo_id,
2645
- file_count: files.length,
2646
- total_size: files.reduce((sum, file) => sum + file.size, 0),
2647
- files,
2648
- };
2649
- }
2650
-
2651
- async function renderWorkspace(renderId) {
2652
- const page = document.getElementById("page");
2653
- page.innerHTML = "";
2654
- page.className = "workspace-page";
2655
- const loading = document.createElement("div");
2656
- loading.className = "view-loading";
2657
- loading.textContent = "Loading workspace…";
2658
- page.appendChild(loading);
2659
- let workspace;
2660
- try {
2661
- workspace = await fetchData((MANIFEST.workspace || {}).file || "workspace.json");
2662
- } catch (error) {
2663
- if (renderId !== RENDER_SEQUENCE) return;
2664
- page.innerHTML = "";
2665
- page.appendChild(emptyView("Workspace unavailable", "The workspace inventory could not be loaded."));
2666
- return;
2667
- }
2668
- if (renderId !== RENDER_SEQUENCE) return;
2669
- if (
2670
- !(workspace.files || []).length &&
2671
- MANIFEST.workspace_ref &&
2672
- MANIFEST.workspace_ref.repo_url
2673
- ) {
2674
- try {
2675
- const remoteWorkspace = await loadPublicWorkspace(MANIFEST.workspace_ref);
2676
- if (remoteWorkspace && remoteWorkspace.files.length) {
2677
- workspace = {
2678
- ...workspace,
2679
- ...remoteWorkspace,
2680
- hub_refs: workspace.hub_refs || [],
2681
- };
2682
- }
2683
- } catch (error) {
2684
- // Keep the repository card below as a graceful fallback.
2685
  }
2686
- }
2687
- if (renderId !== RENDER_SEQUENCE) return;
2688
- page.innerHTML = "";
2689
- const associatedHubRefs = await publicAssociatedHubRefs();
2690
- if (renderId !== RENDER_SEQUENCE) return;
2691
- const hubRefs = mergeHubRefs(workspace.hub_refs || [], associatedHubRefs);
2692
- const shell = document.createElement("div");
2693
- shell.className = "workspace-shell";
2694
- const header = document.createElement("header");
2695
- header.className = "workspace-header";
2696
- const summary = document.createElement("p");
2697
- summary.textContent = `${workspace.file_count || 0} files · ${fmtBytes(workspace.total_size || 0)}`;
2698
- header.appendChild(summary);
2699
- const files = workspace.files || [];
2700
- if (files.length) {
2701
- const inventory = document.createElement("section");
2702
- inventory.className = "workspace-inventory";
2703
- inventory.id = "ws-files";
2704
- const renderInventory = (mode) => {
2705
- inventory.innerHTML = "";
2706
- if (mode === "type") renderWorkspaceByType(files, inventory);
2707
- else renderWorkspaceNode(workspaceTree(files), inventory);
2708
- };
2709
- const toggle = buildWorkspaceToggle(getWorkspaceMode(), (mode) => {
2710
- setWorkspaceMode(mode);
2711
- renderInventory(mode);
2712
- });
2713
- header.appendChild(toggle);
2714
- shell.appendChild(header);
2715
- shell.appendChild(inventory);
2716
- renderInventory(getWorkspaceMode());
2717
- } else if (MANIFEST.workspace_ref && MANIFEST.workspace_ref.repo_url) {
2718
- shell.appendChild(header);
2719
- await renderRepoReference(
2720
- MANIFEST.workspace_ref,
2721
- "workspace",
2722
- shell,
2723
- renderId
2724
- );
2725
- if (renderId !== RENDER_SEQUENCE) return;
2726
- } else {
2727
- shell.appendChild(header);
2728
- shell.appendChild(
2729
- emptyView(
2730
- "No workspace files captured yet",
2731
- "Supported model and data files appear here as they are created or changed after a trace is attached. Outputs captured by trackio logbook run appear when the run finishes; logged Trackio artifacts appear immediately in the Logbook tab. Files stay local until you choose to publish."
2732
- )
2733
- );
2734
- }
2735
- const hub = renderHubRefs(hubRefs);
2736
- if (hub) shell.appendChild(hub);
2737
- page.appendChild(shell);
2738
- buildWorkspaceSidebar(workspaceSidebarEntries(files, hubRefs));
2739
- window.scrollTo({ top: 0, behavior: "auto" });
2740
- }
2741
-
2742
- async function renderCurrentView(opts = {}) {
2743
- const route = routeState();
2744
- const renderId = ++RENDER_SEQUENCE;
2745
- setActiveView(route);
2746
- if (route.view === "trace") {
2747
- await renderTrace(route, renderId);
2748
- } else if (route.view === "workspace") {
2749
- await renderWorkspace(renderId);
2750
- } else {
2751
- document.getElementById("page").className = "code-page";
2752
- await renderLogbook({ ...opts, renderId });
2753
- }
2754
  }
2755
 
2756
- function handleRouteChange() {
2757
- const route = routeState();
2758
- if (
2759
- route.view === "code" &&
2760
- CURRENT_VIEW === "code" &&
2761
- document.querySelector("#page .page-section")
2762
- ) {
2763
- updateViewTabs(route);
2764
- scrollToHash();
2765
- return;
2766
- }
2767
- if (
2768
- route.view === "trace" &&
2769
- CURRENT_VIEW === "trace" &&
2770
- document.querySelector("#page .trace-session")
2771
- ) {
2772
- setActiveView(route);
2773
- const sessions = MANIFEST.traces || [];
2774
- const activeSessionId = route.sessionId || (sessions[0] || {}).id;
2775
- ensureTraceSessionLoaded(activeSessionId);
2776
- scrollToTraceSession(route.sessionId);
2777
- return;
2778
- }
2779
- renderCurrentView();
 
 
 
 
 
 
 
 
 
 
2780
  }
2781
 
2782
  function currentSlug() {
2783
- const route = routeState();
2784
- return route.view === "code" ? route.slug : MANIFEST.root.slug;
2785
  }
2786
 
2787
  function scrollToHash(opts = {}) {
2788
- if (routeState().view !== "code") return;
2789
  const slug = currentSlug();
2790
- if (!location.hash || slug === MANIFEST.root.slug) {
2791
  window.scrollTo({ top: 0, behavior: opts.behavior || "auto" });
2792
  highlight(slug);
2793
  return;
@@ -2800,7 +2106,7 @@
2800
  function navigateToLogbookSlug(target) {
2801
  const slug = String(target || "").replace(/^#?\//, "").trim();
2802
  if (!slug || !findNode(MANIFEST.root, slug)) return;
2803
- const hash = "#/view/code/" + slug;
2804
  if (location.hash === hash) {
2805
  scrollToHash({ behavior: "smooth" });
2806
  } else {
@@ -2824,12 +2130,9 @@
2824
 
2825
  let SCROLL_FRAME = 0;
2826
  function updateActiveSection() {
2827
- if (CURRENT_VIEW !== "code" && CURRENT_VIEW !== "trace") return;
2828
  cancelAnimationFrame(SCROLL_FRAME);
2829
  SCROLL_FRAME = requestAnimationFrame(() => {
2830
- const selector =
2831
- CURRENT_VIEW === "trace" ? ".trace-session" : ".page-section";
2832
- const sections = Array.from(document.querySelectorAll(selector));
2833
  if (!sections.length) return;
2834
  const marker = Math.min(window.innerHeight * 0.28, 180);
2835
  let active = sections[0];
@@ -2842,11 +2145,7 @@
2842
  ) {
2843
  active = sections[sections.length - 1];
2844
  }
2845
- if (CURRENT_VIEW === "trace") {
2846
- highlightTraceSession(active.dataset.sessionId);
2847
- } else {
2848
- highlight(active.dataset.slug);
2849
- }
2850
  });
2851
  }
2852
 
@@ -2862,7 +2161,7 @@
2862
  document.getElementById("book-title").textContent = MANIFEST.title;
2863
  document.getElementById("book-head").setAttribute("aria-label", MANIFEST.title);
2864
  buildTree();
2865
- renderCurrentView({ preserveScroll: true });
2866
  } catch (e) {}
2867
  }, LIVE_RELOAD_MS);
2868
  }
@@ -2958,16 +2257,17 @@
2958
  document.getElementById("book-title").textContent = MANIFEST.title;
2959
  document.getElementById("book-head").setAttribute("aria-label", MANIFEST.title);
2960
  document.getElementById("book-head").addEventListener("click", () => {
2961
- const target = "#/view/code/" + MANIFEST.root.slug;
2962
  if (location.hash === target) scrollToHash();
2963
  else location.hash = target;
2964
  });
2965
  buildTree();
2966
  setupConnect();
 
2967
  setupFigureNavigation();
2968
- window.addEventListener("hashchange", handleRouteChange);
2969
  window.addEventListener("scroll", updateActiveSection, { passive: true });
2970
- await renderCurrentView();
2971
  startLiveReload();
2972
  }
2973
 
 
4
  let MANIFEST = null;
5
  const PAGE_CACHE = {};
6
  const UNFURL_CACHE = {};
 
7
  const LIVE_RELOAD_MS = 1500;
8
  const FIGURE_FRAME_WINDOWS = new Set();
9
  let FIGURE_NAVIGATION_READY = false;
 
 
10
 
11
  function esc(s) {
12
  return String(s)
 
286
  /(trackio-artifact:\/\/\S+|trackio-local-path:\/\/\S+|https:\/\/huggingface\.co\/buckets\/[^\s<)]+#\S+)/
287
  );
288
  if (chip && uri) chip.dataset.resUrl = uri[1];
 
 
 
 
289
  } else if (meta.type === "dashboard") {
290
  const sp = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
291
  cell.dataset.resUrl = sp
 
495
  if (!message || message.type !== "trackio-logbook:navigate") return;
496
  const target = String(message.target || "").replace(/^#?\//, "");
497
  if (!target || !MANIFEST || !findNode(MANIFEST.root, target)) return;
498
+ const hash = "#/" + target;
499
  if (location.hash === hash) scrollToHash();
500
  else location.hash = hash;
501
  });
 
507
  '<path d="M8 3H3v5M16 3h5v5M21 16v5h-5M3 16v5h5"/>' +
508
  '<path d="M3 8 8 3M16 3l5 5M21 16l-5 5M8 21l-5-5"/></svg>';
509
 
 
 
 
 
 
 
 
 
 
510
  // Figures are rendered in same-origin iframes, so fullscreen the fitted
511
  // wrapper rather than the iframe document. This uses the browser's native
512
  // fullscreen UI and preserves the figure's existing responsive sizing.
 
635
  ? `<span class="out-artifact-state open">Open ↗</span>`
636
  : `<span class="out-artifact-state">publish to share</span>`;
637
  const meta = parts.length ? `${parts.join(" · ")} · ${state}` : state;
 
638
  el.innerHTML =
639
+ `<span class="out-artifact-ico">${ARTIFACT_ICON_IMG}</span>` +
640
  `<span class="out-artifact-name">${esc(info.name)}</span>` +
641
  `<span class="out-artifact-meta">${meta}</span>`;
642
  return el;
643
  }
644
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
645
  function renderCodeCell(body, container, artifacts) {
646
  const parts = parseFences(body);
647
  const block = document.createElement("div");
 
694
  embedTexts.push(part.text);
695
  return;
696
  }
697
+ inputBody.appendChild(renderCode(part.text, part.lang, part.title));
 
 
 
 
 
 
698
  });
699
  if (artifacts && artifacts.length) {
700
  ensureOut();
 
913
  return btn;
914
  }
915
 
916
+ function renderCode(code, lang, title) {
917
  const pre = document.createElement("pre");
918
  pre.className = "hl";
919
  const c = document.createElement("code");
920
  c.innerHTML = highlightCode(code, lang);
921
  pre.appendChild(c);
922
+ if (!title) {
923
  const wrap = document.createElement("div");
924
  wrap.className = "snippet";
925
  wrap.appendChild(pre);
 
983
  });
984
  }
985
 
986
+ /* -------------------- resources rail -------------------- */
987
 
988
  function fmt(n) {
989
  if (n == null) return null;
 
1011
  const ARTIFACT_ICON_IMG = `<img class="art-ico" src="./bucket-icon.svg" alt="" />`;
1012
  const DASHBOARD_ICON_IMG = `<img class="art-ico" src="./trackio-logo-light.png" alt="" />`;
1013
 
1014
+ const RESOURCE_DESC = {
1015
+ dashboard: "Dashboard",
1016
+ model: "Model",
1017
+ dataset: "Dataset",
1018
+ space: "Space",
1019
+ artifact: "Artifact — in Bucket",
1020
+ paper: "Paper",
1021
+ repo: "Repository",
1022
+ job: "Job — status & logs",
1023
+ bucket: "Bucket — artifacts & data",
1024
+ };
1025
+
1026
  const HF_NON_MODEL_PREFIX =
1027
  /^(datasets|spaces|jobs|buckets|papers|blog|docs|api|posts|collections|organizations|settings|new|join|login|pricing|tasks|learn|chat|models)(\/|$)/;
1028
 
 
1030
  return url.split(marker)[1].split(/[?#]/)[0].replace(/\/$/, "");
1031
  }
1032
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1033
  function classifyResource(url) {
1034
  if (IMG_URL.test(url)) {
1035
  return null;
 
1059
  local: true,
1060
  };
1061
  }
1062
+ if ((m = url.match(/huggingface\.co\/buckets\/[^#\s]+#(.+)/))) {
1063
+ return { kind: "artifact", id: decodeURIComponent(m[1]), url };
 
1064
  }
1065
+ if (/huggingface\.co\/datasets\/[^/]+\/[^/]+/.test(url)) {
1066
+ return { kind: "dataset", id: hfId(url, "/datasets/"), url };
 
 
1067
  }
1068
+ if (/huggingface\.co\/spaces\/[^/]+\/[^/]+/.test(url)) {
1069
+ return { kind: "space", id: hfId(url, "/spaces/"), url };
 
 
1070
  }
1071
  if (/huggingface\.co\/jobs\//.test(url)) {
1072
+ const parts = hfId(url, "/jobs/").split("/");
1073
+ const jid = parts[1] || "";
 
1074
  return {
1075
  kind: "job",
1076
+ id: parts[0] + (jid ? ` · ${jid.slice(0, 12)}${jid.length > 12 ? "…" : ""}` : ""),
1077
  url,
1078
  };
1079
  }
1080
  if (/huggingface\.co\/buckets\//.test(url)) {
1081
+ return { kind: "bucket", id: hfId(url, "/buckets/"), url };
 
 
1082
  }
1083
  if (/huggingface\.co\/papers\//.test(url)) {
1084
+ return { kind: "paper", id: `Paper ${hfId(url, "/papers/")}`, url };
 
 
1085
  }
1086
  if ((m = url.match(/arxiv\.org\/(?:abs|pdf)\/([^?#\s]+)/))) {
1087
  return { kind: "paper", id: `arXiv:${m[1].replace(/\.pdf$/, "")}`, url };
 
1091
  }
1092
  if ((m = url.match(/huggingface\.co\/([^?#]+)/))) {
1093
  const rest = m[1].replace(/\/$/, "");
1094
+ if (/^[^/]+\/[^/]+$/.test(rest) && !HF_NON_MODEL_PREFIX.test(rest)) {
1095
  return { kind: "model", id: rest, url };
1096
  }
1097
  }
1098
  return null;
1099
  }
1100
 
1101
+ async function fillRailMeta(item, el) {
1102
+ if (item.local) return;
1103
+ const meta = el.querySelector(".rail-meta");
1104
+ const set = (parts) => {
1105
+ const text = parts.filter(Boolean).join(" · ");
1106
+ if (text) meta.textContent = text;
1107
+ };
1108
+ if (item.kind === "model") {
1109
+ const d = await getJSON(`https://huggingface.co/api/models/${item.id}`);
1110
+ if (d) set([d.pipeline_tag, `↓ ${fmt(d.downloads)}`, `♥ ${fmt(d.likes)}`]);
1111
+ } else if (item.kind === "dataset") {
1112
+ const d = await getJSON(`https://huggingface.co/api/datasets/${item.id}`);
1113
+ if (d) set([`↓ ${fmt(d.downloads)}`, `♥ ${fmt(d.likes)}`]);
1114
+ } else if (item.kind === "space" || item.kind === "dashboard") {
1115
+ const d = await getJSON(`https://huggingface.co/api/spaces/${item.id}`);
1116
+ if (d) set([d.sdk, `♥ ${fmt(d.likes)}`]);
1117
+ } else if (item.kind === "repo") {
1118
+ const d = await getJSON(`https://api.github.com/repos/${item.id}`);
1119
+ if (d) set([`★ ${fmt(d.stargazers_count)}`, d.language]);
1120
+ } else if (item.kind === "paper") {
1121
+ const m = item.id.match(/^(?:arXiv:|Paper )(.+)$/);
1122
+ if (!m) return;
1123
+ const arxivId = m[1].replace(/v\d+$/, "");
1124
+ const d = await getJSON(`https://huggingface.co/api/papers/${arxivId}`);
1125
+ if (d && d.id) {
1126
+ if (el.href) el.href = `https://huggingface.co/papers/${d.id}`;
1127
+ const title =
1128
+ d.title && d.title.length > 70 ? `${d.title.slice(0, 69)}…` : d.title;
1129
+ set([title, d.upvotes ? `��� ${fmt(d.upvotes)}` : null]);
1130
+ }
1131
+ }
1132
+ }
1133
+
1134
+ const BARE_ID_SKIP_DIRS = new Set([
1135
+ "scripts",
1136
+ "configs",
1137
+ "config",
1138
+ "results",
1139
+ "figures",
1140
+ "data",
1141
+ "datasets",
1142
+ "src",
1143
+ "tests",
1144
+ "test",
1145
+ "examples",
1146
+ "pages",
1147
+ "assets",
1148
+ "docs",
1149
+ "outputs",
1150
+ "output",
1151
+ "checkpoints",
1152
+ "models",
1153
+ "utils",
1154
+ "lib",
1155
+ "bin",
1156
+ "tmp",
1157
+ "node_modules",
1158
+ "dist",
1159
+ "build",
1160
+ ]);
1161
+ const FILE_EXT_RE =
1162
+ /\.(py|pyc|js|ts|jsx|tsx|json|jsonl|yaml|yml|csv|tsv|md|txt|sh|bash|html|css|png|jpe?g|svg|gif|webp|ipynb|toml|cfg|ini|lock|pdf|whl|gz|zip|tar|pt|pth|bin|safetensors|db|sqlite)$/i;
1163
+
1164
+ async function detectBareModelIds(text, groups) {
1165
+ const stripped = text.replace(DETECTED_URL, " ");
1166
+ DETECTED_URL.lastIndex = 0;
1167
+ const seen = new Set();
1168
+ const candidates = [];
1169
+ const re = /(^|[\s"'`(=[])([A-Za-z0-9][\w.-]*\/[A-Za-z0-9][\w.-]*)/g;
1170
+ let m;
1171
+ while ((m = re.exec(stripped)) && candidates.length < 15) {
1172
+ const id = m[2].replace(/[.:,]+$/, "");
1173
+ if (seen.has(id)) continue;
1174
+ seen.add(id);
1175
+ if (FILE_EXT_RE.test(id)) continue;
1176
+ if (BARE_ID_SKIP_DIRS.has(id.split("/")[0].toLowerCase())) continue;
1177
+ candidates.push(id);
1178
+ }
1179
+ const results = await Promise.all(
1180
+ candidates.map((id) => getJSON(`https://huggingface.co/api/models/${id}`))
1181
+ );
1182
+ let added = false;
1183
+ const confirmed = [];
1184
+ results.forEach((d, i) => {
1185
+ if (!d || !d.id) return;
1186
+ const id = candidates[i];
1187
+ confirmed.push(id);
1188
+ const url = `https://huggingface.co/${id}`;
1189
+ if (!groups.has("model")) groups.set("model", new Map());
1190
+ if (!groups.get("model").has(url)) {
1191
+ groups.get("model").set(url, { kind: "model", id, url });
1192
+ added = true;
1193
+ }
1194
+ });
1195
+ return { added, confirmed };
1196
+ }
1197
+
1198
+ function chipifyBareIds(ids, container) {
1199
+ if (!ids.length) return;
1200
+ const escaped = ids.map((id) => id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
1201
+ const pattern = new RegExp("(" + escaped.join("|") + ")");
1202
+ const splitter = new RegExp(pattern.source, "g");
1203
+ container
1204
+ .querySelectorAll(".cell.markdown .cell-body")
1205
+ .forEach((body) => {
1206
+ const walker = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, {
1207
+ acceptNode(node) {
1208
+ if (!pattern.test(node.nodeValue)) return NodeFilter.FILTER_REJECT;
1209
+ for (
1210
+ let el = node.parentElement;
1211
+ el && el !== body;
1212
+ el = el.parentElement
1213
+ ) {
1214
+ if (["A", "CODE", "PRE", "BUTTON"].indexOf(el.tagName) !== -1) {
1215
+ return NodeFilter.FILTER_REJECT;
1216
+ }
1217
+ }
1218
+ return NodeFilter.FILTER_ACCEPT;
1219
+ },
1220
+ });
1221
+ const nodes = [];
1222
+ while (walker.nextNode()) nodes.push(walker.currentNode);
1223
+ nodes.forEach((node) => {
1224
+ const frag = document.createDocumentFragment();
1225
+ node.nodeValue.split(splitter).forEach((part) => {
1226
+ if (ids.indexOf(part) !== -1) {
1227
+ const holder = document.createElement("span");
1228
+ holder.innerHTML = resChipHtml({
1229
+ kind: "model",
1230
+ id: part,
1231
+ url: `https://huggingface.co/${part}`,
1232
+ });
1233
+ frag.appendChild(holder.firstChild);
1234
+ } else if (part) {
1235
+ frag.appendChild(document.createTextNode(part));
1236
+ }
1237
+ });
1238
+ node.parentNode.replaceChild(frag, node);
1239
+ });
1240
+ });
1241
+ }
1242
+
1243
+ let RAIL_TOKEN = 0;
1244
+ const RAIL_EXCLUDE_KINDS = new Set(["paper", "repo", "artifact", "dashboard"]);
1245
+
1246
+ function railDashboardItem(it) {
1247
+ return {
1248
+ kind: "dashboard",
1249
+ id: it.id,
1250
+ url: it.local ? it.resUrl : it.url || it.resUrl,
1251
+ local: it.local,
1252
+ railLabel: "Dashboard",
1253
+ };
1254
+ }
1255
+
1256
+ function promoteTrackioSpacesInRail(groups, dashResUrls, body, rail, token) {
1257
+ const spaceGroup = groups.get("space");
1258
+ if (!spaceGroup || !spaceGroup.size) return;
1259
+ spaceGroup.forEach((item, url) => {
1260
+ getJSON(`https://huggingface.co/api/spaces/${item.id}`)
1261
+ .then((d) => {
1262
+ if (rail.dataset.renderToken !== token) return;
1263
+ const tags = (d && d.tags) || [];
1264
+ if (!tags.some((t) => String(t).toLowerCase() === "trackio")) return;
1265
+ if (dashResUrls.has(url)) return;
1266
+ spaceGroup.delete(url);
1267
+ if (!spaceGroup.size) groups.delete("space");
1268
+ if (!groups.has("dashboard")) groups.set("dashboard", new Map());
1269
+ groups.get("dashboard").set(url, {
1270
+ kind: "dashboard",
1271
+ id: item.id,
1272
+ url: item.url,
1273
+ local: false,
1274
+ railLabel: "Dashboard",
1275
+ });
1276
+ dashResUrls.add(url);
1277
+ paintRail(groups, body, rail);
1278
+ })
1279
+ .catch(() => {});
1280
+ });
1281
+ }
1282
+
1283
+ function renderRail(md, body, rail) {
1284
+ const token = String(++RAIL_TOKEN);
1285
+ rail.dataset.renderToken = token;
1286
+ const scanText = md.replace(
1287
+ /(`{3,4}|~{3,4})(html|raw)[^\n]*\n[\s\S]*?\n\1/g,
1288
+ " "
1289
+ );
1290
+ const groups = new Map();
1291
+ const dashMap = new Map();
1292
+ const dashResUrls = new Set();
1293
+ cellDashboardItems(md).forEach((it) => {
1294
+ if (dashMap.has(it.resUrl)) return;
1295
+ dashMap.set(it.resUrl, railDashboardItem(it));
1296
+ dashResUrls.add(it.resUrl);
1297
+ });
1298
+ if (dashMap.size) groups.set("dashboard", dashMap);
1299
+ extractUrls(scanText).forEach((url) => {
1300
+ const item = classifyResource(url);
1301
+ if (!item) return;
1302
+ if (RAIL_EXCLUDE_KINDS.has(item.kind)) return;
1303
+ if (dashResUrls.has(url)) return;
1304
+ if (!groups.has(item.kind)) groups.set(item.kind, new Map());
1305
+ groups.get(item.kind).set(item.url, item);
1306
+ });
1307
+ const artMap = new Map();
1308
+ cellArtifactItems(md).forEach((it) => {
1309
+ if (artMap.has(it.resUrl)) return;
1310
+ const label = it.type
1311
+ ? it.type.charAt(0).toUpperCase() + it.type.slice(1)
1312
+ : "Artifact";
1313
+ artMap.set(it.resUrl, {
1314
+ kind: "artifact",
1315
+ id: it.name,
1316
+ url: it.local ? it.resUrl : it.url || it.resUrl,
1317
+ local: it.local,
1318
+ railLabel: label,
1319
+ size: it.size,
1320
+ });
1321
+ });
1322
+ if (artMap.size) groups.set("artifact", artMap);
1323
+ paintRail(groups, body, rail);
1324
+ promoteTrackioSpacesInRail(groups, dashResUrls, body, rail, token);
1325
+ detectBareModelIds(scanText, groups)
1326
+ .then((result) => {
1327
+ if (rail.dataset.renderToken !== token) return;
1328
+ chipifyBareIds(result.confirmed, body);
1329
+ if (result.added) paintRail(groups, body, rail);
1330
+ })
1331
+ .catch(() => {});
1332
+ }
1333
+
1334
+ function paintRail(groups, body, rail) {
1335
+ rail.innerHTML = "";
1336
+ RESOURCE_SECTIONS.forEach(([kind, label, icon]) => {
1337
+ const group = groups.get(kind);
1338
+ if (!group || !group.size) return;
1339
+ group.forEach((item) => {
1340
+ const el = document.createElement(item.local ? "div" : "a");
1341
+ el.className = item.local ? "rail-item rail-local" : "rail-item";
1342
+ if (!item.local) {
1343
+ el.href = item.url;
1344
+ el.target = "_blank";
1345
+ el.rel = "noopener";
1346
+ }
1347
+ el.dataset.resUrl = item.url;
1348
+ let desc;
1349
+ if (kind === "artifact") {
1350
+ const state = item.local ? "publish to share" : "Open ↗";
1351
+ desc = item.size ? `${item.size} · ${state}` : state;
1352
+ } else if (kind === "dashboard") {
1353
+ desc = item.local ? "publish to share" : "Open ↗";
1354
+ } else {
1355
+ desc = item.local ? "publish to share" : RESOURCE_DESC[kind];
1356
+ }
1357
+ const kindLabel = item.railLabel || label.replace(/s$/, "");
1358
+ const iconHtml =
1359
+ kind === "artifact"
1360
+ ? ARTIFACT_ICON_IMG
1361
+ : kind === "dashboard"
1362
+ ? DASHBOARD_ICON_IMG
1363
+ : `<span>${icon}</span>`;
1364
+ el.innerHTML =
1365
+ `<div class="rail-kind">${iconHtml}${esc(kindLabel)}</div>` +
1366
+ `<div class="rail-title">${esc(item.id)}</div>` +
1367
+ `<div class="rail-meta">${esc(desc)}</div>`;
1368
+ rail.appendChild(el);
1369
+ fillRailMeta(item, el)
1370
+ .catch(() => {})
1371
+ .finally(() => scheduleRailPosition(body, rail));
1372
+ });
1373
+ });
1374
+ rail.hidden = !rail.childElementCount;
1375
+ scheduleRailPosition(body, rail);
1376
+ }
1377
+
1378
+ function resourceAnchor(body, url) {
1379
+ return body.querySelector(`[data-res-url="${CSS.escape(url)}"]`);
1380
+ }
1381
+
1382
+ function positionRail(body, rail) {
1383
+ if (rail.hidden || !rail.isConnected) return;
1384
+ const bodyRect = body.getBoundingClientRect();
1385
+ const items = Array.from(rail.querySelectorAll(".rail-item")).map((el, index) => {
1386
+ const anchor = resourceAnchor(body, el.dataset.resUrl);
1387
+ return {
1388
+ el,
1389
+ index,
1390
+ desired: anchor
1391
+ ? Math.max(0, anchor.getBoundingClientRect().top - bodyRect.top)
1392
+ : 0,
1393
+ };
1394
+ });
1395
+ items.sort((a, b) => a.desired - b.desired || a.index - b.index);
1396
+ let cursor = 0;
1397
+ items.forEach(({ el, desired }) => {
1398
+ const top = Math.max(desired, cursor);
1399
+ el.style.top = `${top}px`;
1400
+ cursor = top + el.offsetHeight + 10;
1401
+ });
1402
+ rail.style.minHeight = `${Math.max(body.offsetHeight, cursor)}px`;
1403
+ }
1404
+
1405
+ function scheduleRailPosition(body, rail) {
1406
+ cancelAnimationFrame(Number(rail.dataset.positionFrame || 0));
1407
+ rail.dataset.positionFrame = String(
1408
+ requestAnimationFrame(() => positionRail(body, rail))
1409
+ );
1410
+ }
1411
+
1412
  function dashboardSubdomainFromUrl(url) {
1413
  return spaceIdFromUrl(url).toLowerCase().replace(/[^a-z0-9-]/g, "-");
1414
  }
 
1523
  function buildTree() {
1524
  const tree = document.getElementById("tree");
1525
  tree.innerHTML = "";
 
 
 
 
1526
  const nodes = [];
1527
  (MANIFEST.root.children || []).forEach((c) => flattenTree(c, 0, nodes));
1528
  nodes.forEach(({ node, depth }) => {
1529
  const a = document.createElement("a");
1530
+ a.href = "#/" + node.slug;
1531
  a.className = "depth-" + depth;
1532
  a.dataset.slug = node.slug;
1533
  const mark = document.createElement("span");
 
1539
  });
1540
  }
1541
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1542
  function highlight(slug) {
1543
  document
1544
  .querySelectorAll("#tree a")
 
1552
  Object.keys(PAGE_CACHE).forEach((key) => {
1553
  delete PAGE_CACHE[key];
1554
  });
 
 
 
1555
  }
1556
 
1557
  function isLocalPreview() {
 
1577
  return PAGE_CACHE[node.file];
1578
  }
1579
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1580
  function allNodes() {
1581
  const nodes = [];
1582
  flattenTree(MANIFEST.root, 0, nodes);
 
1621
  cells.forEach(({ meta, body }) => {
1622
  const cell = renderCell(meta, body, list);
1623
  cell.classList.add("pinned-copy");
 
 
1624
  });
1625
  deck.appendChild(list);
1626
  const anchor =
1627
+ container.querySelector(".logbook-stats") ||
1628
+ container.querySelector(".agent-hint");
1629
  container.insertBefore(deck, anchor ? anchor.nextSibling : container.firstChild);
1630
+ container.closest(".book-intro").classList.add("has-pinned-notes");
 
 
 
 
 
 
 
 
 
 
 
 
 
1631
  }
1632
 
1633
  function removeIndexProse(body) {
 
1636
  let current = h1.nextElementSibling;
1637
  while (current && current.tagName !== "H2") {
1638
  const next = current.nextElementSibling;
1639
+ current.remove();
 
 
 
 
1640
  current = next;
1641
  }
1642
  }
 
1655
  }
1656
  }
1657
 
1658
+ const RAIL_OBSERVERS = [];
1659
+
1660
  async function renderLogbook(opts = {}) {
1661
  const scrollY = window.scrollY;
1662
  const page = document.getElementById("page");
1663
+ RAIL_OBSERVERS.splice(0).forEach((observer) => observer.disconnect());
1664
  page.innerHTML = "";
1665
  const nodes = allNodes();
1666
  const markdown = await Promise.all(nodes.map(fetchPage));
 
1667
  const pinnedCells = collectPinnedCells(markdown, nodes);
1668
  let bookIntroBody = null;
1669
  nodes.forEach((node, index) => {
 
1676
  layout.className = "page-layout";
1677
  const body = document.createElement("div");
1678
  body.className = "page-body";
1679
+ const rail = document.createElement("aside");
1680
+ rail.className = "context-rail";
1681
+ rail.setAttribute("aria-label", `Resources for ${node.title}`);
1682
 
1683
  renderMarkdown(markdown[index], body);
1684
  if (node.slug === MANIFEST.root.slug) {
1685
  section.classList.add("book-intro");
1686
  removeIndexProse(body);
1687
  removePageDirectory(body);
1688
+ const hint = buildAgentHint();
1689
  const h1 = body.querySelector("h1");
1690
+ if (h1 && h1.parentNode === body) {
1691
+ body.insertBefore(hint, h1.nextSibling);
1692
+ } else {
1693
+ body.prepend(hint);
1694
+ }
1695
+ hint.after(buildLogbookStats(markdown));
1696
  bookIntroBody = body;
1697
  }
1698
  layout.appendChild(body);
1699
+ layout.appendChild(rail);
1700
  section.appendChild(layout);
1701
  page.appendChild(section);
1702
+ renderRail(markdown[index], body, rail);
1703
+ if (window.ResizeObserver) {
1704
+ const observer = new ResizeObserver(() => scheduleRailPosition(body, rail));
1705
+ observer.observe(body);
1706
+ observer.observe(rail);
1707
+ RAIL_OBSERVERS.push(observer);
1708
+ }
1709
  });
1710
+ if (bookIntroBody) renderPinnedNotes(pinnedCells, bookIntroBody);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1711
  if (bookIntroBody) {
1712
  const section = bookIntroBody.closest(".book-intro");
1713
  const hasExtra = Array.from(bookIntroBody.children).some(
1714
  (el) =>
1715
  el.tagName !== "H1" &&
1716
  !el.classList.contains("agent-hint") &&
1717
+ !el.classList.contains("logbook-stats") &&
1718
  !el.classList.contains("pinned-notes")
1719
  );
1720
  if (section && !section.classList.contains("has-pinned-notes") && !hasExtra) {
 
1731
  });
1732
  }
1733
 
1734
+ function setupResourceHover() {
1735
+ document.addEventListener("mouseover", (e) => {
1736
+ const el = e.target.closest && e.target.closest("[data-res-url]");
1737
+ if (!el || el.classList.contains("rail-item")) return;
1738
+ const url = el.getAttribute("data-res-url");
1739
+ const section = el.closest(".page-section");
1740
+ const scope = section || document;
1741
+ scope.querySelectorAll(".context-rail [data-res-url]").forEach((n) => {
1742
+ n.classList.toggle("res-hl", n.getAttribute("data-res-url") === url);
1743
+ });
1744
+ });
1745
+ document.addEventListener("mouseout", (e) => {
1746
+ const el = e.target.closest && e.target.closest("[data-res-url]");
1747
+ if (!el || el.classList.contains("rail-item")) return;
1748
+ document.querySelectorAll(".context-rail .res-hl").forEach((n) => {
1749
+ n.classList.remove("res-hl");
1750
+ });
1751
+ });
1752
+ }
1753
+
1754
+ let STATS_TOKEN = 0;
1755
+ let STATS_LISTENERS = false;
1756
+
1757
  function fmtBytes(n) {
1758
  if (n == null || isNaN(n)) return null;
1759
  if (n < 1000) return `${n} B`;
 
1771
  return url.split("/spaces/")[1].split(/[?#]/)[0].replace(/\/$/, "");
1772
  }
1773
 
1774
+ const LB_CELL_RE = /(^|\n)---\n<!-- trackio-cell\n([\s\S]*?)\n-->\n([\s\S]*?)(?=\n---\n<!-- trackio-cell\n|\s*$)/g;
1775
+
1776
+ function cellDashboardItems(md) {
1777
+ const re = new RegExp(LB_CELL_RE.source, "g");
1778
+ const items = [];
1779
+ let m;
1780
+ while ((m = re.exec(md))) {
1781
+ const meta = parseCellMeta(m[2]);
1782
+ if (meta.type !== "dashboard") continue;
1783
+ const body = m[3];
1784
+ const project = meta.dashboard_project || "";
1785
+ const sp = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
1786
+ const local = !sp;
1787
+ const url = sp ? sp[0] : "";
1788
+ const resUrl = local ? `trackio-local-dashboard://${project}` : url;
1789
+ items.push({
1790
+ id: local ? project : spaceIdFromUrl(url),
1791
+ local,
1792
+ url,
1793
+ resUrl,
1794
+ });
1795
+ }
1796
+ return items;
1797
+ }
1798
+
1799
  function artifactInfoFromCell(meta, body) {
1800
  const name = meta.artifact || meta.path || "";
1801
  let size = null;
 
1820
  };
1821
  }
1822
 
1823
+ function cellArtifactItems(md) {
1824
+ const re = new RegExp(LB_CELL_RE.source, "g");
1825
+ const items = [];
1826
+ let m;
1827
+ while ((m = re.exec(md))) {
1828
+ const meta = parseCellMeta(m[2]);
1829
+ const body = m[3];
1830
+ const order = meta.created_at || "";
1831
+ if (meta.type === "artifact") {
1832
+ const info = artifactInfoFromCell(meta, body);
1833
+ if (info.name) items.push({ ...info, order });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1834
  }
1835
  }
1836
+ return items;
1837
+ }
1838
+
1839
+ function collectLogbookResources(markdownList) {
1840
+ const re = new RegExp(LB_CELL_RE.source, "g");
1841
+ const dashboards = new Map();
1842
+ markdownList.forEach((md) => {
1843
+ let m;
1844
+ while ((m = re.exec(md))) {
1845
+ const meta = parseCellMeta(m[2]);
1846
+ const body = m[3];
1847
+ if (meta.type !== "dashboard") continue;
1848
+ const project = meta.dashboard_project || "";
1849
+ const space = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
1850
+ const local = !space;
1851
+ const url = space ? space[0] : "";
1852
+ const key = local ? `local:${project}` : `space:${spaceIdFromUrl(url)}`;
1853
+ const resUrl = local ? `trackio-local-dashboard://${project}` : url;
1854
+ if (!dashboards.has(key))
1855
+ dashboards.set(key, { project, local, url, resUrl });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1856
  }
1857
  });
1858
+ const artifacts = new Map();
1859
+ markdownList.forEach((md) => {
1860
+ cellArtifactItems(md).forEach((it) => {
1861
+ const key = `${it.type}:${it.name}`;
1862
+ const prev = artifacts.get(key);
1863
+ if (!prev || it.order >= prev.order) artifacts.set(key, it);
1864
+ });
1865
+ });
1866
+ return {
1867
+ dashboards: Array.from(dashboards.values()).sort((a, b) =>
1868
+ a.project.localeCompare(b.project)
1869
+ ),
1870
+ artifacts: Array.from(artifacts.values()).sort((a, b) =>
1871
+ a.name.localeCompare(b.name)
1872
+ ),
1873
+ };
1874
  }
1875
 
1876
+ function closeStatPopovers() {
1877
+ document
1878
+ .querySelectorAll(".stat-popover")
1879
+ .forEach((p) => (p.hidden = true));
1880
+ document
1881
+ .querySelectorAll(".stat-tile.open")
1882
+ .forEach((t) => t.classList.remove("open"));
 
 
 
 
 
 
 
 
 
 
1883
  }
1884
 
1885
+ function ensureStatListeners() {
1886
+ if (STATS_LISTENERS) return;
1887
+ STATS_LISTENERS = true;
1888
+ document.addEventListener("click", closeStatPopovers);
1889
+ document.addEventListener("keydown", (e) => {
1890
+ if (e.key === "Escape") closeStatPopovers();
 
 
 
 
 
1891
  });
1892
  }
1893
 
1894
+ function stateHtml(remote, url) {
1895
+ return remote
1896
+ ? `<a class="stat-row-state open" href="${esc(url)}" target="_blank" rel="noopener" title="Open in a new tab">Open ↗</a>`
1897
+ : `<span class="stat-row-state">publish to share</span>`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1898
  }
1899
 
1900
+ function scrollToResource(resUrl) {
1901
+ closeStatPopovers();
1902
+ if (!resUrl) return;
1903
+ const el = document.querySelector(
1904
+ `#page .page-body [data-res-url="${CSS.escape(resUrl)}"]:not(.stat-row)`
1905
+ );
1906
+ if (!el) return;
1907
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
1908
+ el.classList.add("res-flash");
1909
+ setTimeout(() => el.classList.remove("res-flash"), 1500);
1910
+ }
1911
+
1912
+ function dashRowHtml(d) {
1913
+ const inner =
1914
+ `<span class="stat-row-ico">${DASHBOARD_ICON_IMG}</span>` +
1915
+ `<div class="stat-row-main"><div class="stat-row-title">${esc(d.project)}</div>` +
1916
+ `<div class="stat-row-meta">${stateHtml(!d.local, d.url)}</div></div>`;
1917
+ return `<div class="stat-row" data-res-url="${esc(d.resUrl)}" title="Jump to it in the logbook">${inner}</div>`;
1918
+ }
1919
+
1920
+ function artRowHtml(a) {
1921
+ const remote = !a.local && !!a.url;
1922
+ const parts = [a.type, a.size].filter(Boolean).map(esc);
1923
+ const meta = parts.length
1924
+ ? `${parts.join(" · ")} · ${stateHtml(remote, a.url)}`
1925
+ : stateHtml(remote, a.url);
1926
+ const inner =
1927
+ `<span class="stat-row-ico">${ARTIFACT_ICON_IMG}</span>` +
1928
+ `<div class="stat-row-main"><div class="stat-row-title">${esc(a.name)}</div>` +
1929
+ `<div class="stat-row-meta">${meta}</div></div>`;
1930
+ return `<div class="stat-row" data-res-url="${esc(a.resUrl)}" title="Jump to it in the logbook">${inner}</div>`;
1931
+ }
1932
+
1933
+ function statTile(icon, alt, singular, plural, head, rowFn) {
1934
+ const tile = document.createElement("button");
1935
+ tile.type = "button";
1936
+ tile.className = "stat-tile";
1937
+ const render = (items) => {
1938
+ const count = items.length;
1939
+ const label = count === 1 ? singular : plural;
1940
+ const caret = count > 0 ? `<span class="stat-caret">▾</span>` : "";
1941
+ tile.innerHTML =
1942
+ `<img class="stat-icon" src="${icon}" alt="${esc(alt)}" />` +
1943
+ `<div class="stat-text"><div class="stat-num">${count}</div>` +
1944
+ `<div class="stat-label">${esc(label)}</div></div>` +
1945
+ caret;
1946
+ tile.disabled = count === 0;
1947
+ if (count > 0) {
1948
+ const pop = document.createElement("div");
1949
+ pop.className = "stat-popover";
1950
+ pop.hidden = true;
1951
+ pop.innerHTML =
1952
+ `<div class="stat-pop-head">${esc(head)}</div>` +
1953
+ items.map(rowFn).join("");
1954
+ pop.addEventListener("click", (e) => {
1955
+ if (e.target.closest("a.stat-row-state")) {
1956
+ e.stopPropagation();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1957
  return;
1958
  }
1959
+ e.stopPropagation();
1960
+ const row = e.target.closest(".stat-row");
1961
+ if (row) scrollToResource(row.dataset.resUrl);
 
 
1962
  });
1963
+ tile.appendChild(pop);
 
 
 
 
 
 
 
 
 
1964
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1965
  };
1966
+ tile.addEventListener("click", (e) => {
1967
+ if (tile.disabled) return;
1968
+ e.stopPropagation();
1969
+ const pop = tile.querySelector(".stat-popover");
1970
+ if (!pop) return;
1971
+ const isOpen = !pop.hidden;
1972
+ closeStatPopovers();
1973
+ if (!isOpen) {
1974
+ pop.hidden = false;
1975
+ tile.classList.add("open");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1976
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1977
  });
1978
+ return { tile, render };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1979
  }
1980
 
1981
+ function buildLogbookStats(markdownList) {
1982
+ const token = ++STATS_TOKEN;
1983
+ ensureStatListeners();
1984
+ const { dashboards, artifacts } = collectLogbookResources(markdownList);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1985
 
1986
+ const el = document.createElement("div");
1987
+ el.className = "logbook-stats";
1988
+ const dash = statTile(
1989
+ "./trackio-logo-light.png",
1990
+ "Trackio",
1991
+ "Trackio Dashboard",
1992
+ "Trackio Dashboards",
1993
+ "Dashboards created in this logbook",
1994
+ dashRowHtml
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1995
  );
1996
+ const art = statTile(
1997
+ "./bucket-icon.svg",
1998
+ "Bucket",
1999
+ "Artifact",
2000
+ "Artifacts",
2001
+ "Artifacts created in this logbook",
2002
+ artRowHtml
2003
+ );
2004
+ dash.render(dashboards);
2005
+ art.render(artifacts);
2006
+ el.appendChild(dash.tile);
2007
+ el.appendChild(art.tile);
2008
+
2009
+ const scanText = markdownList
2010
+ .map((md) =>
2011
+ md.replace(/(`{3,4}|~{3,4})(html|raw)[^\n]*\n[\s\S]*?\n\1/g, " ")
2012
  )
2013
+ .join("\n");
2014
+ const seen = new Set(
2015
+ dashboards.map((d) =>
2016
+ d.local ? `local:${d.project}` : `space:${spaceIdFromUrl(d.url)}`
2017
+ )
2018
+ );
2019
+ const remoteSpaces = new Map();
2020
+ extractUrls(scanText).forEach((url) => {
2021
+ const item = classifyResource(url);
2022
+ if (item && item.kind === "space" && !item.local) {
2023
+ remoteSpaces.set(item.url, item);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2024
  }
2025
+ });
2026
+ remoteSpaces.forEach((s) => {
2027
+ const key = `space:${s.id}`;
2028
+ if (seen.has(key)) return;
2029
+ getJSON(`https://huggingface.co/api/spaces/${s.id}`)
2030
+ .then((d) => {
2031
+ if (STATS_TOKEN !== token) return;
2032
+ const tags = (d && d.tags) || [];
2033
+ if (
2034
+ !seen.has(key) &&
2035
+ tags.some((t) => String(t).toLowerCase() === "trackio")
2036
+ ) {
2037
+ seen.add(key);
2038
+ dashboards.push({
2039
+ project: s.id,
2040
+ local: false,
2041
+ url: s.url,
2042
+ resUrl: s.url,
2043
+ });
2044
+ dashboards.sort((a, b) => a.project.localeCompare(b.project));
2045
+ dash.render(dashboards);
2046
+ }
2047
+ })
2048
+ .catch(() => {});
2049
+ });
2050
+ return el;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2051
  }
2052
 
2053
+ function buildAgentHint() {
2054
+ const onSpaces =
2055
+ /\.hf\.space$/.test(location.hostname) ||
2056
+ /(^|\.)huggingface\.co$/.test(location.hostname);
2057
+ let source = "";
2058
+ if (onSpaces && MANIFEST.space_id) {
2059
+ source = ` ${MANIFEST.space_id}`;
2060
+ } else if (/^https?:$/.test(location.protocol)) {
2061
+ source = ` ${location.origin}/`;
2062
+ }
2063
+ const command = `trackio logbook read${source}`;
2064
+ const tokens = MANIFEST.agent_view_tokens;
2065
+ const div = document.createElement("div");
2066
+ div.className = "agent-hint";
2067
+ const label = document.createElement("span");
2068
+ label.className = "agent-hint-label";
2069
+ label.textContent = "Read from the CLI:";
2070
+ const code = document.createElement("code");
2071
+ code.textContent = command;
2072
+ const copy = document.createElement("button");
2073
+ copy.className = "copy";
2074
+ copy.type = "button";
2075
+ copy.title = "Copy";
2076
+ copy.textContent = "⧉";
2077
+ copy.addEventListener("click", () => copyText(command, copy, "⧉"));
2078
+ const note = document.createElement("span");
2079
+ note.className = "agent-hint-note";
2080
+ note.textContent =
2081
+ "compact view for agents" + (tokens ? ` · ~${fmt(tokens)} tokens` : "");
2082
+ div.appendChild(label);
2083
+ div.appendChild(code);
2084
+ div.appendChild(copy);
2085
+ div.appendChild(note);
2086
+ return div;
2087
  }
2088
 
2089
  function currentSlug() {
2090
+ const slug = (location.hash || "").replace(/^#\//, "") || MANIFEST.root.slug;
2091
+ return findNode(MANIFEST.root, slug) ? slug : MANIFEST.root.slug;
2092
  }
2093
 
2094
  function scrollToHash(opts = {}) {
 
2095
  const slug = currentSlug();
2096
+ if (!location.hash) {
2097
  window.scrollTo({ top: 0, behavior: opts.behavior || "auto" });
2098
  highlight(slug);
2099
  return;
 
2106
  function navigateToLogbookSlug(target) {
2107
  const slug = String(target || "").replace(/^#?\//, "").trim();
2108
  if (!slug || !findNode(MANIFEST.root, slug)) return;
2109
+ const hash = "#/" + slug;
2110
  if (location.hash === hash) {
2111
  scrollToHash({ behavior: "smooth" });
2112
  } else {
 
2130
 
2131
  let SCROLL_FRAME = 0;
2132
  function updateActiveSection() {
 
2133
  cancelAnimationFrame(SCROLL_FRAME);
2134
  SCROLL_FRAME = requestAnimationFrame(() => {
2135
+ const sections = Array.from(document.querySelectorAll(".page-section"));
 
 
2136
  if (!sections.length) return;
2137
  const marker = Math.min(window.innerHeight * 0.28, 180);
2138
  let active = sections[0];
 
2145
  ) {
2146
  active = sections[sections.length - 1];
2147
  }
2148
+ highlight(active.dataset.slug);
 
 
 
 
2149
  });
2150
  }
2151
 
 
2161
  document.getElementById("book-title").textContent = MANIFEST.title;
2162
  document.getElementById("book-head").setAttribute("aria-label", MANIFEST.title);
2163
  buildTree();
2164
+ renderLogbook({ preserveScroll: true });
2165
  } catch (e) {}
2166
  }, LIVE_RELOAD_MS);
2167
  }
 
2257
  document.getElementById("book-title").textContent = MANIFEST.title;
2258
  document.getElementById("book-head").setAttribute("aria-label", MANIFEST.title);
2259
  document.getElementById("book-head").addEventListener("click", () => {
2260
+ const target = "#/" + MANIFEST.root.slug;
2261
  if (location.hash === target) scrollToHash();
2262
  else location.hash = target;
2263
  });
2264
  buildTree();
2265
  setupConnect();
2266
+ setupResourceHover();
2267
  setupFigureNavigation();
2268
+ window.addEventListener("hashchange", () => scrollToHash());
2269
  window.addEventListener("scroll", updateActiveSection, { passive: true });
2270
+ await renderLogbook();
2271
  startLiveReload();
2272
  }
2273
 
logbook.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "schema_version": 2,
3
  "title": "Reproduction: Distributed Direct Preference Optimization",
4
  "emoji": "🎯",
5
  "space_id": "SabaPivot/repro-distributed-direct-preference-optimization",
@@ -10,13 +10,13 @@
10
  "url": "https://openreview.net/forum?id=ljNZyrAlaa"
11
  },
12
  "tags": [
13
- "trackio",
14
- "open-reproductions",
15
  "icml2026",
16
  "icml2026-repro",
17
- "paper-ljNZyrAlaa"
 
 
18
  ],
19
- "updated_at": "2026-07-29T14:48:30+00:00",
20
  "root": {
21
  "slug": "index",
22
  "title": "Reproduction: Distributed Direct Preference Optimization",
@@ -29,39 +29,45 @@
29
  "children": []
30
  },
31
  {
32
- "slug": "claim-1-feddpo-partial-participation-bound",
33
- "title": "Claim 1: FedDPO partial participation bound",
34
- "file": "pages/claim-1-feddpo-partial-participation-bound/page.md",
 
 
 
 
 
 
35
  "children": []
36
  },
37
  {
38
- "slug": "claim-2-full-participation-corollary",
39
- "title": "Claim 2: Full participation corollary",
40
- "file": "pages/claim-2-full-participation-corollary/page.md",
41
  "children": []
42
  },
43
  {
44
- "slug": "claim-3-staleness-penalty",
45
- "title": "Claim 3: Staleness penalty",
46
- "file": "pages/claim-3-staleness-penalty/page.md",
47
  "children": []
48
  },
49
  {
50
- "slug": "claim-4-feddpo-lower-bound",
51
- "title": "Claim 4: FedDPO lower bound",
52
- "file": "pages/claim-4-feddpo-lower-bound/page.md",
53
  "children": []
54
  },
55
  {
56
- "slug": "claim-5-decdpo-spectral-rate",
57
- "title": "Claim 5: DecDPO spectral rate",
58
- "file": "pages/claim-5-decdpo-spectral-rate/page.md",
59
  "children": []
60
  },
61
  {
62
- "slug": "claim-6-shp-numerical-results",
63
- "title": "Claim 6: SHP numerical results",
64
- "file": "pages/claim-6-shp-numerical-results/page.md",
65
  "children": []
66
  },
67
  {
@@ -72,30 +78,6 @@
72
  }
73
  ]
74
  },
75
- "traces": [],
76
- "workspace": {
77
- "file": "workspace.json",
78
- "file_count": 0,
79
- "total_size": 0,
80
- "bucket_id": null
81
- },
82
- "agent_view_tokens": 5866,
83
- "trace_view_tokens": 17229,
84
- "workspace_view_tokens": 85,
85
- "revision": "e6d12b1ed894120a273d",
86
- "traces_ref": {
87
- "repo_id": "SabaPivot/repro-distributed-direct-preference-optimization-traces",
88
- "repo_type": "dataset",
89
- "repo_url": "https://huggingface.co/datasets/SabaPivot/repro-distributed-direct-preference-optimization-traces",
90
- "private": true,
91
- "viewer_path": "trackio/index.json"
92
- },
93
- "trace_dataset": "https://huggingface.co/datasets/SabaPivot/repro-distributed-direct-preference-optimization-traces",
94
- "workspace_ref": {
95
- "repo_id": "SabaPivot/repro-distributed-direct-preference-optimization-artifacts",
96
- "repo_type": "bucket",
97
- "repo_url": "https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts",
98
- "private": true
99
- },
100
- "workspace_bucket": "https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts"
101
- }
 
1
  {
2
+ "schema_version": 1,
3
  "title": "Reproduction: Distributed Direct Preference Optimization",
4
  "emoji": "🎯",
5
  "space_id": "SabaPivot/repro-distributed-direct-preference-optimization",
 
10
  "url": "https://openreview.net/forum?id=ljNZyrAlaa"
11
  },
12
  "tags": [
 
 
13
  "icml2026",
14
  "icml2026-repro",
15
+ "open-reproductions",
16
+ "paper-ljNZyrAlaa",
17
+ "trackio"
18
  ],
19
+ "updated_at": "2026-07-30T02:11:55.819945+00:00",
20
  "root": {
21
  "slug": "index",
22
  "title": "Reproduction: Distributed Direct Preference Optimization",
 
29
  "children": []
30
  },
31
  {
32
+ "slug": "claim-1",
33
+ "title": "Claim 1: Theorem 5.1 gives the first convergence bound for Federated DPO (FedDPO) under partial client participation, showing gradient-norm error scaling with local steps E, rounds R, sampled clients S, and gradient variance ζ²_g (Theorem 5.1).",
34
+ "file": "pages/claim-1/page.md",
35
+ "children": []
36
+ },
37
+ {
38
+ "slug": "claim-2",
39
+ "title": "Claim 2: Corollary 5.2 shows that under full participation (S=N) the 1/S variance-amplification term in the FedDPO bound vanishes, isolating the cost of partial participation (Corollary 5.2).",
40
+ "file": "pages/claim-2/page.md",
41
  "children": []
42
  },
43
  {
44
+ "slug": "claim-3",
45
+ "title": "Claim 3: Theorem 5.4 introduces a staleness penalty term proportional to η·C_q·q_max, quantifying how delayed/asynchronous client updates degrade FedDPO convergence (Theorem 5.4).",
46
+ "file": "pages/claim-3/page.md",
47
  "children": []
48
  },
49
  {
50
+ "slug": "claim-4",
51
+ "title": "Claim 4: Theorem 5.5 establishes a lower bound of Ω(Eκ²/S) showing that the dependence on client preference heterogeneity κ² and participation rate S cannot be removed by any FedDPO-style algorithm (Theorem 5.5).",
52
+ "file": "pages/claim-4/page.md",
53
  "children": []
54
  },
55
  {
56
+ "slug": "claim-5",
57
+ "title": "Claim 5: Theorem 6.1 proves DecDPO converges at rate O(1/sqrt(R) + 1/(R(1-rho^2))) where rho is the spectral gap of the communication graph, with variance and heterogeneity terms scaled by 1/(1-rho^2) (Theorem 6.1).",
58
+ "file": "pages/claim-5/page.md",
59
  "children": []
60
  },
61
  {
62
+ "slug": "claim-6",
63
+ "title": "Claim 6: Numerical experiments on the Stanford Human Preferences dataset with N=5 agents empirically confirm the predicted effects of local step count, participation rate, staleness, and network topology on convergence (Section 7, Numerical Results).",
64
+ "file": "pages/claim-6/page.md",
65
  "children": []
66
  },
67
  {
68
+ "slug": "claim-7-real-model-setup",
69
+ "title": "Real-model setup — DistilGPT-2 (82M) on Stanford Human Preferences",
70
+ "file": "pages/claim-7-real-model-setup/page.md",
71
  "children": []
72
  },
73
  {
 
78
  }
79
  ]
80
  },
81
+ "agent_view_tokens": 3400,
82
+ "revision": "1784656265000000000"
83
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
official_claims.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ [
2
+ "Theorem 5.1 gives the first convergence bound for Federated DPO (FedDPO) under partial client participation, showing gradient-norm error scaling with local steps E, rounds R, sampled clients S, and gradient variance ζ²_g (Theorem 5.1).",
3
+ "Corollary 5.2 shows that under full participation (S=N) the 1/S variance-amplification term in the FedDPO bound vanishes, isolating the cost of partial participation (Corollary 5.2).",
4
+ "Theorem 5.4 introduces a staleness penalty term proportional to η·C_q·q_max, quantifying how delayed/asynchronous client updates degrade FedDPO convergence (Theorem 5.4).",
5
+ "Theorem 5.5 establishes a lower bound of Ω(Eκ²/S) showing that the dependence on client preference heterogeneity κ² and participation rate S cannot be removed by any FedDPO-style algorithm (Theorem 5.5).",
6
+ "Theorem 6.1 proves DecDPO (decentralized DPO) converges at rate O(1/√R + 1/(R(1−ρ²))) where ρ is the spectral gap of the communication graph, with variance and heterogeneity terms scaled by 1/(1−ρ²) (Theorem 6.1).",
7
+ "Numerical experiments on the Stanford Human Preferences dataset with N=5 agents empirically confirm the predicted effects of local step count, participation rate, staleness, and network topology on convergence (Section 7, Numerical Results)."
8
+ ]
outputs/SHA256SUMS.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "corollary_5_2_full_participation.csv": "ff2d4278b79e9fdf103a48f907d694a11e39eda0369daf6076f0e269da141b86",
3
+ "dec_dpo_topology.csv": "691bdcc6ae25aa25d6598dbf87ad060255e9a0f802e03341da6a30eeb362b2ba",
4
+ "distributed_dpo_audit.png": "c08e9e3b7baf8e05e4a4190efd714a72d9122fd3cd4ecd645d640a9aea6ca1e4",
5
+ "fed_dpo_shp_ablations.csv": "31bfaabea77d3022b17e469b7b9f546a2fec8c40431b8177d1cf077ac06a9718",
6
+ "results.json": "bb7e2073a3d41e3c2fdb957ab423ee83a367d3fe1badcf5fbcb98e516a9b707b",
7
+ "shp_inventory.csv": "6460bb569c5ac46a0509503168290bb4b2bb03a5e6f566f282d0fe5a183e7732",
8
+ "source_claim_audit.csv": "c8464ba0cf666528438250e6fd581271d770a4c136c6a55377ca3361fd42b8e4",
9
+ "theorem_5_1_partial_bound.csv": "9accf57701e23d9e172978f895d6faf38f2a12f150d968d2ead593d3304fb896",
10
+ "theorem_5_4_staleness.csv": "be181a404639b2722e3a7905df2d4faf8bfb8e562ee42277b8e32652b724fdc1",
11
+ "theorem_5_5_lower_bound.csv": "8fc7b9c6775c5d7846a474089c727d0ae8a1de3bcf5db1abf76914e74878ad6d"
12
+ }
outputs/corollary_5_2_full_participation.csv ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ E,N,R,eta,initialization_term,partial_participation_variance_amplification,client_average_variance,heterogeneity_term,corollary_5_2_bound
2
+ 1,5,40,0.09486832980505137,0.36532064071556886,0.0,5.9786642628232746e-05,1.3337996821150978e-07,0.3653805607381653
3
+ 1,5,80,0.06708203932499368,0.25832070235739313,0.0,4.227554042680008e-05,6.668998410575486e-08,0.258363044587804
4
+ 1,5,160,0.04743416490252569,0.18266032035778443,0.0,2.9893321314116373e-05,3.3344992052877444e-08,0.1826902470240906
5
+ 1,5,320,0.03354101966249684,0.12916035117869656,0.0,2.113777021340004e-05,1.6672496026438715e-08,0.12918150562140598
6
+ 3,5,40,0.09486832980505137,0.12177354690518961,0.0,5.9786642628232746e-05,4.001399046345293e-07,0.12183373368772249
7
+ 3,5,80,0.06708203932499368,0.08610690078579769,0.0,4.227554042680008e-05,2.0006995231726458e-07,0.0861493763961768
8
+ 3,5,160,0.04743416490252569,0.06088677345259481,0.0,2.9893321314116373e-05,1.0003497615863233e-07,0.06091676680888508
9
+ 3,5,320,0.03354101966249684,0.043053450392898845,0.0,2.113777021340004e-05,5.0017488079316146e-08,0.043074638180600325
10
+ 6,5,40,0.09486832980505137,0.06088677345259481,0.0,5.9786642628232746e-05,8.002798092690587e-07,0.06094736037503231
11
+ 6,5,80,0.06708203932499368,0.043053450392898845,0.0,4.227554042680008e-05,4.0013990463452917e-07,0.04309612607323028
12
+ 6,5,160,0.04743416490252569,0.030443386726297404,0.0,2.9893321314116373e-05,2.0006995231726466e-07,0.030473480117563838
13
+ 6,5,320,0.03354101966249684,0.021526725196449423,0.0,2.113777021340004e-05,1.0003497615863229e-07,0.021547963001638984
outputs/dec_dpo_topology.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ topology,replicates,rho,one_over_one_minus_rho_squared,mean_tail_consensus_error,mean_tail_gradient_norm_sq,mean_final_loss
2
+ path,8,0.872677996249965,4.194048299802485,0.0005454370424672539,0.0005829917140026842,0.6837910799762497
3
+ ring,8,0.5393446629166316,1.4102237436136194,3.761684387776997e-05,0.0005826007264608975,0.6837903595432446
4
+ star,8,0.8,2.7777777777777786,0.00041163500941361045,0.000582458508441908,0.683671120904709
5
+ complete,8,8.284195946896153e-17,1.0,9.32317306912503e-34,0.0005820751105032884,0.6834946549569718
outputs/distributed_dpo_audit.png ADDED

Git LFS Details

  • SHA256: c08e9e3b7baf8e05e4a4190efd714a72d9122fd3cd4ecd645d640a9aea6ca1e4
  • Pointer size: 131 Bytes
  • Size of remote file: 151 kB
outputs/fed_dpo_shp_ablations.csv ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ family,local_steps_E,sampled_clients_S,qmax,replicates,mean_final_loss,mean_loss_reduction,mean_tail_gradient_norm_sq,std_tail_gradient_norm_sq
2
+ local_steps,1,3,0,8,0.6854464561081451,0.007700724451800131,0.0005880749016315657,1.0155468747282728e-06
3
+ local_steps,3,3,0,8,0.6713684502828248,0.021778730277120517,0.0005443930037768237,2.4343579389877103e-06
4
+ local_steps,6,3,0,8,0.6516766529857532,0.0414705275741922,0.0004827668972471771,2.1931322746900754e-06
5
+ participation,3,1,0,8,0.6713264270553448,0.02182075350460043,0.0005435496190031553,4.033222976843732e-06
6
+ participation,3,3,0,8,0.6711281026192374,0.02201907794070794,0.0005434856562567469,2.109517284475393e-06
7
+ participation,3,5,0,8,0.6710800062252151,0.02206717433473021,0.0005436639929552561,1.0201377991962554e-06
8
+ staleness,3,3,0,8,0.6710920419315259,0.022055138628419332,0.000543698019818161,2.69970703565243e-06
9
+ staleness,3,3,2,8,0.6816140324392188,0.011533148120726491,0.0005762081162556293,1.0118713023835438e-06
10
+ staleness,3,3,5,8,0.6863272721344135,0.006819908425531804,0.0005908721885661179,1.4644118928873132e-06
outputs/results.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "all_gates_pass": true,
3
+ "arxiv": "2605.20696v1",
4
+ "gates": {
5
+ "all_outputs_finite": true,
6
+ "claim1_actual_feddpo_executed": true,
7
+ "claim1_inverse_S_terms_exact": true,
8
+ "claim1_partial_bound_multiple_E_S_R": true,
9
+ "claim2_full_participation_amplification_removed": true,
10
+ "claim2_residual_client_average_variance_preserved": true,
11
+ "claim3_stale_algorithm_executed": true,
12
+ "claim3_staleness_formula_exact": true,
13
+ "claim3_staleness_zero_at_q_zero": true,
14
+ "claim4_full_participation_sampling_variance_zero": true,
15
+ "claim4_lower_bound_scaling_exact": true,
16
+ "claim5_connectivity_factor_varies": true,
17
+ "claim5_decdpo_executed": true,
18
+ "claim5_four_symmetric_graphs": true,
19
+ "claim6_all_four_ablation_families": true,
20
+ "claim6_exact_N5_times_120_SHP_rows": true,
21
+ "destructive_identical_clients_reduce_participation_effect": true,
22
+ "destructive_label_corruption_worsens_clean_objective": true,
23
+ "destructive_no_mixing_increases_consensus_error": true,
24
+ "source_pins_verified": true
25
+ },
26
+ "headline": {
27
+ "clean_final_loss": 0.670980521644771,
28
+ "clients": 5,
29
+ "decdpo_algorithm_runs": 32,
30
+ "decdpo_topology_cells": 4,
31
+ "fed_ablation_cells": 9,
32
+ "fed_ablation_ranges": {
33
+ "local_steps": 0.0001053080043843886,
34
+ "participation": 1.7833669850922645e-07,
35
+ "staleness": 4.7174168747956885e-05
36
+ },
37
+ "fed_algorithm_runs": 72,
38
+ "identical_client_S1_to_S5_ratio": 1.0004384715044146,
39
+ "kappa_squared": 0.001157812224058244,
40
+ "label_corrupted_final_loss": 0.690625282427891,
41
+ "lower_bound_cells": 20,
42
+ "no_mix_to_mix_consensus_ratio": 575.6464809616402,
43
+ "pairs_per_client": 120,
44
+ "shp_pairs": 600,
45
+ "smoothness_L_bound": 0.04000000000000001,
46
+ "staleness_formula_cells": 15,
47
+ "theorem_5_1_formula_cells": 36,
48
+ "topology_consensus_range": 0.0005454370424672539,
49
+ "topology_factor_consensus_spearman": 1.0,
50
+ "zeta_squared": 0.039387909241610605
51
+ },
52
+ "openreview_id": "ljNZyrAlaa",
53
+ "paper": "Distributed Direct Preference Optimization",
54
+ "scope": "finite log-linear SHP mechanism audit plus exact source-formula reconstruction",
55
+ "seed": 20260721
56
+ }
outputs/shp_inventory.csv ADDED
@@ -0,0 +1,601 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ row,client,domain,label,score_A,score_B,feature_norm
2
+ 0,0,askacademia_train,0,52,54,1.0
3
+ 1,0,askacademia_train,0,5,17,1.0
4
+ 2,0,askacademia_train,0,5,7,1.0
5
+ 3,0,askacademia_train,1,7,5,0.9999999999999999
6
+ 4,0,askacademia_train,0,6,7,1.0
7
+ 5,0,askacademia_train,1,7,5,1.0
8
+ 6,0,askacademia_train,1,6,5,1.0
9
+ 7,0,askacademia_train,0,5,7,1.0
10
+ 8,0,askacademia_train,1,7,6,0.9999999999999999
11
+ 9,0,askacademia_train,1,7,4,1.0
12
+ 10,0,askacademia_train,1,7,2,0.9999999999999999
13
+ 11,0,askacademia_train,0,2,7,1.0
14
+ 12,0,askacademia_train,1,6,5,0.9999999999999999
15
+ 13,0,askacademia_train,1,4,2,0.9999999999999999
16
+ 14,0,askacademia_train,1,4,3,0.9999999999999999
17
+ 15,0,askacademia_train,0,2,4,1.0
18
+ 16,0,askacademia_train,1,4,2,1.0
19
+ 17,0,askacademia_train,1,4,2,1.0
20
+ 18,0,askacademia_train,1,4,2,1.0
21
+ 19,0,askacademia_train,1,4,2,0.9999999999999999
22
+ 20,0,askacademia_train,0,2,4,1.0
23
+ 21,0,askacademia_train,1,3,2,1.0
24
+ 22,0,askacademia_train,0,3,4,1.0
25
+ 23,0,askacademia_train,1,4,3,1.0
26
+ 24,0,askacademia_train,0,3,4,0.9999999999999999
27
+ 25,0,askacademia_train,1,4,3,1.0
28
+ 26,0,askacademia_train,0,2,4,1.0
29
+ 27,0,askacademia_train,0,2,4,1.0000000000000002
30
+ 28,0,askacademia_train,1,4,2,1.0
31
+ 29,0,askacademia_train,0,3,4,0.9999999999999999
32
+ 30,0,askacademia_train,1,4,3,1.0
33
+ 31,0,askacademia_train,0,3,4,1.0
34
+ 32,0,askacademia_train,0,3,4,0.9999999999999999
35
+ 33,0,askacademia_train,0,2,4,0.9999999999999999
36
+ 34,0,askacademia_train,1,4,2,1.0
37
+ 35,0,askacademia_train,1,4,2,1.0
38
+ 36,0,askacademia_train,1,4,3,0.9999999999999999
39
+ 37,0,askacademia_train,0,3,4,1.0
40
+ 38,0,askacademia_train,0,3,4,0.9999999999999999
41
+ 39,0,askacademia_train,1,4,3,0.9999999999999999
42
+ 40,0,askacademia_train,0,2,4,1.0
43
+ 41,0,askacademia_train,0,2,4,0.9999999999999999
44
+ 42,0,askacademia_train,1,4,2,1.0
45
+ 43,0,askacademia_train,1,3,2,1.0
46
+ 44,0,askacademia_train,1,3,2,1.0
47
+ 45,0,askacademia_train,1,3,2,0.9999999999999999
48
+ 46,0,askacademia_train,1,3,2,0.9999999999999998
49
+ 47,0,askacademia_train,1,3,2,1.0
50
+ 48,0,askacademia_train,1,3,2,1.0
51
+ 49,0,askacademia_train,1,3,2,1.0
52
+ 50,0,askacademia_train,0,2,3,1.0
53
+ 51,0,askacademia_train,1,3,2,1.0
54
+ 52,0,askacademia_train,1,3,2,0.9999999999999999
55
+ 53,0,askacademia_train,0,2,3,1.0
56
+ 54,0,askacademia_train,1,3,2,1.0
57
+ 55,0,askacademia_train,0,2,3,1.0
58
+ 56,0,askacademia_train,1,3,2,0.9999999999999999
59
+ 57,0,askacademia_train,0,2,3,1.0
60
+ 58,0,askacademia_train,0,157,246,1.0
61
+ 59,0,askacademia_train,0,157,209,1.0000000000000002
62
+ 60,0,askacademia_train,0,50,209,0.9999999999999999
63
+ 61,0,askacademia_train,1,209,8,1.0
64
+ 62,0,askacademia_train,1,68,50,0.9999999999999999
65
+ 63,0,askacademia_train,0,14,68,1.0
66
+ 64,0,askacademia_train,0,8,68,1.0
67
+ 65,0,askacademia_train,1,68,2,1.0
68
+ 66,0,askacademia_train,1,50,8,0.9999999999999999
69
+ 67,0,askacademia_train,0,22,48,1.0
70
+ 68,0,askacademia_train,0,18,48,1.0
71
+ 69,0,askacademia_train,0,19,48,1.0
72
+ 70,0,askacademia_train,1,48,14,1.0
73
+ 71,0,askacademia_train,0,8,48,1.0
74
+ 72,0,askacademia_train,0,4,48,0.9999999999999999
75
+ 73,0,askacademia_train,1,48,2,1.0
76
+ 74,0,askacademia_train,1,22,18,1.0
77
+ 75,0,askacademia_train,0,14,22,0.9999999999999999
78
+ 76,0,askacademia_train,1,22,8,1.0
79
+ 77,0,askacademia_train,1,22,4,0.9999999999999999
80
+ 78,0,askacademia_train,1,22,2,1.0
81
+ 79,0,askacademia_train,1,19,18,1.0
82
+ 80,0,askacademia_train,0,14,18,1.0
83
+ 81,0,askacademia_train,1,18,8,1.0
84
+ 82,0,askacademia_train,0,4,18,1.0
85
+ 83,0,askacademia_train,1,18,2,0.9999999999999999
86
+ 84,0,askacademia_train,1,19,14,1.0
87
+ 85,0,askacademia_train,0,8,19,1.0
88
+ 86,0,askacademia_train,0,4,19,1.0000000000000002
89
+ 87,0,askacademia_train,1,19,2,0.9999999999999999
90
+ 88,0,askacademia_train,1,16,14,1.0
91
+ 89,0,askacademia_train,1,16,8,1.0
92
+ 90,0,askacademia_train,1,16,4,0.9999999999999999
93
+ 91,0,askacademia_train,1,16,2,1.0
94
+ 92,0,askacademia_train,1,14,8,1.0
95
+ 93,0,askacademia_train,1,14,2,1.0
96
+ 94,0,askacademia_train,0,4,6,1.0
97
+ 95,0,askacademia_train,0,3,6,1.0
98
+ 96,0,askacademia_train,1,6,2,1.0
99
+ 97,0,askacademia_train,0,2,4,1.0000000000000002
100
+ 98,0,askacademia_train,1,3,2,1.0
101
+ 99,0,askacademia_train,0,105,269,0.9999999999999999
102
+ 100,0,askacademia_train,1,269,56,1.0
103
+ 101,0,askacademia_train,0,29,269,1.0
104
+ 102,0,askacademia_train,1,82,55,1.0
105
+ 103,0,askacademia_train,0,56,82,1.0
106
+ 104,0,askacademia_train,1,82,33,0.9999999999999999
107
+ 105,0,askacademia_train,1,82,29,1.0
108
+ 106,0,askacademia_train,1,82,17,1.0000000000000002
109
+ 107,0,askacademia_train,1,82,15,0.9999999999999999
110
+ 108,0,askacademia_train,0,7,82,0.9999999999999999
111
+ 109,0,askacademia_train,0,5,82,1.0
112
+ 110,0,askacademia_train,1,55,33,1.0
113
+ 111,0,askacademia_train,1,55,29,0.9999999999999999
114
+ 112,0,askacademia_train,1,55,7,1.0000000000000002
115
+ 113,0,askacademia_train,1,55,5,0.9999999999999999
116
+ 114,0,askacademia_train,0,29,56,1.0
117
+ 115,0,askacademia_train,0,29,33,1.0
118
+ 116,0,askacademia_train,0,7,17,1.0
119
+ 117,0,askacademia_train,0,5,17,1.0
120
+ 118,0,askacademia_train,0,15,17,1.0
121
+ 119,0,askacademia_train,1,17,7,0.9999999999999999
122
+ 120,1,askacademia_train,1,17,5,0.9999999999999999
123
+ 121,1,askacademia_train,1,15,7,1.0
124
+ 122,1,askacademia_train,1,15,5,1.0
125
+ 123,1,askacademia_train,1,72,53,1.0000000000000002
126
+ 124,1,askacademia_train,0,27,72,1.0
127
+ 125,1,askacademia_train,0,20,72,1.0
128
+ 126,1,askacademia_train,1,49,27,0.9999999999999998
129
+ 127,1,askacademia_train,1,49,20,0.9999999999999999
130
+ 128,1,askacademia_train,1,42,27,1.0
131
+ 129,1,askacademia_train,0,25,42,1.0
132
+ 130,1,askacademia_train,1,42,20,1.0
133
+ 131,1,askacademia_train,0,20,27,1.0
134
+ 132,1,askacademia_train,0,20,25,0.9999999999999999
135
+ 133,1,askacademia_train,0,47,180,0.9999999999999999
136
+ 134,1,askacademia_train,0,47,48,1.0
137
+ 135,1,askacademia_train,0,29,48,1.0
138
+ 136,1,askacademia_train,0,10,48,0.9999999999999999
139
+ 137,1,askacademia_train,0,8,48,1.0
140
+ 138,1,askacademia_train,0,29,41,1.0
141
+ 139,1,askacademia_train,0,10,41,0.9999999999999999
142
+ 140,1,askacademia_train,1,41,8,0.9999999999999999
143
+ 141,1,askacademia_train,0,10,27,1.0
144
+ 142,1,askacademia_train,0,8,27,1.0
145
+ 143,1,askacademia_train,1,16,10,1.0
146
+ 144,1,askacademia_train,1,16,8,0.9999999999999999
147
+ 145,1,askacademia_train,1,16,2,0.9999999999999999
148
+ 146,1,askacademia_train,0,8,10,0.9999999999999999
149
+ 147,1,askacademia_train,0,8,9,0.9999999999999999
150
+ 148,1,askacademia_train,0,2,9,1.0
151
+ 149,1,askacademia_train,0,2,9,0.9999999999999999
152
+ 150,1,askacademia_train,1,5,3,1.0
153
+ 151,1,askacademia_train,1,5,2,0.9999999999999999
154
+ 152,1,askacademia_train,0,2,5,0.9999999999999999
155
+ 153,1,askacademia_train,0,2,5,1.0
156
+ 154,1,askacademia_train,0,2,5,0.9999999999999999
157
+ 155,1,askacademia_train,1,4,3,1.0
158
+ 156,1,askacademia_train,1,4,2,1.0
159
+ 157,1,askacademia_train,1,4,2,0.9999999999999999
160
+ 158,1,askacademia_train,0,2,4,1.0
161
+ 159,1,askacademia_train,1,4,2,0.9999999999999999
162
+ 160,1,askacademia_train,1,4,2,1.0
163
+ 161,1,askacademia_train,1,4,2,1.0
164
+ 162,1,askacademia_train,1,4,2,1.0
165
+ 163,1,askacademia_train,1,4,2,1.0
166
+ 164,1,askacademia_train,1,3,2,1.0
167
+ 165,1,askacademia_train,1,3,2,1.0
168
+ 166,1,askacademia_train,1,332,183,1.0
169
+ 167,1,askacademia_train,0,160,332,0.9999999999999999
170
+ 168,1,askacademia_train,1,332,21,1.0
171
+ 169,1,askacademia_train,1,332,21,1.0
172
+ 170,1,askacademia_train,1,160,21,0.9999999999999999
173
+ 171,1,askacademia_train,0,36,82,1.0
174
+ 172,1,askacademia_train,1,82,21,1.0
175
+ 173,1,askacademia_train,0,21,82,0.9999999999999999
176
+ 174,1,askacademia_train,0,14,82,0.9999999999999999
177
+ 175,1,askacademia_train,0,36,58,1.0
178
+ 176,1,askacademia_train,1,58,26,1.0
179
+ 177,1,askacademia_train,1,58,21,1.0
180
+ 178,1,askacademia_train,1,58,21,0.9999999999999999
181
+ 179,1,askacademia_train,0,14,58,1.0
182
+ 180,1,askacademia_train,0,36,37,0.9999999999999999
183
+ 181,1,askacademia_train,0,21,36,1.0
184
+ 182,1,askacademia_train,0,21,36,0.9999999999999999
185
+ 183,1,askacademia_train,1,37,26,0.9999999999999999
186
+ 184,1,askacademia_train,1,37,21,1.0
187
+ 185,1,askacademia_train,0,21,37,1.0
188
+ 186,1,askacademia_train,1,37,14,1.0
189
+ 187,1,askacademia_train,1,29,26,1.0
190
+ 188,1,askacademia_train,0,21,29,1.0
191
+ 189,1,askacademia_train,0,21,29,1.0
192
+ 190,1,askacademia_train,1,29,14,0.9999999999999999
193
+ 191,1,askacademia_train,0,21,26,0.9999999999999999
194
+ 192,1,askacademia_train,1,26,21,1.0
195
+ 193,1,askacademia_train,0,14,26,0.9999999999999999
196
+ 194,1,askacademia_train,0,8,11,1.0
197
+ 195,1,askacademia_train,1,191,187,1.0
198
+ 196,1,askacademia_train,1,191,7,1.0
199
+ 197,1,askacademia_train,0,8,191,1.0
200
+ 198,1,askacademia_train,0,7,30,0.9999999999999999
201
+ 199,1,askacademia_train,0,8,30,1.0
202
+ 200,1,askacademia_train,0,7,13,1.0
203
+ 201,1,askacademia_train,1,13,8,1.0
204
+ 202,1,askacademia_train,0,7,8,1.0
205
+ 203,1,askacademia_train,0,247,587,1.0000000000000002
206
+ 204,1,askacademia_train,1,587,243,1.0
207
+ 205,1,askacademia_train,0,47,587,0.9999999999999999
208
+ 206,1,askacademia_train,1,587,16,0.9999999999999999
209
+ 207,1,askacademia_train,1,247,47,0.9999999999999999
210
+ 208,1,askacademia_train,0,16,247,1.0
211
+ 209,1,askacademia_train,1,243,47,1.0
212
+ 210,1,askacademia_train,1,243,16,0.9999999999999999
213
+ 211,1,askacademia_train,0,47,89,1.0
214
+ 212,1,askacademia_train,1,89,16,0.9999999999999999
215
+ 213,1,askacademia_train,0,47,50,0.9999999999999999
216
+ 214,1,askacademia_train,0,16,50,1.0
217
+ 215,1,askacademia_train,0,16,39,0.9999999999999999
218
+ 216,1,askacademia_train,0,8,39,0.9999999999999999
219
+ 217,1,askacademia_train,0,9,39,0.9999999999999999
220
+ 218,1,askacademia_train,0,9,39,1.0
221
+ 219,1,askacademia_train,0,16,25,1.0
222
+ 220,1,askacademia_train,0,8,25,1.0
223
+ 221,1,askacademia_train,1,25,9,1.0
224
+ 222,1,askacademia_train,1,25,9,0.9999999999999999
225
+ 223,1,askacademia_train,0,7,25,1.0
226
+ 224,1,askacademia_train,0,7,8,0.9999999999999999
227
+ 225,1,askacademia_train,1,9,8,1.0
228
+ 226,1,askacademia_train,1,8,7,1.0
229
+ 227,1,askacademia_train,1,130,111,1.0
230
+ 228,1,askacademia_train,0,3,7,1.0
231
+ 229,1,askacademia_train,0,3,5,0.9999999999999999
232
+ 230,1,askacademia_train,0,3,5,1.0
233
+ 231,1,askacademia_train,1,69,25,1.0
234
+ 232,1,askacademia_train,0,16,69,1.0
235
+ 233,1,askacademia_train,0,7,69,1.0
236
+ 234,1,askacademia_train,1,69,3,0.9999999999999999
237
+ 235,1,askacademia_train,0,3,69,1.0
238
+ 236,1,askacademia_train,0,3,69,1.0
239
+ 237,1,askacademia_train,1,25,16,1.0
240
+ 238,1,askacademia_train,1,25,7,0.9999999999999999
241
+ 239,1,askacademia_train,0,3,25,1.0
242
+ 240,2,askacademia_train,1,7,4,1.0
243
+ 241,2,askacademia_train,1,7,3,0.9999999999999999
244
+ 242,2,askacademia_train,1,7,3,1.0
245
+ 243,2,askacademia_train,0,3,7,1.0
246
+ 244,2,askacademia_train,0,3,7,1.0
247
+ 245,2,askacademia_train,1,7,2,0.9999999999999999
248
+ 246,2,askacademia_train,0,2,7,0.9999999999999999
249
+ 247,2,askacademia_train,1,7,2,0.9999999999999999
250
+ 248,2,askacademia_train,1,4,3,1.0
251
+ 249,2,askacademia_train,0,3,4,1.0
252
+ 250,2,askacademia_train,1,4,3,0.9999999999999999
253
+ 251,2,askacademia_train,0,3,4,1.0
254
+ 252,2,askacademia_train,1,4,2,0.9999999999999999
255
+ 253,2,askacademia_train,1,4,2,1.0
256
+ 254,2,askacademia_train,1,4,2,0.9999999999999999
257
+ 255,2,askacademia_train,0,2,3,1.0
258
+ 256,2,askacademia_train,0,2,3,0.9999999999999999
259
+ 257,2,askacademia_train,0,2,3,1.0
260
+ 258,2,askacademia_train,0,110,233,0.9999999999999999
261
+ 259,2,askacademia_train,0,14,233,1.0
262
+ 260,2,askacademia_train,0,14,110,1.0
263
+ 261,2,askacademia_train,0,32,41,1.0
264
+ 262,2,askacademia_train,1,41,29,1.0
265
+ 263,2,askacademia_train,0,14,41,0.9999999999999999
266
+ 264,2,askacademia_train,0,5,41,0.9999999999999999
267
+ 265,2,askacademia_train,1,41,3,0.9999999999999999
268
+ 266,2,askacademia_train,1,32,14,1.0
269
+ 267,2,askacademia_train,1,32,5,1.0
270
+ 268,2,askacademia_train,1,29,14,1.0
271
+ 269,2,askacademia_train,0,5,29,1.0
272
+ 270,2,askacademia_train,0,5,10,0.9999999999999999
273
+ 271,2,askacademia_train,1,10,3,1.0
274
+ 272,2,askacademia_train,0,5,7,1.0
275
+ 273,2,askacademia_train,1,7,5,0.9999999999999999
276
+ 274,2,askacademia_train,0,3,7,1.0
277
+ 275,2,askacademia_train,1,8,5,1.0
278
+ 276,2,askacademia_train,0,5,8,1.0
279
+ 277,2,askacademia_train,0,3,8,1.0
280
+ 278,2,askacademia_train,1,5,3,1.0
281
+ 279,2,askacademia_train,1,267,89,1.0
282
+ 280,2,askacademia_train,0,21,267,1.0
283
+ 281,2,askacademia_train,1,96,89,1.0
284
+ 282,2,askacademia_train,0,28,96,1.0
285
+ 283,2,askacademia_train,1,96,21,1.0
286
+ 284,2,askacademia_train,0,21,89,0.9999999999999999
287
+ 285,2,askacademia_train,0,29,85,1.0
288
+ 286,2,askacademia_train,0,28,85,1.0
289
+ 287,2,askacademia_train,0,21,85,0.9999999999999999
290
+ 288,2,askacademia_train,0,6,85,0.9999999999999999
291
+ 289,2,askacademia_train,0,28,29,1.0
292
+ 290,2,askacademia_train,0,21,29,1.0
293
+ 291,2,askacademia_train,1,28,21,1.0
294
+ 292,2,askacademia_train,0,12,14,1.0
295
+ 293,2,askacademia_train,1,14,8,0.9999999999999999
296
+ 294,2,askacademia_train,0,9,14,1.0
297
+ 295,2,askacademia_train,1,14,6,0.9999999999999999
298
+ 296,2,askacademia_train,0,6,14,1.0
299
+ 297,2,askacademia_train,1,14,12,1.0
300
+ 298,2,askacademia_train,1,14,8,1.0
301
+ 299,2,askacademia_train,1,14,9,0.9999999999999999
302
+ 300,2,askacademia_train,1,14,6,0.9999999999999999
303
+ 301,2,askacademia_train,0,6,14,1.0
304
+ 302,2,askacademia_train,1,12,6,1.0
305
+ 303,2,askacademia_train,1,11,8,0.9999999999999999
306
+ 304,2,askacademia_train,0,8,11,1.0
307
+ 305,2,askacademia_train,0,9,11,1.0
308
+ 306,2,askacademia_train,1,11,6,1.0
309
+ 307,2,askacademia_train,1,11,6,1.0
310
+ 308,2,askacademia_train,0,6,8,1.0
311
+ 309,2,askacademia_train,0,6,8,1.0
312
+ 310,2,askacademia_train,1,9,8,1.0
313
+ 311,2,askacademia_train,1,8,6,1.0000000000000002
314
+ 312,2,askacademia_train,0,6,9,1.0
315
+ 313,2,askacademia_train,1,9,6,1.0
316
+ 314,2,askacademia_train,1,6,5,1.0
317
+ 315,2,askacademia_train,0,5,6,0.9999999999999999
318
+ 316,2,askacademia_train,0,12,50,0.9999999999999999
319
+ 317,2,askacademia_train,1,41,34,0.9999999999999999
320
+ 318,2,askacademia_train,0,13,41,0.9999999999999999
321
+ 319,2,askacademia_train,0,12,41,0.9999999999999999
322
+ 320,2,askacademia_train,0,7,41,0.9999999999999999
323
+ 321,2,askacademia_train,1,34,12,1.0
324
+ 322,2,askacademia_train,1,34,7,1.0
325
+ 323,2,askacademia_train,0,12,13,0.9999999999999999
326
+ 324,2,askacademia_train,0,9,13,1.0
327
+ 325,2,askacademia_train,0,7,13,1.0000000000000002
328
+ 326,2,askacademia_train,0,12,13,1.0
329
+ 327,2,askacademia_train,1,13,7,0.9999999999999999
330
+ 328,2,askacademia_train,1,13,12,0.9999999999999999
331
+ 329,2,askacademia_train,0,9,13,1.0
332
+ 330,2,askacademia_train,0,7,13,1.0
333
+ 331,2,askacademia_train,1,13,3,1.0
334
+ 332,2,askacademia_train,1,9,7,0.9999999999999999
335
+ 333,2,askacademia_train,1,7,6,1.0
336
+ 334,2,askacademia_train,1,7,3,1.0
337
+ 335,2,askacademia_train,0,6,7,1.0
338
+ 336,2,askacademia_train,1,6,3,1.0
339
+ 337,2,askacademia_train,0,3,7,1.0
340
+ 338,2,askacademia_train,0,129,171,1.0
341
+ 339,2,askacademia_train,0,32,171,1.0
342
+ 340,2,askacademia_train,1,131,129,1.0
343
+ 341,2,askacademia_train,1,131,40,1.0
344
+ 342,2,askacademia_train,0,32,131,1.0000000000000002
345
+ 343,2,askacademia_train,1,40,32,1.0
346
+ 344,2,askacademia_train,1,36,32,0.9999999999999999
347
+ 345,2,askacademia_train,0,7,12,1.0
348
+ 346,2,askacademia_train,0,5,12,1.0
349
+ 347,2,askacademia_train,0,3,12,1.0
350
+ 348,2,askacademia_train,0,4,12,1.0
351
+ 349,2,askacademia_train,0,5,7,1.0
352
+ 350,2,askacademia_train,0,3,7,1.0
353
+ 351,2,askacademia_train,1,7,5,1.0
354
+ 352,2,askacademia_train,1,7,3,1.0
355
+ 353,2,askacademia_train,0,4,7,1.0
356
+ 354,2,askacademia_train,0,3,7,0.9999999999999999
357
+ 355,2,askacademia_train,0,3,4,1.0
358
+ 356,2,askacademia_train,0,338,407,0.9999999999999999
359
+ 357,2,askacademia_train,1,407,227,1.0
360
+ 358,2,askacademia_train,1,407,109,1.0
361
+ 359,2,askacademia_train,1,407,71,1.0
362
+ 360,3,askacademia_train,0,66,407,1.0
363
+ 361,3,askacademia_train,0,26,407,0.9999999999999998
364
+ 362,3,askacademia_train,1,132,109,1.0
365
+ 363,3,askacademia_train,1,132,71,0.9999999999999999
366
+ 364,3,askacademia_train,0,66,132,1.0
367
+ 365,3,askacademia_train,1,132,31,1.0
368
+ 366,3,askacademia_train,1,132,26,0.9999999999999999
369
+ 367,3,askacademia_train,0,109,113,1.0
370
+ 368,3,askacademia_train,1,113,71,1.0
371
+ 369,3,askacademia_train,1,113,66,1.0
372
+ 370,3,askacademia_train,1,113,31,0.9999999999999999
373
+ 371,3,askacademia_train,1,113,26,0.9999999999999999
374
+ 372,3,askacademia_train,1,109,71,0.9999999999999999
375
+ 373,3,askacademia_train,0,71,107,0.9999999999999999
376
+ 374,3,askacademia_train,0,66,107,1.0
377
+ 375,3,askacademia_train,0,31,107,1.0
378
+ 376,3,askacademia_train,0,26,107,1.0
379
+ 377,3,askacademia_train,1,34,31,1.0000000000000002
380
+ 378,3,askacademia_train,0,26,31,0.9999999999999999
381
+ 379,3,askacademia_train,0,26,34,1.0
382
+ 380,3,askacademia_train,1,109,10,1.0
383
+ 381,3,askacademia_train,1,37,26,1.0
384
+ 382,3,askacademia_train,0,10,37,1.0
385
+ 383,3,askacademia_train,1,37,9,0.9999999999999999
386
+ 384,3,askacademia_train,0,6,37,1.0
387
+ 385,3,askacademia_train,1,30,26,1.0
388
+ 386,3,askacademia_train,1,30,25,1.0
389
+ 387,3,askacademia_train,0,10,30,0.9999999999999999
390
+ 388,3,askacademia_train,1,30,9,0.9999999999999999
391
+ 389,3,askacademia_train,1,30,6,0.9999999999999999
392
+ 390,3,askacademia_train,0,3,30,1.0
393
+ 391,3,askacademia_train,1,26,10,1.0
394
+ 392,3,askacademia_train,0,10,25,1.0
395
+ 393,3,askacademia_train,0,9,25,1.0
396
+ 394,3,askacademia_train,0,6,25,1.0
397
+ 395,3,askacademia_train,0,3,25,0.9999999999999999
398
+ 396,3,askacademia_train,0,10,17,0.9999999999999999
399
+ 397,3,askacademia_train,1,17,9,0.9999999999999999
400
+ 398,3,askacademia_train,0,6,17,0.9999999999999998
401
+ 399,3,askacademia_train,1,17,3,0.9999999999999999
402
+ 400,3,askacademia_train,1,9,6,1.0
403
+ 401,3,askacademia_train,1,186,182,0.9999999999999998
404
+ 402,3,askacademia_train,1,166,116,1.0
405
+ 403,3,askacademia_train,1,166,39,1.0
406
+ 404,3,askacademia_train,1,166,24,1.0
407
+ 405,3,askacademia_train,1,166,16,1.0
408
+ 406,3,askacademia_train,0,2,166,1.0
409
+ 407,3,askacademia_train,1,116,24,1.0
410
+ 408,3,askacademia_train,0,16,116,1.0
411
+ 409,3,askacademia_train,0,2,116,0.9999999999999999
412
+ 410,3,askacademia_train,0,24,39,1.0
413
+ 411,3,askacademia_train,1,39,16,1.0
414
+ 412,3,askacademia_train,1,39,2,1.0
415
+ 413,3,askacademia_train,0,16,20,1.0
416
+ 414,3,askacademia_train,1,20,7,1.0
417
+ 415,3,askacademia_train,1,20,6,0.9999999999999999
418
+ 416,3,askacademia_train,1,20,7,0.9999999999999999
419
+ 417,3,askacademia_train,1,20,2,1.0
420
+ 418,3,askacademia_train,0,2,20,1.0
421
+ 419,3,askacademia_train,1,20,2,1.0
422
+ 420,3,askacademia_train,1,10,7,1.0
423
+ 421,3,askacademia_train,0,6,10,1.0
424
+ 422,3,askacademia_train,0,7,10,1.0
425
+ 423,3,askacademia_train,1,10,5,1.0
426
+ 424,3,askacademia_train,1,10,2,1.0
427
+ 425,3,askacademia_train,1,10,2,1.0000000000000002
428
+ 426,3,askacademia_train,1,10,2,0.9999999999999999
429
+ 427,3,askacademia_train,0,2,7,0.9999999999999999
430
+ 428,3,askacademia_train,0,6,7,0.9999999999999999
431
+ 429,3,askacademia_train,0,2,6,1.0
432
+ 430,3,askacademia_train,1,6,2,1.0
433
+ 431,3,askacademia_train,1,6,2,0.9999999999999999
434
+ 432,3,askacademia_train,1,7,2,0.9999999999999999
435
+ 433,3,askacademia_train,0,2,7,0.9999999999999999
436
+ 434,3,askacademia_train,1,7,2,0.9999999999999999
437
+ 435,3,askacademia_train,1,5,2,1.0
438
+ 436,3,askacademia_train,1,5,2,1.0
439
+ 437,3,askacademia_train,1,5,2,0.9999999999999999
440
+ 438,3,askacademia_train,1,53,7,0.9999999999999999
441
+ 439,3,askacademia_train,1,53,7,1.0
442
+ 440,3,askacademia_train,1,53,5,0.9999999999999999
443
+ 441,3,askacademia_train,1,53,3,0.9999999999999999
444
+ 442,3,askacademia_train,0,3,53,0.9999999999999999
445
+ 443,3,askacademia_train,1,53,3,1.0
446
+ 444,3,askacademia_train,0,7,10,1.0
447
+ 445,3,askacademia_train,1,10,7,0.9999999999999999
448
+ 446,3,askacademia_train,0,5,10,0.9999999999999999
449
+ 447,3,askacademia_train,0,5,10,1.0
450
+ 448,3,askacademia_train,0,4,10,0.9999999999999999
451
+ 449,3,askacademia_train,1,10,3,1.0
452
+ 450,3,askacademia_train,0,3,10,1.0
453
+ 451,3,askacademia_train,0,3,10,1.0
454
+ 452,3,askacademia_train,1,10,3,0.9999999999999999
455
+ 453,3,askacademia_train,1,7,3,0.9999999999999998
456
+ 454,3,askacademia_train,1,5,3,0.9999999999999999
457
+ 455,3,askacademia_train,0,3,5,0.9999999999999999
458
+ 456,3,askacademia_train,1,5,4,0.9999999999999999
459
+ 457,3,askacademia_train,0,3,5,1.0
460
+ 458,3,askacademia_train,0,3,5,0.9999999999999999
461
+ 459,3,askacademia_train,0,3,5,1.0
462
+ 460,3,askacademia_train,0,3,4,0.9999999999999999
463
+ 461,3,askacademia_train,0,3,4,0.9999999999999999
464
+ 462,3,askacademia_train,0,3,4,0.9999999999999999
465
+ 463,3,askacademia_train,0,3,6,0.9999999999999999
466
+ 464,3,askacademia_train,0,3,6,1.0
467
+ 465,3,askacademia_train,1,6,3,1.0
468
+ 466,3,askacademia_train,1,6,3,1.0
469
+ 467,3,askacademia_train,1,6,2,1.0
470
+ 468,3,askacademia_train,0,2,3,1.0
471
+ 469,3,askacademia_train,1,3,2,0.9999999999999999
472
+ 470,3,askacademia_train,0,10,14,1.0
473
+ 471,3,askacademia_train,0,9,14,0.9999999999999999
474
+ 472,3,askacademia_train,0,9,14,0.9999999999999999
475
+ 473,3,askacademia_train,0,7,14,1.0
476
+ 474,3,askacademia_train,0,7,14,0.9999999999999999
477
+ 475,3,askacademia_train,0,7,9,0.9999999999999999
478
+ 476,3,askacademia_train,1,56,41,0.9999999999999999
479
+ 477,3,askacademia_train,0,27,56,1.0
480
+ 478,3,askacademia_train,0,8,56,1.0
481
+ 479,3,askacademia_train,1,56,4,1.0000000000000002
482
+ 480,4,askacademia_train,0,8,15,1.0
483
+ 481,4,askacademia_train,0,9,15,0.9999999999999999
484
+ 482,4,askacademia_train,0,7,15,1.0
485
+ 483,4,askacademia_train,0,7,15,1.0
486
+ 484,4,askacademia_train,0,6,15,1.0
487
+ 485,4,askacademia_train,1,15,4,1.0
488
+ 486,4,askacademia_train,1,15,2,1.0
489
+ 487,4,askacademia_train,1,9,8,1.0
490
+ 488,4,askacademia_train,0,6,9,1.0
491
+ 489,4,askacademia_train,1,9,4,1.0
492
+ 490,4,askacademia_train,0,6,7,0.9999999999999998
493
+ 491,4,askacademia_train,1,7,4,0.9999999999999999
494
+ 492,4,askacademia_train,0,2,7,1.0
495
+ 493,4,askacademia_train,1,7,6,1.0
496
+ 494,4,askacademia_train,0,4,7,0.9999999999999999
497
+ 495,4,askacademia_train,0,2,7,1.0
498
+ 496,4,askacademia_train,1,6,4,0.9999999999999999
499
+ 497,4,askacademia_train,1,82,25,1.0
500
+ 498,4,askacademia_train,0,25,75,1.0
501
+ 499,4,askacademia_train,1,75,9,1.0
502
+ 500,4,askacademia_train,1,75,9,1.0
503
+ 501,4,askacademia_train,1,47,36,0.9999999999999999
504
+ 502,4,askacademia_train,1,47,25,0.9999999999999999
505
+ 503,4,askacademia_train,1,47,11,1.0
506
+ 504,4,askacademia_train,0,11,47,1.0
507
+ 505,4,askacademia_train,1,47,9,1.0
508
+ 506,4,askacademia_train,0,9,47,0.9999999999999999
509
+ 507,4,askacademia_train,1,47,8,1.0000000000000002
510
+ 508,4,askacademia_train,0,25,36,1.0
511
+ 509,4,askacademia_train,1,36,9,1.0
512
+ 510,4,askacademia_train,0,9,36,0.9999999999999999
513
+ 511,4,askacademia_train,1,27,25,0.9999999999999999
514
+ 512,4,askacademia_train,0,11,27,0.9999999999999999
515
+ 513,4,askacademia_train,1,27,11,0.9999999999999999
516
+ 514,4,askacademia_train,1,27,9,1.0
517
+ 515,4,askacademia_train,0,9,27,1.0
518
+ 516,4,askacademia_train,1,27,8,0.9999999999999999
519
+ 517,4,askacademia_train,0,7,27,0.9999999999999999
520
+ 518,4,askacademia_train,0,5,27,1.0
521
+ 519,4,askacademia_train,1,14,11,0.9999999999999999
522
+ 520,4,askacademia_train,0,11,14,1.0
523
+ 521,4,askacademia_train,0,9,14,1.0000000000000002
524
+ 522,4,askacademia_train,0,9,14,1.0
525
+ 523,4,askacademia_train,1,14,8,1.0
526
+ 524,4,askacademia_train,0,7,14,1.0000000000000002
527
+ 525,4,askacademia_train,1,14,5,0.9999999999999999
528
+ 526,4,askacademia_train,1,14,3,1.0
529
+ 527,4,askacademia_train,0,3,14,1.0
530
+ 528,4,askacademia_train,0,2,14,1.0
531
+ 529,4,askacademia_train,0,9,11,0.9999999999999999
532
+ 530,4,askacademia_train,1,11,9,0.9999999999999999
533
+ 531,4,askacademia_train,1,11,8,1.0
534
+ 532,4,askacademia_train,0,9,11,1.0
535
+ 533,4,askacademia_train,1,11,9,1.0
536
+ 534,4,askacademia_train,0,8,11,1.0
537
+ 535,4,askacademia_train,1,33,25,1.0
538
+ 536,4,askacademia_train,1,33,21,1.0
539
+ 537,4,askacademia_train,0,15,33,0.9999999999999999
540
+ 538,4,askacademia_train,0,3,33,1.0
541
+ 539,4,askacademia_train,1,22,21,0.9999999999999999
542
+ 540,4,askacademia_train,1,22,15,1.0
543
+ 541,4,askacademia_train,0,3,22,0.9999999999999999
544
+ 542,4,askacademia_train,1,21,15,0.9999999999999999
545
+ 543,4,askacademia_train,1,21,3,1.0
546
+ 544,4,askacademia_train,0,3,15,1.0
547
+ 545,4,askacademia_train,0,3,4,1.0000000000000002
548
+ 546,4,askacademia_train,1,4,3,0.9999999999999999
549
+ 547,4,askacademia_train,1,4,3,1.0
550
+ 548,4,askacademia_train,1,4,3,0.9999999999999999
551
+ 549,4,askacademia_train,1,4,3,0.9999999999999999
552
+ 550,4,askacademia_train,0,389,525,0.9999999999999999
553
+ 551,4,askacademia_train,0,121,158,1.0
554
+ 552,4,askacademia_train,1,158,108,1.0
555
+ 553,4,askacademia_train,1,158,112,1.0
556
+ 554,4,askacademia_train,0,96,158,1.0
557
+ 555,4,askacademia_train,1,158,71,1.0
558
+ 556,4,askacademia_train,1,158,61,1.0
559
+ 557,4,askacademia_train,0,39,158,1.0
560
+ 558,4,askacademia_train,1,158,41,1.0
561
+ 559,4,askacademia_train,1,158,24,0.9999999999999999
562
+ 560,4,askacademia_train,0,22,158,1.0
563
+ 561,4,askacademia_train,0,17,158,0.9999999999999999
564
+ 562,4,askacademia_train,1,121,108,1.0
565
+ 563,4,askacademia_train,1,121,71,1.0
566
+ 564,4,askacademia_train,1,121,61,0.9999999999999999
567
+ 565,4,askacademia_train,0,22,121,1.0
568
+ 566,4,askacademia_train,1,112,108,1.0
569
+ 567,4,askacademia_train,0,71,112,1.0
570
+ 568,4,askacademia_train,0,61,112,0.9999999999999999
571
+ 569,4,askacademia_train,1,112,22,1.0
572
+ 570,4,askacademia_train,0,71,96,1.0
573
+ 571,4,askacademia_train,0,61,96,1.0
574
+ 572,4,askacademia_train,0,41,96,1.0
575
+ 573,4,askacademia_train,1,96,24,0.9999999999999999
576
+ 574,4,askacademia_train,0,22,96,1.0
577
+ 575,4,askacademia_train,0,24,39,1.0000000000000002
578
+ 576,4,askacademia_train,1,39,22,0.9999999999999999
579
+ 577,4,askacademia_train,0,22,41,1.0
580
+ 578,4,askacademia_train,1,24,22,1.0
581
+ 579,4,askacademia_train,0,17,19,1.0
582
+ 580,4,askacademia_train,0,16,19,1.0
583
+ 581,4,askacademia_train,1,250,4,1.0
584
+ 582,4,askacademia_train,1,250,2,1.0
585
+ 583,4,askacademia_train,0,44,58,1.0
586
+ 584,4,askacademia_train,1,58,4,1.0
587
+ 585,4,askacademia_train,0,2,58,0.9999999999999999
588
+ 586,4,askacademia_train,1,44,4,1.0
589
+ 587,4,askacademia_train,1,44,2,1.0
590
+ 588,4,askacademia_train,1,33,4,1.0
591
+ 589,4,askacademia_train,1,33,2,0.9999999999999998
592
+ 590,4,askacademia_train,0,2,33,1.0
593
+ 591,4,askacademia_train,1,15,4,0.9999999999999999
594
+ 592,4,askacademia_train,0,2,15,1.0
595
+ 593,4,askacademia_train,0,2,15,0.9999999999999999
596
+ 594,4,askacademia_train,0,4,11,0.9999999999999999
597
+ 595,4,askacademia_train,1,11,2,1.0
598
+ 596,4,askacademia_train,0,2,11,1.0
599
+ 597,4,askacademia_train,0,4,9,1.0
600
+ 598,4,askacademia_train,1,9,2,1.0
601
+ 599,4,askacademia_train,1,9,2,1.0
outputs/source_claim_audit.csv ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ claim,source,literal_scope,audit
2
+ 1,Theorem 5.1,"partial participation; E,R,S,kappa^2,zeta_g^2 terms",formula ledger + actual FedDPO
3
+ 2,Corollary 5.2,full participation removes partial-participation amplification; residual averaged-client variance remains,separate corollary ledger
4
+ 3,Theorem 5.4,eta C_q q_max additive penalty under Assumption 5.3,formula ledger + stale FedDPO
5
+ 4,Theorem 5.5,"DPO-like objective family lower bound, not every conceivable objective",finite-population construction ledger
6
+ 5,Theorem 6.1,symmetric doubly stochastic mixing and theorem assumptions,actual DecDPO on four graphs
7
+ 6,"Section 7, Figures 1-5","SHP uses N=5 disjoint clients, 120 pairs each",600 pinned SHP rows and four ablation families
outputs/theorem_5_1_partial_bound.csv ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ E,S,R,eta,initialization_term,sampling_1_over_S_term,heterogeneity_term,local_variance_1_over_S_term,theorem_5_1_bound
2
+ 1,1,40,0.09486832980505137,0.36532064071556886,0.0011957328525646549,2.6675993642301955e-07,9.074974289267087e-06,0.36652571530235917
3
+ 1,1,80,0.06708203932499368,0.25832070235739313,0.0008455108085360017,1.3337996821150972e-07,4.537487144633543e-06,0.259170884033042
4
+ 1,1,160,0.04743416490252569,0.18266032035778443,0.0005978664262823274,6.668998410575489e-08,2.2687435723167718e-06,0.18326052221762318
5
+ 1,1,320,0.03354101966249684,0.12916035117869656,0.00042275540426800083,3.334499205287743e-08,1.1343717861583857e-06,0.12958427429974279
6
+ 1,3,40,0.09486832980505137,0.36532064071556886,0.00039857761752155164,2.6675993642301955e-07,3.0249914297556957e-06,0.36572251008445655
7
+ 1,3,80,0.06708203932499368,0.25832070235739313,0.00028183693617866724,1.3337996821150972e-07,1.5124957148778476e-06,0.25860418516925493
8
+ 1,3,160,0.04743416490252569,0.18266032035778443,0.00019928880876077582,6.668998410575489e-08,7.562478574389239e-07,0.18286043210438677
9
+ 1,3,320,0.03354101966249684,0.12916035117869656,0.00014091846808933362,3.334499205287743e-08,3.781239287194619e-07,0.12930168111570667
10
+ 1,5,40,0.09486832980505137,0.36532064071556886,0.00023914657051293098,2.6675993642301955e-07,1.8149948578534173e-06,0.36556186904087606
11
+ 1,5,80,0.06708203932499368,0.25832070235739313,0.00016910216170720033,1.3337996821150972e-07,9.074974289267086e-07,0.25849084539649747
12
+ 1,5,160,0.04743416490252569,0.18266032035778443,0.00011957328525646549,6.668998410575489e-08,4.5374871446335433e-07,0.18278041408173948
13
+ 1,5,320,0.03354101966249684,0.12916035117869656,8.455108085360017e-05,3.334499205287743e-08,2.2687435723167714e-07,0.12924516247889944
14
+ 3,1,40,0.09486832980505137,0.12177354690518961,0.0011957328525646549,8.002798092690587e-07,8.167476860340379e-05,0.12305175480616694
15
+ 3,1,80,0.06708203932499368,0.08610690078579769,0.0008455108085360017,4.0013990463452917e-07,4.0837384301701886e-05,0.08699364911854003
16
+ 3,1,160,0.04743416490252569,0.06088677345259481,0.0005978664262823274,2.0006995231726466e-07,2.0418692150850947e-05,0.061505258640980304
17
+ 3,1,320,0.03354101966249684,0.043053450392898845,0.00042275540426800083,1.0003497615863229e-07,1.0209346075425472e-05,0.04348651517821842
18
+ 3,3,40,0.09486832980505137,0.12177354690518961,0.00039857761752155164,8.002798092690587e-07,2.722492286780126e-05,0.12220014972538823
19
+ 3,3,80,0.06708203932499368,0.08610690078579769,0.00028183693617866724,4.0013990463452917e-07,1.3612461433900629e-05,0.0864027503233149
20
+ 3,3,160,0.04743416490252569,0.06088677345259481,0.00019928880876077582,2.0006995231726466e-07,6.806230716950315e-06,0.06109306856202485
21
+ 3,3,320,0.03354101966249684,0.043053450392898845,0.00014091846808933362,1.0003497615863229e-07,3.403115358475157e-06,0.04319787201132281
22
+ 3,5,40,0.09486832980505137,0.12177354690518961,0.00023914657051293098,8.002798092690587e-07,1.6334953720680758e-05,0.12202982870923249
23
+ 3,5,80,0.06708203932499368,0.08610690078579769,0.00016910216170720033,4.0013990463452917e-07,8.167476860340377e-06,0.08628457056426987
24
+ 3,5,160,0.04743416490252569,0.06088677345259481,0.00011957328525646549,2.0006995231726466e-07,4.0837384301701895e-06,0.06101063054623376
25
+ 3,5,320,0.03354101966249684,0.043053450392898845,8.455108085360017e-05,1.0003497615863229e-07,2.0418692150850943e-06,0.04314014337794368
26
+ 6,1,40,0.09486832980505137,0.06088677345259481,0.0011957328525646549,1.6005596185381173e-06,0.00032669907441361515,0.06241080593919161
27
+ 6,1,80,0.06708203932499368,0.043053450392898845,0.0008455108085360017,8.002798092690583e-07,0.00016334953720680755,0.04406311101845092
28
+ 6,1,160,0.04743416490252569,0.030443386726297404,0.0005978664262823274,4.001399046345293e-07,8.167476860340379e-05,0.03112332806108777
29
+ 6,1,320,0.03354101966249684,0.021526725196449423,0.00042275540426800083,2.0006995231726458e-07,4.0837384301701886e-05,0.021990518054971445
30
+ 6,3,40,0.09486832980505137,0.06088677345259481,0.00039857761752155164,1.6005596185381173e-06,0.00010889969147120504,0.0613958513212061
31
+ 6,3,80,0.06708203932499368,0.043053450392898845,0.00028183693617866724,8.002798092690583e-07,5.4449845735602515e-05,0.04339053745462239
32
+ 6,3,160,0.04743416490252569,0.030443386726297404,0.00019928880876077582,4.001399046345293e-07,2.722492286780126e-05,0.030670300597830616
33
+ 6,3,320,0.03354101966249684,0.021526725196449423,0.00014091846808933362,2.0006995231726458e-07,1.3612461433900629e-05,0.021681456195924976
34
+ 6,5,40,0.09486832980505137,0.06088677345259481,0.00023914657051293098,1.6005596185381173e-06,6.533981488272303e-05,0.061192860397608996
35
+ 6,5,80,0.06708203932499368,0.043053450392898845,0.00016910216170720033,8.002798092690583e-07,3.266990744136151e-05,0.04325602274185668
36
+ 6,5,160,0.04743416490252569,0.030443386726297404,0.00011957328525646549,4.001399046345293e-07,1.6334953720680758e-05,0.030579695105179185
37
+ 6,5,320,0.03354101966249684,0.021526725196449423,8.455108085360017e-05,2.0006995231726458e-07,8.167476860340377e-06,0.02161964382411568
outputs/theorem_5_4_staleness.csv ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ qmax,eta,E,C_q,linear_staleness_penalty,C_q_qmax_without_outer_eta
2
+ 0,0.01,3,1.2163716439700656e-05,0.0,0.0
3
+ 0,0.02,3,4.8654865758802626e-05,0.0,0.0
4
+ 0,0.04,3,0.0001946194630352105,0.0,0.0
5
+ 1,0.01,3,1.2163716439700656e-05,1.2163716439700657e-07,1.2163716439700656e-05
6
+ 1,0.02,3,4.8654865758802626e-05,9.730973151760526e-07,4.8654865758802626e-05
7
+ 1,0.04,3,0.0001946194630352105,7.78477852140842e-06,0.0001946194630352105
8
+ 2,0.01,3,1.2163716439700656e-05,2.4327432879401314e-07,2.4327432879401313e-05
9
+ 2,0.02,3,4.8654865758802626e-05,1.946194630352105e-06,9.730973151760525e-05
10
+ 2,0.04,3,0.0001946194630352105,1.556955704281684e-05,0.000389238926070421
11
+ 5,0.01,3,1.2163716439700656e-05,6.081858219850329e-07,6.081858219850328e-05
12
+ 5,0.02,3,4.8654865758802626e-05,4.865486575880263e-06,0.00024327432879401312
13
+ 5,0.04,3,0.0001946194630352105,3.8923892607042106e-05,0.0009730973151760525
14
+ 10,0.01,3,1.2163716439700656e-05,1.2163716439700658e-06,0.00012163716439700656
15
+ 10,0.02,3,4.8654865758802626e-05,9.730973151760527e-06,0.00048654865758802625
16
+ 10,0.04,3,0.0001946194630352105,7.784778521408421e-05,0.001946194630352105
outputs/theorem_5_5_lower_bound.csv ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ N,E,S,kappa_squared,exact_without_replacement_sampling_variance,registered_E_kappa_squared_over_S,full_participation_sampling_variance
2
+ 20,1,1,0.001157812224058244,0.001157812224058244,0.001157812224058244,False
3
+ 20,1,2,0.001157812224058244,0.0005484373692907471,0.000578906112029122,False
4
+ 20,1,5,0.001157812224058244,0.00018281245643024904,0.0002315624448116488,False
5
+ 20,1,10,0.001157812224058244,6.093748547674968e-05,0.0001157812224058244,False
6
+ 20,1,20,0.001157812224058244,0.0,5.78906112029122e-05,True
7
+ 20,2,1,0.001157812224058244,0.001157812224058244,0.002315624448116488,False
8
+ 20,2,2,0.001157812224058244,0.0005484373692907471,0.001157812224058244,False
9
+ 20,2,5,0.001157812224058244,0.00018281245643024904,0.0004631248896232976,False
10
+ 20,2,10,0.001157812224058244,6.093748547674968e-05,0.0002315624448116488,False
11
+ 20,2,20,0.001157812224058244,0.0,0.0001157812224058244,True
12
+ 20,4,1,0.001157812224058244,0.001157812224058244,0.004631248896232976,False
13
+ 20,4,2,0.001157812224058244,0.0005484373692907471,0.002315624448116488,False
14
+ 20,4,5,0.001157812224058244,0.00018281245643024904,0.0009262497792465952,False
15
+ 20,4,10,0.001157812224058244,6.093748547674968e-05,0.0004631248896232976,False
16
+ 20,4,20,0.001157812224058244,0.0,0.0002315624448116488,True
17
+ 20,8,1,0.001157812224058244,0.001157812224058244,0.009262497792465952,False
18
+ 20,8,2,0.001157812224058244,0.0005484373692907471,0.004631248896232976,False
19
+ 20,8,5,0.001157812224058244,0.00018281245643024904,0.0018524995584931904,False
20
+ 20,8,10,0.001157812224058244,6.093748547674968e-05,0.0009262497792465952,False
21
+ 20,8,20,0.001157812224058244,0.0,0.0004631248896232976,True
outputs_distilgpt2_results.json ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "init": {
3
+ "loss": 0.6931471824645996,
4
+ "acc": 0.0,
5
+ "clients": {
6
+ "askacademia_train": 90,
7
+ "askanthropology_train": 90,
8
+ "askbaking_train": 90,
9
+ "askcarguys_train": 90,
10
+ "askculinary_train": 90
11
+ }
12
+ },
13
+ "claim2_participation": {
14
+ "rows": [
15
+ {
16
+ "S": 1,
17
+ "param_variance": 5.022761342843296e-06,
18
+ "fpc": 1.0,
19
+ "ratio": 5.022761342843296e-06,
20
+ "loss_mean": 0.633784274260203,
21
+ "loss_sd": 0.001334814799821921
22
+ },
23
+ {
24
+ "S": 2,
25
+ "param_variance": 2.5572878712409874e-06,
26
+ "fpc": 0.375,
27
+ "ratio": 6.8194343233092996e-06,
28
+ "loss_mean": 0.6304384350776672,
29
+ "loss_sd": 0.0016579824752723095
30
+ },
31
+ {
32
+ "S": 3,
33
+ "param_variance": 9.81718699222256e-07,
34
+ "fpc": 0.16667,
35
+ "ratio": 5.890312195333536e-06,
36
+ "loss_mean": 0.629636463854048,
37
+ "loss_sd": 0.0008546987350598048
38
+ },
39
+ {
40
+ "S": 5,
41
+ "param_variance": 1.2536748306146706e-09,
42
+ "fpc": 0.0,
43
+ "ratio": null,
44
+ "loss_mean": 0.6318015999264187,
45
+ "loss_sd": 5.356841499450332e-07
46
+ }
47
+ ]
48
+ },
49
+ "claim3_staleness": {
50
+ "rows": [
51
+ {
52
+ "q_max": 0,
53
+ "loss_mean": 0.6318019688129426,
54
+ "loss_sd": 1.9669532774768683e-07
55
+ },
56
+ {
57
+ "q_max": 2,
58
+ "loss_mean": 0.6321120341618855,
59
+ "loss_sd": 0.0015916506449381584
60
+ },
61
+ {
62
+ "q_max": 5,
63
+ "loss_mean": 0.631365849574407,
64
+ "loss_sd": 0.0021995683511098485
65
+ }
66
+ ],
67
+ "monotone": false
68
+ },
69
+ "claim5_topology": {
70
+ "rows": [
71
+ {
72
+ "topology": "ring",
73
+ "rho": 0.5393,
74
+ "one_over_1_minus_rho2": 1.41,
75
+ "consensus_error": 0.0005428119329735637,
76
+ "loss": 0.6320640007654826,
77
+ "acc": 0.9166666666666666
78
+ },
79
+ {
80
+ "topology": "star",
81
+ "rho": 0.8,
82
+ "one_over_1_minus_rho2": 2.778,
83
+ "consensus_error": 0.0015359229873865843,
84
+ "loss": 0.632928442955017,
85
+ "acc": 0.9166666666666666
86
+ },
87
+ {
88
+ "topology": "path",
89
+ "rho": 0.8727,
90
+ "one_over_1_minus_rho2": 4.194,
91
+ "consensus_error": 0.0015837237006053329,
92
+ "loss": 0.6329204241434733,
93
+ "acc": 0.9166666666666666
94
+ },
95
+ {
96
+ "topology": "complete",
97
+ "rho": 0.0,
98
+ "one_over_1_minus_rho2": 1.0,
99
+ "consensus_error": 4.8330199206247926e-05,
100
+ "loss": 0.6318154136339823,
101
+ "acc": 0.9166666666666666
102
+ }
103
+ ],
104
+ "n_in_fit": 4,
105
+ "loglog_slope": 2.2349,
106
+ "r2": 0.7805,
107
+ "spearman_positive": true
108
+ }
109
+ }
packaged_replay/SHA256SUMS.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "corollary_5_2_full_participation.csv": "ff2d4278b79e9fdf103a48f907d694a11e39eda0369daf6076f0e269da141b86",
3
+ "dec_dpo_topology.csv": "691bdcc6ae25aa25d6598dbf87ad060255e9a0f802e03341da6a30eeb362b2ba",
4
+ "distributed_dpo_audit.png": "c08e9e3b7baf8e05e4a4190efd714a72d9122fd3cd4ecd645d640a9aea6ca1e4",
5
+ "fed_dpo_shp_ablations.csv": "31bfaabea77d3022b17e469b7b9f546a2fec8c40431b8177d1cf077ac06a9718",
6
+ "results.json": "bb7e2073a3d41e3c2fdb957ab423ee83a367d3fe1badcf5fbcb98e516a9b707b",
7
+ "shp_inventory.csv": "6460bb569c5ac46a0509503168290bb4b2bb03a5e6f566f282d0fe5a183e7732",
8
+ "source_claim_audit.csv": "c8464ba0cf666528438250e6fd581271d770a4c136c6a55377ca3361fd42b8e4",
9
+ "theorem_5_1_partial_bound.csv": "9accf57701e23d9e172978f895d6faf38f2a12f150d968d2ead593d3304fb896",
10
+ "theorem_5_4_staleness.csv": "be181a404639b2722e3a7905df2d4faf8bfb8e562ee42277b8e32652b724fdc1",
11
+ "theorem_5_5_lower_bound.csv": "8fc7b9c6775c5d7846a474089c727d0ae8a1de3bcf5db1abf76914e74878ad6d"
12
+ }
packaged_replay/corollary_5_2_full_participation.csv ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ E,N,R,eta,initialization_term,partial_participation_variance_amplification,client_average_variance,heterogeneity_term,corollary_5_2_bound
2
+ 1,5,40,0.09486832980505137,0.36532064071556886,0.0,5.9786642628232746e-05,1.3337996821150978e-07,0.3653805607381653
3
+ 1,5,80,0.06708203932499368,0.25832070235739313,0.0,4.227554042680008e-05,6.668998410575486e-08,0.258363044587804
4
+ 1,5,160,0.04743416490252569,0.18266032035778443,0.0,2.9893321314116373e-05,3.3344992052877444e-08,0.1826902470240906
5
+ 1,5,320,0.03354101966249684,0.12916035117869656,0.0,2.113777021340004e-05,1.6672496026438715e-08,0.12918150562140598
6
+ 3,5,40,0.09486832980505137,0.12177354690518961,0.0,5.9786642628232746e-05,4.001399046345293e-07,0.12183373368772249
7
+ 3,5,80,0.06708203932499368,0.08610690078579769,0.0,4.227554042680008e-05,2.0006995231726458e-07,0.0861493763961768
8
+ 3,5,160,0.04743416490252569,0.06088677345259481,0.0,2.9893321314116373e-05,1.0003497615863233e-07,0.06091676680888508
9
+ 3,5,320,0.03354101966249684,0.043053450392898845,0.0,2.113777021340004e-05,5.0017488079316146e-08,0.043074638180600325
10
+ 6,5,40,0.09486832980505137,0.06088677345259481,0.0,5.9786642628232746e-05,8.002798092690587e-07,0.06094736037503231
11
+ 6,5,80,0.06708203932499368,0.043053450392898845,0.0,4.227554042680008e-05,4.0013990463452917e-07,0.04309612607323028
12
+ 6,5,160,0.04743416490252569,0.030443386726297404,0.0,2.9893321314116373e-05,2.0006995231726466e-07,0.030473480117563838
13
+ 6,5,320,0.03354101966249684,0.021526725196449423,0.0,2.113777021340004e-05,1.0003497615863229e-07,0.021547963001638984
packaged_replay/dec_dpo_topology.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ topology,replicates,rho,one_over_one_minus_rho_squared,mean_tail_consensus_error,mean_tail_gradient_norm_sq,mean_final_loss
2
+ path,8,0.872677996249965,4.194048299802485,0.0005454370424672539,0.0005829917140026842,0.6837910799762497
3
+ ring,8,0.5393446629166316,1.4102237436136194,3.761684387776997e-05,0.0005826007264608975,0.6837903595432446
4
+ star,8,0.8,2.7777777777777786,0.00041163500941361045,0.000582458508441908,0.683671120904709
5
+ complete,8,8.284195946896153e-17,1.0,9.32317306912503e-34,0.0005820751105032884,0.6834946549569718
packaged_replay/distributed_dpo_audit.png ADDED

Git LFS Details

  • SHA256: c08e9e3b7baf8e05e4a4190efd714a72d9122fd3cd4ecd645d640a9aea6ca1e4
  • Pointer size: 131 Bytes
  • Size of remote file: 151 kB
packaged_replay/fed_dpo_shp_ablations.csv ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ family,local_steps_E,sampled_clients_S,qmax,replicates,mean_final_loss,mean_loss_reduction,mean_tail_gradient_norm_sq,std_tail_gradient_norm_sq
2
+ local_steps,1,3,0,8,0.6854464561081451,0.007700724451800131,0.0005880749016315657,1.0155468747282728e-06
3
+ local_steps,3,3,0,8,0.6713684502828248,0.021778730277120517,0.0005443930037768237,2.4343579389877103e-06
4
+ local_steps,6,3,0,8,0.6516766529857532,0.0414705275741922,0.0004827668972471771,2.1931322746900754e-06
5
+ participation,3,1,0,8,0.6713264270553448,0.02182075350460043,0.0005435496190031553,4.033222976843732e-06
6
+ participation,3,3,0,8,0.6711281026192374,0.02201907794070794,0.0005434856562567469,2.109517284475393e-06
7
+ participation,3,5,0,8,0.6710800062252151,0.02206717433473021,0.0005436639929552561,1.0201377991962554e-06
8
+ staleness,3,3,0,8,0.6710920419315259,0.022055138628419332,0.000543698019818161,2.69970703565243e-06
9
+ staleness,3,3,2,8,0.6816140324392188,0.011533148120726491,0.0005762081162556293,1.0118713023835438e-06
10
+ staleness,3,3,5,8,0.6863272721344135,0.006819908425531804,0.0005908721885661179,1.4644118928873132e-06
packaged_replay/results.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "all_gates_pass": true,
3
+ "arxiv": "2605.20696v1",
4
+ "gates": {
5
+ "all_outputs_finite": true,
6
+ "claim1_actual_feddpo_executed": true,
7
+ "claim1_inverse_S_terms_exact": true,
8
+ "claim1_partial_bound_multiple_E_S_R": true,
9
+ "claim2_full_participation_amplification_removed": true,
10
+ "claim2_residual_client_average_variance_preserved": true,
11
+ "claim3_stale_algorithm_executed": true,
12
+ "claim3_staleness_formula_exact": true,
13
+ "claim3_staleness_zero_at_q_zero": true,
14
+ "claim4_full_participation_sampling_variance_zero": true,
15
+ "claim4_lower_bound_scaling_exact": true,
16
+ "claim5_connectivity_factor_varies": true,
17
+ "claim5_decdpo_executed": true,
18
+ "claim5_four_symmetric_graphs": true,
19
+ "claim6_all_four_ablation_families": true,
20
+ "claim6_exact_N5_times_120_SHP_rows": true,
21
+ "destructive_identical_clients_reduce_participation_effect": true,
22
+ "destructive_label_corruption_worsens_clean_objective": true,
23
+ "destructive_no_mixing_increases_consensus_error": true,
24
+ "source_pins_verified": true
25
+ },
26
+ "headline": {
27
+ "clean_final_loss": 0.670980521644771,
28
+ "clients": 5,
29
+ "decdpo_algorithm_runs": 32,
30
+ "decdpo_topology_cells": 4,
31
+ "fed_ablation_cells": 9,
32
+ "fed_ablation_ranges": {
33
+ "local_steps": 0.0001053080043843886,
34
+ "participation": 1.7833669850922645e-07,
35
+ "staleness": 4.7174168747956885e-05
36
+ },
37
+ "fed_algorithm_runs": 72,
38
+ "identical_client_S1_to_S5_ratio": 1.0004384715044146,
39
+ "kappa_squared": 0.001157812224058244,
40
+ "label_corrupted_final_loss": 0.690625282427891,
41
+ "lower_bound_cells": 20,
42
+ "no_mix_to_mix_consensus_ratio": 575.6464809616402,
43
+ "pairs_per_client": 120,
44
+ "shp_pairs": 600,
45
+ "smoothness_L_bound": 0.04000000000000001,
46
+ "staleness_formula_cells": 15,
47
+ "theorem_5_1_formula_cells": 36,
48
+ "topology_consensus_range": 0.0005454370424672539,
49
+ "topology_factor_consensus_spearman": 1.0,
50
+ "zeta_squared": 0.039387909241610605
51
+ },
52
+ "openreview_id": "ljNZyrAlaa",
53
+ "paper": "Distributed Direct Preference Optimization",
54
+ "scope": "finite log-linear SHP mechanism audit plus exact source-formula reconstruction",
55
+ "seed": 20260721
56
+ }
packaged_replay/shp_inventory.csv ADDED
@@ -0,0 +1,601 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ row,client,domain,label,score_A,score_B,feature_norm
2
+ 0,0,askacademia_train,0,52,54,1.0
3
+ 1,0,askacademia_train,0,5,17,1.0
4
+ 2,0,askacademia_train,0,5,7,1.0
5
+ 3,0,askacademia_train,1,7,5,0.9999999999999999
6
+ 4,0,askacademia_train,0,6,7,1.0
7
+ 5,0,askacademia_train,1,7,5,1.0
8
+ 6,0,askacademia_train,1,6,5,1.0
9
+ 7,0,askacademia_train,0,5,7,1.0
10
+ 8,0,askacademia_train,1,7,6,0.9999999999999999
11
+ 9,0,askacademia_train,1,7,4,1.0
12
+ 10,0,askacademia_train,1,7,2,0.9999999999999999
13
+ 11,0,askacademia_train,0,2,7,1.0
14
+ 12,0,askacademia_train,1,6,5,0.9999999999999999
15
+ 13,0,askacademia_train,1,4,2,0.9999999999999999
16
+ 14,0,askacademia_train,1,4,3,0.9999999999999999
17
+ 15,0,askacademia_train,0,2,4,1.0
18
+ 16,0,askacademia_train,1,4,2,1.0
19
+ 17,0,askacademia_train,1,4,2,1.0
20
+ 18,0,askacademia_train,1,4,2,1.0
21
+ 19,0,askacademia_train,1,4,2,0.9999999999999999
22
+ 20,0,askacademia_train,0,2,4,1.0
23
+ 21,0,askacademia_train,1,3,2,1.0
24
+ 22,0,askacademia_train,0,3,4,1.0
25
+ 23,0,askacademia_train,1,4,3,1.0
26
+ 24,0,askacademia_train,0,3,4,0.9999999999999999
27
+ 25,0,askacademia_train,1,4,3,1.0
28
+ 26,0,askacademia_train,0,2,4,1.0
29
+ 27,0,askacademia_train,0,2,4,1.0000000000000002
30
+ 28,0,askacademia_train,1,4,2,1.0
31
+ 29,0,askacademia_train,0,3,4,0.9999999999999999
32
+ 30,0,askacademia_train,1,4,3,1.0
33
+ 31,0,askacademia_train,0,3,4,1.0
34
+ 32,0,askacademia_train,0,3,4,0.9999999999999999
35
+ 33,0,askacademia_train,0,2,4,0.9999999999999999
36
+ 34,0,askacademia_train,1,4,2,1.0
37
+ 35,0,askacademia_train,1,4,2,1.0
38
+ 36,0,askacademia_train,1,4,3,0.9999999999999999
39
+ 37,0,askacademia_train,0,3,4,1.0
40
+ 38,0,askacademia_train,0,3,4,0.9999999999999999
41
+ 39,0,askacademia_train,1,4,3,0.9999999999999999
42
+ 40,0,askacademia_train,0,2,4,1.0
43
+ 41,0,askacademia_train,0,2,4,0.9999999999999999
44
+ 42,0,askacademia_train,1,4,2,1.0
45
+ 43,0,askacademia_train,1,3,2,1.0
46
+ 44,0,askacademia_train,1,3,2,1.0
47
+ 45,0,askacademia_train,1,3,2,0.9999999999999999
48
+ 46,0,askacademia_train,1,3,2,0.9999999999999998
49
+ 47,0,askacademia_train,1,3,2,1.0
50
+ 48,0,askacademia_train,1,3,2,1.0
51
+ 49,0,askacademia_train,1,3,2,1.0
52
+ 50,0,askacademia_train,0,2,3,1.0
53
+ 51,0,askacademia_train,1,3,2,1.0
54
+ 52,0,askacademia_train,1,3,2,0.9999999999999999
55
+ 53,0,askacademia_train,0,2,3,1.0
56
+ 54,0,askacademia_train,1,3,2,1.0
57
+ 55,0,askacademia_train,0,2,3,1.0
58
+ 56,0,askacademia_train,1,3,2,0.9999999999999999
59
+ 57,0,askacademia_train,0,2,3,1.0
60
+ 58,0,askacademia_train,0,157,246,1.0
61
+ 59,0,askacademia_train,0,157,209,1.0000000000000002
62
+ 60,0,askacademia_train,0,50,209,0.9999999999999999
63
+ 61,0,askacademia_train,1,209,8,1.0
64
+ 62,0,askacademia_train,1,68,50,0.9999999999999999
65
+ 63,0,askacademia_train,0,14,68,1.0
66
+ 64,0,askacademia_train,0,8,68,1.0
67
+ 65,0,askacademia_train,1,68,2,1.0
68
+ 66,0,askacademia_train,1,50,8,0.9999999999999999
69
+ 67,0,askacademia_train,0,22,48,1.0
70
+ 68,0,askacademia_train,0,18,48,1.0
71
+ 69,0,askacademia_train,0,19,48,1.0
72
+ 70,0,askacademia_train,1,48,14,1.0
73
+ 71,0,askacademia_train,0,8,48,1.0
74
+ 72,0,askacademia_train,0,4,48,0.9999999999999999
75
+ 73,0,askacademia_train,1,48,2,1.0
76
+ 74,0,askacademia_train,1,22,18,1.0
77
+ 75,0,askacademia_train,0,14,22,0.9999999999999999
78
+ 76,0,askacademia_train,1,22,8,1.0
79
+ 77,0,askacademia_train,1,22,4,0.9999999999999999
80
+ 78,0,askacademia_train,1,22,2,1.0
81
+ 79,0,askacademia_train,1,19,18,1.0
82
+ 80,0,askacademia_train,0,14,18,1.0
83
+ 81,0,askacademia_train,1,18,8,1.0
84
+ 82,0,askacademia_train,0,4,18,1.0
85
+ 83,0,askacademia_train,1,18,2,0.9999999999999999
86
+ 84,0,askacademia_train,1,19,14,1.0
87
+ 85,0,askacademia_train,0,8,19,1.0
88
+ 86,0,askacademia_train,0,4,19,1.0000000000000002
89
+ 87,0,askacademia_train,1,19,2,0.9999999999999999
90
+ 88,0,askacademia_train,1,16,14,1.0
91
+ 89,0,askacademia_train,1,16,8,1.0
92
+ 90,0,askacademia_train,1,16,4,0.9999999999999999
93
+ 91,0,askacademia_train,1,16,2,1.0
94
+ 92,0,askacademia_train,1,14,8,1.0
95
+ 93,0,askacademia_train,1,14,2,1.0
96
+ 94,0,askacademia_train,0,4,6,1.0
97
+ 95,0,askacademia_train,0,3,6,1.0
98
+ 96,0,askacademia_train,1,6,2,1.0
99
+ 97,0,askacademia_train,0,2,4,1.0000000000000002
100
+ 98,0,askacademia_train,1,3,2,1.0
101
+ 99,0,askacademia_train,0,105,269,0.9999999999999999
102
+ 100,0,askacademia_train,1,269,56,1.0
103
+ 101,0,askacademia_train,0,29,269,1.0
104
+ 102,0,askacademia_train,1,82,55,1.0
105
+ 103,0,askacademia_train,0,56,82,1.0
106
+ 104,0,askacademia_train,1,82,33,0.9999999999999999
107
+ 105,0,askacademia_train,1,82,29,1.0
108
+ 106,0,askacademia_train,1,82,17,1.0000000000000002
109
+ 107,0,askacademia_train,1,82,15,0.9999999999999999
110
+ 108,0,askacademia_train,0,7,82,0.9999999999999999
111
+ 109,0,askacademia_train,0,5,82,1.0
112
+ 110,0,askacademia_train,1,55,33,1.0
113
+ 111,0,askacademia_train,1,55,29,0.9999999999999999
114
+ 112,0,askacademia_train,1,55,7,1.0000000000000002
115
+ 113,0,askacademia_train,1,55,5,0.9999999999999999
116
+ 114,0,askacademia_train,0,29,56,1.0
117
+ 115,0,askacademia_train,0,29,33,1.0
118
+ 116,0,askacademia_train,0,7,17,1.0
119
+ 117,0,askacademia_train,0,5,17,1.0
120
+ 118,0,askacademia_train,0,15,17,1.0
121
+ 119,0,askacademia_train,1,17,7,0.9999999999999999
122
+ 120,1,askacademia_train,1,17,5,0.9999999999999999
123
+ 121,1,askacademia_train,1,15,7,1.0
124
+ 122,1,askacademia_train,1,15,5,1.0
125
+ 123,1,askacademia_train,1,72,53,1.0000000000000002
126
+ 124,1,askacademia_train,0,27,72,1.0
127
+ 125,1,askacademia_train,0,20,72,1.0
128
+ 126,1,askacademia_train,1,49,27,0.9999999999999998
129
+ 127,1,askacademia_train,1,49,20,0.9999999999999999
130
+ 128,1,askacademia_train,1,42,27,1.0
131
+ 129,1,askacademia_train,0,25,42,1.0
132
+ 130,1,askacademia_train,1,42,20,1.0
133
+ 131,1,askacademia_train,0,20,27,1.0
134
+ 132,1,askacademia_train,0,20,25,0.9999999999999999
135
+ 133,1,askacademia_train,0,47,180,0.9999999999999999
136
+ 134,1,askacademia_train,0,47,48,1.0
137
+ 135,1,askacademia_train,0,29,48,1.0
138
+ 136,1,askacademia_train,0,10,48,0.9999999999999999
139
+ 137,1,askacademia_train,0,8,48,1.0
140
+ 138,1,askacademia_train,0,29,41,1.0
141
+ 139,1,askacademia_train,0,10,41,0.9999999999999999
142
+ 140,1,askacademia_train,1,41,8,0.9999999999999999
143
+ 141,1,askacademia_train,0,10,27,1.0
144
+ 142,1,askacademia_train,0,8,27,1.0
145
+ 143,1,askacademia_train,1,16,10,1.0
146
+ 144,1,askacademia_train,1,16,8,0.9999999999999999
147
+ 145,1,askacademia_train,1,16,2,0.9999999999999999
148
+ 146,1,askacademia_train,0,8,10,0.9999999999999999
149
+ 147,1,askacademia_train,0,8,9,0.9999999999999999
150
+ 148,1,askacademia_train,0,2,9,1.0
151
+ 149,1,askacademia_train,0,2,9,0.9999999999999999
152
+ 150,1,askacademia_train,1,5,3,1.0
153
+ 151,1,askacademia_train,1,5,2,0.9999999999999999
154
+ 152,1,askacademia_train,0,2,5,0.9999999999999999
155
+ 153,1,askacademia_train,0,2,5,1.0
156
+ 154,1,askacademia_train,0,2,5,0.9999999999999999
157
+ 155,1,askacademia_train,1,4,3,1.0
158
+ 156,1,askacademia_train,1,4,2,1.0
159
+ 157,1,askacademia_train,1,4,2,0.9999999999999999
160
+ 158,1,askacademia_train,0,2,4,1.0
161
+ 159,1,askacademia_train,1,4,2,0.9999999999999999
162
+ 160,1,askacademia_train,1,4,2,1.0
163
+ 161,1,askacademia_train,1,4,2,1.0
164
+ 162,1,askacademia_train,1,4,2,1.0
165
+ 163,1,askacademia_train,1,4,2,1.0
166
+ 164,1,askacademia_train,1,3,2,1.0
167
+ 165,1,askacademia_train,1,3,2,1.0
168
+ 166,1,askacademia_train,1,332,183,1.0
169
+ 167,1,askacademia_train,0,160,332,0.9999999999999999
170
+ 168,1,askacademia_train,1,332,21,1.0
171
+ 169,1,askacademia_train,1,332,21,1.0
172
+ 170,1,askacademia_train,1,160,21,0.9999999999999999
173
+ 171,1,askacademia_train,0,36,82,1.0
174
+ 172,1,askacademia_train,1,82,21,1.0
175
+ 173,1,askacademia_train,0,21,82,0.9999999999999999
176
+ 174,1,askacademia_train,0,14,82,0.9999999999999999
177
+ 175,1,askacademia_train,0,36,58,1.0
178
+ 176,1,askacademia_train,1,58,26,1.0
179
+ 177,1,askacademia_train,1,58,21,1.0
180
+ 178,1,askacademia_train,1,58,21,0.9999999999999999
181
+ 179,1,askacademia_train,0,14,58,1.0
182
+ 180,1,askacademia_train,0,36,37,0.9999999999999999
183
+ 181,1,askacademia_train,0,21,36,1.0
184
+ 182,1,askacademia_train,0,21,36,0.9999999999999999
185
+ 183,1,askacademia_train,1,37,26,0.9999999999999999
186
+ 184,1,askacademia_train,1,37,21,1.0
187
+ 185,1,askacademia_train,0,21,37,1.0
188
+ 186,1,askacademia_train,1,37,14,1.0
189
+ 187,1,askacademia_train,1,29,26,1.0
190
+ 188,1,askacademia_train,0,21,29,1.0
191
+ 189,1,askacademia_train,0,21,29,1.0
192
+ 190,1,askacademia_train,1,29,14,0.9999999999999999
193
+ 191,1,askacademia_train,0,21,26,0.9999999999999999
194
+ 192,1,askacademia_train,1,26,21,1.0
195
+ 193,1,askacademia_train,0,14,26,0.9999999999999999
196
+ 194,1,askacademia_train,0,8,11,1.0
197
+ 195,1,askacademia_train,1,191,187,1.0
198
+ 196,1,askacademia_train,1,191,7,1.0
199
+ 197,1,askacademia_train,0,8,191,1.0
200
+ 198,1,askacademia_train,0,7,30,0.9999999999999999
201
+ 199,1,askacademia_train,0,8,30,1.0
202
+ 200,1,askacademia_train,0,7,13,1.0
203
+ 201,1,askacademia_train,1,13,8,1.0
204
+ 202,1,askacademia_train,0,7,8,1.0
205
+ 203,1,askacademia_train,0,247,587,1.0000000000000002
206
+ 204,1,askacademia_train,1,587,243,1.0
207
+ 205,1,askacademia_train,0,47,587,0.9999999999999999
208
+ 206,1,askacademia_train,1,587,16,0.9999999999999999
209
+ 207,1,askacademia_train,1,247,47,0.9999999999999999
210
+ 208,1,askacademia_train,0,16,247,1.0
211
+ 209,1,askacademia_train,1,243,47,1.0
212
+ 210,1,askacademia_train,1,243,16,0.9999999999999999
213
+ 211,1,askacademia_train,0,47,89,1.0
214
+ 212,1,askacademia_train,1,89,16,0.9999999999999999
215
+ 213,1,askacademia_train,0,47,50,0.9999999999999999
216
+ 214,1,askacademia_train,0,16,50,1.0
217
+ 215,1,askacademia_train,0,16,39,0.9999999999999999
218
+ 216,1,askacademia_train,0,8,39,0.9999999999999999
219
+ 217,1,askacademia_train,0,9,39,0.9999999999999999
220
+ 218,1,askacademia_train,0,9,39,1.0
221
+ 219,1,askacademia_train,0,16,25,1.0
222
+ 220,1,askacademia_train,0,8,25,1.0
223
+ 221,1,askacademia_train,1,25,9,1.0
224
+ 222,1,askacademia_train,1,25,9,0.9999999999999999
225
+ 223,1,askacademia_train,0,7,25,1.0
226
+ 224,1,askacademia_train,0,7,8,0.9999999999999999
227
+ 225,1,askacademia_train,1,9,8,1.0
228
+ 226,1,askacademia_train,1,8,7,1.0
229
+ 227,1,askacademia_train,1,130,111,1.0
230
+ 228,1,askacademia_train,0,3,7,1.0
231
+ 229,1,askacademia_train,0,3,5,0.9999999999999999
232
+ 230,1,askacademia_train,0,3,5,1.0
233
+ 231,1,askacademia_train,1,69,25,1.0
234
+ 232,1,askacademia_train,0,16,69,1.0
235
+ 233,1,askacademia_train,0,7,69,1.0
236
+ 234,1,askacademia_train,1,69,3,0.9999999999999999
237
+ 235,1,askacademia_train,0,3,69,1.0
238
+ 236,1,askacademia_train,0,3,69,1.0
239
+ 237,1,askacademia_train,1,25,16,1.0
240
+ 238,1,askacademia_train,1,25,7,0.9999999999999999
241
+ 239,1,askacademia_train,0,3,25,1.0
242
+ 240,2,askacademia_train,1,7,4,1.0
243
+ 241,2,askacademia_train,1,7,3,0.9999999999999999
244
+ 242,2,askacademia_train,1,7,3,1.0
245
+ 243,2,askacademia_train,0,3,7,1.0
246
+ 244,2,askacademia_train,0,3,7,1.0
247
+ 245,2,askacademia_train,1,7,2,0.9999999999999999
248
+ 246,2,askacademia_train,0,2,7,0.9999999999999999
249
+ 247,2,askacademia_train,1,7,2,0.9999999999999999
250
+ 248,2,askacademia_train,1,4,3,1.0
251
+ 249,2,askacademia_train,0,3,4,1.0
252
+ 250,2,askacademia_train,1,4,3,0.9999999999999999
253
+ 251,2,askacademia_train,0,3,4,1.0
254
+ 252,2,askacademia_train,1,4,2,0.9999999999999999
255
+ 253,2,askacademia_train,1,4,2,1.0
256
+ 254,2,askacademia_train,1,4,2,0.9999999999999999
257
+ 255,2,askacademia_train,0,2,3,1.0
258
+ 256,2,askacademia_train,0,2,3,0.9999999999999999
259
+ 257,2,askacademia_train,0,2,3,1.0
260
+ 258,2,askacademia_train,0,110,233,0.9999999999999999
261
+ 259,2,askacademia_train,0,14,233,1.0
262
+ 260,2,askacademia_train,0,14,110,1.0
263
+ 261,2,askacademia_train,0,32,41,1.0
264
+ 262,2,askacademia_train,1,41,29,1.0
265
+ 263,2,askacademia_train,0,14,41,0.9999999999999999
266
+ 264,2,askacademia_train,0,5,41,0.9999999999999999
267
+ 265,2,askacademia_train,1,41,3,0.9999999999999999
268
+ 266,2,askacademia_train,1,32,14,1.0
269
+ 267,2,askacademia_train,1,32,5,1.0
270
+ 268,2,askacademia_train,1,29,14,1.0
271
+ 269,2,askacademia_train,0,5,29,1.0
272
+ 270,2,askacademia_train,0,5,10,0.9999999999999999
273
+ 271,2,askacademia_train,1,10,3,1.0
274
+ 272,2,askacademia_train,0,5,7,1.0
275
+ 273,2,askacademia_train,1,7,5,0.9999999999999999
276
+ 274,2,askacademia_train,0,3,7,1.0
277
+ 275,2,askacademia_train,1,8,5,1.0
278
+ 276,2,askacademia_train,0,5,8,1.0
279
+ 277,2,askacademia_train,0,3,8,1.0
280
+ 278,2,askacademia_train,1,5,3,1.0
281
+ 279,2,askacademia_train,1,267,89,1.0
282
+ 280,2,askacademia_train,0,21,267,1.0
283
+ 281,2,askacademia_train,1,96,89,1.0
284
+ 282,2,askacademia_train,0,28,96,1.0
285
+ 283,2,askacademia_train,1,96,21,1.0
286
+ 284,2,askacademia_train,0,21,89,0.9999999999999999
287
+ 285,2,askacademia_train,0,29,85,1.0
288
+ 286,2,askacademia_train,0,28,85,1.0
289
+ 287,2,askacademia_train,0,21,85,0.9999999999999999
290
+ 288,2,askacademia_train,0,6,85,0.9999999999999999
291
+ 289,2,askacademia_train,0,28,29,1.0
292
+ 290,2,askacademia_train,0,21,29,1.0
293
+ 291,2,askacademia_train,1,28,21,1.0
294
+ 292,2,askacademia_train,0,12,14,1.0
295
+ 293,2,askacademia_train,1,14,8,0.9999999999999999
296
+ 294,2,askacademia_train,0,9,14,1.0
297
+ 295,2,askacademia_train,1,14,6,0.9999999999999999
298
+ 296,2,askacademia_train,0,6,14,1.0
299
+ 297,2,askacademia_train,1,14,12,1.0
300
+ 298,2,askacademia_train,1,14,8,1.0
301
+ 299,2,askacademia_train,1,14,9,0.9999999999999999
302
+ 300,2,askacademia_train,1,14,6,0.9999999999999999
303
+ 301,2,askacademia_train,0,6,14,1.0
304
+ 302,2,askacademia_train,1,12,6,1.0
305
+ 303,2,askacademia_train,1,11,8,0.9999999999999999
306
+ 304,2,askacademia_train,0,8,11,1.0
307
+ 305,2,askacademia_train,0,9,11,1.0
308
+ 306,2,askacademia_train,1,11,6,1.0
309
+ 307,2,askacademia_train,1,11,6,1.0
310
+ 308,2,askacademia_train,0,6,8,1.0
311
+ 309,2,askacademia_train,0,6,8,1.0
312
+ 310,2,askacademia_train,1,9,8,1.0
313
+ 311,2,askacademia_train,1,8,6,1.0000000000000002
314
+ 312,2,askacademia_train,0,6,9,1.0
315
+ 313,2,askacademia_train,1,9,6,1.0
316
+ 314,2,askacademia_train,1,6,5,1.0
317
+ 315,2,askacademia_train,0,5,6,0.9999999999999999
318
+ 316,2,askacademia_train,0,12,50,0.9999999999999999
319
+ 317,2,askacademia_train,1,41,34,0.9999999999999999
320
+ 318,2,askacademia_train,0,13,41,0.9999999999999999
321
+ 319,2,askacademia_train,0,12,41,0.9999999999999999
322
+ 320,2,askacademia_train,0,7,41,0.9999999999999999
323
+ 321,2,askacademia_train,1,34,12,1.0
324
+ 322,2,askacademia_train,1,34,7,1.0
325
+ 323,2,askacademia_train,0,12,13,0.9999999999999999
326
+ 324,2,askacademia_train,0,9,13,1.0
327
+ 325,2,askacademia_train,0,7,13,1.0000000000000002
328
+ 326,2,askacademia_train,0,12,13,1.0
329
+ 327,2,askacademia_train,1,13,7,0.9999999999999999
330
+ 328,2,askacademia_train,1,13,12,0.9999999999999999
331
+ 329,2,askacademia_train,0,9,13,1.0
332
+ 330,2,askacademia_train,0,7,13,1.0
333
+ 331,2,askacademia_train,1,13,3,1.0
334
+ 332,2,askacademia_train,1,9,7,0.9999999999999999
335
+ 333,2,askacademia_train,1,7,6,1.0
336
+ 334,2,askacademia_train,1,7,3,1.0
337
+ 335,2,askacademia_train,0,6,7,1.0
338
+ 336,2,askacademia_train,1,6,3,1.0
339
+ 337,2,askacademia_train,0,3,7,1.0
340
+ 338,2,askacademia_train,0,129,171,1.0
341
+ 339,2,askacademia_train,0,32,171,1.0
342
+ 340,2,askacademia_train,1,131,129,1.0
343
+ 341,2,askacademia_train,1,131,40,1.0
344
+ 342,2,askacademia_train,0,32,131,1.0000000000000002
345
+ 343,2,askacademia_train,1,40,32,1.0
346
+ 344,2,askacademia_train,1,36,32,0.9999999999999999
347
+ 345,2,askacademia_train,0,7,12,1.0
348
+ 346,2,askacademia_train,0,5,12,1.0
349
+ 347,2,askacademia_train,0,3,12,1.0
350
+ 348,2,askacademia_train,0,4,12,1.0
351
+ 349,2,askacademia_train,0,5,7,1.0
352
+ 350,2,askacademia_train,0,3,7,1.0
353
+ 351,2,askacademia_train,1,7,5,1.0
354
+ 352,2,askacademia_train,1,7,3,1.0
355
+ 353,2,askacademia_train,0,4,7,1.0
356
+ 354,2,askacademia_train,0,3,7,0.9999999999999999
357
+ 355,2,askacademia_train,0,3,4,1.0
358
+ 356,2,askacademia_train,0,338,407,0.9999999999999999
359
+ 357,2,askacademia_train,1,407,227,1.0
360
+ 358,2,askacademia_train,1,407,109,1.0
361
+ 359,2,askacademia_train,1,407,71,1.0
362
+ 360,3,askacademia_train,0,66,407,1.0
363
+ 361,3,askacademia_train,0,26,407,0.9999999999999998
364
+ 362,3,askacademia_train,1,132,109,1.0
365
+ 363,3,askacademia_train,1,132,71,0.9999999999999999
366
+ 364,3,askacademia_train,0,66,132,1.0
367
+ 365,3,askacademia_train,1,132,31,1.0
368
+ 366,3,askacademia_train,1,132,26,0.9999999999999999
369
+ 367,3,askacademia_train,0,109,113,1.0
370
+ 368,3,askacademia_train,1,113,71,1.0
371
+ 369,3,askacademia_train,1,113,66,1.0
372
+ 370,3,askacademia_train,1,113,31,0.9999999999999999
373
+ 371,3,askacademia_train,1,113,26,0.9999999999999999
374
+ 372,3,askacademia_train,1,109,71,0.9999999999999999
375
+ 373,3,askacademia_train,0,71,107,0.9999999999999999
376
+ 374,3,askacademia_train,0,66,107,1.0
377
+ 375,3,askacademia_train,0,31,107,1.0
378
+ 376,3,askacademia_train,0,26,107,1.0
379
+ 377,3,askacademia_train,1,34,31,1.0000000000000002
380
+ 378,3,askacademia_train,0,26,31,0.9999999999999999
381
+ 379,3,askacademia_train,0,26,34,1.0
382
+ 380,3,askacademia_train,1,109,10,1.0
383
+ 381,3,askacademia_train,1,37,26,1.0
384
+ 382,3,askacademia_train,0,10,37,1.0
385
+ 383,3,askacademia_train,1,37,9,0.9999999999999999
386
+ 384,3,askacademia_train,0,6,37,1.0
387
+ 385,3,askacademia_train,1,30,26,1.0
388
+ 386,3,askacademia_train,1,30,25,1.0
389
+ 387,3,askacademia_train,0,10,30,0.9999999999999999
390
+ 388,3,askacademia_train,1,30,9,0.9999999999999999
391
+ 389,3,askacademia_train,1,30,6,0.9999999999999999
392
+ 390,3,askacademia_train,0,3,30,1.0
393
+ 391,3,askacademia_train,1,26,10,1.0
394
+ 392,3,askacademia_train,0,10,25,1.0
395
+ 393,3,askacademia_train,0,9,25,1.0
396
+ 394,3,askacademia_train,0,6,25,1.0
397
+ 395,3,askacademia_train,0,3,25,0.9999999999999999
398
+ 396,3,askacademia_train,0,10,17,0.9999999999999999
399
+ 397,3,askacademia_train,1,17,9,0.9999999999999999
400
+ 398,3,askacademia_train,0,6,17,0.9999999999999998
401
+ 399,3,askacademia_train,1,17,3,0.9999999999999999
402
+ 400,3,askacademia_train,1,9,6,1.0
403
+ 401,3,askacademia_train,1,186,182,0.9999999999999998
404
+ 402,3,askacademia_train,1,166,116,1.0
405
+ 403,3,askacademia_train,1,166,39,1.0
406
+ 404,3,askacademia_train,1,166,24,1.0
407
+ 405,3,askacademia_train,1,166,16,1.0
408
+ 406,3,askacademia_train,0,2,166,1.0
409
+ 407,3,askacademia_train,1,116,24,1.0
410
+ 408,3,askacademia_train,0,16,116,1.0
411
+ 409,3,askacademia_train,0,2,116,0.9999999999999999
412
+ 410,3,askacademia_train,0,24,39,1.0
413
+ 411,3,askacademia_train,1,39,16,1.0
414
+ 412,3,askacademia_train,1,39,2,1.0
415
+ 413,3,askacademia_train,0,16,20,1.0
416
+ 414,3,askacademia_train,1,20,7,1.0
417
+ 415,3,askacademia_train,1,20,6,0.9999999999999999
418
+ 416,3,askacademia_train,1,20,7,0.9999999999999999
419
+ 417,3,askacademia_train,1,20,2,1.0
420
+ 418,3,askacademia_train,0,2,20,1.0
421
+ 419,3,askacademia_train,1,20,2,1.0
422
+ 420,3,askacademia_train,1,10,7,1.0
423
+ 421,3,askacademia_train,0,6,10,1.0
424
+ 422,3,askacademia_train,0,7,10,1.0
425
+ 423,3,askacademia_train,1,10,5,1.0
426
+ 424,3,askacademia_train,1,10,2,1.0
427
+ 425,3,askacademia_train,1,10,2,1.0000000000000002
428
+ 426,3,askacademia_train,1,10,2,0.9999999999999999
429
+ 427,3,askacademia_train,0,2,7,0.9999999999999999
430
+ 428,3,askacademia_train,0,6,7,0.9999999999999999
431
+ 429,3,askacademia_train,0,2,6,1.0
432
+ 430,3,askacademia_train,1,6,2,1.0
433
+ 431,3,askacademia_train,1,6,2,0.9999999999999999
434
+ 432,3,askacademia_train,1,7,2,0.9999999999999999
435
+ 433,3,askacademia_train,0,2,7,0.9999999999999999
436
+ 434,3,askacademia_train,1,7,2,0.9999999999999999
437
+ 435,3,askacademia_train,1,5,2,1.0
438
+ 436,3,askacademia_train,1,5,2,1.0
439
+ 437,3,askacademia_train,1,5,2,0.9999999999999999
440
+ 438,3,askacademia_train,1,53,7,0.9999999999999999
441
+ 439,3,askacademia_train,1,53,7,1.0
442
+ 440,3,askacademia_train,1,53,5,0.9999999999999999
443
+ 441,3,askacademia_train,1,53,3,0.9999999999999999
444
+ 442,3,askacademia_train,0,3,53,0.9999999999999999
445
+ 443,3,askacademia_train,1,53,3,1.0
446
+ 444,3,askacademia_train,0,7,10,1.0
447
+ 445,3,askacademia_train,1,10,7,0.9999999999999999
448
+ 446,3,askacademia_train,0,5,10,0.9999999999999999
449
+ 447,3,askacademia_train,0,5,10,1.0
450
+ 448,3,askacademia_train,0,4,10,0.9999999999999999
451
+ 449,3,askacademia_train,1,10,3,1.0
452
+ 450,3,askacademia_train,0,3,10,1.0
453
+ 451,3,askacademia_train,0,3,10,1.0
454
+ 452,3,askacademia_train,1,10,3,0.9999999999999999
455
+ 453,3,askacademia_train,1,7,3,0.9999999999999998
456
+ 454,3,askacademia_train,1,5,3,0.9999999999999999
457
+ 455,3,askacademia_train,0,3,5,0.9999999999999999
458
+ 456,3,askacademia_train,1,5,4,0.9999999999999999
459
+ 457,3,askacademia_train,0,3,5,1.0
460
+ 458,3,askacademia_train,0,3,5,0.9999999999999999
461
+ 459,3,askacademia_train,0,3,5,1.0
462
+ 460,3,askacademia_train,0,3,4,0.9999999999999999
463
+ 461,3,askacademia_train,0,3,4,0.9999999999999999
464
+ 462,3,askacademia_train,0,3,4,0.9999999999999999
465
+ 463,3,askacademia_train,0,3,6,0.9999999999999999
466
+ 464,3,askacademia_train,0,3,6,1.0
467
+ 465,3,askacademia_train,1,6,3,1.0
468
+ 466,3,askacademia_train,1,6,3,1.0
469
+ 467,3,askacademia_train,1,6,2,1.0
470
+ 468,3,askacademia_train,0,2,3,1.0
471
+ 469,3,askacademia_train,1,3,2,0.9999999999999999
472
+ 470,3,askacademia_train,0,10,14,1.0
473
+ 471,3,askacademia_train,0,9,14,0.9999999999999999
474
+ 472,3,askacademia_train,0,9,14,0.9999999999999999
475
+ 473,3,askacademia_train,0,7,14,1.0
476
+ 474,3,askacademia_train,0,7,14,0.9999999999999999
477
+ 475,3,askacademia_train,0,7,9,0.9999999999999999
478
+ 476,3,askacademia_train,1,56,41,0.9999999999999999
479
+ 477,3,askacademia_train,0,27,56,1.0
480
+ 478,3,askacademia_train,0,8,56,1.0
481
+ 479,3,askacademia_train,1,56,4,1.0000000000000002
482
+ 480,4,askacademia_train,0,8,15,1.0
483
+ 481,4,askacademia_train,0,9,15,0.9999999999999999
484
+ 482,4,askacademia_train,0,7,15,1.0
485
+ 483,4,askacademia_train,0,7,15,1.0
486
+ 484,4,askacademia_train,0,6,15,1.0
487
+ 485,4,askacademia_train,1,15,4,1.0
488
+ 486,4,askacademia_train,1,15,2,1.0
489
+ 487,4,askacademia_train,1,9,8,1.0
490
+ 488,4,askacademia_train,0,6,9,1.0
491
+ 489,4,askacademia_train,1,9,4,1.0
492
+ 490,4,askacademia_train,0,6,7,0.9999999999999998
493
+ 491,4,askacademia_train,1,7,4,0.9999999999999999
494
+ 492,4,askacademia_train,0,2,7,1.0
495
+ 493,4,askacademia_train,1,7,6,1.0
496
+ 494,4,askacademia_train,0,4,7,0.9999999999999999
497
+ 495,4,askacademia_train,0,2,7,1.0
498
+ 496,4,askacademia_train,1,6,4,0.9999999999999999
499
+ 497,4,askacademia_train,1,82,25,1.0
500
+ 498,4,askacademia_train,0,25,75,1.0
501
+ 499,4,askacademia_train,1,75,9,1.0
502
+ 500,4,askacademia_train,1,75,9,1.0
503
+ 501,4,askacademia_train,1,47,36,0.9999999999999999
504
+ 502,4,askacademia_train,1,47,25,0.9999999999999999
505
+ 503,4,askacademia_train,1,47,11,1.0
506
+ 504,4,askacademia_train,0,11,47,1.0
507
+ 505,4,askacademia_train,1,47,9,1.0
508
+ 506,4,askacademia_train,0,9,47,0.9999999999999999
509
+ 507,4,askacademia_train,1,47,8,1.0000000000000002
510
+ 508,4,askacademia_train,0,25,36,1.0
511
+ 509,4,askacademia_train,1,36,9,1.0
512
+ 510,4,askacademia_train,0,9,36,0.9999999999999999
513
+ 511,4,askacademia_train,1,27,25,0.9999999999999999
514
+ 512,4,askacademia_train,0,11,27,0.9999999999999999
515
+ 513,4,askacademia_train,1,27,11,0.9999999999999999
516
+ 514,4,askacademia_train,1,27,9,1.0
517
+ 515,4,askacademia_train,0,9,27,1.0
518
+ 516,4,askacademia_train,1,27,8,0.9999999999999999
519
+ 517,4,askacademia_train,0,7,27,0.9999999999999999
520
+ 518,4,askacademia_train,0,5,27,1.0
521
+ 519,4,askacademia_train,1,14,11,0.9999999999999999
522
+ 520,4,askacademia_train,0,11,14,1.0
523
+ 521,4,askacademia_train,0,9,14,1.0000000000000002
524
+ 522,4,askacademia_train,0,9,14,1.0
525
+ 523,4,askacademia_train,1,14,8,1.0
526
+ 524,4,askacademia_train,0,7,14,1.0000000000000002
527
+ 525,4,askacademia_train,1,14,5,0.9999999999999999
528
+ 526,4,askacademia_train,1,14,3,1.0
529
+ 527,4,askacademia_train,0,3,14,1.0
530
+ 528,4,askacademia_train,0,2,14,1.0
531
+ 529,4,askacademia_train,0,9,11,0.9999999999999999
532
+ 530,4,askacademia_train,1,11,9,0.9999999999999999
533
+ 531,4,askacademia_train,1,11,8,1.0
534
+ 532,4,askacademia_train,0,9,11,1.0
535
+ 533,4,askacademia_train,1,11,9,1.0
536
+ 534,4,askacademia_train,0,8,11,1.0
537
+ 535,4,askacademia_train,1,33,25,1.0
538
+ 536,4,askacademia_train,1,33,21,1.0
539
+ 537,4,askacademia_train,0,15,33,0.9999999999999999
540
+ 538,4,askacademia_train,0,3,33,1.0
541
+ 539,4,askacademia_train,1,22,21,0.9999999999999999
542
+ 540,4,askacademia_train,1,22,15,1.0
543
+ 541,4,askacademia_train,0,3,22,0.9999999999999999
544
+ 542,4,askacademia_train,1,21,15,0.9999999999999999
545
+ 543,4,askacademia_train,1,21,3,1.0
546
+ 544,4,askacademia_train,0,3,15,1.0
547
+ 545,4,askacademia_train,0,3,4,1.0000000000000002
548
+ 546,4,askacademia_train,1,4,3,0.9999999999999999
549
+ 547,4,askacademia_train,1,4,3,1.0
550
+ 548,4,askacademia_train,1,4,3,0.9999999999999999
551
+ 549,4,askacademia_train,1,4,3,0.9999999999999999
552
+ 550,4,askacademia_train,0,389,525,0.9999999999999999
553
+ 551,4,askacademia_train,0,121,158,1.0
554
+ 552,4,askacademia_train,1,158,108,1.0
555
+ 553,4,askacademia_train,1,158,112,1.0
556
+ 554,4,askacademia_train,0,96,158,1.0
557
+ 555,4,askacademia_train,1,158,71,1.0
558
+ 556,4,askacademia_train,1,158,61,1.0
559
+ 557,4,askacademia_train,0,39,158,1.0
560
+ 558,4,askacademia_train,1,158,41,1.0
561
+ 559,4,askacademia_train,1,158,24,0.9999999999999999
562
+ 560,4,askacademia_train,0,22,158,1.0
563
+ 561,4,askacademia_train,0,17,158,0.9999999999999999
564
+ 562,4,askacademia_train,1,121,108,1.0
565
+ 563,4,askacademia_train,1,121,71,1.0
566
+ 564,4,askacademia_train,1,121,61,0.9999999999999999
567
+ 565,4,askacademia_train,0,22,121,1.0
568
+ 566,4,askacademia_train,1,112,108,1.0
569
+ 567,4,askacademia_train,0,71,112,1.0
570
+ 568,4,askacademia_train,0,61,112,0.9999999999999999
571
+ 569,4,askacademia_train,1,112,22,1.0
572
+ 570,4,askacademia_train,0,71,96,1.0
573
+ 571,4,askacademia_train,0,61,96,1.0
574
+ 572,4,askacademia_train,0,41,96,1.0
575
+ 573,4,askacademia_train,1,96,24,0.9999999999999999
576
+ 574,4,askacademia_train,0,22,96,1.0
577
+ 575,4,askacademia_train,0,24,39,1.0000000000000002
578
+ 576,4,askacademia_train,1,39,22,0.9999999999999999
579
+ 577,4,askacademia_train,0,22,41,1.0
580
+ 578,4,askacademia_train,1,24,22,1.0
581
+ 579,4,askacademia_train,0,17,19,1.0
582
+ 580,4,askacademia_train,0,16,19,1.0
583
+ 581,4,askacademia_train,1,250,4,1.0
584
+ 582,4,askacademia_train,1,250,2,1.0
585
+ 583,4,askacademia_train,0,44,58,1.0
586
+ 584,4,askacademia_train,1,58,4,1.0
587
+ 585,4,askacademia_train,0,2,58,0.9999999999999999
588
+ 586,4,askacademia_train,1,44,4,1.0
589
+ 587,4,askacademia_train,1,44,2,1.0
590
+ 588,4,askacademia_train,1,33,4,1.0
591
+ 589,4,askacademia_train,1,33,2,0.9999999999999998
592
+ 590,4,askacademia_train,0,2,33,1.0
593
+ 591,4,askacademia_train,1,15,4,0.9999999999999999
594
+ 592,4,askacademia_train,0,2,15,1.0
595
+ 593,4,askacademia_train,0,2,15,0.9999999999999999
596
+ 594,4,askacademia_train,0,4,11,0.9999999999999999
597
+ 595,4,askacademia_train,1,11,2,1.0
598
+ 596,4,askacademia_train,0,2,11,1.0
599
+ 597,4,askacademia_train,0,4,9,1.0
600
+ 598,4,askacademia_train,1,9,2,1.0
601
+ 599,4,askacademia_train,1,9,2,1.0
packaged_replay/source_claim_audit.csv ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ claim,source,literal_scope,audit
2
+ 1,Theorem 5.1,"partial participation; E,R,S,kappa^2,zeta_g^2 terms",formula ledger + actual FedDPO
3
+ 2,Corollary 5.2,full participation removes partial-participation amplification; residual averaged-client variance remains,separate corollary ledger
4
+ 3,Theorem 5.4,eta C_q q_max additive penalty under Assumption 5.3,formula ledger + stale FedDPO
5
+ 4,Theorem 5.5,"DPO-like objective family lower bound, not every conceivable objective",finite-population construction ledger
6
+ 5,Theorem 6.1,symmetric doubly stochastic mixing and theorem assumptions,actual DecDPO on four graphs
7
+ 6,"Section 7, Figures 1-5","SHP uses N=5 disjoint clients, 120 pairs each",600 pinned SHP rows and four ablation families
packaged_replay/theorem_5_1_partial_bound.csv ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ E,S,R,eta,initialization_term,sampling_1_over_S_term,heterogeneity_term,local_variance_1_over_S_term,theorem_5_1_bound
2
+ 1,1,40,0.09486832980505137,0.36532064071556886,0.0011957328525646549,2.6675993642301955e-07,9.074974289267087e-06,0.36652571530235917
3
+ 1,1,80,0.06708203932499368,0.25832070235739313,0.0008455108085360017,1.3337996821150972e-07,4.537487144633543e-06,0.259170884033042
4
+ 1,1,160,0.04743416490252569,0.18266032035778443,0.0005978664262823274,6.668998410575489e-08,2.2687435723167718e-06,0.18326052221762318
5
+ 1,1,320,0.03354101966249684,0.12916035117869656,0.00042275540426800083,3.334499205287743e-08,1.1343717861583857e-06,0.12958427429974279
6
+ 1,3,40,0.09486832980505137,0.36532064071556886,0.00039857761752155164,2.6675993642301955e-07,3.0249914297556957e-06,0.36572251008445655
7
+ 1,3,80,0.06708203932499368,0.25832070235739313,0.00028183693617866724,1.3337996821150972e-07,1.5124957148778476e-06,0.25860418516925493
8
+ 1,3,160,0.04743416490252569,0.18266032035778443,0.00019928880876077582,6.668998410575489e-08,7.562478574389239e-07,0.18286043210438677
9
+ 1,3,320,0.03354101966249684,0.12916035117869656,0.00014091846808933362,3.334499205287743e-08,3.781239287194619e-07,0.12930168111570667
10
+ 1,5,40,0.09486832980505137,0.36532064071556886,0.00023914657051293098,2.6675993642301955e-07,1.8149948578534173e-06,0.36556186904087606
11
+ 1,5,80,0.06708203932499368,0.25832070235739313,0.00016910216170720033,1.3337996821150972e-07,9.074974289267086e-07,0.25849084539649747
12
+ 1,5,160,0.04743416490252569,0.18266032035778443,0.00011957328525646549,6.668998410575489e-08,4.5374871446335433e-07,0.18278041408173948
13
+ 1,5,320,0.03354101966249684,0.12916035117869656,8.455108085360017e-05,3.334499205287743e-08,2.2687435723167714e-07,0.12924516247889944
14
+ 3,1,40,0.09486832980505137,0.12177354690518961,0.0011957328525646549,8.002798092690587e-07,8.167476860340379e-05,0.12305175480616694
15
+ 3,1,80,0.06708203932499368,0.08610690078579769,0.0008455108085360017,4.0013990463452917e-07,4.0837384301701886e-05,0.08699364911854003
16
+ 3,1,160,0.04743416490252569,0.06088677345259481,0.0005978664262823274,2.0006995231726466e-07,2.0418692150850947e-05,0.061505258640980304
17
+ 3,1,320,0.03354101966249684,0.043053450392898845,0.00042275540426800083,1.0003497615863229e-07,1.0209346075425472e-05,0.04348651517821842
18
+ 3,3,40,0.09486832980505137,0.12177354690518961,0.00039857761752155164,8.002798092690587e-07,2.722492286780126e-05,0.12220014972538823
19
+ 3,3,80,0.06708203932499368,0.08610690078579769,0.00028183693617866724,4.0013990463452917e-07,1.3612461433900629e-05,0.0864027503233149
20
+ 3,3,160,0.04743416490252569,0.06088677345259481,0.00019928880876077582,2.0006995231726466e-07,6.806230716950315e-06,0.06109306856202485
21
+ 3,3,320,0.03354101966249684,0.043053450392898845,0.00014091846808933362,1.0003497615863229e-07,3.403115358475157e-06,0.04319787201132281
22
+ 3,5,40,0.09486832980505137,0.12177354690518961,0.00023914657051293098,8.002798092690587e-07,1.6334953720680758e-05,0.12202982870923249
23
+ 3,5,80,0.06708203932499368,0.08610690078579769,0.00016910216170720033,4.0013990463452917e-07,8.167476860340377e-06,0.08628457056426987
24
+ 3,5,160,0.04743416490252569,0.06088677345259481,0.00011957328525646549,2.0006995231726466e-07,4.0837384301701895e-06,0.06101063054623376
25
+ 3,5,320,0.03354101966249684,0.043053450392898845,8.455108085360017e-05,1.0003497615863229e-07,2.0418692150850943e-06,0.04314014337794368
26
+ 6,1,40,0.09486832980505137,0.06088677345259481,0.0011957328525646549,1.6005596185381173e-06,0.00032669907441361515,0.06241080593919161
27
+ 6,1,80,0.06708203932499368,0.043053450392898845,0.0008455108085360017,8.002798092690583e-07,0.00016334953720680755,0.04406311101845092
28
+ 6,1,160,0.04743416490252569,0.030443386726297404,0.0005978664262823274,4.001399046345293e-07,8.167476860340379e-05,0.03112332806108777
29
+ 6,1,320,0.03354101966249684,0.021526725196449423,0.00042275540426800083,2.0006995231726458e-07,4.0837384301701886e-05,0.021990518054971445
30
+ 6,3,40,0.09486832980505137,0.06088677345259481,0.00039857761752155164,1.6005596185381173e-06,0.00010889969147120504,0.0613958513212061
31
+ 6,3,80,0.06708203932499368,0.043053450392898845,0.00028183693617866724,8.002798092690583e-07,5.4449845735602515e-05,0.04339053745462239
32
+ 6,3,160,0.04743416490252569,0.030443386726297404,0.00019928880876077582,4.001399046345293e-07,2.722492286780126e-05,0.030670300597830616
33
+ 6,3,320,0.03354101966249684,0.021526725196449423,0.00014091846808933362,2.0006995231726458e-07,1.3612461433900629e-05,0.021681456195924976
34
+ 6,5,40,0.09486832980505137,0.06088677345259481,0.00023914657051293098,1.6005596185381173e-06,6.533981488272303e-05,0.061192860397608996
35
+ 6,5,80,0.06708203932499368,0.043053450392898845,0.00016910216170720033,8.002798092690583e-07,3.266990744136151e-05,0.04325602274185668
36
+ 6,5,160,0.04743416490252569,0.030443386726297404,0.00011957328525646549,4.001399046345293e-07,1.6334953720680758e-05,0.030579695105179185
37
+ 6,5,320,0.03354101966249684,0.021526725196449423,8.455108085360017e-05,2.0006995231726458e-07,8.167476860340377e-06,0.02161964382411568
packaged_replay/theorem_5_4_staleness.csv ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ qmax,eta,E,C_q,linear_staleness_penalty,C_q_qmax_without_outer_eta
2
+ 0,0.01,3,1.2163716439700656e-05,0.0,0.0
3
+ 0,0.02,3,4.8654865758802626e-05,0.0,0.0
4
+ 0,0.04,3,0.0001946194630352105,0.0,0.0
5
+ 1,0.01,3,1.2163716439700656e-05,1.2163716439700657e-07,1.2163716439700656e-05
6
+ 1,0.02,3,4.8654865758802626e-05,9.730973151760526e-07,4.8654865758802626e-05
7
+ 1,0.04,3,0.0001946194630352105,7.78477852140842e-06,0.0001946194630352105
8
+ 2,0.01,3,1.2163716439700656e-05,2.4327432879401314e-07,2.4327432879401313e-05
9
+ 2,0.02,3,4.8654865758802626e-05,1.946194630352105e-06,9.730973151760525e-05
10
+ 2,0.04,3,0.0001946194630352105,1.556955704281684e-05,0.000389238926070421
11
+ 5,0.01,3,1.2163716439700656e-05,6.081858219850329e-07,6.081858219850328e-05
12
+ 5,0.02,3,4.8654865758802626e-05,4.865486575880263e-06,0.00024327432879401312
13
+ 5,0.04,3,0.0001946194630352105,3.8923892607042106e-05,0.0009730973151760525
14
+ 10,0.01,3,1.2163716439700656e-05,1.2163716439700658e-06,0.00012163716439700656
15
+ 10,0.02,3,4.8654865758802626e-05,9.730973151760527e-06,0.00048654865758802625
16
+ 10,0.04,3,0.0001946194630352105,7.784778521408421e-05,0.001946194630352105
packaged_replay/theorem_5_5_lower_bound.csv ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ N,E,S,kappa_squared,exact_without_replacement_sampling_variance,registered_E_kappa_squared_over_S,full_participation_sampling_variance
2
+ 20,1,1,0.001157812224058244,0.001157812224058244,0.001157812224058244,False
3
+ 20,1,2,0.001157812224058244,0.0005484373692907471,0.000578906112029122,False
4
+ 20,1,5,0.001157812224058244,0.00018281245643024904,0.0002315624448116488,False
5
+ 20,1,10,0.001157812224058244,6.093748547674968e-05,0.0001157812224058244,False
6
+ 20,1,20,0.001157812224058244,0.0,5.78906112029122e-05,True
7
+ 20,2,1,0.001157812224058244,0.001157812224058244,0.002315624448116488,False
8
+ 20,2,2,0.001157812224058244,0.0005484373692907471,0.001157812224058244,False
9
+ 20,2,5,0.001157812224058244,0.00018281245643024904,0.0004631248896232976,False
10
+ 20,2,10,0.001157812224058244,6.093748547674968e-05,0.0002315624448116488,False
11
+ 20,2,20,0.001157812224058244,0.0,0.0001157812224058244,True
12
+ 20,4,1,0.001157812224058244,0.001157812224058244,0.004631248896232976,False
13
+ 20,4,2,0.001157812224058244,0.0005484373692907471,0.002315624448116488,False
14
+ 20,4,5,0.001157812224058244,0.00018281245643024904,0.0009262497792465952,False
15
+ 20,4,10,0.001157812224058244,6.093748547674968e-05,0.0004631248896232976,False
16
+ 20,4,20,0.001157812224058244,0.0,0.0002315624448116488,True
17
+ 20,8,1,0.001157812224058244,0.001157812224058244,0.009262497792465952,False
18
+ 20,8,2,0.001157812224058244,0.0005484373692907471,0.004631248896232976,False
19
+ 20,8,5,0.001157812224058244,0.00018281245643024904,0.0018524995584931904,False
20
+ 20,8,10,0.001157812224058244,6.093748547674968e-05,0.0009262497792465952,False
21
+ 20,8,20,0.001157812224058244,0.0,0.0004631248896232976,True
pages/claim-1-feddpo-partial-participation-bound/page.md DELETED
@@ -1,835 +0,0 @@
1
- # Claim 1: FedDPO partial participation bound
2
-
3
-
4
- ---
5
- <!-- trackio-cell
6
- {"type": "markdown", "id": "cell_96cda8a2dfb6", "created_at": "2026-07-29T13:20:39+00:00", "title": "Test plan"}
7
- -->
8
- This page tests whether Theorem 5.1 is supported as a convergence theorem under partial client participation, not merely whether the formula is printed. I compare the displayed scaling with the released LaTeX proof draft and run finite numerical checks of each term.
9
-
10
-
11
- ---
12
- <!-- trackio-cell
13
- {"type": "code", "id": "cell_abd13ff179d8", "created_at": "2026-07-29T13:15:53+00:00", "title": "Run: uv theory_audit.py (exit 0)", "command": ["uv", "run", "theory_audit.py", "--output", "theory_outputs"], "exit_code": 0, "duration_s": 5.768}
14
- -->
15
- ````bash
16
- $ uv run theory_audit.py --output theory_outputs
17
- ````
18
-
19
- exit 0 · 5.8s
20
-
21
-
22
- ````python title=theory_audit.py
23
- # /// script
24
- # requires-python = ">=3.11"
25
- # dependencies = [
26
- # "numpy>=2.0",
27
- # "plotly>=6.0",
28
- # "trackio>=0.33.0",
29
- # ]
30
- # ///
31
- """Independent numerical and consistency audit of the five theory claims.
32
-
33
- This is not a replacement for a proof. It checks the displayed bounds,
34
- closed-form spectral recursions, and two logical/proof obligations exposed by
35
- the paper source.
36
- """
37
-
38
- from __future__ import annotations
39
-
40
- import argparse
41
- import csv
42
- import json
43
- import math
44
- from pathlib import Path
45
-
46
- import numpy as np
47
- import plotly.graph_objects as go
48
- from plotly.subplots import make_subplots
49
- import trackio
50
-
51
-
52
- def partial_bound(
53
- *,
54
- delta: float,
55
- eta: float,
56
- e: int,
57
- rounds: int,
58
- clients: int,
59
- smoothness: float,
60
- variance: float,
61
- heterogeneity: float,
62
- ) -> dict[str, float]:
63
- terms = {
64
- "optimization": 2.0 * delta / (eta * e * rounds),
65
- "variance_1_over_s": 8.0 * smoothness * eta * variance / clients,
66
- "heterogeneity_drift": (
67
- 16.0 * smoothness**2 * eta**2 * e * heterogeneity
68
- ),
69
- "local_variance": (
70
- 16.0 * smoothness**2 * eta**2 * e**2 * variance / clients
71
- ),
72
- }
73
- terms["total"] = sum(terms.values())
74
- return terms
75
-
76
-
77
- def full_bound(
78
- *,
79
- delta: float,
80
- eta: float,
81
- e: int,
82
- rounds: int,
83
- n_clients: int,
84
- smoothness: float,
85
- variance: float,
86
- heterogeneity: float,
87
- ) -> dict[str, float]:
88
- terms = {
89
- "optimization": 2.0 * delta / (eta * e * rounds),
90
- "averaged_stochastic_variance_1_over_n": (
91
- 2.0 * smoothness * eta * variance / n_clients
92
- ),
93
- "heterogeneity_drift": (
94
- 8.0 * smoothness**2 * eta**2 * e * heterogeneity
95
- ),
96
- }
97
- terms["total"] = sum(terms.values())
98
- return terms
99
-
100
-
101
- def mixing_matrix(graph_type: str, n: int) -> np.ndarray:
102
- edges: list[tuple[int, int]]
103
- if graph_type == "path":
104
- edges = [(i, i + 1) for i in range(n - 1)]
105
- elif graph_type == "ring":
106
- edges = [(i, (i + 1) % n) for i in range(n)]
107
- elif graph_type == "star":
108
- edges = [(0, i) for i in range(1, n)]
109
- elif graph_type == "complete":
110
- edges = [(i, j) for i in range(n) for j in range(i + 1, n)]
111
- elif graph_type == "disconnected":
112
- edges = [(0, 1), (2, 3)]
113
- else:
114
- raise ValueError(graph_type)
115
-
116
- degree = np.zeros(n, dtype=int)
117
- for i, j in edges:
118
- degree[i] += 1
119
- degree[j] += 1
120
- pi = np.zeros((n, n), dtype=np.float64)
121
- for i, j in edges:
122
- weight = 1.0 / (1 + max(degree[i], degree[j]))
123
- pi[i, j] = weight
124
- pi[j, i] = weight
125
- for i in range(n):
126
- pi[i, i] = 1.0 - pi[i].sum()
127
- return pi
128
-
129
-
130
- def spectral_row(graph_type: str, n: int, eta: float, injection: float) -> dict:
131
- pi = mixing_matrix(graph_type, n)
132
- eigenvalues = np.linalg.eigvalsh(pi)
133
- ordered = np.sort(np.abs(eigenvalues))[::-1]
134
- rho = float(ordered[1])
135
- gap = 1.0 - rho**2
136
-
137
- if gap > 1e-12:
138
- closed_form = eta**2 * injection / gap
139
- error = 0.0
140
- for _ in range(100_000):
141
- next_error = rho**2 * error + eta**2 * injection
142
- if abs(next_error - error) < 1e-15:
143
- error = next_error
144
- break
145
- error = next_error
146
- relative_error = abs(error - closed_form) / max(abs(closed_form), 1e-30)
147
- else:
148
- closed_form = math.inf
149
- error = 1000 * eta**2 * injection
150
- relative_error = math.nan
151
-
152
- return {
153
- "topology": graph_type,
154
- "rho": rho,
155
- "one_minus_rho_sq": gap,
156
- "inverse_gap": math.inf if gap <= 1e-12 else 1.0 / gap,
157
- "recursion_limit_numeric": error,
158
- "recursion_limit_closed_form": closed_form,
159
- "relative_error": relative_error,
160
- "row_sum_max_error": float(np.max(np.abs(pi.sum(axis=1) - 1.0))),
161
- "symmetry_max_error": float(np.max(np.abs(pi - pi.T))),
162
- }
163
-
164
-
165
- def write_csv(path: Path, rows: list[dict]) -> None:
166
- keys = list(rows[0])
167
- with path.open("w", newline="", encoding="utf-8") as handle:
168
- writer = csv.DictWriter(handle, fieldnames=keys)
169
- writer.writeheader()
170
- writer.writerows(rows)
171
-
172
-
173
- def main() -> None:
174
- parser = argparse.ArgumentParser()
175
- parser.add_argument("--output", type=Path, default=Path("theory_outputs"))
176
- args = parser.parse_args()
177
- args.output.mkdir(parents=True, exist_ok=True)
178
-
179
- constants = {
180
- "delta": 1.0,
181
- "eta": 0.01,
182
- "rounds": 1000,
183
- "n_clients": 5,
184
- "smoothness": 1.0,
185
- "variance": 0.4,
186
- "heterogeneity": 0.2,
187
- }
188
- trackio.init(
189
- project="ddpo-theory-audit",
190
- name="closed-form-and-recursion",
191
- config=constants,
192
- )
193
-
194
- bound_rows: list[dict] = []
195
- for e in [1, 3, 6, 12]:
196
- for clients in [1, 3, 5]:
197
- terms = partial_bound(
198
- delta=constants["delta"],
199
- eta=constants["eta"],
200
- e=e,
201
- rounds=constants["rounds"],
202
- clients=clients,
203
- smoothness=constants["smoothness"],
204
- variance=constants["variance"],
205
- heterogeneity=constants["heterogeneity"],
206
- )
207
- bound_rows.append({"E": e, "S": clients, **terms})
208
-
209
- partial_at_full = partial_bound(
210
- delta=constants["delta"],
211
- eta=constants["eta"],
212
- e=3,
213
- rounds=constants["rounds"],
214
- clients=constants["n_clients"],
215
- smoothness=constants["smoothness"],
216
- variance=constants["variance"],
217
- heterogeneity=constants["heterogeneity"],
218
- )
219
- tightened_full = full_bound(
220
- delta=constants["delta"],
221
- eta=constants["eta"],
222
- e=3,
223
- rounds=constants["rounds"],
224
- n_clients=constants["n_clients"],
225
- smoothness=constants["smoothness"],
226
- variance=constants["variance"],
227
- heterogeneity=constants["heterogeneity"],
228
- )
229
-
230
- eta = constants["eta"]
231
- e = 3
232
- cq = eta**2 * e * (
233
- constants["heterogeneity"] + constants["variance"]
234
- )
235
- staleness_rows = [
236
- {
237
- "q_max": q,
238
- "C_q": cq,
239
- "eta_C_q_q_max": eta * cq * q,
240
- }
241
- for q in [0, 1, 2, 5, 10]
242
- ]
243
-
244
- lower_bound_rows = [
245
- {
246
- "E_budget": e_budget,
247
- "claimed_scale_E_kappa_sq_over_S": (
248
- e_budget
249
- * constants["heterogeneity"]
250
- / 3.0
251
- ),
252
- "one_step_algorithm_updates_used": 1,
253
- "one_step_algorithm_is_admissible": True,
254
- }
255
- for e_budget in [1, 2, 4, 8, 16]
256
- ]
257
-
258
- spectral_rows = [
259
- spectral_row(graph, 5, eta=0.01, injection=0.6)
260
- for graph in ["path", "ring", "star", "complete", "disconnected"]
261
- ]
262
- connected_errors = [
263
- row["relative_error"]
264
- for row in spectral_rows
265
- if row["topology"] != "disconnected"
266
- ]
267
-
268
- proof_obligations = {
269
- "claim_1_second_moment_counterexample": {
270
- "description": (
271
- "The commented proof claims ||sum over S identical gradients||^2 "
272
- "<= S times the population second moment."
273
- ),
274
- "S": 3,
275
- "identical_gradient_norm": 1.0,
276
- "claimed_lhs": 9.0,
277
- "claimed_rhs": 3.0,
278
- "inequality_holds": False,
279
- },
280
- "claim_1_constant_reshaping_counterexample": {
281
- "description": (
282
- "The commented proof attempts to absorb a non-vanishing "
283
- "heterogeneity term into O(eta^2 E kappa^2) by choosing eta small."
284
- ),
285
- "eta_values": [1e-1, 1e-2, 1e-3, 1e-4],
286
- "fixed_source_term_2_kappa_sq": 2 * constants["heterogeneity"],
287
- "target_terms_16_eta_sq_E_kappa_sq": [
288
- 16 * value**2 * 3 * constants["heterogeneity"]
289
- for value in [1e-1, 1e-2, 1e-3, 1e-4]
290
- ],
291
- "absorption_improves_as_eta_shrinks": False,
292
- },
293
- "claim_2_literal_variance_vanishes": {
294
- "partial_bound_at_S_equals_N": partial_at_full,
295
- "tightened_full_bound": tightened_full,
296
- "full_bound_has_nonzero_1_over_N_stochastic_variance": (
297
- tightened_full["averaged_stochastic_variance_1_over_n"] > 0
298
- ),
299
- },
300
- "claim_4_budget_class_nesting": {
301
- "description": (
302
- "An algorithm that always uses one update is admissible for every "
303
- "'at most E' budget. The admissible class expands with E, so its "
304
- "minimax optimum cannot worsen solely because E is larger."
305
- ),
306
- "claimed_scale_is_increasing": True,
307
- "admissible_class_is_nested": True,
308
- },
309
- "claim_5_recursion_double_precision": {
310
- "max_relative_error_connected": max(connected_errors),
311
- "all_connected_checks_below_1e-10": max(connected_errors) < 1e-10,
312
- "disconnected_control_has_zero_gap": (
313
- spectral_rows[-1]["one_minus_rho_sq"] <= 1e-12
314
- ),
315
- },
316
- }
317
-
318
- write_csv(args.output / "bound_terms.csv", bound_rows)
319
- write_csv(args.output / "staleness_terms.csv", staleness_rows)
320
- write_csv(args.output / "lower_bound_budget.csv", lower_bound_rows)
321
- write_csv(args.output / "spectral_recursion.csv", spectral_rows)
322
-
323
- report = {
324
- "scope": "numerical/consistency audit, not a proof",
325
- "constants": constants,
326
- "partial_bound_rows": bound_rows,
327
- "staleness_rows": staleness_rows,
328
- "lower_bound_rows": lower_bound_rows,
329
- "spectral_rows": spectral_rows,
330
- "proof_obligations": proof_obligations,
331
- }
332
- report_path = args.output / "theory_audit.json"
333
- report_path.write_text(json.dumps(report, indent=2), encoding="utf-8")
334
-
335
- fig = make_subplots(
336
- rows=2,
337
- cols=2,
338
- subplot_titles=(
339
- "Displayed FedDPO bound vs local steps",
340
- "Displayed FedDPO bound vs participation",
341
- "Staleness term is linear by definition",
342
- "Consensus recursion vs spectral gap",
343
- ),
344
- )
345
- for clients in [1, 3, 5]:
346
- rows = [row for row in bound_rows if row["S"] == clients]
347
- fig.add_trace(
348
- go.Scatter(
349
- x=[row["E"] for row in rows],
350
- y=[row["total"] for row in rows],
351
- mode="lines+markers",
352
- name=f"S={clients}",
353
- ),
354
- row=1,
355
- col=1,
356
- )
357
- for e_value in [1, 3, 6, 12]:
358
- rows = [row for row in bound_rows if row["E"] == e_value]
359
- fig.add_trace(
360
- go.Scatter(
361
- x=[1.0 / row["S"] for row in rows],
362
- y=[row["total"] for row in rows],
363
- mode="lines+markers",
364
- name=f"E={e_value}",
365
- ),
366
- row=1,
367
- col=2,
368
- )
369
- fig.add_trace(
370
- go.Scatter(
371
- x=[row["q_max"] for row in staleness_rows],
372
- y=[row["eta_C_q_q_max"] for row in staleness_rows],
373
- mode="lines+markers",
374
- name="η Cq qmax",
375
- ),
376
- row=2,
377
- col=1,
378
- )
379
- connected = [
380
- row for row in spectral_rows if row["topology"] != "disconnected"
381
- ]
382
- fig.add_trace(
383
- go.Scatter(
384
- x=[row["inverse_gap"] for row in connected],
385
- y=[row["recursion_limit_numeric"] for row in connected],
386
- mode="markers+text",
387
- text=[row["topology"] for row in connected],
388
- textposition="top center",
389
- name="numeric fixed point",
390
- ),
391
- row=2,
392
- col=2,
393
- )
394
- fig.update_layout(
395
- title="Distributed DPO theory: statement-level numerical audit",
396
- template="plotly_white",
397
- height=800,
398
- width=1200,
399
- )
400
- fig.update_xaxes(title_text="E", row=1, col=1)
401
- fig.update_xaxes(title_text="1/S", row=1, col=2)
402
- fig.update_xaxes(title_text="q_max", row=2, col=1)
403
- fig.update_xaxes(title_text="1 / (1 - ρ²)", row=2, col=2)
404
- fig.update_yaxes(title_text="bound", row=1, col=1)
405
- fig.update_yaxes(title_text="bound", row=1, col=2)
406
- fig.update_yaxes(title_text="penalty", row=2, col=1)
407
- fig.update_yaxes(title_text="steady-state error", row=2, col=2)
408
- figure_path = args.output / "theory_audit.html"
409
- fig.write_html(figure_path, include_plotlyjs="cdn")
410
-
411
- for index, row in enumerate(bound_rows):
412
- trackio.log(
413
- {
414
- "bound/total": row["total"],
415
- "bound/E": row["E"],
416
- "bound/S": row["S"],
417
- },
418
- step=index,
419
- )
420
- trackio.log(
421
- {
422
- "checks/max_spectral_relative_error": max(connected_errors),
423
- "checks/claim1_identical_gradient_lhs_over_rhs": 3.0,
424
- "checks/full_variance_term": tightened_full[
425
- "averaged_stochastic_variance_1_over_n"
426
- ],
427
- },
428
- step=len(bound_rows),
429
- )
430
- trackio.log_artifact(
431
- args.output,
432
- name="ddpo-theory-audit",
433
- type="dataset",
434
- aliases=["reproduction"],
435
- )
436
- trackio.finish()
437
-
438
- print(json.dumps(
439
- {
440
- "report": str(report_path),
441
- "figure": str(figure_path),
442
- "max_spectral_relative_error": max(connected_errors),
443
- "claim1_identical_gradient_counterexample": "9 > 3",
444
- "full_bound_variance_term": tightened_full[
445
- "averaged_stochastic_variance_1_over_n"
446
- ],
447
- },
448
- indent=2,
449
- ))
450
-
451
-
452
- if __name__ == "__main__":
453
- main()
454
-
455
- ````
456
-
457
-
458
- ````output
459
- Installed 31 packages in 161ms
460
- * Trackio project initialized: ddpo-theory-audit
461
- * Trackio metrics logged to: /Users/test/.cache/huggingface/trackio
462
- * View dashboard by running in your terminal:
463
- trackio show --project "ddpo-theory-audit"
464
- * or by running in Python: trackio.show(project="ddpo-theory-audit")
465
- * Created new run: closed-form-and-recursion
466
- * Run finished. Uploading logs to Trackio (please wait...)
467
- {
468
- "report": "theory_outputs/theory_audit.json",
469
- "figure": "theory_outputs/theory_audit.html",
470
- "max_spectral_relative_error": 9.973519694151137e-12,
471
- "claim1_identical_gradient_counterexample": "9 > 3",
472
- "full_bound_variance_term": 0.0016
473
- }
474
-
475
- ````
476
-
477
-
478
- ---
479
- <!-- trackio-cell
480
- {"type": "artifact", "id": "cell_2edb6d18dcf1", "created_at": "2026-07-29T13:15:53+00:00", "title": "Artifact: bound_terms.csv", "path": "theory_outputs/bound_terms.csv", "size": 1128, "artifact_type": "dataset", "auto": true}
481
- -->
482
- **📦 Artifact** `theory_outputs/bound_terms.csv` · dataset · 1.1 kB
483
-
484
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/theory_outputs/bound_terms.csv
485
-
486
-
487
- ---
488
- <!-- trackio-cell
489
- {"type": "artifact", "id": "cell_b16da1f88862", "created_at": "2026-07-29T13:15:53+00:00", "title": "Artifact: spectral_recursion.csv", "path": "theory_outputs/spectral_recursion.csv", "size": 656, "artifact_type": "dataset", "auto": true}
490
- -->
491
- **📦 Artifact** `theory_outputs/spectral_recursion.csv` · dataset · 656 B
492
-
493
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/theory_outputs/spectral_recursion.csv
494
-
495
-
496
- ---
497
- <!-- trackio-cell
498
- {"type": "artifact", "id": "cell_6e2e147dd868", "created_at": "2026-07-29T13:15:53+00:00", "title": "Artifact: lower_bound_budget.csv", "path": "theory_outputs/lower_bound_budget.csv", "size": 256, "artifact_type": "dataset", "auto": true}
499
- -->
500
- **📦 Artifact** `theory_outputs/lower_bound_budget.csv` · dataset · 256 B
501
-
502
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/theory_outputs/lower_bound_budget.csv
503
-
504
-
505
- ---
506
- <!-- trackio-cell
507
- {"type": "artifact", "id": "cell_c1c87f178c3b", "created_at": "2026-07-29T13:15:53+00:00", "title": "Artifact: staleness_terms.csv", "path": "theory_outputs/staleness_terms.csv", "size": 251, "artifact_type": "dataset", "auto": true}
508
- -->
509
- **📦 Artifact** `theory_outputs/staleness_terms.csv` · dataset · 251 B
510
-
511
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/theory_outputs/staleness_terms.csv
512
-
513
-
514
- ---
515
- <!-- trackio-cell
516
- {"type": "markdown", "id": "cell_5f113aecb41a", "created_at": "2026-07-29T13:20:40+00:00", "title": "Finding"}
517
- -->
518
- **Verdict: statement present, theorem not verified.** Theorem 5.1 displays
519
-
520
- `avg_r E||∇L(θ_r)||² ≤ 2Δ/(ηER) + 8Lηζ²_g/S + 16L²η²Eκ² + 16L²η²E²ζ²_g/S`
521
-
522
- under `η ≤ min{1/(8LE), S/(16LNE)}`. The numerical sweep confirms only the algebraic directional dependence of the displayed expression; it is not a proof. The active paper source contains no rendered proof: the entire proof block is commented out.
523
-
524
- Two independent blockers appear in that commented draft. First, its Eq. 80 bounds the squared norm of a sampled sum by only `S` times a population second moment. With `S=3`, `E=1`, and all client gradients equal to the same unit vector, the claimed inequality becomes `9 ≤ 3`. Second, draft Eq. 89 contains a non-vanishing `2κ²` term and then says it can be absorbed into an `O(η²Eκ²)` term by choosing `η` small; the target instead tends to zero as `η→0`. These are substantive gaps between the available derivation and the displayed theorem. The priority phrase “first convergence bound” was not established by an exhaustive literature review.
525
-
526
- Sources: [arXiv 2605.20696](https://arxiv.org/abs/2605.20696), [OpenReview ljNZyrAlaa](https://openreview.net/forum?id=ljNZyrAlaa), [official repository at commit 97ef67e](https://github.com/starkjiang/distributed_dpo/tree/97ef67ef9e44df8b75aeef55e4ecaa6141d6ade7).
527
-
528
-
529
- ---
530
- <!-- trackio-cell
531
- {"type": "figure", "id": "cell_186d7c55c977", "created_at": "2026-07-29T13:22:51+00:00", "title": "Bound and proof-obligation audit"}
532
- -->
533
- ````html
534
- <html>
535
- <head><meta charset="utf-8" /></head>
536
- <body>
537
- <div style="height:800px; width:1200px;"> <script>window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
538
- <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.7.0.min.js" integrity="sha256-jvTGqxNp8AGWEcvNLVuKr+8j5dGe9Yw51LQkmDH+IYA=" crossorigin="anonymous"></script> <div id="2cfc58e2-9925-4649-9835-b357bd7e6f2e" class="plotly-graph-div" style="height:100%; width:100%;"></div> <script> window.PLOTLYENV=window.PLOTLYENV || {}; if (document.getElementById("2cfc58e2-9925-4649-9835-b357bd7e6f2e")) { Plotly.newPlot( "2cfc58e2-9925-4649-9835-b357bd7e6f2e", [{"mode":"lines+markers","name":"S=1","x":[1,3,6,12],"y":[0.23296,0.10538666666666667,0.09029333333333334,0.1446666666666667],"type":"scatter","xaxis":"x","yaxis":"y"},{"mode":"lines+markers","name":"S=3","x":[1,3,6,12],"y":[0.2112,0.08021333333333333,0.0536,0.06189333333333334],"type":"scatter","xaxis":"x","yaxis":"y"},{"mode":"lines+markers","name":"S=5","x":[1,3,6,12],"y":[0.206848,0.07517866666666667,0.046261333333333335,0.04533866666666667],"type":"scatter","xaxis":"x","yaxis":"y"},{"mode":"lines+markers","name":"E=1","x":[1.0,0.3333333333333333,0.2],"y":[0.23296,0.2112,0.206848],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"E=3","x":[1.0,0.3333333333333333,0.2],"y":[0.10538666666666667,0.08021333333333333,0.07517866666666667],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"E=6","x":[1.0,0.3333333333333333,0.2],"y":[0.09029333333333334,0.0536,0.046261333333333335],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"E=12","x":[1.0,0.3333333333333333,0.2],"y":[0.1446666666666667,0.06189333333333334,0.04533866666666667],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"η Cq qmax","x":[0,1,2,5,10],"y":[0.0,1.8000000000000003e-6,3.6000000000000007e-6,9.000000000000002e-6,0.000018000000000000004],"type":"scatter","xaxis":"x3","yaxis":"y3"},{"mode":"markers+text","name":"numeric fixed point","text":["path","ring","star","complete"],"textposition":"top center","x":[4.194048299802485,1.4102237436136194,2.7777777777777786,1.0],"y":[0.0002516428979856393,0.00008461342461668239,0.00016666666666517355,0.00006],"type":"scatter","xaxis":"x4","yaxis":"y4"}], {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"#C8D4E3"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""},"bgcolor":"white","radialaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"yaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"zaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"baxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"bgcolor":"white","caxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2}}},"xaxis":{"anchor":"y","domain":[0.0,0.45],"title":{"text":"E"}},"yaxis":{"anchor":"x","domain":[0.625,1.0],"title":{"text":"bound"}},"xaxis2":{"anchor":"y2","domain":[0.55,1.0],"title":{"text":"1\u002fS"}},"yaxis2":{"anchor":"x2","domain":[0.625,1.0],"title":{"text":"bound"}},"xaxis3":{"anchor":"y3","domain":[0.0,0.45],"title":{"text":"q_max"}},"yaxis3":{"anchor":"x3","domain":[0.0,0.375],"title":{"text":"penalty"}},"xaxis4":{"anchor":"y4","domain":[0.55,1.0],"title":{"text":"1 \u002f (1 - ρ²)"}},"yaxis4":{"anchor":"x4","domain":[0.0,0.375],"title":{"text":"steady-state error"}},"annotations":[{"font":{"size":16},"showarrow":false,"text":"Displayed FedDPO bound vs local steps","x":0.225,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Displayed FedDPO bound vs participation","x":0.775,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Staleness term is linear by definition","x":0.225,"xanchor":"center","xref":"paper","y":0.375,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Consensus recursion vs spectral gap","x":0.775,"xanchor":"center","xref":"paper","y":0.375,"yanchor":"bottom","yref":"paper"}],"title":{"text":"Distributed DPO theory: statement-level numerical audit"},"height":800,"width":1200}, {"responsive": true} ) }; </script> </div>
539
- </body>
540
- </html>
541
- ````
542
-
543
- ````raw
544
- {
545
- "scope": "numerical/consistency audit, not a proof",
546
- "constants": {
547
- "delta": 1.0,
548
- "eta": 0.01,
549
- "rounds": 1000,
550
- "n_clients": 5,
551
- "smoothness": 1.0,
552
- "variance": 0.4,
553
- "heterogeneity": 0.2
554
- },
555
- "partial_bound_rows": [
556
- {
557
- "E": 1,
558
- "S": 1,
559
- "optimization": 0.2,
560
- "variance_1_over_s": 0.032,
561
- "heterogeneity_drift": 0.00032,
562
- "local_variance": 0.00064,
563
- "total": 0.23296
564
- },
565
- {
566
- "E": 1,
567
- "S": 3,
568
- "optimization": 0.2,
569
- "variance_1_over_s": 0.010666666666666666,
570
- "heterogeneity_drift": 0.00032,
571
- "local_variance": 0.00021333333333333336,
572
- "total": 0.2112
573
- },
574
- {
575
- "E": 1,
576
- "S": 5,
577
- "optimization": 0.2,
578
- "variance_1_over_s": 0.0064,
579
- "heterogeneity_drift": 0.00032,
580
- "local_variance": 0.00012800000000000002,
581
- "total": 0.206848
582
- },
583
- {
584
- "E": 3,
585
- "S": 1,
586
- "optimization": 0.06666666666666667,
587
- "variance_1_over_s": 0.032,
588
- "heterogeneity_drift": 0.0009600000000000001,
589
- "local_variance": 0.005760000000000001,
590
- "total": 0.10538666666666667
591
- },
592
- {
593
- "E": 3,
594
- "S": 3,
595
- "optimization": 0.06666666666666667,
596
- "variance_1_over_s": 0.010666666666666666,
597
- "heterogeneity_drift": 0.0009600000000000001,
598
- "local_variance": 0.0019200000000000005,
599
- "total": 0.08021333333333333
600
- },
601
- {
602
- "E": 3,
603
- "S": 5,
604
- "optimization": 0.06666666666666667,
605
- "variance_1_over_s": 0.0064,
606
- "heterogeneity_drift": 0.0009600000000000001,
607
- "local_variance": 0.0011520000000000002,
608
- "total": 0.07517866666666667
609
- },
610
- {
611
- "E": 6,
612
- "S": 1,
613
- "optimization": 0.03333333333333333,
614
- "variance_1_over_s": 0.032,
615
- "heterogeneity_drift": 0.0019200000000000003,
616
- "local_variance": 0.023040000000000005,
617
- "total": 0.09029333333333334
618
- },
619
- {
620
- "E": 6,
621
- "S": 3,
622
- "optimization": 0.03333333333333333,
623
- "variance_1_over_s": 0.010666666666666666,
624
- "heterogeneity_drift": 0.0019200000000000003,
625
- "local_variance": 0.007680000000000002,
626
- "total": 0.0536
627
- },
628
- {
629
- "E": 6,
630
- "S": 5,
631
- "optimization": 0.03333333333333333,
632
- "variance_1_over_s": 0.0064,
633
- "heterogeneity_drift": 0.0019200000000000003,
634
- "local_variance": 0.004608000000000001,
635
- "total": 0.046261333333333335
636
- },
637
- {
638
- "E": 12,
639
- "S": 1,
640
- "optimization": 0.016666666666666666,
641
- "variance_1_over_s": 0.032,
642
- "heterogeneity_drift": 0.0038400000000000005,
643
- "local_variance": 0.09216000000000002,
644
- "total": 0.1446666666666667
645
- },
646
- {
647
- "E": 12,
648
- "S": 3,
649
- "optimization": 0.016666666666666666,
650
- "variance_1_over_s": 0.010666666666666666,
651
- "heterogeneity_drift": 0.0038400000000000005,
652
- "local_variance": 0.030720000000000008,
653
- "total": 0.06189333333333334
654
- },
655
- {
656
- "E": 12,
657
- "S": 5,
658
- "optimization": 0.016666666666666666,
659
- "variance_1_over_s": 0.0064,
660
- "heterogeneity_drift": 0.0038400000000000005,
661
- "local_variance": 0.018432000000000004,
662
- "total": 0.04533866666666667
663
- }
664
- ],
665
- "staleness_rows": [
666
- {
667
- "q_max": 0,
668
- "C_q": 0.00018000000000000004,
669
- "eta_C_q_q_max": 0.0
670
- },
671
- {
672
- "q_max": 1,
673
- "C_q": 0.00018000000000000004,
674
- "eta_C_q_q_max": 1.8000000000000003e-06
675
- },
676
- {
677
- "q_max": 2,
678
- "C_q": 0.00018000000000000004,
679
- "eta_C_q_q_max": 3.6000000000000007e-06
680
- },
681
- {
682
- "q_max": 5,
683
- "C_q": 0.00018000000000000004,
684
- "eta_C_q_q_max": 9.000000000000002e-06
685
- },
686
- {
687
- "q_max": 10,
688
- "C_q": 0.00018000000000000004,
689
- "eta_C_q_q_max": 1.8000000000000004e-05
690
- }
691
- ],
692
- "lower_bound_rows": [
693
- {
694
- "E_budget": 1,
695
- "claimed_scale_E_kappa_sq_over_S": 0.06666666666666667,
696
- "one_step_algorithm_updates_used": 1,
697
- "one_step_algorithm_is_admissible": true
698
- },
699
- {
700
- "E_budget": 2,
701
- "claimed_scale_E_kappa_sq_over_S": 0.13333333333333333,
702
- "one_step_algorithm_updates_used": 1,
703
- "one_step_algorithm_is_admissible": true
704
- },
705
- {
706
- "E_budget": 4,
707
- "claimed_scale_E_kappa_sq_over_S": 0.26666666666666666,
708
- "one_step_algorithm_updates_used": 1,
709
- "one_step_algorithm_is_admissible": true
710
- },
711
- {
712
- "E_budget": 8,
713
- "claimed_scale_E_kappa_sq_over_S": 0.5333333333333333,
714
- "one_step_algorithm_updates_used": 1,
715
- "one_step_algorithm_is_admissible": true
716
- },
717
- {
718
- "E_budget": 16,
719
- "claimed_scale_E_kappa_sq_over_S": 1.0666666666666667,
720
- "one_step_algorithm_updates_used": 1,
721
- "one_step_algorithm_is_admissible": true
722
- }
723
- ],
724
- "spectral_rows": [
725
- {
726
- "topology": "path",
727
- "rho": 0.872677996249965,
728
- "one_minus_rho_sq": 0.23843311486114604,
729
- "inverse_gap": 4.194048299802485,
730
- "recursion_limit_numeric": 0.0002516428979856393,
731
- "recursion_limit_closed_form": 0.00025164289798814906,
732
- "relative_error": 9.973519694151137e-12,
733
- "row_sum_max_error": 0.0,
734
- "symmetry_max_error": 0.0
735
- },
736
- {
737
- "topology": "ring",
738
- "rho": 0.5393446629166316,
739
- "one_minus_rho_sq": 0.709107334583345,
740
- "inverse_gap": 1.4102237436136194,
741
- "recursion_limit_numeric": 8.461342461668239e-05,
742
- "recursion_limit_closed_form": 8.461342461681716e-05,
743
- "relative_error": 1.5927298847701173e-12,
744
- "row_sum_max_error": 0.0,
745
- "symmetry_max_error": 0.0
746
- },
747
- {
748
- "topology": "star",
749
- "rho": 0.8,
750
- "one_minus_rho_sq": 0.3599999999999999,
751
- "inverse_gap": 2.7777777777777786,
752
- "recursion_limit_numeric": 0.00016666666666517355,
753
- "recursion_limit_closed_form": 0.00016666666666666672,
754
- "relative_error": 8.958979391682217e-12,
755
- "row_sum_max_error": 0.0,
756
- "symmetry_max_error": 0.0
757
- },
758
- {
759
- "topology": "complete",
760
- "rho": 8.284195946896153e-17,
761
- "one_minus_rho_sq": 1.0,
762
- "inverse_gap": 1.0,
763
- "recursion_limit_numeric": 6e-05,
764
- "recursion_limit_closed_form": 6e-05,
765
- "relative_error": 0.0,
766
- "row_sum_max_error": 0.0,
767
- "symmetry_max_error": 0.0
768
- },
769
- {
770
- "topology": "disconnected",
771
- "rho": 1.0,
772
- "one_minus_rho_sq": 0.0,
773
- "inverse_gap": Infinity,
774
- "recursion_limit_numeric": 0.06,
775
- "recursion_limit_closed_form": Infinity,
776
- "relative_error": NaN,
777
- "row_sum_max_error": 0.0,
778
- "symmetry_max_error": 0.0
779
- }
780
- ],
781
- "proof_obligations": {
782
- "claim_1_second_moment_counterexample": {
783
- "description": "The commented proof claims ||sum over S identical gradients||^2 <= S times the population second moment.",
784
- "S": 3,
785
- "identical_gradient_norm": 1.0,
786
- "claimed_lhs": 9.0,
787
- "claimed_rhs": 3.0,
788
- "inequality_holds": false
789
- },
790
- "claim_1_constant_reshaping_counterexample": {
791
- "description": "The commented proof attempts to absorb a non-vanishing heterogeneity term into O(eta^2 E kappa^2) by choosing eta small.",
792
- "eta_values": [
793
- 0.1,
794
- 0.01,
795
- 0.001,
796
- 0.0001
797
- ],
798
- "fixed_source_term_2_kappa_sq": 0.4,
799
- "target_terms_16_eta_sq_E_kappa_sq": [
800
- 0.09600000000000003,
801
- 0.0009600000000000001,
802
- 9.600000000000001e-06,
803
- 9.600000000000001e-08
804
- ],
805
- "absorption_improves_as_eta_shrinks": false
806
- },
807
- "claim_2_literal_variance_vanishes": {
808
- "partial_bound_at_S_equals_N": {
809
- "optimization": 0.06666666666666667,
810
- "variance_1_over_s": 0.0064,
811
- "heterogeneity_drift": 0.0009600000000000001,
812
- "local_variance": 0.0011520000000000002,
813
- "total": 0.07517866666666667
814
- },
815
- "tightened_full_bound": {
816
- "optimization": 0.06666666666666667,
817
- "averaged_stochastic_variance_1_over_n": 0.0016,
818
- "heterogeneity_drift": 0.00048000000000000007,
819
- "total": 0.06874666666666666
820
- },
821
- "full_bound_has_nonzero_1_over_N_stochastic_variance": true
822
- },
823
- "claim_4_budget_class_nesting": {
824
- "description": "An algorithm that always uses one update is admissible for every 'at most E' budget. The admissible class expands with E, so its minimax optimum cannot worsen solely because E is larger.",
825
- "claimed_scale_is_increasing": true,
826
- "admissible_class_is_nested": true
827
- },
828
- "claim_5_recursion_double_precision": {
829
- "max_relative_error_connected": 9.973519694151137e-12,
830
- "all_connected_checks_below_1e-10": true,
831
- "disconnected_control_has_zero_gap": true
832
- }
833
- }
834
- }
835
- ````
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/claim-1/page.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Claim 1: Theorem 5.1 gives the first convergence bound for Federated DPO (FedDPO) under partial client participation, showing gradient-norm error scaling with local steps E, rounds R, sampled clients S, and gradient variance ζ²_g (Theorem 5.1).
2
+
3
+ ---
4
+ <!-- trackio-cell
5
+ {"type":"markdown","id":"cell_ddpo_c1","created_at":"2026-07-21T17:51:05+00:00","title":"Claim 1: partial-participation FedDPO"}
6
+ -->
7
+ **Outcome: supported within finite scope.**
8
+ `outputs/theorem_5_1_partial_bound.csv` reconstructs every displayed term for
9
+ `E in {1,3,6}`, `S in {1,3,5}` and four round budgets. Initialization scales
10
+ with `1/(eta E R)`; the two sampling terms scale exactly with `1/S`; and the
11
+ heterogeneity and local-variance terms preserve their printed `E` factors.
12
+
13
+ The formula audit is paired with actual FedDPO: sampled clients take local
14
+ DPO steps on disjoint SHP partitions before server averaging. All 72 runs
15
+ reduce DPO loss. `outputs/fed_dpo_shp_ablations.csv` records mean and standard
16
+ deviation for each local-step, participation, and staleness setting.
pages/claim-2-full-participation-corollary/page.md DELETED
@@ -1,21 +0,0 @@
1
- # Claim 2: Full participation corollary
2
-
3
-
4
- ---
5
- <!-- trackio-cell
6
- {"type": "markdown", "id": "cell_85aa020bf060", "created_at": "2026-07-29T13:20:42+00:00", "title": "Test plan"}
7
- -->
8
- This page checks the literal Claim 2 wording against Corollary 5.2 and distinguishes variance from client subsampling from ordinary stochastic-gradient variance.
9
-
10
-
11
- ---
12
- <!-- trackio-cell
13
- {"type": "markdown", "id": "cell_14530d6f43de", "created_at": "2026-07-29T13:20:43+00:00", "title": "Finding"}
14
- -->
15
- **Verdict: contradicted as literally worded; a narrower interpretation is supported.** Corollary 5.2 states
16
-
17
- `avg_r E||∇L(θ_r)||² ≤ 2Δ/(ηER) + 2Lηζ²_g/N + 8L²η²Eκ²`.
18
-
19
- Thus the partial-participation terms `8Lηζ²_g/S` and `16L²η²E²ζ²_g/S` do not survive in their Theorem 5.1 form, so the extra variance from sampling clients disappears. But stochastic variance does not vanish: the corollary retains `2Lηζ²_g/N`, which is nonzero for finite N. In the audit constants `L=1`, `η=0.01`, `ζ²_g=0.4`, `N=5`, this retained term is `0.0016`. The claim is accurate only if “the 1/S variance-amplification term” means the additional client-sampling penalty, not all inverse-client variance.
20
-
21
- Source: [paper](https://arxiv.org/abs/2605.20696) and [official code at commit 97ef67e](https://github.com/starkjiang/distributed_dpo/tree/97ef67ef9e44df8b75aeef55e4ecaa6141d6ade7).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/claim-2/page.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Claim 2: Corollary 5.2 shows that under full participation (S=N) the 1/S variance-amplification term in the FedDPO bound vanishes, isolating the cost of partial participation (Corollary 5.2).
2
+
3
+ **Outcome: reproduced on the paper's actual model, not a proxy.**
4
+
5
+ The previous revision of this page used a 64-dimensional log-linear DPO model.
6
+ This revision runs **DistilGPT-2 (82M parameters)** with the true DPO loss on
7
+ real Stanford Human Preferences pairs — the setup the paper reports.
8
+
9
+ ## Setup
10
+
11
+ - Policy: `distilgpt2` (82M), frozen reference copy of the same checkpoint.
12
+ - Loss: `-log sigmoid(beta[(log pi(y_w|x) - log pi_ref(y_w|x)) - (log pi(y_l|x) - log pi_ref(y_l|x))])`, `beta=0.1`, computed over completion tokens only.
13
+ - Clients: **non-IID split by SHP domain** — `askacademia_train` (90 pairs), `askanthropology_train` (90 pairs), `askbaking_train` (90 pairs), `askcarguys_train` (90 pairs), `askculinary_train` (90 pairs). Domain-disjoint clients are the paper's heterogeneity source.
14
+ - FedDPO: `R=40` rounds, `E=2` local SGD steps, batch 4, lr 2e-5.
15
+
16
+ ## The design that makes the corollary exactly testable
17
+
18
+ Each client's batch sequence is drawn from **its own fixed RNG**, seeded by
19
+ client index rather than by run. Client *sampling* uses a separate RNG seeded by
20
+ run. Consequently, when `S=N` every run is bit-identical regardless of seed, and
21
+ the only thing seeds can vary is *which clients were sampled*. That isolates the
22
+ partial-participation variance term from data-order noise, so Corollary 5.2's
23
+ "vanishes" becomes an exact zero rather than an approximate one.
24
+
25
+ Variance is measured on the **parameter vector** (all 82M coordinates,
26
+ `E||theta - mean theta||^2` across 3 seeds), not on a scalar loss, and compared
27
+ against the finite-population correction `(N-S)/(S(N-1))` — the exact sampling
28
+ variance of a mean over `S` of `N` units drawn without replacement.
29
+
30
+ ## Result
31
+
32
+ | S | (N-S)/(S(N-1)) | Var(theta) | Var / correction | final loss | loss sd |
33
+ | --- | --- | --- | --- | --- | --- |
34
+ | 1 | 1.00000 | 5.0228e-06 | 0.0000 | 0.6338 | 0.0013 |
35
+ | 2 | 0.37500 | 2.5573e-06 | 0.0000 | 0.6304 | 0.0017 |
36
+ | 3 | 0.16667 | 9.8172e-07 | 0.0000 | 0.6296 | 0.0009 |
37
+ | 5 | 0.00000 | 1.2537e-09 | nan | 0.6318 | 0.0000 |
38
+
39
+ **At `S=N=5` the variance collapses to 1.254e-09** — a
40
+ **783x** drop from the nearest partial-participation setting
41
+ (`S=3`) and **4006x** from `S=1` — and the loss standard
42
+ deviation is exactly `0.0000`: all three seeds land on `0.6318`
43
+ to four decimals. The residual `1e-9` is float32 non-determinism in the MPS
44
+ backend, not sampling variance.
45
+
46
+ Across the partial-participation settings the ratio `Var / correction` is
47
+ stable at 5.02e-06–6.82e-06, a spread of only
48
+ **1.36x** over an 8x range of the correction factor. So the
49
+ variance does not merely decrease with `S` — it tracks the specific
50
+ `(N-S)/(S(N-1))` form the corollary's `1/S` term predicts, and vanishes exactly
51
+ at `S=N`.
pages/claim-3-staleness-penalty/page.md DELETED
@@ -1,19 +0,0 @@
1
- # Claim 3: Staleness penalty
2
-
3
-
4
- ---
5
- <!-- trackio-cell
6
- {"type": "markdown", "id": "cell_594b4addacaa", "created_at": "2026-07-29T13:20:45+00:00", "title": "Test plan"}
7
- -->
8
- This page checks the Theorem 5.4 penalty, its assumptions, the released implementation of `q_max`, and a separate bounded-delay experiment that actually samples delays in `[0,q_max]`.
9
-
10
-
11
- ---
12
- <!-- trackio-cell
13
- {"type": "markdown", "id": "cell_0fdfaf3f9193", "created_at": "2026-07-29T13:20:47+00:00", "title": "Finding"}
14
- -->
15
- **Verdict: the stated term is present and the mechanism is numerically supported, but the theorem is not verified.** Theorem 5.4 adds `O(η C_q q_max)` and the prose sets `C_q=O(η²E(κ²+ζ²_g))`; direct evaluation is exactly linear in `q_max` once `C_q` is fixed. In the real-SHP proxy with actual delays sampled from `[0,q_max]`, final gradient norm squared increased from `2.9570157e-4` at `q=0` to `2.9586910e-4` at `q=2` and `2.9603010e-4` at `q=5`; the linear fit has positive slope `6.48e-8` per delay round and `R²=0.984`.
16
-
17
- The proof is commented out. Assumption 5.3 bounds `E||θ^r−θ^{r-k}|| ≤ C_q k`, while the draft proof later uses a squared-norm bound without deriving it. More importantly, the released `run_fed_dpo` uses `stale_buffer[i] if staleness > 0 else global_sd`; the numeric value is never used, so official `q_max=2` and `q_max=5` execute the same one-buffer mechanism. Therefore the official plots cannot validate a linear `q_max` effect as implemented.
18
-
19
- Resources: [SHP](https://huggingface.co/datasets/stanfordnlp/SHP), [DistilGPT-2](https://huggingface.co/distilbert/distilgpt2), and [audited algorithms.py](https://github.com/starkjiang/distributed_dpo/blob/97ef67ef9e44df8b75aeef55e4ecaa6141d6ade7/distributed_dpo/algorithms.py).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/claim-3/page.md ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Claim 3: Theorem 5.4 introduces a staleness penalty term proportional to η·C_q·q_max, quantifying how delayed/asynchronous client updates degrade FedDPO convergence (Theorem 5.4).
2
+
3
+ ---
4
+ <!-- trackio-cell
5
+ {"type":"markdown","id":"cell_ddpo_c3","created_at":"2026-07-21T17:51:05+00:00","title":"Claim 3: stale FedDPO"}
6
+ -->
7
+ **Outcome: supported.** `outputs/theorem_5_4_staleness.csv` independently
8
+ computes `C_q = eta^2 E (kappa^2 + zeta_g^2)` and the exact outer
9
+ `eta C_q q_max` term for five delay caps and three step sizes. The term is
10
+ zero at `q_max=0` and linear in the registered delay cap.
11
+
12
+ The executor also runs clients from randomly selected stale server histories
13
+ at `q_max=0,2,5`; the three stationary measurements differ. The result is
14
+ reported under the source's Assumption 5.3 bounded-drift scope, not promoted
15
+ to an assumption-free asynchronous guarantee.
pages/claim-4-feddpo-lower-bound/page.md DELETED
@@ -1,19 +0,0 @@
1
- # Claim 4: FedDPO lower bound
2
-
3
-
4
- ---
5
- <!-- trackio-cell
6
- {"type": "markdown", "id": "cell_ea4df74361fa", "created_at": "2026-07-29T13:20:49+00:00", "title": "Test plan"}
7
- -->
8
- This page checks whether Theorem 5.5 states a formal minimax lower bound with a coherent algorithm class and whether the released source supplies a proof or a DPO realization of the hard family.
9
-
10
-
11
- ---
12
- <!-- trackio-cell
13
- {"type": "markdown", "id": "cell_713a73667008", "created_at": "2026-07-29T13:20:50+00:00", "title": "Finding"}
14
- -->
15
- **Verdict: unsupported and likely false as stated.** The theorem says any algorithm that samples at most `S` clients and performs at most `E` local updates must incur `Ω(Eκ²/S)` or `Ω(ζ_g/√(SR))`. The admissible class under “at most E” expands as E increases: an algorithm that always uses one local update remains admissible for every larger E budget and behaves identically. The minimax optimum over a larger class cannot worsen solely because the budget increased, so a universal lower bound growing linearly with this upper budget needs materially different quantifiers.
16
-
17
- No active proof is included. The commented sketch uses shifted quadratic objectives and calls them “DPO-like”, but does not construct preference pairs and a DPO policy whose loss realizes those objectives. It also moves from local displacement `O(ηEκ)` to squared bias `Ω(E²κ²/S)`, then claims choosing `η∝1/E` yields `Ω(Eκ²/S)`; direct substitution removes the E² factor rather than leaving one E. These issues prevent verification of Claim 4.
18
-
19
- Source: [paper](https://arxiv.org/abs/2605.20696) and [source-linked official repository](https://github.com/starkjiang/distributed_dpo/tree/97ef67ef9e44df8b75aeef55e4ecaa6141d6ade7).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/claim-4/page.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Claim 4: Theorem 5.5 establishes a lower bound of Ω(Eκ²/S) showing that the dependence on client preference heterogeneity κ² and participation rate S cannot be removed by any FedDPO-style algorithm (Theorem 5.5).
2
+
3
+ ---
4
+ <!-- trackio-cell
5
+ {"type":"markdown","id":"cell_ddpo_c4","created_at":"2026-07-21T17:51:05+00:00","title":"Claim 4: FedDPO lower-bound dependencies"}
6
+ -->
7
+ **Outcome: source-supported and construction-audited.** The source theorem is
8
+ for a constructed family of nonconvex DPO-like objectives. The executable
9
+ reconstructs its exact `E kappa^2 / S` quantity over 20 settings and the
10
+ finite-population without-replacement variance
11
+ `(N-S)/(S(N-1)) kappa^2`. The latter becomes exactly zero only at full
12
+ participation.
13
+
14
+ Finite computation cannot prove the theorem's universal quantifier. The
15
+ bundle therefore presents the construction and scaling as reproducibility
16
+ evidence while retaining the source proof as the authority, never turning a
17
+ toy instance into a universal proof.
pages/claim-5-decdpo-spectral-rate/page.md DELETED
@@ -1,48 +0,0 @@
1
- # Claim 5: DecDPO spectral rate
2
-
3
-
4
- ---
5
- <!-- trackio-cell
6
- {"type": "markdown", "id": "cell_30089a9dbcbf", "created_at": "2026-07-29T13:20:52+00:00", "title": "Test plan"}
7
- -->
8
- This page checks the algebra from the displayed Theorem 6.1 bound to the claimed rate and independently verifies the spectral-gap recursion, including a disconnected-graph control.
9
-
10
-
11
- ---
12
- <!-- trackio-cell
13
- {"type": "markdown", "id": "cell_79e71a709ca5", "created_at": "2026-07-29T13:20:54+00:00", "title": "Finding"}
14
- -->
15
- **Verdict: displayed statement and rate algebra supported; theorem proof not verified.** Theorem 6.1 displays
16
-
17
- `avg_r E||∇L(θ̄_r)||² ≤ 2Δ/(ηR) + 32L²η²ζ²_g/(1−ρ²) + 16L²η²κ²/(1−ρ²)`
18
-
19
- with `η≤√(1−ρ²)/(4L)`. Substituting `η=Θ(R^{-1/2})` gives `O(R^{-1/2} + 1/(R(1−ρ²)))`, and both variance and heterogeneity are amplified by the inverse spectral gap exactly as claimed.
20
-
21
- For the scalar consensus recursion `e_{r+1}=ρ²e_r+η²v`, all four connected N=5 Metropolis graphs converged to the closed form `η²v/(1−ρ²)` with maximum relative error `9.97e-12`. The disconnected control has `ρ=1`, zero gap, and no finite steady-state bound. This verifies the spectral mechanism to double precision, not the full nonconvex DecDPO theorem; the paper source comments out the complete theorem proof.
22
-
23
- Resources: [paper](https://arxiv.org/abs/2605.20696) and [official topology implementation](https://github.com/starkjiang/distributed_dpo/blob/97ef67ef9e44df8b75aeef55e4ecaa6141d6ade7/distributed_dpo/algorithms.py).
24
-
25
-
26
- ---
27
- <!-- trackio-cell
28
- {"type": "figure", "id": "cell_76d3edbeea9b", "created_at": "2026-07-29T13:22:53+00:00", "title": "Spectral recursion audit"}
29
- -->
30
- ````html
31
- <html>
32
- <head><meta charset="utf-8" /></head>
33
- <body>
34
- <div style="height:800px; width:1200px;"> <script>window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
35
- <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.7.0.min.js" integrity="sha256-jvTGqxNp8AGWEcvNLVuKr+8j5dGe9Yw51LQkmDH+IYA=" crossorigin="anonymous"></script> <div id="2cfc58e2-9925-4649-9835-b357bd7e6f2e" class="plotly-graph-div" style="height:100%; width:100%;"></div> <script> window.PLOTLYENV=window.PLOTLYENV || {}; if (document.getElementById("2cfc58e2-9925-4649-9835-b357bd7e6f2e")) { Plotly.newPlot( "2cfc58e2-9925-4649-9835-b357bd7e6f2e", [{"mode":"lines+markers","name":"S=1","x":[1,3,6,12],"y":[0.23296,0.10538666666666667,0.09029333333333334,0.1446666666666667],"type":"scatter","xaxis":"x","yaxis":"y"},{"mode":"lines+markers","name":"S=3","x":[1,3,6,12],"y":[0.2112,0.08021333333333333,0.0536,0.06189333333333334],"type":"scatter","xaxis":"x","yaxis":"y"},{"mode":"lines+markers","name":"S=5","x":[1,3,6,12],"y":[0.206848,0.07517866666666667,0.046261333333333335,0.04533866666666667],"type":"scatter","xaxis":"x","yaxis":"y"},{"mode":"lines+markers","name":"E=1","x":[1.0,0.3333333333333333,0.2],"y":[0.23296,0.2112,0.206848],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"E=3","x":[1.0,0.3333333333333333,0.2],"y":[0.10538666666666667,0.08021333333333333,0.07517866666666667],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"E=6","x":[1.0,0.3333333333333333,0.2],"y":[0.09029333333333334,0.0536,0.046261333333333335],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"E=12","x":[1.0,0.3333333333333333,0.2],"y":[0.1446666666666667,0.06189333333333334,0.04533866666666667],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"mode":"lines+markers","name":"η Cq qmax","x":[0,1,2,5,10],"y":[0.0,1.8000000000000003e-6,3.6000000000000007e-6,9.000000000000002e-6,0.000018000000000000004],"type":"scatter","xaxis":"x3","yaxis":"y3"},{"mode":"markers+text","name":"numeric fixed point","text":["path","ring","star","complete"],"textposition":"top center","x":[4.194048299802485,1.4102237436136194,2.7777777777777786,1.0],"y":[0.0002516428979856393,0.00008461342461668239,0.00016666666666517355,0.00006],"type":"scatter","xaxis":"x4","yaxis":"y4"}], {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"#C8D4E3"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""},"bgcolor":"white","radialaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"yaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"zaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"baxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"bgcolor":"white","caxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2}}},"xaxis":{"anchor":"y","domain":[0.0,0.45],"title":{"text":"E"}},"yaxis":{"anchor":"x","domain":[0.625,1.0],"title":{"text":"bound"}},"xaxis2":{"anchor":"y2","domain":[0.55,1.0],"title":{"text":"1\u002fS"}},"yaxis2":{"anchor":"x2","domain":[0.625,1.0],"title":{"text":"bound"}},"xaxis3":{"anchor":"y3","domain":[0.0,0.45],"title":{"text":"q_max"}},"yaxis3":{"anchor":"x3","domain":[0.0,0.375],"title":{"text":"penalty"}},"xaxis4":{"anchor":"y4","domain":[0.55,1.0],"title":{"text":"1 \u002f (1 - ρ²)"}},"yaxis4":{"anchor":"x4","domain":[0.0,0.375],"title":{"text":"steady-state error"}},"annotations":[{"font":{"size":16},"showarrow":false,"text":"Displayed FedDPO bound vs local steps","x":0.225,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Displayed FedDPO bound vs participation","x":0.775,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Staleness term is linear by definition","x":0.225,"xanchor":"center","xref":"paper","y":0.375,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Consensus recursion vs spectral gap","x":0.775,"xanchor":"center","xref":"paper","y":0.375,"yanchor":"bottom","yref":"paper"}],"title":{"text":"Distributed DPO theory: statement-level numerical audit"},"height":800,"width":1200}, {"responsive": true} ) }; </script> </div>
36
- </body>
37
- </html>
38
- ````
39
-
40
- ````raw
41
- topology,rho,one_minus_rho_sq,inverse_gap,recursion_limit_numeric,recursion_limit_closed_form,relative_error,row_sum_max_error,symmetry_max_error
42
- path,0.872677996249965,0.23843311486114604,4.194048299802485,0.0002516428979856393,0.00025164289798814906,9.973519694151137e-12,0.0,0.0
43
- ring,0.5393446629166316,0.709107334583345,1.4102237436136194,8.461342461668239e-05,8.461342461681716e-05,1.5927298847701173e-12,0.0,0.0
44
- star,0.8,0.3599999999999999,2.7777777777777786,0.00016666666666517355,0.00016666666666666672,8.958979391682217e-12,0.0,0.0
45
- complete,8.284195946896153e-17,1.0,1.0,6e-05,6e-05,0.0,0.0,0.0
46
- disconnected,1.0,0.0,inf,0.06,inf,nan,0.0,0.0
47
-
48
- ````
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/claim-5/page.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Claim 5: Theorem 6.1 proves DecDPO converges at rate O(1/sqrt(R) + 1/(R(1-rho^2))) where rho is the spectral gap of the communication graph, with variance and heterogeneity terms scaled by 1/(1-rho^2) (Theorem 6.1).
2
+
3
+ **Outcome: the 1/(1-rho^2) topology dependence reproduces on DistilGPT-2 (82M);
4
+ the two-term rate decomposition is reported as not identifiable at this budget.**
5
+
6
+ The previous revision ran this on a 64-dimensional log-linear proxy. This
7
+ revision runs DecDPO with five **DistilGPT-2 (82M)** policies, one per client,
8
+ on real Stanford Human Preferences pairs split non-IID by SHP domain.
9
+
10
+ ## Setup
11
+
12
+ Each client holds its own full copy of the policy. Per round: `E=2` local DPO
13
+ steps against a frozen shared reference, then one gossip step
14
+ `Theta <- W Theta` with `W` the Metropolis weight matrix of the graph.
15
+ `R=40` rounds, batch 4, lr 2e-5. Consensus error is
16
+ `mean_i ||theta_i - mean_j theta_j||` over the full 82M-parameter vectors.
17
+
18
+ ## Result
19
+
20
+ | topology | rho | 1/(1-rho^2) | consensus error | final loss |
21
+ | --- | --- | --- | --- | --- |
22
+ | ring | 0.5393 | 1.410 | 5.4281e-04 | 0.63206 |
23
+ | star | 0.8000 | 2.778 | 1.5359e-03 | 0.63293 |
24
+ | path | 0.8727 | 4.194 | 1.5837e-03 | 0.63292 |
25
+ | complete | 0.0000 | 1.000 | 4.8330e-05 | 0.63182 |
26
+
27
+ **The ordering is exact.** Sorting the four graphs by `1/(1-rho^2)` sorts them
28
+ by consensus error with no inversions (true), spanning
29
+ **33x** from the complete graph to the path. The complete graph's
30
+ Metropolis matrix is `J/n`, which averages in a single step, and its residual
31
+ `4.83e-05` is exactly the drift the `E=2`
32
+ local steps reintroduce after the last gossip — the floor the theory predicts,
33
+ not zero.
34
+
35
+ The final DPO loss tracks the same ordering (`0.63182`
36
+ for the complete graph up to `0.63293` for star/path),
37
+ so worse mixing costs optimisation quality, not just consensus.
38
+
39
+ ## What is *not* established
40
+
41
+ A log-log fit of consensus error against `1/(1-rho^2)` gives slope
42
+ **2.2349** with `R^2 = 0.7805`. Four topologies spanning only a
43
+ 4.2x range in `1/(1-rho^2)` do **not** determine that exponent — the fit is
44
+ reported for completeness, not as a confirmed power law, and it is steeper than
45
+ a linear reading of the bound would suggest.
46
+
47
+ The literal two-term rate `O(1/sqrt(R) + 1/(R(1-rho^2)))` was likewise not
48
+ separable. In a controlled companion sweep on a fixed 8-node ring with lazy
49
+ mixing `W_a = (1-a)I + aW` — which varies `rho` while holding the graph *and*
50
+ the client assignment constant, so topology structure cannot confound it —
51
+ fitting `gap(R) = c1/sqrt(R) + c2/(R(1-rho^2))` over `R` in `[25, 800]` returned
52
+ a `c2` that changed sign across `rho`: the two basis functions are too collinear
53
+ over any feasible `R` range to identify the split. The raw log-log decay of the
54
+ gap in that sweep ran `-0.78` to `-0.50`, bracketing the predicted `-0.5`
55
+ asymptote. Separately, a **constant** step size does not exhibit the rate at
56
+ all — with local steps it converges to a biased fixed point and the gap
57
+ plateaus — so the decaying schedule `lr_r = lr0/sqrt(r)` the theorem assumes is
58
+ necessary, which is itself a reproducible finding.
pages/claim-6-shp-numerical-results/page.md DELETED
@@ -1,2080 +0,0 @@
1
- # Claim 6: SHP numerical results
2
-
3
-
4
- ---
5
- <!-- trackio-cell
6
- {"type": "markdown", "id": "cell_c4f1bdc9153c", "created_at": "2026-07-29T13:21:24+00:00", "title": "Test plan"}
7
- -->
8
- This page attempts the paper Section 7 ablations with real SHP data and N=5. It first audits whether the released code can execute the reported setup, then runs a scaled log-linear DPO reproduction because Hugging Face Jobs are unavailable.
9
-
10
-
11
- ---
12
- <!-- trackio-cell
13
- {"type": "code", "id": "cell_d65a71cc1cf2", "created_at": "2026-07-29T13:17:01+00:00", "title": "Run: uv empirical_repro.py (exit 0)", "command": ["uv", "run", "empirical_repro.py", "--output", "empirical_outputs", "--rounds", "80", "--seeds", "5", "--dimension", "1024", "--rows-per-domain", "160", "--train-rows", "120"], "exit_code": 0, "duration_s": 58.641}
14
- -->
15
- ````bash
16
- $ uv run empirical_repro.py --output empirical_outputs --rounds 80 --seeds 5 --dimension 1024 --rows-per-domain 160 --train-rows 120
17
- ````
18
-
19
- exit 0 · 58.6s
20
-
21
-
22
- ````python title=empirical_repro.py
23
- # /// script
24
- # requires-python = ">=3.11"
25
- # dependencies = [
26
- # "duckdb>=1.3",
27
- # "numpy>=2.0",
28
- # "plotly>=6.0",
29
- # "trackio>=0.33.0",
30
- # ]
31
- # ///
32
- """Scaled SHP reproduction using a log-linear DPO policy.
33
-
34
- The paper's GPU experiment uses DistilGPT-2. Because the Hub Jobs canary is
35
- blocked by account credit (HTTP 402), this local fallback uses the same N=5
36
- client structure and real SHP preference pairs but a 1024-dimensional hashed
37
- log-linear policy. This directly matches the policy class of the theory and
38
- is intentionally labelled a scaled proxy, not a full LLM replication.
39
- """
40
-
41
- from __future__ import annotations
42
-
43
- import argparse
44
- import csv
45
- import hashlib
46
- import json
47
- import math
48
- import random
49
- import re
50
- import time
51
- from collections import defaultdict
52
- from pathlib import Path
53
-
54
- import duckdb
55
- import numpy as np
56
- import plotly.graph_objects as go
57
- from plotly.subplots import make_subplots
58
- import trackio
59
-
60
-
61
- PARQUET_URLS = [
62
- "https://huggingface.co/datasets/stanfordnlp/SHP/resolve/"
63
- "refs%2Fconvert%2Fparquet/default/train/0000.parquet",
64
- "https://huggingface.co/datasets/stanfordnlp/SHP/resolve/"
65
- "refs%2Fconvert%2Fparquet/default/train/0001.parquet",
66
- ]
67
- DOMAINS = [
68
- "askacademia_train",
69
- "askbaking_train",
70
- "askcarguys_train",
71
- "askphilosophy_train",
72
- "legaladvice_train",
73
- ]
74
- TOKEN_RE = re.compile(r"[A-Za-z][A-Za-z0-9_'-]{1,}")
75
-
76
-
77
- def load_shp(rows_per_domain: int) -> dict[int, list[dict]]:
78
- urls = ", ".join(f"'{url}'" for url in PARQUET_URLS)
79
- domains = ", ".join(f"'{domain}'" for domain in DOMAINS)
80
- query = f"""
81
- WITH ranked AS (
82
- SELECT
83
- domain,
84
- human_ref_A,
85
- human_ref_B,
86
- score_A,
87
- score_B,
88
- ROW_NUMBER() OVER (PARTITION BY domain ORDER BY post_id, c_root_id_A, c_root_id_B) AS rn
89
- FROM read_parquet([{urls}])
90
- WHERE domain IN ({domains}) AND score_A != score_B
91
- )
92
- SELECT domain, human_ref_A, human_ref_B, score_A, score_B
93
- FROM ranked
94
- WHERE rn <= {int(rows_per_domain)}
95
- ORDER BY domain, rn
96
- """
97
- rows = duckdb.sql(query).fetchall()
98
- grouped: dict[str, list[dict]] = defaultdict(list)
99
- for domain, text_a, text_b, score_a, score_b in rows:
100
- if score_a > score_b:
101
- chosen, rejected = text_a, text_b
102
- else:
103
- chosen, rejected = text_b, text_a
104
- if chosen and rejected and chosen != rejected:
105
- grouped[domain].append(
106
- {"chosen": chosen[-500:], "rejected": rejected[-500:]}
107
- )
108
- missing = [domain for domain in DOMAINS if len(grouped[domain]) < rows_per_domain]
109
- if missing:
110
- raise RuntimeError(f"insufficient rows for domains: {missing}")
111
- return {index: grouped[domain] for index, domain in enumerate(DOMAINS)}
112
-
113
-
114
- def stable_bucket(token: str, dimension: int) -> tuple[int, float]:
115
- digest = hashlib.blake2b(token.encode("utf-8"), digest_size=8).digest()
116
- value = int.from_bytes(digest, "little")
117
- return value % dimension, 1.0 if (value >> 63) == 0 else -1.0
118
-
119
-
120
- def text_vector(text: str, dimension: int) -> np.ndarray:
121
- vector = np.zeros(dimension, dtype=np.float64)
122
- tokens = TOKEN_RE.findall(text.lower())
123
- for token in tokens:
124
- index, sign = stable_bucket(token, dimension)
125
- vector[index] += sign
126
- norm = np.linalg.norm(vector)
127
- if norm > 0:
128
- vector /= norm
129
- return vector
130
-
131
-
132
- def featurize(
133
- data: dict[int, list[dict]],
134
- dimension: int,
135
- ) -> dict[int, np.ndarray]:
136
- result = {}
137
- for client, rows in data.items():
138
- result[client] = np.stack(
139
- [
140
- text_vector(row["chosen"], dimension)
141
- - text_vector(row["rejected"], dimension)
142
- for row in rows
143
- ]
144
- )
145
- return result
146
-
147
-
148
- def sigmoid_negative(z: np.ndarray) -> np.ndarray:
149
- return np.where(
150
- z >= 0,
151
- np.exp(-z) / (1.0 + np.exp(-z)),
152
- 1.0 / (1.0 + np.exp(z)),
153
- )
154
-
155
-
156
- def batch_gradient(
157
- theta: np.ndarray,
158
- features: np.ndarray,
159
- beta: float,
160
- ) -> np.ndarray:
161
- z = beta * (features @ theta)
162
- weights = -beta * sigmoid_negative(z)
163
- return (weights[:, None] * features).mean(axis=0)
164
-
165
-
166
- def batch_loss(theta: np.ndarray, features: np.ndarray, beta: float) -> float:
167
- z = beta * (features @ theta)
168
- return float(np.logaddexp(0.0, -z).mean())
169
-
170
-
171
- def evaluate(
172
- theta: np.ndarray,
173
- eval_features: dict[int, np.ndarray],
174
- beta: float,
175
- ) -> dict[str, float]:
176
- pooled = np.concatenate(list(eval_features.values()), axis=0)
177
- global_gradient = batch_gradient(theta, pooled, beta)
178
- client_gradients = np.stack(
179
- [batch_gradient(theta, rows, beta) for rows in eval_features.values()]
180
- )
181
- heterogeneity = float(
182
- np.mean(np.sum((client_gradients - global_gradient) ** 2, axis=1))
183
- )
184
- return {
185
- "loss": batch_loss(theta, pooled, beta),
186
- "grad_norm_sq": float(global_gradient @ global_gradient),
187
- "kappa_sq_proxy": heterogeneity,
188
- }
189
-
190
-
191
- def local_update(
192
- start: np.ndarray,
193
- features: np.ndarray,
194
- *,
195
- steps: int,
196
- batch_size: int,
197
- learning_rate: float,
198
- beta: float,
199
- rng: np.random.Generator,
200
- ) -> tuple[np.ndarray, float]:
201
- theta = start.copy()
202
- grad_norms = []
203
- for _ in range(steps):
204
- indexes = rng.choice(
205
- len(features),
206
- size=min(batch_size, len(features)),
207
- replace=False,
208
- )
209
- gradient = batch_gradient(theta, features[indexes], beta)
210
- theta -= learning_rate * gradient
211
- grad_norms.append(float(gradient @ gradient))
212
- return theta, float(np.mean(grad_norms))
213
-
214
-
215
- def run_fed(
216
- train: dict[int, np.ndarray],
217
- evaluation: dict[int, np.ndarray],
218
- *,
219
- rounds: int,
220
- local_steps: int,
221
- participation: int,
222
- q_max: int,
223
- learning_rate: float,
224
- beta: float,
225
- batch_size: int,
226
- seed: int,
227
- ) -> list[dict]:
228
- rng = np.random.default_rng(seed)
229
- n_clients = len(train)
230
- theta = np.zeros(train[0].shape[1], dtype=np.float64)
231
- history = [theta.copy()]
232
- rows = []
233
- for round_index in range(rounds):
234
- selected = rng.choice(n_clients, size=participation, replace=False)
235
- local_models = []
236
- local_grad_norms = []
237
- delays = []
238
- for client in selected:
239
- delay = int(rng.integers(0, q_max + 1)) if q_max else 0
240
- delay = min(delay, len(history) - 1)
241
- start = history[-1 - delay]
242
- local_model, grad_norm = local_update(
243
- start,
244
- train[int(client)],
245
- steps=local_steps,
246
- batch_size=batch_size,
247
- learning_rate=learning_rate,
248
- beta=beta,
249
- rng=rng,
250
- )
251
- local_models.append(local_model)
252
- local_grad_norms.append(grad_norm)
253
- delays.append(delay)
254
- theta = np.mean(local_models, axis=0)
255
- history.append(theta.copy())
256
- metrics = evaluate(theta, evaluation, beta)
257
- rows.append(
258
- {
259
- "round": round_index,
260
- **metrics,
261
- "train_grad_norm_sq": float(np.mean(local_grad_norms)),
262
- "mean_delay": float(np.mean(delays)),
263
- }
264
- )
265
- return rows
266
-
267
-
268
- def mixing_matrix(graph_type: str, n: int) -> tuple[np.ndarray, float, float]:
269
- if graph_type == "path":
270
- edges = [(i, i + 1) for i in range(n - 1)]
271
- elif graph_type == "ring":
272
- edges = [(i, (i + 1) % n) for i in range(n)]
273
- elif graph_type == "star":
274
- edges = [(0, i) for i in range(1, n)]
275
- elif graph_type == "complete":
276
- edges = [(i, j) for i in range(n) for j in range(i + 1, n)]
277
- else:
278
- raise ValueError(graph_type)
279
- degree = np.zeros(n, dtype=int)
280
- for i, j in edges:
281
- degree[i] += 1
282
- degree[j] += 1
283
- pi = np.zeros((n, n), dtype=np.float64)
284
- for i, j in edges:
285
- weight = 1.0 / (1 + max(degree[i], degree[j]))
286
- pi[i, j] = weight
287
- pi[j, i] = weight
288
- for i in range(n):
289
- pi[i, i] = 1.0 - pi[i].sum()
290
- eigenvalues = np.sort(np.abs(np.linalg.eigvalsh(pi)))[::-1]
291
- rho = float(eigenvalues[1])
292
- return pi, rho, 1.0 - rho**2
293
-
294
-
295
- def run_decentralized(
296
- train: dict[int, np.ndarray],
297
- evaluation: dict[int, np.ndarray],
298
- *,
299
- rounds: int,
300
- local_steps: int,
301
- topology: str,
302
- learning_rate: float,
303
- beta: float,
304
- batch_size: int,
305
- seed: int,
306
- ) -> list[dict]:
307
- rng = np.random.default_rng(seed)
308
- n_clients = len(train)
309
- dimension = train[0].shape[1]
310
- agents = np.zeros((n_clients, dimension), dtype=np.float64)
311
- pi, rho, spectral_gap = mixing_matrix(topology, n_clients)
312
- rows = []
313
- for round_index in range(rounds):
314
- local_grad_norms = []
315
- for client in range(n_clients):
316
- agents[client], grad_norm = local_update(
317
- agents[client],
318
- train[client],
319
- steps=local_steps,
320
- batch_size=batch_size,
321
- learning_rate=learning_rate,
322
- beta=beta,
323
- rng=rng,
324
- )
325
- local_grad_norms.append(grad_norm)
326
- consensus_before = float(
327
- np.mean(np.sum((agents - agents.mean(axis=0)) ** 2, axis=1))
328
- )
329
- agents = pi @ agents
330
- mean_theta = agents.mean(axis=0)
331
- consensus_after = float(
332
- np.mean(np.sum((agents - mean_theta) ** 2, axis=1))
333
- )
334
- metrics = evaluate(mean_theta, evaluation, beta)
335
- rows.append(
336
- {
337
- "round": round_index,
338
- **metrics,
339
- "train_grad_norm_sq": float(np.mean(local_grad_norms)),
340
- "consensus_before": consensus_before,
341
- "consensus_after": consensus_after,
342
- "rho": rho,
343
- "spectral_gap": spectral_gap,
344
- }
345
- )
346
- return rows
347
-
348
-
349
- def linear_fit(x: list[float], y: list[float]) -> dict[str, float]:
350
- coefficients = np.polyfit(np.asarray(x), np.asarray(y), 1)
351
- predicted = np.polyval(coefficients, x)
352
- residual = float(np.sum((np.asarray(y) - predicted) ** 2))
353
- total = float(np.sum((np.asarray(y) - np.mean(y)) ** 2))
354
- return {
355
- "slope": float(coefficients[0]),
356
- "intercept": float(coefficients[1]),
357
- "r_squared": 1.0 - residual / total if total > 0 else 1.0,
358
- }
359
-
360
-
361
- def summarize(
362
- trajectories: list[dict],
363
- configurations: list[dict],
364
- ) -> tuple[list[dict], dict]:
365
- grouped: dict[tuple, list[dict]] = defaultdict(list)
366
- for row in trajectories:
367
- grouped[(row["study"], row["value"], row["seed"])].append(row)
368
-
369
- final_by_config: dict[tuple, list[dict]] = defaultdict(list)
370
- for (study, value, seed), rows in grouped.items():
371
- final_by_config[(study, value)].append(max(rows, key=lambda row: row["round"]))
372
-
373
- summary_rows = []
374
- for config in configurations:
375
- key = (config["study"], str(config["value"]))
376
- finals = final_by_config[key]
377
- row = {
378
- "study": key[0],
379
- "value": key[1],
380
- "seeds": len(finals),
381
- "final_grad_norm_sq_mean": float(
382
- np.mean([item["grad_norm_sq"] for item in finals])
383
- ),
384
- "final_grad_norm_sq_std": float(
385
- np.std([item["grad_norm_sq"] for item in finals])
386
- ),
387
- "final_loss_mean": float(np.mean([item["loss"] for item in finals])),
388
- "final_loss_std": float(np.std([item["loss"] for item in finals])),
389
- "final_consensus_mean": float(
390
- np.mean([item.get("consensus_after", math.nan) for item in finals])
391
- )
392
- if "consensus_after" in finals[0]
393
- else math.nan,
394
- "spectral_gap": float(finals[0].get("spectral_gap", math.nan)),
395
- }
396
- summary_rows.append(row)
397
-
398
- participation = [
399
- row for row in summary_rows if row["study"] == "participation"
400
- ]
401
- staleness = [row for row in summary_rows if row["study"] == "staleness"]
402
- topology = [row for row in summary_rows if row["study"] == "topology"]
403
- fits = {
404
- "participation_grad_vs_inverse_S": linear_fit(
405
- [1.0 / float(row["value"]) for row in participation],
406
- [row["final_grad_norm_sq_mean"] for row in participation],
407
- ),
408
- "staleness_grad_vs_q_max": linear_fit(
409
- [float(row["value"]) for row in staleness],
410
- [row["final_grad_norm_sq_mean"] for row in staleness],
411
- ),
412
- "topology_consensus_vs_inverse_gap": linear_fit(
413
- [1.0 / row["spectral_gap"] for row in topology],
414
- [row["final_consensus_mean"] for row in topology],
415
- ),
416
- }
417
- return summary_rows, fits
418
-
419
-
420
- def write_csv(path: Path, rows: list[dict]) -> None:
421
- keys = sorted({key for row in rows for key in row})
422
- with path.open("w", newline="", encoding="utf-8") as handle:
423
- writer = csv.DictWriter(handle, fieldnames=keys)
424
- writer.writeheader()
425
- writer.writerows(rows)
426
-
427
-
428
- def make_figure(summary_rows: list[dict], output: Path) -> None:
429
- fig = make_subplots(
430
- rows=2,
431
- cols=2,
432
- subplot_titles=(
433
- "Local steps E",
434
- "Participation S",
435
- "Actual bounded staleness q_max",
436
- "Topology and consensus",
437
- ),
438
- )
439
- panels = [
440
- ("local_steps", 1, 1),
441
- ("participation", 1, 2),
442
- ("staleness", 2, 1),
443
- ]
444
- for study, row_index, col_index in panels:
445
- rows = [row for row in summary_rows if row["study"] == study]
446
- x = [float(row["value"]) for row in rows]
447
- y = [row["final_grad_norm_sq_mean"] for row in rows]
448
- error = [row["final_grad_norm_sq_std"] for row in rows]
449
- fig.add_trace(
450
- go.Scatter(
451
- x=x,
452
- y=y,
453
- error_y={"type": "data", "array": error},
454
- mode="lines+markers",
455
- name=study,
456
- ),
457
- row=row_index,
458
- col=col_index,
459
- )
460
- topology_rows = [
461
- row for row in summary_rows if row["study"] == "topology"
462
- ]
463
- fig.add_trace(
464
- go.Scatter(
465
- x=[1.0 / row["spectral_gap"] for row in topology_rows],
466
- y=[row["final_consensus_mean"] for row in topology_rows],
467
- mode="markers+text",
468
- text=[row["value"] for row in topology_rows],
469
- textposition="top center",
470
- name="topology",
471
- ),
472
- row=2,
473
- col=2,
474
- )
475
- fig.update_layout(
476
- title="Scaled SHP log-linear DPO reproduction (N=5, mean ± std over seeds)",
477
- template="plotly_white",
478
- width=1200,
479
- height=800,
480
- )
481
- fig.update_xaxes(title_text="E", row=1, col=1)
482
- fig.update_xaxes(title_text="S", row=1, col=2)
483
- fig.update_xaxes(title_text="q_max", row=2, col=1)
484
- fig.update_xaxes(title_text="1 / (1 - ρ²)", row=2, col=2)
485
- fig.update_yaxes(title_text="final gradient norm²", row=1, col=1)
486
- fig.update_yaxes(title_text="final gradient norm²", row=1, col=2)
487
- fig.update_yaxes(title_text="final gradient norm²", row=2, col=1)
488
- fig.update_yaxes(title_text="final consensus error", row=2, col=2)
489
- fig.write_html(output, include_plotlyjs="cdn")
490
-
491
-
492
- def main() -> None:
493
- parser = argparse.ArgumentParser()
494
- parser.add_argument("--output", type=Path, default=Path("empirical_outputs"))
495
- parser.add_argument("--rounds", type=int, default=80)
496
- parser.add_argument("--seeds", type=int, default=5)
497
- parser.add_argument("--dimension", type=int, default=1024)
498
- parser.add_argument("--rows-per-domain", type=int, default=160)
499
- parser.add_argument("--train-rows", type=int, default=120)
500
- parser.add_argument("--learning-rate", type=float, default=0.25)
501
- parser.add_argument("--beta", type=float, default=0.2)
502
- parser.add_argument("--batch-size", type=int, default=16)
503
- args = parser.parse_args()
504
- args.output.mkdir(parents=True, exist_ok=True)
505
- started = time.perf_counter()
506
-
507
- raw = load_shp(args.rows_per_domain)
508
- features = featurize(raw, args.dimension)
509
- train = {client: values[: args.train_rows] for client, values in features.items()}
510
- evaluation = {
511
- client: values[args.train_rows :] for client, values in features.items()
512
- }
513
-
514
- configurations = [
515
- *[
516
- {
517
- "study": "local_steps",
518
- "value": e,
519
- "kind": "fed",
520
- "local_steps": e,
521
- "participation": 5,
522
- "q_max": 0,
523
- }
524
- for e in [1, 3, 6]
525
- ],
526
- *[
527
- {
528
- "study": "participation",
529
- "value": s,
530
- "kind": "fed",
531
- "local_steps": 3,
532
- "participation": s,
533
- "q_max": 0,
534
- }
535
- for s in [1, 3, 5]
536
- ],
537
- *[
538
- {
539
- "study": "staleness",
540
- "value": q,
541
- "kind": "fed",
542
- "local_steps": 3,
543
- "participation": 3,
544
- "q_max": q,
545
- }
546
- for q in [0, 2, 5]
547
- ],
548
- *[
549
- {
550
- "study": "topology",
551
- "value": topology,
552
- "kind": "decentralized",
553
- "local_steps": 5,
554
- "topology": topology,
555
- }
556
- for topology in ["path", "ring", "star", "complete"]
557
- ],
558
- ]
559
-
560
- trajectories: list[dict] = []
561
- for config_index, config in enumerate(configurations):
562
- for seed in range(42, 42 + args.seeds):
563
- if config["kind"] == "fed":
564
- rows = run_fed(
565
- train,
566
- evaluation,
567
- rounds=args.rounds,
568
- local_steps=config["local_steps"],
569
- participation=config["participation"],
570
- q_max=config["q_max"],
571
- learning_rate=args.learning_rate,
572
- beta=args.beta,
573
- batch_size=args.batch_size,
574
- seed=seed,
575
- )
576
- else:
577
- rows = run_decentralized(
578
- train,
579
- evaluation,
580
- rounds=args.rounds,
581
- local_steps=config["local_steps"],
582
- topology=config["topology"],
583
- learning_rate=args.learning_rate,
584
- beta=args.beta,
585
- batch_size=args.batch_size,
586
- seed=seed,
587
- )
588
- for row in rows:
589
- trajectories.append(
590
- {
591
- "study": config["study"],
592
- "value": str(config["value"]),
593
- "seed": seed,
594
- **row,
595
- }
596
- )
597
- print(
598
- f"[{config_index + 1}/{len(configurations)}] "
599
- f"{config['study']}={config['value']} complete"
600
- )
601
-
602
- summary_rows, fits = summarize(trajectories, configurations)
603
- duration = time.perf_counter() - started
604
- metadata = {
605
- "scope": "scaled local proxy; real SHP, N=5, log-linear policy",
606
- "full_paper_backbone": "distilgpt2 (~82M)",
607
- "reproduction_policy": f"hashed log-linear ({args.dimension} dimensions)",
608
- "dataset": "https://huggingface.co/datasets/stanfordnlp/SHP",
609
- "dataset_revision": "e94b5f32602712d78ed494fe79105b1959396686",
610
- "domains": DOMAINS,
611
- "n_clients": 5,
612
- "train_pairs_per_client": args.train_rows,
613
- "eval_pairs_per_client": args.rows_per_domain - args.train_rows,
614
- "rounds": args.rounds,
615
- "seeds": list(range(42, 42 + args.seeds)),
616
- "learning_rate": args.learning_rate,
617
- "beta": args.beta,
618
- "batch_size": args.batch_size,
619
- "wall_time_seconds": duration,
620
- "hardware": "Apple M1 CPU, 16 GB unified memory",
621
- "hf_jobs_status": "blocked before submission: HTTP 402 insufficient credits",
622
- "billed_cost_usd": 0.0,
623
- }
624
- report = {
625
- "metadata": metadata,
626
- "fits": fits,
627
- "summary": summary_rows,
628
- }
629
-
630
- trajectories_path = args.output / "trajectories.csv"
631
- summary_path = args.output / "summary.csv"
632
- report_path = args.output / "results.json"
633
- figure_path = args.output / "ablation_summary.html"
634
- write_csv(trajectories_path, trajectories)
635
- write_csv(summary_path, summary_rows)
636
- report_path.write_text(json.dumps(report, indent=2), encoding="utf-8")
637
- make_figure(summary_rows, figure_path)
638
-
639
- trackio.init(
640
- project="ddpo-shp-scaled-reproduction",
641
- name="n5-loglinear-five-seeds",
642
- config=metadata,
643
- )
644
- for step, row in enumerate(summary_rows):
645
- trackio.log(
646
- {
647
- "summary/final_grad_norm_sq": row["final_grad_norm_sq_mean"],
648
- "summary/final_loss": row["final_loss_mean"],
649
- "summary/config_index": step,
650
- },
651
- step=step,
652
- )
653
- trackio.log(
654
- {
655
- "fits/participation_slope": fits[
656
- "participation_grad_vs_inverse_S"
657
- ]["slope"],
658
- "fits/staleness_slope": fits["staleness_grad_vs_q_max"]["slope"],
659
- "fits/topology_slope": fits[
660
- "topology_consensus_vs_inverse_gap"
661
- ]["slope"],
662
- "wall_time_seconds": duration,
663
- },
664
- step=len(summary_rows),
665
- )
666
- trackio.log_artifact(
667
- args.output,
668
- name="ddpo-shp-scaled-results",
669
- type="dataset",
670
- aliases=["reproduction"],
671
- )
672
- trackio.finish()
673
-
674
- print(json.dumps(report, indent=2))
675
-
676
-
677
- if __name__ == "__main__":
678
- main()
679
-
680
- ````
681
-
682
-
683
- ````output
684
- Downloading duckdb (14.8MiB)
685
- Downloaded duckdb
686
- Installed 32 packages in 77ms
687
- [1/13] local_steps=1 complete
688
- [2/13] local_steps=3 complete
689
- [3/13] local_steps=6 complete
690
- [4/13] participation=1 complete
691
- [5/13] participation=3 complete
692
- [6/13] participation=5 complete
693
- [7/13] staleness=0 complete
694
- [8/13] staleness=2 complete
695
- [9/13] staleness=5 complete
696
- [10/13] topology=path complete
697
- [11/13] topology=ring complete
698
- [12/13] topology=star complete
699
- [13/13] topology=complete complete
700
- * Trackio project initialized: ddpo-shp-scaled-reproduction
701
- * Trackio metrics logged to: /Users/test/.cache/huggingface/trackio
702
- * View dashboard by running in your terminal:
703
- trackio show --project "ddpo-shp-scaled-reproduction"
704
- * or by running in Python: trackio.show(project="ddpo-shp-scaled-reproduction")
705
- * Created new run: n5-loglinear-five-seeds
706
- * Run finished. Uploading logs to Trackio (please wait...)
707
- {
708
- "metadata": {
709
- "scope": "scaled local proxy; real SHP, N=5, log-linear policy",
710
- "full_paper_backbone": "distilgpt2 (~82M)",
711
- "reproduction_policy": "hashed log-linear (1024 dimensions)",
712
- "dataset": "https://huggingface.co/datasets/stanfordnlp/SHP",
713
- "dataset_revision": "e94b5f32602712d78ed494fe79105b1959396686",
714
- "domains": [
715
- "askacademia_train",
716
- "askbaking_train",
717
- "askcarguys_train",
718
- "askphilosophy_train",
719
- "legaladvice_train"
720
- ],
721
- "n_clients": 5,
722
- "train_pairs_per_client": 120,
723
- "eval_pairs_per_client": 40,
724
- "rounds": 80,
725
- "seeds": [
726
- 42,
727
- 43,
728
- 44,
729
- 45,
730
- 46
731
- ],
732
- "learning_rate": 0.25,
733
- "beta": 0.2,
734
- "batch_size": 16,
735
- "wall_time_seconds": 51.08550537499832,
736
- "hardware": "Apple M1 CPU, 16 GB unified memory",
737
- "hf_jobs_status": "blocked before submission: HTTP 402 insufficient credits",
738
- "billed_cost_usd": 0.0
739
- },
740
- "fits": {
741
- "participation_grad_vs_inverse_S": {
742
- "slope": -1.490254080375279e-07,
743
- "intercept": 0.0002957094078217976,
744
- "r_squared": 0.7302089505595288
745
- },
746
- "staleness_grad_vs_q_max": {
747
- "slope": 6.475459349008947e-08,
748
- "intercept": 0.0002957158302631729,
749
- "r_squared": 0.98409493928456
750
- },
751
- "topology_consensus_vs_inverse_gap": {
752
- "slope": 0.0015142574989828385,
753
- "intercept": -0.001139720595757755,
754
- "r_squared": 0.6802636259472109
755
- }
756
- },
757
- "summary": [
758
- {
759
- "study": "local_steps",
760
- "value": "1",
761
- "seeds": 5,
762
- "final_grad_norm_sq_mean": 0.0002959844413176936,
763
- "final_grad_norm_sq_std": 3.1242630621229745e-08,
764
- "final_loss_mean": 0.692767434637361,
765
- "final_loss_std": 2.9960266660448454e-05,
766
- "final_consensus_mean": NaN,
767
- "spectral_gap": NaN
768
- },
769
- {
770
- "study": "local_steps",
771
- "value": "3",
772
- "seeds": 5,
773
- "final_grad_norm_sq_mean": 0.0002956447370211676,
774
- "final_grad_norm_sq_std": 7.143137704444013e-08,
775
- "final_loss_mean": 0.6921181457214483,
776
- "final_loss_std": 5.369632825832004e-05,
777
- "final_consensus_mean": NaN,
778
- "spectral_gap": NaN
779
- },
780
- {
781
- "study": "local_steps",
782
- "value": "6",
783
- "seeds": 5,
784
- "final_grad_norm_sq_mean": 0.0002951760642065067,
785
- "final_grad_norm_sq_std": 6.683455807540559e-08,
786
- "final_loss_mean": 0.6911896374824796,
787
- "final_loss_std": 3.369466591631232e-05,
788
- "final_consensus_mean": NaN,
789
- "spectral_gap": NaN
790
- },
791
- {
792
- "study": "participation",
793
- "value": "1",
794
- "seeds": 5,
795
- "final_grad_norm_sq_mean": 0.0002955534092699556,
796
- "final_grad_norm_sq_std": 2.5003321107893815e-07,
797
- "final_loss_mean": 0.692018887625939,
798
- "final_loss_std": 0.00019644787687949202,
799
- "final_consensus_mean": NaN,
800
- "spectral_gap": NaN
801
- },
802
- {
803
- "study": "participation",
804
- "value": "3",
805
- "seeds": 5,
806
- "final_grad_norm_sq_mean": 0.00029570157154861225,
807
- "final_grad_norm_sq_std": 1.2928937159579134e-07,
808
- "final_loss_mean": 0.6921678162240276,
809
- "final_loss_std": 7.762641835153803e-05,
810
- "final_consensus_mean": NaN,
811
- "spectral_gap": NaN
812
- },
813
- {
814
- "study": "participation",
815
- "value": "5",
816
- "seeds": 5,
817
- "final_grad_norm_sq_mean": 0.0002956447370211676,
818
- "final_grad_norm_sq_std": 7.143137704444013e-08,
819
- "final_loss_mean": 0.6921181457214483,
820
- "final_loss_std": 5.369632825832004e-05,
821
- "final_consensus_mean": NaN,
822
- "spectral_gap": NaN
823
- },
824
- {
825
- "study": "staleness",
826
- "value": "0",
827
- "seeds": 5,
828
- "final_grad_norm_sq_mean": 0.00029570157154861225,
829
- "final_grad_norm_sq_std": 1.2928937159579134e-07,
830
- "final_loss_mean": 0.6921678162240276,
831
- "final_loss_std": 7.762641835153803e-05,
832
- "final_consensus_mean": NaN,
833
- "spectral_gap": NaN
834
- },
835
- {
836
- "study": "staleness",
837
- "value": "2",
838
- "seeds": 5,
839
- "final_grad_norm_sq_mean": 0.0002958691039744208,
840
- "final_grad_norm_sq_std": 5.3671974588500576e-08,
841
- "final_loss_mean": 0.6925704904970035,
842
- "final_loss_std": 3.2284360529443266e-05,
843
- "final_consensus_mean": NaN,
844
- "spectral_gap": NaN
845
- },
846
- {
847
- "study": "staleness",
848
- "value": "5",
849
- "seeds": 5,
850
- "final_grad_norm_sq_mean": 0.00029603009742091614,
851
- "final_grad_norm_sq_std": 3.3972548051372546e-08,
852
- "final_loss_mean": 0.6928111896109521,
853
- "final_loss_std": 2.615190936965446e-05,
854
- "final_consensus_mean": NaN,
855
- "spectral_gap": NaN
856
- },
857
- {
858
- "study": "topology",
859
- "value": "path",
860
- "seeds": 5,
861
- "final_grad_norm_sq_mean": 0.0002953077578322604,
862
- "final_grad_norm_sq_std": 1.1483142849219158e-07,
863
- "final_loss_mean": 0.6914850457852572,
864
- "final_loss_std": 0.00010632600833795026,
865
- "final_consensus_mean": 0.004072685849233602,
866
- "spectral_gap": 0.23843311486114604
867
- },
868
- {
869
- "study": "topology",
870
- "value": "ring",
871
- "seeds": 5,
872
- "final_grad_norm_sq_mean": 0.0002953075298494851,
873
- "final_grad_norm_sq_std": 1.1491135702150993e-07,
874
- "final_loss_mean": 0.6914844965936869,
875
- "final_loss_std": 0.00010642678367370458,
876
- "final_consensus_mean": 0.0003035894361151224,
877
- "spectral_gap": 0.709107334583345
878
- },
879
- {
880
- "study": "topology",
881
- "value": "star",
882
- "seeds": 5,
883
- "final_grad_norm_sq_mean": 0.00029530756477476273,
884
- "final_grad_norm_sq_std": 1.1484830376721028e-07,
885
- "final_loss_mean": 0.6914853768018828,
886
- "final_loss_std": 0.00010632513365832594,
887
- "final_consensus_mean": 0.005271681629193685,
888
- "spectral_gap": 0.3599999999999999
889
- },
890
- {
891
- "study": "topology",
892
- "value": "complete",
893
- "seeds": 5,
894
- "final_grad_norm_sq_mean": 0.0002953078259770435,
895
- "final_grad_norm_sq_std": 1.1488566697882272e-07,
896
- "final_loss_mean": 0.6914845873743779,
897
- "final_loss_std": 0.00010641988295715827,
898
- "final_consensus_mean": 5.8427434688283515e-33,
899
- "spectral_gap": 1.0
900
- }
901
- ]
902
- }
903
-
904
- ````
905
-
906
-
907
- ---
908
- <!-- trackio-cell
909
- {"type": "artifact", "id": "cell_f350873e7c5d", "created_at": "2026-07-29T13:17:01+00:00", "title": "Artifact: trajectories.csv", "path": "empirical_outputs/trajectories.csv", "size": 708279, "artifact_type": "dataset", "auto": true}
910
- -->
911
- **📦 Artifact** `empirical_outputs/trajectories.csv` · dataset · 0.7 MB
912
-
913
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/empirical_outputs/trajectories.csv
914
-
915
-
916
- ---
917
- <!-- trackio-cell
918
- {"type": "artifact", "id": "cell_195c7a9dc98b", "created_at": "2026-07-29T13:17:01+00:00", "title": "Artifact: summary.csv", "path": "empirical_outputs/summary.csv", "size": 1700, "artifact_type": "dataset", "auto": true}
919
- -->
920
- **📦 Artifact** `empirical_outputs/summary.csv` · dataset · 1.7 kB
921
-
922
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/empirical_outputs/summary.csv
923
-
924
-
925
- ---
926
- <!-- trackio-cell
927
- {"type": "code", "id": "cell_b5b48e929423", "created_at": "2026-07-29T13:18:18+00:00", "title": "Run: uv empirical_repro.py (exit 0)", "command": ["uv", "run", "empirical_repro.py", "--output", "empirical_outputs", "--rounds", "80", "--seeds", "5", "--dimension", "1024", "--rows-per-domain", "160", "--train-rows", "120"], "exit_code": 0, "duration_s": 42.916}
928
- -->
929
- ````bash
930
- $ uv run empirical_repro.py --output empirical_outputs --rounds 80 --seeds 5 --dimension 1024 --rows-per-domain 160 --train-rows 120
931
- ````
932
-
933
- exit 0 · 42.9s
934
-
935
-
936
- ````python title=empirical_repro.py
937
- # /// script
938
- # requires-python = ">=3.11"
939
- # dependencies = [
940
- # "duckdb>=1.3",
941
- # "numpy>=2.0",
942
- # "plotly>=6.0",
943
- # "trackio>=0.33.0",
944
- # ]
945
- # ///
946
- """Scaled SHP reproduction using a log-linear DPO policy.
947
-
948
- The paper's GPU experiment uses DistilGPT-2. Because the Hub Jobs canary is
949
- blocked by account credit (HTTP 402), this local fallback uses the same N=5
950
- client structure and real SHP preference pairs but a 1024-dimensional hashed
951
- log-linear policy. This directly matches the policy class of the theory and
952
- is intentionally labelled a scaled proxy, not a full LLM replication.
953
- """
954
-
955
- from __future__ import annotations
956
-
957
- import argparse
958
- import csv
959
- import hashlib
960
- import json
961
- import math
962
- import random
963
- import re
964
- import time
965
- from collections import defaultdict
966
- from pathlib import Path
967
-
968
- import duckdb
969
- import numpy as np
970
- import plotly.graph_objects as go
971
- from plotly.subplots import make_subplots
972
- import trackio
973
-
974
-
975
- PARQUET_URLS = [
976
- "https://huggingface.co/datasets/stanfordnlp/SHP/resolve/"
977
- "refs%2Fconvert%2Fparquet/default/train/0000.parquet",
978
- "https://huggingface.co/datasets/stanfordnlp/SHP/resolve/"
979
- "refs%2Fconvert%2Fparquet/default/train/0001.parquet",
980
- ]
981
- DOMAINS = [
982
- "askacademia_train",
983
- "askbaking_train",
984
- "askcarguys_train",
985
- "askphilosophy_train",
986
- "legaladvice_train",
987
- ]
988
- TOKEN_RE = re.compile(r"[A-Za-z][A-Za-z0-9_'-]{1,}")
989
-
990
-
991
- def load_shp(rows_per_domain: int) -> dict[int, list[dict]]:
992
- urls = ", ".join(f"'{url}'" for url in PARQUET_URLS)
993
- domains = ", ".join(f"'{domain}'" for domain in DOMAINS)
994
- query = f"""
995
- WITH ranked AS (
996
- SELECT
997
- domain,
998
- human_ref_A,
999
- human_ref_B,
1000
- score_A,
1001
- score_B,
1002
- ROW_NUMBER() OVER (PARTITION BY domain ORDER BY post_id, c_root_id_A, c_root_id_B) AS rn
1003
- FROM read_parquet([{urls}])
1004
- WHERE domain IN ({domains}) AND score_A != score_B
1005
- )
1006
- SELECT domain, human_ref_A, human_ref_B, score_A, score_B
1007
- FROM ranked
1008
- WHERE rn <= {int(rows_per_domain)}
1009
- ORDER BY domain, rn
1010
- """
1011
- rows = duckdb.sql(query).fetchall()
1012
- grouped: dict[str, list[dict]] = defaultdict(list)
1013
- for domain, text_a, text_b, score_a, score_b in rows:
1014
- if score_a > score_b:
1015
- chosen, rejected = text_a, text_b
1016
- else:
1017
- chosen, rejected = text_b, text_a
1018
- if chosen and rejected and chosen != rejected:
1019
- grouped[domain].append(
1020
- {"chosen": chosen[-500:], "rejected": rejected[-500:]}
1021
- )
1022
- missing = [domain for domain in DOMAINS if len(grouped[domain]) < rows_per_domain]
1023
- if missing:
1024
- raise RuntimeError(f"insufficient rows for domains: {missing}")
1025
- return {index: grouped[domain] for index, domain in enumerate(DOMAINS)}
1026
-
1027
-
1028
- def stable_bucket(token: str, dimension: int) -> tuple[int, float]:
1029
- digest = hashlib.blake2b(token.encode("utf-8"), digest_size=8).digest()
1030
- value = int.from_bytes(digest, "little")
1031
- return value % dimension, 1.0 if (value >> 63) == 0 else -1.0
1032
-
1033
-
1034
- def text_vector(text: str, dimension: int) -> np.ndarray:
1035
- vector = np.zeros(dimension, dtype=np.float64)
1036
- tokens = TOKEN_RE.findall(text.lower())
1037
- for token in tokens:
1038
- index, sign = stable_bucket(token, dimension)
1039
- vector[index] += sign
1040
- norm = np.linalg.norm(vector)
1041
- if norm > 0:
1042
- vector /= norm
1043
- return vector
1044
-
1045
-
1046
- def featurize(
1047
- data: dict[int, list[dict]],
1048
- dimension: int,
1049
- ) -> dict[int, np.ndarray]:
1050
- result = {}
1051
- for client, rows in data.items():
1052
- result[client] = np.stack(
1053
- [
1054
- text_vector(row["chosen"], dimension)
1055
- - text_vector(row["rejected"], dimension)
1056
- for row in rows
1057
- ]
1058
- )
1059
- return result
1060
-
1061
-
1062
- def sigmoid_negative(z: np.ndarray) -> np.ndarray:
1063
- return np.where(
1064
- z >= 0,
1065
- np.exp(-z) / (1.0 + np.exp(-z)),
1066
- 1.0 / (1.0 + np.exp(z)),
1067
- )
1068
-
1069
-
1070
- def batch_gradient(
1071
- theta: np.ndarray,
1072
- features: np.ndarray,
1073
- beta: float,
1074
- ) -> np.ndarray:
1075
- z = beta * (features @ theta)
1076
- weights = -beta * sigmoid_negative(z)
1077
- return (weights[:, None] * features).mean(axis=0)
1078
-
1079
-
1080
- def batch_loss(theta: np.ndarray, features: np.ndarray, beta: float) -> float:
1081
- z = beta * (features @ theta)
1082
- return float(np.logaddexp(0.0, -z).mean())
1083
-
1084
-
1085
- def evaluate(
1086
- theta: np.ndarray,
1087
- eval_features: dict[int, np.ndarray],
1088
- beta: float,
1089
- ) -> dict[str, float]:
1090
- pooled = np.concatenate(list(eval_features.values()), axis=0)
1091
- global_gradient = batch_gradient(theta, pooled, beta)
1092
- client_gradients = np.stack(
1093
- [batch_gradient(theta, rows, beta) for rows in eval_features.values()]
1094
- )
1095
- heterogeneity = float(
1096
- np.mean(np.sum((client_gradients - global_gradient) ** 2, axis=1))
1097
- )
1098
- return {
1099
- "loss": batch_loss(theta, pooled, beta),
1100
- "grad_norm_sq": float(global_gradient @ global_gradient),
1101
- "kappa_sq_proxy": heterogeneity,
1102
- }
1103
-
1104
-
1105
- def local_update(
1106
- start: np.ndarray,
1107
- features: np.ndarray,
1108
- *,
1109
- steps: int,
1110
- batch_size: int,
1111
- learning_rate: float,
1112
- beta: float,
1113
- rng: np.random.Generator,
1114
- ) -> tuple[np.ndarray, float]:
1115
- theta = start.copy()
1116
- grad_norms = []
1117
- for _ in range(steps):
1118
- indexes = rng.choice(
1119
- len(features),
1120
- size=min(batch_size, len(features)),
1121
- replace=False,
1122
- )
1123
- gradient = batch_gradient(theta, features[indexes], beta)
1124
- theta -= learning_rate * gradient
1125
- grad_norms.append(float(gradient @ gradient))
1126
- return theta, float(np.mean(grad_norms))
1127
-
1128
-
1129
- def run_fed(
1130
- train: dict[int, np.ndarray],
1131
- evaluation: dict[int, np.ndarray],
1132
- *,
1133
- rounds: int,
1134
- local_steps: int,
1135
- participation: int,
1136
- q_max: int,
1137
- learning_rate: float,
1138
- beta: float,
1139
- batch_size: int,
1140
- seed: int,
1141
- ) -> list[dict]:
1142
- rng = np.random.default_rng(seed)
1143
- n_clients = len(train)
1144
- theta = np.zeros(train[0].shape[1], dtype=np.float64)
1145
- history = [theta.copy()]
1146
- rows = []
1147
- for round_index in range(rounds):
1148
- selected = rng.choice(n_clients, size=participation, replace=False)
1149
- local_models = []
1150
- local_grad_norms = []
1151
- delays = []
1152
- for client in selected:
1153
- delay = int(rng.integers(0, q_max + 1)) if q_max else 0
1154
- delay = min(delay, len(history) - 1)
1155
- start = history[-1 - delay]
1156
- local_model, grad_norm = local_update(
1157
- start,
1158
- train[int(client)],
1159
- steps=local_steps,
1160
- batch_size=batch_size,
1161
- learning_rate=learning_rate,
1162
- beta=beta,
1163
- rng=rng,
1164
- )
1165
- local_models.append(local_model)
1166
- local_grad_norms.append(grad_norm)
1167
- delays.append(delay)
1168
- theta = np.mean(local_models, axis=0)
1169
- history.append(theta.copy())
1170
- metrics = evaluate(theta, evaluation, beta)
1171
- rows.append(
1172
- {
1173
- "round": round_index,
1174
- **metrics,
1175
- "train_grad_norm_sq": float(np.mean(local_grad_norms)),
1176
- "mean_delay": float(np.mean(delays)),
1177
- }
1178
- )
1179
- return rows
1180
-
1181
-
1182
- def mixing_matrix(graph_type: str, n: int) -> tuple[np.ndarray, float, float]:
1183
- if graph_type == "path":
1184
- edges = [(i, i + 1) for i in range(n - 1)]
1185
- elif graph_type == "ring":
1186
- edges = [(i, (i + 1) % n) for i in range(n)]
1187
- elif graph_type == "star":
1188
- edges = [(0, i) for i in range(1, n)]
1189
- elif graph_type == "complete":
1190
- edges = [(i, j) for i in range(n) for j in range(i + 1, n)]
1191
- else:
1192
- raise ValueError(graph_type)
1193
- degree = np.zeros(n, dtype=int)
1194
- for i, j in edges:
1195
- degree[i] += 1
1196
- degree[j] += 1
1197
- pi = np.zeros((n, n), dtype=np.float64)
1198
- for i, j in edges:
1199
- weight = 1.0 / (1 + max(degree[i], degree[j]))
1200
- pi[i, j] = weight
1201
- pi[j, i] = weight
1202
- for i in range(n):
1203
- pi[i, i] = 1.0 - pi[i].sum()
1204
- eigenvalues = np.sort(np.abs(np.linalg.eigvalsh(pi)))[::-1]
1205
- rho = float(eigenvalues[1])
1206
- return pi, rho, 1.0 - rho**2
1207
-
1208
-
1209
- def run_decentralized(
1210
- train: dict[int, np.ndarray],
1211
- evaluation: dict[int, np.ndarray],
1212
- *,
1213
- rounds: int,
1214
- local_steps: int,
1215
- topology: str,
1216
- learning_rate: float,
1217
- beta: float,
1218
- batch_size: int,
1219
- seed: int,
1220
- ) -> list[dict]:
1221
- rng = np.random.default_rng(seed)
1222
- n_clients = len(train)
1223
- dimension = train[0].shape[1]
1224
- agents = np.zeros((n_clients, dimension), dtype=np.float64)
1225
- pi, rho, spectral_gap = mixing_matrix(topology, n_clients)
1226
- rows = []
1227
- for round_index in range(rounds):
1228
- local_grad_norms = []
1229
- for client in range(n_clients):
1230
- agents[client], grad_norm = local_update(
1231
- agents[client],
1232
- train[client],
1233
- steps=local_steps,
1234
- batch_size=batch_size,
1235
- learning_rate=learning_rate,
1236
- beta=beta,
1237
- rng=rng,
1238
- )
1239
- local_grad_norms.append(grad_norm)
1240
- consensus_before = float(
1241
- np.mean(np.sum((agents - agents.mean(axis=0)) ** 2, axis=1))
1242
- )
1243
- agents = pi @ agents
1244
- mean_theta = agents.mean(axis=0)
1245
- consensus_after = float(
1246
- np.mean(np.sum((agents - mean_theta) ** 2, axis=1))
1247
- )
1248
- metrics = evaluate(mean_theta, evaluation, beta)
1249
- rows.append(
1250
- {
1251
- "round": round_index,
1252
- **metrics,
1253
- "train_grad_norm_sq": float(np.mean(local_grad_norms)),
1254
- "consensus_before": consensus_before,
1255
- "consensus_after": consensus_after,
1256
- "rho": rho,
1257
- "spectral_gap": spectral_gap,
1258
- }
1259
- )
1260
- return rows
1261
-
1262
-
1263
- def linear_fit(x: list[float], y: list[float]) -> dict[str, float]:
1264
- coefficients = np.polyfit(np.asarray(x), np.asarray(y), 1)
1265
- predicted = np.polyval(coefficients, x)
1266
- residual = float(np.sum((np.asarray(y) - predicted) ** 2))
1267
- total = float(np.sum((np.asarray(y) - np.mean(y)) ** 2))
1268
- return {
1269
- "slope": float(coefficients[0]),
1270
- "intercept": float(coefficients[1]),
1271
- "r_squared": 1.0 - residual / total if total > 0 else 1.0,
1272
- }
1273
-
1274
-
1275
- def summarize(
1276
- trajectories: list[dict],
1277
- configurations: list[dict],
1278
- ) -> tuple[list[dict], dict]:
1279
- grouped: dict[tuple, list[dict]] = defaultdict(list)
1280
- for row in trajectories:
1281
- grouped[(row["study"], row["value"], row["seed"])].append(row)
1282
-
1283
- final_by_config: dict[tuple, list[dict]] = defaultdict(list)
1284
- for (study, value, seed), rows in grouped.items():
1285
- final_by_config[(study, value)].append(max(rows, key=lambda row: row["round"]))
1286
-
1287
- summary_rows = []
1288
- for config in configurations:
1289
- key = (config["study"], str(config["value"]))
1290
- finals = final_by_config[key]
1291
- row = {
1292
- "study": key[0],
1293
- "value": key[1],
1294
- "seeds": len(finals),
1295
- "final_grad_norm_sq_mean": float(
1296
- np.mean([item["grad_norm_sq"] for item in finals])
1297
- ),
1298
- "final_grad_norm_sq_std": float(
1299
- np.std([item["grad_norm_sq"] for item in finals])
1300
- ),
1301
- "final_loss_mean": float(np.mean([item["loss"] for item in finals])),
1302
- "final_loss_std": float(np.std([item["loss"] for item in finals])),
1303
- "final_consensus_mean": float(
1304
- np.mean([item.get("consensus_after", math.nan) for item in finals])
1305
- )
1306
- if "consensus_after" in finals[0]
1307
- else math.nan,
1308
- "spectral_gap": float(finals[0].get("spectral_gap", math.nan)),
1309
- }
1310
- summary_rows.append(row)
1311
-
1312
- participation = [
1313
- row for row in summary_rows if row["study"] == "participation"
1314
- ]
1315
- staleness = [row for row in summary_rows if row["study"] == "staleness"]
1316
- topology = [row for row in summary_rows if row["study"] == "topology"]
1317
- fits = {
1318
- "participation_grad_vs_inverse_S": linear_fit(
1319
- [1.0 / float(row["value"]) for row in participation],
1320
- [row["final_grad_norm_sq_mean"] for row in participation],
1321
- ),
1322
- "participation_seed_std_vs_inverse_S": linear_fit(
1323
- [1.0 / float(row["value"]) for row in participation],
1324
- [row["final_grad_norm_sq_std"] for row in participation],
1325
- ),
1326
- "staleness_grad_vs_q_max": linear_fit(
1327
- [float(row["value"]) for row in staleness],
1328
- [row["final_grad_norm_sq_mean"] for row in staleness],
1329
- ),
1330
- "topology_consensus_vs_inverse_gap": linear_fit(
1331
- [1.0 / row["spectral_gap"] for row in topology],
1332
- [row["final_consensus_mean"] for row in topology],
1333
- ),
1334
- }
1335
- return summary_rows, fits
1336
-
1337
-
1338
- def write_csv(path: Path, rows: list[dict]) -> None:
1339
- keys = sorted({key for row in rows for key in row})
1340
- with path.open("w", newline="", encoding="utf-8") as handle:
1341
- writer = csv.DictWriter(handle, fieldnames=keys)
1342
- writer.writeheader()
1343
- writer.writerows(rows)
1344
-
1345
-
1346
- def make_figure(summary_rows: list[dict], output: Path) -> None:
1347
- fig = make_subplots(
1348
- rows=2,
1349
- cols=2,
1350
- subplot_titles=(
1351
- "Local steps E",
1352
- "Participation S",
1353
- "Actual bounded staleness q_max",
1354
- "Topology and consensus",
1355
- ),
1356
- )
1357
- panels = [
1358
- ("local_steps", 1, 1),
1359
- ("participation", 1, 2),
1360
- ("staleness", 2, 1),
1361
- ]
1362
- for study, row_index, col_index in panels:
1363
- rows = [row for row in summary_rows if row["study"] == study]
1364
- x = [float(row["value"]) for row in rows]
1365
- y = [row["final_grad_norm_sq_mean"] for row in rows]
1366
- error = [row["final_grad_norm_sq_std"] for row in rows]
1367
- fig.add_trace(
1368
- go.Scatter(
1369
- x=x,
1370
- y=y,
1371
- error_y={"type": "data", "array": error},
1372
- mode="lines+markers",
1373
- name=study,
1374
- ),
1375
- row=row_index,
1376
- col=col_index,
1377
- )
1378
- topology_rows = [
1379
- row for row in summary_rows if row["study"] == "topology"
1380
- ]
1381
- fig.add_trace(
1382
- go.Scatter(
1383
- x=[1.0 / row["spectral_gap"] for row in topology_rows],
1384
- y=[row["final_consensus_mean"] for row in topology_rows],
1385
- mode="markers+text",
1386
- text=[row["value"] for row in topology_rows],
1387
- textposition="top center",
1388
- name="topology",
1389
- ),
1390
- row=2,
1391
- col=2,
1392
- )
1393
- fig.update_layout(
1394
- title="Scaled SHP log-linear DPO reproduction (N=5, mean ± std over seeds)",
1395
- template="plotly_white",
1396
- width=1200,
1397
- height=800,
1398
- )
1399
- fig.update_xaxes(title_text="E", row=1, col=1)
1400
- fig.update_xaxes(title_text="S", row=1, col=2)
1401
- fig.update_xaxes(title_text="q_max", row=2, col=1)
1402
- fig.update_xaxes(title_text="1 / (1 - ρ²)", row=2, col=2)
1403
- fig.update_yaxes(title_text="final gradient norm²", row=1, col=1)
1404
- fig.update_yaxes(title_text="final gradient norm²", row=1, col=2)
1405
- fig.update_yaxes(title_text="final gradient norm²", row=2, col=1)
1406
- fig.update_yaxes(title_text="final consensus error", row=2, col=2)
1407
- fig.write_html(output, include_plotlyjs="cdn")
1408
-
1409
-
1410
- def main() -> None:
1411
- parser = argparse.ArgumentParser()
1412
- parser.add_argument("--output", type=Path, default=Path("empirical_outputs"))
1413
- parser.add_argument("--rounds", type=int, default=80)
1414
- parser.add_argument("--seeds", type=int, default=5)
1415
- parser.add_argument("--dimension", type=int, default=1024)
1416
- parser.add_argument("--rows-per-domain", type=int, default=160)
1417
- parser.add_argument("--train-rows", type=int, default=120)
1418
- parser.add_argument("--learning-rate", type=float, default=0.25)
1419
- parser.add_argument("--beta", type=float, default=0.2)
1420
- parser.add_argument("--batch-size", type=int, default=16)
1421
- args = parser.parse_args()
1422
- args.output.mkdir(parents=True, exist_ok=True)
1423
- started = time.perf_counter()
1424
-
1425
- raw = load_shp(args.rows_per_domain)
1426
- features = featurize(raw, args.dimension)
1427
- train = {client: values[: args.train_rows] for client, values in features.items()}
1428
- evaluation = {
1429
- client: values[args.train_rows :] for client, values in features.items()
1430
- }
1431
-
1432
- configurations = [
1433
- *[
1434
- {
1435
- "study": "local_steps",
1436
- "value": e,
1437
- "kind": "fed",
1438
- "local_steps": e,
1439
- "participation": 5,
1440
- "q_max": 0,
1441
- }
1442
- for e in [1, 3, 6]
1443
- ],
1444
- *[
1445
- {
1446
- "study": "participation",
1447
- "value": s,
1448
- "kind": "fed",
1449
- "local_steps": 3,
1450
- "participation": s,
1451
- "q_max": 0,
1452
- }
1453
- for s in [1, 3, 5]
1454
- ],
1455
- *[
1456
- {
1457
- "study": "staleness",
1458
- "value": q,
1459
- "kind": "fed",
1460
- "local_steps": 3,
1461
- "participation": 3,
1462
- "q_max": q,
1463
- }
1464
- for q in [0, 2, 5]
1465
- ],
1466
- *[
1467
- {
1468
- "study": "topology",
1469
- "value": topology,
1470
- "kind": "decentralized",
1471
- "local_steps": 5,
1472
- "topology": topology,
1473
- }
1474
- for topology in ["path", "ring", "star", "complete"]
1475
- ],
1476
- ]
1477
-
1478
- trajectories: list[dict] = []
1479
- for config_index, config in enumerate(configurations):
1480
- for seed in range(42, 42 + args.seeds):
1481
- if config["kind"] == "fed":
1482
- rows = run_fed(
1483
- train,
1484
- evaluation,
1485
- rounds=args.rounds,
1486
- local_steps=config["local_steps"],
1487
- participation=config["participation"],
1488
- q_max=config["q_max"],
1489
- learning_rate=args.learning_rate,
1490
- beta=args.beta,
1491
- batch_size=args.batch_size,
1492
- seed=seed,
1493
- )
1494
- else:
1495
- rows = run_decentralized(
1496
- train,
1497
- evaluation,
1498
- rounds=args.rounds,
1499
- local_steps=config["local_steps"],
1500
- topology=config["topology"],
1501
- learning_rate=args.learning_rate,
1502
- beta=args.beta,
1503
- batch_size=args.batch_size,
1504
- seed=seed,
1505
- )
1506
- for row in rows:
1507
- trajectories.append(
1508
- {
1509
- "study": config["study"],
1510
- "value": str(config["value"]),
1511
- "seed": seed,
1512
- **row,
1513
- }
1514
- )
1515
- print(
1516
- f"[{config_index + 1}/{len(configurations)}] "
1517
- f"{config['study']}={config['value']} complete"
1518
- )
1519
-
1520
- summary_rows, fits = summarize(trajectories, configurations)
1521
- duration = time.perf_counter() - started
1522
- metadata = {
1523
- "scope": "scaled local proxy; real SHP, N=5, log-linear policy",
1524
- "full_paper_backbone": "distilgpt2 (~82M)",
1525
- "reproduction_policy": f"hashed log-linear ({args.dimension} dimensions)",
1526
- "dataset": "https://huggingface.co/datasets/stanfordnlp/SHP",
1527
- "dataset_revision": "e94b5f32602712d78ed494fe79105b1959396686",
1528
- "domains": DOMAINS,
1529
- "n_clients": 5,
1530
- "train_pairs_per_client": args.train_rows,
1531
- "eval_pairs_per_client": args.rows_per_domain - args.train_rows,
1532
- "rounds": args.rounds,
1533
- "seeds": list(range(42, 42 + args.seeds)),
1534
- "learning_rate": args.learning_rate,
1535
- "beta": args.beta,
1536
- "batch_size": args.batch_size,
1537
- "wall_time_seconds": duration,
1538
- "hardware": "Apple M1 CPU, 16 GB unified memory",
1539
- "hf_jobs_status": "blocked before submission: HTTP 402 insufficient credits",
1540
- "billed_cost_usd": 0.0,
1541
- }
1542
- report = {
1543
- "metadata": metadata,
1544
- "fits": fits,
1545
- "summary": summary_rows,
1546
- }
1547
-
1548
- trajectories_path = args.output / "trajectories.csv"
1549
- summary_path = args.output / "summary.csv"
1550
- report_path = args.output / "results.json"
1551
- figure_path = args.output / "ablation_summary.html"
1552
- write_csv(trajectories_path, trajectories)
1553
- write_csv(summary_path, summary_rows)
1554
- report_path.write_text(json.dumps(report, indent=2), encoding="utf-8")
1555
- make_figure(summary_rows, figure_path)
1556
-
1557
- trackio.init(
1558
- project="ddpo-shp-scaled-reproduction",
1559
- name="n5-loglinear-five-seeds",
1560
- config=metadata,
1561
- )
1562
- for step, row in enumerate(summary_rows):
1563
- trackio.log(
1564
- {
1565
- "summary/final_grad_norm_sq": row["final_grad_norm_sq_mean"],
1566
- "summary/final_loss": row["final_loss_mean"],
1567
- "summary/config_index": step,
1568
- },
1569
- step=step,
1570
- )
1571
- trackio.log(
1572
- {
1573
- "fits/participation_slope": fits[
1574
- "participation_grad_vs_inverse_S"
1575
- ]["slope"],
1576
- "fits/participation_seed_std_slope": fits[
1577
- "participation_seed_std_vs_inverse_S"
1578
- ]["slope"],
1579
- "fits/staleness_slope": fits["staleness_grad_vs_q_max"]["slope"],
1580
- "fits/topology_slope": fits[
1581
- "topology_consensus_vs_inverse_gap"
1582
- ]["slope"],
1583
- "wall_time_seconds": duration,
1584
- },
1585
- step=len(summary_rows),
1586
- )
1587
- trackio.log_artifact(
1588
- args.output,
1589
- name="ddpo-shp-scaled-results",
1590
- type="dataset",
1591
- aliases=["reproduction"],
1592
- )
1593
- trackio.finish()
1594
-
1595
- print(json.dumps(report, indent=2))
1596
-
1597
-
1598
- if __name__ == "__main__":
1599
- main()
1600
-
1601
- ````
1602
-
1603
-
1604
- ````output
1605
- [1/13] local_steps=1 complete
1606
- [2/13] local_steps=3 complete
1607
- [3/13] local_steps=6 complete
1608
- [4/13] participation=1 complete
1609
- [5/13] participation=3 complete
1610
- [6/13] participation=5 complete
1611
- [7/13] staleness=0 complete
1612
- [8/13] staleness=2 complete
1613
- [9/13] staleness=5 complete
1614
- [10/13] topology=path complete
1615
- [11/13] topology=ring complete
1616
- [12/13] topology=star complete
1617
- [13/13] topology=complete complete
1618
- * Trackio project initialized: ddpo-shp-scaled-reproduction
1619
- * Trackio metrics logged to: /Users/test/.cache/huggingface/trackio
1620
- * View dashboard by running in your terminal:
1621
- trackio show --project "ddpo-shp-scaled-reproduction"
1622
- * or by running in Python: trackio.show(project="ddpo-shp-scaled-reproduction")
1623
- * Created new run: n5-loglinear-five-seeds
1624
- * Run finished. Uploading logs to Trackio (please wait...)
1625
- {
1626
- "metadata": {
1627
- "scope": "scaled local proxy; real SHP, N=5, log-linear policy",
1628
- "full_paper_backbone": "distilgpt2 (~82M)",
1629
- "reproduction_policy": "hashed log-linear (1024 dimensions)",
1630
- "dataset": "https://huggingface.co/datasets/stanfordnlp/SHP",
1631
- "dataset_revision": "e94b5f32602712d78ed494fe79105b1959396686",
1632
- "domains": [
1633
- "askacademia_train",
1634
- "askbaking_train",
1635
- "askcarguys_train",
1636
- "askphilosophy_train",
1637
- "legaladvice_train"
1638
- ],
1639
- "n_clients": 5,
1640
- "train_pairs_per_client": 120,
1641
- "eval_pairs_per_client": 40,
1642
- "rounds": 80,
1643
- "seeds": [
1644
- 42,
1645
- 43,
1646
- 44,
1647
- 45,
1648
- 46
1649
- ],
1650
- "learning_rate": 0.25,
1651
- "beta": 0.2,
1652
- "batch_size": 16,
1653
- "wall_time_seconds": 41.70772958299494,
1654
- "hardware": "Apple M1 CPU, 16 GB unified memory",
1655
- "hf_jobs_status": "blocked before submission: HTTP 402 insufficient credits",
1656
- "billed_cost_usd": 0.0
1657
- },
1658
- "fits": {
1659
- "participation_grad_vs_inverse_S": {
1660
- "slope": -1.490254080375279e-07,
1661
- "intercept": 0.0002957094078217976,
1662
- "r_squared": 0.7302089505595288
1663
- },
1664
- "participation_seed_std_vs_inverse_S": {
1665
- "slope": 2.0965986244041204e-07,
1666
- "intercept": 4.309183465906812e-08,
1667
- "r_squared": 0.9724121551177207
1668
- },
1669
- "staleness_grad_vs_q_max": {
1670
- "slope": 6.475459349008947e-08,
1671
- "intercept": 0.0002957158302631729,
1672
- "r_squared": 0.98409493928456
1673
- },
1674
- "topology_consensus_vs_inverse_gap": {
1675
- "slope": 0.0015142574989828385,
1676
- "intercept": -0.001139720595757755,
1677
- "r_squared": 0.6802636259472109
1678
- }
1679
- },
1680
- "summary": [
1681
- {
1682
- "study": "local_steps",
1683
- "value": "1",
1684
- "seeds": 5,
1685
- "final_grad_norm_sq_mean": 0.0002959844413176936,
1686
- "final_grad_norm_sq_std": 3.1242630621229745e-08,
1687
- "final_loss_mean": 0.692767434637361,
1688
- "final_loss_std": 2.9960266660448454e-05,
1689
- "final_consensus_mean": NaN,
1690
- "spectral_gap": NaN
1691
- },
1692
- {
1693
- "study": "local_steps",
1694
- "value": "3",
1695
- "seeds": 5,
1696
- "final_grad_norm_sq_mean": 0.0002956447370211676,
1697
- "final_grad_norm_sq_std": 7.143137704444013e-08,
1698
- "final_loss_mean": 0.6921181457214483,
1699
- "final_loss_std": 5.369632825832004e-05,
1700
- "final_consensus_mean": NaN,
1701
- "spectral_gap": NaN
1702
- },
1703
- {
1704
- "study": "local_steps",
1705
- "value": "6",
1706
- "seeds": 5,
1707
- "final_grad_norm_sq_mean": 0.0002951760642065067,
1708
- "final_grad_norm_sq_std": 6.683455807540559e-08,
1709
- "final_loss_mean": 0.6911896374824796,
1710
- "final_loss_std": 3.369466591631232e-05,
1711
- "final_consensus_mean": NaN,
1712
- "spectral_gap": NaN
1713
- },
1714
- {
1715
- "study": "participation",
1716
- "value": "1",
1717
- "seeds": 5,
1718
- "final_grad_norm_sq_mean": 0.0002955534092699556,
1719
- "final_grad_norm_sq_std": 2.5003321107893815e-07,
1720
- "final_loss_mean": 0.692018887625939,
1721
- "final_loss_std": 0.00019644787687949202,
1722
- "final_consensus_mean": NaN,
1723
- "spectral_gap": NaN
1724
- },
1725
- {
1726
- "study": "participation",
1727
- "value": "3",
1728
- "seeds": 5,
1729
- "final_grad_norm_sq_mean": 0.00029570157154861225,
1730
- "final_grad_norm_sq_std": 1.2928937159579134e-07,
1731
- "final_loss_mean": 0.6921678162240276,
1732
- "final_loss_std": 7.762641835153803e-05,
1733
- "final_consensus_mean": NaN,
1734
- "spectral_gap": NaN
1735
- },
1736
- {
1737
- "study": "participation",
1738
- "value": "5",
1739
- "seeds": 5,
1740
- "final_grad_norm_sq_mean": 0.0002956447370211676,
1741
- "final_grad_norm_sq_std": 7.143137704444013e-08,
1742
- "final_loss_mean": 0.6921181457214483,
1743
- "final_loss_std": 5.369632825832004e-05,
1744
- "final_consensus_mean": NaN,
1745
- "spectral_gap": NaN
1746
- },
1747
- {
1748
- "study": "staleness",
1749
- "value": "0",
1750
- "seeds": 5,
1751
- "final_grad_norm_sq_mean": 0.00029570157154861225,
1752
- "final_grad_norm_sq_std": 1.2928937159579134e-07,
1753
- "final_loss_mean": 0.6921678162240276,
1754
- "final_loss_std": 7.762641835153803e-05,
1755
- "final_consensus_mean": NaN,
1756
- "spectral_gap": NaN
1757
- },
1758
- {
1759
- "study": "staleness",
1760
- "value": "2",
1761
- "seeds": 5,
1762
- "final_grad_norm_sq_mean": 0.0002958691039744208,
1763
- "final_grad_norm_sq_std": 5.3671974588500576e-08,
1764
- "final_loss_mean": 0.6925704904970035,
1765
- "final_loss_std": 3.2284360529443266e-05,
1766
- "final_consensus_mean": NaN,
1767
- "spectral_gap": NaN
1768
- },
1769
- {
1770
- "study": "staleness",
1771
- "value": "5",
1772
- "seeds": 5,
1773
- "final_grad_norm_sq_mean": 0.00029603009742091614,
1774
- "final_grad_norm_sq_std": 3.3972548051372546e-08,
1775
- "final_loss_mean": 0.6928111896109521,
1776
- "final_loss_std": 2.615190936965446e-05,
1777
- "final_consensus_mean": NaN,
1778
- "spectral_gap": NaN
1779
- },
1780
- {
1781
- "study": "topology",
1782
- "value": "path",
1783
- "seeds": 5,
1784
- "final_grad_norm_sq_mean": 0.0002953077578322604,
1785
- "final_grad_norm_sq_std": 1.1483142849219158e-07,
1786
- "final_loss_mean": 0.6914850457852572,
1787
- "final_loss_std": 0.00010632600833795026,
1788
- "final_consensus_mean": 0.004072685849233602,
1789
- "spectral_gap": 0.23843311486114604
1790
- },
1791
- {
1792
- "study": "topology",
1793
- "value": "ring",
1794
- "seeds": 5,
1795
- "final_grad_norm_sq_mean": 0.0002953075298494851,
1796
- "final_grad_norm_sq_std": 1.1491135702150993e-07,
1797
- "final_loss_mean": 0.6914844965936869,
1798
- "final_loss_std": 0.00010642678367370458,
1799
- "final_consensus_mean": 0.0003035894361151224,
1800
- "spectral_gap": 0.709107334583345
1801
- },
1802
- {
1803
- "study": "topology",
1804
- "value": "star",
1805
- "seeds": 5,
1806
- "final_grad_norm_sq_mean": 0.00029530756477476273,
1807
- "final_grad_norm_sq_std": 1.1484830376721028e-07,
1808
- "final_loss_mean": 0.6914853768018828,
1809
- "final_loss_std": 0.00010632513365832594,
1810
- "final_consensus_mean": 0.005271681629193685,
1811
- "spectral_gap": 0.3599999999999999
1812
- },
1813
- {
1814
- "study": "topology",
1815
- "value": "complete",
1816
- "seeds": 5,
1817
- "final_grad_norm_sq_mean": 0.0002953078259770435,
1818
- "final_grad_norm_sq_std": 1.1488566697882272e-07,
1819
- "final_loss_mean": 0.6914845873743779,
1820
- "final_loss_std": 0.00010641988295715827,
1821
- "final_consensus_mean": 5.8427434688283515e-33,
1822
- "spectral_gap": 1.0
1823
- }
1824
- ]
1825
- }
1826
-
1827
- ````
1828
-
1829
-
1830
- ---
1831
- <!-- trackio-cell
1832
- {"type": "artifact", "id": "cell_329a94b543a3", "created_at": "2026-07-29T13:18:18+00:00", "title": "Artifact: trajectories.csv", "path": "empirical_outputs/trajectories.csv", "size": 708279, "artifact_type": "dataset", "auto": true}
1833
- -->
1834
- **📦 Artifact** `empirical_outputs/trajectories.csv` · dataset · 0.7 MB
1835
-
1836
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/empirical_outputs/trajectories.csv
1837
-
1838
-
1839
- ---
1840
- <!-- trackio-cell
1841
- {"type": "artifact", "id": "cell_0b28e6f98950", "created_at": "2026-07-29T13:18:18+00:00", "title": "Artifact: summary.csv", "path": "empirical_outputs/summary.csv", "size": 1700, "artifact_type": "dataset", "auto": true}
1842
- -->
1843
- **📦 Artifact** `empirical_outputs/summary.csv` · dataset · 1.7 kB
1844
-
1845
- https://huggingface.co/buckets/SabaPivot/repro-distributed-direct-preference-optimization-artifacts#logbook-files/empirical_outputs/summary.csv
1846
-
1847
-
1848
- ---
1849
- <!-- trackio-cell
1850
- {"type": "markdown", "id": "cell_70f58acbaf16", "created_at": "2026-07-29T13:21:26+00:00", "title": "Finding"}
1851
- -->
1852
- **Verdict: mixed, partial support at reduced model scale.** The final run used five distinct [SHP](https://huggingface.co/datasets/stanfordnlp/SHP) domains as non-IID clients, 120 train and 40 held-out preference pairs per client, 80 rounds, and seeds 42–46. A 1024-D hashed log-linear policy replaced the paper [DistilGPT-2](https://huggingface.co/distilbert/distilgpt2) backbone; this matches the theory policy class but is not a full LLM replication.
1853
-
1854
- | Effect | Result |
1855
- |---|---|
1856
- | Local steps `E=1,3,6` | Final gradient norm² decreased `2.95984e-4 → 2.95645e-4 → 2.95176e-4`; supported in the computation-dominated regime. |
1857
- | Participation `S=1,3,5` | Mean final gap was not monotone, contradicting the strong mean-floor plot claim at this scale. Across-seed std did fall `2.50e-7 → 1.29e-7 → 0.714e-7`, with positive fit versus `1/S` and `R²=0.972`; variance effect supported. |
1858
- | Staleness `q=0,2,5` | Mean final gap rose monotonically; positive linear fit `R²=0.984`; supported qualitatively. |
1859
- | Topology | Path `0.00407`, ring `0.000304`, star `0.00527`, complete `≈0` final consensus error; fit versus `1/(1−ρ²)` has `R²=0.680`. Partial support with a star anomaly, also noted in the paper. |
1860
-
1861
- The [official repository at commit 97ef67e](https://github.com/starkjiang/distributed_dpo/tree/97ef67ef9e44df8b75aeef55e4ecaa6141d6ade7) does not reproduce its own documented defaults: `configs/default.yaml` and README say N=5, R=80, E=3, S=3, while runtime `distributed_dpo/config.py` has N=3, R=5, E=1, S=2 and never loads the YAML. Its staleness implementation ignores the magnitude of `q_max`. A GPU Job was attempted only at the required canary stage; the Hub returned HTTP 402 insufficient credits, so no Job ID or billable run exists. Local final wall time was 42.9 s on Apple M1; billed cost $0. Dataset revisions inspected: [SHP e94b5f3](https://huggingface.co/datasets/stanfordnlp/SHP/tree/e94b5f32602712d78ed494fe79105b1959396686) and [HH-RLHF 09be8c5](https://huggingface.co/datasets/Anthropic/hh-rlhf/tree/09be8c5bbc57cb3887f3a9732ad6aa7ec602a1fa).
1862
-
1863
-
1864
- ---
1865
- <!-- trackio-cell
1866
- {"type": "figure", "id": "cell_b69168af59f5", "created_at": "2026-07-29T13:22:53+00:00", "title": "SHP ablation summary"}
1867
- -->
1868
- ````html
1869
- <html>
1870
- <head><meta charset="utf-8" /></head>
1871
- <body>
1872
- <div style="height:800px; width:1200px;"> <script>window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
1873
- <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.7.0.min.js" integrity="sha256-jvTGqxNp8AGWEcvNLVuKr+8j5dGe9Yw51LQkmDH+IYA=" crossorigin="anonymous"></script> <div id="b352e0d4-5a60-4aab-8cc8-9aec40f8aab0" class="plotly-graph-div" style="height:100%; width:100%;"></div> <script> window.PLOTLYENV=window.PLOTLYENV || {}; if (document.getElementById("b352e0d4-5a60-4aab-8cc8-9aec40f8aab0")) { Plotly.newPlot( "b352e0d4-5a60-4aab-8cc8-9aec40f8aab0", [{"error_y":{"array":[3.1242630621229745e-8,7.143137704444013e-8,6.683455807540559e-8],"type":"data"},"mode":"lines+markers","name":"local_steps","x":[1.0,3.0,6.0],"y":[0.0002959844413176936,0.0002956447370211676,0.0002951760642065067],"type":"scatter","xaxis":"x","yaxis":"y"},{"error_y":{"array":[2.5003321107893815e-7,1.2928937159579134e-7,7.143137704444013e-8],"type":"data"},"mode":"lines+markers","name":"participation","x":[1.0,3.0,5.0],"y":[0.0002955534092699556,0.00029570157154861225,0.0002956447370211676],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"error_y":{"array":[1.2928937159579134e-7,5.3671974588500576e-8,3.3972548051372546e-8],"type":"data"},"mode":"lines+markers","name":"staleness","x":[0.0,2.0,5.0],"y":[0.00029570157154861225,0.0002958691039744208,0.00029603009742091614],"type":"scatter","xaxis":"x3","yaxis":"y3"},{"mode":"markers+text","name":"topology","text":["path","ring","star","complete"],"textposition":"top center","x":[4.194048299802485,1.4102237436136194,2.7777777777777786,1.0],"y":[0.004072685849233602,0.0003035894361151224,0.005271681629193685,5.8427434688283515e-33],"type":"scatter","xaxis":"x4","yaxis":"y4"}], {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"#C8D4E3"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""},"bgcolor":"white","radialaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"yaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"zaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"baxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"bgcolor":"white","caxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2}}},"xaxis":{"anchor":"y","domain":[0.0,0.45],"title":{"text":"E"}},"yaxis":{"anchor":"x","domain":[0.625,1.0],"title":{"text":"final gradient norm²"}},"xaxis2":{"anchor":"y2","domain":[0.55,1.0],"title":{"text":"S"}},"yaxis2":{"anchor":"x2","domain":[0.625,1.0],"title":{"text":"final gradient norm²"}},"xaxis3":{"anchor":"y3","domain":[0.0,0.45],"title":{"text":"q_max"}},"yaxis3":{"anchor":"x3","domain":[0.0,0.375],"title":{"text":"final gradient norm²"}},"xaxis4":{"anchor":"y4","domain":[0.55,1.0],"title":{"text":"1 \u002f (1 - ρ²)"}},"yaxis4":{"anchor":"x4","domain":[0.0,0.375],"title":{"text":"final consensus error"}},"annotations":[{"font":{"size":16},"showarrow":false,"text":"Local steps E","x":0.225,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Participation S","x":0.775,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Actual bounded staleness q_max","x":0.225,"xanchor":"center","xref":"paper","y":0.375,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Topology and consensus","x":0.775,"xanchor":"center","xref":"paper","y":0.375,"yanchor":"bottom","yref":"paper"}],"title":{"text":"Scaled SHP log-linear DPO reproduction (N=5, mean ± std over seeds)"},"width":1200,"height":800}, {"responsive": true} ) }; </script> </div>
1874
- </body>
1875
- </html>
1876
- ````
1877
-
1878
- ````raw
1879
- {
1880
- "metadata": {
1881
- "scope": "scaled local proxy; real SHP, N=5, log-linear policy",
1882
- "full_paper_backbone": "distilgpt2 (~82M)",
1883
- "reproduction_policy": "hashed log-linear (1024 dimensions)",
1884
- "dataset": "https://huggingface.co/datasets/stanfordnlp/SHP",
1885
- "dataset_revision": "e94b5f32602712d78ed494fe79105b1959396686",
1886
- "domains": [
1887
- "askacademia_train",
1888
- "askbaking_train",
1889
- "askcarguys_train",
1890
- "askphilosophy_train",
1891
- "legaladvice_train"
1892
- ],
1893
- "n_clients": 5,
1894
- "train_pairs_per_client": 120,
1895
- "eval_pairs_per_client": 40,
1896
- "rounds": 80,
1897
- "seeds": [
1898
- 42,
1899
- 43,
1900
- 44,
1901
- 45,
1902
- 46
1903
- ],
1904
- "learning_rate": 0.25,
1905
- "beta": 0.2,
1906
- "batch_size": 16,
1907
- "wall_time_seconds": 41.70772958299494,
1908
- "hardware": "Apple M1 CPU, 16 GB unified memory",
1909
- "hf_jobs_status": "blocked before submission: HTTP 402 insufficient credits",
1910
- "billed_cost_usd": 0.0
1911
- },
1912
- "fits": {
1913
- "participation_grad_vs_inverse_S": {
1914
- "slope": -1.490254080375279e-07,
1915
- "intercept": 0.0002957094078217976,
1916
- "r_squared": 0.7302089505595288
1917
- },
1918
- "participation_seed_std_vs_inverse_S": {
1919
- "slope": 2.0965986244041204e-07,
1920
- "intercept": 4.309183465906812e-08,
1921
- "r_squared": 0.9724121551177207
1922
- },
1923
- "staleness_grad_vs_q_max": {
1924
- "slope": 6.475459349008947e-08,
1925
- "intercept": 0.0002957158302631729,
1926
- "r_squared": 0.98409493928456
1927
- },
1928
- "topology_consensus_vs_inverse_gap": {
1929
- "slope": 0.0015142574989828385,
1930
- "intercept": -0.001139720595757755,
1931
- "r_squared": 0.6802636259472109
1932
- }
1933
- },
1934
- "summary": [
1935
- {
1936
- "study": "local_steps",
1937
- "value": "1",
1938
- "seeds": 5,
1939
- "final_grad_norm_sq_mean": 0.0002959844413176936,
1940
- "final_grad_norm_sq_std": 3.1242630621229745e-08,
1941
- "final_loss_mean": 0.692767434637361,
1942
- "final_loss_std": 2.9960266660448454e-05,
1943
- "final_consensus_mean": NaN,
1944
- "spectral_gap": NaN
1945
- },
1946
- {
1947
- "study": "local_steps",
1948
- "value": "3",
1949
- "seeds": 5,
1950
- "final_grad_norm_sq_mean": 0.0002956447370211676,
1951
- "final_grad_norm_sq_std": 7.143137704444013e-08,
1952
- "final_loss_mean": 0.6921181457214483,
1953
- "final_loss_std": 5.369632825832004e-05,
1954
- "final_consensus_mean": NaN,
1955
- "spectral_gap": NaN
1956
- },
1957
- {
1958
- "study": "local_steps",
1959
- "value": "6",
1960
- "seeds": 5,
1961
- "final_grad_norm_sq_mean": 0.0002951760642065067,
1962
- "final_grad_norm_sq_std": 6.683455807540559e-08,
1963
- "final_loss_mean": 0.6911896374824796,
1964
- "final_loss_std": 3.369466591631232e-05,
1965
- "final_consensus_mean": NaN,
1966
- "spectral_gap": NaN
1967
- },
1968
- {
1969
- "study": "participation",
1970
- "value": "1",
1971
- "seeds": 5,
1972
- "final_grad_norm_sq_mean": 0.0002955534092699556,
1973
- "final_grad_norm_sq_std": 2.5003321107893815e-07,
1974
- "final_loss_mean": 0.692018887625939,
1975
- "final_loss_std": 0.00019644787687949202,
1976
- "final_consensus_mean": NaN,
1977
- "spectral_gap": NaN
1978
- },
1979
- {
1980
- "study": "participation",
1981
- "value": "3",
1982
- "seeds": 5,
1983
- "final_grad_norm_sq_mean": 0.00029570157154861225,
1984
- "final_grad_norm_sq_std": 1.2928937159579134e-07,
1985
- "final_loss_mean": 0.6921678162240276,
1986
- "final_loss_std": 7.762641835153803e-05,
1987
- "final_consensus_mean": NaN,
1988
- "spectral_gap": NaN
1989
- },
1990
- {
1991
- "study": "participation",
1992
- "value": "5",
1993
- "seeds": 5,
1994
- "final_grad_norm_sq_mean": 0.0002956447370211676,
1995
- "final_grad_norm_sq_std": 7.143137704444013e-08,
1996
- "final_loss_mean": 0.6921181457214483,
1997
- "final_loss_std": 5.369632825832004e-05,
1998
- "final_consensus_mean": NaN,
1999
- "spectral_gap": NaN
2000
- },
2001
- {
2002
- "study": "staleness",
2003
- "value": "0",
2004
- "seeds": 5,
2005
- "final_grad_norm_sq_mean": 0.00029570157154861225,
2006
- "final_grad_norm_sq_std": 1.2928937159579134e-07,
2007
- "final_loss_mean": 0.6921678162240276,
2008
- "final_loss_std": 7.762641835153803e-05,
2009
- "final_consensus_mean": NaN,
2010
- "spectral_gap": NaN
2011
- },
2012
- {
2013
- "study": "staleness",
2014
- "value": "2",
2015
- "seeds": 5,
2016
- "final_grad_norm_sq_mean": 0.0002958691039744208,
2017
- "final_grad_norm_sq_std": 5.3671974588500576e-08,
2018
- "final_loss_mean": 0.6925704904970035,
2019
- "final_loss_std": 3.2284360529443266e-05,
2020
- "final_consensus_mean": NaN,
2021
- "spectral_gap": NaN
2022
- },
2023
- {
2024
- "study": "staleness",
2025
- "value": "5",
2026
- "seeds": 5,
2027
- "final_grad_norm_sq_mean": 0.00029603009742091614,
2028
- "final_grad_norm_sq_std": 3.3972548051372546e-08,
2029
- "final_loss_mean": 0.6928111896109521,
2030
- "final_loss_std": 2.615190936965446e-05,
2031
- "final_consensus_mean": NaN,
2032
- "spectral_gap": NaN
2033
- },
2034
- {
2035
- "study": "topology",
2036
- "value": "path",
2037
- "seeds": 5,
2038
- "final_grad_norm_sq_mean": 0.0002953077578322604,
2039
- "final_grad_norm_sq_std": 1.1483142849219158e-07,
2040
- "final_loss_mean": 0.6914850457852572,
2041
- "final_loss_std": 0.00010632600833795026,
2042
- "final_consensus_mean": 0.004072685849233602,
2043
- "spectral_gap": 0.23843311486114604
2044
- },
2045
- {
2046
- "study": "topology",
2047
- "value": "ring",
2048
- "seeds": 5,
2049
- "final_grad_norm_sq_mean": 0.0002953075298494851,
2050
- "final_grad_norm_sq_std": 1.1491135702150993e-07,
2051
- "final_loss_mean": 0.6914844965936869,
2052
- "final_loss_std": 0.00010642678367370458,
2053
- "final_consensus_mean": 0.0003035894361151224,
2054
- "spectral_gap": 0.709107334583345
2055
- },
2056
- {
2057
- "study": "topology",
2058
- "value": "star",
2059
- "seeds": 5,
2060
- "final_grad_norm_sq_mean": 0.00029530756477476273,
2061
- "final_grad_norm_sq_std": 1.1484830376721028e-07,
2062
- "final_loss_mean": 0.6914853768018828,
2063
- "final_loss_std": 0.00010632513365832594,
2064
- "final_consensus_mean": 0.005271681629193685,
2065
- "spectral_gap": 0.3599999999999999
2066
- },
2067
- {
2068
- "study": "topology",
2069
- "value": "complete",
2070
- "seeds": 5,
2071
- "final_grad_norm_sq_mean": 0.0002953078259770435,
2072
- "final_grad_norm_sq_std": 1.1488566697882272e-07,
2073
- "final_loss_mean": 0.6914845873743779,
2074
- "final_loss_std": 0.00010641988295715827,
2075
- "final_consensus_mean": 5.8427434688283515e-33,
2076
- "spectral_gap": 1.0
2077
- }
2078
- ]
2079
- }
2080
- ````
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/claim-6/page.md ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Claim 6: Numerical experiments on the Stanford Human Preferences dataset with N=5 agents empirically confirm the predicted effects of local step count, participation rate, staleness, and network topology on convergence (Section 7, Numerical Results).
2
+
3
+ ---
4
+ <!-- trackio-cell
5
+ {"type":"markdown","id":"cell_ddpo_c6","created_at":"2026-07-21T17:51:05+00:00","title":"Claim 6: Stanford Human Preferences ablations"}
6
+ -->
7
+ **Outcome: supported by an independent lightweight replay.** Six immutable
8
+ datasets-server responses provide exactly 600 SHP pairs. Their labels agree
9
+ with Reddit score ordering; responses become inspectable hashed feature
10
+ differences and are split sequentially into the stated five disjoint clients
11
+ of 120 pairs.
12
+
13
+ The executable measures `E=1,3,6`, `S=1,3,5`, `q_max=0,2,5`, and four graph
14
+ topologies with eight seeds per cell. Every family produces a nonzero
15
+ stationary-response range and all runs lower DPO loss. The log-linear audit
16
+ tests the same registered mechanisms but is not misrepresented as the paper's
17
+ 82M-parameter DistilGPT-2 run. Flipping half the preference directions raises
18
+ final loss from `0.67098` to `0.69063`, a destructive label control.