RFTSystems commited on
Commit
295b4c9
·
verified ·
1 Parent(s): d01a4f3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +263 -219
app.py CHANGED
@@ -1,309 +1,353 @@
1
- # app.py — Coherent_Compute_Engine (RFTSystems) — Gradio 6.x compatible
2
- # Live measured throughput + stability + energy proxy, with verification baselines + receipt download.
3
- # No estimates. No precomputed data.
 
 
4
 
5
  import os
6
- import time
7
  import json
 
8
  import math
9
  import hashlib
10
  import platform
11
- from datetime import datetime, timezone
12
 
13
  import numpy as np
14
  import gradio as gr
15
 
16
- # Optional: numba acceleration
 
 
 
17
  try:
18
  import numba as nb
19
  NUMBA_OK = True
20
  except Exception:
21
- NUMBA_OK = False
22
  nb = None
 
23
 
24
  APP_TITLE = "Coherent Compute Engine"
25
- RESULTS_DIR = "receipts"
26
-
27
- # -----------------------------
28
- # Definition: what an "item" is
29
- # -----------------------------
30
- # One coherent state update of [Psi, E, L] per oscillator per step.
31
- # Items/sec = (N oscillators * steps) / elapsed_seconds
32
-
33
- # -----------------------------
34
- # Core update: vectorised (NumPy)
35
- # -----------------------------
36
- def np_step(Psi, E, L, scale=1.0):
 
 
37
  phase = 0.997 * Psi + 0.003 * E
38
- drive = np.tanh(phase * scale)
39
  Psi_n = 0.999 * Psi + 0.001 * drive
40
  E_n = 0.995 * E + 0.004 * Psi_n
41
  L_n = 0.998 * L + 0.001 * (Psi_n * E_n)
42
  return Psi_n, E_n, L_n
43
 
44
- # -----------------------------
45
- # Baseline: tiny Python loop (safety-capped)
46
- # -----------------------------
47
- def pyloop_step(Psi, E, L, scale=1.0):
48
- phase = 0.997 * Psi + 0.003 * E
49
- drive = math.tanh(phase * scale)
50
- Psi_n = 0.999 * Psi + 0.001 * drive
51
- E_n = 0.995 * E + 0.004 * Psi_n
52
- L_n = 0.998 * L + 0.001 * (Psi_n * E_n)
53
- return Psi_n, E_n, L_n
54
 
55
- def run_python_loop_baseline(n, steps, seed=7, cap_seconds=1.2):
56
- """
57
- Scalar baseline on a small subset for a short capped duration.
58
- Reports throughput in items/sec for that subset.
59
- """
60
- rng = np.random.default_rng(seed)
61
- n0 = min(int(n), 150_000) # safety subset
62
- Psi = rng.random(n0, dtype=np.float32)
63
- E = rng.random(n0, dtype=np.float32)
64
- L = rng.random(n0, dtype=np.float32)
65
-
66
- t0 = time.time()
67
- done = 0
68
- for _ in range(int(steps)):
69
- if (time.time() - t0) > cap_seconds:
70
- break
71
- for i in range(n0):
72
- Psi[i], E[i], L[i] = pyloop_step(float(Psi[i]), float(E[i]), float(L[i]))
73
- done += 1
74
-
75
- elapsed = max(1e-9, time.time() - t0)
76
- items = done * n0
77
- thr_Bps = (items / elapsed) / 1e9
78
- return thr_Bps, elapsed, n0, done
79
-
80
- # -----------------------------
81
- # Optional: Numba kernel
82
- # -----------------------------
83
  if NUMBA_OK:
84
  @nb.njit(fastmath=True, parallel=True)
85
- def nb_run(Psi, E, L, steps):
86
- for _ in range(steps):
87
- phase = 0.997 * Psi + 0.003 * E
88
- drive = np.tanh(phase)
89
- Psi = 0.999 * Psi + 0.001 * drive
90
- E = 0.995 * E + 0.004 * Psi
91
- L = 0.998 * L + 0.001 * (Psi * E)
92
- return Psi, E, L
93
-
94
- def compute_coherence(Psi_before, Psi_after):
95
- v1 = Psi_before.astype(np.float64, copy=False)
96
- v2 = Psi_after.astype(np.float64, copy=False)
97
- num = float(np.dot(v1, v2)) + 1e-12
98
- den = float(np.linalg.norm(v1) * np.linalg.norm(v2)) + 1e-12
99
- return num / den
100
-
101
- def compute_energy(E):
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  return float(np.mean(np.clip(E, 0.0, 1.5)))
103
 
104
- def get_cpu_string():
105
- try:
106
- return platform.processor() or platform.uname().processor or ""
107
- except Exception:
108
- return ""
109
 
110
- def sha256_bytes(b: bytes) -> str:
111
- return hashlib.sha256(b).hexdigest()
 
 
 
112
 
113
- def make_receipt(payload: dict):
114
- os.makedirs(RESULTS_DIR, exist_ok=True)
115
- ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H-%M-%SZ")
116
- fname = f"receipt_{ts}.json"
117
- path = os.path.join(RESULTS_DIR, fname)
118
 
119
- canon = json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
120
- h = sha256_bytes(canon)
121
 
122
- payload_out = dict(payload)
123
- payload_out["receipt_sha256"] = h
124
 
125
- with open(path, "w", encoding="utf-8") as f:
126
- json.dump(payload_out, f, indent=2)
 
 
127
 
128
- return path, h, payload_out
 
129
 
130
- def run_engine(n_oscillators: int, steps: int, include_baselines: bool):
131
- # Safety rails for HF Spaces stability
132
- n = int(max(50_000, min(int(n_oscillators), 25_000_000)))
133
- steps = int(max(10, min(int(steps), 2_000)))
134
 
135
- rng = np.random.default_rng(7)
136
- Psi = rng.random(n, dtype=np.float32)
137
- E = rng.random(n, dtype=np.float32)
138
- L = rng.random(n, dtype=np.float32)
139
 
140
- sample = min(n, 250_000)
141
- Psi0 = Psi[:sample].copy()
142
 
143
- engine = "numpy"
144
- t0 = time.time()
145
 
146
- if NUMBA_OK:
147
- engine = "numba"
148
- try:
149
- _Psi_w = Psi[:50_000].copy()
150
- _E_w = E[:50_000].copy()
151
- _L_w = L[:50_000].copy()
152
- nb_run(_Psi_w, _E_w, _L_w, 2)
153
- except Exception:
154
- engine = "numpy"
155
-
156
- if engine == "numba":
157
- Psi, E, L = nb_run(Psi, E, L, steps)
158
- else:
159
- for _ in range(steps):
160
- Psi, E, L = np_step(Psi, E, L)
161
 
162
- elapsed = max(1e-9, time.time() - t0)
163
 
 
 
 
164
  items = n * steps
165
- thr_Bps = (items / elapsed) / 1e9
 
 
 
 
 
 
166
 
167
- coh = compute_coherence(Psi0, Psi[:sample])
168
- coh_abs = abs(coh)
169
- meanE = compute_energy(E[:sample])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
- base_numpy = None
172
- base_py = None
173
- speedup_vs_py = None
174
- speedup_vs_numpy = None
175
 
176
- if include_baselines:
177
- # Baseline A: forced NumPy
178
- t1 = time.time()
179
- PsiA = rng.random(n, dtype=np.float32)
180
- EA = rng.random(n, dtype=np.float32)
181
- LA = rng.random(n, dtype=np.float32)
 
 
 
182
  for _ in range(steps):
183
- PsiA, EA, LA = np_step(PsiA, EA, LA)
184
- elA = max(1e-9, time.time() - t1)
185
- base_numpy = (n * steps / elA) / 1e9
186
 
187
- # Baseline B: Python loop (subset + cap)
188
- base_py, py_elapsed, py_n, py_steps_done = run_python_loop_baseline(n=n, steps=steps, seed=7)
189
 
190
- if base_py and base_py > 0:
191
- speedup_vs_py = thr_Bps / base_py
192
- if base_numpy and base_numpy > 0:
193
- speedup_vs_numpy = thr_Bps / base_numpy
194
 
195
- payload = {
196
- "app": APP_TITLE,
197
- "timestamp_utc": datetime.now(timezone.utc).isoformat(),
198
- "definition_of_item": "One coherent update of [Psi,E,L] per oscillator per step",
199
- "n_oscillators": n,
200
- "steps": steps,
201
- "engine": engine,
202
- "elapsed_seconds": elapsed,
203
- "throughput_Bps": thr_Bps,
204
- "coherence_C": coh,
205
- "coherence_abs": coh_abs,
206
- "mean_energy_proxy": meanE,
207
- "cpu": get_cpu_string(),
208
- "cores_available": os.cpu_count() or 1,
209
- "baselines_enabled": bool(include_baselines),
210
- "baseline_numpy_Bps": base_numpy,
211
- "baseline_python_loop_Bps": base_py,
212
- "speedup_vs_python_loop_x": speedup_vs_py,
213
- "speedup_vs_numpy_x": speedup_vs_numpy,
214
- "notes": [
215
- "All values measured live on the Space runtime machine.",
216
- "Baselines are measured on the same machine with the same workload settings.",
217
- "Python loop baseline is safety-capped and uses a subset to keep the Space responsive.",
218
- ],
219
- }
220
 
221
- receipt_path, receipt_sha, payload_out = make_receipt(payload)
 
 
 
 
222
 
223
- result = {
224
- "Throughput (B/s)": f"{thr_Bps:.3f}",
225
- "Coherence (|C|)": f"{coh_abs:.5f}",
226
- "Mean Energy": f"{meanE:.5f}",
 
227
  "Elapsed Time (s)": f"{elapsed:.2f}",
228
- "Oscillators": f"{n:,}",
229
- "Steps": f"{steps}",
230
  "Engine": engine,
231
- "CPU Cores Available": int(os.cpu_count() or 1),
 
232
  }
233
 
 
 
234
  if include_baselines:
235
- result["Baseline: numpy (B/s)"] = f"{base_numpy:.3f}" if base_numpy is not None else "n/a"
236
- result["Baseline: python_loop (B/s)"] = f"{base_py:.3f}" if base_py is not None else "n/a"
237
- if speedup_vs_py is not None:
238
- result["Speedup vs python_loop (x)"] = f"{speedup_vs_py:.1f}"
239
- if speedup_vs_numpy is not None:
240
- result["Speedup vs numpy (x)"] = f"{speedup_vs_numpy:.2f}"
241
- result["Note"] = "Speedups can be <1.0 depending on runtime/Numba warmup/CPU features. Reported as-is."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
- result["Receipt SHA-256 (in file)"] = "written in receipt"
244
 
245
- return json.dumps(result, indent=2), receipt_path
 
246
 
 
247
 
248
- INTRO_MD = """
249
- ### What this is
250
- - **No precomputed results**
251
- - **No GPUs required**
252
- - Measures **real throughput**, **stability**, and **energy behaviour** on the machine running this Space.
253
 
254
- ### What an “item” is
255
- - One coherent state update of **[Ψ, E, L]** per oscillator per step.
256
 
257
- Everything you see below is computed **right now**, on this machine.
258
- """
259
 
260
- NOTES_MD = """
261
- **Notes**
262
- - This runs on the Hugging Face Space runtime machine. Your browser just displays the UI.
263
- - If the Space is under load, throughput will vary — that variance is real and is part of the measurement.
264
- - Baselines are verification anchors measured live on the same machine.
 
265
  """
266
 
267
- # Gradio 6.x: do NOT pass theme into Blocks(); pass theme into launch()
268
- with gr.Blocks(title=APP_TITLE) as demo:
269
- gr.Markdown(f"# {APP_TITLE}")
270
- gr.Markdown(INTRO_MD)
 
 
 
 
 
 
 
 
271
 
272
  with gr.Row():
273
  n_slider = gr.Slider(
274
- minimum=250_000,
275
  maximum=25_000_000,
276
  value=6_400_000,
277
  step=50_000,
278
  label="Number of Oscillators",
279
  )
280
- steps_slider = gr.Slider(
281
- minimum=50,
282
  maximum=2000,
283
  value=650,
284
- step=10,
285
  label="Simulation Steps",
286
  )
287
 
288
  include_baselines = gr.Checkbox(
289
  value=True,
290
- label="Include baselines (NumPy + tiny Python loop)",
291
- info="Baselines are measured live too. Python loop is safety-capped."
292
  )
293
 
294
  run_btn = gr.Button("Run Engine", variant="primary")
295
 
296
- out_json = gr.Code(label="Results", language="json")
297
- receipt_file = gr.File(label="Receipt (download)", file_count="single")
 
298
 
299
- gr.Markdown(NOTES_MD)
 
 
 
 
 
300
 
301
  run_btn.click(
302
  fn=run_engine,
303
- inputs=[n_slider, steps_slider, include_baselines],
304
- outputs=[out_json, receipt_file],
305
  )
306
 
307
- if __name__ == "__main__":
308
- # Gradio 6.x: queue() signature changed; keep it simple and stable.
309
- demo.queue().launch(theme=gr.themes.Soft())
 
1
+ # app.py — Coherent_Compute_Engine (RFTSystems)
2
+ # Live, on-machine benchmarking + receipt download (SHA-256)
3
+ # - Clarifies units: "B items/s" (billions of items per second) + raw items/s
4
+ # - Baselines are optional + clearly "context only"
5
+ # - Adds a Trust KPI badge: receipt SHA-256 generated from THIS run
6
 
7
  import os
 
8
  import json
9
+ import time
10
  import math
11
  import hashlib
12
  import platform
13
+ import datetime as dt
14
 
15
  import numpy as np
16
  import gradio as gr
17
 
18
+ # ----------------------------
19
+ # Optional Numba acceleration
20
+ # ----------------------------
21
+ NUMBA_OK = False
22
  try:
23
  import numba as nb
24
  NUMBA_OK = True
25
  except Exception:
 
26
  nb = None
27
+ NUMBA_OK = False
28
 
29
  APP_TITLE = "Coherent Compute Engine"
30
+ OUT_DIR = "/tmp/receipts"
31
+ os.makedirs(OUT_DIR, exist_ok=True)
32
+
33
+ # ----------------------------
34
+ # "Item" definition
35
+ # ----------------------------
36
+ # One coherent state update of [Ψ, E, L] per oscillator per step.
37
+ # items = n_oscillators * steps
38
+
39
+ # ----------------------------
40
+ # Core update rules (safe + stable)
41
+ # ----------------------------
42
+ def _np_step(Psi, E, L):
43
+ # Branchless, numerically tame, vectorised.
44
  phase = 0.997 * Psi + 0.003 * E
45
+ drive = np.tanh(phase)
46
  Psi_n = 0.999 * Psi + 0.001 * drive
47
  E_n = 0.995 * E + 0.004 * Psi_n
48
  L_n = 0.998 * L + 0.001 * (Psi_n * E_n)
49
  return Psi_n, E_n, L_n
50
 
 
 
 
 
 
 
 
 
 
 
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  if NUMBA_OK:
53
  @nb.njit(fastmath=True, parallel=True)
54
+ def _nb_step(Psi, E, L):
55
+ # same math as numpy path, but parallel
56
+ n = Psi.shape[0]
57
+ for i in nb.prange(n):
58
+ phase = 0.997 * Psi[i] + 0.003 * E[i]
59
+ drive = math.tanh(phase)
60
+ Psi_n = 0.999 * Psi[i] + 0.001 * drive
61
+ E_n = 0.995 * E[i] + 0.004 * Psi_n
62
+ L_n = 0.998 * L[i] + 0.001 * (Psi_n * E_n)
63
+ Psi[i] = Psi_n
64
+ E[i] = E_n
65
+ L[i] = L_n
66
+
67
+
68
+ # ----------------------------
69
+ # Metrics (simple + honest)
70
+ # ----------------------------
71
+ def coherence_abs_from_final(Psi):
72
+ # Coherence proxy: |corr(Psi[i], Psi[i+1])|
73
+ # (stable, cheap, avoids extra state storage)
74
+ if Psi.shape[0] < 3:
75
+ return 0.0
76
+ a = Psi[:-1]
77
+ b = Psi[1:]
78
+ num = float(np.dot(a, b)) + 1e-12
79
+ den = float(np.linalg.norm(a) * np.linalg.norm(b)) + 1e-12
80
+ return float(abs(num / den))
81
+
82
+
83
+ def mean_energy(E):
84
  return float(np.mean(np.clip(E, 0.0, 1.5)))
85
 
 
 
 
 
 
86
 
87
+ # ----------------------------
88
+ # Canonical JSON + receipt hashing
89
+ # ----------------------------
90
+ def canon_json_bytes(obj) -> bytes:
91
+ return json.dumps(obj, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
92
 
 
 
 
 
 
93
 
94
+ def sha256_hex(data: bytes) -> str:
95
+ return hashlib.sha256(data).hexdigest()
96
 
 
 
97
 
98
+ def write_receipt(payload: dict) -> str:
99
+ # Hash the receipt WITHOUT the hash field, then embed it.
100
+ payload_nohash = dict(payload)
101
+ payload_nohash.pop("receipt_sha256", None)
102
 
103
+ h = sha256_hex(canon_json_bytes(payload_nohash))
104
+ payload["receipt_sha256"] = h
105
 
106
+ fname = f"receipt_{dt.datetime.utcnow().strftime('%Y-%m-%dT%H-%M-%SZ')}_{h[:10]}.json"
107
+ path = os.path.join(OUT_DIR, fname)
 
 
108
 
109
+ with open(path, "wb") as f:
110
+ f.write(canon_json_bytes(payload))
 
 
111
 
112
+ return path, h
 
113
 
 
 
114
 
115
+ # ----------------------------
116
+ # Baselines (optional, live)
117
+ # ----------------------------
118
+ def baseline_numpy(Psi, E, L, steps):
119
+ t0 = time.perf_counter()
120
+ for _ in range(steps):
121
+ Psi, E, L = _np_step(Psi, E, L)
122
+ t1 = time.perf_counter()
123
+ return (t1 - t0)
 
 
 
 
 
 
124
 
 
125
 
126
+ def baseline_python_loop(n, steps, seed=7, cap_items=200_000):
127
+ # Safety-capped pure-Python loop so it doesn't stall the Space.
128
+ # It measures real work, but only for a small capped subset.
129
  items = n * steps
130
+ if items > cap_items:
131
+ # reduce n first, then steps, to keep a meaningful kernel shape
132
+ scale = cap_items / max(1, items)
133
+ n2 = max(256, int(n * scale))
134
+ steps2 = max(5, int(steps * 0.25))
135
+ else:
136
+ n2, steps2 = n, steps
137
 
138
+ rng = np.random.default_rng(seed)
139
+ Psi = rng.random(n2).astype(np.float32)
140
+ E = rng.random(n2).astype(np.float32)
141
+ L = rng.random(n2).astype(np.float32)
142
+
143
+ t0 = time.perf_counter()
144
+ for _ in range(steps2):
145
+ for i in range(n2):
146
+ phase = 0.997 * float(Psi[i]) + 0.003 * float(E[i])
147
+ drive = math.tanh(phase)
148
+ Psi_n = 0.999 * float(Psi[i]) + 0.001 * drive
149
+ E_n = 0.995 * float(E[i]) + 0.004 * Psi_n
150
+ L_n = 0.998 * float(L[i]) + 0.001 * (Psi_n * E_n)
151
+ Psi[i] = Psi_n
152
+ E[i] = E_n
153
+ L[i] = L_n
154
+ t1 = time.perf_counter()
155
+
156
+ # Compute throughput for the *capped* run
157
+ elapsed = (t1 - t0)
158
+ items_done = int(n2) * int(steps2)
159
+ thr = (items_done / max(1e-9, elapsed)) # items/sec (raw)
160
+ return elapsed, items_done, thr, (n2, steps2)
161
+
162
+
163
+ # ----------------------------
164
+ # Main benchmark
165
+ # ----------------------------
166
+ def run_engine(n_oscillators: int, steps: int, include_baselines: bool):
167
+ # Hard safety guards (Spaces can be shared + unpredictable)
168
+ n_oscillators = int(max(50_000, min(int(n_oscillators), 25_000_000)))
169
+ steps = int(max(25, min(int(steps), 2_000)))
170
+
171
+ seed = 7
172
+ rng = np.random.default_rng(seed)
173
+ Psi = rng.random(n_oscillators, dtype=np.float32)
174
+ E = rng.random(n_oscillators, dtype=np.float32)
175
+ L = rng.random(n_oscillators, dtype=np.float32)
176
 
177
+ engine = "numba" if NUMBA_OK else "numpy"
 
 
 
178
 
179
+ # Warmup (Numba compiles on first call; keep it honest but amortise compile)
180
+ if NUMBA_OK:
181
+ _nb_step(Psi[:10_000].copy(), E[:10_000].copy(), L[:10_000].copy())
182
+
183
+ t0 = time.perf_counter()
184
+ if NUMBA_OK:
185
+ for _ in range(steps):
186
+ _nb_step(Psi, E, L)
187
+ else:
188
  for _ in range(steps):
189
+ Psi, E, L = _np_step(Psi, E, L)
190
+ t1 = time.perf_counter()
 
191
 
192
+ elapsed = float(t1 - t0)
193
+ items = int(n_oscillators) * int(steps)
194
 
195
+ thr_items_per_s = items / max(1e-12, elapsed)
196
+ thr_B_items_per_s = thr_items_per_s / 1e9
 
 
197
 
198
+ coh = coherence_abs_from_final(Psi)
199
+ eng = mean_energy(E)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
+ # Metadata (keep it factual; no guessing)
202
+ cpu = platform.processor() or ""
203
+ cores = os.cpu_count() or 1
204
+ pyver = platform.python_version()
205
+ plat = platform.platform()
206
 
207
+ results = {
208
+ "Throughput (B items/s)": f"{thr_B_items_per_s:.3f}",
209
+ "Throughput (items/s)": f"{thr_items_per_s:,.0f}",
210
+ "Coherence (|C|)": f"{coh:.5f}",
211
+ "Mean Energy": f"{eng:.5f}",
212
  "Elapsed Time (s)": f"{elapsed:.2f}",
213
+ "Oscillators": f"{n_oscillators:,}",
214
+ "Steps": f"{steps:,}",
215
  "Engine": engine,
216
+ "CPU": cpu,
217
+ "Cores Available": int(cores),
218
  }
219
 
220
+ # Optional baselines (context only)
221
+ baseline_info = {}
222
  if include_baselines:
223
+ # NumPy baseline measured live (same maths), but smaller copy for fairness on memory
224
+ Psi_b = rng.random(n_oscillators, dtype=np.float32)
225
+ E_b = rng.random(n_oscillators, dtype=np.float32)
226
+ L_b = rng.random(n_oscillators, dtype=np.float32)
227
+
228
+ np_elapsed = baseline_numpy(Psi_b, E_b, L_b, steps)
229
+ np_thr = items / max(1e-12, np_elapsed)
230
+ np_thr_B = np_thr / 1e9
231
+
232
+ py_elapsed, py_items, py_thr, (n2, s2) = baseline_python_loop(n_oscillators, steps)
233
+
234
+ baseline_info = {
235
+ "Baseline: numpy (B items/s)": f"{np_thr_B:.3f}",
236
+ "Baseline: numpy Engine": "numpy",
237
+ "Baseline: python_loop (B items/s)": f"{(py_thr/1e9):.3f}",
238
+ "Baseline: python_loop Engine": "python_loop (safety-capped)",
239
+ "Baseline: python_loop items measured": f"{py_items:,} (cap run n={n2:,}, steps={s2:,})",
240
+ "Speedup vs python_loop (x)": f"{(thr_items_per_s / max(1e-9, py_thr)):.1f}",
241
+ "Speedup vs numpy (x)": f"{(thr_items_per_s / max(1e-9, np_thr)):.2f}",
242
+ "Note": "Baselines are for context only; all are measured live on this machine.",
243
+ }
244
+
245
+ results.update(baseline_info)
246
+
247
+ # Receipt payload (full fidelity + reproducible hash)
248
+ receipt_payload = {
249
+ "app": APP_TITLE,
250
+ "timestamp_utc": dt.datetime.utcnow().isoformat() + "Z",
251
+ "definition_of_item": "One coherent state update of [Psi, E, L] per oscillator per step",
252
+ "inputs": {
253
+ "oscillators": n_oscillators,
254
+ "steps": steps,
255
+ "include_baselines": bool(include_baselines),
256
+ "seed": seed,
257
+ },
258
+ "runtime": {
259
+ "engine": engine,
260
+ "python": pyver,
261
+ "platform": plat,
262
+ "cpu": cpu,
263
+ "cores_available": int(cores),
264
+ "numba_available": bool(NUMBA_OK),
265
+ },
266
+ "outputs": {
267
+ "throughput_items_per_s": float(thr_items_per_s),
268
+ "throughput_B_items_per_s": float(thr_B_items_per_s),
269
+ "coherence_abs": float(coh),
270
+ "mean_energy": float(eng),
271
+ "elapsed_s": float(elapsed),
272
+ },
273
+ "baselines": baseline_info if include_baselines else None,
274
+ }
275
 
276
+ receipt_path, receipt_sha = write_receipt(receipt_payload)
277
 
278
+ # Trust KPI line + include hash in results
279
+ results["Receipt SHA-256 (in file)"] = receipt_sha
280
 
281
+ trust_badge = f"**Receipt verified:** SHA-256 generated from this run → `{receipt_sha}`"
282
 
283
+ # Pretty JSON for the UI
284
+ pretty = json.dumps(results, indent=2)
 
 
 
285
 
286
+ return trust_badge, pretty, receipt_path
 
287
 
 
 
288
 
289
+ # ----------------------------
290
+ # UI
291
+ # ----------------------------
292
+ CUSTOM_CSS = """
293
+ #app-wrap {max-width: 980px; margin: 0 auto;}
294
+ .kpi {padding: 10px 12px; border-radius: 12px; background: rgba(120,120,255,0.08); border: 1px solid rgba(120,120,255,0.18);}
295
  """
296
 
297
+ with gr.Blocks(title=APP_TITLE, css=CUSTOM_CSS) as demo:
298
+ gr.Markdown(f"# {APP_TITLE}", elem_id="app-wrap")
299
+
300
+ gr.Markdown(
301
+ "Everything you see below is computed **right now, on this machine**.\n\n"
302
+ "**What an “item” is**\n"
303
+ "• One coherent state update of `[Ψ, E, L]` per oscillator per step\n\n"
304
+ "**What you get**\n"
305
+ "• Real throughput (items/sec), stability proxy (|C|), energy behaviour\n"
306
+ "• A downloadable receipt with a SHA-256 hash (verification-first)\n"
307
+ "• Optional baselines (context only), measured live too\n"
308
+ )
309
 
310
  with gr.Row():
311
  n_slider = gr.Slider(
312
+ minimum=50_000,
313
  maximum=25_000_000,
314
  value=6_400_000,
315
  step=50_000,
316
  label="Number of Oscillators",
317
  )
318
+ s_slider = gr.Slider(
319
+ minimum=25,
320
  maximum=2000,
321
  value=650,
322
+ step=1,
323
  label="Simulation Steps",
324
  )
325
 
326
  include_baselines = gr.Checkbox(
327
  value=True,
328
+ label="Include baselines (context only)",
329
+ info="Baselines are measured live too. Python loop is safety-capped.",
330
  )
331
 
332
  run_btn = gr.Button("Run Engine", variant="primary")
333
 
334
+ trust_md = gr.Markdown("", elem_classes=["kpi"])
335
+ results_box = gr.Code(label="Results", language="json")
336
+ receipt_file = gr.File(label="Receipt (download)")
337
 
338
+ gr.Markdown(
339
+ "### Notes\n"
340
+ "• This runs on the Hugging Face Space runtime machine (not your phone UI).\n"
341
+ "• If the Space is under load, throughput will move — that’s real behaviour.\n"
342
+ "• **B items/s** means “billions of items per second”, not bytes.\n"
343
+ )
344
 
345
  run_btn.click(
346
  fn=run_engine,
347
+ inputs=[n_slider, s_slider, include_baselines],
348
+ outputs=[trust_md, results_box, receipt_file],
349
  )
350
 
351
+ # Queue without version-fragile kwargs (Gradio 6 changed queue args)
352
+ demo.queue()
353
+ demo.launch()