"""Exact-value driver (T5/T6). For each n: * upper bound: smallest b at which the fort-cover search finds a witness quickly (descending from min(12, published bound)); the witness is replayed by closure_oracle and stored in results/upper_bound_witnesses.jsonl with the full chronology; * SAT lower bound: fort-cover UNSAT at b = Z_upper - 1 within the time limit (static final CNF re-solved with proof logging, DRAT checked by drat-trim); and, independently, the round-based encoding (P4) at s = Z_upper - 1 within its own time limit; * brute-force lower bound is read from results/brute_force_values.json when present. Every run is recorded in results/solver_runs.jsonl. usage: python3 code/run_exact.py N [N ...] (env: FORT_LIMIT, ROUND_LIMIT seconds) """ import json import os import sys import time import common from closure_oracle import closure, replay from graph_constructor import adjacency, edge_list_sha256, edges_formula, label from sat_or_ilp_solver import fort_cover, round_sat, solve_with_proof K = 5 FORT_LIMIT = float(os.environ.get("FORT_LIMIT", "900")) ROUND_LIMIT = float(os.environ.get("ROUND_LIMIT", "600")) def record(rec): rec["utc"] = common.utcnow() rec.update(common.versions()) common.append_jsonl(os.path.join(common.RESULTS, "solver_runs.jsonl"), rec) print(json.dumps(rec)[:300], flush=True) def upper_bound_search(n, start): """Descend b from start while a witness is found within a short limit.""" adj = adjacency(n, K) best = None b = start while b >= 1: r = fort_cover(n, K, b, time_limit=FORT_LIMIT) record({"n": n, "k": K, "method": "fort_cover", "bound": b, "sat": r["sat"], "iterations": r["iterations"], "forts": len(r["forts"]), "wall_seconds": r["wall_seconds"], "timeout": r["sat"] is None}) if r["sat"]: S = r["witness"] final, chron = closure(adj, S) assert len(final) == 2 * n ok, fin, bad = replay(adj, S, chron) assert ok and len(fin) == 2 * n best = {"n": n, "k": K, "size": len(S), "S": [label(w, n) for w in S], "chronology": [[label(a, n), label(c, n)] for a, c in chron], "graph_sha256": edge_list_sha256(edges_formula(n, K)), "source": "fort_cover", "utc": common.utcnow()} common.append_jsonl(os.path.join(common.RESULTS, "upper_bound_witnesses.jsonl"), best) b = len(S) - 1 continue return best, b, r # r is the UNSAT (or timeout) result at b return best, b, None def lower_bound_certificate(n, b, r): """r: fort_cover result with sat False at bound b. Re-solve the static CNF with proof logging.""" cert_dir = os.path.join(common.CERTS, "fortcover") os.makedirs(cert_dir, exist_ok=True) clauses = r["base_clauses"] + r["fort_clauses"] cnf_path = os.path.join(cert_dir, "P%d_5_atmost%d.cnf" % (n, b)) proof_path = os.path.join(cert_dir, "P%d_5_atmost%d.drat" % (n, b)) forts_path = os.path.join(cert_dir, "P%d_5_atmost%d.forts.json" % (n, b)) with open(forts_path, "w") as f: json.dump({"n": n, "k": K, "bound": b, "svar": r["svar"], "normalised": r["normalised"], "symmetric": r["symmetric"], "forts": r["forts"], "forts_labels": [[label(w, n) for w in F] for F in r["forts"]]}, f) out = solve_with_proof(clauses, r["nv"], "cadical195", cnf_path, proof_path) out.update({"n": n, "k": K, "bound": b, "method": "fort_cover_static_proof", "forts_path": os.path.relpath(forts_path, common.ROOT), "forts_sha256": common.sha256_file(forts_path), "num_forts": len(r["forts"])}) record(out) common.append_jsonl(os.path.join(common.RESULTS, "lower_bound_certificates.jsonl"), out) return out if __name__ == "__main__": ns = [int(a) for a in sys.argv[1:]] published = {11: 6, 12: 8, 13: 10, 14: 11, 16: 9} for n in ns: start = min(12, published.get(n, 12)) t0 = time.time() best, b, r = upper_bound_search(n, start) Zu = best["size"] if best else start lower = None if r is not None and r["sat"] is False: cert = lower_bound_certificate(n, b, r) lower = b + 1 # second path: round-based encoding at s = Zu - 1 # SKIP_ROUND=1 (reproduce.sh default mode) omits the round-based path, whose runs at n >= 18 only time out rr = round_sat(n, K, Zu - 1, time_limit=ROUND_LIMIT) if (n <= 30 and os.environ.get("SKIP_ROUND") != "1") else None if rr is not None: record({"n": n, "k": K, "method": "round_sat", "solver": rr["solver"], "bound": Zu - 1, "sat": rr["sat"], "T": rr["T"], "num_vars": rr["num_vars"], "num_clauses": rr["num_clauses"], "wall_seconds": rr["solve_seconds"], "timeout": rr["timeout"]}) print("n=%d: upper=%d (witness size), fort-cover lower=%s, round_sat(%d)=%s, total %.1fs" % ( n, Zu, lower, Zu - 1, rr["sat"] if rr else None, time.time() - t0), flush=True)