RFTSystems commited on
Commit
8d79e2a
·
verified ·
1 Parent(s): 02f4856

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +530 -106
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import math
3
  import json
 
4
  import numpy as np
5
  import pandas as pd
6
  import matplotlib.pyplot as plt
@@ -20,7 +21,9 @@ os.makedirs(OUTDIR, exist_ok=True)
20
  # Shared utilities
21
  # -----------------------------
22
  def set_seed(seed: int):
23
- np.random.seed(int(seed) % (2**32 - 1))
 
 
24
 
25
  def clamp(x, lo, hi):
26
  return max(lo, min(hi, x))
@@ -49,7 +52,7 @@ def tau_eff_adaptive(
49
  """
50
  τ_eff is implemented here as a timing/decision delay modifier.
51
  - base: baseline τ_eff
52
- - slow_by: explicit slow-down term (I wanted this behaviour: slow by 1.0)
53
  - gain: reaction strength to uncertainty
54
  - cap: prevents absurd values
55
  """
@@ -103,6 +106,7 @@ def simulate_neo(
103
  dist = float(np.linalg.norm(meas))
104
 
105
  speed = float(np.linalg.norm(vel))
 
106
  uncertainty = clamp((noise_km / max(alert_km, 1.0)) * 2.0 + (speed / 200.0) * 0.2, 0.0, 1.0)
107
 
108
  baseline_alert = dist <= alert_km
@@ -302,11 +306,6 @@ def simulate_jitter(
302
 
303
  # -----------------------------
304
  # Starship-style Landing Harness (2D)
305
- # FIXES:
306
- # - wind is SIGNED (gusts left/right), not always positive drift
307
- # - control authority increased so the goal is actually reachable
308
- # - gate cannot veto "must-correct" moments (override when error is big / low altitude)
309
- # - includes simple wind feed-forward cancellation term
310
  # -----------------------------
311
  def simulate_landing(
312
  seed: int,
@@ -328,7 +327,7 @@ def simulate_landing(
328
  x = 60.0
329
  xv = 0.0
330
 
331
- # A tiny integral term helps remove persistent bias
332
  ix = 0.0
333
 
334
  anomalies = 0
@@ -336,39 +335,31 @@ def simulate_landing(
336
  ops_proxy = 0
337
  rows = []
338
 
339
- # Tuned plant constants (simple, but consistent)
340
  g = -9.81
341
 
342
- # Control authority (this is what makes 10m achievable)
343
- LAT_CTRL = 0.95 # lateral accel per control unit
344
- WIND_PUSH = 0.28 # lateral accel per m/s wind
345
- VERT_CTRL = 0.22 # vertical accel per control unit
346
 
347
- # Override thresholds (safety style)
348
  OVERRIDE_X = 18.0
349
  OVERRIDE_ALT = 260.0
350
 
351
  for t in range(int(steps)):
352
- # Signed wind with gusty behaviour (not always pushing one way)
353
  gust = math.sin(0.08 * t) + 0.55 * math.sin(0.21 * t + 0.7)
354
  wind = (wind_max * 0.75) * gust + np.random.normal(0.0, 0.65)
355
  wind = clamp(wind, -wind_max, wind_max)
356
 
357
- # Thrust disturbance
358
  thrust_dev = np.random.normal(0.0, thrust_noise)
359
 
360
- # Measurement noise
361
  meas_alt = alt + np.random.normal(0, 0.6)
362
  meas_vv = vv + np.random.normal(0, 0.35)
363
  meas_x = x + np.random.normal(0, 0.8)
364
  meas_xv = xv + np.random.normal(0, 0.25)
365
 
366
- # Uncertainty proxy
367
  uncertainty = clamp((abs(thrust_dev) / 5.0) * 0.18 + (abs(wind) / max(wind_max, 1e-9)) * 0.30, 0.0, 1.0)
368
  tau = tau_eff_adaptive(uncertainty, base=1.0, slow_by=1.0, gain=tau_gain, cap=4.0)
369
  conf = rft_confidence(uncertainty)
370
 
371
- # Anomaly definition (count only meaningful events)
372
  anomaly_types = []
373
  if abs(wind) > (0.85 * wind_max):
374
  anomaly_types.append("High wind")
@@ -380,23 +371,17 @@ def simulate_landing(
380
  if is_anomaly:
381
  anomalies += 1
382
 
383
- # Baseline control (continuous)
384
  u_base_x = -kp_baseline * meas_x - 0.30 * meas_xv
385
  u_base_v = -kp_baseline * (meas_vv + 5.0)
386
 
387
- # RFT control (gated + override)
388
- phase = 1.0 - clamp(meas_alt / 1000.0, 0.0, 1.0) # 0 high up, 1 near ground
389
  lookahead = 1.0 + 1.6 * phase
390
 
391
- # Wind feed-forward: cancel expected push
392
- # If wind is pushing +, we apply opposite control; vice versa.
393
  wind_ff = (WIND_PUSH * wind) / max(LAT_CTRL, 1e-9)
394
 
395
- # Integral accumulates only when closer (so it doesn't explode up high)
396
  if meas_alt < 600:
397
  ix = clamp(ix + (meas_x * dt) * 0.0025, -40.0, 40.0)
398
 
399
- # Gate + override logic
400
  do_action = rft_gate(conf, tau, gate_threshold)
401
  must_act = (abs(meas_x) > OVERRIDE_X) or (meas_alt < OVERRIDE_ALT)
402
  do_action = bool(do_action or must_act)
@@ -404,20 +389,16 @@ def simulate_landing(
404
  u_rft_x = 0.0
405
  u_rft_v = 0.0
406
  if do_action:
407
- # PD + small I + wind FF
408
  u_rft_x = (-kp_rft * lookahead * meas_x) - (0.42 * meas_xv) - (0.20 * ix) - wind_ff
409
  u_rft_v = (-kp_rft * lookahead * (meas_vv + 5.0))
410
  actions += 1
411
 
412
- # Saturate control (realistic bounded actuation)
413
  u_rft_x = clamp(u_rft_x, -20.0, 20.0)
414
  u_rft_v = clamp(u_rft_v, -18.0, 18.0)
415
 
416
- # Apply dynamics
417
  vv = vv + (g + VERT_CTRL * u_rft_v + 0.09 * thrust_dev) * dt
418
  alt = max(0.0, alt + vv * dt)
419
 
420
- # Lateral acceleration from wind and control
421
  xv = xv + (WIND_PUSH * wind - LAT_CTRL * u_rft_x) * dt
422
  x = x + xv * dt
423
 
@@ -501,6 +482,387 @@ def simulate_landing(
501
 
502
  return summary, [p_alt, p_x, p_w, p_a], csv_path
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  # -----------------------------
505
  # Benchmarks
506
  # -----------------------------
@@ -595,35 +957,33 @@ def run_benchmarks(
595
  return txt, score, score_path, all_imgs, [neo_csv, jit_csv, land_csv]
596
 
597
  # -----------------------------
598
- # UI text blocks (full openness)
599
  # -----------------------------
600
  HOME_MD = """
601
  # Rendered Frame Theory (RFT) — Agent Console
602
 
603
- I built this Space to be transparent, reproducible, and benchmarkable.
604
 
605
- I’m not asking anyone to “believe” in anything here.
606
- Run it. Change the parameters. Break it. Compare baseline vs RFT.
607
 
608
- What I’m demonstrating is a practical idea:
609
 
610
  **Decision timing matters.**
611
  RFT treats timing (τ_eff), uncertainty, and action “collapse” as first-class controls.
612
 
613
- This Space contains three working agent harnesses:
614
- - **NEO alerting** (reduce early false positives under noisy tracking)
615
- - **Satellite jitter reduction** (reduce actuator duty / chatter while keeping residual low)
616
- - **Starship-style landing harness** (simplified, but structured to test decision timing under wind/thrust disturbances)
617
-
618
- Every tab shows what it’s doing, why, and where it wins or loses.
619
 
620
- No SciPy. No hidden dependencies. No model weights. No tricks.
621
  """
622
 
623
  LIVE_MD = """
624
  # Live Console
625
 
626
- This tab is a single place to run everything quickly and export logs.
627
 
628
  - deterministic runs (seeded)
629
  - plots saved
@@ -634,99 +994,78 @@ This tab is a single place to run everything quickly and export logs.
634
  THEORY_PRACTICE_MD = """
635
  # Theory → Practice (how I implement RFT here)
636
 
637
- This Space uses RFT in a practical way:
638
-
639
- ## 1) Uncertainty (explicit)
640
- I compute an uncertainty proxy from noise + disturbance scale.
641
 
642
  ## 2) Confidence
643
- Confidence is the complement: confidence = 1 − uncertainty (clipped 0..1).
644
 
645
  ## 3) Adaptive τ_eff
646
- τ_eff is implemented as a timing/decision strictness modifier:
647
- - higher uncertainty → higher τ_eff
648
- - and yes, I explicitly slow τ_eff by 1.0, because this was the behaviour I wanted to test.
649
 
650
  ## 4) Collapse gate
651
- I only apply “decisive actions” when the gate condition passes:
652
- - confidence must exceed a threshold
653
- - τ_eff increases strictness (makes the gate harder under uncertainty)
654
 
655
- ## 5) Why this matters
656
  Baseline controllers often act constantly.
657
- RFT tries to act less often, but more decisively, so you waste less energy and trigger fewer junk corrections/alerts.
658
  """
659
 
660
  MATH_MD = r"""
661
  # Mathematics (minimal and implementation-linked)
662
 
663
- ## Variables (used in this Space)
664
- - u ∈ [0,1] : uncertainty proxy (dimensionless)
665
- - C ∈ [0,1] : confidence proxy (dimensionless)
666
- - τ_eff ≥ 1 : effective render/decision timing factor (dimensionless)
667
-
668
- ## Definitions
669
 
670
- ### Confidence
671
  \[
672
  C = \text{clip}(1 - u, 0, 1)
673
  \]
674
 
675
- ### Adaptive τ_eff (with “slow by 1.0”)
676
  \[
677
  \tau_{\text{eff}} = \text{clip}(1 + 1.0 + g\cdot u,\; 1,\; \tau_{\max})
678
  \]
679
 
680
- ### Collapse gate (concept)
681
- Higher τ_eff makes decisions stricter:
682
  \[
683
  \text{Gate} = \left[C \ge \theta + k(\tau_{\text{eff}}-1)\right]
684
  \]
685
-
686
- That is exactly what I implement here: more uncertainty → higher τ_eff → harder gate → fewer low-confidence actions.
687
  """
688
 
689
  INVESTOR_MD = """
690
- # Investor / Agency Walkthrough (plain language)
691
 
692
- ## What I’m proving inside this Space
693
- I’m demonstrating a decision-timing framework that can be applied to:
694
- - alert filtering (NEO / tracking)
695
  - stabilisation (jitter reduction)
696
- - anomaly-aware control loops (landing harness)
697
-
698
- This is a runnable harness:
699
- - you can reproduce results with seeds
700
- - you can export logs
701
- - you can compare baseline vs RFT
702
- - you can change thresholds and see behaviour shift
703
 
704
- ## What I’m not claiming
705
- - I’m not claiming flight certification
706
- - I’m not claiming any company is using this
707
- - I’m not claiming this replaces aerospace validation pipelines
708
 
709
- ## What would make it production-grade
710
  - real sensor ingestion + timing constraints
711
  - hardware-in-loop testing
712
- - systematic dataset validation
713
- - integration targets (embedded, REST, batch)
714
  """
715
 
716
  REPRO_MD = """
717
  # Reproducibility & Logs
718
 
719
- Everything here is reproducible:
720
- - set the seed
721
- - run baseline vs RFT with the same seed
722
- - export the CSV
723
- - verify plots and metrics
724
-
725
- CSV schema is explicit in the exports:
726
- - time index
727
- - state values
728
- - uncertainty, confidence, τ_eff
729
- - alerts/actions flags
730
  """
731
 
732
  # -----------------------------
@@ -776,6 +1115,40 @@ def ui_run_landing(seed, steps, dt, wind_max, thrust_noise, kp_base, kp_rft, gat
776
  summary_txt = json.dumps(summary, indent=2)
777
  return summary_txt, imgs[0], imgs[1], imgs[2], imgs[3], csv_path
778
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
779
  def ui_run_bench(seed, neo_steps, neo_dt, neo_alert_km, neo_noise_km, jit_steps, jit_dt, jit_noise, land_steps, land_dt, land_wind, land_thrust_noise, tau_gain):
780
  txt, score_df, score_csv, imgs, logs = run_benchmarks(
781
  seed=int(seed),
@@ -784,7 +1157,6 @@ def ui_run_bench(seed, neo_steps, neo_dt, neo_alert_km, neo_noise_km, jit_steps,
784
  land_steps=int(land_steps), land_dt=float(land_dt), land_wind=float(land_wind), land_thrust_noise=float(land_thrust_noise),
785
  tau_gain=float(tau_gain)
786
  )
787
- # IMPORTANT: 16 outputs expected. We return 10 images + 3 files + 3 objects = 16.
788
  return (
789
  txt, score_df, score_csv,
790
  imgs[0], imgs[1], imgs[2], imgs[3], imgs[4], imgs[5], imgs[6], imgs[7], imgs[8], imgs[9],
@@ -794,7 +1166,7 @@ def ui_run_bench(seed, neo_steps, neo_dt, neo_alert_km, neo_noise_km, jit_steps,
794
  # -----------------------------
795
  # Gradio UI
796
  # -----------------------------
797
- with gr.Blocks(title="RFT — Agent Console (NEO / Jitter / Landing)") as demo:
798
  gr.Markdown(HOME_MD)
799
 
800
  with gr.Tabs():
@@ -862,7 +1234,6 @@ with gr.Blocks(title="RFT — Agent Console (NEO / Jitter / Landing)") as demo:
862
  with gr.Tab("NEO Agent"):
863
  gr.Markdown(
864
  "# Near-Earth Object (NEO) Alerting Agent\n"
865
- "This is a test harness for filtering close-approach alerts under noise.\n"
866
  "Baseline: distance threshold only.\n"
867
  "RFT: distance threshold + confidence + τ_eff collapse gate.\n"
868
  )
@@ -898,7 +1269,6 @@ with gr.Blocks(title="RFT — Agent Console (NEO / Jitter / Landing)") as demo:
898
  "# Satellite Jitter Reduction\n"
899
  "Baseline: continuous correction.\n"
900
  "RFT: gated correction using confidence + τ_eff.\n"
901
- "This is a simple but honest test of duty-cycle reduction.\n"
902
  )
903
  with gr.Row():
904
  seed_j = gr.Number(value=42, precision=0, label="Seed")
@@ -930,7 +1300,6 @@ with gr.Blocks(title="RFT — Agent Console (NEO / Jitter / Landing)") as demo:
930
  gr.Markdown(
931
  "# Starship-style Landing Harness (Simplified)\n"
932
  "This is not a flight model. It’s a timing-control harness.\n"
933
- "Baseline vs RFT shows whether gated decision timing can reduce waste and still hit the landing goal.\n"
934
  )
935
  with gr.Row():
936
  seed_l = gr.Number(value=42, precision=0, label="Seed")
@@ -962,13 +1331,68 @@ with gr.Blocks(title="RFT — Agent Console (NEO / Jitter / Landing)") as demo:
962
  )
963
 
964
  # ----------------------------------------------------------
965
- with gr.Tab("Benchmarks"):
966
  gr.Markdown(
967
- "# Benchmarks\n"
968
- "Run full packs from the Live Console tab.\n"
969
- "Everything is seeded, logged, and exportable.\n"
 
970
  )
971
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
972
  with gr.Tab("Theory → Practice"):
973
  gr.Markdown(THEORY_PRACTICE_MD)
974
 
 
1
  import os
2
  import math
3
  import json
4
+ import random
5
  import numpy as np
6
  import pandas as pd
7
  import matplotlib.pyplot as plt
 
21
  # Shared utilities
22
  # -----------------------------
23
  def set_seed(seed: int):
24
+ seed = int(seed) % (2**32 - 1)
25
+ np.random.seed(seed)
26
+ random.seed(seed)
27
 
28
  def clamp(x, lo, hi):
29
  return max(lo, min(hi, x))
 
52
  """
53
  τ_eff is implemented here as a timing/decision delay modifier.
54
  - base: baseline τ_eff
55
+ - slow_by: explicit slow-down term
56
  - gain: reaction strength to uncertainty
57
  - cap: prevents absurd values
58
  """
 
106
  dist = float(np.linalg.norm(meas))
107
 
108
  speed = float(np.linalg.norm(vel))
109
+ # uncertainty proxy: noise relative to alert radius + a mild speed term
110
  uncertainty = clamp((noise_km / max(alert_km, 1.0)) * 2.0 + (speed / 200.0) * 0.2, 0.0, 1.0)
111
 
112
  baseline_alert = dist <= alert_km
 
306
 
307
  # -----------------------------
308
  # Starship-style Landing Harness (2D)
 
 
 
 
 
309
  # -----------------------------
310
  def simulate_landing(
311
  seed: int,
 
327
  x = 60.0
328
  xv = 0.0
329
 
330
+ # Integral term helps remove persistent bias
331
  ix = 0.0
332
 
333
  anomalies = 0
 
335
  ops_proxy = 0
336
  rows = []
337
 
 
338
  g = -9.81
339
 
340
+ LAT_CTRL = 0.95
341
+ WIND_PUSH = 0.28
342
+ VERT_CTRL = 0.22
 
343
 
 
344
  OVERRIDE_X = 18.0
345
  OVERRIDE_ALT = 260.0
346
 
347
  for t in range(int(steps)):
 
348
  gust = math.sin(0.08 * t) + 0.55 * math.sin(0.21 * t + 0.7)
349
  wind = (wind_max * 0.75) * gust + np.random.normal(0.0, 0.65)
350
  wind = clamp(wind, -wind_max, wind_max)
351
 
 
352
  thrust_dev = np.random.normal(0.0, thrust_noise)
353
 
 
354
  meas_alt = alt + np.random.normal(0, 0.6)
355
  meas_vv = vv + np.random.normal(0, 0.35)
356
  meas_x = x + np.random.normal(0, 0.8)
357
  meas_xv = xv + np.random.normal(0, 0.25)
358
 
 
359
  uncertainty = clamp((abs(thrust_dev) / 5.0) * 0.18 + (abs(wind) / max(wind_max, 1e-9)) * 0.30, 0.0, 1.0)
360
  tau = tau_eff_adaptive(uncertainty, base=1.0, slow_by=1.0, gain=tau_gain, cap=4.0)
361
  conf = rft_confidence(uncertainty)
362
 
 
363
  anomaly_types = []
364
  if abs(wind) > (0.85 * wind_max):
365
  anomaly_types.append("High wind")
 
371
  if is_anomaly:
372
  anomalies += 1
373
 
 
374
  u_base_x = -kp_baseline * meas_x - 0.30 * meas_xv
375
  u_base_v = -kp_baseline * (meas_vv + 5.0)
376
 
377
+ phase = 1.0 - clamp(meas_alt / 1000.0, 0.0, 1.0)
 
378
  lookahead = 1.0 + 1.6 * phase
379
 
 
 
380
  wind_ff = (WIND_PUSH * wind) / max(LAT_CTRL, 1e-9)
381
 
 
382
  if meas_alt < 600:
383
  ix = clamp(ix + (meas_x * dt) * 0.0025, -40.0, 40.0)
384
 
 
385
  do_action = rft_gate(conf, tau, gate_threshold)
386
  must_act = (abs(meas_x) > OVERRIDE_X) or (meas_alt < OVERRIDE_ALT)
387
  do_action = bool(do_action or must_act)
 
389
  u_rft_x = 0.0
390
  u_rft_v = 0.0
391
  if do_action:
 
392
  u_rft_x = (-kp_rft * lookahead * meas_x) - (0.42 * meas_xv) - (0.20 * ix) - wind_ff
393
  u_rft_v = (-kp_rft * lookahead * (meas_vv + 5.0))
394
  actions += 1
395
 
 
396
  u_rft_x = clamp(u_rft_x, -20.0, 20.0)
397
  u_rft_v = clamp(u_rft_v, -18.0, 18.0)
398
 
 
399
  vv = vv + (g + VERT_CTRL * u_rft_v + 0.09 * thrust_dev) * dt
400
  alt = max(0.0, alt + vv * dt)
401
 
 
402
  xv = xv + (WIND_PUSH * wind - LAT_CTRL * u_rft_x) * dt
403
  x = x + xv * dt
404
 
 
482
 
483
  return summary, [p_alt, p_x, p_w, p_a], csv_path
484
 
485
+ # ===============================================================
486
+ # Predator Avoidance (Reflex vs QuantumConscious "RFT-style")
487
+ # ===============================================================
488
+
489
+ def numpy_convolve2d_toroidal(array: np.ndarray, kernel: np.ndarray) -> np.ndarray:
490
+ out = np.zeros_like(array, dtype=float)
491
+ kcx = kernel.shape[0] // 2
492
+ kcy = kernel.shape[1] // 2
493
+ rows, cols = array.shape
494
+ for i in range(rows):
495
+ for j in range(cols):
496
+ val = 0.0
497
+ for m in range(kernel.shape[0]):
498
+ for n in range(kernel.shape[1]):
499
+ x = (i + m - kcx) % rows
500
+ y = (j + n - kcy) % cols
501
+ val += array[x, y] * kernel[m, n]
502
+ out[i, j] = val
503
+ return out
504
+
505
+ class Predator:
506
+ def __init__(self, grid_size: int):
507
+ self.grid_size = grid_size
508
+ self.x = random.randint(0, grid_size - 1)
509
+ self.y = random.randint(0, grid_size - 1)
510
+
511
+ def move(self):
512
+ dx, dy = random.choice([(0,1), (0,-1), (1,0), (-1,0)])
513
+ self.x = (self.x + dx) % self.grid_size
514
+ self.y = (self.y + dy) % self.grid_size
515
+
516
+ class ReflexAgent:
517
+ def __init__(self, grid_size: int):
518
+ self.grid_size = grid_size
519
+ self.x = random.randint(0, grid_size - 1)
520
+ self.y = random.randint(0, grid_size - 1)
521
+ self.collisions = 0
522
+
523
+ def move(self):
524
+ dx, dy = random.choice([(0,1), (0,-1), (1,0), (-1,0)])
525
+ self.x = (self.x + dx) % self.grid_size
526
+ self.y = (self.y + dy) % self.grid_size
527
+
528
+ class QuantumConsciousAgent:
529
+ def __init__(
530
+ self,
531
+ grid_size: int,
532
+ move_kernel: np.ndarray,
533
+ energy_max: float,
534
+ energy_regen: float,
535
+ base_override_cost: float,
536
+ quantum_boost_prob: float,
537
+ quantum_boost_amount: float,
538
+ sense_noise_prob: float,
539
+ alpha: float,
540
+ beta: float,
541
+ dt_internal: float,
542
+ override_threshold: float
543
+ ):
544
+ self.grid_size = grid_size
545
+ self.move_kernel = move_kernel.astype(float)
546
+
547
+ # "probability field" + initial collapse
548
+ self.pos_prob = np.zeros((grid_size, grid_size), dtype=float)
549
+ x, y = np.random.randint(grid_size), np.random.randint(grid_size)
550
+ self.pos_prob[x, y] = 1.0
551
+ self.x, self.y = int(x), int(y)
552
+
553
+ # energy + override state
554
+ self.energy_max = float(energy_max)
555
+ self.energy = float(energy_max)
556
+ self.energy_regen = float(energy_regen)
557
+ self.base_override_cost = float(base_override_cost)
558
+ self.quantum_boost_prob = float(quantum_boost_prob)
559
+ self.quantum_boost_amount = float(quantum_boost_amount)
560
+ self.sense_noise_prob = float(sense_noise_prob)
561
+
562
+ self.alpha = float(alpha)
563
+ self.beta = float(beta)
564
+ self.dt_internal = float(dt_internal)
565
+ self.override_threshold = float(override_threshold)
566
+
567
+ self.psi_override = (0.1 + 0j)
568
+ self.overrides = 0
569
+ self.collisions = 0
570
+
571
+ def move(self):
572
+ dx, dy = random.choice([(0,1), (0,-1), (1,0), (-1,0)])
573
+ self.x = (self.x + dx) % self.grid_size
574
+ self.y = (self.y + dy) % self.grid_size
575
+
576
+ def sense_predators(self, predators):
577
+ perceived = []
578
+ for p in predators:
579
+ if random.random() < self.sense_noise_prob:
580
+ # drop this predator (sensor miss)
581
+ continue
582
+ perceived.append((p.x, p.y))
583
+ return perceived
584
+
585
+ def compute_threat(self, perceived):
586
+ # threat = probability mass near predators (radius window)
587
+ threat = 0.0
588
+ radius = 2
589
+ for (px, py) in perceived:
590
+ xs = [(px + dx) % self.grid_size for dx in range(-radius, radius + 1)]
591
+ ys = [(py + dy) % self.grid_size for dy in range(-radius, radius + 1)]
592
+ sub = self.pos_prob[np.ix_(xs, ys)]
593
+ threat += float(sub.sum())
594
+ return threat
595
+
596
+ def update_override_state(self, perceived):
597
+ T = self.compute_threat(perceived)
598
+ E = self.energy / max(self.energy_max, 1e-9)
599
+ # same structural shape as your PDF: H = alpha*T - beta*E + small recursion term
600
+ H = self.alpha * T - self.beta * E + 0.01 * (abs(self.psi_override) ** 2)
601
+ self.psi_override *= np.exp(-1j * H * self.dt_internal)
602
+
603
+ def get_override_probability(self):
604
+ return float(abs(self.psi_override) ** 2)
605
+
606
+ def apply_override(self, perceived):
607
+ # diffuse probability a little (kernel), then suppress regions near predators
608
+ field = numpy_convolve2d_toroidal(self.pos_prob, self.move_kernel)
609
+ field = np.maximum(field, 0.0)
610
+
611
+ # suppress predator neighborhoods
612
+ for (px, py) in perceived:
613
+ for dx in range(-2, 3):
614
+ for dy in range(-2, 3):
615
+ nx = (px + dx) % self.grid_size
616
+ ny = (py + dy) % self.grid_size
617
+ dist = abs(dx) + abs(dy)
618
+ field[nx, ny] *= (1.0 - 0.30 / (dist + 1.0))
619
+
620
+ s = float(field.sum())
621
+ if s <= 0:
622
+ # fallback to uniform
623
+ field[:] = 1.0 / (self.grid_size * self.grid_size)
624
+ else:
625
+ field /= s
626
+
627
+ self.pos_prob = field
628
+
629
+ # collapse away from predator cells explicitly
630
+ flat = self.pos_prob.flatten().copy()
631
+ for (px, py) in perceived:
632
+ flat[px * self.grid_size + py] = 0.0
633
+
634
+ tot = float(flat.sum())
635
+ if tot <= 0:
636
+ # if all got zeroed (rare), just random move
637
+ self.move()
638
+ return
639
+
640
+ flat /= tot
641
+ idx = np.random.choice(self.grid_size * self.grid_size, p=flat)
642
+ self.x, self.y = divmod(int(idx), self.grid_size)
643
+
644
+ def quantum_energy_boost(self):
645
+ if random.random() < self.quantum_boost_prob:
646
+ return float(self.quantum_boost_amount)
647
+ return 0.0
648
+
649
+ def regen_energy(self):
650
+ boost = self.quantum_energy_boost()
651
+ self.energy = clamp(self.energy + self.energy_regen + boost, 0.0, self.energy_max)
652
+ # occasional full regen (as in your runs)
653
+ if self.energy < self.energy_max and random.random() < 0.05:
654
+ self.energy = self.energy_max
655
+
656
+ def move_consciously(self, predators, group_coherence: float):
657
+ if self.energy <= 0:
658
+ self.move()
659
+ return 0, 0.0, 0.0 # acted?, P_ov, threat
660
+
661
+ perceived = self.sense_predators(predators)
662
+ self.update_override_state(perceived)
663
+ P_ov = self.get_override_probability()
664
+ threat = self.compute_threat(perceived)
665
+
666
+ acted = 0
667
+ if (P_ov > self.override_threshold) and (self.energy > 0):
668
+ effective_cost = self.base_override_cost * (1.0 - float(group_coherence))
669
+ if self.energy >= effective_cost:
670
+ self.overrides += 1
671
+ self.energy -= effective_cost
672
+ self.apply_override(perceived)
673
+ self.psi_override = (0.1 + 0j)
674
+ acted = 1
675
+ else:
676
+ self.move()
677
+ else:
678
+ self.move()
679
+
680
+ return acted, P_ov, threat
681
+
682
+ def simulate_predator(
683
+ seed: int,
684
+ grid_size: int,
685
+ steps: int,
686
+ num_reflex: int,
687
+ num_conscious: int,
688
+ num_predators: int,
689
+ group_coherence: float,
690
+ sense_noise_prob: float,
691
+ override_threshold: float,
692
+ alpha: float,
693
+ beta: float,
694
+ dt_internal: float,
695
+ energy_max: float,
696
+ base_override_cost: float,
697
+ energy_regen: float,
698
+ quantum_boost_prob: float,
699
+ quantum_boost_amount: float,
700
+ show_heatmap: bool
701
+ ):
702
+ set_seed(seed)
703
+
704
+ move_kernel = np.array([[0, 0.2, 0],
705
+ [0.2, 0.2, 0.2],
706
+ [0, 0.2, 0]], dtype=float)
707
+
708
+ reflex_agents = [ReflexAgent(grid_size) for _ in range(int(num_reflex))]
709
+ conscious_agents = [
710
+ QuantumConsciousAgent(
711
+ grid_size=grid_size,
712
+ move_kernel=move_kernel,
713
+ energy_max=energy_max,
714
+ energy_regen=energy_regen,
715
+ base_override_cost=base_override_cost,
716
+ quantum_boost_prob=quantum_boost_prob,
717
+ quantum_boost_amount=quantum_boost_amount,
718
+ sense_noise_prob=sense_noise_prob,
719
+ alpha=alpha,
720
+ beta=beta,
721
+ dt_internal=dt_internal,
722
+ override_threshold=override_threshold
723
+ )
724
+ for _ in range(int(num_conscious))
725
+ ]
726
+ predators = [Predator(grid_size) for _ in range(int(num_predators))]
727
+
728
+ reflex_collisions_cum = []
729
+ conscious_collisions_cum = []
730
+ conscious_overrides_avg = []
731
+ conscious_energy_avg = []
732
+ conscious_threat_avg = []
733
+ conscious_pov_avg = []
734
+ conscious_actions_avg = []
735
+
736
+ rows = []
737
+ ops_proxy = 0
738
+
739
+ for t in range(int(steps)):
740
+ # predators move first
741
+ for p in predators:
742
+ p.move()
743
+
744
+ # reflex move + collision check
745
+ for a in reflex_agents:
746
+ a.move()
747
+ for p in predators:
748
+ if a.x == p.x and a.y == p.y:
749
+ a.collisions += 1
750
+
751
+ # conscious move + collision check
752
+ actions = []
753
+ povs = []
754
+ threats = []
755
+ for a in conscious_agents:
756
+ acted, P_ov, threat = a.move_consciously(predators, group_coherence)
757
+ a.regen_energy()
758
+ actions.append(acted)
759
+ povs.append(P_ov)
760
+ threats.append(threat)
761
+ for p in predators:
762
+ if a.x == p.x and a.y == p.y:
763
+ a.collisions += 1
764
+
765
+ ops_proxy += 18
766
+
767
+ reflex_collisions = int(sum(a.collisions for a in reflex_agents))
768
+ conscious_collisions = int(sum(a.collisions for a in conscious_agents))
769
+ avg_overrides = float(np.mean([a.overrides for a in conscious_agents])) if conscious_agents else 0.0
770
+ avg_energy = float(np.mean([a.energy for a in conscious_agents])) if conscious_agents else 0.0
771
+ avg_threat = float(np.mean(threats)) if threats else 0.0
772
+ avg_pov = float(np.mean(povs)) if povs else 0.0
773
+ avg_act = float(np.mean(actions)) if actions else 0.0
774
+
775
+ reflex_collisions_cum.append(reflex_collisions)
776
+ conscious_collisions_cum.append(conscious_collisions)
777
+ conscious_overrides_avg.append(avg_overrides)
778
+ conscious_energy_avg.append(avg_energy)
779
+ conscious_threat_avg.append(avg_threat)
780
+ conscious_pov_avg.append(avg_pov)
781
+ conscious_actions_avg.append(avg_act)
782
+
783
+ # log row (one line per step)
784
+ rows.append({
785
+ "t": t,
786
+ "reflex_collisions_cum": reflex_collisions,
787
+ "conscious_collisions_cum": conscious_collisions,
788
+ "avg_conscious_overrides": avg_overrides,
789
+ "avg_conscious_energy": avg_energy,
790
+ "avg_conscious_threat": avg_threat,
791
+ "avg_conscious_P_override": avg_pov,
792
+ "avg_conscious_action": avg_act,
793
+ "predators_positions": "|".join([f"{p.x},{p.y}" for p in predators]),
794
+ })
795
+
796
+ df = pd.DataFrame(rows)
797
+ csv_path = df_to_csv_file(df, f"predator_log_seed{seed}.csv")
798
+
799
+ # Plot 1: collisions (cumulative)
800
+ fig1 = plt.figure(figsize=(10, 4))
801
+ ax = fig1.add_subplot(111)
802
+ ax.plot(df["t"], df["reflex_collisions_cum"], label="Reflex collisions (cum)")
803
+ ax.plot(df["t"], df["conscious_collisions_cum"], label="Conscious collisions (cum)")
804
+ ax.set_title("Predator Avoidance: Collisions (Reflex vs RFT)")
805
+ ax.set_xlabel("t (step)")
806
+ ax.set_ylabel("collisions (cum)")
807
+ ax.legend()
808
+ p_col = save_plot(fig1, f"predator_collisions_seed{seed}.png")
809
+
810
+ # Plot 2: overrides + energy
811
+ fig2 = plt.figure(figsize=(10, 4))
812
+ ax = fig2.add_subplot(111)
813
+ ax.plot(df["t"], df["avg_conscious_overrides"], label="Avg overrides (conscious)")
814
+ ax.plot(df["t"], df["avg_conscious_energy"], label="Avg energy (conscious)")
815
+ ax.set_title("Predator Avoidance: Overrides + Energy (Conscious)")
816
+ ax.set_xlabel("t (step)")
817
+ ax.set_ylabel("value")
818
+ ax.legend()
819
+ p_ov = save_plot(fig2, f"predator_overrides_energy_seed{seed}.png")
820
+
821
+ # Plot 3: threat + P_override + actions
822
+ fig3 = plt.figure(figsize=(10, 4))
823
+ ax = fig3.add_subplot(111)
824
+ ax.plot(df["t"], df["avg_conscious_threat"], label="Avg threat")
825
+ ax.plot(df["t"], df["avg_conscious_P_override"], label="Avg P_override")
826
+ ax.plot(df["t"], df["avg_conscious_action"], label="Avg action rate")
827
+ ax.set_title("Predator Avoidance: Threat vs Override Probability vs Action Rate")
828
+ ax.set_xlabel("t (step)")
829
+ ax.set_ylabel("value")
830
+ ax.legend()
831
+ p_thr = save_plot(fig3, f"predator_threat_seed{seed}.png")
832
+
833
+ heatmap_path = None
834
+ if show_heatmap and len(conscious_agents) > 0:
835
+ # show the final probability field of agent 0
836
+ field = conscious_agents[0].pos_prob
837
+ fig4 = plt.figure(figsize=(6, 5))
838
+ ax = fig4.add_subplot(111)
839
+ im = ax.imshow(field, aspect="auto")
840
+ ax.set_title("Conscious Agent[0]: Final probability field (pos_prob)")
841
+ ax.set_xlabel("y")
842
+ ax.set_ylabel("x")
843
+ fig4.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
844
+ heatmap_path = save_plot(fig4, f"predator_probfield_seed{seed}.png")
845
+
846
+ summary = {
847
+ "seed": int(seed),
848
+ "grid_size": int(grid_size),
849
+ "steps": int(steps),
850
+ "num_reflex": int(num_reflex),
851
+ "num_conscious": int(num_conscious),
852
+ "num_predators": int(num_predators),
853
+ "final_reflex_collisions": int(df["reflex_collisions_cum"].iloc[-1]) if len(df) else 0,
854
+ "final_conscious_collisions": int(df["conscious_collisions_cum"].iloc[-1]) if len(df) else 0,
855
+ "final_avg_conscious_overrides": float(df["avg_conscious_overrides"].iloc[-1]) if len(df) else 0.0,
856
+ "final_avg_conscious_energy": float(df["avg_conscious_energy"].iloc[-1]) if len(df) else 0.0,
857
+ "ops_proxy": int(ops_proxy),
858
+ }
859
+
860
+ imgs = [p_col, p_ov, p_thr]
861
+ if heatmap_path is not None:
862
+ imgs.append(heatmap_path)
863
+
864
+ return summary, imgs, csv_path
865
+
866
  # -----------------------------
867
  # Benchmarks
868
  # -----------------------------
 
957
  return txt, score, score_path, all_imgs, [neo_csv, jit_csv, land_csv]
958
 
959
  # -----------------------------
960
+ # UI text blocks
961
  # -----------------------------
962
  HOME_MD = """
963
  # Rendered Frame Theory (RFT) — Agent Console
964
 
965
+ This Space is meant to be transparent, reproducible, and benchmarkable.
966
 
967
+ Run it. Change parameters. Break it. Compare baseline vs RFT.
 
968
 
969
+ Core idea:
970
 
971
  **Decision timing matters.**
972
  RFT treats timing (τ_eff), uncertainty, and action “collapse” as first-class controls.
973
 
974
+ This Space contains:
975
+ - **NEO alerting**
976
+ - **Satellite jitter reduction**
977
+ - **Starship-style landing harness**
978
+ - **Predator avoidance** (Reflex vs RFT-style "QuantumConscious" agents)
 
979
 
980
+ No SciPy. No hidden dependencies. No model weights.
981
  """
982
 
983
  LIVE_MD = """
984
  # Live Console
985
 
986
+ Run everything quickly and export logs.
987
 
988
  - deterministic runs (seeded)
989
  - plots saved
 
994
  THEORY_PRACTICE_MD = """
995
  # Theory → Practice (how I implement RFT here)
996
 
997
+ ## 1) Uncertainty
998
+ Explicit uncertainty proxy from noise + disturbance scale.
 
 
999
 
1000
  ## 2) Confidence
1001
+ confidence = 1 − uncertainty (clipped 0..1).
1002
 
1003
  ## 3) Adaptive τ_eff
1004
+ Higher uncertainty higher τ_eff.
 
 
1005
 
1006
  ## 4) Collapse gate
1007
+ Act only when the gate passes:
1008
+ - confidence exceeds a threshold
1009
+ - τ_eff increases strictness under uncertainty
1010
 
1011
+ ## 5) Why it matters
1012
  Baseline controllers often act constantly.
1013
+ RFT tries to act less often, but more decisively.
1014
  """
1015
 
1016
  MATH_MD = r"""
1017
  # Mathematics (minimal and implementation-linked)
1018
 
1019
+ u [0,1] : uncertainty proxy
1020
+ C ∈ [0,1] : confidence proxy
1021
+ τ_eff 1 : effective decision timing factor
 
 
 
1022
 
1023
+ Confidence:
1024
  \[
1025
  C = \text{clip}(1 - u, 0, 1)
1026
  \]
1027
 
1028
+ Adaptive τ_eff:
1029
  \[
1030
  \tau_{\text{eff}} = \text{clip}(1 + 1.0 + g\cdot u,\; 1,\; \tau_{\max})
1031
  \]
1032
 
1033
+ Collapse gate (concept):
 
1034
  \[
1035
  \text{Gate} = \left[C \ge \theta + k(\tau_{\text{eff}}-1)\right]
1036
  \]
 
 
1037
  """
1038
 
1039
  INVESTOR_MD = """
1040
+ # Investor / Agency Walkthrough
1041
 
1042
+ What this Space demonstrates:
1043
+ - alert filtering (NEO)
 
1044
  - stabilisation (jitter reduction)
1045
+ - anomaly-aware control (landing harness)
1046
+ - threat-aware avoidance (predator demo)
 
 
 
 
 
1047
 
1048
+ What it is not:
1049
+ - not flight-certified
1050
+ - not a production pipeline
1051
+ - not a claim that anyone is using it
1052
 
1053
+ What makes it production-grade:
1054
  - real sensor ingestion + timing constraints
1055
  - hardware-in-loop testing
1056
+ - dataset validation
 
1057
  """
1058
 
1059
  REPRO_MD = """
1060
  # Reproducibility & Logs
1061
 
1062
+ Everything is reproducible:
1063
+ - set seed
1064
+ - run
1065
+ - export CSV
1066
+ - verify plots + metrics
1067
+
1068
+ CSV schema is explicit in the exports.
 
 
 
 
1069
  """
1070
 
1071
  # -----------------------------
 
1115
  summary_txt = json.dumps(summary, indent=2)
1116
  return summary_txt, imgs[0], imgs[1], imgs[2], imgs[3], csv_path
1117
 
1118
+ def ui_run_predator(seed, grid_size, steps, num_reflex, num_conscious, num_predators,
1119
+ group_coherence, sense_noise_prob, override_threshold,
1120
+ alpha, beta, dt_internal,
1121
+ energy_max, base_override_cost, energy_regen,
1122
+ quantum_boost_prob, quantum_boost_amount,
1123
+ show_heatmap):
1124
+ summary, imgs, csv_path = simulate_predator(
1125
+ seed=int(seed),
1126
+ grid_size=int(grid_size),
1127
+ steps=int(steps),
1128
+ num_reflex=int(num_reflex),
1129
+ num_conscious=int(num_conscious),
1130
+ num_predators=int(num_predators),
1131
+ group_coherence=float(group_coherence),
1132
+ sense_noise_prob=float(sense_noise_prob),
1133
+ override_threshold=float(override_threshold),
1134
+ alpha=float(alpha),
1135
+ beta=float(beta),
1136
+ dt_internal=float(dt_internal),
1137
+ energy_max=float(energy_max),
1138
+ base_override_cost=float(base_override_cost),
1139
+ energy_regen=float(energy_regen),
1140
+ quantum_boost_prob=float(quantum_boost_prob),
1141
+ quantum_boost_amount=float(quantum_boost_amount),
1142
+ show_heatmap=bool(show_heatmap)
1143
+ )
1144
+ summary_txt = json.dumps(summary, indent=2)
1145
+ # imgs: 3 or 4
1146
+ img1 = imgs[0] if len(imgs) > 0 else None
1147
+ img2 = imgs[1] if len(imgs) > 1 else None
1148
+ img3 = imgs[2] if len(imgs) > 2 else None
1149
+ img4 = imgs[3] if len(imgs) > 3 else None
1150
+ return summary_txt, img1, img2, img3, img4, csv_path
1151
+
1152
  def ui_run_bench(seed, neo_steps, neo_dt, neo_alert_km, neo_noise_km, jit_steps, jit_dt, jit_noise, land_steps, land_dt, land_wind, land_thrust_noise, tau_gain):
1153
  txt, score_df, score_csv, imgs, logs = run_benchmarks(
1154
  seed=int(seed),
 
1157
  land_steps=int(land_steps), land_dt=float(land_dt), land_wind=float(land_wind), land_thrust_noise=float(land_thrust_noise),
1158
  tau_gain=float(tau_gain)
1159
  )
 
1160
  return (
1161
  txt, score_df, score_csv,
1162
  imgs[0], imgs[1], imgs[2], imgs[3], imgs[4], imgs[5], imgs[6], imgs[7], imgs[8], imgs[9],
 
1166
  # -----------------------------
1167
  # Gradio UI
1168
  # -----------------------------
1169
+ with gr.Blocks(title="RFT — Agent Console (NEO / Jitter / Landing / Predator)") as demo:
1170
  gr.Markdown(HOME_MD)
1171
 
1172
  with gr.Tabs():
 
1234
  with gr.Tab("NEO Agent"):
1235
  gr.Markdown(
1236
  "# Near-Earth Object (NEO) Alerting Agent\n"
 
1237
  "Baseline: distance threshold only.\n"
1238
  "RFT: distance threshold + confidence + τ_eff collapse gate.\n"
1239
  )
 
1269
  "# Satellite Jitter Reduction\n"
1270
  "Baseline: continuous correction.\n"
1271
  "RFT: gated correction using confidence + τ_eff.\n"
 
1272
  )
1273
  with gr.Row():
1274
  seed_j = gr.Number(value=42, precision=0, label="Seed")
 
1300
  gr.Markdown(
1301
  "# Starship-style Landing Harness (Simplified)\n"
1302
  "This is not a flight model. It’s a timing-control harness.\n"
 
1303
  )
1304
  with gr.Row():
1305
  seed_l = gr.Number(value=42, precision=0, label="Seed")
 
1331
  )
1332
 
1333
  # ----------------------------------------------------------
1334
+ with gr.Tab("Predator Avoidance"):
1335
  gr.Markdown(
1336
+ "# Predator Avoidance (Reflex vs RFT)\n"
1337
+ "Grid world with roaming predators.\n"
1338
+ "Reflex agents: random walk.\n"
1339
+ "Conscious agents: probability field + threat-weighted override.\n"
1340
  )
1341
 
1342
+ with gr.Row():
1343
+ seed_p = gr.Number(value=42, precision=0, label="Seed")
1344
+ grid_size = gr.Slider(10, 60, value=20, step=1, label="Grid size")
1345
+ steps_p = gr.Slider(50, 1500, value=200, step=1, label="Steps")
1346
+
1347
+ with gr.Row():
1348
+ num_reflex = gr.Slider(0, 50, value=10, step=1, label="Reflex agents")
1349
+ num_conscious = gr.Slider(0, 20, value=3, step=1, label="Conscious agents")
1350
+ num_predators = gr.Slider(1, 20, value=3, step=1, label="Predators")
1351
+
1352
+ with gr.Accordion("RFT / Agent parameters", open=True):
1353
+ with gr.Row():
1354
+ group_coherence = gr.Slider(0.0, 0.95, value=0.30, step=0.01, label="Group coherence")
1355
+ sense_noise_prob = gr.Slider(0.0, 0.9, value=0.10, step=0.01, label="Sense noise probability")
1356
+ override_threshold = gr.Slider(0.0, 1.0, value=0.01, step=0.005, label="Override threshold (P_ov)")
1357
+
1358
+ with gr.Row():
1359
+ alpha = gr.Slider(0.0, 50.0, value=15.0, step=0.5, label="alpha (threat gain)")
1360
+ beta = gr.Slider(0.0, 10.0, value=0.5, step=0.05, label="beta (energy term)")
1361
+ dt_internal = gr.Slider(0.01, 1.0, value=0.2, step=0.01, label="override dt")
1362
+
1363
+ with gr.Row():
1364
+ energy_max = gr.Slider(1.0, 300.0, value=100.0, step=1.0, label="Energy max")
1365
+ base_override_cost = gr.Slider(0.0, 10.0, value=1.0, step=0.1, label="Base override cost")
1366
+ energy_regen = gr.Slider(0.0, 1.0, value=0.05, step=0.01, label="Energy regen")
1367
+
1368
+ with gr.Row():
1369
+ quantum_boost_prob = gr.Slider(0.0, 1.0, value=0.10, step=0.01, label="Quantum boost probability")
1370
+ quantum_boost_amount = gr.Slider(0.0, 50.0, value=5.0, step=0.5, label="Quantum boost amount")
1371
+ show_heatmap = gr.Checkbox(value=True, label="Show probability field heatmap (agent[0])")
1372
+
1373
+ run_p = gr.Button("Run Predator Simulation")
1374
+
1375
+ out_p_summary = gr.Textbox(label="Summary JSON", lines=12)
1376
+ with gr.Row():
1377
+ out_p_img1 = gr.Image(label="Collisions (cumulative)")
1378
+ out_p_img2 = gr.Image(label="Overrides + Energy")
1379
+ with gr.Row():
1380
+ out_p_img3 = gr.Image(label="Threat / P_override / Action rate")
1381
+ out_p_img4 = gr.Image(label="Final probability field (optional)")
1382
+ out_p_csv = gr.File(label="Download Predator CSV log")
1383
+
1384
+ run_p.click(
1385
+ ui_run_predator,
1386
+ inputs=[seed_p, grid_size, steps_p, num_reflex, num_conscious, num_predators,
1387
+ group_coherence, sense_noise_prob, override_threshold,
1388
+ alpha, beta, dt_internal,
1389
+ energy_max, base_override_cost, energy_regen,
1390
+ quantum_boost_prob, quantum_boost_amount,
1391
+ show_heatmap],
1392
+ outputs=[out_p_summary, out_p_img1, out_p_img2, out_p_img3, out_p_img4, out_p_csv]
1393
+ )
1394
+
1395
+ # ----------------------------------------------------------
1396
  with gr.Tab("Theory → Practice"):
1397
  gr.Markdown(THEORY_PRACTICE_MD)
1398