import subprocess, sys, glob, os
Z3RS = "./target/debug/z3rs"
DEFINITE = ("sat", "unsat")
ERR_MARKERS = ("error", "unsupported", "unknown symbol", "unknown function", "unknown sort")
def file_status(path):
try:
txt = open(path, encoding="utf-8", errors="ignore").read()
except OSError:
return None
import re
m = re.search(r":status\s+(sat|unsat|unknown)", txt)
return m.group(1) if m else None
def verdicts(cmd, timeout):
try:
r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
except subprocess.TimeoutExpired:
return None, "timeout"
out = r.stdout
v = [l.strip() for l in out.splitlines() if l.strip() in ("sat", "unsat", "unknown")]
err = "error" if (any(m in out.lower() for m in ERR_MARKERS) or r.returncode not in (0, 1)) else None
return v, err
def main():
pat = sys.argv[1] if len(sys.argv) > 1 else "**/*.smt2"
timeout = int(sys.argv[2]) if len(sys.argv) > 2 else 20
if os.path.isdir(pat):
pat = os.path.join(pat, "**", "*.smt2")
files = sorted(glob.glob(pat, recursive=True))
agree = disagree = unk = err = tmo = z3fail = 0
mismatches = []
for f in files:
ours, oerr = verdicts([Z3RS, f], timeout)
if oerr == "timeout":
tmo += 1; continue
if oerr == "error":
err += 1; continue
theirs, _ = verdicts(["z3", f], timeout)
if not theirs:
status = file_status(f)
if status in ("sat", "unsat") and ours:
if ours[0] == "unknown":
unk += 1
elif ours[0] == status:
agree += 1
else:
disagree += 1
mismatches.append((os.path.basename(f), ours, [f"status:{status}"]))
else:
z3fail += 1
continue
bad = False
for o, t in zip(ours, theirs):
if o == "unknown":
unk += 1
elif o in DEFINITE and t in DEFINITE and o != t:
bad = True
(mismatches.append((os.path.basename(f), ours, theirs)) or None) if bad else None
agree += 0 if bad else 1
disagree += 1 if bad else 0
print(f"files={len(files)} agree={agree} disagree={disagree} "
f"z3rs_unknown_lines={unk} z3rs_gap(error)={err} z3rs_timeout={tmo} z3_no_verdict={z3fail}")
for name, o, t in mismatches:
print(f" MISMATCH {name}: z3rs={o} z3={t}")
sys.exit(1 if disagree else 0)
if __name__ == "__main__":
main()