everydaytok commited on
Commit
0a0ada9
Β·
verified Β·
1 Parent(s): a959aa7

Update practicality_axioms.py

Browse files
Files changed (1) hide show
  1. practicality_axioms.py +97 -8
practicality_axioms.py CHANGED
@@ -1,9 +1,18 @@
 
 
 
 
 
 
 
 
1
  import math
2
  import random
3
  import torch
4
  import itertools
5
- from typing import Dict, List, Tuple, Set, Optional, Any
6
  from dataclasses import dataclass, field
 
7
  import practicality_core as core
8
 
9
  @dataclass
@@ -56,9 +65,13 @@ class StructuralModel:
56
  class Axiom:
57
  CONTINUOUS = "CONTINUOUS"; DISCRETE = "DISCRETE"; QUADRATIC = "QUADRATIC"
58
  BILINEAR = "BILINEAR"; METRIC = "METRIC"; SYMMETRIC = "SYMMETRIC"
59
- MUTABLE = "MUTABLE"; EXTREMAL = "EXTREMAL"; ENTROPY = "ENTROPY"
60
- ATOMIC = "ATOMIC"; PARSIMONY = "PARSIMONY"; DUALITY = "DUALITY"
61
- MONOTONE_PRODUCT = "MONOTONE_PRODUCT"; ORDERED = "ORDERED"
 
 
 
 
62
 
63
  ALL_AXIOMS = [getattr(Axiom, a) for a in dir(Axiom) if not a.startswith("__")]
64
 
@@ -71,6 +84,7 @@ def _make_hyp(hid, binding, h_type, claim, derivation, pinned, free, conf, is_fd
71
  confidence=conf, is_fully_determined=is_fd)
72
 
73
  def _hyp_continuous(p, bt, a, m): return [_make_hyp("cnt", bt.binding, "continuous", "Manifold", [], {}, p.variables, 0.45)]
 
74
  def _hyp_discrete(p, bt, a, m):
75
  b = dict(bt.binding); pinned = {}
76
  box = {v: core.IV(b.get(v, 0)-max(0.05*(p.bounds[v][1]-p.bounds[v][0]), 1e-4),
@@ -81,11 +95,13 @@ def _hyp_discrete(p, bt, a, m):
81
  b[v] = iv.mid()
82
  if iv.width() < 1e-2: pinned[v] = b[v]
83
  return [_make_hyp("dis", b, "discrete", "TopoScope", [], pinned, p.variables, 0.80)]
 
84
  def _hyp_quadratic(p, bt, a, m):
85
  hyps = []; b = dict(bt.binding)
86
  if bt.l9 and bt.l9.dominant_vars:
87
  for v in bt.l9.dominant_vars[:2]: hyps.append(_make_hyp(f"qua_{v}", b, "quadratic", f"Root({v})", [], {v: b[v]}, p.variables, 0.70))
88
  return hyps if hyps else [_make_hyp("qua", b, "quadratic", "Root", [], {}, p.variables, 0.55)]
 
89
  def _hyp_bilinear(p, bt, a, m):
90
  hyps = []; b = dict(bt.binding)
91
  for vi, vj in p.bilinear_pairs:
@@ -97,6 +113,7 @@ def _hyp_bilinear(p, bt, a, m):
97
  nb = dict(b); nb[vi] = nb[vj] = gm
98
  hyps.append(_make_hyp(f"bil_eq_{vi}_{vj}", nb, "bilinear", "GeoMean", ["bilinear"], {vi: gm, vj: gm}, [v for v in p.variables if v not in [vi, vj]], 0.70))
99
  return hyps
 
100
  def _hyp_monotone_product(p, bt, a, m):
101
  hyps = []; b = dict(bt.binding)
102
  if not p.monotone_targets: return hyps
@@ -120,6 +137,7 @@ def _hyp_monotone_product(p, bt, a, m):
120
  hyps.append(_make_hyp(f"mpr_{v_small}_{v_large}_r{int(ratio*100)}", nb, "monotone_product",
121
  "MonoProd", ["ordered", "hc4"], pinned, [u for u in p.variables if u not in pinned], 0.88))
122
  return hyps
 
123
  def _hyp_metric(p, bt, a, m):
124
  hyps = []; b = dict(bt.binding)
125
  for mc in p.compiled_constraints:
@@ -139,6 +157,7 @@ def _hyp_metric(p, bt, a, m):
139
  lo, hi = p.bounds.get(v, (-10, 10)); nb[v] = max(lo, min(hi, b.get(v, 0)*scale))
140
  hyps.append(_make_hyp(f"met_{hash(mc.expr_str)%9999}", nb, "metric", "RadialProject", ["metric", mc.expr_str], {}, list(p.variables), 0.75))
141
  return hyps
 
142
  def _hyp_symmetric(p, bt, a, m):
143
  hyps = []; b = dict(bt.binding)
144
  vl = p.variables
@@ -151,21 +170,43 @@ def _hyp_symmetric(p, bt, a, m):
151
  nb = dict(b); nb[vi], nb[vj] = bvj, bvi
152
  hyps.append(_make_hyp(f"sym_{vi}_{vj}", nb, "symmetric", "Swap", ["symmetric"], {vi: nb[vi], vj: nb[vj]}, [v for v in p.variables if v not in [vi, vj]], 0.60))
153
  return hyps[:5]
 
154
  def _hyp_ordered(p, bt, a, m): return [_make_hyp("ord", bt.binding, "ordered", "OrderBal", [], {}, p.variables, 0.67)]
155
  def _hyp_monotone(p, bt, a, m): return [_make_hyp("mon", bt.binding, "monotone", "MonoPath", [], {}, p.variables, 0.67)]
 
 
 
156
  def _hyp_mutable(p, bt, a, m):
157
  b = dict(bt.binding); pinned = {}
158
  if bt.l9 and bt.l9.dominant_vars:
159
  v = bt.l9.dominant_vars[0]; lo, hi = p.bounds.get(v, (-10, 10))
160
  b[v] = max(lo, min(hi, b.get(v, 0)+random.gauss(0, (hi-lo)*0.05))); pinned = {v: b[v]}
161
  return [_make_hyp("mut", b, "mutable", "Perturb", [], pinned, p.variables, 0.40)]
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  def _hyp_extremal(p, bt, a, m):
163
  hyps = []; b = dict(bt.binding)
164
  if bt.l9 and bt.l9.dominant_vars:
165
  v = bt.l9.dominant_vars[0]; lo, hi = p.bounds.get(v, (0, 1))
166
  for val in [lo, hi]: nb = dict(b); nb[v] = val; hyps.append(_make_hyp(f"ext_{v}_{val:.3f}", nb, "extremal", "PinBound", [], {v: val}, p.variables, 0.65))
167
  return hyps
 
168
  def _hyp_entropy(p, bt, a, m): return [_make_hyp("ent", {v: random.uniform(*p.bounds[v]) for v in p.variables}, "entropy", "MaxEnt", [], {}, p.variables, 0.48)]
 
 
 
 
169
  def _hyp_atomic(p, bt, a, m):
170
  hyps = []; b = dict(bt.binding)
171
  for mc in p.compiled_constraints:
@@ -179,6 +220,14 @@ def _hyp_atomic(p, bt, a, m):
179
  except: pass
180
  if hyps: break
181
  return hyps
 
 
 
 
 
 
 
 
182
  def _hyp_parsimony(p, bt, a, m):
183
  b = dict(bt.binding); nb = {}
184
  max_val = max((abs(v) for v in b.values() if math.isfinite(v)), default=1.0)
@@ -190,6 +239,7 @@ def _hyp_parsimony(p, bt, a, m):
190
  candidates = [round(val*m)/m for m in [1, 2, 4] if lo <= round(val*m)/m <= hi]
191
  nb[v] = min(candidates, key=lambda c: abs(c-val)) if candidates else val
192
  return [_make_hyp("par", nb, "parsimony", "Occam", [], {}, p.variables, 0.58)]
 
193
  def _hyp_duality(p, bt, a, m): return [_make_hyp("dua", bt.binding, "duality", "Tight", [], {}, p.variables, 0.68)]
194
 
195
  AXIOM_CONSTRUCTORS = {
@@ -197,10 +247,16 @@ AXIOM_CONSTRUCTORS = {
197
  Axiom.QUADRATIC: _hyp_quadratic, Axiom.BILINEAR: _hyp_bilinear,
198
  Axiom.METRIC: _hyp_metric, Axiom.SYMMETRIC: _hyp_symmetric,
199
  Axiom.ORDERED: _hyp_ordered, Axiom.MONOTONE: _hyp_monotone,
200
- Axiom.MUTABLE: _hyp_mutable, Axiom.EXTREMAL: _hyp_extremal,
201
- Axiom.ENTROPY: _hyp_entropy, Axiom.ATOMIC: _hyp_atomic,
202
- Axiom.PARSIMONY: _hyp_parsimony, Axiom.DUALITY: _hyp_duality,
203
- Axiom.MONOTONE_PRODUCT: _hyp_monotone_product
 
 
 
 
 
 
204
  }
205
 
206
  # ══════════════════════════════════════════════════════════════════════
@@ -379,6 +435,39 @@ class SequenceRayTracer:
379
 
380
  return best_binding, best_ce, traces, best_ray_name
381
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  # Re-expose batch optimization so axioms engine remains self-contained
383
  _batched_deduce_and_evaluate = axioms._batched_deduce_and_evaluate
384
  _mprt_sample = axioms._mprt_sample
 
1
+ """
2
+ practicality_axioms.py
3
+ ======================
4
+ The complete, unabridged Axiom Deduction Engine.
5
+ Houses all 28 structural axioms, constructors, the UCB1 Bandit,
6
+ and the full decoupled SequenceRayTracer.
7
+ """
8
+
9
  import math
10
  import random
11
  import torch
12
  import itertools
13
+ from typing import Dict, List, Tuple, Set, Optional, Any, Callable
14
  from dataclasses import dataclass, field
15
+ from collections import defaultdict, deque
16
  import practicality_core as core
17
 
18
  @dataclass
 
65
  class Axiom:
66
  CONTINUOUS = "CONTINUOUS"; DISCRETE = "DISCRETE"; QUADRATIC = "QUADRATIC"
67
  BILINEAR = "BILINEAR"; METRIC = "METRIC"; SYMMETRIC = "SYMMETRIC"
68
+ ORDERED = "ORDERED"; MONOTONE = "MONOTONE"; CONVEX = "CONVEX"
69
+ MONOTONE_PRODUCT = "MONOTONE_PRODUCT"; CONSERVED = "CONSERVED"; MUTABLE = "MUTABLE"
70
+ NETWORK = "NETWORK"; EQUILIBRIUM = "EQUILIBRIUM"; SUPERPOSITION = "SUPERPOSITION"
71
+ LOCALITY = "LOCALITY"; EXTREMAL = "EXTREMAL"; ENTROPY = "ENTROPY"
72
+ INJECTIVE = "INJECTIVE"; SURJECTIVE = "SURJECTIVE"; TRANSITIVE = "TRANSITIVE"
73
+ ATOMIC = "ATOMIC"; IMPLICATION = "IMPLICATION"; NEGATION = "NEGATION"
74
+ COMPOSITE = "COMPOSITE"; HOLISM = "HOLISM"; PARSIMONY = "PARSIMONY"; DUALITY = "DUALITY"
75
 
76
  ALL_AXIOMS = [getattr(Axiom, a) for a in dir(Axiom) if not a.startswith("__")]
77
 
 
84
  confidence=conf, is_fully_determined=is_fd)
85
 
86
  def _hyp_continuous(p, bt, a, m): return [_make_hyp("cnt", bt.binding, "continuous", "Manifold", [], {}, p.variables, 0.45)]
87
+
88
  def _hyp_discrete(p, bt, a, m):
89
  b = dict(bt.binding); pinned = {}
90
  box = {v: core.IV(b.get(v, 0)-max(0.05*(p.bounds[v][1]-p.bounds[v][0]), 1e-4),
 
95
  b[v] = iv.mid()
96
  if iv.width() < 1e-2: pinned[v] = b[v]
97
  return [_make_hyp("dis", b, "discrete", "TopoScope", [], pinned, p.variables, 0.80)]
98
+
99
  def _hyp_quadratic(p, bt, a, m):
100
  hyps = []; b = dict(bt.binding)
101
  if bt.l9 and bt.l9.dominant_vars:
102
  for v in bt.l9.dominant_vars[:2]: hyps.append(_make_hyp(f"qua_{v}", b, "quadratic", f"Root({v})", [], {v: b[v]}, p.variables, 0.70))
103
  return hyps if hyps else [_make_hyp("qua", b, "quadratic", "Root", [], {}, p.variables, 0.55)]
104
+
105
  def _hyp_bilinear(p, bt, a, m):
106
  hyps = []; b = dict(bt.binding)
107
  for vi, vj in p.bilinear_pairs:
 
113
  nb = dict(b); nb[vi] = nb[vj] = gm
114
  hyps.append(_make_hyp(f"bil_eq_{vi}_{vj}", nb, "bilinear", "GeoMean", ["bilinear"], {vi: gm, vj: gm}, [v for v in p.variables if v not in [vi, vj]], 0.70))
115
  return hyps
116
+
117
  def _hyp_monotone_product(p, bt, a, m):
118
  hyps = []; b = dict(bt.binding)
119
  if not p.monotone_targets: return hyps
 
137
  hyps.append(_make_hyp(f"mpr_{v_small}_{v_large}_r{int(ratio*100)}", nb, "monotone_product",
138
  "MonoProd", ["ordered", "hc4"], pinned, [u for u in p.variables if u not in pinned], 0.88))
139
  return hyps
140
+
141
  def _hyp_metric(p, bt, a, m):
142
  hyps = []; b = dict(bt.binding)
143
  for mc in p.compiled_constraints:
 
157
  lo, hi = p.bounds.get(v, (-10, 10)); nb[v] = max(lo, min(hi, b.get(v, 0)*scale))
158
  hyps.append(_make_hyp(f"met_{hash(mc.expr_str)%9999}", nb, "metric", "RadialProject", ["metric", mc.expr_str], {}, list(p.variables), 0.75))
159
  return hyps
160
+
161
  def _hyp_symmetric(p, bt, a, m):
162
  hyps = []; b = dict(bt.binding)
163
  vl = p.variables
 
170
  nb = dict(b); nb[vi], nb[vj] = bvj, bvi
171
  hyps.append(_make_hyp(f"sym_{vi}_{vj}", nb, "symmetric", "Swap", ["symmetric"], {vi: nb[vi], vj: nb[vj]}, [v for v in p.variables if v not in [vi, vj]], 0.60))
172
  return hyps[:5]
173
+
174
  def _hyp_ordered(p, bt, a, m): return [_make_hyp("ord", bt.binding, "ordered", "OrderBal", [], {}, p.variables, 0.67)]
175
  def _hyp_monotone(p, bt, a, m): return [_make_hyp("mon", bt.binding, "monotone", "MonoPath", [], {}, p.variables, 0.67)]
176
+ def _hyp_convex(p, bt, a, m): return [_make_hyp("cvx", bt.binding, "convex", "ConvMix", [], {}, p.variables, 0.63)]
177
+ def _hyp_conserved(p, bt, a, m): return [_make_hyp("csv", bt.binding, "conserved", "Conserve", [], {}, p.variables, 0.82)]
178
+
179
  def _hyp_mutable(p, bt, a, m):
180
  b = dict(bt.binding); pinned = {}
181
  if bt.l9 and bt.l9.dominant_vars:
182
  v = bt.l9.dominant_vars[0]; lo, hi = p.bounds.get(v, (-10, 10))
183
  b[v] = max(lo, min(hi, b.get(v, 0)+random.gauss(0, (hi-lo)*0.05))); pinned = {v: b[v]}
184
  return [_make_hyp("mut", b, "mutable", "Perturb", [], pinned, p.variables, 0.40)]
185
+
186
+ def _hyp_network(p, bt, a, m): return [_make_hyp("net", bt.binding, "network", "HubProp", [], {}, p.variables, 0.65)]
187
+ def _hyp_equilibrium(p, bt, a, m): return [_make_hyp("eql", bt.binding, "equilibrium", "GradBal", [], {}, p.variables, 0.72)]
188
+
189
+ def _hyp_superposition(p, bt, a, m):
190
+ if a and len(a)>0:
191
+ other=random.choice(a); lam=0.5
192
+ nb={v:lam*bt.binding.get(v,0)+(1-lam)*other.binding.get(v,0) for v in p.variables}
193
+ return [_make_hyp("sup",nb,"superposition","Superpose",[],{},p.variables,0.58)]
194
+ return []
195
+
196
+ def _hyp_locality(p, bt, a, m): return [_make_hyp("loc", bt.binding, "locality", "LocalFirst", [], {}, p.variables, 0.72)]
197
+
198
  def _hyp_extremal(p, bt, a, m):
199
  hyps = []; b = dict(bt.binding)
200
  if bt.l9 and bt.l9.dominant_vars:
201
  v = bt.l9.dominant_vars[0]; lo, hi = p.bounds.get(v, (0, 1))
202
  for val in [lo, hi]: nb = dict(b); nb[v] = val; hyps.append(_make_hyp(f"ext_{v}_{val:.3f}", nb, "extremal", "PinBound", [], {v: val}, p.variables, 0.65))
203
  return hyps
204
+
205
  def _hyp_entropy(p, bt, a, m): return [_make_hyp("ent", {v: random.uniform(*p.bounds[v]) for v in p.variables}, "entropy", "MaxEnt", [], {}, p.variables, 0.48)]
206
+ def _hyp_injective(p, bt, a, m): return [_make_hyp("inj", bt.binding, "injective", "Distinct", [], {}, p.variables, 0.50)]
207
+ def _hyp_surjective(p, bt, a, m): return [_make_hyp("sur", bt.binding, "surjective", "Sweep", [], {}, p.variables, 0.45)]
208
+ def _hyp_transitive(p, bt, a, m): return [_make_hyp("tra", bt.binding, "transitive", "TransSnap", [], {}, p.variables, 0.77)]
209
+
210
  def _hyp_atomic(p, bt, a, m):
211
  hyps = []; b = dict(bt.binding)
212
  for mc in p.compiled_constraints:
 
220
  except: pass
221
  if hyps: break
222
  return hyps
223
+
224
+ def _hyp_implication(p, bt, a, m): return [_make_hyp("imp", bt.binding, "implication", "Imply", [], {}, p.variables, 0.78)]
225
+ def _hyp_negation(p, bt, a, m):
226
+ nb={v:max(p.bounds[v][0],min(p.bounds[v][1],(p.bounds[v][0]+p.bounds[v][1])-bt.binding.get(v,(p.bounds[v][0]+p.bounds[v][1])/2))) for v in p.variables}
227
+ return [_make_hyp("neg",nb,"negation","Mirror",[],{},p.variables,0.42)]
228
+ def _hyp_composite(p, bt, a, m): return [_make_hyp("cmp", bt.binding, "composite", "Enz", [], {}, p.variables, 0.90)]
229
+ def _hyp_holism(p, bt, a, m): return [_make_hyp("hol", bt.binding, "holism", "Global", [], {}, p.variables, 0.73)]
230
+
231
  def _hyp_parsimony(p, bt, a, m):
232
  b = dict(bt.binding); nb = {}
233
  max_val = max((abs(v) for v in b.values() if math.isfinite(v)), default=1.0)
 
239
  candidates = [round(val*m)/m for m in [1, 2, 4] if lo <= round(val*m)/m <= hi]
240
  nb[v] = min(candidates, key=lambda c: abs(c-val)) if candidates else val
241
  return [_make_hyp("par", nb, "parsimony", "Occam", [], {}, p.variables, 0.58)]
242
+
243
  def _hyp_duality(p, bt, a, m): return [_make_hyp("dua", bt.binding, "duality", "Tight", [], {}, p.variables, 0.68)]
244
 
245
  AXIOM_CONSTRUCTORS = {
 
247
  Axiom.QUADRATIC: _hyp_quadratic, Axiom.BILINEAR: _hyp_bilinear,
248
  Axiom.METRIC: _hyp_metric, Axiom.SYMMETRIC: _hyp_symmetric,
249
  Axiom.ORDERED: _hyp_ordered, Axiom.MONOTONE: _hyp_monotone,
250
+ Axiom.CONVEX: _hyp_convex, Axiom.CONSERVED: _hyp_conserved,
251
+ Axiom.MUTABLE: _hyp_mutable, Axiom.NETWORK: _hyp_network,
252
+ Axiom.EQUILIBRIUM: _hyp_equilibrium, Axiom.SUPERPOSITION: _hyp_superposition,
253
+ Axiom.LOCALITY: _hyp_locality, Axiom.EXTREMAL: _hyp_extremal,
254
+ Axiom.ENTROPY: _hyp_entropy, Axiom.INJECTIVE: _hyp_injective,
255
+ Axiom.SURJECTIVE: _hyp_surjective, Axiom.TRANSITIVE: _hyp_transitive,
256
+ Axiom.ATOMIC: _hyp_atomic, Axiom.IMPLICATION: _hyp_implication,
257
+ Axiom.NEGATION: _hyp_negation, Axiom.COMPOSITE: _hyp_composite,
258
+ Axiom.HOLISM: _hyp_holism, Axiom.PARSIMONY: _hyp_parsimony,
259
+ Axiom.DUALITY: _hyp_duality, Axiom.MONOTONE_PRODUCT: _hyp_monotone_product
260
  }
261
 
262
  # ══════════════════════════════════════════════════════════════════════
 
435
 
436
  return best_binding, best_ce, traces, best_ray_name
437
 
438
+ # ══════════════════════════════════════════════════════════════════════
439
+ # UCB1 BANDIT SEEDER
440
+ # ══════════════════════════════════════════════════════════════════════
441
+ class UCB1BanditSeeder:
442
+ def __init__(self):
443
+ self.stats = {a: {"tries": 0, "reward": 0.0} for a in ALL_AXIOMS}
444
+ self.total_tries = 0
445
+
446
+ def record_reward(self, axiom, ce_before, ce_after):
447
+ reward = max(0.0, ce_before - ce_after)
448
+ self.stats[axiom]["tries"] += 1
449
+ self.stats[axiom]["reward"] += reward
450
+ self.total_tries += 1
451
+
452
+ def intelligent_branch(self, ray, out_baton, remaining_axioms, branch_width):
453
+ scored = []
454
+ for ax in remaining_axioms:
455
+ tries = self.stats[ax]["tries"]
456
+ if tries == 0: ucb = 999.0
457
+ else:
458
+ avg_reward = self.stats[ax]["reward"] / tries
459
+ exploration = math.sqrt(math.log(self.total_tries + 1) / tries)
460
+ ucb = avg_reward + 0.5 * exploration
461
+ scored.append((ucb, ax))
462
+ scored.sort(key=lambda x: x[0] * random.random(), reverse=True)
463
+ children = []
464
+ for _, axiom in scored[:branch_width]:
465
+ child = ray.extend(axiom, "branch", new_prior=out_baton.ce)
466
+ if child:
467
+ child.baton = out_baton
468
+ children.append(child)
469
+ return children
470
+
471
  # Re-expose batch optimization so axioms engine remains self-contained
472
  _batched_deduce_and_evaluate = axioms._batched_deduce_and_evaluate
473
  _mprt_sample = axioms._mprt_sample