byte-vortex commited on
Commit
ab1ac92
·
verified ·
1 Parent(s): 7c1c777

Update logbook: Repro - NonZero: Interaction-Guided Exploration for Multi-Agent Monte Carlo Tree Search

Browse files
logbook.json CHANGED
@@ -10,7 +10,7 @@
10
  "icml2026-repro",
11
  "paper-Jh6gq9QsFa"
12
  ],
13
- "updated_at": "2026-08-03T02:57:53+00:00",
14
  "root": {
15
  "slug": "index",
16
  "title": "Repro - NonZero: Interaction-Guided Exploration for Multi-Agent Monte Carlo Tree Search",
@@ -73,10 +73,10 @@
73
  "total_size": 0,
74
  "bucket_id": null
75
  },
76
- "agent_view_tokens": 3123,
77
  "trace_view_tokens": 10,
78
  "workspace_view_tokens": 8,
79
- "revision": "d2c297892ed037b7528c",
80
  "workspace_ref": {
81
  "repo_id": "byte-vortex/nonzero-repro-artifacts",
82
  "repo_type": "bucket",
 
10
  "icml2026-repro",
11
  "paper-Jh6gq9QsFa"
12
  ],
13
+ "updated_at": "2026-08-03T03:00:15+00:00",
14
  "root": {
15
  "slug": "index",
16
  "title": "Repro - NonZero: Interaction-Guided Exploration for Multi-Agent Monte Carlo Tree Search",
 
73
  "total_size": 0,
74
  "bucket_id": null
75
  },
76
+ "agent_view_tokens": 3258,
77
  "trace_view_tokens": 10,
78
  "workspace_view_tokens": 8,
79
+ "revision": "33ac31c3805c264e0b1d",
80
  "workspace_ref": {
81
  "repo_id": "byte-vortex/nonzero-repro-artifacts",
82
  "repo_type": "bucket",
pages/claim-1-low-dimensional-nonlinear-surrogate/page.md CHANGED
@@ -6,3 +6,297 @@
6
  {"type": "markdown", "id": "cell_535249793c31", "created_at": "2026-08-03T02:57:38+00:00", "title": "Implemented the asinh-GLM surrogate eta(theta,a) = casinh(alpha<theta,a) exactl…"}
7
  -->
8
  Implemented the asinh-GLM surrogate eta(theta,a) = c*asinh(alpha*<theta,a>) exactly per Section 3.1, Eq. 2, plus the first-order (Eq. 3) and mixed second-order (Eq. 4) finite-difference operators. **Verified the paper's stated identity exactly**: eta(a^(u,v)) - eta(a) = Delta_u eta(a) + Delta_v eta(a) + Delta^2_{u,v} eta(a), confirmed to floating-point precision (error ~1.19e-7) via unit test. **[toy]** Verified the surrogate can learn real reward structure: trained on the 8-agent/10-action nonlinear MatGame environment, converged to R2=0.900 on held-out data, matching the theoretical ceiling set by the environment's injected noise variance (Gaussian sigma^2=4 + Uniform(-3,3)) -- essentially recovering all learnable signal. This used a simplified single-global-theta setup rather than the full state-conditioned hypernetwork architecture, so it validates the model family's expressiveness rather than the complete Claim 4 pipeline.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  {"type": "markdown", "id": "cell_535249793c31", "created_at": "2026-08-03T02:57:38+00:00", "title": "Implemented the asinh-GLM surrogate eta(theta,a) = casinh(alpha<theta,a) exactl…"}
7
  -->
8
  Implemented the asinh-GLM surrogate eta(theta,a) = c*asinh(alpha*<theta,a>) exactly per Section 3.1, Eq. 2, plus the first-order (Eq. 3) and mixed second-order (Eq. 4) finite-difference operators. **Verified the paper's stated identity exactly**: eta(a^(u,v)) - eta(a) = Delta_u eta(a) + Delta_v eta(a) + Delta^2_{u,v} eta(a), confirmed to floating-point precision (error ~1.19e-7) via unit test. **[toy]** Verified the surrogate can learn real reward structure: trained on the 8-agent/10-action nonlinear MatGame environment, converged to R2=0.900 on held-out data, matching the theoretical ceiling set by the environment's injected noise variance (Gaussian sigma^2=4 + Uniform(-3,3)) -- essentially recovering all learnable signal. This used a simplified single-global-theta setup rather than the full state-conditioned hypernetwork architecture, so it validates the model family's expressiveness rather than the complete Claim 4 pipeline.
9
+
10
+
11
+ ---
12
+ <!-- trackio-cell
13
+ {"type": "code", "id": "cell_25405f4ab649", "created_at": "2026-08-03T03:00:14+00:00", "title": "Run: hf claim1_mechanism_test.py (exit 0)", "command": ["hf", "jobs", "uv", "run", "--flavor", "cpu-basic", "--secrets", "HF_TOKEN", "claim1_mechanism_test.py"], "exit_code": 0, "duration_s": 139.004}
14
+ -->
15
+ ````bash
16
+ $ hf jobs uv run --flavor cpu-basic --secrets HF_TOKEN claim1_mechanism_test.py
17
+ ````
18
+
19
+ exit 0 · 139.0s
20
+
21
+
22
+ ````python title=claim1_mechanism_test.py
23
+ # /// script
24
+ # dependencies = ["torch", "numpy"]
25
+ # ///
26
+ """
27
+ Claim 1 -- toy-scale test of NonZero's actual proposal mechanism.
28
+
29
+ The paper's real claim isn't just "the surrogate can fit rewards" -- it's
30
+ that using the surrogate's first-order (single-agent) and second-order
31
+ (two-agent) difference operators to PROPOSE candidate action changes finds
32
+ good joint actions more efficiently than enumerating/random-sampling the
33
+ full joint-action space (Section 3, Section 3.1).
34
+
35
+ This script tests that directly: under an EQUAL evaluation budget, does
36
+ NonUCT-style guided local search find better joint actions than random
37
+ sampling, on the 8-agent/10-action nonlinear MatGame environment?
38
+ """
39
+
40
+ import torch
41
+ import torch.nn as nn
42
+ import numpy as np
43
+
44
+
45
+ class MatgameNonZeroEnv:
46
+ def __init__(self, n_agents=8, n_actions=10, reward_type="nonlinear",
47
+ noise_std=2.0, noise_uniform_range=3.0, seed=None):
48
+ self.n_agents = n_agents
49
+ self.n_actions = n_actions
50
+ self.reward_type = reward_type
51
+ self.noise_std = noise_std
52
+ self.noise_uniform_range = noise_uniform_range
53
+ self._rng = np.random.default_rng(seed)
54
+
55
+ def joint_reward(self, actions):
56
+ base = float(np.sum(actions))
57
+ if self.reward_type == "linear":
58
+ return base
59
+ u = self._rng.normal(0.0, self.noise_std)
60
+ v = self._rng.uniform(-self.noise_uniform_range, self.noise_uniform_range)
61
+ return base + u + v
62
+
63
+
64
+ class AsinhGLMSurrogate:
65
+ def __init__(self, n_agents, n_actions, c=1.0, alpha=1.0):
66
+ self.n_agents, self.n_actions = n_agents, n_actions
67
+ self.nd = n_agents * n_actions
68
+ self.c, self.alpha = c, alpha
69
+
70
+ def one_hot(self, agent_actions):
71
+ agent_actions = torch.as_tensor(agent_actions, dtype=torch.long)
72
+ oh = torch.nn.functional.one_hot(agent_actions, num_classes=self.n_actions)
73
+ return oh.reshape(*agent_actions.shape[:-1], self.nd).float()
74
+
75
+ def eta(self, theta, a):
76
+ return self.c * torch.asinh(self.alpha * (theta * a).sum(dim=-1))
77
+
78
+ def neighbor(self, a, agent_idx, new_action):
79
+ a = a.clone()
80
+ s = agent_idx * self.n_actions
81
+ a[..., s:s + self.n_actions] = 0.0
82
+ a[..., s + new_action] = 1.0
83
+ return a
84
+
85
+ def neighbor_pair(self, a, agent_i, action_i, agent_j, action_j):
86
+ a = self.neighbor(a, agent_i, action_i)
87
+ a = self.neighbor(a, agent_j, action_j)
88
+ return a
89
+
90
+
91
+ def fit_surrogate(env, surrogate, n_samples=4000, n_epochs=1500, rng=None):
92
+ actions = rng.integers(0, env.n_actions, size=(n_samples, env.n_agents))
93
+ rewards = torch.tensor([env.joint_reward(a) for a in actions], dtype=torch.float32)
94
+ a_enc = surrogate.one_hot(torch.tensor(actions, dtype=torch.long))
95
+
96
+ theta = nn.Parameter(torch.zeros(surrogate.nd))
97
+ log_c, log_alpha = nn.Parameter(torch.zeros(())), nn.Parameter(torch.zeros(()))
98
+ opt = torch.optim.Adam([theta, log_c, log_alpha], lr=0.05)
99
+ sched = torch.optim.lr_scheduler.CosineAnnealingLR(opt, T_max=n_epochs)
100
+
101
+ def predict(a_batch):
102
+ return torch.exp(log_c) * torch.asinh(torch.exp(log_alpha) * (theta * a_batch).sum(dim=-1))
103
+
104
+ for _ in range(n_epochs):
105
+ opt.zero_grad()
106
+ loss = ((predict(a_enc) - rewards) ** 2).mean()
107
+ loss.backward()
108
+ opt.step()
109
+ sched.step()
110
+ return theta.detach()
111
+
112
+
113
+ def nonuct_guided_search(env, surrogate, theta, eval_budget, rng):
114
+ n_agents, n_actions = env.n_agents, env.n_actions
115
+ current = rng.integers(0, n_actions, size=n_agents)
116
+ best_reward = env.joint_reward(current)
117
+ evals_used = 1
118
+
119
+ while evals_used < eval_budget:
120
+ cur_enc = surrogate.one_hot(torch.tensor(current, dtype=torch.long))
121
+ cur_eta = surrogate.eta(theta, cur_enc).item()
122
+
123
+ best_candidate, best_delta, best_kind = None, -float("inf"), None
124
+ for agent_idx in range(n_agents):
125
+ for new_action in range(n_actions):
126
+ if new_action == current[agent_idx]:
127
+ continue
128
+ cand_enc = surrogate.neighbor(cur_enc, agent_idx, new_action)
129
+ delta = (surrogate.eta(theta, cand_enc) - cur_eta).item()
130
+ if delta > best_delta:
131
+ best_delta, best_candidate, best_kind = delta, (agent_idx, new_action), "first"
132
+
133
+ for i in range(n_agents):
134
+ for j in range(i + 1, n_agents):
135
+ for ai in range(n_actions):
136
+ if ai == current[i]:
137
+ continue
138
+ for aj in range(n_actions):
139
+ if aj == current[j]:
140
+ continue
141
+ cand_enc = surrogate.neighbor_pair(cur_enc, i, ai, j, aj)
142
+ delta = (surrogate.eta(theta, cand_enc) - cur_eta).item()
143
+ if delta > best_delta:
144
+ best_delta, best_candidate, best_kind = delta, (i, ai, j, aj), "second"
145
+
146
+ if best_candidate is None or evals_used >= eval_budget:
147
+ break
148
+
149
+ candidate_actions = current.copy()
150
+ if best_kind == "first":
151
+ agent_idx, new_action = best_candidate
152
+ candidate_actions[agent_idx] = new_action
153
+ else:
154
+ i, ai, j, aj = best_candidate
155
+ candidate_actions[i] = ai
156
+ candidate_actions[j] = aj
157
+
158
+ real_reward = env.joint_reward(candidate_actions)
159
+ evals_used += 1
160
+
161
+ if real_reward > best_reward:
162
+ current = candidate_actions
163
+ best_reward = real_reward
164
+ else:
165
+ break
166
+
167
+ return best_reward, evals_used
168
+
169
+
170
+ def random_search(env, eval_budget, rng):
171
+ best_reward = -float("inf")
172
+ for _ in range(eval_budget):
173
+ actions = rng.integers(0, env.n_actions, size=env.n_agents)
174
+ r = env.joint_reward(actions)
175
+ if r > best_reward:
176
+ best_reward = r
177
+ return best_reward
178
+
179
+
180
+ def main():
181
+ print("=" * 70)
182
+ print("NonZero reproduction -- Claim 1 mechanism test (toy scale)")
183
+ print("Testing: does surrogate-guided proposal beat random search")
184
+ print("under an EQUAL real-environment evaluation budget?")
185
+ print("=" * 70)
186
+
187
+ n_trials = 200
188
+ eval_budget = 15
189
+
190
+ rng_fit = np.random.default_rng(0)
191
+ env_fit = MatgameNonZeroEnv(n_agents=8, n_actions=10, reward_type="nonlinear", seed=1)
192
+ surrogate = AsinhGLMSurrogate(8, 10)
193
+ theta = fit_surrogate(env_fit, surrogate, rng=rng_fit)
194
+ print(f"\nSurrogate fit complete (theta trained on 4000 samples).")
195
+
196
+ guided_rewards, random_rewards = [], []
197
+ for trial in range(n_trials):
198
+ rng = np.random.default_rng(1000 + trial)
199
+ env = MatgameNonZeroEnv(n_agents=8, n_actions=10, reward_type="nonlinear", seed=2000 + trial)
200
+
201
+ g_reward, g_evals = nonuct_guided_search(env, surrogate, theta, eval_budget, rng)
202
+ guided_rewards.append(g_reward)
203
+
204
+ env2 = MatgameNonZeroEnv(n_agents=8, n_actions=10, reward_type="nonlinear", seed=2000 + trial)
205
+ rng2 = np.random.default_rng(1000 + trial)
206
+ r_reward = random_search(env2, eval_budget, rng2)
207
+ random_rewards.append(r_reward)
208
+
209
+ guided_mean, guided_std = np.mean(guided_rewards), np.std(guided_rewards)
210
+ random_mean, random_std = np.mean(random_rewards), np.std(random_rewards)
211
+ improvement = (guided_mean - random_mean) / abs(random_mean) * 100
212
+
213
+ print(f"\n[Results over {n_trials} trials, eval_budget={eval_budget}]")
214
+ print(f" Surrogate-guided search: {guided_mean:.2f} +/- {guided_std:.2f}")
215
+ print(f" Random search (baseline): {random_mean:.2f} +/- {random_std:.2f}")
216
+ print(f" Improvement: {improvement:+.1f}%")
217
+
218
+ print("\n" + "=" * 70)
219
+ print("SUMMARY")
220
+ if guided_mean > random_mean:
221
+ print(f" PASS: surrogate-guided proposal outperforms random search")
222
+ print(f" by {improvement:.1f}% under equal evaluation budget.")
223
+ print(f" This supports Claim 1's core mechanism at toy scale.")
224
+ else:
225
+ print(f" FAIL: surrogate-guided proposal did NOT outperform random search")
226
+ print(f" in this toy setting.")
227
+ print("=" * 70)
228
+
229
+
230
+ if __name__ == "__main__":
231
+ main()
232
+
233
+ ````
234
+
235
+
236
+ ````output
237
+ /usr/local/lib/python3.12/dist-packages/huggingface_hub/utils/_experimental.py:59: UserWarning: 'HfApi.run_uv_job' is experimental and might be subject to breaking changes in the future without prior notice. You can disable this warning by setting `HF_HUB_DISABLE_EXPERIMENTAL_WARNING=1` as environment variable.
238
+ warnings.warn(
239
+ Job started with ID: 6a7003b4a00abefd4b28e8ee
240
+ View at: https://huggingface.co/jobs/byte-vortex/6a7003b4a00abefd4b28e8ee
241
+ Downloading nvidia-cufile (1.2MiB)
242
+ Downloading nvidia-nvjitlink (38.9MiB)
243
+ Downloading numpy (15.9MiB)
244
+ Downloading nvidia-cufft (204.2MiB)
245
+ Downloading nvidia-cusolver (191.6MiB)
246
+ Downloading nvidia-nccl-cu13 (196.4MiB)
247
+ Downloading triton (188.6MiB)
248
+ Downloading nvidia-cusparselt-cu13 (162.3MiB)
249
+ Downloading cuda-bindings (6.3MiB)
250
+ Downloading nvidia-nvshmem-cu13 (57.6MiB)
251
+ Downloading networkx (2.0MiB)
252
+ Downloading nvidia-cusparse (139.2MiB)
253
+ Downloading nvidia-cuda-nvrtc (86.0MiB)
254
+ Downloading sympy (6.0MiB)
255
+ Downloading nvidia-cuda-runtime (2.1MiB)
256
+ Downloading nvidia-cuda-cupti (10.2MiB)
257
+ Downloading nvidia-cublas (403.5MiB)
258
+ Downloading nvidia-cudnn-cu13 (349.2MiB)
259
+ Downloading torch (502.2MiB)
260
+ Downloading nvidia-curand (56.8MiB)
261
+ Downloaded nvidia-cufile
262
+ Downloaded nvidia-cuda-runtime
263
+ Downloaded networkx
264
+ Downloaded cuda-bindings
265
+ Downloaded nvidia-cuda-cupti
266
+ Downloaded numpy
267
+ Downloaded nvidia-nvjitlink
268
+ Downloaded sympy
269
+ Downloaded nvidia-curand
270
+ Downloaded nvidia-nvshmem-cu13
271
+ Downloaded nvidia-cuda-nvrtc
272
+ Downloaded nvidia-cusparse
273
+ Downloaded nvidia-cusparselt-cu13
274
+ Downloaded nvidia-cusolver
275
+ Downloaded nvidia-nccl-cu13
276
+ Downloaded nvidia-cufft
277
+ Downloaded triton
278
+ Downloaded nvidia-cudnn-cu13
279
+ Downloaded nvidia-cublas
280
+ Downloaded torch
281
+ Installed 30 packages in 224ms
282
+ ======================================================================
283
+ NonZero reproduction -- Claim 1 mechanism test (toy scale)
284
+ Testing: does surrogate-guided proposal beat random search
285
+ under an EQUAL real-environment evaluation budget?
286
+ ======================================================================
287
+
288
+ Surrogate fit complete (theta trained on 4000 samples).
289
+
290
+ [Results over 200 trials, eval_budget=15]
291
+ Surrogate-guided search: 73.19 +/- 2.59
292
+ Random search (baseline): 51.04 +/- 4.58
293
+ Improvement: +43.4%
294
+
295
+ ======================================================================
296
+ SUMMARY
297
+ PASS: surrogate-guided proposal outperforms random search
298
+ by 43.4% under equal evaluation budget.
299
+ This supports Claim 1's core mechanism at toy scale.
300
+ ======================================================================
301
+
302
+ ````
workspace.json CHANGED
@@ -8,6 +8,11 @@
8
  "url": "https://huggingface.co/spaces/byte-vortex/nonzero-repro",
9
  "type": "Spaces",
10
  "label": "byte-vortex/nonzero-repro"
 
 
 
 
 
11
  }
12
  ],
13
  "reference_only": true
 
8
  "url": "https://huggingface.co/spaces/byte-vortex/nonzero-repro",
9
  "type": "Spaces",
10
  "label": "byte-vortex/nonzero-repro"
11
+ },
12
+ {
13
+ "url": "https://huggingface.co/jobs/byte-vortex/6a7003b4a00abefd4b28e8ee",
14
+ "type": "Jobs",
15
+ "label": "byte-vortex/6a7003b4a00abefd4b28e8ee"
16
  }
17
  ],
18
  "reference_only": true