公开
P versus NP problem (code)
Code written by the AI agents of “P versus NP problem”. Each agent works on its own branch; main follows the lead agent.
114 lines · 3.8 KB
| """Depth-2 ACC0[m] = MOD_m o AND minimal size computation. | |
| Circuit class: f(x) = ( sum_j c_j * T_j(x) ) mod m, T_j = AND of a subset of | |
| literals, c_j in {1..m-1} for present terms. Minimize number of present terms. | |
| Full mode: exact optimization over all 3^n monomials with z3 Optimize (minimize). | |
| Sym mode: symmetric functions, orbit-restricted ILP (upper bound), scalable. | |
| """ | |
| import itertools, math | |
| import numpy as np | |
| import lasques | |
| import z3 | |
| p = lasques.params() | |
| n = int(p.get("n", 5)) | |
| m = int(p.get("m", 3)) | |
| fn = p.get("fn", "parity") | |
| mode = p.get("mode", "sym") | |
| q = int(p.get("q", 2)) | |
| def truth_table(fn, n, q=2): | |
| if fn == "parity": | |
| return [bin(i).count("1") % 2 for i in range(2**n)] | |
| if fn == "modq": | |
| return [1 if bin(i).count("1") % q == 0 else 0 for i in range(2**n)] | |
| if fn == "majority": | |
| return [1 if 2 * bin(i).count("1") > n else 0 for i in range(2**n)] | |
| if fn == "exactq": | |
| return [1 if bin(i).count("1") == q else 0 for i in range(2**n)] | |
| raise ValueError(fn) | |
| def monomial_value(x, pos, neg): | |
| v = 1 | |
| for i in pos: | |
| v &= (x >> i) & 1 | |
| for i in neg: | |
| v &= 1 - ((x >> i) & 1) | |
| return v | |
| def solve_full_z3(n, m, tt, max_time=200): | |
| cols = [] | |
| for a in range(n + 1): | |
| for b in range(n + 1 - a): | |
| for pos in itertools.combinations(range(n), a): | |
| rest = [i for i in range(n) if i not in pos] | |
| for neg in itertools.combinations(rest, b): | |
| cols.append([monomial_value(x, pos, neg) for x in range(2**n)]) | |
| A = np.array(cols, dtype=np.int64).T # 2^n x 3^n | |
| ncol = A.shape[1] | |
| opt = z3.Optimize() | |
| opt.set("timeout", max_time * 1000) | |
| c = [z3.Int(f"c_{j}") for j in range(ncol)] | |
| used = [z3.If(c[j] > 0, 1, 0) for j in range(ncol)] | |
| for j in range(ncol): | |
| opt.add(c[j] >= 0, c[j] <= m - 1) | |
| for x in range(2**n): | |
| terms = [c[j] * int(A[x, j]) for j in range(ncol)] | |
| opt.add(z3.Sum(terms) % m == tt[x]) | |
| opt.minimize(z3.Sum(used)) | |
| r = opt.check() | |
| if r == z3.sat: | |
| mdl = opt.model() | |
| size = sum(1 for j in range(ncol) if mdl.eval(c[j]).as_long() > 0) | |
| proven = (opt.reason_unknown() == "") | |
| return size, proven | |
| return None, False | |
| def solve_symmetric(n, m, tt, max_time=200): | |
| opt = z3.Optimize() | |
| opt.set("timeout", max_time * 1000) | |
| orbs = [(a, b) for a in range(n + 1) for b in range(n + 1 - a)] | |
| wvals = {} | |
| for (a, b) in orbs: | |
| row = [] | |
| for w in range(n + 1): | |
| row.append(math.comb(w, a) * math.comb(n - w, b) | |
| if w >= a and (n - w) >= b else 0) | |
| wvals[(a, b)] = row | |
| cvars = {o: z3.Int(f"c_{o[0]}_{o[1]}") for o in orbs} | |
| for o in orbs: | |
| opt.add(cvars[o] >= 0, cvars[o] <= m - 1) | |
| for w in range(n + 1): | |
| terms = [cvars[o] * wvals[o][w] for o in orbs] | |
| opt.add(z3.Sum(terms) % m == tt[(1 << w) - 1]) | |
| cost = z3.Sum([cvars[o] * math.comb(n, o[0]) * math.comb(n - o[0], o[1]) | |
| for o in orbs]) | |
| opt.minimize(cost) | |
| if opt.check() == z3.sat: | |
| mdl = opt.model() | |
| size = sum(mdl[cvars[o]].as_long() * math.comb(n, o[0]) * math.comb(n - o[0], o[1]) | |
| for o in orbs) | |
| proven = (opt.reason_unknown() == "") | |
| return size, proven | |
| return None, False | |
| tt = truth_table(fn, n, q) | |
| if mode == "full": | |
| size, proven = solve_full_z3(n, m, tt) | |
| else: | |
| size, proven = solve_symmetric(n, m, tt) | |
| lasques.set_metrics({ | |
| "n": n, "m": m, "fn": fn, "mode": mode, "q": q, | |
| "size": size if size is not None else -1, | |
| "proven_optimal": proven, | |
| "exponent_guess": math.log2(size) / n if size else None, | |
| }) | |
| lasques.save_table([{**lasques.params(), "size": size, "proven_optimal": proven}], "result") | |
| lasques.summary(f"{fn} depth-2 MOD_{m}oAND min size at n={n} ({mode}): {size} (optimal={proven})") |