Buckets:
| """leaner_ce — a lean, dependency-free counterexample engine for the Solo protocol. | |
| The FALSE-side engine for a flagship solver: given `E1 ⇒ E2?`, find a finite | |
| magma (Fin n, ◇) where E1 holds for all assignments and E2 fails for some | |
| assignment, and submit it as a Lean `decideFin!` certificate. | |
| Single file, Python stdlib only (no pysat / no LLM), well under 500 KB. Escalating | |
| deterministic ladder: | |
| 1. exhaustive Fin 2-3 | |
| 2. structured table families Fin 2-7 + direct products | |
| 3. constraint-propagation backtracking Fin 4-6 | |
| 4. value-symmetry targeted backtracking Fin 6 (pin E2 sides to 0/1, propagate) | |
| On the 850 public FALSE problems this clears 848 (only hard2_0027/0051 need a | |
| large magma). It has no true-implication prover — an integrator pairs it with a | |
| proof stage (deterministic miners + LLM) for the full flagship. | |
| Assembled from the tested cebench modules (core/search/backtrack); see | |
| artifacts/ce-backtrack_leaner/ for the development version + benchmarks. | |
| """ | |
| import json | |
| import re | |
| import sys | |
| import time | |
| from itertools import product, permutations | |
| DIAMOND = "◇" | |
| # ── protocol ── | |
| def read_message(): | |
| line = sys.stdin.readline() | |
| if not line: | |
| sys.exit(0) | |
| return json.loads(line.strip()) | |
| def send_message(msg): | |
| print(json.dumps(msg), flush=True) | |
| def call_judge(verdict, code): | |
| send_message({"call": "judge", "verdict": verdict, "code": code}) | |
| return read_message() | |
| # ── equation parse + codegen evaluator ── | |
| def _normalize(text): | |
| return text.replace("*", DIAMOND) | |
| def parse_variables(text): | |
| seen, out = set(), [] | |
| for v in re.findall(r"\b([a-z])\b", text): | |
| if v not in seen: | |
| seen.add(v) | |
| out.append(v) | |
| return out | |
| def _parse_expr(s, vars_set): | |
| s = s.strip() | |
| while len(s) >= 2 and s[0] == "(" and s[-1] == ")": | |
| depth = 0 | |
| matched = True | |
| for i, c in enumerate(s): | |
| if c == "(": | |
| depth += 1 | |
| elif c == ")": | |
| depth -= 1 | |
| if depth == 0 and i < len(s) - 1: | |
| matched = False | |
| break | |
| if matched: | |
| s = s[1:-1].strip() | |
| else: | |
| break | |
| depth = 0 | |
| last_op = -1 | |
| for i, c in enumerate(s): | |
| if c == "(": | |
| depth += 1 | |
| elif c == ")": | |
| depth -= 1 | |
| elif c == DIAMOND and depth == 0: | |
| last_op = i | |
| if last_op >= 0: | |
| return ("op", _parse_expr(s[:last_op], vars_set), | |
| _parse_expr(s[last_op + 1:], vars_set)) | |
| s = s.strip() | |
| if len(s) == 1 and s in vars_set: | |
| return s | |
| raise ValueError(f"cannot parse: {s!r}") | |
| def _expr_code(ast): | |
| if isinstance(ast, str): | |
| return ast | |
| _, l, r = ast | |
| return f"t[{_expr_code(l)}][{_expr_code(r)}]" | |
| class Equation: | |
| __slots__ = ("variables", "lhs", "rhs", "_holds", "_violated") | |
| def __init__(self, text): | |
| text = _normalize(text) | |
| self.variables = parse_variables(text) | |
| vs = set(self.variables) | |
| lhs_str, rhs_str = text.split("=", 1) | |
| self.lhs = _parse_expr(lhs_str, vs) | |
| self.rhs = _parse_expr(rhs_str, vs) | |
| k = len(self.variables) | |
| if k == 0: | |
| unpack = "_" | |
| elif k == 1: | |
| unpack = self.variables[0] + "," | |
| else: | |
| unpack = ", ".join(self.variables) | |
| lc, rc = _expr_code(self.lhs), _expr_code(self.rhs) | |
| ns = {} | |
| exec(f"def _h(t, A):\n for {unpack} in A:\n if {lc}!={rc}: return False\n return True\n", ns) | |
| exec(f"def _v(t, A):\n for {unpack} in A:\n if {lc}!={rc}: return True\n return False\n", ns) | |
| self._holds, self._violated = ns["_h"], ns["_v"] | |
| def holds(self, t, A): | |
| return self._holds(t, A) | |
| def violated(self, t, A): | |
| return self._violated(t, A) | |
| _AC = {} | |
| def assigns(n, k): | |
| key = (n, k) | |
| a = _AC.get(key) | |
| if a is None: | |
| a = _AC[key] = list(product(range(n), repeat=k)) | |
| return a | |
| # ── structured table families ── | |
| def structured_tables(n): | |
| for c in range(n): | |
| yield [[c] * n for _ in range(n)] | |
| yield [[i] * n for i in range(n)] | |
| yield [list(range(n)) for _ in range(n)] | |
| yield [[(i + j) % n for j in range(n)] for i in range(n)] | |
| yield [[(i - j) % n for j in range(n)] for i in range(n)] | |
| yield [[max(i, j) for j in range(n)] for i in range(n)] | |
| yield [[min(i, j) for j in range(n)] for i in range(n)] | |
| yield [[i if i != 0 else j for j in range(n)] for i in range(n)] | |
| yield [[j if j != 0 else i for j in range(n)] for i in range(n)] | |
| for k in range(1, n): | |
| yield [[(i + k) % n] * n for i in range(n)] | |
| yield [[(j + k) % n for j in range(n)] for _ in range(n)] | |
| if n > 1: | |
| yield [[(i * j) % n for j in range(n)] for i in range(n)] | |
| if n in (2, 4): | |
| yield [[(i ^ j) % n for j in range(n)] for i in range(n)] | |
| for c in range(n): | |
| for thresh in range(1, n): | |
| yield [[i if i < thresh else c for _ in range(n)] for i in range(n)] | |
| yield [[j if j < thresh else c for j in range(n)] for _ in range(n)] | |
| yield [[i if i >= j else j for j in range(n)] for i in range(n)] | |
| yield [[i if i <= j else j for j in range(n)] for i in range(n)] | |
| yield [[i for _ in range(n)] for i in range(n)] | |
| yield [[j for j in range(n)] for _ in range(n)] | |
| if n >= 2: | |
| yield [[0 if i != j else i for j in range(n)] for i in range(n)] | |
| yield [[(i + j + 1) % n for j in range(n)] for i in range(n)] | |
| if n >= 3: | |
| yield [[i if i == j else (i + j) % n for j in range(n)] for i in range(n)] | |
| yield [[i if i == j else 0 for j in range(n)] for i in range(n)] | |
| yield [[i if i == j else n - 1 for j in range(n)] for i in range(n)] | |
| if n <= 4: | |
| for perm in permutations(range(n)): | |
| yield [[perm[j] for j in range(n)] for _ in range(n)] | |
| yield [[perm[i] for _ in range(n)] for i in range(n)] | |
| if n >= 4: | |
| for d in range(2, n): | |
| if n % d == 0: | |
| m = n // d | |
| yield [[(i // m) * m + (j % m) for j in range(n)] for i in range(n)] | |
| yield [[(i % d) + (j // d) * d for j in range(n)] for i in range(n)] | |
| if n <= 5: | |
| for chooser in range(min(2 ** (n * n), 1025)): | |
| table = [[0] * n for _ in range(n)] | |
| valid = True | |
| for i in range(n): | |
| for j in range(n): | |
| bit = (chooser >> (i * n + j)) & 1 | |
| table[i][j] = i if bit else j | |
| if i == j and table[i][j] != i: | |
| valid = False | |
| break | |
| if not valid: | |
| break | |
| if valid: | |
| yield table | |
| for c in range(n): | |
| t = [[c] * n for _ in range(n)] | |
| for i in range(n): | |
| t[i][i] = i | |
| yield t | |
| if n >= 2: | |
| yield [[(n - 1 - i) for _ in range(n)] for i in range(n)] | |
| yield [[(n - 1 - j) for j in range(n)] for _ in range(n)] | |
| yield [[(n - 1 - i + j) % n for j in range(n)] for i in range(n)] | |
| yield [[(i + n - 1 - j) % n for j in range(n)] for i in range(n)] | |
| for a in range(n): | |
| for b in range(n): | |
| if (a, b) in ((0, 0), (1, 1)): | |
| continue | |
| yield [[(a * i + b * j) % n for j in range(n)] for i in range(n)] | |
| for a in range(1, min(n, 4)): | |
| for b in range(1, min(n, 4)): | |
| for c in range(1, min(n, 3)): | |
| yield [[(a * i + b * j + c) % n for j in range(n)] for i in range(n)] | |
| def product_tables(n): | |
| for p in range(2, n): | |
| if n % p: | |
| continue | |
| q = n // p | |
| for a1 in range(p): | |
| for b1 in range(q): | |
| for a2 in range(p): | |
| for b2 in range(q): | |
| if a1 == a2 == b1 == b2 == 0: | |
| continue | |
| table = [[0] * n for _ in range(n)] | |
| for i in range(n): | |
| for j in range(n): | |
| r, s = i // q, i % q | |
| tt, u = j // q, j % q | |
| table[i][j] = ((a1 * r + a2 * tt) % p) * q + (b1 * s + b2 * u) % q | |
| yield table | |
| # ── searches ── | |
| def search_exhaustive(e1, e2, max_n=3): | |
| k1, k2 = len(e1.variables), len(e2.variables) | |
| for n in range(2, max_n + 1): | |
| A1, A2 = assigns(n, k1), assigns(n, k2) | |
| for enc in range(n ** (n * n)): | |
| t = [[(enc // (n ** (i * n + j))) % n for j in range(n)] for i in range(n)] | |
| if e1.holds(t, A1) and e2.violated(t, A2): | |
| return n, t | |
| return None, None | |
| def search_structured(e1, e2, max_n=7): | |
| k1, k2 = len(e1.variables), len(e2.variables) | |
| for n in range(2, max_n + 1): | |
| A1, A2 = assigns(n, k1), assigns(n, k2) | |
| for t in structured_tables(n): | |
| if e1.holds(t, A1) and e2.violated(t, A2): | |
| return n, t | |
| for n in range(4, 10): | |
| A1, A2 = assigns(n, k1), assigns(n, k2) | |
| for t in product_tables(n): | |
| if e1.holds(t, A1) and e2.violated(t, A2): | |
| return n, t | |
| return None, None | |
| # constraint-propagation backtracking (see cebench/backtrack.py) | |
| KNOWN, CELL, OPEN = 0, 1, 2 | |
| def _ground(ast, env): | |
| if isinstance(ast, str): | |
| return env[ast] | |
| _, l, r = ast | |
| return (_ground(l, env), _ground(r, env)) | |
| def _gcons(eq, n): | |
| k = len(eq.variables) | |
| out = [] | |
| for a in assigns(n, k): | |
| env = dict(zip(eq.variables, a)) | |
| out.append((_ground(eq.lhs, env), _ground(eq.rhs, env))) | |
| return out | |
| def _eval(gt, T, n): | |
| if isinstance(gt, int): | |
| return (KNOWN, gt) | |
| l, r = gt | |
| sl = _eval(l, T, n) | |
| if sl[0] != KNOWN: | |
| return (OPEN, sl[1]) | |
| sr = _eval(r, T, n) | |
| if sr[0] != KNOWN: | |
| return (OPEN, sr[1]) | |
| cell = sl[1] * n + sr[1] | |
| v = T[cell] | |
| return (KNOWN, v) if v != -1 else (CELL, cell) | |
| def _propagate(T, n, cons, trail): | |
| progress = True | |
| while progress: | |
| progress = False | |
| for lg, rg in cons: | |
| s1, v1 = _eval(lg, T, n) | |
| s2, v2 = _eval(rg, T, n) | |
| if s1 == KNOWN and s2 == KNOWN: | |
| if v1 != v2: | |
| return False | |
| elif s1 == KNOWN and s2 == CELL: | |
| T[v2] = v1 | |
| trail.append(v2) | |
| progress = True | |
| elif s2 == KNOWN and s1 == CELL: | |
| T[v1] = v2 | |
| trail.append(v1) | |
| progress = True | |
| return True | |
| def _pick(T, n, cons): | |
| for lg, rg in cons: | |
| s1, v1 = _eval(lg, T, n) | |
| s2, v2 = _eval(rg, T, n) | |
| if s1 == KNOWN and s2 == KNOWN: | |
| continue | |
| if s1 in (CELL, OPEN): | |
| return v1 | |
| if s2 in (CELL, OPEN): | |
| return v2 | |
| return None | |
| def _e2_complete(T, n, e2): | |
| A2 = assigns(n, len(e2.variables)) | |
| base = [x if x != -1 else 0 for x in T] | |
| tbl = [base[i * n:(i + 1) * n] for i in range(n)] | |
| if e2.violated(tbl, A2): | |
| return tbl | |
| free = [i for i in range(n * n) if T[i] == -1] | |
| if free and n ** len(free) <= 20000: | |
| for combo in product(range(n), repeat=len(free)): | |
| for c, val in zip(free, combo): | |
| base[c] = val | |
| tbl = [base[i * n:(i + 1) * n] for i in range(n)] | |
| if e2.violated(tbl, A2): | |
| return tbl | |
| return None | |
| def search_backtrack(e1, e2, n, deadline): | |
| cons = _gcons(e1, n) | |
| T = [-1] * (n * n) | |
| def rec(): | |
| if time.time() > deadline: | |
| return None | |
| cell = _pick(T, n, cons) | |
| if cell is None: | |
| return _e2_complete(T, n, e2) | |
| for val in range(n): | |
| trail = [cell] | |
| T[cell] = val | |
| if _propagate(T, n, cons, trail): | |
| res = rec() | |
| if res is not None: | |
| return res | |
| for c in trail: | |
| T[c] = -1 | |
| return None | |
| return rec() | |
| def search_targeted(e1, e2, n, deadline): | |
| """Pin E2.lhs(a2)=0, E2.rhs(a2)=1 (WLOG by value symmetry) and propagate.""" | |
| cons1 = _gcons(e1, n) | |
| for a2 in assigns(n, len(e2.variables)): | |
| if time.time() > deadline: | |
| return None | |
| env = dict(zip(e2.variables, a2)) | |
| l2, r2 = _ground(e2.lhs, env), _ground(e2.rhs, env) | |
| if l2 == r2: | |
| continue | |
| cons = cons1 + [(l2, 0), (r2, 1)] | |
| T = [-1] * (n * n) | |
| def rec(): | |
| if time.time() > deadline: | |
| return None | |
| cell = _pick(T, n, cons) | |
| if cell is None: | |
| return [[(T[i * n + j] if T[i * n + j] != -1 else 0) | |
| for j in range(n)] for i in range(n)] | |
| for val in range(n): | |
| trail = [cell] | |
| T[cell] = val | |
| if _propagate(T, n, cons, trail): | |
| res = rec() | |
| if res is not None: | |
| return res | |
| for c in trail: | |
| T[c] = -1 | |
| return None | |
| res = rec() | |
| if res is not None: | |
| return res | |
| return None | |
| def search_affine(e1, e2, min_n=2, max_n=32, deadline=None): | |
| """Parametric affine sweep: op(x,y) = (a*x + b*y + c) mod n over a,b,c in Z_n. | |
| Reaches affine counterexamples at orders that the Fin<=7 structured / | |
| backtracking / targeted search all miss, at ~ms per candidate — fully | |
| deterministic and general (not a lookup). E.g. hard2_0051 is 7*(x+y) mod 13, | |
| invisible to arbitrary-cell search but instant here. (Credit: django-cat.) | |
| Returns (n, a, b, c) so the caller emits a finOpTable-free direct-Fin cert | |
| (make_false_affine_code), which is SOUND at every order (unlike finOpTable, | |
| which mis-parses entries >=10).""" | |
| k1, k2 = len(e1.variables), len(e2.variables) | |
| for n in range(min_n, max_n + 1): | |
| if deadline and time.time() > deadline: | |
| return None, None, None, None | |
| A1, A2 = assigns(n, k1), assigns(n, k2) | |
| for a in range(n): | |
| for b in range(n): | |
| for c in range(n): | |
| t = [[(a * i + b * j + c) % n for j in range(n)] for i in range(n)] | |
| if e1.holds(t, A1) and e2.violated(t, A2): | |
| return n, a, b, c | |
| return None, None, None, None | |
| # ── certificate ── | |
| def make_false_code(n, table): | |
| return ( | |
| "import JudgeProblem\n" | |
| "import JudgeDecide.DecideBang\n" | |
| "import JudgeFinOp.MemoFinOp\n" | |
| "open MemoFinOp\n\n" | |
| "set_option maxRecDepth 100000 in\n" | |
| "set_option maxHeartbeats 4000000 in\n" # decideFin! at Fin>=11 exceeds the 200k default | |
| "def submission : Goal := by\n" | |
| f" let m : Magma (Fin {n}) := {{\n" | |
| f" op := finOpTable \"{json.dumps(table)}\"\n" | |
| f" }}\n" | |
| f" refine ⟨Fin {n}, m, ?_⟩\n" | |
| f" decideFin!\n" | |
| ) | |
| def make_false_affine_code(n, a, b, c): | |
| """Affine op given DIRECTLY as x ◇ y = (a*x + b*y + c) mod n via Fin.mul / | |
| Fin.add — no finOpTable, so it is SOUND at every order (finOpTable's | |
| extractDigits mis-parses table entries >=10). The judge's declaration | |
| allowlist admits Fin.* (but not the HMul./HAdd. wrappers). (Template credit: | |
| django-cat's hard2_0051 cert, x ◇ y = 7*(x+y) mod 13.)""" | |
| op = (f"fun x y => Fin.add (Fin.add (Fin.mul ({a} : Fin {n}) x) " | |
| f"(Fin.mul ({b} : Fin {n}) y)) ({c} : Fin {n})") | |
| return ( | |
| "import JudgeProblem\n" | |
| "import JudgeDecide.DecideBang\n\n" | |
| "set_option maxRecDepth 100000 in\n" | |
| "set_option maxHeartbeats 4000000 in\n" # decideFin! at Fin>=11 exceeds the 200k default | |
| "def submission : Goal := by\n" | |
| f" refine ⟨Fin {n}, ⟨{op}⟩, ?_⟩\n" | |
| " decideFin!\n" | |
| ) | |
| def find_counterexample(e1, e2, budget_s): | |
| """Returns a full Lean FALSE-certificate string, or None if no CE is found.""" | |
| t0 = time.time() | |
| n, t = search_exhaustive(e1, e2, max_n=3) | |
| if n: | |
| return make_false_code(n, t) | |
| n, t = search_structured(e1, e2, max_n=7) | |
| if n: | |
| return make_false_code(n, t) | |
| # plain propagation backtracking is fast (<=8s) & complete at small n; it | |
| # owns Fin 4-5 and finds small arbitrary CEs the structured families miss. | |
| for size in (4, 5): | |
| t = search_backtrack(e1, e2, size, deadline=min(t0 + budget_s * 0.5, time.time() + 8)) | |
| if t is not None: | |
| return make_false_code(size, t) | |
| # Affine Z_n sweep BEFORE the expensive Fin 6-7 targeted search. It is cheap | |
| # (~seconds to Fin 13) and its cost is machine-independent, so affine-only | |
| # CEs (hard2_0051 @ Fin13, hard2_0096 @ Fin9) are found in seconds rather | |
| # than after a ~100s fruitless targeted search — keeping the recovery ROBUST | |
| # on slow eval hardware instead of racing the deadline. Emitted via the | |
| # finOpTable-free direct-Fin cert, so it is sound at any order (finOpTable | |
| # mis-parses table entries >=10). min_n=8 because Fin<=7 (affine included) | |
| # is already covered by search_structured/backtrack above. Any CE it returns | |
| # is verified (holds ∧ violated), so it can only add solves, never flip a | |
| # verdict; running it before targeted (not after) makes 0051/0096 robust | |
| # while keeping small-n arbitrary CEs (backtrack) as the preferred cert. | |
| n, a, b, c = search_affine(e1, e2, min_n=8, max_n=13, | |
| deadline=min(t0 + budget_s * 0.6, t0 + 15)) | |
| if n: | |
| return make_false_affine_code(n, a, b, c) | |
| # targeted search (pin E2 sides) owns Fin 6 — it finds what plain backtrack | |
| # + all-zero completion misses. Expensive, so it runs last. | |
| for size in (6, 7): | |
| t = search_targeted(e1, e2, size, deadline=t0 + budget_s * 0.95) | |
| if t is not None: | |
| return make_false_code(size, t) | |
| return None | |
| def main(): | |
| startup = read_message() | |
| problem = startup["problem"] | |
| budget = startup.get("budget", {}) or {} | |
| budget_s = min(float(budget.get("timeout_seconds", 60)), 120) | |
| e1 = Equation(problem["equation1"]) | |
| e2 = Equation(problem["equation2"]) | |
| code = find_counterexample(e1, e2, budget_s) | |
| if code is not None: | |
| call_judge("false", code) | |
| # No true-implication prover in this FALSE engine; if no CE, exit (unsolved). | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 18.6 kB
- Xet hash:
- e5c6f3bcfb1298cb3d2f6845b249b06a66a43e0038b1a1bf9375b124d790a925
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.