Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,14 +1,16 @@
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
-
PRACTICALITY SYSTEM 11.
|
| 4 |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 5 |
-
|
| 6 |
-
Β·
|
| 7 |
-
|
| 8 |
-
Β·
|
| 9 |
-
Β·
|
| 10 |
-
|
| 11 |
-
Β·
|
|
|
|
|
|
|
| 12 |
"""
|
| 13 |
|
| 14 |
import time, random, math, threading, asyncio, warnings, itertools, json
|
|
@@ -30,7 +32,7 @@ import uvicorn
|
|
| 30 |
warnings.filterwarnings("ignore")
|
| 31 |
USE_GPU = torch.cuda.is_available()
|
| 32 |
DEVICE = torch.device("cuda" if USE_GPU else "cpu")
|
| 33 |
-
print(f"[SYSTEM 11.
|
| 34 |
|
| 35 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 36 |
# SECTION 1: CONSTANTS
|
|
@@ -127,14 +129,11 @@ def compile_iv(expr,variables):
|
|
| 127 |
@dataclass
|
| 128 |
class PSLVar: name:str; lo:float; hi:float; weight:float=1.0
|
| 129 |
@dataclass
|
| 130 |
-
class PSLConstraint: kind:str; expr:str; scope:str="root"; weight:float=1.0;
|
| 131 |
@dataclass
|
| 132 |
class PSLScope: name:str; order:int=0; depends:List[str]=field(default_factory=list); vars:List[PSLVar]=field(default_factory=list); links:List[str]=field(default_factory=list); constraints:List[PSLConstraint]=field(default_factory=list)
|
| 133 |
@dataclass
|
| 134 |
-
class PSLProgram:
|
| 135 |
-
name:str; vars:List[PSLVar]; constraints:List[PSLConstraint]
|
| 136 |
-
scopes:List[PSLScope]; scope_order:List[str]
|
| 137 |
-
annotations:Dict[str,str]=field(default_factory=dict) # var β axl_field
|
| 138 |
|
| 139 |
def parse_psl(text:str) -> PSLProgram:
|
| 140 |
lines=[l.strip() for l in text.strip().split('\n') if l.strip() and not l.strip().startswith('#')]
|
|
@@ -143,18 +142,14 @@ def parse_psl(text:str) -> PSLProgram:
|
|
| 143 |
def advance():
|
| 144 |
nonlocal i; l=lines[i]; i+=1; return l
|
| 145 |
def peek(): return lines[i] if i<len(lines) else ""
|
| 146 |
-
def pvar(rest
|
| 147 |
p=rest.split()
|
| 148 |
-
if len(p)>=3
|
| 149 |
-
|
| 150 |
-
return PSLVar(p[0],float(p[1]),float(p[2]),w)
|
| 151 |
-
return None
|
| 152 |
-
def parse_weight(rest):
|
| 153 |
-
"""Extract WEIGHT value from end of constraint string."""
|
| 154 |
if 'WEIGHT' in rest:
|
| 155 |
-
|
| 156 |
return rest.strip(), 1.0
|
| 157 |
-
def parse_scope_body(sname,
|
| 158 |
svars,scons,links=[],[],[]
|
| 159 |
while i<len(lines):
|
| 160 |
l=peek(); tk=l.split(None,1)
|
|
@@ -164,20 +159,17 @@ def parse_psl(text:str) -> PSLProgram:
|
|
| 164 |
if kw=="VAR":
|
| 165 |
v=pvar(rest)
|
| 166 |
if v: svars.append(v)
|
| 167 |
-
elif kw=="LINK":
|
| 168 |
-
links.extend(rest.split())
|
| 169 |
elif kw in ("EQ","GEQ","LEQ"):
|
| 170 |
-
expr,wt=
|
| 171 |
-
scons.append(PSLConstraint(kw.lower(),expr,scope=sname,weight=wt))
|
| 172 |
elif kw=="CONSERVE":
|
| 173 |
-
expr,_=
|
| 174 |
-
scons.append(PSLConstraint("eq",expr,scope=sname,weight=10.0))
|
| 175 |
elif kw=="BRANCH":
|
| 176 |
opts=[]
|
| 177 |
-
while i<len(lines) and not peek().startswith("END"):
|
| 178 |
bl=advance()
|
| 179 |
if bl.upper().startswith("OPTION"): opts.append(bl.split(None,1)[1].strip())
|
| 180 |
-
advance()
|
| 181 |
scons.append(PSLConstraint("or_eq","",scope=sname,weight=1.0,branches=opts))
|
| 182 |
elif kw=="ANNOTATE":
|
| 183 |
parts=rest.split()
|
|
@@ -192,11 +184,9 @@ def parse_psl(text:str) -> PSLProgram:
|
|
| 192 |
v=pvar(rest)
|
| 193 |
if v: prog.vars.append(v)
|
| 194 |
elif kw in ("EQ","GEQ","LEQ"):
|
| 195 |
-
expr,wt=
|
| 196 |
-
prog.constraints.append(PSLConstraint(kw.lower(),expr,weight=wt))
|
| 197 |
elif kw=="CONSERVE":
|
| 198 |
-
expr,_=
|
| 199 |
-
prog.constraints.append(PSLConstraint("eq",expr,weight=10.0))
|
| 200 |
elif kw=="BRANCH":
|
| 201 |
opts=[]
|
| 202 |
while i<len(lines) and not peek().upper().startswith("END"):
|
|
@@ -218,9 +208,8 @@ def parse_psl(text:str) -> PSLProgram:
|
|
| 218 |
idx=rest.upper().index("DEPENDS")
|
| 219 |
depends=rest[idx:].split()[1:]
|
| 220 |
sc=parse_scope_body(sname,order,depends)
|
| 221 |
-
prog.scopes.append(sc)
|
| 222 |
-
|
| 223 |
-
prog.scopes.sort(key=lambda s: s.order)
|
| 224 |
prog.scope_order=[s.name for s in prog.scopes]
|
| 225 |
return prog
|
| 226 |
|
|
@@ -228,8 +217,8 @@ def parse_psl(text:str) -> PSLProgram:
|
|
| 228 |
class ExpandedProblem:
|
| 229 |
variables:List[str]; bounds:Dict[str,Tuple[float,float]]
|
| 230 |
constraints:List['Constraint']
|
| 231 |
-
scope_groups:Dict[str,List[int]]; scope_vars:Dict[str,List[str]]
|
| 232 |
-
annotations:Dict[str,str]=field(default_factory=dict)
|
| 233 |
|
| 234 |
def expand_psl(prog:PSLProgram) -> ExpandedProblem:
|
| 235 |
variables=[]; bounds={}; constraints=[]
|
|
@@ -275,89 +264,60 @@ def expand_psl(prog:PSLProgram) -> ExpandedProblem:
|
|
| 275 |
prog.scope_order,prog.annotations)
|
| 276 |
|
| 277 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 278 |
-
# SECTION 4: AXL LAYER
|
| 279 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 280 |
@dataclass
|
| 281 |
class AXLInvariant:
|
| 282 |
-
name: str
|
| 283 |
-
expr: str
|
| 284 |
-
tolerance: float = VERIFY_G2_TOLERANCE
|
| 285 |
|
| 286 |
@dataclass
|
| 287 |
class AXLProblemDef:
|
| 288 |
-
name:
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
constraints: List[Dict] # {kind: EQ/GEQ/LEQ/CONSERVE, expr, weight}
|
| 293 |
-
scopes: List[Dict] # {name, order, vars, constraints}
|
| 294 |
-
anchors: List[AXLInvariant] # verification oracles
|
| 295 |
-
observations: Dict[str,float] = field(default_factory=dict)
|
| 296 |
-
|
| 297 |
def variables_list(self): return [v["name"] for v in self.variables]
|
| 298 |
|
| 299 |
class AXLtoPSLCompiler:
|
| 300 |
-
"""
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
def compile(self, prob: AXLProblemDef) -> str:
|
| 305 |
-
lines = [f"SPACE {prob.name}"]
|
| 306 |
-
|
| 307 |
-
# Global variables
|
| 308 |
for v in prob.variables:
|
| 309 |
-
lo,
|
| 310 |
-
# Observations β zero-width bound
|
| 311 |
if v["name"] in prob.observations:
|
| 312 |
-
val
|
| 313 |
-
lo = hi = val
|
| 314 |
lines.append(f"VAR {v['name']} {lo} {hi}")
|
| 315 |
-
# ANNOTATE for reverse mapping
|
| 316 |
lines.append(f"ANNOTATE {v['name']} FROM_AXL {prob.name}.{v['name']}")
|
| 317 |
-
|
| 318 |
-
# Global constraints
|
| 319 |
for c in prob.constraints:
|
| 320 |
-
wt
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
lines.append(f"
|
| 324 |
-
|
| 325 |
-
lines.append(
|
| 326 |
-
|
| 327 |
-
# TEND β soft constraints (global vars)
|
| 328 |
for v in prob.variables:
|
| 329 |
-
tends
|
| 330 |
-
if tends
|
| 331 |
-
|
| 332 |
-
elif tends
|
| 333 |
-
lines.append(f"EQ {v['name']} - {v['hi']} WEIGHT {self.TEND_WEIGHT}")
|
| 334 |
-
elif tends.startswith("TOWARD:"):
|
| 335 |
-
val = tends.split(":")[1]
|
| 336 |
-
lines.append(f"EQ {v['name']} - {val} WEIGHT {self.TEND_WEIGHT}")
|
| 337 |
-
|
| 338 |
-
# Scopes
|
| 339 |
for sc in prob.scopes:
|
| 340 |
-
|
| 341 |
-
lines.append(f"SCOPE {sc['name']} ORDER {sc.get('order',0)}{
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
if c["kind"] == "CONSERVE":
|
| 348 |
-
lines.append(f" CONSERVE {c['expr']}")
|
| 349 |
-
elif c["kind"] == "BRANCH":
|
| 350 |
lines.append(f" BRANCH {c.get('name','br')}")
|
| 351 |
-
for opt in c.get("options",
|
| 352 |
-
lines.append(f" OPTION {opt}")
|
| 353 |
lines.append(" END BRANCH")
|
| 354 |
-
else:
|
| 355 |
-
lines.append(f" {c['kind']} {c['expr']} WEIGHT {wt}")
|
| 356 |
lines.append("END")
|
| 357 |
-
|
| 358 |
return "\n".join(lines)
|
| 359 |
|
| 360 |
-
AXL_COMPILER
|
| 361 |
|
| 362 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 363 |
# SECTION 5: PROBLEM & CONSTRAINT COMPILATION
|
|
@@ -373,7 +333,6 @@ class MathConstraint:
|
|
| 373 |
fast_iv:Optional[Callable]=field(default=None,repr=False)
|
| 374 |
fast_pt:Optional[Callable]=field(default=None,repr=False)
|
| 375 |
fast_np:Optional[Callable]=field(default=None,repr=False)
|
| 376 |
-
fast_torch:Optional[Callable]=field(default=None,repr=False)
|
| 377 |
syms_used:List[str]=field(default_factory=list)
|
| 378 |
parsed:Optional[sp.Expr]=field(default=None,repr=False)
|
| 379 |
scope:str="root"
|
|
@@ -405,10 +364,6 @@ def compile_mc(kind,expr_str,direction,variables,weight=1.0,scope="root",branche
|
|
| 405 |
mc.fast_iv=compile_iv(parsed,variables)
|
| 406 |
mc.fast_pt=sp.lambdify([sp.Symbol(v) for v in mc.syms_used],parsed,modules="math")
|
| 407 |
mc.fast_np=sp.lambdify([sp.Symbol(v) for v in mc.syms_used],parsed,modules="numpy")
|
| 408 |
-
if USE_GPU:
|
| 409 |
-
_tops={"sin":torch.sin,"cos":torch.cos,"exp":torch.exp,"sqrt":torch.sqrt,"log":torch.log,"Abs":torch.abs}
|
| 410 |
-
try: mc.fast_torch=sp.lambdify([sp.Symbol(v) for v in mc.syms_used],parsed,modules=[_tops,"math"])
|
| 411 |
-
except: pass
|
| 412 |
fast_jac={}
|
| 413 |
for v in mc.syms_used:
|
| 414 |
try:
|
|
@@ -422,8 +377,7 @@ def compile_mc(kind,expr_str,direction,variables,weight=1.0,scope="root",branche
|
|
| 422 |
for sym in parsed.free_symbols:
|
| 423 |
v_str=str(sym)
|
| 424 |
try:
|
| 425 |
-
sols=sp.solve(parsed,sym)
|
| 426 |
-
pm[v_str]=[]
|
| 427 |
for sol in sols:
|
| 428 |
fs=list(sol.free_symbols)
|
| 429 |
pm[v_str].append({"syms":[str(s) for s in fs],"func":sp.lambdify(fs,sol,modules="math")})
|
|
@@ -435,8 +389,7 @@ def compile_mc(kind,expr_str,direction,variables,weight=1.0,scope="root",branche
|
|
| 435 |
|
| 436 |
@dataclass
|
| 437 |
class Problem:
|
| 438 |
-
pid:str; variables:List[str]
|
| 439 |
-
constraints:List[Constraint]; bounds:Dict[str,Tuple[float,float]]
|
| 440 |
tier:str="hard"
|
| 441 |
scope_groups:Dict[str,List[int]]=field(default_factory=dict)
|
| 442 |
scope_vars:Dict[str,List[str]]=field(default_factory=dict)
|
|
@@ -462,9 +415,9 @@ class Problem:
|
|
| 462 |
if mc.fast_pt is None: total+=1.0; continue
|
| 463 |
try:
|
| 464 |
val=float(mc.fast_pt(*[b.get(v,0.0) for v in mc.syms_used]))
|
| 465 |
-
if mc.kind=="equality":
|
| 466 |
-
elif mc.direction=="geq":
|
| 467 |
-
else:
|
| 468 |
except: total+=1.0
|
| 469 |
for v,(lo,hi) in self.bounds.items():
|
| 470 |
bv=b.get(v,0.0); total+=max(0.0,lo-bv)+max(0.0,bv-hi)
|
|
@@ -515,7 +468,8 @@ class Problem:
|
|
| 515 |
for bmc in mc.branches:
|
| 516 |
if bmc.fast_np:
|
| 517 |
try:
|
| 518 |
-
args=[b_matrix[:,vti[v]] for v in bmc.syms_used]
|
|
|
|
| 519 |
val=bmc.fast_np(*args)
|
| 520 |
if not isinstance(val,np.ndarray): val=np.full(N,float(val),dtype=np.float32)
|
| 521 |
bv.append(np.abs(val))
|
|
@@ -525,7 +479,8 @@ class Problem:
|
|
| 525 |
else:
|
| 526 |
if mc.fast_np is None: total+=1.0; continue
|
| 527 |
try:
|
| 528 |
-
args=[b_matrix[:,vti[v]] for v in mc.syms_used]
|
|
|
|
| 529 |
val=mc.fast_np(*args)
|
| 530 |
if not isinstance(val,np.ndarray): val=np.full(N,float(val),dtype=np.float32)
|
| 531 |
if mc.kind=="equality": total+=np.abs(val)*mc.weight
|
|
@@ -542,46 +497,123 @@ class Problem:
|
|
| 542 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 543 |
@dataclass
|
| 544 |
class VerifyResult:
|
| 545 |
-
gate1_ce:
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
overall_pass: bool
|
| 550 |
-
failed_gates: List[str] = field(default_factory=list)
|
| 551 |
|
| 552 |
class VerifyLayer:
|
| 553 |
-
def run(self,
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
g1_ce = base_problem.constraint_energy(binding)
|
| 558 |
-
g1_pass = g1_ce < VERIFY_G1_THRESHOLD
|
| 559 |
-
|
| 560 |
-
# Gate 2 β invariant checks
|
| 561 |
-
g2 = {}
|
| 562 |
for inv in anchors:
|
| 563 |
try:
|
| 564 |
-
syms
|
| 565 |
-
expr
|
| 566 |
-
func
|
| 567 |
-
args
|
| 568 |
-
err
|
| 569 |
-
g2[inv.name]
|
| 570 |
-
except
|
| 571 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 572 |
|
| 573 |
-
|
| 574 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
|
| 581 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
|
| 583 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 584 |
-
# SECTION
|
| 585 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 586 |
@dataclass
|
| 587 |
class L7Certificate: topology_sig:str; hub_vars:List[str]; solve_order:List[str]
|
|
@@ -644,10 +676,12 @@ class ResidualOracle:
|
|
| 644 |
re=[e for e,c in sorted(de,key=lambda x:-x[1])[:5]]
|
| 645 |
return L9Certificate(round(ce,6),rv,re)
|
| 646 |
|
| 647 |
-
TOPOLOGY_ORACLE=TopologyOracle()
|
|
|
|
|
|
|
| 648 |
|
| 649 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 650 |
-
# SECTION
|
| 651 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 652 |
def _hc4(box,constraints):
|
| 653 |
cur=dict(box)
|
|
@@ -666,7 +700,8 @@ def _hc4(box,constraints):
|
|
| 666 |
try:
|
| 667 |
riv=mc.fast_iv(cur)
|
| 668 |
if ((mc.kind=="equality" and not riv.contains_zero()) or
|
| 669 |
-
(mc.kind=="inequality" and ((mc.direction=="geq" and riv.hi<-1e-10) or
|
|
|
|
| 670 |
return None
|
| 671 |
except: pass
|
| 672 |
return cur
|
|
@@ -758,8 +793,12 @@ def _adam_polish(problem,binding,steps=ADAM_STEPS):
|
|
| 758 |
if nce<best_ce: best_ce=nce; best_b=dict(b)
|
| 759 |
return best_b,best_ce
|
| 760 |
|
| 761 |
-
def solve_by_hypothesis(problem, budget=TOTAL_BUDGET
|
|
|
|
| 762 |
t0=time.time()
|
|
|
|
|
|
|
|
|
|
| 763 |
init_b={v:max(lo,min(hi,(lo+hi)/2)) for v,(lo,hi) in problem.bounds.items()}
|
| 764 |
tb=_global_hc4_tighten(problem)
|
| 765 |
full_box={v:IV(tb[v][0],tb[v][1]) for v in problem.variables if v in tb}
|
|
@@ -767,26 +806,17 @@ def solve_by_hypothesis(problem, budget=TOTAL_BUDGET):
|
|
| 767 |
if mprt_ce<problem.constraint_energy(init_b): init_b=mprt_b
|
| 768 |
snap_b,snap_ce=_algebraic_snap(problem,init_b)
|
| 769 |
if snap_ce<problem.constraint_energy(init_b): init_b=snap_b
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
from dataclasses import dataclass as _dc
|
| 773 |
-
@_dc
|
| 774 |
-
class _SM:
|
| 775 |
-
best_binding:dict; best_ce:float
|
| 776 |
-
tested:list=field(default_factory=list)
|
| 777 |
-
failure_patterns:set=field(default_factory=set)
|
| 778 |
-
scope_witnesses:dict=field(default_factory=dict)
|
| 779 |
-
confirmed_ranges:dict=field(default_factory=dict)
|
| 780 |
-
conflict_vars:set=field(default_factory=set)
|
| 781 |
-
|
| 782 |
-
model=_SM(best_binding=init_b,best_ce=problem.constraint_energy(init_b))
|
| 783 |
active_scopes=[s for s in problem.scope_order if s!="root" and problem.scope_vars.get(s)]
|
|
|
|
| 784 |
if model.best_ce<SOLVE_THRESHOLD:
|
| 785 |
l7=TOPOLOGY_ORACLE.evaluate(problem,active_scopes)
|
| 786 |
l9=RESIDUAL_ORACLE.evaluate(model.best_binding,problem,l7.hub_vars)
|
| 787 |
-
return {"binding":model.best_binding,"ce":model.best_ce,"solved":True,
|
|
|
|
| 788 |
|
| 789 |
-
oracle=HypothesisOracle(); consec=0
|
| 790 |
for round_idx in range(HYPOTHESIS_MAX_ROUNDS):
|
| 791 |
if model.best_ce<SOLVE_THRESHOLD: break
|
| 792 |
l7=TOPOLOGY_ORACLE.evaluate(problem,active_scopes)
|
|
@@ -810,12 +840,17 @@ def solve_by_hypothesis(problem, budget=TOTAL_BUDGET):
|
|
| 810 |
eb,ece=_mprt_sample(problem,work_box,N_MPRT_EXPLORE)
|
| 811 |
if ece<model.best_ce: model.best_ce=ece; model.best_binding=dict(eb); consec=0
|
| 812 |
|
| 813 |
-
|
|
|
|
| 814 |
gb,gce=_gradient_polish(problem,model.best_binding)
|
| 815 |
if gce<model.best_ce: model.best_ce=gce; model.best_binding=gb
|
| 816 |
-
if SOLVE_THRESHOLD<model.best_ce<1.0:
|
| 817 |
ab,ace=_adam_polish(problem,model.best_binding)
|
| 818 |
if ace<model.best_ce: model.best_ce=ace; model.best_binding=ab
|
|
|
|
|
|
|
|
|
|
|
|
|
| 819 |
|
| 820 |
final_l7=TOPOLOGY_ORACLE.evaluate(problem,active_scopes)
|
| 821 |
final_l9=RESIDUAL_ORACLE.evaluate(model.best_binding,problem,final_l7.hub_vars)
|
|
@@ -823,36 +858,12 @@ def solve_by_hypothesis(problem, budget=TOTAL_BUDGET):
|
|
| 823 |
"l7":final_l7,"l9":final_l9,"time":round(time.time()-t0,3)}
|
| 824 |
|
| 825 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 826 |
-
# SECTION
|
| 827 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 828 |
-
@dataclass
|
| 829 |
-
class Hypothesis:
|
| 830 |
-
hid:str; binding:Dict[str,float]; h_type:str; claim:str
|
| 831 |
-
derivation:List[str]; pinned_vars:Dict[str,float]; free_vars:List[str]
|
| 832 |
-
confidence:float; ce:float=float('inf')
|
| 833 |
-
|
| 834 |
-
@dataclass
|
| 835 |
-
class HypothesisTrace:
|
| 836 |
-
hid: str
|
| 837 |
-
round_idx: int
|
| 838 |
-
domain_name: str
|
| 839 |
-
action: str
|
| 840 |
-
ce_before: float
|
| 841 |
-
ce_after: float
|
| 842 |
-
verify: Optional[VerifyResult]
|
| 843 |
-
survived: bool
|
| 844 |
-
elapsed_ms: float
|
| 845 |
-
|
| 846 |
-
@dataclass
|
| 847 |
-
class StructuralModel:
|
| 848 |
-
best_binding:Dict[str,float]; best_ce:float
|
| 849 |
-
tested:List[Hypothesis]=field(default_factory=list)
|
| 850 |
-
failure_patterns:Set[str]=field(default_factory=set)
|
| 851 |
-
scope_witnesses:Dict[str,Dict[str,Tuple]]=field(default_factory=dict)
|
| 852 |
-
confirmed_ranges:Dict[str,Tuple[float,float]]=field(default_factory=dict)
|
| 853 |
-
conflict_vars:Set[str]=field(default_factory=set)
|
| 854 |
-
|
| 855 |
class HypothesisOracle:
|
|
|
|
|
|
|
|
|
|
| 856 |
def generate(self,problem,model,l7,l8,l9,round_idx):
|
| 857 |
hyps=[]
|
| 858 |
hyps.extend(self._branch_hypotheses(problem,model,l9))
|
|
@@ -860,6 +871,11 @@ class HypothesisOracle:
|
|
| 860 |
hyps.extend(self._coherence_hypotheses(problem,model,l8))
|
| 861 |
hyps.extend(self._residual_chain_hypotheses(problem,model,l9))
|
| 862 |
if round_idx>=3: hyps.extend(self._manifold_tangent_hypotheses(problem,model,l9))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 863 |
hyps=[h for h in hyps if h.hid not in model.failure_patterns]
|
| 864 |
return sorted(hyps,key=lambda h:-h.confidence)
|
| 865 |
|
|
@@ -875,9 +891,10 @@ class HypothesisOracle:
|
|
| 875 |
val=float(proj["func"](*[ref.get(s,0.0) for s in proj["syms"]]))
|
| 876 |
if not math.isfinite(val) or abs(val)>1e6 or not(lo<=val<=hi): continue
|
| 877 |
b=dict(ref); b[v]=val
|
| 878 |
-
hyps.append(Hypothesis(hid=f"br_{hash(expr_str)%9999}_{v}_{pi}",
|
| 879 |
-
claim=f"AlgBranch:{v}={val:.4f}",
|
| 880 |
-
pinned_vars={v:val},
|
|
|
|
| 881 |
confidence=0.85 if pi==0 else 0.70))
|
| 882 |
except: pass
|
| 883 |
return hyps
|
|
@@ -890,16 +907,18 @@ class HypothesisOracle:
|
|
| 890 |
if not svars: continue
|
| 891 |
scope_mcs=[problem.compiled_constraints[i] for i in problem.scope_groups.get(sn,[])]
|
| 892 |
if not scope_mcs: continue
|
| 893 |
-
start_box={v:IV(*tb.get(v,problem.bounds
|
| 894 |
cont=_hc4(start_box,scope_mcs)
|
| 895 |
if cont:
|
| 896 |
for v,iv in cont.items():
|
| 897 |
b[v]=iv.mid()
|
| 898 |
chain_steps.append(sn)
|
| 899 |
if chain_steps:
|
| 900 |
-
hyps.append(Hypothesis(
|
| 901 |
-
|
| 902 |
-
|
|
|
|
|
|
|
| 903 |
free_vars=[v for v in problem.variables if not any(v in problem.scope_vars.get(sn,[]) for sn in chain_steps)],
|
| 904 |
confidence=0.80))
|
| 905 |
return hyps
|
|
@@ -910,10 +929,11 @@ class HypothesisOracle:
|
|
| 910 |
for v,(lo,hi) in l8.tightened_bounds.items():
|
| 911 |
if v in problem.bounds: b[v]=(lo+hi)/2.0
|
| 912 |
return [Hypothesis(hid=f"coh_{hash(tuple(sorted(l8.incoherent_vars)))%9999}",
|
| 913 |
-
binding=b,h_type="coherence",claim=f"
|
| 914 |
derivation=list(l8.incoherent_vars),
|
| 915 |
pinned_vars={v:b[v] for v in l8.incoherent_vars if v in b},
|
| 916 |
-
free_vars=[v for v in problem.variables if v not in l8.incoherent_vars],
|
|
|
|
| 917 |
|
| 918 |
def _residual_chain_hypotheses(self,problem,model,l9):
|
| 919 |
if not l9.dominant_vars: return []
|
|
@@ -988,7 +1008,11 @@ def _test_hypothesis(problem,hyp):
|
|
| 988 |
return best_b,best_ce
|
| 989 |
|
| 990 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 991 |
-
# SECTION
|
|
|
|
|
|
|
|
|
|
|
|
|
| 992 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 993 |
class Axiom:
|
| 994 |
DISCRETE="DISCRETE"; CONTINUOUS="CONTINUOUS"; METRIC="METRIC"; NETWORK="NETWORK"
|
|
@@ -996,15 +1020,15 @@ class Axiom:
|
|
| 996 |
QUADRATIC="QUADRATIC"; BILINEAR="BILINEAR"; ORDERED="ORDERED"; SYMMETRIC="SYMMETRIC"
|
| 997 |
TRANSITIVE="TRANSITIVE"; ATOMIC="ATOMIC"; COMPOSITE="COMPOSITE"
|
| 998 |
|
| 999 |
-
AXIOM_CONTRADICTIONS=[
|
| 1000 |
-
|
|
|
|
|
|
|
| 1001 |
|
| 1002 |
@dataclass
|
| 1003 |
class AbstractDomain:
|
| 1004 |
name:str; axioms:Set[str]; derivation:str="Base"; confidence:float=1.0
|
| 1005 |
-
def is_consistent(self):
|
| 1006 |
-
return not any(p.issubset(self.axioms) for p in AXIOM_CONTRADICTIONS)
|
| 1007 |
-
def __str__(self): return f"[{self.name}|{self.derivation}] {{{', '.join(sorted(self.axioms))}}}"
|
| 1008 |
|
| 1009 |
BASE_LIBRARY=[
|
| 1010 |
AbstractDomain("GraphSpace",{Axiom.DISCRETE,Axiom.NETWORK,Axiom.SYMMETRIC,Axiom.ATOMIC}),
|
|
@@ -1024,19 +1048,18 @@ class WisdomOps:
|
|
| 1024 |
@staticmethod
|
| 1025 |
def union(d1,d2):
|
| 1026 |
merged=d1.axioms|d2.axioms
|
| 1027 |
-
c=AbstractDomain(WisdomOps._fn(f"{d1.name}
|
| 1028 |
for pair in AXIOM_CONTRADICTIONS:
|
| 1029 |
if pair.issubset(c.axioms):
|
| 1030 |
counts={ax:sum(ax in d.axioms for d in BASE_LIBRARY) for ax in pair}
|
| 1031 |
c.axioms.discard(min(counts,key=counts.get))
|
| 1032 |
return c
|
| 1033 |
@staticmethod
|
| 1034 |
-
def relax(d,axioms): return AbstractDomain(WisdomOps._fn(f"{d.name}_Rlx"),d.axioms-axioms,
|
| 1035 |
@staticmethod
|
| 1036 |
def inject(d,axioms):
|
| 1037 |
-
merged=d.axioms|axioms
|
| 1038 |
-
|
| 1039 |
-
c=AbstractDomain(WisdomOps._fn(f"{d.name}+{ax_str}"),merged,f"Inject",d.confidence*0.9)
|
| 1040 |
for pair in AXIOM_CONTRADICTIONS:
|
| 1041 |
if pair.issubset(c.axioms):
|
| 1042 |
to_rm=pair-d.axioms
|
|
@@ -1052,60 +1075,107 @@ class WisdomOps:
|
|
| 1052 |
return AbstractDomain(WisdomOps._fn(f"{d.name}*"),{fm.get(ax,ax) for ax in d.axioms},"Dual",d.confidence*0.7)
|
| 1053 |
|
| 1054 |
class PSLTranslator:
|
| 1055 |
-
|
| 1056 |
-
|
| 1057 |
-
|
| 1058 |
-
|
| 1059 |
-
|
| 1060 |
-
|
| 1061 |
-
|
| 1062 |
-
|
| 1063 |
-
|
| 1064 |
-
|
| 1065 |
-
|
| 1066 |
-
|
| 1067 |
-
|
| 1068 |
-
|
| 1069 |
-
|
| 1070 |
-
|
| 1071 |
-
|
| 1072 |
-
lines.append(f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1073 |
lines.append(f" LINK {' '.join(variables)}")
|
| 1074 |
-
|
|
|
|
| 1075 |
lines.append("END"); si+=1
|
| 1076 |
-
|
| 1077 |
-
|
| 1078 |
-
|
| 1079 |
-
|
| 1080 |
-
|
| 1081 |
-
lines.append(f"
|
| 1082 |
-
lines.append(f" LINK {' '.join(grp)}")
|
| 1083 |
-
for j in range(len(grp)-1):
|
| 1084 |
-
lines.append(f" EQ {grp[j]}**2 + {grp[j+1]}**2 - 1.0")
|
| 1085 |
-
lines.append(f" EQ {grp[j]}*{grp[j+1]} - 0.0")
|
| 1086 |
-
lines.append("END"); si+=1
|
| 1087 |
-
if Axiom.ORDERED in ax and Axiom.BILINEAR not in ax:
|
| 1088 |
-
lines.append(f"SCOPE ordered_{si} ORDER {si}")
|
| 1089 |
-
lines.append(f" LINK {' '.join(variables)}")
|
| 1090 |
-
for i in range(n-1): lines.append(f" GEQ {variables[i+1]} - {variables[i]}")
|
| 1091 |
lines.append("END"); si+=1
|
|
|
|
| 1092 |
if Axiom.METRIC in ax and Axiom.INJECTIVE in ax and n>=2:
|
| 1093 |
-
lines.append(f"SCOPE
|
| 1094 |
-
lines.append(f" LINK {' '.join(variables[:min(
|
| 1095 |
-
for
|
| 1096 |
-
lines.append(f" GEQ ({variables[
|
| 1097 |
lines.append("END"); si+=1
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
-
lines.append(f"
|
| 1101 |
-
|
|
|
|
|
|
|
|
|
|
| 1102 |
lines.append("END"); si+=1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1103 |
return "\n".join(lines)
|
| 1104 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1105 |
@dataclass
|
| 1106 |
class DebateRound:
|
| 1107 |
round_idx:int; domain:AbstractDomain; psl_text:str
|
| 1108 |
-
ce:float; solved:bool; action:str
|
| 1109 |
traces:List[HypothesisTrace]=field(default_factory=list)
|
| 1110 |
|
| 1111 |
class WisdomDebate:
|
|
@@ -1125,19 +1195,20 @@ class WisdomDebate:
|
|
| 1125 |
|
| 1126 |
def _candidates(self,current,round_idx):
|
| 1127 |
cands=[(d,"Library") for d in self.library]
|
| 1128 |
-
for d1,d2 in itertools.combinations(self.library[:5],2):
|
|
|
|
| 1129 |
for d in self.library[:4]: cands.append((WisdomOps.dual(d),"Dual"))
|
| 1130 |
if round_idx>2:
|
| 1131 |
chosen=random.sample([Axiom.BILINEAR,Axiom.QUADRATIC,Axiom.CONSERVED,Axiom.METRIC,Axiom.ORDERED],2)
|
| 1132 |
-
cands.append((WisdomOps.inject(current,set(chosen)),
|
| 1133 |
return cands
|
| 1134 |
|
| 1135 |
def debate(self,axl_def:AXLProblemDef,base_problem:Problem) -> Tuple[Dict,float,List[DebateRound]]:
|
| 1136 |
-
problem_axioms=axl_def.axioms
|
| 1137 |
current=min(self.library,key=lambda d:self._critic_score(problem_axioms,d)[0])
|
| 1138 |
self.history=[]; self.best_ce=float('inf'); self.best_binding={}; self.all_traces=[]
|
| 1139 |
|
| 1140 |
-
print(f"\n{'β'*
|
| 1141 |
|
| 1142 |
for round_idx in range(self.MAX_ROUNDS):
|
| 1143 |
cands=self._candidates(current,round_idx)
|
|
@@ -1145,99 +1216,110 @@ class WisdomDebate:
|
|
| 1145 |
scored.sort(key=lambda x:x[0])
|
| 1146 |
tried={r.domain.name for r in self.history}
|
| 1147 |
score,winner,action=next((s for s in scored if s[1].name not in tried),scored[0])
|
|
|
|
| 1148 |
|
| 1149 |
-
print(f"\n[R{round_idx+1}]
|
| 1150 |
-
|
|
|
|
|
|
|
|
|
|
| 1151 |
round_traces=[]
|
| 1152 |
|
| 1153 |
try:
|
| 1154 |
prog=parse_psl(psl_text); ep=expand_psl(prog)
|
| 1155 |
if not ep.variables:
|
| 1156 |
-
print(
|
|
|
|
| 1157 |
dom_prob=Problem(pid=f"dom_{winner.name}",variables=ep.variables,
|
| 1158 |
constraints=ep.constraints,bounds=ep.bounds,
|
| 1159 |
scope_groups=ep.scope_groups,scope_vars=ep.scope_vars,
|
| 1160 |
scope_order=ep.scope_order)
|
| 1161 |
t_start=time.time()
|
| 1162 |
-
|
|
|
|
| 1163 |
elapsed=round((time.time()-t_start)*1000,1)
|
| 1164 |
binding=result["binding"]; ce=result["ce"]; solved=result["solved"]
|
| 1165 |
|
| 1166 |
# Verify against base problem + anchors
|
| 1167 |
verify=VERIFY_LAYER.run(binding,base_problem,axl_def.anchors)
|
|
|
|
| 1168 |
|
| 1169 |
trace=HypothesisTrace(
|
| 1170 |
hid=f"R{round_idx+1}_{winner.name[:10]}",
|
| 1171 |
-
round_idx=round_idx+1,
|
| 1172 |
-
|
| 1173 |
-
|
| 1174 |
-
|
| 1175 |
-
|
| 1176 |
-
verify=verify,
|
| 1177 |
-
survived=verify.overall_pass,
|
| 1178 |
-
elapsed_ms=elapsed)
|
| 1179 |
round_traces.append(trace); self.all_traces.append(trace)
|
| 1180 |
|
| 1181 |
status="β SURVIVED" if verify.overall_pass else "β FAILED"
|
| 1182 |
-
print(f"
|
|
|
|
| 1183 |
for inv_name,(err,passed) in verify.gate2_results.items():
|
| 1184 |
-
print(f" [{'
|
| 1185 |
|
| 1186 |
-
if
|
| 1187 |
-
self.best_ce=
|
| 1188 |
-
|
| 1189 |
-
|
|
|
|
|
|
|
| 1190 |
print(f"\nβ VERIFIED + SOLVED in round {round_idx+1}"); break
|
|
|
|
| 1191 |
except Exception as e:
|
| 1192 |
-
|
| 1193 |
trace=HypothesisTrace(hid=f"R{round_idx+1}_ERR",round_idx=round_idx+1,
|
| 1194 |
domain_name=winner.name,action=action,ce_before=99.0,ce_after=99.0,
|
| 1195 |
verify=None,survived=False,elapsed_ms=0)
|
| 1196 |
round_traces.append(trace); self.all_traces.append(trace)
|
| 1197 |
|
| 1198 |
self.history.append(DebateRound(round_idx,winner,psl_text,
|
| 1199 |
-
self.best_ce,self.best_ce<SOLVE_THRESHOLD,action,round_traces))
|
| 1200 |
current=winner
|
| 1201 |
|
| 1202 |
-
print(f"\n{'β'*
|
| 1203 |
return self.best_binding,self.best_ce,self.history
|
| 1204 |
|
| 1205 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1206 |
-
# SECTION
|
| 1207 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1208 |
-
|
| 1209 |
-
class AXLProblemDef:
|
| 1210 |
-
name:str; description:str; axioms:Set[str]
|
| 1211 |
-
variables:List[Dict]; constraints:List[Dict]
|
| 1212 |
-
scopes:List[Dict]; anchors:List[AXLInvariant]
|
| 1213 |
-
observations:Dict[str,float]=field(default_factory=dict)
|
| 1214 |
-
|
| 1215 |
-
def variables_list(self): return [v["name"] for v in self.variables]
|
| 1216 |
|
| 1217 |
-
|
|
|
|
|
|
|
| 1218 |
AXLProblemDef(
|
| 1219 |
name="NormManifold4D",
|
| 1220 |
-
description="
|
| 1221 |
axioms={Axiom.CONTINUOUS,Axiom.QUADRATIC,Axiom.CONSERVED,Axiom.METRIC,Axiom.SYMMETRIC},
|
| 1222 |
variables=[
|
| 1223 |
-
{"name":"x1","lo":-1.0,"hi":1.0},
|
| 1224 |
-
{"name":"
|
|
|
|
|
|
|
| 1225 |
],
|
| 1226 |
constraints=[
|
| 1227 |
{"kind":"CONSERVE","expr":"x1**2 + x2**2 + x3**2 + x4**2 - 1.0"},
|
| 1228 |
-
{"kind":"EQ", "expr":"x1 + x2 + x3 + x4","weight":
|
| 1229 |
],
|
| 1230 |
scopes=[{"name":"sphere","order":0,"vars":["x1","x2","x3","x4"],
|
| 1231 |
-
"constraints":[
|
|
|
|
|
|
|
| 1232 |
anchors=[
|
| 1233 |
AXLInvariant("unit_sphere","x1**2 + x2**2 + x3**2 + x4**2 - 1.0",1e-3),
|
| 1234 |
AXLInvariant("zero_sum","x1 + x2 + x3 + x4",1e-3),
|
|
|
|
| 1235 |
],
|
| 1236 |
observations={"x1":0.5},
|
| 1237 |
),
|
|
|
|
|
|
|
|
|
|
| 1238 |
AXLProblemDef(
|
| 1239 |
name="BilinearChain6",
|
| 1240 |
-
description="6-
|
| 1241 |
axioms={Axiom.DISCRETE,Axiom.ORDERED,Axiom.BILINEAR,Axiom.CONSERVED,Axiom.NETWORK},
|
| 1242 |
variables=[{"name":f"t{i}","lo":0.0,"hi":3.0} for i in range(1,7)],
|
| 1243 |
constraints=[
|
|
@@ -1248,77 +1330,90 @@ AXL_PROBLEMS = [
|
|
| 1248 |
{"kind":"GEQ","expr":"t5 - t4","weight":1.0},
|
| 1249 |
{"kind":"GEQ","expr":"t6 - t5","weight":1.0},
|
| 1250 |
],
|
| 1251 |
-
scopes=[
|
| 1252 |
-
|
| 1253 |
-
|
| 1254 |
-
|
| 1255 |
-
|
| 1256 |
-
|
| 1257 |
-
]},
|
| 1258 |
-
],
|
| 1259 |
anchors=[
|
| 1260 |
AXLInvariant("conservation","t1 + t2 + t3 + t4 + t5 + t6 - 9.0",1e-3),
|
| 1261 |
-
AXLInvariant("
|
| 1262 |
-
AXLInvariant("bilinear_mid","t3*t4 - 2.0",0.
|
|
|
|
| 1263 |
],
|
| 1264 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1265 |
AXLProblemDef(
|
| 1266 |
name="PhaseCollider",
|
| 1267 |
-
description="
|
| 1268 |
axioms={Axiom.DISCRETE,Axiom.MUTABLE,Axiom.SYMMETRIC,Axiom.NETWORK,Axiom.CONSERVED},
|
| 1269 |
variables=[
|
| 1270 |
-
{"name":"p1x","lo":-2.0,"hi":2.0},
|
| 1271 |
-
{"name":"
|
|
|
|
|
|
|
| 1272 |
],
|
| 1273 |
constraints=[
|
| 1274 |
-
{"kind":"CONSERVE","expr":"p1x + p2x"},
|
| 1275 |
-
{"kind":"CONSERVE","expr":"p1y + p2y"},
|
| 1276 |
-
],
|
| 1277 |
-
scopes=[
|
| 1278 |
-
{"name":"phase","order":0,"vars":["p1x","p2x","p1y","p2y"],
|
| 1279 |
-
"constraints":[
|
| 1280 |
-
{"kind":"BRANCH","name":"collision_mode","options":[
|
| 1281 |
-
"p1x**2 + p1y**2 - 1.0", # phase A: unit circle
|
| 1282 |
-
"p1x**2 + p1y**2 - 2.0", # phase B: larger circle
|
| 1283 |
-
]},
|
| 1284 |
-
{"kind":"EQ","expr":"(p1x - p2x)**2 + (p1y - p2y)**2 - 1.0","weight":2.0},
|
| 1285 |
-
]},
|
| 1286 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1287 |
anchors=[
|
| 1288 |
AXLInvariant("momentum_x","p1x + p2x",1e-3),
|
| 1289 |
AXLInvariant("momentum_y","p1y + p2y",1e-3),
|
| 1290 |
-
|
|
|
|
|
|
|
| 1291 |
],
|
| 1292 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1293 |
AXLProblemDef(
|
| 1294 |
name="MetricPacking3D",
|
| 1295 |
-
description="3
|
| 1296 |
axioms={Axiom.CONTINUOUS,Axiom.METRIC,Axiom.INJECTIVE,Axiom.CONSERVED,Axiom.SYMMETRIC},
|
| 1297 |
variables=[
|
| 1298 |
-
{"name":"a","lo":-3.0,"hi":3.0},
|
|
|
|
|
|
|
| 1299 |
],
|
| 1300 |
constraints=[
|
|
|
|
| 1301 |
{"kind":"GEQ","expr":"(a - b)**2 - 1.0","weight":2.0},
|
| 1302 |
{"kind":"GEQ","expr":"(b - c)**2 - 1.0","weight":2.0},
|
| 1303 |
{"kind":"GEQ","expr":"(a - c)**2 - 4.0","weight":2.0},
|
| 1304 |
-
{"kind":"CONSERVE","expr":"a + b + c"}, # centred at 0
|
| 1305 |
-
],
|
| 1306 |
-
scopes=[
|
| 1307 |
-
{"name":"packing","order":0,"vars":["a","b","c"],
|
| 1308 |
-
"constraints":[
|
| 1309 |
-
{"kind":"EQ","expr":"a**2 + b**2 + c**2 - 6.0","weight":1.5},
|
| 1310 |
-
]},
|
| 1311 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1312 |
anchors=[
|
| 1313 |
AXLInvariant("centred","a + b + c",1e-3),
|
| 1314 |
-
AXLInvariant("sep_ab","(a - b)**2 - 1.0",0.
|
| 1315 |
-
AXLInvariant("sep_bc","(b - c)**2 - 1.0",0.
|
|
|
|
| 1316 |
],
|
| 1317 |
),
|
| 1318 |
]
|
| 1319 |
|
| 1320 |
def build_base_problem(axl_def:AXLProblemDef) -> Problem:
|
| 1321 |
-
"""Compile the AXL definition directly to a Problem for use as verification oracle."""
|
| 1322 |
psl_text=AXL_COMPILER.compile(axl_def)
|
| 1323 |
prog=parse_psl(psl_text); ep=expand_psl(prog)
|
| 1324 |
return Problem(pid=f"base_{axl_def.name}",variables=ep.variables,
|
|
@@ -1327,10 +1422,10 @@ def build_base_problem(axl_def:AXLProblemDef) -> Problem:
|
|
| 1327 |
scope_order=ep.scope_order,annotations=ep.annotations)
|
| 1328 |
|
| 1329 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1330 |
-
# SECTION
|
| 1331 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββοΏ½οΏ½οΏ½βββββ
|
| 1332 |
STATE_LOCK=threading.Lock()
|
| 1333 |
-
RUN_LOG:List[Dict]=[]
|
| 1334 |
DEBATE_ENGINE=WisdomDebate()
|
| 1335 |
POOL=ThreadPoolExecutor(max_workers=2)
|
| 1336 |
|
|
@@ -1338,33 +1433,30 @@ def _run_problem(axl_def:AXLProblemDef):
|
|
| 1338 |
t0=time.time()
|
| 1339 |
try:
|
| 1340 |
base_prob=build_base_problem(axl_def)
|
| 1341 |
-
binding,
|
| 1342 |
elapsed=round(time.time()-t0,2)
|
| 1343 |
-
|
| 1344 |
survived=[t for t in DEBATE_ENGINE.all_traces if t.survived]
|
| 1345 |
failed=[t for t in DEBATE_ENGINE.all_traces if not t.survived]
|
| 1346 |
best_trace=min((t for t in survived),key=lambda t:t.ce_after,default=None)
|
| 1347 |
-
|
| 1348 |
-
# FIX: Calculate actual CE against the original base problem
|
| 1349 |
-
actual_base_ce = base_prob.constraint_energy(binding)
|
| 1350 |
-
is_truly_solved = len(survived) > 0
|
| 1351 |
-
|
| 1352 |
record={
|
| 1353 |
"problem":axl_def.name,
|
| 1354 |
"description":axl_def.description,
|
| 1355 |
"axioms":sorted(axl_def.axioms),
|
| 1356 |
-
"ce":round(actual_base_ce,
|
| 1357 |
-
"
|
| 1358 |
-
"solved":is_truly_solved, # ONLY true if verified
|
| 1359 |
"elapsed":elapsed,
|
| 1360 |
"binding":{k:round(v,5) for k,v in binding.items()},
|
|
|
|
| 1361 |
"traces":[{
|
| 1362 |
"hid":t.hid,"round":t.round_idx,"domain":t.domain_name,
|
| 1363 |
-
"action":t.action,"
|
|
|
|
| 1364 |
"g1_ce":round(t.verify.gate1_ce,5) if t.verify else None,
|
| 1365 |
"g1":t.verify.gate1_pass if t.verify else False,
|
| 1366 |
"g2":t.verify.gate2_pass if t.verify else False,
|
| 1367 |
-
"g2_detail":{k:(round(err,6),ok)
|
|
|
|
| 1368 |
"survived":t.survived,"ms":t.elapsed_ms,
|
| 1369 |
} for t in DEBATE_ENGINE.all_traces],
|
| 1370 |
"survived_count":len(survived),
|
|
@@ -1375,6 +1467,7 @@ def _run_problem(axl_def:AXLProblemDef):
|
|
| 1375 |
RUN_LOG.append(record)
|
| 1376 |
if len(RUN_LOG)>40: RUN_LOG.pop(0)
|
| 1377 |
except Exception as e:
|
|
|
|
| 1378 |
print(f"[RUN ERROR] {axl_def.name}: {e}")
|
| 1379 |
|
| 1380 |
async def run_loop():
|
|
@@ -1382,7 +1475,7 @@ async def run_loop():
|
|
| 1382 |
while True:
|
| 1383 |
prob=random.choice(AXL_PROBLEMS)
|
| 1384 |
await loop.run_in_executor(POOL,_run_problem,prob)
|
| 1385 |
-
await asyncio.sleep(0.
|
| 1386 |
|
| 1387 |
@asynccontextmanager
|
| 1388 |
async def lifespan(app):
|
|
@@ -1391,167 +1484,135 @@ async def lifespan(app):
|
|
| 1391 |
POOL.shutdown(wait=False)
|
| 1392 |
|
| 1393 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1394 |
-
# SECTION
|
| 1395 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1396 |
-
app=FastAPI(title="Practicality 11.
|
| 1397 |
-
|
| 1398 |
-
def _render_trace_table(traces:List[Dict]) -> str:
|
| 1399 |
-
rows=""
|
| 1400 |
-
for t in traces:
|
| 1401 |
-
g1c="#4CAF50" if t["g1"] else "#EF5350"
|
| 1402 |
-
g2c="#4CAF50" if t["g2"] else "#EF5350"
|
| 1403 |
-
sc="#4CAF50" if t["survived"] else "#EF5350"
|
| 1404 |
-
star=" β" if t["survived"] else ""
|
| 1405 |
-
g2d=" ".join(f"{k}={v[0]:.4f}{'β' if v[1] else 'β'}" for k,v in t.get("g2_detail",{}).items())
|
| 1406 |
-
rows+=(f"<tr>"
|
| 1407 |
-
f"<td style='color:#888'>{t['round']}</td>"
|
| 1408 |
-
f"<td style='color:#FF9800'>{t['domain']}</td>"
|
| 1409 |
-
f"<td style='color:#555;font-size:0.75em'>{t['action']}</td>"
|
| 1410 |
-
f"<td style='color:#26C6DA'>{t['ce']:.5f}</td>"
|
| 1411 |
-
f"<td style='color:{g1c}'>{t['g1_ce']:.4f}{'β' if t['g1'] else 'β'}</td>"
|
| 1412 |
-
f"<td style='color:{g2c}'>{'β' if t['g2'] else 'β'} {g2d}</td>"
|
| 1413 |
-
f"<td style='color:{sc};font-weight:700'>{'SURVIVED'+star if t['survived'] else 'failed'}</td>"
|
| 1414 |
-
f"<td style='color:#444'>{t['ms']}ms</td>"
|
| 1415 |
-
f"</tr>")
|
| 1416 |
-
return rows
|
| 1417 |
|
| 1418 |
def _render_collapse(record:Dict) -> str:
|
| 1419 |
-
b=record["binding"]
|
| 1420 |
-
traces=record["traces"]
|
| 1421 |
survived=[t for t in traces if t["survived"]]
|
| 1422 |
-
|
| 1423 |
-
# FIX: If nothing survived, pick the best attempt to show WHY it failed
|
| 1424 |
best=min(survived,key=lambda t:t["ce"],default=None)
|
| 1425 |
-
if not best and traces:
|
| 1426 |
-
|
| 1427 |
-
|
| 1428 |
-
obs_vars=set()
|
| 1429 |
-
for axl in AXL_PROBLEMS:
|
| 1430 |
-
if axl.name==record["problem"]: obs_vars=set(axl.observations.keys()); break
|
| 1431 |
|
| 1432 |
-
|
| 1433 |
-
|
| 1434 |
-
|
|
|
|
| 1435 |
|
| 1436 |
binding_rows="".join(
|
| 1437 |
-
f"<tr><td style='color:#888;width:
|
| 1438 |
f"<td style='color:#26C6DA;font-weight:700'>{val:+.5f}</td>"
|
| 1439 |
-
f"<td style='color:#
|
| 1440 |
-
for v,val in b.items()
|
| 1441 |
-
)
|
| 1442 |
|
| 1443 |
inv_rows=""
|
| 1444 |
if best and best.get("g2_detail"):
|
| 1445 |
for inv,(err,ok) in best["g2_detail"].items():
|
| 1446 |
c="#4CAF50" if ok else "#EF5350"
|
| 1447 |
-
inv_rows+=f"<tr><td style='color:{c}'>{'β' if ok else 'β'}</td>
|
| 1448 |
-
|
| 1449 |
-
|
| 1450 |
-
|
| 1451 |
-
|
| 1452 |
-
|
| 1453 |
-
|
| 1454 |
-
|
| 1455 |
-
|
| 1456 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1457 |
|
| 1458 |
return f"""
|
| 1459 |
-
<div style='border:1px solid #
|
| 1460 |
-
<div style='background:#
|
| 1461 |
-
<span style='color:{ce_color};font-weight:700;font-size:1.
|
| 1462 |
-
<span style='color:#
|
| 1463 |
-
<span style='color:#333;
|
| 1464 |
-
<span style='color:#555;
|
|
|
|
| 1465 |
</div>
|
| 1466 |
-
<div style='display:flex
|
| 1467 |
-
<div style='flex:
|
| 1468 |
-
<div style='color:#333;font-size:0.
|
| 1469 |
-
<table style='
|
| 1470 |
-
<tr><th style='color:#333;font-size:0.75em;text-align:left'>VAR</th>
|
| 1471 |
-
<th style='color:#333;font-size:0.75em;text-align:left'>VALUE</th>
|
| 1472 |
-
<th></th></tr>
|
| 1473 |
-
{binding_rows}
|
| 1474 |
-
</table>
|
| 1475 |
</div>
|
| 1476 |
-
<div style='flex:
|
| 1477 |
-
<div style='color:#333;font-size:0.
|
| 1478 |
-
<table style='
|
| 1479 |
-
<tr><th style='color:#333;font-size:0.75em;text-align:left'>β</th>
|
| 1480 |
-
<th style='color:#333;font-size:0.75em;text-align:left'>NAME</th>
|
| 1481 |
-
<th style='color:#333;font-size:0.75em;text-align:left'>|ERR|</th></tr>
|
| 1482 |
{inv_rows or "<tr><td colspan='3' style='color:#222'>β</td></tr>"}
|
| 1483 |
</table>
|
| 1484 |
</div>
|
| 1485 |
-
<div style='flex:1;padding:
|
| 1486 |
-
<div style='color:#333;font-size:0.
|
| 1487 |
-
HYPOTHESIS TRAIL β
|
| 1488 |
-
</div>
|
| 1489 |
-
<div style='line-height:2'>{trail}</div>
|
| 1490 |
-
<div style='color:#555;font-size:0.8em;margin-top:8px'>
|
| 1491 |
-
Best domain: <span style='color:#FF9800'>{record['best_domain']}</span>
|
| 1492 |
</div>
|
|
|
|
| 1493 |
</div>
|
| 1494 |
</div>
|
| 1495 |
</div>"""
|
| 1496 |
|
| 1497 |
@app.get("/",response_class=HTMLResponse)
|
| 1498 |
async def dashboard():
|
| 1499 |
-
with STATE_LOCK: log=list(reversed(RUN_LOG[-
|
| 1500 |
-
|
| 1501 |
-
runs=len(RUN_LOG) if RUN_LOG else 0
|
| 1502 |
-
solved=sum(1 for r in RUN_LOG if r.get("solved",False))
|
| 1503 |
avg_ce=round(sum(r["ce"] for r in RUN_LOG)/max(1,runs),5) if RUN_LOG else 0
|
| 1504 |
|
| 1505 |
-
collapses="".join(_render_collapse(r) for r in log) if log else \
|
| 1506 |
-
"<div style='color:#222;padding:20px'>Warming up β first run startingβ¦</div>"
|
| 1507 |
-
|
| 1508 |
-
# Hypothesis survival summary table across all recent runs
|
| 1509 |
all_traces=[t for r in log for t in r.get("traces",[])]
|
| 1510 |
-
|
| 1511 |
for t in all_traces:
|
| 1512 |
-
|
| 1513 |
-
|
| 1514 |
-
|
|
|
|
| 1515 |
domain_rows="".join(
|
| 1516 |
f"<tr><td style='color:#FF9800'>{d}</td>"
|
| 1517 |
f"<td style='color:#aaa'>{s['tried']}</td>"
|
| 1518 |
f"<td style='color:#4CAF50'>{s['survived']}</td>"
|
| 1519 |
f"<td style='color:#EF5350'>{s['tried']-s['survived']}</td>"
|
| 1520 |
-
f"<td style='color:#26C6DA'>{round(s['total_ce']/s['tried'],
|
| 1521 |
-
f"<td style='color:#555'>{
|
| 1522 |
-
|
| 1523 |
-
|
|
|
|
|
|
|
| 1524 |
|
| 1525 |
-
|
|
|
|
|
|
|
|
|
|
| 1526 |
<meta http-equiv="refresh" content="4">
|
| 1527 |
<style>
|
| 1528 |
body{{background:#090909;color:#e0e0e0;font-family:monospace;padding:20px;max-width:1400px}}
|
| 1529 |
-
h1{{color:#26C6DA;border-bottom:1px solid #1a1a1a;padding-bottom:6px;font-size:1.
|
| 1530 |
-
h3{{color:#
|
| 1531 |
table{{width:100%;border-collapse:collapse;margin-bottom:10px}}
|
| 1532 |
-
th,td{{padding:
|
| 1533 |
-
th{{color:#
|
| 1534 |
-
.badge{{display:inline-block;padding:3px 10px;border-radius:
|
| 1535 |
</style></head><body>
|
| 1536 |
-
<h1>β Practicality
|
| 1537 |
-
<div style='color:#
|
| 1538 |
-
AXL
|
| 1539 |
</div>
|
| 1540 |
-
<div style='margin-bottom:
|
| 1541 |
<span class='badge' style='color:#aaa'>Runs: {runs}</span>
|
| 1542 |
<span class='badge' style='color:#4CAF50'>Solved: {solved}</span>
|
| 1543 |
<span class='badge' style='color:#26C6DA'>Avg BaseCE: {avg_ce}</span>
|
| 1544 |
<span class='badge' style='color:#FF9800'>Problems: {len(AXL_PROBLEMS)}</span>
|
| 1545 |
<span class='badge' style='color:#5C6BC0'>Library: {len(DEBATE_ENGINE.library)}</span>
|
| 1546 |
</div>
|
| 1547 |
-
|
| 1548 |
-
<h3>DOMAIN SURVIVAL SUMMARY</h3>
|
| 1549 |
<table>
|
| 1550 |
-
<tr><th>Domain</th><th>Tried</th><th>Survived</th><th>Failed</th><th>Avg
|
| 1551 |
{domain_rows}
|
| 1552 |
</table>
|
| 1553 |
-
|
| 1554 |
-
<h3>COLLAPSE VIEW β Recent Runs</h3>
|
| 1555 |
{collapses}
|
| 1556 |
</body></html>"""
|
| 1557 |
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
+
PRACTICALITY SYSTEM 11.1 β AXL/PSL PIPELINE
|
| 4 |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 5 |
+
FIXED IN 11.1:
|
| 6 |
+
Β· PSLTranslator now grounds domain PSL in actual base constraints
|
| 7 |
+
Domain adds SOFT structural hints (weight 0.15), never replaces base
|
| 8 |
+
Β· Observations pin variables in domain PSL (zero-width VAR bounds)
|
| 9 |
+
Β· DomainStrategy: wisdom layer informs HOW to search, not WHAT to search
|
| 10 |
+
Each domain maps to hypothesis weights + polish preference + explore trigger
|
| 11 |
+
Β· PhaseCollider redesigned to be provably feasible
|
| 12 |
+
Β· StructuralModel moved before solve_by_hypothesis (no more _SM hack)
|
| 13 |
+
Β· HypothesisOracle accepts DomainStrategy, applies confidence weights
|
| 14 |
"""
|
| 15 |
|
| 16 |
import time, random, math, threading, asyncio, warnings, itertools, json
|
|
|
|
| 32 |
warnings.filterwarnings("ignore")
|
| 33 |
USE_GPU = torch.cuda.is_available()
|
| 34 |
DEVICE = torch.device("cuda" if USE_GPU else "cpu")
|
| 35 |
+
print(f"[SYSTEM 11.1] Compute: {'GPU' if USE_GPU else 'CPU'}")
|
| 36 |
|
| 37 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 38 |
# SECTION 1: CONSTANTS
|
|
|
|
| 129 |
@dataclass
|
| 130 |
class PSLVar: name:str; lo:float; hi:float; weight:float=1.0
|
| 131 |
@dataclass
|
| 132 |
+
class PSLConstraint: kind:str; expr:str; scope:str="root"; weight:float=1.0; branches:List[str]=field(default_factory=list)
|
| 133 |
@dataclass
|
| 134 |
class PSLScope: name:str; order:int=0; depends:List[str]=field(default_factory=list); vars:List[PSLVar]=field(default_factory=list); links:List[str]=field(default_factory=list); constraints:List[PSLConstraint]=field(default_factory=list)
|
| 135 |
@dataclass
|
| 136 |
+
class PSLProgram: name:str; vars:List[PSLVar]; constraints:List[PSLConstraint]; scopes:List[PSLScope]; scope_order:List[str]; annotations:Dict[str,str]=field(default_factory=dict)
|
|
|
|
|
|
|
|
|
|
| 137 |
|
| 138 |
def parse_psl(text:str) -> PSLProgram:
|
| 139 |
lines=[l.strip() for l in text.strip().split('\n') if l.strip() and not l.strip().startswith('#')]
|
|
|
|
| 142 |
def advance():
|
| 143 |
nonlocal i; l=lines[i]; i+=1; return l
|
| 144 |
def peek(): return lines[i] if i<len(lines) else ""
|
| 145 |
+
def pvar(rest):
|
| 146 |
p=rest.split()
|
| 147 |
+
return PSLVar(p[0],float(p[1]),float(p[2])) if len(p)>=3 else None
|
| 148 |
+
def pw(rest):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
if 'WEIGHT' in rest:
|
| 150 |
+
p=rest.split('WEIGHT'); return p[0].strip(), float(p[1].split()[0])
|
| 151 |
return rest.strip(), 1.0
|
| 152 |
+
def parse_scope_body(sname,order=0,depends=None):
|
| 153 |
svars,scons,links=[],[],[]
|
| 154 |
while i<len(lines):
|
| 155 |
l=peek(); tk=l.split(None,1)
|
|
|
|
| 159 |
if kw=="VAR":
|
| 160 |
v=pvar(rest)
|
| 161 |
if v: svars.append(v)
|
| 162 |
+
elif kw=="LINK": links.extend(rest.split())
|
|
|
|
| 163 |
elif kw in ("EQ","GEQ","LEQ"):
|
| 164 |
+
expr,wt=pw(rest); scons.append(PSLConstraint(kw.lower(),expr,scope=sname,weight=wt))
|
|
|
|
| 165 |
elif kw=="CONSERVE":
|
| 166 |
+
expr,_=pw(rest); scons.append(PSLConstraint("eq",expr,scope=sname,weight=10.0))
|
|
|
|
| 167 |
elif kw=="BRANCH":
|
| 168 |
opts=[]
|
| 169 |
+
while i<len(lines) and not peek().upper().startswith("END"):
|
| 170 |
bl=advance()
|
| 171 |
if bl.upper().startswith("OPTION"): opts.append(bl.split(None,1)[1].strip())
|
| 172 |
+
advance()
|
| 173 |
scons.append(PSLConstraint("or_eq","",scope=sname,weight=1.0,branches=opts))
|
| 174 |
elif kw=="ANNOTATE":
|
| 175 |
parts=rest.split()
|
|
|
|
| 184 |
v=pvar(rest)
|
| 185 |
if v: prog.vars.append(v)
|
| 186 |
elif kw in ("EQ","GEQ","LEQ"):
|
| 187 |
+
expr,wt=pw(rest); prog.constraints.append(PSLConstraint(kw.lower(),expr,weight=wt))
|
|
|
|
| 188 |
elif kw=="CONSERVE":
|
| 189 |
+
expr,_=pw(rest); prog.constraints.append(PSLConstraint("eq",expr,weight=10.0))
|
|
|
|
| 190 |
elif kw=="BRANCH":
|
| 191 |
opts=[]
|
| 192 |
while i<len(lines) and not peek().upper().startswith("END"):
|
|
|
|
| 208 |
idx=rest.upper().index("DEPENDS")
|
| 209 |
depends=rest[idx:].split()[1:]
|
| 210 |
sc=parse_scope_body(sname,order,depends)
|
| 211 |
+
prog.scopes.append(sc); prog.scope_order.append(sname)
|
| 212 |
+
prog.scopes.sort(key=lambda s:s.order)
|
|
|
|
| 213 |
prog.scope_order=[s.name for s in prog.scopes]
|
| 214 |
return prog
|
| 215 |
|
|
|
|
| 217 |
class ExpandedProblem:
|
| 218 |
variables:List[str]; bounds:Dict[str,Tuple[float,float]]
|
| 219 |
constraints:List['Constraint']
|
| 220 |
+
scope_groups:Dict[str,List[int]]; scope_vars:Dict[str,List[str]]
|
| 221 |
+
scope_order:List[str]; annotations:Dict[str,str]=field(default_factory=dict)
|
| 222 |
|
| 223 |
def expand_psl(prog:PSLProgram) -> ExpandedProblem:
|
| 224 |
variables=[]; bounds={}; constraints=[]
|
|
|
|
| 264 |
prog.scope_order,prog.annotations)
|
| 265 |
|
| 266 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 267 |
+
# SECTION 4: AXL LAYER
|
| 268 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 269 |
@dataclass
|
| 270 |
class AXLInvariant:
|
| 271 |
+
name:str; expr:str; tolerance:float=VERIFY_G2_TOLERANCE
|
|
|
|
|
|
|
| 272 |
|
| 273 |
@dataclass
|
| 274 |
class AXLProblemDef:
|
| 275 |
+
name:str; description:str; axioms:Set[str]
|
| 276 |
+
variables:List[Dict]; constraints:List[Dict]
|
| 277 |
+
scopes:List[Dict]; anchors:List[AXLInvariant]
|
| 278 |
+
observations:Dict[str,float]=field(default_factory=dict)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
def variables_list(self): return [v["name"] for v in self.variables]
|
| 280 |
|
| 281 |
class AXLtoPSLCompiler:
|
| 282 |
+
"""Compile AXL directly to PSL β used only for the BASE problem oracle."""
|
| 283 |
+
TEND_WEIGHT=0.3
|
| 284 |
+
def compile(self,prob:AXLProblemDef) -> str:
|
| 285 |
+
lines=[f"SPACE base_{prob.name}"]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
for v in prob.variables:
|
| 287 |
+
lo,hi=v["lo"],v["hi"]
|
|
|
|
| 288 |
if v["name"] in prob.observations:
|
| 289 |
+
val=prob.observations[v["name"]]; lo=hi=val
|
|
|
|
| 290 |
lines.append(f"VAR {v['name']} {lo} {hi}")
|
|
|
|
| 291 |
lines.append(f"ANNOTATE {v['name']} FROM_AXL {prob.name}.{v['name']}")
|
|
|
|
|
|
|
| 292 |
for c in prob.constraints:
|
| 293 |
+
wt=c.get("weight",1.0)
|
| 294 |
+
if c["kind"]=="CONSERVE": lines.append(f"CONSERVE {c['expr']}")
|
| 295 |
+
elif c["kind"]=="BRANCH":
|
| 296 |
+
lines.append(f"BRANCH {c.get('name','br')}")
|
| 297 |
+
for opt in c.get("options",[]): lines.append(f" OPTION {opt}")
|
| 298 |
+
lines.append("END BRANCH")
|
| 299 |
+
else: lines.append(f"{c['kind']} {c['expr']} WEIGHT {wt}")
|
|
|
|
| 300 |
for v in prob.variables:
|
| 301 |
+
tends=v.get("tends","")
|
| 302 |
+
if tends=="MIN": lines.append(f"EQ {v['name']} - {v['lo']} WEIGHT {self.TEND_WEIGHT}")
|
| 303 |
+
elif tends=="MAX": lines.append(f"EQ {v['name']} - {v['hi']} WEIGHT {self.TEND_WEIGHT}")
|
| 304 |
+
elif tends.startswith("TOWARD:"): lines.append(f"EQ {v['name']} - {tends.split(':')[1]} WEIGHT {self.TEND_WEIGHT}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
for sc in prob.scopes:
|
| 306 |
+
dep=f" DEPENDS {' '.join(sc.get('depends',[]))}" if sc.get('depends') else ""
|
| 307 |
+
lines.append(f"SCOPE {sc['name']} ORDER {sc.get('order',0)}{dep}")
|
| 308 |
+
if sc.get("vars"): lines.append(f" LINK {' '.join(sc['vars'])}")
|
| 309 |
+
for c in sc.get("constraints",[]):
|
| 310 |
+
wt=c.get("weight",1.0)
|
| 311 |
+
if c["kind"]=="CONSERVE": lines.append(f" CONSERVE {c['expr']}")
|
| 312 |
+
elif c["kind"]=="BRANCH":
|
|
|
|
|
|
|
|
|
|
| 313 |
lines.append(f" BRANCH {c.get('name','br')}")
|
| 314 |
+
for opt in c.get("options",[]): lines.append(f" OPTION {opt}")
|
|
|
|
| 315 |
lines.append(" END BRANCH")
|
| 316 |
+
else: lines.append(f" {c['kind']} {c['expr']} WEIGHT {wt}")
|
|
|
|
| 317 |
lines.append("END")
|
|
|
|
| 318 |
return "\n".join(lines)
|
| 319 |
|
| 320 |
+
AXL_COMPILER=AXLtoPSLCompiler()
|
| 321 |
|
| 322 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 323 |
# SECTION 5: PROBLEM & CONSTRAINT COMPILATION
|
|
|
|
| 333 |
fast_iv:Optional[Callable]=field(default=None,repr=False)
|
| 334 |
fast_pt:Optional[Callable]=field(default=None,repr=False)
|
| 335 |
fast_np:Optional[Callable]=field(default=None,repr=False)
|
|
|
|
| 336 |
syms_used:List[str]=field(default_factory=list)
|
| 337 |
parsed:Optional[sp.Expr]=field(default=None,repr=False)
|
| 338 |
scope:str="root"
|
|
|
|
| 364 |
mc.fast_iv=compile_iv(parsed,variables)
|
| 365 |
mc.fast_pt=sp.lambdify([sp.Symbol(v) for v in mc.syms_used],parsed,modules="math")
|
| 366 |
mc.fast_np=sp.lambdify([sp.Symbol(v) for v in mc.syms_used],parsed,modules="numpy")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
fast_jac={}
|
| 368 |
for v in mc.syms_used:
|
| 369 |
try:
|
|
|
|
| 377 |
for sym in parsed.free_symbols:
|
| 378 |
v_str=str(sym)
|
| 379 |
try:
|
| 380 |
+
sols=sp.solve(parsed,sym); pm[v_str]=[]
|
|
|
|
| 381 |
for sol in sols:
|
| 382 |
fs=list(sol.free_symbols)
|
| 383 |
pm[v_str].append({"syms":[str(s) for s in fs],"func":sp.lambdify(fs,sol,modules="math")})
|
|
|
|
| 389 |
|
| 390 |
@dataclass
|
| 391 |
class Problem:
|
| 392 |
+
pid:str; variables:List[str]; constraints:List[Constraint]; bounds:Dict[str,Tuple[float,float]]
|
|
|
|
| 393 |
tier:str="hard"
|
| 394 |
scope_groups:Dict[str,List[int]]=field(default_factory=dict)
|
| 395 |
scope_vars:Dict[str,List[str]]=field(default_factory=dict)
|
|
|
|
| 415 |
if mc.fast_pt is None: total+=1.0; continue
|
| 416 |
try:
|
| 417 |
val=float(mc.fast_pt(*[b.get(v,0.0) for v in mc.syms_used]))
|
| 418 |
+
if mc.kind=="equality": total+=abs(val)*mc.weight
|
| 419 |
+
elif mc.direction=="geq": total+=max(0.0,-val)*mc.weight
|
| 420 |
+
else: total+=max(0.0,val)*mc.weight
|
| 421 |
except: total+=1.0
|
| 422 |
for v,(lo,hi) in self.bounds.items():
|
| 423 |
bv=b.get(v,0.0); total+=max(0.0,lo-bv)+max(0.0,bv-hi)
|
|
|
|
| 468 |
for bmc in mc.branches:
|
| 469 |
if bmc.fast_np:
|
| 470 |
try:
|
| 471 |
+
args=[b_matrix[:,vti[v]] for v in bmc.syms_used if v in vti]
|
| 472 |
+
if len(args)!=len(bmc.syms_used): continue
|
| 473 |
val=bmc.fast_np(*args)
|
| 474 |
if not isinstance(val,np.ndarray): val=np.full(N,float(val),dtype=np.float32)
|
| 475 |
bv.append(np.abs(val))
|
|
|
|
| 479 |
else:
|
| 480 |
if mc.fast_np is None: total+=1.0; continue
|
| 481 |
try:
|
| 482 |
+
args=[b_matrix[:,vti[v]] for v in mc.syms_used if v in vti]
|
| 483 |
+
if len(args)!=len(mc.syms_used): total+=1.0; continue
|
| 484 |
val=mc.fast_np(*args)
|
| 485 |
if not isinstance(val,np.ndarray): val=np.full(N,float(val),dtype=np.float32)
|
| 486 |
if mc.kind=="equality": total+=np.abs(val)*mc.weight
|
|
|
|
| 497 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 498 |
@dataclass
|
| 499 |
class VerifyResult:
|
| 500 |
+
gate1_ce:float; gate1_pass:bool
|
| 501 |
+
gate2_results:Dict[str,Tuple[float,bool]]
|
| 502 |
+
gate2_pass:bool; overall_pass:bool
|
| 503 |
+
failed_gates:List[str]=field(default_factory=list)
|
|
|
|
|
|
|
| 504 |
|
| 505 |
class VerifyLayer:
|
| 506 |
+
def run(self,binding:Dict[str,float],base_problem:Problem,anchors:List[AXLInvariant]) -> VerifyResult:
|
| 507 |
+
g1_ce=base_problem.constraint_energy(binding)
|
| 508 |
+
g1_pass=g1_ce<VERIFY_G1_THRESHOLD
|
| 509 |
+
g2={}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 510 |
for inv in anchors:
|
| 511 |
try:
|
| 512 |
+
syms={v:sp.Symbol(v) for v in binding}
|
| 513 |
+
expr=parse_expr(inv.expr,local_dict=syms)
|
| 514 |
+
func=sp.lambdify(list(expr.free_symbols),expr,modules="math")
|
| 515 |
+
args=[binding.get(str(s),0.0) for s in expr.free_symbols]
|
| 516 |
+
err=abs(float(func(*args)))
|
| 517 |
+
g2[inv.name]=(round(err,6),err<inv.tolerance)
|
| 518 |
+
except: g2[inv.name]=(999.0,False)
|
| 519 |
+
g2_pass=all(v[1] for v in g2.values()) if g2 else True
|
| 520 |
+
failed=(["Gate1"] if not g1_pass else [])+[k for k,v in g2.items() if not v[1]]
|
| 521 |
+
return VerifyResult(gate1_ce=round(g1_ce,6),gate1_pass=g1_pass,
|
| 522 |
+
gate2_results=g2,gate2_pass=g2_pass,
|
| 523 |
+
overall_pass=g1_pass and g2_pass,failed_gates=failed)
|
| 524 |
+
|
| 525 |
+
VERIFY_LAYER=VerifyLayer()
|
| 526 |
|
| 527 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 528 |
+
# SECTION 7: DOMAIN STRATEGY β NEW
|
| 529 |
+
# Wisdom layer informs HOW to search, not WHAT to search.
|
| 530 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 531 |
+
@dataclass
|
| 532 |
+
class DomainStrategy:
|
| 533 |
+
name: str
|
| 534 |
+
hyp_weights: Dict[str,float] # h_type β confidence multiplier
|
| 535 |
+
polish: str # "adam" | "gradient" | "both"
|
| 536 |
+
explore_early: bool # True β explore_trigger=2, False β 4
|
| 537 |
+
scope_priority: str # "ordered" | "hub" | "natural"
|
| 538 |
+
note: str=""
|
| 539 |
+
|
| 540 |
+
DOMAIN_STRATEGIES: Dict[str,DomainStrategy] = {
|
| 541 |
+
"NormManifold": DomainStrategy("NormManifold",
|
| 542 |
+
{"branch":1.3,"manifold":2.0,"chain":0.8,"residual_chain":1.1},
|
| 543 |
+
"adam", False, "hub",
|
| 544 |
+
"Quadratic manifolds β manifold tangents most useful; Adam navigates smooth bowl"),
|
| 545 |
+
"MetricPacking": DomainStrategy("MetricPacking",
|
| 546 |
+
{"branch":1.2,"manifold":0.8,"chain":1.5,"residual_chain":1.2},
|
| 547 |
+
"gradient", True, "hub",
|
| 548 |
+
"Separation constraints β algebraic branches + early exploration"),
|
| 549 |
+
"SequentialChain": DomainStrategy("SequentialChain",
|
| 550 |
+
{"branch":0.9,"manifold":0.5,"chain":2.0,"residual_chain":1.5},
|
| 551 |
+
"gradient", False, "ordered",
|
| 552 |
+
"Ordered chains β topology chain hypotheses dominate"),
|
| 553 |
+
"BilinearCoupling":DomainStrategy("BilinearCoupling",
|
| 554 |
+
{"branch":1.3,"manifold":1.6,"chain":1.0,"residual_chain":1.0},
|
| 555 |
+
"adam", False, "natural",
|
| 556 |
+
"Bilinear products β manifold + branch both useful; Adam for coupling"),
|
| 557 |
+
"PhaseJump": DomainStrategy("PhaseJump",
|
| 558 |
+
{"branch":2.0,"manifold":1.0,"chain":0.7,"residual_chain":0.9},
|
| 559 |
+
"adam", True, "natural",
|
| 560 |
+
"OR constraints β branch hypotheses highest priority; explore early"),
|
| 561 |
+
"GraphSpace": DomainStrategy("GraphSpace",
|
| 562 |
+
{"branch":1.0,"manifold":0.7,"chain":1.3,"residual_chain":1.0},
|
| 563 |
+
"gradient", False, "hub",
|
| 564 |
+
"Network hubs β chain + gradient works well"),
|
| 565 |
+
"HierarchicalTree":DomainStrategy("HierarchicalTree",
|
| 566 |
+
{"branch":0.9,"manifold":0.6,"chain":1.8,"residual_chain":1.2},
|
| 567 |
+
"gradient", False, "ordered",
|
| 568 |
+
"Hierarchical ordering β chain hypotheses + ordered scope priority"),
|
| 569 |
+
"DiscreteSchedule":DomainStrategy("DiscreteSchedule",
|
| 570 |
+
{"branch":1.0,"manifold":0.5,"chain":2.0,"residual_chain":1.3},
|
| 571 |
+
"gradient", False, "ordered",
|
| 572 |
+
"Scheduling β chain + ordering; manifold less useful for discrete"),
|
| 573 |
+
"FluidContinuum": DomainStrategy("FluidContinuum",
|
| 574 |
+
{"branch":1.1,"manifold":1.8,"chain":0.8,"residual_chain":1.0},
|
| 575 |
+
"adam", True, "natural",
|
| 576 |
+
"Continuous flow β manifold tangents + Adam; explore broadly"),
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
DEFAULT_STRATEGY=DomainStrategy("Default",
|
| 580 |
+
{"branch":1.0,"manifold":1.0,"chain":1.0,"residual_chain":1.0},
|
| 581 |
+
"both", False, "natural")
|
| 582 |
+
|
| 583 |
+
def get_strategy(domain_name:str) -> DomainStrategy:
|
| 584 |
+
# Check exact match, then prefix match for derived domains (unions, duals)
|
| 585 |
+
if domain_name in DOMAIN_STRATEGIES: return DOMAIN_STRATEGIES[domain_name]
|
| 586 |
+
for k,v in DOMAIN_STRATEGIES.items():
|
| 587 |
+
if k in domain_name: return v
|
| 588 |
+
return DEFAULT_STRATEGY
|
| 589 |
|
| 590 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 591 |
+
# SECTION 8: SHARED TYPES (before solve_by_hypothesis to avoid forward refs)
|
| 592 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 593 |
+
@dataclass
|
| 594 |
+
class Hypothesis:
|
| 595 |
+
hid:str; binding:Dict[str,float]; h_type:str; claim:str
|
| 596 |
+
derivation:List[str]; pinned_vars:Dict[str,float]; free_vars:List[str]
|
| 597 |
+
confidence:float; ce:float=float('inf')
|
| 598 |
|
| 599 |
+
@dataclass
|
| 600 |
+
class HypothesisTrace:
|
| 601 |
+
hid:str; round_idx:int; domain_name:str; action:str
|
| 602 |
+
ce_before:float; ce_after:float
|
| 603 |
+
verify:Optional[VerifyResult]; survived:bool; elapsed_ms:float
|
| 604 |
+
strategy_note:str=""
|
| 605 |
+
|
| 606 |
+
@dataclass
|
| 607 |
+
class StructuralModel:
|
| 608 |
+
best_binding:Dict[str,float]; best_ce:float
|
| 609 |
+
tested:List[Hypothesis]=field(default_factory=list)
|
| 610 |
+
failure_patterns:Set[str]=field(default_factory=set)
|
| 611 |
+
scope_witnesses:Dict[str,Dict[str,Tuple]]=field(default_factory=dict)
|
| 612 |
+
confirmed_ranges:Dict[str,Tuple[float,float]]=field(default_factory=dict)
|
| 613 |
+
conflict_vars:Set[str]=field(default_factory=set)
|
| 614 |
|
| 615 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 616 |
+
# SECTION 9: ORACLES
|
| 617 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 618 |
@dataclass
|
| 619 |
class L7Certificate: topology_sig:str; hub_vars:List[str]; solve_order:List[str]
|
|
|
|
| 676 |
re=[e for e,c in sorted(de,key=lambda x:-x[1])[:5]]
|
| 677 |
return L9Certificate(round(ce,6),rv,re)
|
| 678 |
|
| 679 |
+
TOPOLOGY_ORACLE=TopologyOracle()
|
| 680 |
+
COHERENCE_ORACLE=CoherenceOracle()
|
| 681 |
+
RESIDUAL_ORACLE=ResidualOracle()
|
| 682 |
|
| 683 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 684 |
+
# SECTION 10: CORE SOLVERS
|
| 685 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 686 |
def _hc4(box,constraints):
|
| 687 |
cur=dict(box)
|
|
|
|
| 700 |
try:
|
| 701 |
riv=mc.fast_iv(cur)
|
| 702 |
if ((mc.kind=="equality" and not riv.contains_zero()) or
|
| 703 |
+
(mc.kind=="inequality" and ((mc.direction=="geq" and riv.hi<-1e-10) or
|
| 704 |
+
(mc.direction=="leq" and riv.lo>1e-10)))):
|
| 705 |
return None
|
| 706 |
except: pass
|
| 707 |
return cur
|
|
|
|
| 793 |
if nce<best_ce: best_ce=nce; best_b=dict(b)
|
| 794 |
return best_b,best_ce
|
| 795 |
|
| 796 |
+
def solve_by_hypothesis(problem:Problem, budget:int=TOTAL_BUDGET,
|
| 797 |
+
strategy:Optional[DomainStrategy]=None) -> Dict:
|
| 798 |
t0=time.time()
|
| 799 |
+
explore_trigger = 2 if (strategy and strategy.explore_early) else 4
|
| 800 |
+
polish_pref = strategy.polish if strategy else "both"
|
| 801 |
+
|
| 802 |
init_b={v:max(lo,min(hi,(lo+hi)/2)) for v,(lo,hi) in problem.bounds.items()}
|
| 803 |
tb=_global_hc4_tighten(problem)
|
| 804 |
full_box={v:IV(tb[v][0],tb[v][1]) for v in problem.variables if v in tb}
|
|
|
|
| 806 |
if mprt_ce<problem.constraint_energy(init_b): init_b=mprt_b
|
| 807 |
snap_b,snap_ce=_algebraic_snap(problem,init_b)
|
| 808 |
if snap_ce<problem.constraint_energy(init_b): init_b=snap_b
|
| 809 |
+
|
| 810 |
+
model=StructuralModel(best_binding=dict(init_b),best_ce=problem.constraint_energy(init_b))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 811 |
active_scopes=[s for s in problem.scope_order if s!="root" and problem.scope_vars.get(s)]
|
| 812 |
+
|
| 813 |
if model.best_ce<SOLVE_THRESHOLD:
|
| 814 |
l7=TOPOLOGY_ORACLE.evaluate(problem,active_scopes)
|
| 815 |
l9=RESIDUAL_ORACLE.evaluate(model.best_binding,problem,l7.hub_vars)
|
| 816 |
+
return {"binding":model.best_binding,"ce":model.best_ce,"solved":True,
|
| 817 |
+
"l7":l7,"l9":l9,"time":round(time.time()-t0,3)}
|
| 818 |
|
| 819 |
+
oracle=HypothesisOracle(strategy=strategy); consec=0
|
| 820 |
for round_idx in range(HYPOTHESIS_MAX_ROUNDS):
|
| 821 |
if model.best_ce<SOLVE_THRESHOLD: break
|
| 822 |
l7=TOPOLOGY_ORACLE.evaluate(problem,active_scopes)
|
|
|
|
| 840 |
eb,ece=_mprt_sample(problem,work_box,N_MPRT_EXPLORE)
|
| 841 |
if ece<model.best_ce: model.best_ce=ece; model.best_binding=dict(eb); consec=0
|
| 842 |
|
| 843 |
+
# Polish β strategy-directed
|
| 844 |
+
if polish_pref in ("gradient","both") and SOLVE_THRESHOLD<model.best_ce<2.0:
|
| 845 |
gb,gce=_gradient_polish(problem,model.best_binding)
|
| 846 |
if gce<model.best_ce: model.best_ce=gce; model.best_binding=gb
|
| 847 |
+
if polish_pref in ("adam","both") and SOLVE_THRESHOLD<model.best_ce<1.0:
|
| 848 |
ab,ace=_adam_polish(problem,model.best_binding)
|
| 849 |
if ace<model.best_ce: model.best_ce=ace; model.best_binding=ab
|
| 850 |
+
# Always try Adam as last resort if still not solved
|
| 851 |
+
if SOLVE_THRESHOLD<model.best_ce<0.5 and polish_pref=="gradient":
|
| 852 |
+
ab,ace=_adam_polish(problem,model.best_binding,steps=60)
|
| 853 |
+
if ace<model.best_ce: model.best_ce=ace; model.best_binding=ab
|
| 854 |
|
| 855 |
final_l7=TOPOLOGY_ORACLE.evaluate(problem,active_scopes)
|
| 856 |
final_l9=RESIDUAL_ORACLE.evaluate(model.best_binding,problem,final_l7.hub_vars)
|
|
|
|
| 858 |
"l7":final_l7,"l9":final_l9,"time":round(time.time()-t0,3)}
|
| 859 |
|
| 860 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 861 |
+
# SECTION 11: HYPOTHESIS ENGINE
|
| 862 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 863 |
class HypothesisOracle:
|
| 864 |
+
def __init__(self, strategy:Optional[DomainStrategy]=None):
|
| 865 |
+
self.strategy=strategy
|
| 866 |
+
|
| 867 |
def generate(self,problem,model,l7,l8,l9,round_idx):
|
| 868 |
hyps=[]
|
| 869 |
hyps.extend(self._branch_hypotheses(problem,model,l9))
|
|
|
|
| 871 |
hyps.extend(self._coherence_hypotheses(problem,model,l8))
|
| 872 |
hyps.extend(self._residual_chain_hypotheses(problem,model,l9))
|
| 873 |
if round_idx>=3: hyps.extend(self._manifold_tangent_hypotheses(problem,model,l9))
|
| 874 |
+
# Apply strategy confidence weights
|
| 875 |
+
if self.strategy:
|
| 876 |
+
for hyp in hyps:
|
| 877 |
+
w=self.strategy.hyp_weights.get(hyp.h_type,1.0)
|
| 878 |
+
hyp.confidence=min(0.99,hyp.confidence*w)
|
| 879 |
hyps=[h for h in hyps if h.hid not in model.failure_patterns]
|
| 880 |
return sorted(hyps,key=lambda h:-h.confidence)
|
| 881 |
|
|
|
|
| 891 |
val=float(proj["func"](*[ref.get(s,0.0) for s in proj["syms"]]))
|
| 892 |
if not math.isfinite(val) or abs(val)>1e6 or not(lo<=val<=hi): continue
|
| 893 |
b=dict(ref); b[v]=val
|
| 894 |
+
hyps.append(Hypothesis(hid=f"br_{hash(expr_str)%9999}_{v}_{pi}",
|
| 895 |
+
binding=b,h_type="branch",claim=f"AlgBranch:{v}={val:.4f}",
|
| 896 |
+
derivation=[expr_str],pinned_vars={v:val},
|
| 897 |
+
free_vars=[u for u in problem.variables if u!=v],
|
| 898 |
confidence=0.85 if pi==0 else 0.70))
|
| 899 |
except: pass
|
| 900 |
return hyps
|
|
|
|
| 907 |
if not svars: continue
|
| 908 |
scope_mcs=[problem.compiled_constraints[i] for i in problem.scope_groups.get(sn,[])]
|
| 909 |
if not scope_mcs: continue
|
| 910 |
+
start_box={v:IV(*tb.get(v,problem.bounds.get(v,(-10,10)))) for v in svars if v in problem.bounds}
|
| 911 |
cont=_hc4(start_box,scope_mcs)
|
| 912 |
if cont:
|
| 913 |
for v,iv in cont.items():
|
| 914 |
b[v]=iv.mid()
|
| 915 |
chain_steps.append(sn)
|
| 916 |
if chain_steps:
|
| 917 |
+
hyps.append(Hypothesis(
|
| 918 |
+
hid=f"chain_{'_'.join(c[:4] for c in chain_steps)}",
|
| 919 |
+
binding=b,h_type="chain",claim=f"TopoChain({' β '.join(chain_steps)})",
|
| 920 |
+
derivation=chain_steps,
|
| 921 |
+
pinned_vars={v:b[v] for sn in chain_steps for v in problem.scope_vars.get(sn,[]) if v in b},
|
| 922 |
free_vars=[v for v in problem.variables if not any(v in problem.scope_vars.get(sn,[]) for sn in chain_steps)],
|
| 923 |
confidence=0.80))
|
| 924 |
return hyps
|
|
|
|
| 929 |
for v,(lo,hi) in l8.tightened_bounds.items():
|
| 930 |
if v in problem.bounds: b[v]=(lo+hi)/2.0
|
| 931 |
return [Hypothesis(hid=f"coh_{hash(tuple(sorted(l8.incoherent_vars)))%9999}",
|
| 932 |
+
binding=b,h_type="coherence",claim=f"CoherMeet({', '.join(list(l8.incoherent_vars)[:3])})",
|
| 933 |
derivation=list(l8.incoherent_vars),
|
| 934 |
pinned_vars={v:b[v] for v in l8.incoherent_vars if v in b},
|
| 935 |
+
free_vars=[v for v in problem.variables if v not in l8.incoherent_vars],
|
| 936 |
+
confidence=0.70)]
|
| 937 |
|
| 938 |
def _residual_chain_hypotheses(self,problem,model,l9):
|
| 939 |
if not l9.dominant_vars: return []
|
|
|
|
| 1008 |
return best_b,best_ce
|
| 1009 |
|
| 1010 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1011 |
+
# SECTION 12: WISDOM LAYER
|
| 1012 |
+
# The PSLTranslator is the core fix:
|
| 1013 |
+
# domain PSL = base constraints (real, full weight) +
|
| 1014 |
+
# soft domain structural hints (weight 0.15)
|
| 1015 |
+
# observations pin variables via zero-width VAR bounds
|
| 1016 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1017 |
class Axiom:
|
| 1018 |
DISCRETE="DISCRETE"; CONTINUOUS="CONTINUOUS"; METRIC="METRIC"; NETWORK="NETWORK"
|
|
|
|
| 1020 |
QUADRATIC="QUADRATIC"; BILINEAR="BILINEAR"; ORDERED="ORDERED"; SYMMETRIC="SYMMETRIC"
|
| 1021 |
TRANSITIVE="TRANSITIVE"; ATOMIC="ATOMIC"; COMPOSITE="COMPOSITE"
|
| 1022 |
|
| 1023 |
+
AXIOM_CONTRADICTIONS=[
|
| 1024 |
+
{Axiom.DISCRETE,Axiom.CONTINUOUS},{Axiom.INJECTIVE,Axiom.SURJECTIVE},
|
| 1025 |
+
{Axiom.ORDERED,Axiom.SYMMETRIC},{Axiom.ATOMIC,Axiom.COMPOSITE},
|
| 1026 |
+
{Axiom.CONSERVED,Axiom.MUTABLE}]
|
| 1027 |
|
| 1028 |
@dataclass
|
| 1029 |
class AbstractDomain:
|
| 1030 |
name:str; axioms:Set[str]; derivation:str="Base"; confidence:float=1.0
|
| 1031 |
+
def is_consistent(self): return not any(p.issubset(self.axioms) for p in AXIOM_CONTRADICTIONS)
|
|
|
|
|
|
|
| 1032 |
|
| 1033 |
BASE_LIBRARY=[
|
| 1034 |
AbstractDomain("GraphSpace",{Axiom.DISCRETE,Axiom.NETWORK,Axiom.SYMMETRIC,Axiom.ATOMIC}),
|
|
|
|
| 1048 |
@staticmethod
|
| 1049 |
def union(d1,d2):
|
| 1050 |
merged=d1.axioms|d2.axioms
|
| 1051 |
+
c=AbstractDomain(WisdomOps._fn(f"{d1.name}U{d2.name}"),merged,"Union",(d1.confidence+d2.confidence)/2)
|
| 1052 |
for pair in AXIOM_CONTRADICTIONS:
|
| 1053 |
if pair.issubset(c.axioms):
|
| 1054 |
counts={ax:sum(ax in d.axioms for d in BASE_LIBRARY) for ax in pair}
|
| 1055 |
c.axioms.discard(min(counts,key=counts.get))
|
| 1056 |
return c
|
| 1057 |
@staticmethod
|
| 1058 |
+
def relax(d,axioms): return AbstractDomain(WisdomOps._fn(f"{d.name}_Rlx"),d.axioms-axioms,"Relax",d.confidence*0.85)
|
| 1059 |
@staticmethod
|
| 1060 |
def inject(d,axioms):
|
| 1061 |
+
merged=d.axioms|axioms; ax_str="".join(a[:2] for a in axioms)
|
| 1062 |
+
c=AbstractDomain(WisdomOps._fn(f"{d.name}+{ax_str}"),merged,"Inject",d.confidence*0.9)
|
|
|
|
| 1063 |
for pair in AXIOM_CONTRADICTIONS:
|
| 1064 |
if pair.issubset(c.axioms):
|
| 1065 |
to_rm=pair-d.axioms
|
|
|
|
| 1075 |
return AbstractDomain(WisdomOps._fn(f"{d.name}*"),{fm.get(ax,ax) for ax in d.axioms},"Dual",d.confidence*0.7)
|
| 1076 |
|
| 1077 |
class PSLTranslator:
|
| 1078 |
+
"""
|
| 1079 |
+
THE CORE FIX.
|
| 1080 |
+
Generates domain PSL = base constraints (full weight) + soft domain hints (0.15).
|
| 1081 |
+
Observations are pinned via zero-width VAR bounds.
|
| 1082 |
+
Domain NEVER replaces the base problem β it only adds soft guidance.
|
| 1083 |
+
"""
|
| 1084 |
+
SOFT = 0.15
|
| 1085 |
+
|
| 1086 |
+
def compile(self, domain:AbstractDomain, axl_def:AXLProblemDef) -> str:
|
| 1087 |
+
ax=domain.axioms; variables=axl_def.variables_list(); n=len(variables)
|
| 1088 |
+
lines=[f"SPACE domain_{domain.name.replace(' ','_')}"]
|
| 1089 |
+
|
| 1090 |
+
# ββ 1. Variables: use actual bounds, pin observations ββββββββββ
|
| 1091 |
+
for v in axl_def.variables:
|
| 1092 |
+
lo,hi=v["lo"],v["hi"]
|
| 1093 |
+
if v["name"] in axl_def.observations:
|
| 1094 |
+
val=axl_def.observations[v["name"]]; lo=hi=val # PINNED
|
| 1095 |
+
lines.append(f"VAR {v['name']} {lo} {hi}")
|
| 1096 |
+
|
| 1097 |
+
# ββ 2. Base global constraints β ALWAYS, full weight βββββββββββ
|
| 1098 |
+
for c in axl_def.constraints:
|
| 1099 |
+
wt=c.get("weight",1.0)
|
| 1100 |
+
if c["kind"]=="CONSERVE":
|
| 1101 |
+
lines.append(f"CONSERVE {c['expr']}")
|
| 1102 |
+
elif c["kind"]=="BRANCH":
|
| 1103 |
+
lines.append(f"BRANCH {c.get('name','br')}")
|
| 1104 |
+
for opt in c.get("options",[]): lines.append(f" OPTION {opt}")
|
| 1105 |
+
lines.append("END BRANCH")
|
| 1106 |
+
else:
|
| 1107 |
+
lines.append(f"{c['kind']} {c['expr']} WEIGHT {wt}")
|
| 1108 |
+
|
| 1109 |
+
# ββ 3. Base scopes β ALWAYS, at their original ORDER ββββββββββ
|
| 1110 |
+
for sc in axl_def.scopes:
|
| 1111 |
+
order=sc.get("order",0)
|
| 1112 |
+
dep=f" DEPENDS {' '.join(sc.get('depends',[]))}" if sc.get('depends') else ""
|
| 1113 |
+
lines.append(f"SCOPE {sc['name']} ORDER {order}{dep}")
|
| 1114 |
+
if sc.get("vars"): lines.append(f" LINK {' '.join(sc['vars'])}")
|
| 1115 |
+
for c in sc.get("constraints",[]):
|
| 1116 |
+
wt=c.get("weight",1.0)
|
| 1117 |
+
if c["kind"]=="CONSERVE":
|
| 1118 |
+
lines.append(f" CONSERVE {c['expr']}")
|
| 1119 |
+
elif c["kind"]=="BRANCH":
|
| 1120 |
+
lines.append(f" BRANCH {c.get('name','br')}")
|
| 1121 |
+
for opt in c.get("options",[]): lines.append(f" OPTION {opt}")
|
| 1122 |
+
lines.append(" END BRANCH")
|
| 1123 |
+
else:
|
| 1124 |
+
lines.append(f" {c['kind']} {c['expr']} WEIGHT {wt}")
|
| 1125 |
+
lines.append("END")
|
| 1126 |
+
|
| 1127 |
+
# ββ 4. Soft domain structural hints β ORDER 100+, weight 0.15 β
|
| 1128 |
+
# These nudge the search without overriding base constraints.
|
| 1129 |
+
si=100
|
| 1130 |
+
|
| 1131 |
+
if Axiom.ORDERED in ax and Axiom.BILINEAR not in ax and n>=2:
|
| 1132 |
+
lines.append(f"SCOPE domain_order ORDER {si}")
|
| 1133 |
lines.append(f" LINK {' '.join(variables)}")
|
| 1134 |
+
for i in range(n-1):
|
| 1135 |
+
lines.append(f" GEQ {variables[i+1]} - {variables[i]} WEIGHT {self.SOFT}")
|
| 1136 |
lines.append("END"); si+=1
|
| 1137 |
+
|
| 1138 |
+
if Axiom.SYMMETRIC in ax and Axiom.NETWORK in ax and n>=2:
|
| 1139 |
+
lines.append(f"SCOPE domain_sym ORDER {si}")
|
| 1140 |
+
lines.append(f" LINK {' '.join(variables[:min(4,n)])}")
|
| 1141 |
+
for i in range(0,min(4,n)-1,2):
|
| 1142 |
+
lines.append(f" EQ {variables[i]} + {variables[i+1]} WEIGHT {self.SOFT}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1143 |
lines.append("END"); si+=1
|
| 1144 |
+
|
| 1145 |
if Axiom.METRIC in ax and Axiom.INJECTIVE in ax and n>=2:
|
| 1146 |
+
lines.append(f"SCOPE domain_sep ORDER {si}")
|
| 1147 |
+
lines.append(f" LINK {' '.join(variables[:min(4,n)])}")
|
| 1148 |
+
for a,b in itertools.combinations(range(min(4,n)),2):
|
| 1149 |
+
lines.append(f" GEQ ({variables[a]} - {variables[b]})**2 - 0.04 WEIGHT {self.SOFT}")
|
| 1150 |
lines.append("END"); si+=1
|
| 1151 |
+
|
| 1152 |
+
if Axiom.BILINEAR in ax and n>=2:
|
| 1153 |
+
lines.append(f"SCOPE domain_bilinear ORDER {si}")
|
| 1154 |
+
grp=variables[:min(3,n)]
|
| 1155 |
+
lines.append(f" LINK {' '.join(grp)}")
|
| 1156 |
+
for j in range(len(grp)-1):
|
| 1157 |
+
lines.append(f" EQ {grp[j]}*{grp[j+1]} WEIGHT {self.SOFT}")
|
| 1158 |
lines.append("END"); si+=1
|
| 1159 |
+
|
| 1160 |
+
if Axiom.MANIFOLD_HINT(ax) and n>=2:
|
| 1161 |
+
# Soft quadratic regularisation β only if base has no quadratic conserve
|
| 1162 |
+
has_quad=any("**2" in c.get("expr","") and c["kind"]=="CONSERVE" for c in axl_def.constraints)
|
| 1163 |
+
if not has_quad:
|
| 1164 |
+
lines.append(f"SCOPE domain_quad ORDER {si}")
|
| 1165 |
+
lines.append(f" LINK {' '.join(variables)}")
|
| 1166 |
+
lines.append(f" EQ {' + '.join(f'{v}**2' for v in variables)} - {float(n)*0.25:.2f} WEIGHT {self.SOFT}")
|
| 1167 |
+
lines.append("END"); si+=1
|
| 1168 |
+
|
| 1169 |
return "\n".join(lines)
|
| 1170 |
|
| 1171 |
+
# Small helper β avoid if-chain sprawl
|
| 1172 |
+
def _manifold_hint(ax): return Axiom.QUADRATIC in ax and Axiom.CONSERVED not in ax
|
| 1173 |
+
Axiom.MANIFOLD_HINT = staticmethod(_manifold_hint)
|
| 1174 |
+
|
| 1175 |
@dataclass
|
| 1176 |
class DebateRound:
|
| 1177 |
round_idx:int; domain:AbstractDomain; psl_text:str
|
| 1178 |
+
ce:float; solved:bool; action:str; strategy_name:str=""
|
| 1179 |
traces:List[HypothesisTrace]=field(default_factory=list)
|
| 1180 |
|
| 1181 |
class WisdomDebate:
|
|
|
|
| 1195 |
|
| 1196 |
def _candidates(self,current,round_idx):
|
| 1197 |
cands=[(d,"Library") for d in self.library]
|
| 1198 |
+
for d1,d2 in itertools.combinations(self.library[:5],2):
|
| 1199 |
+
cands.append((WisdomOps.union(d1,d2),"Union"))
|
| 1200 |
for d in self.library[:4]: cands.append((WisdomOps.dual(d),"Dual"))
|
| 1201 |
if round_idx>2:
|
| 1202 |
chosen=random.sample([Axiom.BILINEAR,Axiom.QUADRATIC,Axiom.CONSERVED,Axiom.METRIC,Axiom.ORDERED],2)
|
| 1203 |
+
cands.append((WisdomOps.inject(current,set(chosen)),"RandInject"))
|
| 1204 |
return cands
|
| 1205 |
|
| 1206 |
def debate(self,axl_def:AXLProblemDef,base_problem:Problem) -> Tuple[Dict,float,List[DebateRound]]:
|
| 1207 |
+
problem_axioms=axl_def.axioms
|
| 1208 |
current=min(self.library,key=lambda d:self._critic_score(problem_axioms,d)[0])
|
| 1209 |
self.history=[]; self.best_ce=float('inf'); self.best_binding={}; self.all_traces=[]
|
| 1210 |
|
| 1211 |
+
print(f"\n{'β'*60}\nDEBATE: {axl_def.name} | Axioms: {problem_axioms}\n{'β'*60}")
|
| 1212 |
|
| 1213 |
for round_idx in range(self.MAX_ROUNDS):
|
| 1214 |
cands=self._candidates(current,round_idx)
|
|
|
|
| 1216 |
scored.sort(key=lambda x:x[0])
|
| 1217 |
tried={r.domain.name for r in self.history}
|
| 1218 |
score,winner,action=next((s for s in scored if s[1].name not in tried),scored[0])
|
| 1219 |
+
strategy=get_strategy(winner.name)
|
| 1220 |
|
| 1221 |
+
print(f"\n[R{round_idx+1}] {winner.name} | {action} | score={score:.1f} | strategy={strategy.name}")
|
| 1222 |
+
print(f" hint: {strategy.note[:60]}")
|
| 1223 |
+
|
| 1224 |
+
# ββ KEY FIX: translate generates base + soft hints βββββββββ
|
| 1225 |
+
psl_text=self.translator.compile(winner,axl_def)
|
| 1226 |
round_traces=[]
|
| 1227 |
|
| 1228 |
try:
|
| 1229 |
prog=parse_psl(psl_text); ep=expand_psl(prog)
|
| 1230 |
if not ep.variables:
|
| 1231 |
+
print(" β No variables"); current=winner; continue
|
| 1232 |
+
|
| 1233 |
dom_prob=Problem(pid=f"dom_{winner.name}",variables=ep.variables,
|
| 1234 |
constraints=ep.constraints,bounds=ep.bounds,
|
| 1235 |
scope_groups=ep.scope_groups,scope_vars=ep.scope_vars,
|
| 1236 |
scope_order=ep.scope_order)
|
| 1237 |
t_start=time.time()
|
| 1238 |
+
# ββ KEY FIX: solver receives domain strategy βββββββββββ
|
| 1239 |
+
result=solve_by_hypothesis(dom_prob,budget=TOTAL_BUDGET,strategy=strategy)
|
| 1240 |
elapsed=round((time.time()-t_start)*1000,1)
|
| 1241 |
binding=result["binding"]; ce=result["ce"]; solved=result["solved"]
|
| 1242 |
|
| 1243 |
# Verify against base problem + anchors
|
| 1244 |
verify=VERIFY_LAYER.run(binding,base_problem,axl_def.anchors)
|
| 1245 |
+
base_ce=verify.gate1_ce # this IS the true base CE now
|
| 1246 |
|
| 1247 |
trace=HypothesisTrace(
|
| 1248 |
hid=f"R{round_idx+1}_{winner.name[:10]}",
|
| 1249 |
+
round_idx=round_idx+1, domain_name=winner.name,
|
| 1250 |
+
action=action, ce_before=self.best_ce if self.best_ce<float('inf') else 99.0,
|
| 1251 |
+
ce_after=base_ce, verify=verify,
|
| 1252 |
+
survived=verify.overall_pass, elapsed_ms=elapsed,
|
| 1253 |
+
strategy_note=strategy.polish)
|
|
|
|
|
|
|
|
|
|
| 1254 |
round_traces.append(trace); self.all_traces.append(trace)
|
| 1255 |
|
| 1256 |
status="β SURVIVED" if verify.overall_pass else "β FAILED"
|
| 1257 |
+
print(f" DomCE={ce:.5f} BaseCE={base_ce:.5f} | "
|
| 1258 |
+
f"G1={'β' if verify.gate1_pass else 'β'} G2={'β' if verify.gate2_pass else 'β'} | {status}")
|
| 1259 |
for inv_name,(err,passed) in verify.gate2_results.items():
|
| 1260 |
+
print(f" [{'β' if passed else 'β'}] {inv_name}: |err|={err:.6f}")
|
| 1261 |
|
| 1262 |
+
if base_ce<self.best_ce:
|
| 1263 |
+
self.best_ce=base_ce; self.best_binding=dict(binding); self.best_domain=winner
|
| 1264 |
+
|
| 1265 |
+
if verify.overall_pass:
|
| 1266 |
+
self.history.append(DebateRound(round_idx,winner,psl_text,base_ce,
|
| 1267 |
+
verify.overall_pass,action,strategy.name,round_traces))
|
| 1268 |
print(f"\nβ VERIFIED + SOLVED in round {round_idx+1}"); break
|
| 1269 |
+
|
| 1270 |
except Exception as e:
|
| 1271 |
+
import traceback; traceback.print_exc()
|
| 1272 |
trace=HypothesisTrace(hid=f"R{round_idx+1}_ERR",round_idx=round_idx+1,
|
| 1273 |
domain_name=winner.name,action=action,ce_before=99.0,ce_after=99.0,
|
| 1274 |
verify=None,survived=False,elapsed_ms=0)
|
| 1275 |
round_traces.append(trace); self.all_traces.append(trace)
|
| 1276 |
|
| 1277 |
self.history.append(DebateRound(round_idx,winner,psl_text,
|
| 1278 |
+
self.best_ce,self.best_ce<SOLVE_THRESHOLD,action,strategy.name,round_traces))
|
| 1279 |
current=winner
|
| 1280 |
|
| 1281 |
+
print(f"\n{'β'*60}\nRESULT: BaseCE={self.best_ce:.5f} | Domain={self.best_domain.name if self.best_domain else '?'}")
|
| 1282 |
return self.best_binding,self.best_ce,self.history
|
| 1283 |
|
| 1284 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1285 |
+
# SECTION 13: HARDCODED AXL PROBLEMS (all verified feasible)
|
| 1286 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1287 |
+
AXL_PROBLEMS=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1288 |
|
| 1289 |
+
# ββ PROBLEM 1: NormManifold4D βββββββββββββββββββββββββββββββββββββ
|
| 1290 |
+
# x1 pinned at 0.5. Find x2,x3,x4 on unit sphere summing to -0.5.
|
| 1291 |
+
# Known solution family: x2=-0.809, x3=0.309, x4=0 (and rotations)
|
| 1292 |
AXLProblemDef(
|
| 1293 |
name="NormManifold4D",
|
| 1294 |
+
description="4 vars on unit sphere, zero sum, x1 observed at 0.5",
|
| 1295 |
axioms={Axiom.CONTINUOUS,Axiom.QUADRATIC,Axiom.CONSERVED,Axiom.METRIC,Axiom.SYMMETRIC},
|
| 1296 |
variables=[
|
| 1297 |
+
{"name":"x1","lo":-1.0,"hi":1.0},
|
| 1298 |
+
{"name":"x2","lo":-1.0,"hi":1.0},
|
| 1299 |
+
{"name":"x3","lo":-1.0,"hi":1.0},
|
| 1300 |
+
{"name":"x4","lo":-1.0,"hi":1.0},
|
| 1301 |
],
|
| 1302 |
constraints=[
|
| 1303 |
{"kind":"CONSERVE","expr":"x1**2 + x2**2 + x3**2 + x4**2 - 1.0"},
|
| 1304 |
+
{"kind":"EQ", "expr":"x1 + x2 + x3 + x4","weight":2.0},
|
| 1305 |
],
|
| 1306 |
scopes=[{"name":"sphere","order":0,"vars":["x1","x2","x3","x4"],
|
| 1307 |
+
"constraints":[
|
| 1308 |
+
{"kind":"EQ","expr":"x1**2 + x2**2 + x3**2 + x4**2 - 1.0","weight":5.0},
|
| 1309 |
+
]}],
|
| 1310 |
anchors=[
|
| 1311 |
AXLInvariant("unit_sphere","x1**2 + x2**2 + x3**2 + x4**2 - 1.0",1e-3),
|
| 1312 |
AXLInvariant("zero_sum","x1 + x2 + x3 + x4",1e-3),
|
| 1313 |
+
AXLInvariant("x1_pinned","x1 - 0.5",1e-3),
|
| 1314 |
],
|
| 1315 |
observations={"x1":0.5},
|
| 1316 |
),
|
| 1317 |
+
|
| 1318 |
+
# ββ PROBLEM 2: BilinearChain6 βββββββββββββββββββββββββββββββββββββ
|
| 1319 |
+
# Known exact solution: t1=0.5,t2=1.0,t3=1.0,t4=2.0,t5=1.5,t6=3.0
|
| 1320 |
AXLProblemDef(
|
| 1321 |
name="BilinearChain6",
|
| 1322 |
+
description="6-var ordered chain with bilinear products and sum conservation",
|
| 1323 |
axioms={Axiom.DISCRETE,Axiom.ORDERED,Axiom.BILINEAR,Axiom.CONSERVED,Axiom.NETWORK},
|
| 1324 |
variables=[{"name":f"t{i}","lo":0.0,"hi":3.0} for i in range(1,7)],
|
| 1325 |
constraints=[
|
|
|
|
| 1330 |
{"kind":"GEQ","expr":"t5 - t4","weight":1.0},
|
| 1331 |
{"kind":"GEQ","expr":"t6 - t5","weight":1.0},
|
| 1332 |
],
|
| 1333 |
+
scopes=[{"name":"chain","order":0,"vars":[f"t{i}" for i in range(1,7)],
|
| 1334 |
+
"constraints":[
|
| 1335 |
+
{"kind":"EQ","expr":"t1*t2 - 0.5","weight":2.0},
|
| 1336 |
+
{"kind":"EQ","expr":"t3*t4 - 2.0","weight":2.0},
|
| 1337 |
+
{"kind":"EQ","expr":"t5*t6 - 4.5","weight":2.0},
|
| 1338 |
+
]}],
|
|
|
|
|
|
|
| 1339 |
anchors=[
|
| 1340 |
AXLInvariant("conservation","t1 + t2 + t3 + t4 + t5 + t6 - 9.0",1e-3),
|
| 1341 |
+
AXLInvariant("bilinear_lo","t1*t2 - 0.5",0.05),
|
| 1342 |
+
AXLInvariant("bilinear_mid","t3*t4 - 2.0",0.05),
|
| 1343 |
+
AXLInvariant("bilinear_hi","t5*t6 - 4.5",0.05),
|
| 1344 |
],
|
| 1345 |
),
|
| 1346 |
+
|
| 1347 |
+
# ββ PROBLEM 3: PhaseCollider (FIXED β provably feasible) ββββββββββ
|
| 1348 |
+
# Conservation: p2 = -p1 (momentum = 0)
|
| 1349 |
+
# Phase A: |p1|=0.5, separation=1.0. Phase B: |p1|=1.0, separation=4.0
|
| 1350 |
+
# Branch on p1 radius; separation follows from conservation automatically.
|
| 1351 |
AXLProblemDef(
|
| 1352 |
name="PhaseCollider",
|
| 1353 |
+
description="2-particle symmetric collision: conservation + phase branch",
|
| 1354 |
axioms={Axiom.DISCRETE,Axiom.MUTABLE,Axiom.SYMMETRIC,Axiom.NETWORK,Axiom.CONSERVED},
|
| 1355 |
variables=[
|
| 1356 |
+
{"name":"p1x","lo":-2.0,"hi":2.0},
|
| 1357 |
+
{"name":"p2x","lo":-2.0,"hi":2.0},
|
| 1358 |
+
{"name":"p1y","lo":-2.0,"hi":2.0},
|
| 1359 |
+
{"name":"p2y","lo":-2.0,"hi":2.0},
|
| 1360 |
],
|
| 1361 |
constraints=[
|
| 1362 |
+
{"kind":"CONSERVE","expr":"p1x + p2x"}, # total momentum x = 0
|
| 1363 |
+
{"kind":"CONSERVE","expr":"p1y + p2y"}, # total momentum y = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1364 |
],
|
| 1365 |
+
scopes=[{"name":"phase","order":0,"vars":["p1x","p2x","p1y","p2y"],
|
| 1366 |
+
"constraints":[
|
| 1367 |
+
# Phase branch: p1 at radius 0.5 OR radius 1.0
|
| 1368 |
+
{"kind":"BRANCH","name":"phase_select","options":[
|
| 1369 |
+
"p1x**2 + p1y**2 - 0.25", # phase A: r=0.5
|
| 1370 |
+
"p1x**2 + p1y**2 - 1.0", # phase B: r=1.0
|
| 1371 |
+
]},
|
| 1372 |
+
# Symmetry: p2 = -p1 (follows from conservation, reinforced)
|
| 1373 |
+
{"kind":"EQ","expr":"p1x + p2x","weight":3.0},
|
| 1374 |
+
{"kind":"EQ","expr":"p1y + p2y","weight":3.0},
|
| 1375 |
+
]}],
|
| 1376 |
anchors=[
|
| 1377 |
AXLInvariant("momentum_x","p1x + p2x",1e-3),
|
| 1378 |
AXLInvariant("momentum_y","p1y + p2y",1e-3),
|
| 1379 |
+
# Phase satisfied: product of both phase residuals near 0
|
| 1380 |
+
AXLInvariant("phase_A_or_B",
|
| 1381 |
+
"(p1x**2 + p1y**2 - 0.25)*(p1x**2 + p1y**2 - 1.0)",0.05),
|
| 1382 |
],
|
| 1383 |
),
|
| 1384 |
+
|
| 1385 |
+
# ββ PROBLEM 4: MetricPacking3D ββββββββββββββββββββββββββββββββββββ
|
| 1386 |
+
# Known solution: a=-sqrt(3), b=0, c=sqrt(3) β (-1.732, 0, 1.732)
|
| 1387 |
+
# centred: 0 β, sep_ab: 3 β₯ 1 β, sep_bc: 3 β₯ 1 β, sep_ac: 12 β₯ 4 β, norm: 6 β
|
| 1388 |
AXLProblemDef(
|
| 1389 |
name="MetricPacking3D",
|
| 1390 |
+
description="3 vars packed with min separation, centred, norm=6",
|
| 1391 |
axioms={Axiom.CONTINUOUS,Axiom.METRIC,Axiom.INJECTIVE,Axiom.CONSERVED,Axiom.SYMMETRIC},
|
| 1392 |
variables=[
|
| 1393 |
+
{"name":"a","lo":-3.0,"hi":3.0},
|
| 1394 |
+
{"name":"b","lo":-3.0,"hi":3.0},
|
| 1395 |
+
{"name":"c","lo":-3.0,"hi":3.0},
|
| 1396 |
],
|
| 1397 |
constraints=[
|
| 1398 |
+
{"kind":"CONSERVE","expr":"a + b + c"}, # centred at 0
|
| 1399 |
{"kind":"GEQ","expr":"(a - b)**2 - 1.0","weight":2.0},
|
| 1400 |
{"kind":"GEQ","expr":"(b - c)**2 - 1.0","weight":2.0},
|
| 1401 |
{"kind":"GEQ","expr":"(a - c)**2 - 4.0","weight":2.0},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1402 |
],
|
| 1403 |
+
scopes=[{"name":"packing","order":0,"vars":["a","b","c"],
|
| 1404 |
+
"constraints":[
|
| 1405 |
+
{"kind":"EQ","expr":"a**2 + b**2 + c**2 - 6.0","weight":2.0},
|
| 1406 |
+
]}],
|
| 1407 |
anchors=[
|
| 1408 |
AXLInvariant("centred","a + b + c",1e-3),
|
| 1409 |
+
AXLInvariant("sep_ab","(a - b)**2 - 1.0",0.5), # β₯ 1 (tolerance on residual)
|
| 1410 |
+
AXLInvariant("sep_bc","(b - c)**2 - 1.0",0.5),
|
| 1411 |
+
AXLInvariant("norm_6","a**2 + b**2 + c**2 - 6.0",0.05),
|
| 1412 |
],
|
| 1413 |
),
|
| 1414 |
]
|
| 1415 |
|
| 1416 |
def build_base_problem(axl_def:AXLProblemDef) -> Problem:
|
|
|
|
| 1417 |
psl_text=AXL_COMPILER.compile(axl_def)
|
| 1418 |
prog=parse_psl(psl_text); ep=expand_psl(prog)
|
| 1419 |
return Problem(pid=f"base_{axl_def.name}",variables=ep.variables,
|
|
|
|
| 1422 |
scope_order=ep.scope_order,annotations=ep.annotations)
|
| 1423 |
|
| 1424 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1425 |
+
# SECTION 14: GLOBAL STATE + RUNNER
|
| 1426 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββοΏ½οΏ½οΏ½βββββ
|
| 1427 |
STATE_LOCK=threading.Lock()
|
| 1428 |
+
RUN_LOG:List[Dict]=[]
|
| 1429 |
DEBATE_ENGINE=WisdomDebate()
|
| 1430 |
POOL=ThreadPoolExecutor(max_workers=2)
|
| 1431 |
|
|
|
|
| 1433 |
t0=time.time()
|
| 1434 |
try:
|
| 1435 |
base_prob=build_base_problem(axl_def)
|
| 1436 |
+
binding,ce,rounds=DEBATE_ENGINE.debate(axl_def,base_prob)
|
| 1437 |
elapsed=round(time.time()-t0,2)
|
|
|
|
| 1438 |
survived=[t for t in DEBATE_ENGINE.all_traces if t.survived]
|
| 1439 |
failed=[t for t in DEBATE_ENGINE.all_traces if not t.survived]
|
| 1440 |
best_trace=min((t for t in survived),key=lambda t:t.ce_after,default=None)
|
| 1441 |
+
actual_base_ce=base_prob.constraint_energy(binding)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1442 |
record={
|
| 1443 |
"problem":axl_def.name,
|
| 1444 |
"description":axl_def.description,
|
| 1445 |
"axioms":sorted(axl_def.axioms),
|
| 1446 |
+
"ce":round(actual_base_ce,6),
|
| 1447 |
+
"solved":len(survived)>0 and actual_base_ce<SOLVE_THRESHOLD,
|
|
|
|
| 1448 |
"elapsed":elapsed,
|
| 1449 |
"binding":{k:round(v,5) for k,v in binding.items()},
|
| 1450 |
+
"observations":axl_def.observations,
|
| 1451 |
"traces":[{
|
| 1452 |
"hid":t.hid,"round":t.round_idx,"domain":t.domain_name,
|
| 1453 |
+
"action":t.action,"strategy":t.strategy_note,
|
| 1454 |
+
"ce":round(t.ce_after,5),
|
| 1455 |
"g1_ce":round(t.verify.gate1_ce,5) if t.verify else None,
|
| 1456 |
"g1":t.verify.gate1_pass if t.verify else False,
|
| 1457 |
"g2":t.verify.gate2_pass if t.verify else False,
|
| 1458 |
+
"g2_detail":{k:(round(err,6),ok)
|
| 1459 |
+
for k,(err,ok) in t.verify.gate2_results.items()} if t.verify else {},
|
| 1460 |
"survived":t.survived,"ms":t.elapsed_ms,
|
| 1461 |
} for t in DEBATE_ENGINE.all_traces],
|
| 1462 |
"survived_count":len(survived),
|
|
|
|
| 1467 |
RUN_LOG.append(record)
|
| 1468 |
if len(RUN_LOG)>40: RUN_LOG.pop(0)
|
| 1469 |
except Exception as e:
|
| 1470 |
+
import traceback; traceback.print_exc()
|
| 1471 |
print(f"[RUN ERROR] {axl_def.name}: {e}")
|
| 1472 |
|
| 1473 |
async def run_loop():
|
|
|
|
| 1475 |
while True:
|
| 1476 |
prob=random.choice(AXL_PROBLEMS)
|
| 1477 |
await loop.run_in_executor(POOL,_run_problem,prob)
|
| 1478 |
+
await asyncio.sleep(0.3)
|
| 1479 |
|
| 1480 |
@asynccontextmanager
|
| 1481 |
async def lifespan(app):
|
|
|
|
| 1484 |
POOL.shutdown(wait=False)
|
| 1485 |
|
| 1486 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1487 |
+
# SECTION 15: FASTAPI + DASHBOARD
|
| 1488 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1489 |
+
app=FastAPI(title="Practicality 11.1",lifespan=lifespan)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1490 |
|
| 1491 |
def _render_collapse(record:Dict) -> str:
|
| 1492 |
+
b=record["binding"]; traces=record["traces"]
|
|
|
|
| 1493 |
survived=[t for t in traces if t["survived"]]
|
|
|
|
|
|
|
| 1494 |
best=min(survived,key=lambda t:t["ce"],default=None)
|
| 1495 |
+
if not best and traces: best=min(traces,key=lambda t:t.get("g1_ce") or 999.0)
|
| 1496 |
+
obs_vars=set(record.get("observations",{}).keys())
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1497 |
|
| 1498 |
+
solved=record["solved"]
|
| 1499 |
+
ce=record["ce"]
|
| 1500 |
+
ce_color="#4CAF50" if solved else ("#FF9800" if ce<0.5 else "#EF5350")
|
| 1501 |
+
status="β SOLVED + VERIFIED" if solved else ("~ PARTIAL" if ce<0.5 else "β UNSOLVED")
|
| 1502 |
|
| 1503 |
binding_rows="".join(
|
| 1504 |
+
f"<tr><td style='color:#888;width:70px'>{v}</td>"
|
| 1505 |
f"<td style='color:#26C6DA;font-weight:700'>{val:+.5f}</td>"
|
| 1506 |
+
f"<td style='color:#4CAF50;font-size:0.75em'>{'[OBS]' if v in obs_vars else ''}</td></tr>"
|
| 1507 |
+
for v,val in b.items())
|
|
|
|
| 1508 |
|
| 1509 |
inv_rows=""
|
| 1510 |
if best and best.get("g2_detail"):
|
| 1511 |
for inv,(err,ok) in best["g2_detail"].items():
|
| 1512 |
c="#4CAF50" if ok else "#EF5350"
|
| 1513 |
+
inv_rows+=(f"<tr><td style='color:{c}'>{'β' if ok else 'β'}</td>"
|
| 1514 |
+
f"<td style='color:#aaa'>{inv}</td>"
|
| 1515 |
+
f"<td style='color:{c}'>{err:.6f}</td></tr>")
|
| 1516 |
+
|
| 1517 |
+
def trail_span(t):
|
| 1518 |
+
c="#4CAF50" if t["survived"] else "#333"
|
| 1519 |
+
star=" β SURVIVED" if t["survived"] else ""
|
| 1520 |
+
strat=f" [{t.get('strategy','')}]" if t.get("strategy") else ""
|
| 1521 |
+
return (f"<div style='color:{c};font-size:0.78em;margin-bottom:3px'>"
|
| 1522 |
+
f"[R{t['round']}] <span style='color:#FF9800'>{t['domain'][:14]}</span>"
|
| 1523 |
+
f" CE={t['ce']:.5f}"
|
| 1524 |
+
f" G1={'β' if t['g1'] else 'β'}{t.get('g1_ce',0):.4f}"
|
| 1525 |
+
f" G2={'β' if t['g2'] else 'β'}"
|
| 1526 |
+
f"<span style='color:#555'>{strat}</span>"
|
| 1527 |
+
f"<span style='color:#4CAF50;font-weight:700'>{star}</span></div>")
|
| 1528 |
+
|
| 1529 |
+
trail="".join(trail_span(t) for t in traces)
|
| 1530 |
|
| 1531 |
return f"""
|
| 1532 |
+
<div style='border:1px solid #222;border-radius:8px;margin-bottom:18px;overflow:hidden'>
|
| 1533 |
+
<div style='background:#0e0e0e;padding:9px 14px;border-bottom:1px solid #1a1a1a;display:flex;align-items:center;gap:16px'>
|
| 1534 |
+
<span style='color:{ce_color};font-weight:700;font-size:1.05em'>{status}</span>
|
| 1535 |
+
<span style='color:#444;font-size:0.85em'>{record["problem"]}</span>
|
| 1536 |
+
<span style='color:#333;font-size:0.8em'>BaseCE={ce:.6f}</span>
|
| 1537 |
+
<span style='color:#555;font-size:0.75em'>{record["elapsed"]}s</span>
|
| 1538 |
+
<span style='color:#26C6DA;font-size:0.75em'>{record["survived_count"]} survived / {record["failed_count"]} failed</span>
|
| 1539 |
</div>
|
| 1540 |
+
<div style='display:flex'>
|
| 1541 |
+
<div style='flex:0 0 180px;padding:10px 12px;border-right:1px solid #1a1a1a'>
|
| 1542 |
+
<div style='color:#333;font-size:0.7em;margin-bottom:5px'>BINDING</div>
|
| 1543 |
+
<table style='border-collapse:collapse;width:100%'>{binding_rows}</table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1544 |
</div>
|
| 1545 |
+
<div style='flex:0 0 200px;padding:10px 12px;border-right:1px solid #1a1a1a'>
|
| 1546 |
+
<div style='color:#333;font-size:0.7em;margin-bottom:5px'>INVARIANTS (Gate 2)</div>
|
| 1547 |
+
<table style='border-collapse:collapse;width:100%'>
|
|
|
|
|
|
|
|
|
|
| 1548 |
{inv_rows or "<tr><td colspan='3' style='color:#222'>β</td></tr>"}
|
| 1549 |
</table>
|
| 1550 |
</div>
|
| 1551 |
+
<div style='flex:1;padding:10px 12px'>
|
| 1552 |
+
<div style='color:#333;font-size:0.7em;margin-bottom:5px'>
|
| 1553 |
+
HYPOTHESIS TRAIL β best domain: <span style='color:#FF9800'>{record["best_domain"]}</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1554 |
</div>
|
| 1555 |
+
{trail}
|
| 1556 |
</div>
|
| 1557 |
</div>
|
| 1558 |
</div>"""
|
| 1559 |
|
| 1560 |
@app.get("/",response_class=HTMLResponse)
|
| 1561 |
async def dashboard():
|
| 1562 |
+
with STATE_LOCK: log=list(reversed(RUN_LOG[-10:]))
|
| 1563 |
+
runs=len(RUN_LOG); solved=sum(1 for r in RUN_LOG if r.get("solved",False))
|
|
|
|
|
|
|
| 1564 |
avg_ce=round(sum(r["ce"] for r in RUN_LOG)/max(1,runs),5) if RUN_LOG else 0
|
| 1565 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1566 |
all_traces=[t for r in log for t in r.get("traces",[])]
|
| 1567 |
+
ds=defaultdict(lambda:{"tried":0,"survived":0,"total_ce":0.0,"strategy":""})
|
| 1568 |
for t in all_traces:
|
| 1569 |
+
ds[t["domain"]]["tried"]+=1
|
| 1570 |
+
ds[t["domain"]]["total_ce"]+=t["ce"]
|
| 1571 |
+
ds[t["domain"]]["strategy"]=t.get("strategy","")
|
| 1572 |
+
if t["survived"]: ds[t["domain"]]["survived"]+=1
|
| 1573 |
domain_rows="".join(
|
| 1574 |
f"<tr><td style='color:#FF9800'>{d}</td>"
|
| 1575 |
f"<td style='color:#aaa'>{s['tried']}</td>"
|
| 1576 |
f"<td style='color:#4CAF50'>{s['survived']}</td>"
|
| 1577 |
f"<td style='color:#EF5350'>{s['tried']-s['survived']}</td>"
|
| 1578 |
+
f"<td style='color:#26C6DA'>{round(s['total_ce']/s['tried'],5) if s['tried'] else 0}</td>"
|
| 1579 |
+
f"<td style='color:#555'>{s['strategy']}</td>"
|
| 1580 |
+
f"<td style='color:{'#4CAF50' if s['survived']>0 else '#333'}'>"
|
| 1581 |
+
f"{round(s['survived']/s['tried']*100):.0f}%</td></tr>"
|
| 1582 |
+
for d,s in sorted(ds.items(),key=lambda x:-x[1]["survived"])
|
| 1583 |
+
) or "<tr><td colspan='7' style='color:#222'>Warming upβ¦</td></tr>"
|
| 1584 |
|
| 1585 |
+
collapses="".join(_render_collapse(r) for r in log) if log else \
|
| 1586 |
+
"<div style='color:#222;padding:20px'>Warming upβ¦</div>"
|
| 1587 |
+
|
| 1588 |
+
return f"""<!DOCTYPE html><html><head><title>Practicality 11.1</title>
|
| 1589 |
<meta http-equiv="refresh" content="4">
|
| 1590 |
<style>
|
| 1591 |
body{{background:#090909;color:#e0e0e0;font-family:monospace;padding:20px;max-width:1400px}}
|
| 1592 |
+
h1{{color:#26C6DA;border-bottom:1px solid #1a1a1a;padding-bottom:6px;font-size:1.15em}}
|
| 1593 |
+
h3{{color:#2a2a2a;margin-top:20px;font-size:0.85em;letter-spacing:2px;text-transform:uppercase}}
|
| 1594 |
table{{width:100%;border-collapse:collapse;margin-bottom:10px}}
|
| 1595 |
+
th,td{{padding:4px 8px;text-align:left;border-bottom:1px solid #0f0f0f;font-size:0.82em}}
|
| 1596 |
+
th{{color:#2a2a2a;font-size:0.72em}}
|
| 1597 |
+
.badge{{display:inline-block;padding:3px 10px;border-radius:3px;background:#0e0e0e;margin:2px;font-size:0.78em;border:1px solid #1a1a1a}}
|
| 1598 |
</style></head><body>
|
| 1599 |
+
<h1>β Practicality 11.1 β AXL/PSL Pipeline (fixed)</h1>
|
| 1600 |
+
<div style='color:#333;font-size:0.75em;margin-bottom:12px'>
|
| 1601 |
+
AXL β PSL (base + soft domain hints) β Solver [strategy-directed] β Gate1 β Gate2 β Collapse
|
| 1602 |
</div>
|
| 1603 |
+
<div style='margin-bottom:16px'>
|
| 1604 |
<span class='badge' style='color:#aaa'>Runs: {runs}</span>
|
| 1605 |
<span class='badge' style='color:#4CAF50'>Solved: {solved}</span>
|
| 1606 |
<span class='badge' style='color:#26C6DA'>Avg BaseCE: {avg_ce}</span>
|
| 1607 |
<span class='badge' style='color:#FF9800'>Problems: {len(AXL_PROBLEMS)}</span>
|
| 1608 |
<span class='badge' style='color:#5C6BC0'>Library: {len(DEBATE_ENGINE.library)}</span>
|
| 1609 |
</div>
|
| 1610 |
+
<h3>Domain Survival + Strategy</h3>
|
|
|
|
| 1611 |
<table>
|
| 1612 |
+
<tr><th>Domain</th><th>Tried</th><th>Survived</th><th>Failed</th><th>Avg BaseCE</th><th>Polish</th><th>Rate</th></tr>
|
| 1613 |
{domain_rows}
|
| 1614 |
</table>
|
| 1615 |
+
<h3>Collapse View β Recent Runs</h3>
|
|
|
|
| 1616 |
{collapses}
|
| 1617 |
</body></html>"""
|
| 1618 |
|