everydaytok commited on
Commit
9f89d01
Β·
verified Β·
1 Parent(s): 21bddda

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +205 -279
app.py CHANGED
@@ -1,36 +1,25 @@
1
  #!/usr/bin/env python3
2
  """
3
- PRACTICALITY SYSTEM 3.12
4
-
5
- ===================================================================
6
- ARCHITECTURE & TENSOR TRANSITION MANIFESTO (V4.0 PREP)
7
- ===================================================================
8
- As the system scales to hundreds of scopes, the current scalar-dict
9
- architecture will bottleneck. To transition to GPU/Numba in V4.0
10
- without regressions, we must adhere to the following mapping:
11
-
12
- 1. DATA STRUCTURES:
13
- - Current: `Box = Dict[str, IV]` passing through Python queues.
14
- - Future Tensor: `bounds = np.zeros((N_boxes, N_vars, 2), dtype=np.float32)`
15
- Dimension 0 represents independent hypotheses/regions.
16
- Dimension 1 represents PSL variables (mapped to integer indices).
17
- Dimension 2 represents [lower_bound, upper_bound].
18
-
19
- 2. EVALUATION (SIMD):
20
- - Current: AST loops evaluating `MathConstraint.fast_iv` one by one.
21
- - Future Tensor: Constraints pre-compiled into vectorized Numpy universal
22
- functions (ufuncs). E.g., `np.add(bounds[:, v1, :], bounds[:, v2, :])`.
23
- Invalid regions generate boolean bitmasks `valid_mask = np.ones(N_boxes)`.
24
- ===================================================================
25
-
26
- Changes from 3.11:
27
- FIX 1 β€” Bounded Coordinate Walker: V3.11 evaluated spikes against the rolling
28
- `current_ce`, causing a divergent walk that ruined chain10. Spikes are
29
- now strictly bounded against `best_ce`, allowing ridge-walking without
30
- exponential climbing.
31
- FIX 2 β€” True Greedy Pass: The secondary snap pass now sorts variables dynamically
32
- by their L9 residual impact, rather than blindly relying on the PSL file's
33
- lexical variable order.
34
  """
35
 
36
  import asyncio, time, random, math, threading, warnings
@@ -63,14 +52,14 @@ HUB_BUDGET_MULT = 2.0
63
  HUB_RESIDUAL_MULT = 2.0
64
  CONSENSUS_MAX_ITER = 8
65
  CONSENSUS_PATIENCE = 3
66
- NEAR_SOLVED_CE = 0.25
67
  HUB_DEGREE_RATIO = 0.6
68
  PERTURB_BASE_SCALE = 0.05
69
  CYCLE_WINDOW = 3
70
  MIN_HYP_FRAC = 0.15
71
  HC4_VOLUME_FLOOR = 0.20
72
  L9_CONTRIB_THRESHOLD = 1e-8
73
- N_PERTURB_RESTARTS = 4
74
  STRUCT_PROBE_COUNT = 5
75
  MERGE_WEIGHT_EXP = 2.0
76
  MIN_SWEEP_BUDGET = 40
@@ -258,7 +247,7 @@ def expand_psl(prog:PSLProgram) -> ExpandedProblem:
258
 
259
  def add_con(kind,expr,direction,scope="root",weight=1.0,branches=None):
260
  idx=len(constraints)
261
- constraints.append(Constraint(kind,expr,direction,weight,scope,branches or[]))
262
  scope_groups[scope].append(idx)
263
  try:
264
  syms={v:sp.Symbol(v) for v in variables}
@@ -328,11 +317,9 @@ def expand_psl(prog:PSLProgram) -> ExpandedProblem:
328
  return ExpandedProblem(variables,bounds,constraints, dict(scope_groups),dict(scope_vars),scope_order)
329
 
330
  # ══════════════════════════════════════════════════════════════════════════
331
- # SECTION 4: PROBLEM DEFINITION (WITH ALGEBRAIC CACHING)
332
  # ══════════════════════════════════════════════════════════════════════════
333
 
334
- PROJECTION_CACHE: Dict[str, Dict[str, List[Dict]]] = {}
335
-
336
  @dataclass
337
  class Constraint:
338
  kind:str; expr:str; direction:str; weight:float=1.0; scope:str="root"
@@ -343,11 +330,11 @@ class MathConstraint:
343
  kind:str; expr_str:str; direction:str; weight:float=1.0
344
  fast_iv:Optional[Callable]=field(default=None,repr=False)
345
  fast_pt:Optional[Callable]=field(default=None,repr=False)
 
346
  syms_used:List[str]=field(default_factory=list)
347
  parsed:Optional[sp.Expr]=field(default=None,repr=False)
348
  degree:int=1; scope:str="root"
349
  branches:List['MathConstraint']=field(default_factory=list)
350
- projections:Dict[str,List[Dict]]=field(default_factory=dict)
351
 
352
  def compile_mc(kind,expr_str,direction,variables,weight=1.0,scope="root",branches=None):
353
  mc=MathConstraint(kind=kind,expr_str=expr_str,direction=direction,weight=weight,scope=scope)
@@ -373,25 +360,14 @@ def compile_mc(kind,expr_str,direction,variables,weight=1.0,scope="root",branche
373
  parsed=parse_expr(expr_str,local_dict=syms); mc.parsed=parsed
374
  mc.syms_used=[v for v in variables if sp.Symbol(v) in parsed.free_symbols]
375
  mc.fast_iv=compile_iv(parsed,variables)
376
- mc.fast_pt=sp.lambdify([sp.Symbol(v) for v in mc.syms_used], parsed,modules="math")
377
- mc.degree=int(sp.total_degree(parsed)) if parsed.is_polynomial() else 1
378
 
379
- if kind == "equality":
380
- if expr_str not in PROJECTION_CACHE:
381
- proj_map = {}
382
- for sym in parsed.free_symbols:
383
- v_str = str(sym)
384
- try:
385
- sols = sp.solve(parsed, sym)
386
- if v_str not in proj_map: proj_map[v_str] =[]
387
- for sol in sols:
388
- free_syms = list(sol.free_symbols)
389
- func = sp.lambdify(free_syms, sol, modules="math")
390
- proj_map[v_str].append({"syms": [str(s) for s in free_syms], "func": func})
391
- except: pass
392
- PROJECTION_CACHE[expr_str] = proj_map
393
- mc.projections = PROJECTION_CACHE.get(expr_str, {})
394
-
395
  except: pass
396
  return mc
397
 
@@ -435,6 +411,48 @@ class Problem:
435
  bv=b.get(v,0.0)
436
  total+=max(0.0,lo-bv)+max(0.0,bv-hi)
437
  return total
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
 
439
  def make_sub_problem(self,scope_name,transferred_bounds=None):
440
  cidxs=self.scope_groups.get(scope_name,[])
@@ -615,138 +633,6 @@ def _global_hc4_tighten(problem:Problem) -> Dict[str,Tuple[float,float]]:
615
  if orig_vol > 0 and new_vol < orig_vol * HC4_VOLUME_FLOOR: return dict(problem.bounds)
616
  return {v:(max(problem.bounds[v][0], contracted[v].lo), min(problem.bounds[v][1], contracted[v].hi)) for v in problem.bounds if v in contracted}
617
 
618
- def _single_snap_pass(problem: Problem, current_binding: Dict[str, float], ordered_vars: List[str], current_ce: float, max_spike_ce: float) -> Tuple[Dict[str, float], float, bool]:
619
- # FIX 1: Max Spike CE is now strictly anchored to the absolute best CE of the pass, preventing divergent walks.
620
- l9 = RESIDUAL_ORACLE.evaluate(current_binding, problem,[])
621
- if not l9.dominant_exprs:
622
- return current_binding, current_ce, False
623
-
624
- for worst_expr in l9.dominant_exprs[:3]:
625
- target_mc = next((mc for mc in problem.compiled_constraints if mc.expr_str == worst_expr), None)
626
- if not target_mc:
627
- for mc in problem.compiled_constraints:
628
- if mc.kind == "or_eq":
629
- for bmc in mc.branches:
630
- if bmc.expr_str == worst_expr: target_mc = bmc; break
631
- if target_mc: break
632
-
633
- if not (target_mc and hasattr(target_mc, 'projections') and target_mc.projections):
634
- continue
635
-
636
- for v in ordered_vars:
637
- if v not in target_mc.projections: continue
638
- for proj in target_mc.projections[v]:
639
- test_binding = dict(current_binding)
640
- val = None
641
- try:
642
- args = [test_binding.get(s, 0.0) for s in proj["syms"]]
643
- val = float(proj["func"](*args))
644
- except (ValueError, TypeError):
645
- for s in proj["syms"]:
646
- lo, hi = problem.bounds.get(s, (-1e18, 1e18))
647
- mid = (lo + hi) / 2.0 if lo != -1e18 else 0.0
648
- test_binding[s] = test_binding.get(s, mid) * 0.9 + mid * 0.1
649
- try:
650
- args = [test_binding.get(s, 0.0) for s in proj["syms"]]
651
- val = float(proj["func"](*args))
652
- except: continue
653
-
654
- if val is None or not math.isfinite(val) or abs(val) > 1e6:
655
- continue
656
-
657
- lo, hi = problem.bounds.get(v, (-1e18, 1e18))
658
- if not (lo <= val <= hi): continue
659
-
660
- test_binding[v] = val
661
- new_ce = problem.constraint_energy(test_binding)
662
-
663
- # Check against the absolute bound, not the rolling CE
664
- if new_ce < max_spike_ce:
665
- return test_binding, new_ce, True
666
-
667
- return current_binding, current_ce, False
668
-
669
- def _algebraic_snap(problem: Problem, binding: Dict[str, float]) -> Tuple[Dict[str, float], float]:
670
- best_ce_overall = problem.constraint_energy(binding)
671
- best_binding_overall = dict(binding)
672
-
673
- active_scopes = [s for s in problem.scope_order if s != "root" and problem.scope_vars.get(s)]
674
- l7 = TOPOLOGY_ORACLE.evaluate(problem, active_scopes)
675
-
676
- # 1. Causal order pass
677
- ordered_vars =[]
678
- if l7.solve_order:
679
- for sn in l7.solve_order:
680
- for v in problem.scope_vars.get(sn,[]):
681
- if v not in ordered_vars: ordered_vars.append(v)
682
- for v in problem.variables:
683
- if v not in ordered_vars: ordered_vars.append(v)
684
-
685
- causal_b = dict(binding)
686
- causal_ce = best_ce_overall
687
- causal_best = best_ce_overall
688
- for _ in range(20):
689
- # FIX 1: Anchor the tolerance mathematically to the best known state
690
- max_allowable_spike = causal_best * 1.15
691
- causal_b, causal_ce, improved = _single_snap_pass(problem, causal_b, ordered_vars, causal_ce, max_allowable_spike)
692
- if improved and causal_ce < causal_best:
693
- causal_best = causal_ce
694
- if causal_ce < best_ce_overall:
695
- best_ce_overall = causal_ce
696
- best_binding_overall = dict(causal_b)
697
- if not improved or causal_ce < SOLVE_THRESHOLD: break
698
-
699
- # 2. FIX 2: True Greedy Pass. Prioritize variables causing the most error dynamically.
700
- greedy_b = dict(binding)
701
- greedy_ce = problem.constraint_energy(binding)
702
- greedy_best = greedy_ce
703
- for _ in range(20):
704
- l9 = RESIDUAL_ORACLE.evaluate(greedy_b, problem,[])
705
- dynamic_greedy_vars = l9.dominant_vars if l9.dominant_vars else problem.variables
706
- # Ensure all variables are included as fallbacks
707
- for v in problem.variables:
708
- if v not in dynamic_greedy_vars: dynamic_greedy_vars.append(v)
709
-
710
- max_allowable_spike = greedy_best * 1.15
711
- greedy_b, greedy_ce, improved = _single_snap_pass(problem, greedy_b, dynamic_greedy_vars, greedy_ce, max_allowable_spike)
712
- if improved and greedy_ce < greedy_best:
713
- greedy_best = greedy_ce
714
- if greedy_ce < best_ce_overall:
715
- best_ce_overall = greedy_ce
716
- best_binding_overall = dict(greedy_b)
717
- if not improved or greedy_ce < SOLVE_THRESHOLD: break
718
-
719
- return best_binding_overall, best_ce_overall
720
-
721
- def _normalisation_sweep(problem:Problem, binding:Dict[str,float], budget:int) -> Dict:
722
- snap_binding, snap_ce = _algebraic_snap(problem, binding)
723
- if snap_ce < SOLVE_THRESHOLD:
724
- return {"binding": snap_binding, "ce": snap_ce, "steps": 1, "hypothesis": "AlgebraicSnap"}
725
-
726
- span_box={}
727
- for v in problem.variables:
728
- lo,hi=problem.bounds[v]; cv=snap_binding.get(v,(lo+hi)/2)
729
- half=max(0.005,(hi-lo)*0.05)
730
- span_box[v]=IV(max(lo,cv-half),min(hi,cv+half))
731
- r=_solve_region(problem,span_box,budget)
732
- if r["ce"]>=snap_ce:
733
- wide_box={}
734
- for v in problem.variables:
735
- lo,hi=problem.bounds[v]; cv=snap_binding.get(v,(lo+hi)/2)
736
- half=(hi-lo)*0.15
737
- wide_box[v]=IV(max(lo,cv-half),min(hi,cv+half))
738
- r2=_solve_region(problem,wide_box,budget)
739
- if r2["ce"]<r["ce"]: r=r2
740
-
741
- if snap_ce < r["ce"]:
742
- r["binding"] = snap_binding; r["ce"] = snap_ce
743
- r["hypothesis"]="NormSweep"; return r
744
-
745
- def _is_norm_problem(problem:Problem) -> bool:
746
- for c in problem.constraints:
747
- if c.kind == "or_eq": return False
748
- return True
749
-
750
  def solve_ae(problem:Problem, budget:int=TOTAL_BUDGET, injected_seed:Dict[str,float]=None) -> Dict:
751
  t0=time.time()
752
  active_scopes=[s for s in problem.scope_order if s!="root" and len(problem.scope_vars.get(s,[]))>0]
@@ -763,9 +649,6 @@ def solve_ae(problem:Problem, budget:int=TOTAL_BUDGET, injected_seed:Dict[str,fl
763
  start_box={v:IV(lo,hi) for v,(lo,hi) in problem.bounds.items()}
764
  res=_solve_region(problem,start_box,budget)
765
  l9=RESIDUAL_ORACLE.evaluate(res["binding"],problem,[])
766
- if res["ce"]<10.0 and res["ce"]>SOLVE_THRESHOLD and _is_norm_problem(problem):
767
- nr=_normalisation_sweep(problem,res["binding"],max(MIN_SWEEP_BUDGET, budget//2))
768
- if nr["ce"]<res["ce"]: res=nr
769
  return {"binding":res["binding"],"ce":res["ce"],
770
  "solved":res["ce"]<SOLVE_THRESHOLD,"steps":res["steps"],
771
  "l7":None,"l9":l9,"time":round(time.time()-t0,3)}
@@ -826,17 +709,12 @@ def solve_ae(problem:Problem, budget:int=TOTAL_BUDGET, injected_seed:Dict[str,fl
826
  total_steps+=r["steps"]
827
  if r["ce"]<ce: composed_binding=r["binding"]; ce=r["ce"]
828
 
829
- if ce<10.0 and ce>SOLVE_THRESHOLD and _is_norm_problem(problem):
830
- nr=_normalisation_sweep(problem,composed_binding,max(MIN_SWEEP_BUDGET, budget//4))
831
- total_steps+=nr["steps"]
832
- if nr["ce"]<ce: composed_binding=nr["binding"]; ce=nr["ce"]
833
-
834
  return {"binding":composed_binding,"ce":ce,
835
  "solved":ce<SOLVE_THRESHOLD,"steps":total_steps,
836
  "l7":l7_cert,"l9":l9_cert,"time":round(time.time()-t0,3)}
837
 
838
  # ══════════════════════════════════════════════════════════════════════════
839
- # SECTION 7: AE2 HYPOTHESIS GENERATORS
840
  # ══════════════════════════════════════════════════════════════════════════
841
 
842
  def _hypothesis_seed(problem:Problem, budget:int, current_binding:Dict[str,float], round_idx:int=0) -> Dict:
@@ -910,44 +788,91 @@ def _hypothesis_struct(problem:Problem, budget:int, current_binding:Dict[str,flo
910
  best_result["hypothesis"]=f"Struct:freeze({target_hub}@{hv:.2f})"
911
  return best_result
912
 
913
- def _hypothesis_perturb(problem:Problem, budget:int, current_binding:Dict[str,float], stale_rounds:int=0) -> Dict:
914
- scale=PERTURB_BASE_SCALE*(1+stale_rounds)
915
- per_budget=max(10,budget//N_PERTURB_RESTARTS)
916
- best_result=None
917
- for _ in range(N_PERTURB_RESTARTS):
918
- perturbed={}
919
- for v,val in current_binding.items():
920
- lo,hi=problem.bounds[v]
921
- noise=random.gauss(0,scale*(hi-lo))
922
- perturbed[v]=max(lo,min(hi,val+noise))
923
- r=solve_ae(problem,per_budget,injected_seed=perturbed)
924
- if best_result is None or r["ce"]<best_result["ce"]: best_result=r
925
- best_result["hypothesis"]=f"Perturb:Οƒ={scale:.3f}Γ—{N_PERTURB_RESTARTS}"
926
- return best_result
927
-
928
- def _local_refine(problem:Problem, budget:int, binding:Dict[str,float]) -> Dict:
929
- snap_binding, snap_ce = _algebraic_snap(problem, binding)
930
- if snap_ce < SOLVE_THRESHOLD:
931
- return {"binding": snap_binding, "ce": snap_ce, "steps": 1, "hypothesis": "AlgebraicSnap"}
932
 
933
- tight_box={}
934
- for v in problem.variables:
935
- lo,hi=problem.bounds[v]; cv=snap_binding.get(v,(lo+hi)/2)
936
- half=(hi-lo)*0.02
937
- tight_box[v]=IV(max(lo,cv-half),min(hi,cv+half))
938
- r=_solve_region(problem,tight_box,max(MIN_SWEEP_BUDGET, budget))
 
 
 
 
 
 
 
 
 
 
 
939
 
940
- if r["ce"]>=snap_ce:
941
- wide_box={v:IV(max(problem.bounds[v][0], snap_binding.get(v,0)-(problem.bounds[v][1]-problem.bounds[v][0])*0.10),
942
- min(problem.bounds[v][1], snap_binding.get(v,0)+(problem.bounds[v][1]-problem.bounds[v][0])*0.10))
943
- for v in problem.variables}
944
- r2=_solve_region(problem,wide_box,max(MIN_SWEEP_BUDGET, budget))
945
- if r2["ce"]<r["ce"]: r=r2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
946
 
947
- if snap_ce < r["ce"]:
948
- r["binding"] = snap_binding; r["ce"] = snap_ce
 
 
 
 
 
 
 
 
 
 
 
 
 
949
 
950
- r["hypothesis"]="LocalRefine"; return r
 
 
 
 
 
 
 
 
 
 
 
 
 
 
951
 
952
  def _merge_bindings(problem:Problem, b1:Dict[str,float], ce1:float, b2:Dict[str,float], ce2:float, budget:int) -> Dict:
953
  w1=1.0/(ce1**MERGE_WEIGHT_EXP+1e-12); w2=1.0/(ce2**MERGE_WEIGHT_EXP+1e-12); wt=w1+w2
@@ -955,22 +880,14 @@ def _merge_bindings(problem:Problem, b1:Dict[str,float], ce1:float, b2:Dict[str,
955
  for v,(lo,hi) in problem.bounds.items(): merged[v]=max(lo,min(hi,merged[v]))
956
 
957
  r=solve_ae(problem,budget,injected_seed=merged)
958
-
959
- if r["ce"] < 10.0 and _is_norm_problem(problem):
960
- nr = _normalisation_sweep(problem, r["binding"], max(MIN_SWEEP_BUDGET, budget))
961
- if nr["ce"] < r["ce"]:
962
- r["binding"] = nr["binding"]
963
- r["ce"] = nr["ce"]
964
- r["steps"] += nr["steps"]
965
-
966
  r["hypothesis"]=f"Merge:w={w1/wt:.2f}/{w2/wt:.2f}"
967
  return r
968
 
969
  # ══════════════════════════════════════════════════════════════════════════
970
- # SECTION 8: CONSENSUS ENGINE
971
  # ══════════════════════════════════════════════════════════════════════════
972
 
973
- def solve_consensus(problem:Problem, budget:int=TOTAL_BUDGET, budget_split:Tuple[float,float,float]=(0.34,0.33,0.33)) -> Dict:
974
  t0=time.time()
975
  round_budget=max(30,budget//(CONSENSUS_MAX_ITER+1))
976
 
@@ -987,14 +904,15 @@ def solve_consensus(problem:Problem, budget:int=TOTAL_BUDGET, budget_split:Tuple
987
  state["consensus_rounds"]=0; state["consensus_history"]=[]
988
  return state
989
 
990
- seed_f, struct_f, perturb_f = budget_split
991
 
992
  for round_idx in range(CONSENSUS_MAX_ITER):
993
- if current_ce<NEAR_SOLVED_CE:
994
- r=_local_refine(problem,round_budget,current_binding)
995
- total_steps+=r["steps"]
996
- history.append({"round":round_idx+1,"mode":"refine","seed_ce":None,"struct_ce":None,"perturb_ce":None,
997
- "winner":"refine","ce":round(r["ce"],5),"seed_h":"","struct_h":"","perturb_h":r.get("hypothesis","")})
 
998
  if r["ce"]<global_best_ce:
999
  global_best_ce=r["ce"]; global_best_binding=dict(r["binding"])
1000
  current_ce=r["ce"]; current_binding=r["binding"]
@@ -1006,25 +924,28 @@ def solve_consensus(problem:Problem, budget:int=TOTAL_BUDGET, budget_split:Tuple
1006
 
1007
  seed_b = max(10, int(round_budget * seed_f))
1008
  struct_b = max(10, int(round_budget * struct_f))
1009
- perturb_b = max(10, round_budget - seed_b - struct_b)
1010
 
1011
  if force_perturb:
1012
- p_res=_hypothesis_perturb(problem,round_budget,current_binding,stale_rounds+2)
1013
- total_steps+=p_res["steps"]
1014
- candidates=[("current",current_ce,current_binding), ("perturb",p_res["ce"],p_res["binding"])]
1015
- mode="force_perturb"; s_res=t_res={"ce":None,"hypothesis":"–","steps":0,"binding":{}}
1016
  merge_res=None
1017
  else:
1018
- s_res =_hypothesis_seed(problem, seed_b, current_binding, round_idx)
1019
- t_res =_hypothesis_struct(problem, struct_b, s_res["binding"], round_idx)
1020
- p_res =_hypothesis_perturb(problem, perturb_b, current_binding, stale_rounds)
1021
- total_steps+=s_res["steps"]+t_res["steps"]+p_res["steps"]
 
 
1022
 
1023
  candidates=[
1024
  ("current", current_ce, current_binding),
1025
  ("seed", s_res["ce"], s_res["binding"]),
1026
  ("struct", t_res["ce"], t_res["binding"]),
1027
- ("perturb", p_res["ce"], p_res["binding"]),
 
1028
  ]
1029
  mode="debate"
1030
 
@@ -1046,10 +967,11 @@ def solve_consensus(problem:Problem, budget:int=TOTAL_BUDGET, budget_split:Tuple
1046
  history.append({"round": round_idx+1, "mode": mode,
1047
  "seed_ce": round(s_res["ce"],5) if s_res["ce"] is not None else None,
1048
  "struct_ce": round(t_res["ce"],5) if t_res["ce"] is not None else None,
1049
- "perturb_ce":round(p_res["ce"],5) if p_res["ce"] is not None else None,
 
1050
  "merge_ce": round(merge_res["ce"],5) if merge_res else None,
1051
  "winner": winner_name, "ce": round(winner_ce,5),
1052
- "seed_h": s_res.get("hypothesis",""), "struct_h": t_res.get("hypothesis",""), "perturb_h": p_res.get("hypothesis",""),
1053
  })
1054
 
1055
  current_ce=winner_ce; current_binding=winner_bind
@@ -1232,13 +1154,13 @@ EMPIRICAL_DATA:Dict={
1232
  "by_pid": defaultdict(_empty_prob_stats)
1233
  }
1234
 
1235
- DEBATE_WINS={"seed":1,"struct":1,"perturb":1,"refine":1,"merge":1}
1236
  INJECTED_SEEDS:Dict[str,Dict[str,float]]={}
1237
 
1238
- def _adaptive_budget_split() -> Tuple[float,float,float]:
1239
- s=DEBATE_WINS["seed"]; t=DEBATE_WINS["struct"]; p=DEBATE_WINS["perturb"]
1240
- total=s+t+p
1241
- raw=(s/total, t/total, p/total)
1242
  floored=[max(MIN_HYP_FRAC,r) for r in raw]
1243
  fsum=sum(floored)
1244
  return tuple(f/fsum for f in floored)
@@ -1300,7 +1222,7 @@ async def lifespan(app: FastAPI):
1300
  yield
1301
  POOL.shutdown(wait=False)
1302
 
1303
- app = FastAPI(title="Practicality System 3.12", lifespan=lifespan)
1304
 
1305
  @app.post("/inject/{pid}")
1306
  async def inject_seed(pid:str, request:Request):
@@ -1332,8 +1254,8 @@ async def dashboard():
1332
  con=d["Consensus"]
1333
  avg_rounds=round(con["rounds"]/runs,2)
1334
  history=con["history"]; debate_rows=""
1335
- col_map={"seed":"#4CAF50","struct":"#FF9800","perturb":"#E040FB",
1336
- "refine":"#26C6DA","merge":"#FFD700","current":"#555","force_perturb":"#FF5252"}
1337
 
1338
  for h in reversed(history):
1339
  wc=col_map.get(h["winner"],"#888")
@@ -1346,12 +1268,14 @@ async def dashboard():
1346
  f"<td style='color:{mc};font-size:0.8em'>{h['mode']}</td>"
1347
  +ce_cell(h['seed_ce'], '#4CAF50')
1348
  +ce_cell(h['struct_ce'], '#FF9800')
1349
- +ce_cell(h['perturb_ce'], '#E040FB')
 
1350
  +ce_cell(h.get('merge_ce'),'#FFD700')
1351
  +f"<td style='color:{wc};font-weight:bold'>{h['winner']}</td>"
1352
- f"<td style='color:#888;font-size:0.75em'>{h.get('seed_h','')[:18]}</td>"
1353
- f"<td style='color:#888;font-size:0.75em'>{h.get('struct_h','')[:18]}</td>"
1354
- f"<td style='color:#888;font-size:0.75em'>{h.get('perturb_h','')[:18]}</td>"
 
1355
  f"</tr>")
1356
 
1357
  prob_rows = ""
@@ -1375,7 +1299,7 @@ async def dashboard():
1375
  f"font-size:0.85em;margin:2px'>{label}: {val}</span>")
1376
 
1377
  html=f"""<!DOCTYPE html><html>
1378
- <head><title>Practicality System 3.12</title>
1379
  <meta http-equiv="refresh" content="3">
1380
  <style>
1381
  body{{background:#0a0a0a;color:#e0e0e0;font-family:monospace;padding:20px}}
@@ -1386,7 +1310,7 @@ async def dashboard():
1386
  th{{color:#444}}
1387
  .witness-box{{background:#111; border:1px solid #333; padding:15px; color:#aaa; white-space:pre-wrap; font-size:0.9em;}}
1388
  </style></head><body>
1389
- <h1>βš— Practicality System 3.12</h1>
1390
  <div style='margin-bottom:16px;line-height:2.2em;'>
1391
  {badge("Trials",runs,"#aaa")}
1392
  {badge("Avg rounds",avg_rounds,"#aaa")}
@@ -1395,13 +1319,14 @@ async def dashboard():
1395
  <br>
1396
  {badge("Seed wins", wins['seed'], '#4CAF50')}
1397
  {badge("Struct wins", wins['struct'], '#FF9800')}
1398
- {badge("Perturb wins",wins['perturb'],'#E040FB')}
1399
- {badge("Refine wins", wins['refine'], '#26C6DA')}
1400
  {badge("Merge wins", wins['merge'], '#FFD700')}
1401
  <br>
1402
  {badge("Seed bdgt", f"{split[0]:.0%}",'#4CAF50')}
1403
  {badge("Struct bdgt", f"{split[1]:.0%}",'#FF9800')}
1404
- {badge("Perturb bdgt",f"{split[2]:.0%}",'#E040FB')}
 
1405
  </div>
1406
  <table>
1407
  <tr><th>Strategy</th><th>Solve Rate</th><th>Avg CE</th><th>Avg Time</th></tr>
@@ -1418,11 +1343,12 @@ async def dashboard():
1418
  <tr><th>Prob/Round</th><th>Mode</th>
1419
  <th style='color:#4CAF50'>Seed</th>
1420
  <th style='color:#FF9800'>Struct</th>
1421
- <th style='color:#E040FB'>Perturb</th>
 
1422
  <th style='color:#FFD700'>Merge</th>
1423
  <th>Winner</th>
1424
- <th>Seed hyp</th><th>Struct hyp</th><th>Perturb hyp</th></tr>
1425
- {debate_rows or "<tr><td colspan='10' style='color:#333'>Warming up…</td></tr>"}
1426
  </table>
1427
 
1428
  <h3>Latest LLM Bridge Export (Universal Witness)</h3>
 
1
  #!/usr/bin/env python3
2
  """
3
+ PRACTICALITY SYSTEM 4.0
4
+ ═══════════════════════════════════════════════════════════════════
5
+ THE VECTORIZED DIAL SYSTEM
6
+
7
+ Changes from 3.12:
8
+ NEW 1 β€” Tensorized Permutations: The engine now compiles SymPy ASTs into
9
+ pure Numpy ufuncs. `Perturb` no longer loops over 4 single hypotheses;
10
+ it generates a continuous float32 tensor of 1,000 parallel dimensions
11
+ and evaluates them simultaneously in a single SIMD clock cycle.
12
+
13
+ NEW 2 β€” The Gradient Dial: Introduced a multi-variable Finite-Difference
14
+ Gradient Descent hypothesis. To prevent "greedy bias" and mode collapse,
15
+ it does not override the system. It competes in the consensus debate
16
+ against the Vectorized Permutations. If the gradient gets stuck in a
17
+ local minimum, the dial dynamically shifts budget back to stochastic
18
+ sampling to blast it out.
19
+
20
+ FIX 1 β€” Replaced Algebraic Sniper with Gradient Refine: Removed the highly
21
+ unstable single-variable algebraic snap (which oscillated on fully10
22
+ and spiked on chain10) in favor of the controlled multi-variable dial.
 
 
 
 
 
 
 
 
 
 
 
23
  """
24
 
25
  import asyncio, time, random, math, threading, warnings
 
52
  HUB_RESIDUAL_MULT = 2.0
53
  CONSENSUS_MAX_ITER = 8
54
  CONSENSUS_PATIENCE = 3
55
+ NEAR_SOLVED_CE = 0.50 # Dial engages refinement earlier
56
  HUB_DEGREE_RATIO = 0.6
57
  PERTURB_BASE_SCALE = 0.05
58
  CYCLE_WINDOW = 3
59
  MIN_HYP_FRAC = 0.15
60
  HC4_VOLUME_FLOOR = 0.20
61
  L9_CONTRIB_THRESHOLD = 1e-8
62
+ N_TENSOR_PERMUTES = 1000 # V4.0: 1,000 parallel tensor evaluations per perturb
63
  STRUCT_PROBE_COUNT = 5
64
  MERGE_WEIGHT_EXP = 2.0
65
  MIN_SWEEP_BUDGET = 40
 
247
 
248
  def add_con(kind,expr,direction,scope="root",weight=1.0,branches=None):
249
  idx=len(constraints)
250
+ constraints.append(Constraint(kind,expr,direction,weight,scope,branches or []))
251
  scope_groups[scope].append(idx)
252
  try:
253
  syms={v:sp.Symbol(v) for v in variables}
 
317
  return ExpandedProblem(variables,bounds,constraints, dict(scope_groups),dict(scope_vars),scope_order)
318
 
319
  # ══════════════════════════════════════════════════════════════════════════
320
+ # SECTION 4: PROBLEM DEFINITION (WITH NUMPY COMPILATION)
321
  # ══════════════════════════════════════════════════════════════════════════
322
 
 
 
323
  @dataclass
324
  class Constraint:
325
  kind:str; expr:str; direction:str; weight:float=1.0; scope:str="root"
 
330
  kind:str; expr_str:str; direction:str; weight:float=1.0
331
  fast_iv:Optional[Callable]=field(default=None,repr=False)
332
  fast_pt:Optional[Callable]=field(default=None,repr=False)
333
+ fast_np:Optional[Callable]=field(default=None,repr=False) # V4.0 Vectorized Evaluator
334
  syms_used:List[str]=field(default_factory=list)
335
  parsed:Optional[sp.Expr]=field(default=None,repr=False)
336
  degree:int=1; scope:str="root"
337
  branches:List['MathConstraint']=field(default_factory=list)
 
338
 
339
  def compile_mc(kind,expr_str,direction,variables,weight=1.0,scope="root",branches=None):
340
  mc=MathConstraint(kind=kind,expr_str=expr_str,direction=direction,weight=weight,scope=scope)
 
360
  parsed=parse_expr(expr_str,local_dict=syms); mc.parsed=parsed
361
  mc.syms_used=[v for v in variables if sp.Symbol(v) in parsed.free_symbols]
362
  mc.fast_iv=compile_iv(parsed,variables)
 
 
363
 
364
+ # Compile standard Math backend for scalars
365
+ mc.fast_pt=sp.lambdify([sp.Symbol(v) for v in mc.syms_used], parsed, modules="math")
366
+
367
+ # Compile Numpy backend for tensors (V4.0 SIMD Evaluation)
368
+ mc.fast_np=sp.lambdify([sp.Symbol(v) for v in mc.syms_used], parsed, modules="numpy")
369
+
370
+ mc.degree=int(sp.total_degree(parsed)) if parsed.is_polynomial() else 1
 
 
 
 
 
 
 
 
 
371
  except: pass
372
  return mc
373
 
 
411
  bv=b.get(v,0.0)
412
  total+=max(0.0,lo-bv)+max(0.0,bv-hi)
413
  return total
414
+
415
+ def constraint_energy_tensor(self, b_matrix: np.ndarray, var_order: List[str]) -> np.ndarray:
416
+ """
417
+ V4.0: Evaluates thousands of permutations simultaneously using Numpy ufuncs.
418
+ b_matrix shape: (N_permutations, N_variables)
419
+ Returns shape: (N_permutations,)
420
+ """
421
+ N = b_matrix.shape[0]
422
+ total = np.zeros(N, dtype=np.float32)
423
+ var_to_idx = {v: i for i, v in enumerate(var_order)}
424
+
425
+ for mc in self.compiled_constraints:
426
+ if mc.kind == "or_eq":
427
+ branch_vals =[]
428
+ for bmc in mc.branches:
429
+ if bmc.fast_np:
430
+ try:
431
+ args = [b_matrix[:, var_to_idx[v]] for v in bmc.syms_used]
432
+ val = np.abs(bmc.fast_np(*args))
433
+ branch_vals.append(val)
434
+ except: pass
435
+ if branch_vals:
436
+ min_vals = np.minimum.reduce(branch_vals)
437
+ total += min_vals * mc.weight
438
+ else: total += 1.0
439
+ else:
440
+ if mc.fast_np is None:
441
+ total += 1.0; continue
442
+ try:
443
+ args = [b_matrix[:, var_to_idx[v]] for v in mc.syms_used]
444
+ val = bmc.fast_np(*args) if hasattr(bmc, 'fast_np') else mc.fast_np(*args)
445
+ if mc.kind == "equality": total += np.abs(val) * mc.weight
446
+ elif mc.direction == "geq": total += np.maximum(0.0, -val) * mc.weight
447
+ else: total += np.maximum(0.0, val) * mc.weight
448
+ except: total += 1.0
449
+
450
+ for i, v in enumerate(var_order):
451
+ lo, hi = self.bounds[v]
452
+ col = b_matrix[:, i]
453
+ total += np.maximum(0.0, lo - col) + np.maximum(0.0, col - hi)
454
+
455
+ return total
456
 
457
  def make_sub_problem(self,scope_name,transferred_bounds=None):
458
  cidxs=self.scope_groups.get(scope_name,[])
 
633
  if orig_vol > 0 and new_vol < orig_vol * HC4_VOLUME_FLOOR: return dict(problem.bounds)
634
  return {v:(max(problem.bounds[v][0], contracted[v].lo), min(problem.bounds[v][1], contracted[v].hi)) for v in problem.bounds if v in contracted}
635
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
  def solve_ae(problem:Problem, budget:int=TOTAL_BUDGET, injected_seed:Dict[str,float]=None) -> Dict:
637
  t0=time.time()
638
  active_scopes=[s for s in problem.scope_order if s!="root" and len(problem.scope_vars.get(s,[]))>0]
 
649
  start_box={v:IV(lo,hi) for v,(lo,hi) in problem.bounds.items()}
650
  res=_solve_region(problem,start_box,budget)
651
  l9=RESIDUAL_ORACLE.evaluate(res["binding"],problem,[])
 
 
 
652
  return {"binding":res["binding"],"ce":res["ce"],
653
  "solved":res["ce"]<SOLVE_THRESHOLD,"steps":res["steps"],
654
  "l7":None,"l9":l9,"time":round(time.time()-t0,3)}
 
709
  total_steps+=r["steps"]
710
  if r["ce"]<ce: composed_binding=r["binding"]; ce=r["ce"]
711
 
 
 
 
 
 
712
  return {"binding":composed_binding,"ce":ce,
713
  "solved":ce<SOLVE_THRESHOLD,"steps":total_steps,
714
  "l7":l7_cert,"l9":l9_cert,"time":round(time.time()-t0,3)}
715
 
716
  # ══════════════════════════════════════════════════════════════════════════
717
+ # SECTION 7: HYPOTHESIS GENERATORS (THE VECTORIZED DIAL)
718
  # ══════════════════════════════════════════════════════════════════════════
719
 
720
  def _hypothesis_seed(problem:Problem, budget:int, current_binding:Dict[str,float], round_idx:int=0) -> Dict:
 
788
  best_result["hypothesis"]=f"Struct:freeze({target_hub}@{hv:.2f})"
789
  return best_result
790
 
791
+ def _hypothesis_vector_perturb(problem:Problem, current_binding:Dict[str,float], stale_rounds:int=0) -> Dict:
792
+ """
793
+ NEW 1: The Vectorized Permutation Bomb.
794
+ Generates N_TENSOR_PERMUTES hypotheses in a continuous Numpy tensor,
795
+ evaluates them simultaneously, and returns the absolute best.
796
+ """
797
+ scale = PERTURB_BASE_SCALE * (1 + stale_rounds)
798
+ N = N_TENSOR_PERMUTES
799
+ V = len(problem.variables)
800
+
801
+ # Generate [N, V] tensor of base coordinates
802
+ base_matrix = np.zeros((N, V), dtype=np.float32)
803
+ for i, v in enumerate(problem.variables):
804
+ base_matrix[:, i] = current_binding.get(v, 0.0)
 
 
 
 
 
805
 
806
+ # Generate [N, V] tensor of perturbations
807
+ noise_matrix = np.zeros((N, V), dtype=np.float32)
808
+ for i, v in enumerate(problem.variables):
809
+ lo, hi = problem.bounds[v]
810
+ noise_matrix[:, i] = np.random.normal(0, scale * (hi - lo), N)
811
+
812
+ # Apply noise and clip to bounds
813
+ test_matrix = base_matrix + noise_matrix
814
+ for i, v in enumerate(problem.variables):
815
+ lo, hi = problem.bounds[v]
816
+ test_matrix[:, i] = np.clip(test_matrix[:, i], lo, hi)
817
+
818
+ # Vectorized CE Evaluation
819
+ ce_vector = problem.constraint_energy_tensor(test_matrix, problem.variables)
820
+
821
+ best_idx = np.argmin(ce_vector)
822
+ best_ce = float(ce_vector[best_idx])
823
 
824
+ best_binding = {v: float(test_matrix[best_idx, i]) for i, v in enumerate(problem.variables)}
825
+
826
+ # Run the single best point through the standard region solver to stabilize it
827
+ return solve_ae(problem, budget=max(10, TOTAL_BUDGET//4), injected_seed=best_binding)
828
+
829
+
830
+ def _hypothesis_gradient_refine(problem: Problem, budget: int, binding: Dict[str, float]) -> Dict:
831
+ """
832
+ NEW 2: The Gradient Dial.
833
+ Competes in the Debate Engine. If it falls into a local minimum "greedy" trap,
834
+ it will be mathematically defeated by the Vectorized Permutation Engine and
835
+ lose its budget allocation.
836
+ """
837
+ b = dict(binding)
838
+ best_ce = problem.constraint_energy(b)
839
+
840
+ steps_taken = 0
841
+ for _ in range(50):
842
+ if best_ce < SOLVE_THRESHOLD: break
843
+ steps_taken += 1
844
 
845
+ grad = {}
846
+ for v in problem.variables:
847
+ lo, hi = problem.bounds[v]
848
+ eps = max(1e-7, (hi - lo) * 1e-5)
849
+
850
+ b_plus = dict(b); b_plus[v] += eps
851
+ b_minus = dict(b); b_minus[v] -= eps
852
+
853
+ cp = problem.constraint_energy(b_plus)
854
+ cm = problem.constraint_energy(b_minus)
855
+
856
+ grad[v] = (cp - cm) / (2 * eps)
857
+
858
+ grad_mag_sq = sum(g**2 for g in grad.values())
859
+ if grad_mag_sq < 1e-12: break
860
 
861
+ lr = min(0.1, best_ce / grad_mag_sq)
862
+
863
+ next_b = {}
864
+ for v in problem.variables:
865
+ lo, hi = problem.bounds[v]
866
+ next_b[v] = max(lo, min(hi, b[v] - lr * grad[v]))
867
+
868
+ next_ce = problem.constraint_energy(next_b)
869
+
870
+ if next_ce >= best_ce: break
871
+ best_ce = next_ce
872
+ b = dict(next_b)
873
+
874
+ return {"binding": b, "ce": best_ce, "steps": steps_taken, "hypothesis": "GradientRefine"}
875
+
876
 
877
  def _merge_bindings(problem:Problem, b1:Dict[str,float], ce1:float, b2:Dict[str,float], ce2:float, budget:int) -> Dict:
878
  w1=1.0/(ce1**MERGE_WEIGHT_EXP+1e-12); w2=1.0/(ce2**MERGE_WEIGHT_EXP+1e-12); wt=w1+w2
 
880
  for v,(lo,hi) in problem.bounds.items(): merged[v]=max(lo,min(hi,merged[v]))
881
 
882
  r=solve_ae(problem,budget,injected_seed=merged)
 
 
 
 
 
 
 
 
883
  r["hypothesis"]=f"Merge:w={w1/wt:.2f}/{w2/wt:.2f}"
884
  return r
885
 
886
  # ══════════════════════════════════════════════════════════════════════════
887
+ # SECTION 8: CONSENSUS ENGINE (THE 4-WAY DIAL)
888
  # ══════════════════════════════════════════════════════════════════════════
889
 
890
+ def solve_consensus(problem:Problem, budget:int=TOTAL_BUDGET, budget_split:Tuple[float,float,float,float]=(0.25,0.25,0.25,0.25)) -> Dict:
891
  t0=time.time()
892
  round_budget=max(30,budget//(CONSENSUS_MAX_ITER+1))
893
 
 
904
  state["consensus_rounds"]=0; state["consensus_history"]=[]
905
  return state
906
 
907
+ seed_f, struct_f, vec_f, grad_f = budget_split
908
 
909
  for round_idx in range(CONSENSUS_MAX_ITER):
910
+ # NEW: The Dial allows the Gradient step to fire earlier
911
+ if current_ce < NEAR_SOLVED_CE:
912
+ r = _hypothesis_gradient_refine(problem, round_budget, current_binding)
913
+ total_steps += r["steps"]
914
+ history.append({"round":round_idx+1,"mode":"refine","seed_ce":None,"struct_ce":None,"vec_ce":None,"grad_ce":None,
915
+ "winner":"refine","ce":round(r["ce"],5),"seed_h":"","struct_h":"","vec_h":"","grad_h":r.get("hypothesis","")})
916
  if r["ce"]<global_best_ce:
917
  global_best_ce=r["ce"]; global_best_binding=dict(r["binding"])
918
  current_ce=r["ce"]; current_binding=r["binding"]
 
924
 
925
  seed_b = max(10, int(round_budget * seed_f))
926
  struct_b = max(10, int(round_budget * struct_f))
927
+ grad_b = max(10, int(round_budget * grad_f))
928
 
929
  if force_perturb:
930
+ p_res = _hypothesis_vector_perturb(problem, current_binding, stale_rounds+2)
931
+ total_steps += p_res["steps"]
932
+ candidates = [("current",current_ce,current_binding), ("vector",p_res["ce"],p_res["binding"])]
933
+ mode="force_perturb"; s_res=t_res=g_res={"ce":None,"hypothesis":"–","steps":0,"binding":{}}
934
  merge_res=None
935
  else:
936
+ s_res = _hypothesis_seed(problem, seed_b, current_binding, round_idx)
937
+ t_res = _hypothesis_struct(problem, struct_b, s_res["binding"], round_idx)
938
+ g_res = _hypothesis_gradient_refine(problem, grad_b, current_binding)
939
+ p_res = _hypothesis_vector_perturb(problem, current_binding, stale_rounds)
940
+
941
+ total_steps += s_res["steps"] + t_res["steps"] + p_res["steps"] + g_res["steps"]
942
 
943
  candidates=[
944
  ("current", current_ce, current_binding),
945
  ("seed", s_res["ce"], s_res["binding"]),
946
  ("struct", t_res["ce"], t_res["binding"]),
947
+ ("vector", p_res["ce"], p_res["binding"]),
948
+ ("gradient",g_res["ce"], g_res["binding"]),
949
  ]
950
  mode="debate"
951
 
 
967
  history.append({"round": round_idx+1, "mode": mode,
968
  "seed_ce": round(s_res["ce"],5) if s_res["ce"] is not None else None,
969
  "struct_ce": round(t_res["ce"],5) if t_res["ce"] is not None else None,
970
+ "vec_ce": round(p_res["ce"],5) if p_res["ce"] is not None else None,
971
+ "grad_ce": round(g_res["ce"],5) if g_res["ce"] is not None else None,
972
  "merge_ce": round(merge_res["ce"],5) if merge_res else None,
973
  "winner": winner_name, "ce": round(winner_ce,5),
974
+ "seed_h": s_res.get("hypothesis",""), "struct_h": t_res.get("hypothesis",""), "vec_h": "Vector[1000]", "grad_h": g_res.get("hypothesis","")
975
  })
976
 
977
  current_ce=winner_ce; current_binding=winner_bind
 
1154
  "by_pid": defaultdict(_empty_prob_stats)
1155
  }
1156
 
1157
+ DEBATE_WINS={"seed":1,"struct":1,"vector":1,"gradient":1,"merge":1}
1158
  INJECTED_SEEDS:Dict[str,Dict[str,float]]={}
1159
 
1160
+ def _adaptive_budget_split() -> Tuple[float,float,float,float]:
1161
+ s=DEBATE_WINS["seed"]; t=DEBATE_WINS["struct"]; v=DEBATE_WINS["vector"]; g=DEBATE_WINS["gradient"]
1162
+ total=s+t+v+g
1163
+ raw=(s/total, t/total, v/total, g/total)
1164
  floored=[max(MIN_HYP_FRAC,r) for r in raw]
1165
  fsum=sum(floored)
1166
  return tuple(f/fsum for f in floored)
 
1222
  yield
1223
  POOL.shutdown(wait=False)
1224
 
1225
+ app = FastAPI(title="Practicality System 4.0", lifespan=lifespan)
1226
 
1227
  @app.post("/inject/{pid}")
1228
  async def inject_seed(pid:str, request:Request):
 
1254
  con=d["Consensus"]
1255
  avg_rounds=round(con["rounds"]/runs,2)
1256
  history=con["history"]; debate_rows=""
1257
+ col_map={"seed":"#4CAF50","struct":"#FF9800","vector":"#E040FB",
1258
+ "gradient":"#26C6DA","refine":"#26C6DA","merge":"#FFD700","current":"#555","force_perturb":"#FF5252"}
1259
 
1260
  for h in reversed(history):
1261
  wc=col_map.get(h["winner"],"#888")
 
1268
  f"<td style='color:{mc};font-size:0.8em'>{h['mode']}</td>"
1269
  +ce_cell(h['seed_ce'], '#4CAF50')
1270
  +ce_cell(h['struct_ce'], '#FF9800')
1271
+ +ce_cell(h.get('vec_ce'),'#E040FB')
1272
+ +ce_cell(h.get('grad_ce'),'#26C6DA')
1273
  +ce_cell(h.get('merge_ce'),'#FFD700')
1274
  +f"<td style='color:{wc};font-weight:bold'>{h['winner']}</td>"
1275
+ f"<td style='color:#888;font-size:0.75em'>{h.get('seed_h','')[:15]}</td>"
1276
+ f"<td style='color:#888;font-size:0.75em'>{h.get('struct_h','')[:15]}</td>"
1277
+ f"<td style='color:#888;font-size:0.75em'>{h.get('vec_h','')[:15]}</td>"
1278
+ f"<td style='color:#888;font-size:0.75em'>{h.get('grad_h','')[:15]}</td>"
1279
  f"</tr>")
1280
 
1281
  prob_rows = ""
 
1299
  f"font-size:0.85em;margin:2px'>{label}: {val}</span>")
1300
 
1301
  html=f"""<!DOCTYPE html><html>
1302
+ <head><title>Practicality System 4.0</title>
1303
  <meta http-equiv="refresh" content="3">
1304
  <style>
1305
  body{{background:#0a0a0a;color:#e0e0e0;font-family:monospace;padding:20px}}
 
1310
  th{{color:#444}}
1311
  .witness-box{{background:#111; border:1px solid #333; padding:15px; color:#aaa; white-space:pre-wrap; font-size:0.9em;}}
1312
  </style></head><body>
1313
+ <h1>βš— Practicality System 4.0</h1>
1314
  <div style='margin-bottom:16px;line-height:2.2em;'>
1315
  {badge("Trials",runs,"#aaa")}
1316
  {badge("Avg rounds",avg_rounds,"#aaa")}
 
1319
  <br>
1320
  {badge("Seed wins", wins['seed'], '#4CAF50')}
1321
  {badge("Struct wins", wins['struct'], '#FF9800')}
1322
+ {badge("Vector wins", wins['vector'], '#E040FB')}
1323
+ {badge("Gradient wins", wins['gradient'], '#26C6DA')}
1324
  {badge("Merge wins", wins['merge'], '#FFD700')}
1325
  <br>
1326
  {badge("Seed bdgt", f"{split[0]:.0%}",'#4CAF50')}
1327
  {badge("Struct bdgt", f"{split[1]:.0%}",'#FF9800')}
1328
+ {badge("Vector bdgt", f"{split[2]:.0%}",'#E040FB')}
1329
+ {badge("Grad bdgt", f"{split[3]:.0%}",'#26C6DA')}
1330
  </div>
1331
  <table>
1332
  <tr><th>Strategy</th><th>Solve Rate</th><th>Avg CE</th><th>Avg Time</th></tr>
 
1343
  <tr><th>Prob/Round</th><th>Mode</th>
1344
  <th style='color:#4CAF50'>Seed</th>
1345
  <th style='color:#FF9800'>Struct</th>
1346
+ <th style='color:#E040FB'>Vector</th>
1347
+ <th style='color:#26C6DA'>Gradient</th>
1348
  <th style='color:#FFD700'>Merge</th>
1349
  <th>Winner</th>
1350
+ <th>Seed hyp</th><th>Struct hyp</th><th>Vector hyp</th><th>Gradient hyp</th></tr>
1351
+ {debate_rows or "<tr><td colspan='12' style='color:#333'>Warming up…</td></tr>"}
1352
  </table>
1353
 
1354
  <h3>Latest LLM Bridge Export (Universal Witness)</h3>