Jump to content

The Principia Machina/TPC-PY/diff volunteer.py

From The Invariance Itself
"""diff_volunteer 0.1.0: the cross-residence differential for
tpc_volunteer 0.1.0. Random inputs from a seed over every function
(random r values, states across every branch of the draw, the params
fixture varied), both residences on the same inputs, every render
compared byte for byte; 0 differences is the pass.
Usage: python3 diff_volunteer.py [seed] [cases]."""
import json
import os
import random
import subprocess
import sys
import tempfile

here = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, here)
from params_fixture import FLEET, fleet  # noqa: E402
from tpc_volunteer import run_case, FNS  # noqa: E402

seed = int(sys.argv[1]) if len(sys.argv) > 1 else 1
count = int(sys.argv[2]) if len(sys.argv) > 2 else 20000
rnd = random.Random(seed)


def pick(xs):
    return xs[rnd.randrange(len(xs))]


def bad():
    return rnd.random() < 0.03


def kind(good, more):
    return pick(more) if bad() else pick(good)


def rhex():
    if bad():
        return pick(["", "zz", "0" * 31, "A" * 32, 5])
    return "%032x" % rnd.getrandbits(128)


def cnt(lo, hi):
    if bad():
        return pick([True, None, "5", 1.5, -1])
    return rnd.randint(lo, hi)


def unit():
    if bad():
        return pick([True, None, "0.5", -0.1, 1.5])
    return round(rnd.random(), rnd.randint(0, 6))


def flag():
    return (rnd.random() < 0.5) if not bad() else pick([1, "x", None])


def params():
    p = fleet()
    r = rnd.random()
    if r < 0.5:
        return p
    invalid = r > 0.93
    for _ in range(rnd.randint(1, 3)):
        k = pick(["VOLUNTEER TIER", "VOLUNTEER RATE", "VOLUNTEER BURST", "BACKOFF BASE", "BACKOFF CAP",
                  "INTAKE w_q", "INTAKE MIN", "INTAKE MAX", "INTAKE MAX_P", "P_V BOUNDS", "P_V ROTATION",
                  "EARLY CALL LIMIT", "VOLUNTEER COOL-OFF", "CONSISTENCY SHARE"])
        if k == "VOLUNTEER TIER":
            p[k] = pick(["ANY GREEN", "TRUST TIER"] + (["TOP"] if invalid else []))
        elif k == "P_V BOUNDS":
            p[k] = pick([[0.25, 0.5], [0.1, 0.2], [0.4, 0.4], [0.01, 0.99]] + ([[0, 0.5], [0.5, 1], [0.5, 0.25]] if invalid else []))
        elif k in ("VOLUNTEER BURST", "EARLY CALL LIMIT", "VOLUNTEER COOL-OFF"):
            p[k] = pick([1, 2, 3, 5, 10, 200] + ([0, -1, 1.5] if invalid else []) if k != "EARLY CALL LIMIT" else [0, 1, 3, 5] + ([-1, 1.5] if invalid else []))
        elif k in ("BACKOFF BASE", "BACKOFF CAP"):
            p[k] = pick([60, 300, 3600, 14400] + ([0.5, 100000000000000] if invalid else []))
        elif k == "VOLUNTEER RATE":
            p[k] = pick([2, 60, 0.5, 1] + ([0, -1] if invalid else []))
        else:
            p[k] = pick([0.1, 0.2, 0.25, 0.5, 0.9, 1, 0] + ([1.5, -0.1, "x"] if invalid else []))
    if invalid and rnd.random() < 0.3:
        del p[pick(["VOLUNTEER TIER", "VOLUNTEER RATE", "BACKOFF CAP", "INTAKE MIN", "P_V BOUNDS"])]
    return p


def facts():
    f = {"certificate_current": rnd.random() < 0.96, "dis_match": rnd.random() < 0.96,
         "state": kind(["GREEN"] * 8 + ["YELLOW", "ORANGE", "SUSPENDED"], ["RED"]),
         "reset_in_force": rnd.random() < 0.05, "suspended": rnd.random() < 0.03, "in_tier": rnd.random() < 0.5}
    if bad():
        f["certificate_current"] = 1
    if bad():
        del f["in_tier"]
    return f


def bucket():
    return {"tokens": kind([0, 0.5, 1, 1.75, 2, 3, round(rnd.uniform(0, 3), 4)], [-1, True, "1"]),
            "updated": cnt(0, 2000000)}


def gen(fn):
    p = params()
    if fn == "standing":
        return {"facts": facts(), "params": p}
    if fn == "refill":
        b = bucket()
        now = b["updated"] + rnd.randint(0, 40000) if isinstance(b["updated"], int) and not bad() else cnt(0, 100)
        return {"bucket": b, "now": now, "params": p}
    if fn == "take":
        return {"bucket": bucket()}
    if fn == "retry":
        return {"attempt": kind([0, 1, 2, 3, 5, 6, 10, 1023, 1024, 5000], [-1, 1.5]), "r": rhex(), "params": p}
    if fn == "intake":
        landed = cnt(0, 100)
        vol = rnd.randint(0, landed) if isinstance(landed, int) and landed >= 0 and not bad() else cnt(0, 100)
        return {"intake": unit(), "volunteer_blocks": vol, "landed_blocks": landed, "params": p}
    if fn == "p_nw":
        return {"intake": kind([0, 0.25, 0.375, 0.5, 0.51, 1, round(rnd.random(), 4)], [-0.1, 1.1]), "params": p}
    if fn == "pv":
        return {"state": {"p_v": kind([None, 0.3, 0.25, 0.5, round(rnd.random(), 4)], [1.5, "x"])} if not bad() else {},
                "r": rhex(), "params": p}
    if fn == "share":
        return {"window": [{"volunteer": flag(), "weight": kind([0, 0.5, 1, 2, round(rnd.uniform(0, 3), 3)], [-1, "1"])}
                           for _ in range(rnd.randint(0, 6))] if not bad() else {},
                "g": kind([1, 2, 0.5], [0, -1]), "v_max": kind([0.25, 0.5, 0.1], [0, 1])}
    now = rnd.randint(2000, 8000)
    st = {"bucket": {"tokens": pick([3, 2, 1.5, 1, 0.9, 0, round(rnd.uniform(0, 3), 3)]), "updated": now - rnd.randint(0, 5000)},
          "retry_until": pick([None] * 6 + [float(now - 10), float(now + 100), float(now), 99999.0, float(rnd.randint(0, 9000))]),
          "attempt": rnd.randint(0, 8), "refusals": rnd.randint(0, 4), "period": rnd.randint(0, 3),
          "closed_until": pick([None] * 6 + [0, 50, 100, 1000]), "intake": pick([0, 0.1, 0.3, 0.45, 0.6, round(rnd.random(), 3)]),
          "p_v": {"p_v": pick([None, 0.3, 0.999, 0.25, 0.5])}}
    if rnd.random() < 0.05:
        st[pick(list(st.keys()))] = pick([None, -1, "x", 1.5])
    per = st["period"] + rnd.randint(0, 1) if isinstance(st["period"], int) else 0
    call = {"now": now, "block": rnd.randint(0, 1200), "period": per, "has_item": rnd.random() < 0.6, "has_falcon": rnd.random() < 0.1,
            "has_own_record": rnd.random() < 0.5, "ratio_k": pick([1 / 3, 0.5, 1000, 0.000001, 0.2]), "standing": facts()}
    if rnd.random() < 0.05:
        call[pick(list(call.keys()))] = pick([None, -1, "x", 1.5, 0])
    return {"state": st, "call": call, "r": rhex(), "params": p}


cases = []
for _ in range(count):
    fn = pick(FNS + ("draw", "draw", "draw"))
    cases.append({"fn": fn, "args": gen(fn)})
CASES_PATH = os.environ.get("TPC_DIFF_CASES")  # named: kept, for crosspy.py
if not CASES_PATH:
    fd, CASES_PATH = tempfile.mkstemp(prefix="tpc_diff_", suffix=".json")  # outside the tree
    os.close(fd)
with open(CASES_PATH, "w", encoding="utf-8") as f:
    json.dump(cases, f, ensure_ascii=False)
py = [run_case(c["fn"], c["args"]) for c in cases]
php = json.loads(subprocess.run(["php", os.path.join(here, "diff_volunteer.php"), CASES_PATH], capture_output=True,
                                text=True, check=True).stdout)
if not os.environ.get("TPC_DIFF_CASES"):
    os.remove(CASES_PATH)
diffs = sum(1 for a, b in zip(py, php) if a != b)
outcomes = {}
for c, a in zip(cases, py):
    k = c["fn"] + ("/ERROR" if a.startswith("ERROR") else "")
    if c["fn"] == "draw" and not a.startswith("ERROR"):
        k = "draw/" + a.split("\n")[0].split("|")[1]
    outcomes[k] = outcomes.get(k, 0) + 1
print("seed", seed, "cases", len(cases), "differences", diffs, "php_len", len(php),
      json.dumps(outcomes, sort_keys=True))
for c, a, b in zip(cases, py, php):
    if a != b:
        print(json.dumps(c, ensure_ascii=False)); print(a); print("---"); print(b); break