The Principia Machina/TPC-PY/tpc yardstick.py
Appearance
# -*- 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])]