Jump to content

The Principia Machina/TPC-PY/run corpus.py

From The Invariance Itself
Revision as of 04:37, 28 September 2026 by BFP Rauch (talk | contribs) (1 revision imported)
# -*- coding: utf-8 -*-
"""
TPC cross-residence corpus runner (TPC-PY side), increment 9
=============================================================
Runs TPC-PY against every published vector corpus. Exit 0 iff all cases
pass. A residence "reproduces the corpus byte for byte" (PMP-TPM TPC)
exactly when this passes behind that residence. Standard library only;
Windows/Linux:

    python run_corpus.py                 # every vectors/*.json
    python run_corpus.py vectors/x.json  # one corpus

Two corpus forms are read, told apart by the case keys (the corpora are
never rewritten; the runner adapts):
  BASE FORM (increments 1-8, hold): {"meta": ..., "cases": [{"id", "fn",
    "input", "expect"}]}; the result is canon(dispatch(fn, input)), an
    exception rendered "ERROR: <msg>".
  RUN_CASE FORM (increment 9: falcon, biblio, cluster, hunk, identity,
    sponsor, beta, score, probe, volunteer, fingerprint; increment 10:
    lint, module; the wiki-base hunk vectors, hunk_wiki, answered by
    tpc_hunk): {"corpus": ...,
    "cases": [{"name", "fn", "args", "expected"}]}; the result is the
    module's run_case(fn, args), the module named by the corpus file
    (<name>_corpus.json -> tpc_<name>); tpc_cluster's run_case takes the
    whole case. run_case renders its own refusals "ERROR:<msg>".
"""
import glob
import json
import os
import platform
import sys
import unicodedata

import tpc_strike as S
import tpc_digest as G
import tpc_sr9 as C
import tpc_zone as Z
import tpc_yardstick as Y
import tpc_challenge as X
import tpc_units as U
import tpc_tests as K
import tpc_hold as HD
import tpc_form as F
import tpc_eom as EO
# increment 9 (run_case form); imported in dependency order
import tpc_beta as BT
import tpc_sponsor as SP
import tpc_falcon as FA
import tpc_biblio as BI
import tpc_cluster as CL
import tpc_hunk as HK
import tpc_identity as ID
import tpc_probe as PR
import tpc_volunteer as VO
import tpc_score as SO
import tpc_fingerprint as FP
# increment 10 (run_case form): the prompt lint, D182.1 F5
import tpc_lint as LI
# increment 10 (run_case form): environment modules, D178.1 (P2-04; tpm_module_spec 0.2.0)
import tpc_module as MO

# corpus file stem -> the module whose run_case answers it
RUN_CASE_MODULES = {
    "falcon": FA, "biblio": BI, "cluster": CL, "hunk": HK, "hunk_wiki": HK, "identity": ID,
    "sponsor": SP, "beta": BT, "score": SO, "probe": PR, "volunteer": VO,
    "fingerprint": FP, "lint": LI, "module": MO,
}


def dispatch(fn, inp):
    # the shared oracle itself: canon() of a value
    if fn == "canon":
        return inp["x"]
    # strike-rule arithmetic
    if fn == "a_of_r":
        return S.a_of_r(inp["rid"], inp["records"], inp.get("tfk_assumptions", []))
    if fn == "d_of_r":
        return S.d_of_r(inp["rid"], inp["records"], inp.get("tfk_assumptions", []))
    if fn == "sr8_scale_factor":
        return S.sr8_scale_factor(inp["measurements"])
    if fn == "mm_contradicts":
        return S.mm_contradicts(inp["x1"], inp["u1"], inp["x2"], inp["u2"], inp["k"], inp.get("S", 1.0))
    if fn == "lm_contradicts":
        return S.lm_contradicts(inp["x_l"], inp["x_m"], inp["u_m"], inp["k"], inp.get("S", 1.0))
    if fn == "sr5_order":
        return S.sr5_order(inp["d1"], inp["d2"])
    if fn == "sr6_independence_count":
        return S.sr6_independence_count(inp["sets"], inp.get("same_model"))
    if fn == "sr6_audit_opens":
        return S.sr6_audit_opens(inp["n_ind"], inp["n_x"])
    # the interim SR3 and SR8 scope (tpc_strike 0.2.0, proposed; D180.3)
    if fn == "sr3_scope":
        return S.sr3_scope(inp["tfk"], inp["quantity"])
    # digests
    if fn == "digest_fields":
        return G.digest_fields(inp["fields"])
    if fn == "combine_digests":
        return G.combine_digests(inp["hex_digests"])
    if fn == "d_tfk":
        return G.d_tfk(inp["d_tpk"], inp["d_trm"], inp["d_tms"])
    # SR9 C-test harness
    if fn == "sr9_c1":
        return C.sr9_c1(inp["entry"], inp["suite"])
    if fn == "sr9_c2":
        return C.sr9_c2(inp["entry"], inp["suite"])
    if fn == "sr9_c4":
        return C.sr9_c4(inp["entry"], inp["suite"])
    if fn == "sr9_harness":
        return C.sr9_harness(inp["entry"], inp["suite"])
    if fn == "tms_params_ok":
        return C.tms_params_ok(inp["params"])
    # TFK zone schemas (increment 4)
    if fn == "normalize_dimension":
        r = Z.normalize_dimension(inp["s"])
        return "null" if r is None else r
    if fn == "canon_decimal":
        r = Z.canon_decimal(inp["s"])
        return "null" if r is None else r
    if fn == "canonical_term":
        return Z.canonical_term(inp["t"])
    if fn == "is_canonical_dimension":
        return Z.is_canonical_dimension(inp["s"])
    if fn == "canon_dimension":
        return Z.canon_dimension(inp["exps"])
    if fn == "t1_well_formed":
        return Z.t1_well_formed(inp["tpk"])
    if fn == "trm_well_formed":
        return Z.trm_well_formed(inp["trm"], inp["tpk"])
    if fn == "tms_well_formed":
        return Z.tms_well_formed(inp["tms"])
    if fn == "zone_preimage":
        return Z.zone_preimage(inp["zone"], inp["value"])
    if fn == "d_tpk":
        return Z.d_tpk(inp["tpk"])
    if fn == "d_trm":
        return Z.d_trm(inp["trm"])
    if fn == "d_tms":
        return Z.d_tms(inp["tms"])
    if fn == "d_tfk_of":
        return Z.d_tfk_of(inp["tfk"])
    if fn == "classify_successor":
        return Z.classify_successor(inp["a"], inp["b"])
    # yardstick evaluator (increment 5)
    if fn == "yardstick_key":
        return Y.yardstick_key(inp["tms"], inp["name"], inp["rid"], inp["records"],
                               inp.get("tfk_assumptions", []))
    if fn == "yardstick_checks":
        return Y.yardstick_checks(inp["tms"], inp["name"], inp["suite"])
    if fn == "yardstick_harness":
        return Y.yardstick_harness(inp["tms"], inp["name"], inp["suite"])
    # execution challenge (D101.1)
    if fn == "challenge_preimage":
        return X.challenge_preimage(inp["nonce"])
    if fn == "challenge_response":
        return X.challenge_response(inp["nonce"])
    if fn == "challenge_verify":
        return X.challenge_verify(inp["nonce"], inp["response"])
    # units (increment 6; D103.1, D104.1, D105.1)
    if fn == "unit_parse":
        return U.unit_parse(inp["u"])
    if fn == "unit_scale":
        return U.unit_scale(inp["u"])
    if fn == "unit_matches":
        return U.unit_matches(inp["u"], inp["dimension"])
    if fn == "normalize_measurement":
        return U.normalize_measurement(inp["value"], inp["uncertainty"], inp["u"])
    if fn == "mm_contradicts_units":
        return U.mm_contradicts_units(inp["x1"], inp["u1"], inp["unit1"], inp["x2"], inp["u2"],
                                      inp["unit2"], inp["k"], inp.get("S", 1.0))
    if fn == "lm_contradicts_units":
        return U.lm_contradicts_units(inp["x_l"], inp["unit_l"], inp["x_m"], inp["u_m"],
                                      inp["unit_m"], inp["k"], inp.get("S", 1.0))
    if fn == "sr8_scale_factor_units":
        return U.sr8_scale_factor_units(inp["measurements"])
    # kernel tests and isomorphism checks (increment 7; D106-D108 pause)
    if fn == "t2_findings":
        return K.t2_findings(inp["prop"])
    if fn == "t2_atomicity":
        return K.t2_atomicity(inp["tpk"])
    if fn == "t3_consistency":
        return K.t3_consistency(inp["tpk"], inp["tms"])
    if fn == "t5_dof_yield":
        return K.t5_dof_yield(inp["tpk"])
    if fn == "kernel_tests":
        return K.kernel_tests(inp["tpk"])
    if fn == "ic_checks":
        return K.ic_checks(inp["trm"], inp["tpk"])
    if fn == "final_checks":
        return K.final_checks(inp["tfk"])
    # the hold-scope function (increment "hold scope"; D111.1, CO-21; 0.2.0: the
    # bibliography list, D171 (j))
    if fn == "hold_scope":
        return HD.hold_scope(inp["history"], inp["lookback_passes"])
    if fn == "held_closure":
        return HD.held_closure(inp["records"], inp["seeds"])
    if fn == "tpx_allocate":
        return HD.tpx_allocate(inp["range"])
    if fn == "hold_preimage":
        return HD.hold_preimage(inp["cause"], inp["seeds"], inp["held"], inp["biblio"])
    if fn == "hold_record":
        return HD.hold_record(inp["hold_id"], inp["cause"], inp["seeds"], inp["held"], inp["biblio"])
    if fn == "release_record":
        return HD.release_record(inp["release_id"], inp["hold"], inp["reproduction"], inp["records"])
    # the declared form (increment 8; D108.1 at Option 1 of every slot)
    if fn == "parse_form":
        return F.parse_form(inp["text"], inp["mode"])
    if fn == "form_names":
        return F.form_names(inp["text"], inp["mode"])
    if fn == "form_dimension":
        return F.form_dimension(inp["text"], inp["mode"], inp["dimensions"])
    if fn == "form_totality":
        return F.form_totality(inp["text"], inp["dimensions"])
    if fn == "eval_form":
        return F.eval_form(inp["text"], inp["mode"], inp["bindings"])
    if fn == "names_check":
        return F.names_check(inp["tpk"])
    if fn == "form_coverage":
        return F.form_coverage(inp["tpk"])
    if fn == "t4_homogeneity":
        return F.t4_homogeneity(inp["tpk"])
    if fn == "t6_totality":
        return F.t6_totality(inp["tpk"])
    if fn == "t3_laws":
        return F.t3_laws(inp["tpk"])
    if fn == "ic4a_signature":
        return F.ic4a_signature(inp["trm"], inp["tpk"])
    # the D variable (tpc_form 0.2.0, unreleased; D177.1)
    if fn == "d_variables":
        return F.d_variables(inp["tpk"])
    if fn == "d_variable_check":
        return F.d_variable_check(inp["tpk"])
    # the public parse tree (tpc_form 0.2.0, unreleased; S32)
    if fn == "form_tree":
        return F.form_tree(inp["text"], inp["mode"])
    if fn == "grammar_witness_count":
        return F.GRAMMAR_WITNESS_COUNT
    # the structure check of the equations of motion (tpc_eom 0.1.0, proposed; D176.1, D177.1)
    if fn == "eom_map":
        return EO.eom_map(inp["tfk"])
    if fn == "eom_findings":
        return EO.eom_findings(inp["tfk"])
    if fn == "eom_class":
        return EO.eom_class(inp["tfk"])
    if fn == "eom_register_test":
        return EO.eom_register_test(inp["tfk"], inp["records"])
    raise KeyError("unknown fn: %s" % fn)


def corpus_form(path, corpus):
    """BASE or RUN_CASE, read from the first case's keys; the module for a
    RUN_CASE corpus from the file stem <name>_corpus.json."""
    cases = corpus["cases"]
    if not cases:
        return "BASE", None
    c0 = cases[0]
    if "input" in c0 and "expect" in c0:
        return "BASE", None
    stem = os.path.basename(path)
    if stem.endswith("_corpus.json"):
        stem = stem[:-len("_corpus.json")]
    if stem not in RUN_CASE_MODULES:
        raise KeyError("no run_case module for corpus %s" % os.path.basename(path))
    return "RUN_CASE", RUN_CASE_MODULES[stem]


def run_one(path):
    with open(path, "r", encoding="utf-8") as f:
        corpus = json.load(f)
    form, mod = corpus_form(path, corpus)
    passed, failures = 0, []
    for c in corpus["cases"]:
        if form == "BASE":
            try:
                got = S.canon(dispatch(c["fn"], c["input"]))
            except Exception as e:
                got = "ERROR: %s" % e
            expect, cid = c["expect"], c["id"]
        else:
            try:
                if mod is CL:
                    got = mod.run_case(c)
                else:
                    got = mod.run_case(c["fn"], c["args"])
            except Exception as e:
                got = "EXCEPTION: %s: %s" % (type(e).__name__, e)
            expect, cid = c["expected"], c["name"]
        if got == expect:
            passed += 1
        else:
            failures.append((cid, expect, got))
    print("  %-22s %d/%d" % (os.path.basename(path), passed, len(corpus["cases"])),
          "PASS" if not failures else "FAIL")
    for cid, exp, got in failures:
        print("    FAIL %s  expected %r  got %r" % (cid, exp, got))
    return not failures


def main(argv):
    here = os.path.dirname(os.path.abspath(__file__))
    if len(argv) > 1:
        paths = [argv[1]]
    else:
        paths = sorted(glob.glob(os.path.join(here, "vectors", "*.json")))
    print("TPC-PY: strike %s, digest %s, sr9 %s, zone %s, yardstick %s, challenge %s, units %s, tests %s, hold %s, form %s, eom %s" % (
        S.TPC_STRIKE_VERSION, G.TPC_DIGEST_VERSION, C.TPC_SR9_VERSION, Z.TPC_ZONE_VERSION,
        Y.TPC_YARDSTICK_VERSION, X.TPC_CHALLENGE_VERSION, U.TPC_UNITS_VERSION, K.TPC_TESTS_VERSION,
        HD.TPC_HOLD_VERSION, F.TPC_FORM_VERSION, EO.TPC_EOM_VERSION))
    print("        falcon %s, biblio %s, cluster %s, hunk %s, identity %s, sponsor %s, beta %s, score %s, probe %s, volunteer %s, fingerprint %s, lint %s, module %s" % (
        FA.VERSION, BI.VERSION, CL.VERSION, HK.VERSION, ID.VERSION, SP.VERSION, BT.VERSION,
        SO.VERSION, PR.VERSION, VO.VERSION, FP.VERSION, LI.VERSION, MO.VERSION))
    ok = True
    for p in paths:
        ok = run_one(p) and ok
    print("RESULT:", "ALL PASS" if ok else "FAILURES")
    # the self-test fields an agent declares before claiming EXECUTED (D101.1, 4b)
    print("ENVIRONMENT: python %s, unicode %s" % (platform.python_version(), unicodedata.unidata_version))
    return 0 if ok else 1


if __name__ == "__main__":
    sys.exit(main(sys.argv))