Jump to content

The Principia Machina/TPC-PY/tpc yardstick.py: Difference between revisions

From The Invariance Itself
TPC-PY source tpc_yardstick.py (0.1.0), SHA-256 0b92c6d3f06e7583; conformed TPS 0.3.0; PROPOSED, not declared (CO-8)
 
m 1 revision imported
(No difference)

Revision as of 04:37, 28 September 2026

# -*- coding: utf-8 -*-
"""
TPC-PY --- the yardstick evaluator (TPC step 2, increment 5)
============================================================
Compiles a yardstick declared in a UWC's TMS (the closed grammar of
D100.1; tpm_zone_schemas 0.2.0 section 4) into the SR9 executable-entry
interface, and runs SR9 C1, C2, C4 on the synthetic record suite. This is
the second line behind the static checks tms_well_formed makes at entry:
TPS 4.5 row 17, MECHANICAL when the entry is executable. Standard library
only; Python 3.7+; Windows/Linux.

WHAT IT BUILDS, from one named yardstick of a well-formed TMS:
  key(rid, records, tfk)  the KEY evaluated on the record, lexicographic,
                          lower is closer; a record whose DOMAIN equals a
                          LIMITING DOMAIN (after text normalization) is
                          keyed by that limiting KEY instead;
  resolve                 FIXED to the framework: SR7 for an L-M pair, SR5
                          on the key otherwise (D100.1: a yardstick orders,
                          it never resolves);
  limiting                the declared LIMITING DOMAINs, where SR9 C2
                          exempts a lowered key.

TERMS, on a synthetic record (TPS 4.5.2 fields):
  SR1 = 1 if the record fails SR1, else 0;  A = a(r) (SR4, tpc_strike);
  S = s(r), the record's steps;  NEG:t = -t;  WSUM = the sum, in canonical
  atom order, of weight * atom, weights read from TMS CONSTANTS as doubles.
  Every value is a double; -0.0 is written as 0.0.

REFUSED, as ["REFUSED", reason], never raised:
  "TMS is not well-formed"                      (tms_well_formed first)
  "no yardstick named <name>"
  "FIELD terms await the record field schema (C-16)"
  "weight <c> is not a finite double"
  "a yardstick value is not finite"

WHAT A PASS MEANS. On a well-formed, FIELD-free yardstick the grammar
already guarantees C1 (SR1 first) and C4 (fixed resolution), and static C2
decides C2 for SR1, A and S exactly. The harness confirms those claims on
the suite as a regression test; it becomes the only mechanical C2 line for
FIELD terms once C-16 lands. A pass on a finite suite is evidence, not
proof (TPS 4.5.2).
"""

import math

import tpc_sr9 as C
import tpc_strike as S
import tpc_zone as Z

TPC_YARDSTICK_VERSION = "0.1.0"


class _Refusal(Exception):
    pass


def _compile_term(t, weights):
    """A canonical term -> (neg, base, parts): parts is the canonical WSUM
    list of (weight, atom), or None for a bare atom."""
    c = Z.canonical_term(Z._text(t))
    neg = c.startswith("NEG:")
    base = c[4:] if neg else c
    if "FIELD:" in base:
        raise _Refusal("FIELD terms await the record field schema (C-16)")
    if base.startswith("WSUM:"):
        parts = []
        for wt in base[5:].split(";"):
            name, atom = wt.split("*", 1)
            w = float(Z.canon_decimal(weights[name]))
            if not math.isfinite(w):
                raise _Refusal("weight " + name + " is not a finite double")
            parts.append((w, atom))
        return neg, "WSUM", parts
    return neg, base, None


def _atom(atom, rid, records, tfk):
    r = records[rid]
    if atom == "SR1":
        return 1.0 if r["sr1_fail"] else 0.0
    if atom == "A":
        return float(S.a_of_r(rid, records, tfk))
    return float(r["steps"])                          # "S"


def _value(term, rid, records, tfk):
    neg, base, parts = term
    if parts is None:
        v = _atom(base, rid, records, tfk)
    else:
        v = 0.0
        for w, atom in parts:
            v = v + w * _atom(atom, rid, records, tfk)
    if neg:
        v = -v
    v = v + 0.0                                       # -0.0 -> 0.0
    if not math.isfinite(v):
        raise _Refusal("a yardstick value is not finite")
    return v


def _build(tms, name):
    """The SR9 entry tuple for one named yardstick, or a _Refusal."""
    if not Z.tms_well_formed(tms)[0]:
        raise _Refusal("TMS is not well-formed")
    ys = [y for y in tms.get("YARDSTICKS", []) if y.get("NAME") == name]
    if not ys:
        raise _Refusal(Z._show("no yardstick named " + name))
    y = ys[0]
    weights = dict((c["NAME"], c["VALUE"]) for c in tms.get("CONSTANTS", []))
    main = [_compile_term(t, weights) for t in y["KEY"]]
    lim = {}
    for le in y["LIMITING"]:
        lim[Z._text(le["DOMAIN"])] = [_compile_term(t, weights) for t in le["KEY"]]

    def key(rid, records, tfk):
        terms = lim.get(Z._text(records[rid]["domain"]), main)
        return tuple(_value(t, rid, records, tfk) for t in terms)

    return (key, C._resolve_regime_aware(key), sorted(lim))


def yardstick_key(tms, name, rid, records, tfk_assumptions=()):
    """["OK", [values]] for one record, or ["REFUSED", reason]."""
    try:
        key, _, _ = _build(tms, name)
        return ["OK", list(key(rid, records, list(tfk_assumptions)))]
    except _Refusal as e:
        return ["REFUSED", str(e)]


def yardstick_checks(tms, name, suite):
    """["OK", C1, C2, C4] with each check's full result from tpc_sr9 (the
    witnesses CAC's refusal names), or ["REFUSED", reason]."""
    try:
        entry = _build(tms, name)
        return ["OK", C.sr9_c1(entry, suite), C.sr9_c2(entry, suite), C.sr9_c4(entry, suite)]
    except _Refusal as e:
        return ["REFUSED", str(e)]


def yardstick_harness(tms, name, suite):
    """["OK", C1 pass, C2 pass, C4 pass, total violations] for the CAC
    gate, or ["REFUSED", reason]."""
    r = yardstick_checks(tms, name, suite)
    if r[0] != "OK":
        return r
    c1, c2, c4 = r[1], r[2], r[3]
    return ["OK", c1[0], c2[0], c4[0], len(c1[1]) + len(c2[1]) + len(c4[1])]