The Principia Machina/TPC-PY/gen form corpus.py: Difference between revisions
Appearance
TPC-PY source gen_form_corpus.py (-), SHA-256 f79d0ed977daf8e9; conformed TPS 0.4.0; PROPOSED, not declared (TPC-PY 0.2.0) |
m 1 revision imported |
(No difference)
| |
Latest revision as of 02:11, 30 September 2026
# -*- coding: utf-8 -*-
"""Generator for tpc/vectors/form_corpus.json (TPC step 2, increment 8: the
D108.1 declared form at Option 1 of every slot of tpm_increment_8_phase_F
0.1.0, selected 2026-09-24; the bounds of D186.1 and S14; the D variable of
D177.1, taken 2026-09-26, with schema 0.5.0's ROLE on every fixture LAW; the public parse
tree of S32, form_tree). Every expectation is HAND-DERIVED and written
literally below, in the order of the formulation's vector plan V1-V6 (V7
is in the zone corpus, V8 in the tests corpus, V9 a differential check, V10
the help set); the generator refuses to write the corpus if the module
disagrees with any of them. 0.5.1 (C-MS-5, increment 11): the decode/ cases
tell a JSON {} from a JSON []; the corpus is written with LF line ends on
every platform (S65).
Run: cd tpc && python3 gen_form_corpus.py (Windows: py gen_form_corpus.py)."""
import copy, json, os, sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import tpc_form as F
import tpc_strike as S
# ---- the spring fixture with its forms (S3: a DOF t; S1: EQUATION, CONDITION;
# ---- S8: FORM, IMAGE_FORM on the signature; an entry E_t identifies t) --------
TPK = {
"DOF": [
{"NAME": "x", "DIMENSION": "L1"},
{"NAME": "v", "DIMENSION": "L1 T-1"},
{"NAME": "z", "DIMENSION": "L1"},
{"NAME": "t", "DIMENSION": "T1"}],
"CONSTANT": [
{"NAME": "m", "DIMENSION": "M1"},
{"NAME": "k_s", "DIMENSION": "M1 T-2"},
{"NAME": "x_max", "DIMENSION": "L1", "VALUE": "0.05", "UNIT": "m", "UNCERTAINTY": "0.001"}],
"LAW": [
{"NAME": "N2", "STATEMENT": "m dv/dt = -k_s x", "REFS": ["m", "v", "k_s", "x", "t"], "ROLE": "EOM(v)",
"EQUATION": "m * D(v, t) = -k_s * x"},
{"NAME": "KIN", "STATEMENT": "dx/dt = v", "REFS": ["x", "v", "t"], "ROLE": "EOM(x)", "EQUATION": "D(x, t) = v"},
{"NAME": "FREE_Z", "STATEMENT": "d2z/dt2 = 0", "REFS": ["z", "t"], "ROLE": "CONSTRAINT", "EQUATION": "D(z, t, 2) = 0"}],
"ASSUMPTION": [
{"NAME": "A_lin", "PROPOSITION": "the restoring force is linear in x (Hooke r\u00e9gime)", "REFS": ["x"]}],
"CONSTRAINT": [
{"NAME": "C_NOZ", "TARGET": "z", "ACTION": "FIX", "VALUE": "0", "UNIT": "m", "STATEMENT": "motion confined to z = 0"}],
"BOUNDARY": [
{"NAME": "B_small", "PREDICATE": "|x| < x_max", "REFS": ["x", "x_max"], "CONDITION": "abs(x) < x_max"}],
}
TRM = {
"HEADER": {
"ENVIRONMENT_INVENTORY": [
{"ENVIRONMENT_QUANTITY": "position", "DIMENSION": "L1"},
{"ENVIRONMENT_QUANTITY": "velocity", "DIMENSION": "L1 T-1"},
{"ENVIRONMENT_QUANTITY": "height", "DIMENSION": "L1"},
{"ENVIRONMENT_QUANTITY": "time", "DIMENSION": "T1"}],
"SIGNATURE": [
{"NAME": "time_derivative", "OVER": ["x", "v", "t"], "IMAGE": "d/dt maps position to velocity",
"FORM": "D(x, t) = v", "IMAGE_FORM": "D(position, time) = velocity"}],
"TRANSFORMATIONS": [
{"NAME": "time_translation", "STATEMENT": "t -> t + t0"}]},
"ENTRIES": [
{"NAME": "E_x", "DOF": "x", "DOMAIN": "|x| < x_max", "ENVIRONMENT_QUANTITY": "position",
"IDENTIFICATION": "x is the displacement from equilibrium along the spring axis",
"FALSIFIER": "a measured restoring force not proportional to x inside the domain",
"FALSIFIER_CLASS": "F3", "BEARS": ["N2", "KIN"], "DIMENSION": "L1"},
{"NAME": "E_v", "DOF": "v", "DOMAIN": "|x| < x_max", "ENVIRONMENT_QUANTITY": "velocity",
"IDENTIFICATION": "v is the time derivative of x",
"FALSIFIER": "a measured velocity differing from dx/dt beyond uncertainty",
"FALSIFIER_CLASS": "F2", "BEARS": ["KIN"], "DIMENSION": "L1 T-1"},
{"NAME": "E_z", "DOF": "z", "DOMAIN": "always", "ENVIRONMENT_QUANTITY": "height",
"IDENTIFICATION": "z is the height above the track",
"FALSIFIER": "any measured z different from 0",
"FALSIFIER_CLASS": "F3", "BEARS": ["FREE_Z", "C_NOZ"], "DIMENSION": "L1"},
{"NAME": "E_t", "DOF": "t", "DOMAIN": "always", "ENVIRONMENT_QUANTITY": "time",
"IDENTIFICATION": "t is the laboratory clock reading",
"FALSIFIER": "two laboratory clocks that disagree beyond their stated uncertainty",
"FALSIFIER_CLASS": "F3", "BEARS": [], "DIMENSION": "T1"}],
}
DIMS = {"x": "L1", "v": "L1 T-1", "z": "L1", "t": "T1", "m": "M1", "k_s": "M1 T-2", "x_max": "L1",
"theta": "1", "a": "1", "b": "1", "y": "L1", "f": "T-1"}
def c(o):
return copy.deepcopy(o)
def law(tpk, name):
return [l for l in tpk["LAW"] if l["NAME"] == name][0]
cases = []
def add(cid, fn, inp, expect, **extra):
cs = {"id": cid, "fn": fn, "input": inp}
cs.update(extra)
cs["expect"] = expect
cases.append(cs)
def P(cid, text, mode, expect, **extra):
add("parse/" + cid, "parse_form", {"text": text, "mode": mode},
"[OK," + expect + "]" if not expect.startswith("REFUSED ") else "[REFUSED," + expect[8:] + "]", **extra)
# ---- V1 PARSE: the fixture's forms, precedence and associativity, canonical spelling --
P("law-N2", "m * D(v, t) = -k_s * x", "equation", "m*D(v,t)=-k_s*x")
P("law-KIN", "D(x, t) = v", "equation", "D(x,t)=v")
P("law-FREE_Z", "D(z, t, 2) = 0", "equation", "D(z,t,2)=0")
P("boundary-B_small", "abs(x) < x_max", "predicate", "abs(x)<x_max")
P("signature-form", "D(x, t) = v", "form", "D(x,t)=v")
P("signature-operation", "D(x, t)", "form", "D(x,t)")
P("assoc-minus", "a-b-c", "expression", "a-b-c")
P("assoc-minus-paren", "a-(b-c)", "expression", "a-(b-c)")
P("assoc-div-mul", "a/b*c", "expression", "a/b*c")
P("assoc-div-paren", "a/(b*c)", "expression", "a/(b*c)")
P("unary-minus-power", "-a^2", "expression", "-a^2")
P("paren-neg-power", "(-a)^2", "expression", "(-a)^2")
P("power-chained-refused", "a^2^3", "expression", "REFUSED chained ^ needs parentheses at 4")
P("power-non-literal-refused", "a^b^c", "expression",
"REFUSED ^ takes an integer or a parenthesized rational exponent at 2")
P("power-paren", "(a^2)^3", "expression", "(a^2)^3")
P("precedence-mul", "a+b*c", "expression", "a+b*c")
P("precedence-paren", "(a+b)*c", "expression", "(a+b)*c")
P("outer-parens-dropped", "((a+b))", "expression", "a+b")
P("outer-parens-each-side", "(a)=(b)", "equation", "a=b")
P("outer-parens-argument", "sqrt((x))", "expression", "sqrt(x)")
P("outer-parens-predicate", "(x<1)", "predicate", "x<1")
P("outer-parens-comparison-side", "(x+1)<2", "predicate", "x+1<2")
P("inner-parens-kept", "a*((b))", "expression", "a*((b))")
P("inner-parens-kept-not", "not ((x<1))", "predicate", "not ((x<1))")
P("literal-fraction", "0.50*x", "expression", "5e-1*x")
P("literal-hundred", "100*x", "expression", "1e2*x")
P("literal-exponent", "1e5", "expression", "1e5")
P("literal-two", "2.0", "expression", "2")
P("literal-zero", "0.0", "expression", "0")
P("exponent-leading-zero", "x^02", "expression", "x^2")
P("exponent-negative", "x^(-1)", "expression", "x^(-1)")
P("exponent-rational", "x^(1/2)", "expression", "x^(1/2)")
P("exponent-rational-as-written", "x^(2/4)", "expression", "x^(2/4)")
P("exponent-zero", "x^0", "expression", "x^0")
P("derivative-n1-dropped", "D(x, t, 1)", "expression", "D(x,t)")
P("derivative-n2", "D(x,t,2)", "expression", "D(x,t,2)")
P("whitespace", "m *\tD(v,\nt) = x", "equation", "m*D(v,t)=x")
P("keywords-precedence", "x<1 or y>2 and z=3", "predicate", "x<1 or y>2 and z=3")
P("keywords-paren", "(x<1 or y>2) and z=3", "predicate", "(x<1 or y>2) and z=3")
P("not-binds-tighter", "not x<1 and y>2", "predicate", "not x<1 and y>2")
P("not-paren", "not (x<1 and y>2)", "predicate", "not (x<1 and y>2)")
P("not-not", "not not x<1", "predicate", "not not x<1")
P("paren-lookahead-double", "((x<1))", "predicate", "x<1")
P("paren-lookahead-nested", "((x+1)<2)", "predicate", "x+1<2")
P("comparison-ops", "a<=1 and a>=0 and a!=1 and a=0 and a>0", "predicate", "a<=1 and a>=0 and a!=1 and a=0 and a>0")
P("functions", "exp(a)+ln(a)+sin(a)+cos(a)+tan(a)+abs(a)+sqrt(a)", "expression",
"exp(a)+ln(a)+sin(a)+cos(a)+tan(a)+abs(a)+sqrt(a)")
P("function-name-as-identifier", "exp+1", "expression", "exp+1")
# refusals
P("equation-without-equals", "a", "equation", "REFUSED the equation has no =")
P("expression-with-equals", "a=b", "expression", "REFUSED unexpected token = at 2")
P("two-equals", "a=b=c", "equation", "REFUSED unexpected token = at 4")
P("unbalanced-open", "x+(", "expression", "REFUSED unexpected end")
P("unbalanced-close", "x+)", "expression", "REFUSED unexpected token ) at 3")
P("unclosed", "(x", "expression", "REFUSED unexpected end")
P("stray-close", "x)", "expression", "REFUSED unexpected token ) at 2")
P("unknown-function", "f(x)", "expression", "REFUSED unknown function f at 1")
P("two-operators-minus", "a--b", "expression", "REFUSED unexpected token - at 3")
P("two-operators-mul-minus", "a*-b", "expression", "REFUSED unexpected token - at 3")
P("two-operators-plus-mul", "a+*b", "expression", "REFUSED unexpected token * at 3")
P("empty", "", "expression", "REFUSED empty form")
P("blank", " \t\n", "expression", "REFUSED empty form")
P("empty-operand-end", "a+", "expression", "REFUSED unexpected end")
P("empty-operand-start", "*a", "expression", "REFUSED unexpected token * at 1")
P("two-operands", "a b", "expression", "REFUSED unexpected token b at 3")
P("implicit-multiplication", "2x", "expression", "REFUSED unexpected token x at 2")
P("unit-inside", "0.05 m", "expression", "REFUSED unexpected token m at 6")
P("hidden-code-point", "x\u202e", "expression", "REFUSED unexpected character <U+202E> at 2")
P("non-ascii", "x\u00d7y", "expression", "REFUSED unexpected character \u00d7 at 2")
P("literal-leading-point", ".5", "expression", "REFUSED unexpected character . at 1")
P("literal-trailing-point", "5.", "expression", "REFUSED unexpected character . at 2")
P("literal-comma", "1,5", "expression", "REFUSED unexpected token , at 2")
P("literal-exponent-too-long", "1e12345", "expression", "REFUSED unexpected token e12345 at 2")
P("literal-two-points", "1.5.2", "expression", "REFUSED unexpected character . at 4")
P("comparison-in-equation", "a<b", "equation", "REFUSED unexpected token < at 2")
P("chained-comparison", "a<b<c", "predicate", "REFUSED unexpected token < at 4")
P("predicate-without-comparison", "x", "predicate", "REFUSED unexpected end")
P("keyword-as-operand", "and", "expression", "REFUSED unexpected token and at 1")
P("keyword-dangling", "x and", "predicate", "REFUSED unexpected token and at 3")
P("keyword-after-comparison", "x<1 and", "predicate", "REFUSED unexpected end")
P("derivative-one-argument", "D(x)", "expression", "REFUSED D is written D(x,t) or D(x,t,n) at 1")
P("derivative-order-zero", "D(x,t,0)", "expression", "REFUSED D is written D(x,t) or D(x,t,n) at 1")
P("derivative-literal-variable", "D(x,2)", "expression", "REFUSED D is written D(x,t) or D(x,t,n) at 1")
P("derivative-in-condition", "D(x,t)<1", "predicate", "REFUSED D is not permitted in a CONDITION at 1")
P("exponent-identifier", "x^y", "expression", "REFUSED ^ takes an integer or a parenthesized rational exponent at 2")
P("exponent-decimal", "x^1.5", "expression", "REFUSED ^ takes an integer or a parenthesized rational exponent at 2")
P("exponent-unparenthesized-negative", "x^-1", "expression",
"REFUSED ^ takes an integer or a parenthesized rational exponent at 2")
P("exponent-zero-denominator", "x^(1/0)", "expression", "REFUSED a rational exponent needs a positive denominator at 2")
add("parse/not-a-string", "parse_form", {"text": 7, "mode": "expression"}, "[REFUSED,the form is not a string]")
add("parse/unknown-mode", "parse_form", {"text": "x", "mode": "law"}, "[REFUSED,unknown mode law]")
add("parse/grammar-witnesses", "grammar_witness_count", {}, "33",
note="the count of witnesses both residences assert when loaded (S2: unambiguity as a vector)")
# names
add("names/law-N2", "form_names", {"text": "m * D(v, t) = -k_s * x", "mode": "equation"}, "[OK,[k_s,m,t,v,x]]")
add("names/functions-excluded", "form_names", {"text": "exp(x)+sqrt(y)+exp", "mode": "expression"}, "[OK,[exp,x,y]]",
note="exp( is the function; a bare exp is an identifier")
add("names/predicate", "form_names", {"text": "x<1 and not y>2", "mode": "predicate"}, "[OK,[x,y]]")
add("names/refused", "form_names", {"text": "x+", "mode": "expression"}, "[REFUSED,unexpected end]")
# ---- V2 DIMENSIONS (T4): each operator's rule with a passing and a failing pair ---
def D(cid, text, mode, expect, **extra):
add("dim/" + cid, "form_dimension", {"text": text, "mode": mode, "dimensions": DIMS},
"[OK," + expect + "]" if not expect.startswith("REFUSED ") else "[REFUSED," + expect[8:] + "]", **extra)
D("plus-pass", "x+z", "expression", "L1")
D("plus-fail", "x+v", "expression", "REFUSED + joins L1 and L1 T-1")
D("minus-pass", "x-z", "expression", "L1")
D("minus-fail", "x-t", "expression", "REFUSED - joins L1 and T1")
D("times", "m*x", "expression", "L1 M1")
D("divide", "x/t", "expression", "L1 T-1")
D("divide-cancels", "x/x", "expression", "1")
D("divide-by-zero", "x/0", "expression", "REFUSED divides by zero")
D("divide-by-zero-expression", "x/(0*x)", "expression", "REFUSED divides by zero")
D("power-integer", "x^2", "expression", "L2")
D("power-negative", "x^(-1)", "expression", "L-1")
D("power-zero", "x^0", "expression", "1")
D("power-rational-pass", "(x^2)^(1/2)", "expression", "L1")
D("power-rational-fail", "x^(1/2)", "expression", "REFUSED ^ (1/2) of L1 is not a dimension")
D("power-rational-frequency", "(k_s/m)^(1/2)", "expression", "T-1")
D("sqrt-pass", "sqrt(x^2)", "expression", "L1")
D("sqrt-fail", "sqrt(x)", "expression", "REFUSED sqrt of L1 is not a dimension")
D("sqrt-frequency", "sqrt(k_s/m)", "expression", "T-1")
D("exp-pass", "exp(theta)", "expression", "1")
D("exp-fail", "exp(x)", "expression", "REFUSED exp needs a dimensionless argument, not L1")
D("ln-ratio", "ln(x/z)", "expression", "1")
D("sin", "sin(theta)", "expression", "1")
D("cos-ratio", "cos(x/x_max)", "expression", "1")
D("tan-fail", "tan(x)", "expression", "REFUSED tan needs a dimensionless argument, not L1")
D("abs", "abs(x)", "expression", "L1")
D("literal", "2*x", "expression", "L1")
D("literal-alone", "2", "expression", "1")
D("zero-any", "0", "expression", "ANY")
D("zero-times", "0*x", "expression", "ANY")
D("zero-plus", "x+0", "expression", "L1")
D("zero-plus-zero", "0+0", "expression", "ANY")
D("zero-over", "0/x", "expression", "ANY")
D("zero-function", "exp(0)", "expression", "1")
D("zero-abs", "abs(0)", "expression", "ANY")
D("equation-N2", "m*D(v,t)=-k_s*x", "equation", "L1 M1 T-2")
D("equation-KIN", "D(x,t)=v", "equation", "L1 T-1")
D("equation-FREE_Z", "D(z,t,2)=0", "equation", "L1 T-2")
D("equation-zero-left", "0=x", "equation", "L1")
D("equation-fail", "m*x=v", "equation", "REFUSED sides have dimensions L1 M1 and L1 T-1")
D("equation-inner-fail", "x+v=v", "equation", "REFUSED + joins L1 and L1 T-1")
D("derivative", "D(x,t)", "expression", "L1 T-1")
D("derivative-second", "D(z,t,2)", "expression", "L1 T-2")
D("derivative-not-T1", "D(x,m)", "expression", "L1 M-1",
note="D177.1: dim(x) less n times dim(m); tpc_form 0.2.0 before D177.1 answered [REFUSED,D needs a T1 variable, not m of M1]")
D("derivative-unknown-operand", "D(q,t)", "expression", "REFUSED q has no DIMENSION")
D("derivative-unknown-variable", "D(x,q)", "expression", "REFUSED q has no DIMENSION")
D("unknown-name", "q+1", "expression", "REFUSED q has no DIMENSION")
D("predicate-pass", "abs(x)<x_max", "predicate", "1")
D("predicate-fail", "x<v", "predicate", "REFUSED < compares L1 and L1 T-1")
D("predicate-zero", "x!=0", "predicate", "1")
D("predicate-literal-fail", "x<1", "predicate", "REFUSED < compares L1 and 1")
D("predicate-ratio", "x/x_max<1", "predicate", "1")
D("form-expression", "D(x,t)", "form", "L1 T-1")
add("dim/unparsable-dimension", "form_dimension", {"text": "q", "mode": "expression", "dimensions": {"q": "bogus"}},
"[REFUSED,q has no DIMENSION]")
add("dim/parse-refused", "form_dimension", {"text": "x+", "mode": "expression", "dimensions": DIMS},
"[REFUSED,unexpected end]")
# ---- V4 PREDICATES AND TOTALITY (T6) -------------------------------------------------
def T(cid, text, expect, **extra):
add("total/" + cid, "form_totality", {"text": text, "dimensions": DIMS}, expect, **extra)
T("B_small", "abs(x)<x_max", "[OK,[]]")
T("divide-unguarded", "1/a<2", "[OK,[uses / on a with no guard a != 0]]")
T("divide-guarded", "a!=0 and 1/a<2", "[OK,[]]")
T("divide-guarded-mirror", "0!=a and 1/a<2", "[OK,[]]")
T("divide-guarded-after", "1/a<2 and a!=0", "[OK,[]]")
T("divide-guard-under-or", "a!=0 or 1/a<2", "[OK,[uses / on a with no guard a != 0]]")
T("divide-guard-wrong-form", "a>0 and 1/a<2", "[OK,[uses / on a with no guard a != 0]]",
note="the guard table is closed: a > 0 is not the fixed form a != 0")
T("ln-guarded", "ln(a)<1 and a>0", "[OK,[]]")
T("ln-guarded-mirror", "ln(a)<1 and 0<a", "[OK,[]]")
T("ln-unguarded", "ln(a)<1", "[OK,[uses ln on a with no guard a > 0]]")
T("ln-guard-wrong-form", "ln(a)<1 and a>=0", "[OK,[uses ln on a with no guard a > 0]]")
T("sqrt-guarded", "sqrt(a)<1 and a>=0", "[OK,[]]")
T("sqrt-guarded-mirror", "sqrt(a)<1 and 0<=a", "[OK,[]]")
T("sqrt-unguarded", "sqrt(a)<1", "[OK,[uses sqrt on a with no guard a >= 0]]")
T("power-negative-guarded", "a^(-1)<1 and a!=0", "[OK,[]]")
T("power-negative-unguarded", "a^(-1)<1", "[OK,[uses ^ with a negative exponent on a with no guard a != 0]]")
T("power-rational-guarded", "a^(1/2)<1 and a>=0", "[OK,[]]")
T("power-rational-unguarded", "a^(1/2)<1", "[OK,[uses ^ with a rational exponent on a with no guard a >= 0]]")
T("power-integer-total", "a^2<1 and a^0<1", "[OK,[]]")
T("tan-refused", "tan(theta)<1", "[OK,[uses tan on theta, which is not total]]")
T("tan-refused-even-guarded", "tan(theta)<1 and theta!=0", "[OK,[uses tan on theta, which is not total]]")
T("total-functions", "exp(a)+sin(a)+cos(a)+abs(a)<1", "[OK,[]]")
T("guards-nested-left", "(a>=0 and b!=0) and sqrt(a)/b<1", "[OK,[]]")
T("guards-nested-right", "a>=0 and (b!=0 and sqrt(a)/b<1)", "[OK,[]]")
T("guard-lost-across-or", "b!=0 and (a>=0 or sqrt(a)/b<1)", "[OK,[uses sqrt on a with no guard a >= 0]]")
T("guard-inside-not", "not (a!=0 and 1/a<2)", "[OK,[]]")
T("guard-negated", "not (a!=0) and 1/a<2", "[OK,[uses / on a with no guard a != 0]]")
T("guard-canonical-spelling", "1/(a+1)<2 and (a+1)!=0", "[OK,[]]")
T("guard-canonical-spelling-2", "1/(a+1)<2 and a+1!=0", "[OK,[]]")
T("guard-other-spelling", "1/(a+1)<2 and (1+a)!=0", "[OK,[uses / on a+1 with no guard a+1 != 0]]",
note="guards match by canonical spelling: a+1 and 1+a are different spellings (S10)")
T("guard-must-itself-be-total", "a!=0 and 1/a!=0 and 1/(1/a)<2", "[OK,[]]")
T("guard-not-total", "1/a!=0 and 1/(1/a)<2", "[OK,[uses / on a with no guard a != 0]]")
T("two-problems-sorted", "1/a<2 and ln(b)<1", "[OK,[uses / on a with no guard a != 0,uses ln on b with no guard b > 0]]")
T("dimension-pass", "x<y", "[OK,[]]")
T("dimension-fail", "x<a", "[REFUSED,< compares L1 and 1]")
T("dimension-inner-fail", "x+a<y", "[REFUSED,+ joins L1 and 1]")
T("parse-refused", "x<", "[REFUSED,unexpected end]")
T("derivative-refused", "D(x,t)<1", "[REFUSED,D is not permitted in a CONDITION at 1]")
# ---- V5 EVALUATION, the ground fragment (S7, S11) -----------------------------------
def B(**kw):
return dict((k, {"VALUE": v[0], "UNIT": v[1]}) for k, v in kw.items())
def E(cid, text, mode, bindings, expect, **extra):
add("eval/" + cid, "eval_form", {"text": text, "mode": mode, "bindings": bindings}, expect, **extra)
E("N2-bound-true", "m * D(v, t) = -k_s * x", "equation", B(m=("2", "kg"), v=("1", "m s-1"), k_s=("3", "N m-1"), x=("0", "m")),
"[OK,0,0,none]", note="D of a bound identifier is 0; -k_s*x is -0.0, written 0")
E("scaled-cm", "2*x=1", "equation", B(x=("50", "cm")), "[OK,1,1,none]")
E("scaled-m", "2*x=1", "equation", B(x=("0.5", "m")), "[OK,1,1,none]")
E("two-units-agree", "x=x_max", "equation", B(x=("0.05", "m"), x_max=("5", "cm")), "[OK,0.05,0.05,none]")
E("false", "x=x_max", "equation", B(x=("0.06", "m"), x_max=("5", "cm")), "[OK,0.06,0.05,none]")
E("kind-difference", "f=w", "equation", B(f=("1", "Hz"), w=("6.283185307179586", "rad s-1")),
"[CONVENTION,units of different kind: Hz1 and rad1]")
E("kind-difference-sum", "f+w", "expression", B(f=("1", "Hz"), w=("6.283185307179586", "rad s-1")),
"[CONVENTION,units of different kind: Hz1 and rad1]")
E("kind-product", "f*w", "expression", B(f=("1", "Hz"), w=("6.283185307179586", "rad s-1")),
"[OK,6.28318530718,rad1 Hz1]")
E("kind-ratio-cancels", "theta/theta", "expression", B(theta=("90", "deg")), "[OK,1,none]")
E("kind-square", "theta*theta", "expression", B(theta=("90", "deg")), "[OK,2.46740110027,rad2]")
E("kind-sqrt", "sqrt(theta*theta)", "expression", B(theta=("90", "deg")), "[OK,1.57079632679,rad1]")
E("kind-sqrt-odd", "sqrt(theta)", "expression", B(theta=("90", "deg")), "[REFUSED,sqrt of kind rad1 is not a kind]")
E("kind-rational-odd", "theta^(1/2)", "expression", B(theta=("90", "deg")), "[REFUSED,^ (1/2) of kind rad1 is not a kind]")
E("angle-in-rad", "theta", "expression", B(theta=("90", "deg")), "[OK,1.57079632679,rad1]")
E("sin", "sin(theta)", "expression", B(theta=("90", "deg")), "[OK,1,none]")
E("cos", "cos(theta)", "expression", B(theta=("90", "deg")), "[OK,6.12323399574e-17,none]")
E("tan", "tan(theta)", "expression", B(theta=("45", "deg")), "[OK,1,none]")
E("sqrt-frequency", "sqrt(k_s/m)", "expression", B(k_s=("8", "N m-1"), m=("2", "kg")), "[OK,2,none]")
E("exp", "exp(a)", "expression", B(a=("1", "1")), "[OK,2.71828182846,none]")
E("exp-overflow", "exp(a)", "expression", B(a=("1000", "1")), "[REFUSED,not a finite double]")
E("product-overflow", "x*x", "expression", B(x=("1e200", "m")), "[REFUSED,not a finite double]")
E("divide-by-zero", "1/x", "expression", B(x=("0", "m")), "[REFUSED,division by zero]")
E("rational-negative-base", "x^(1/2)", "expression", B(x=("-4", "1")), "[REFUSED,a negative base under a rational exponent]")
E("rational", "x^(1/2)", "expression", B(x=("4", "1")), "[OK,2,none]")
E("integer-power", "x^3", "expression", B(x=("2", "m")), "[OK,8,none]")
E("negative-power", "x^(-2)", "expression", B(x=("4", "1")), "[OK,0.0625,none]")
E("negative-power-of-zero", "x^(-1)", "expression", B(x=("0", "1")), "[REFUSED,0 under a negative exponent]")
E("ln", "ln(a)", "expression", B(a=("1", "1")), "[OK,0,none]")
E("ln-non-positive", "ln(a)", "expression", B(a=("0", "1")), "[REFUSED,ln of a non-positive value]")
E("sqrt-negative", "sqrt(a)", "expression", B(a=("-1", "1")), "[REFUSED,sqrt of a negative value]")
E("abs", "abs(x)", "expression", B(x=("-3", "m")), "[OK,3,none]")
E("negation", "-x", "expression", B(x=("-3", "m")), "[OK,3,none]")
E("literal-hundred", "100*x", "expression", B(x=("2", "cm")), "[OK,2,none]")
E("unbound", "x+y", "expression", B(x=("4", "1")), "[UNBOUND,y]")
E("unbound-derivative", "D(y,t)", "expression", B(x=("4", "1")), "[UNBOUND,y]")
E("derivative-bound", "D(x,t)", "expression", B(x=("4", "m")), "[OK,0,none]",
note="the derivative variable t need not be bound")
E("derivative-plus", "D(x,t,2)+x", "expression", B(x=("4", "m")), "[OK,4,none]")
E("binding-not-normalizable", "x", "expression", B(x=("1e9999", "m")), "[REFUSED,VALUE 1e9999 in UNIT m is not a finite double]")
E("binding-unit-refused", "x", "expression", B(x=("1", "furlong")), "[REFUSED,UNIT furlong: furlong is not a unit symbol]")
E("predicate-not-evaluated", "x<1", "predicate", B(x=("1", "1")), "[REFUSED,a predicate is not evaluated]")
E("parse-refused", "x+", "expression", B(x=("1", "1")), "[REFUSED,unexpected end]")
E("form-mode", "D(x,t)=v", "form", B(x=("1", "m"), v=("0", "m s-1")), "[OK,0,0,none]")
# ---- V3 NAMES and the TPK-level checks -----------------------------------------------
add("names_check/spring", "names_check", {"tpk": TPK}, "[true,[]]")
t = c(TPK); law(t, "KIN")["REFS"] = ["x", "v"]
add("names_check/derivative-variable-not-in-refs", "names_check", {"tpk": t},
"[false,[LAW:KIN: EQUATION names t, which is not in REFS]]")
t = c(TPK); law(t, "N2")["REFS"] = ["m", "v", "k_s", "x", "t", "z"]
add("names_check/refs-member-unused", "names_check", {"tpk": t}, "[false,[LAW:N2: REFS z is not named in EQUATION]]")
t = c(TPK); t["BOUNDARY"][0]["REFS"] = ["x"]
add("names_check/condition-names-nonmember", "names_check", {"tpk": t},
"[false,[BOUNDARY:B_small: CONDITION names x_max, which is not in REFS]]")
t = c(TPK); law(t, "N2")["EQUATION"] = "m * D(v, t) ="
add("names_check/does-not-parse", "names_check", {"tpk": t}, "[false,[LAW:N2: EQUATION does not parse: unexpected end]]")
t = c(TPK); law(t, "N2")["EQUATION"] = "m * D(v, t) = -k_s * x\u202e"
add("names_check/hidden-left-to-T1", "names_check", {"tpk": t}, "[true,[]]")
t = c(TPK); law(t, "N2")["EQUATION"] = 7
add("names_check/wrong-type-left-to-T1", "names_check", {"tpk": t}, "[true,[]]")
add("names_check/not-an-object", "names_check", {"tpk": "x"}, "[true,[]]")
add("coverage/spring-with-forms", "form_coverage", {"tpk": TPK}, "[[],[]]")
t = c(TPK)
for l in t["LAW"]:
del l["EQUATION"]
del t["BOUNDARY"][0]["CONDITION"]
add("coverage/no-forms", "form_coverage", {"tpk": t}, "[[FREE_Z,KIN,N2],[B_small]]")
t = c(TPK); del law(t, "KIN")["EQUATION"]
add("coverage/partial", "form_coverage", {"tpk": t}, "[[KIN],[]]")
# T4
add("t4/spring", "t4_homogeneity", {"tpk": TPK}, "[true,[]]")
t = c(TPK); law(t, "N2")["EQUATION"] = "m * D(v, t) = k_s"
add("t4/sides-differ", "t4_homogeneity", {"tpk": t},
"[false,[LAW:N2: EQUATION sides have dimensions L1 M1 T-2 and M1 T-2 (T4)]]")
t = c(TPK); law(t, "KIN")["EQUATION"] = "D(x, t) + x = v"
add("t4/inner-sum", "t4_homogeneity", {"tpk": t}, "[false,[LAW:KIN: EQUATION + joins L1 T-1 and L1 (T4)]]")
t = c(TPK); law(t, "KIN")["EQUATION"] = "D(x, m) = v"; law(t, "KIN")["REFS"] = ["x", "v", "m"]
add("t4/derivative-variable-not-T1", "t4_homogeneity", {"tpk": t},
"[false,[LAW:KIN: EQUATION sides have dimensions L1 M-1 and L1 T-1 (T4)]]",
note="D177.1: D(x,m) is L1 M-1 (that m is no DOF is T1's refusal, d_variable_check); tpc_form 0.2.0 before "
"D177.1 answered [false,[LAW:KIN: EQUATION D needs a T1 variable, not m of M1 (T4)]]")
t = c(TPK); law(t, "N2")["EQUATION"] = "m * D(v, t) = -k_s * x"; law(t, "KIN")["EQUATION"] = "D(x,t) = x"
add("t4/two-laws-one-fails", "t4_homogeneity", {"tpk": t},
"[false,[LAW:KIN: EQUATION sides have dimensions L1 T-1 and L1 (T4)]]")
t = c(TPK); law(t, "N2")["EQUATION"] = "m * D(v, t) ="
add("t4/parse-left-to-T1", "t4_homogeneity", {"tpk": t}, "[true,[]]")
t = c(TPK); del law(t, "N2")["EQUATION"]
add("t4/law-without-form-not-checked", "t4_homogeneity", {"tpk": t}, "[true,[]]")
add("t4/constant-without-value-allowed", "t4_homogeneity", {"tpk": TPK}, "[true,[]]",
note="m and k_s carry no VALUE: T4 reads DIMENSION only (V3)")
# T6
add("t6/spring", "t6_totality", {"tpk": TPK}, "[true,[]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "x / x_max < 1"
add("t6/unguarded-divide", "t6_totality", {"tpk": t},
"[false,[BOUNDARY:B_small: CONDITION uses / on x_max with no guard x_max != 0 (T6)]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "x_max != 0 and x / x_max < 1"
add("t6/guarded-divide", "t6_totality", {"tpk": t}, "[true,[]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "x < v"; t["BOUNDARY"][0]["REFS"] = ["x", "v"]
add("t6/comparison-dimensions", "t6_totality", {"tpk": t},
"[false,[BOUNDARY:B_small: CONDITION < compares L1 and L1 T-1 (T6)]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "abs(x) < x_max and tan(x / x_max) < 1"
add("t6/tan-refused", "t6_totality", {"tpk": t},
"[false,[BOUNDARY:B_small: CONDITION uses / on x_max with no guard x_max != 0 (T6),"
"BOUNDARY:B_small: CONDITION uses tan on x/x_max, which is not total (T6)]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "abs(x) <"
add("t6/parse-left-to-T1", "t6_totality", {"tpk": t}, "[true,[]]")
t = c(TPK); del t["BOUNDARY"][0]["CONDITION"]
add("t6/boundary-without-form-not-checked", "t6_totality", {"tpk": t}, "[true,[]]")
# T3 over laws, the ground fragment
add("t3laws/spring-nothing-claimed", "t3_laws", {"tpk": TPK}, "[true,[]]",
note="N2 and KIN name unbound identifiers; FREE_Z evaluates 0 = 0 through the FIXed z")
def tpk_consts(laws, consts, cons=()):
return {"DOF": [{"NAME": "z", "DIMENSION": "L1"}, {"NAME": "t", "DIMENSION": "T1"}],
"CONSTANT": consts, "LAW": laws, "CONSTRAINT": list(cons)}
def K(name, dim, value=None, unit=None):
e = {"NAME": name, "DIMENSION": dim}
if value is not None:
e["VALUE"] = value
e["UNIT"] = unit
return e
def LW(name, eq, refs, role="DEFINITION"):
"""A test law. Its ROLE (schema 0.5.0) by its physics: DEFINITION where every name it
relates is a CONSTANT (the law defines one constant by others), else as passed."""
return {"NAME": name, "STATEMENT": eq, "REFS": refs, "ROLE": role, "EQUATION": eq}
C_NOZ = {"NAME": "C_NOZ", "TARGET": "z", "ACTION": "FIX", "VALUE": "0", "UNIT": "m", "STATEMENT": "z = 0"}
add("t3laws/bound-true", "t3_laws", {"tpk": tpk_consts([LW("L", "a + a = b", ["a", "b"])], [K("a", "L1", "1", "m"), K("b", "L1", "2", "m")])},
"[true,[]]")
add("t3laws/bound-false", "t3_laws", {"tpk": tpk_consts([LW("L", "a = b", ["a", "b"])], [K("a", "L1", "1", "m"), K("b", "L1", "2", "m")])},
"[false,[LAW:L: L evaluates 1 = 2 under the declared values (T3)]]")
add("t3laws/bound-true-other-unit", "t3_laws", {"tpk": tpk_consts([LW("L", "a = b", ["a", "b"])], [K("a", "L1", "1", "m"), K("b", "L1", "100", "cm")])},
"[true,[]]")
add("t3laws/fixed-dof", "t3_laws", {"tpk": tpk_consts([LW("L", "z = a", ["z", "a"], "CONSTRAINT")], [K("a", "L1", "1", "m")], [C_NOZ])},
"[false,[LAW:L and CONSTRAINT:C_NOZ: L evaluates 0 = 1 under the fixed values (T3)]]")
add("t3laws/derivative-of-fixed-dof", "t3_laws",
{"tpk": tpk_consts([LW("L", "D(z, t) = a", ["z", "t", "a"], "CONSTRAINT")], [K("a", "L1 T-1", "1", "m s-1")], [C_NOZ])},
"[false,[LAW:L and CONSTRAINT:C_NOZ: L evaluates 0 = 1 under the fixed values (T3)]]")
add("t3laws/free-identifier-not-evaluated", "t3_laws", {"tpk": tpk_consts([LW("L", "a = b", ["a", "b"])], [K("a", "L1", "1", "m"), K("b", "L1")])},
"[true,[]]")
add("t3laws/kind-difference", "t3_laws",
{"tpk": tpk_consts([LW("L", "f = w", ["f", "w"])], [K("f", "T-1", "1", "Hz"), K("w", "T-1", "6.283185307179586", "rad s-1")])},
"[false,[LAW:L: the two sides of EQUATION cannot be compared: units of different kind: Hz1 and rad1 (T3)]]")
add("t3laws/overflow", "t3_laws", {"tpk": tpk_consts([LW("L", "big * big = big", ["big"])], [K("big", "L1", "1e200", "m")])},
"[false,[LAW:L: EQUATION cannot be evaluated under the declared values: not a finite double (T3)]]")
add("t3laws/binding-not-normalizable", "t3_laws", {"tpk": tpk_consts([LW("L", "a = a", ["a"])], [K("a", "L1", "1e9999", "m")])},
"[false,[LAW:L: EQUATION cannot be evaluated: VALUE 1e9999 in UNIT m is not a finite double (T3)]]")
add("t3laws/division-by-zero", "t3_laws", {"tpk": tpk_consts([LW("L", "b / a = b", ["a", "b"])], [K("a", "L1", "0", "m"), K("b", "L1", "1", "m")])},
"[false,[LAW:L: EQUATION cannot be evaluated under the declared values: division by zero (T3)]]")
add("t3laws/two-laws-one-left-side", "t3_laws",
{"tpk": tpk_consts([LW("KIN", "D(x, t) = v", ["x", "t", "v"]), LW("KIN2", "D(x,t) = 2 * v", ["x", "t", "v"])],
[K("x", "L1"), K("v", "L1 T-1")])},
"[false,[LAW:KIN and LAW:KIN2: the left side D(x,t) is equated to v and to 2*v (T3)]]")
add("t3laws/two-laws-same-right-side", "t3_laws",
{"tpk": tpk_consts([LW("KIN", "D(x, t) = v", ["x", "t", "v"]), LW("KIN2", "D(x,t) = (v)", ["x", "t", "v"])],
[K("x", "L1"), K("v", "L1 T-1")])},
"[true,[]]", note="redundant, not contradictory: one canonical right side")
add("t3laws/three-laws-one-left-side", "t3_laws",
{"tpk": tpk_consts([LW("A", "x = v", ["x", "v"]), LW("B", "x = 2*v", ["x", "v"]), LW("C", "x = v", ["x", "v"])],
[K("x", "L1"), K("v", "L1")])},
"[false,[LAW:A and LAW:B: the left side x is equated to v and to 2*v (T3),"
"LAW:B and LAW:C: the left side x is equated to 2*v and to v (T3)]]")
t = c(TPK); law(t, "N2")["EQUATION"] = "m * D(v, t) ="
add("t3laws/parse-left-to-T1", "t3_laws", {"tpk": t}, "[true,[]]")
add("t3laws/not-an-object", "t3_laws", {"tpk": "x"}, "[true,[]]")
# ---- V6 SIGNATURE (IC4 a) ----------------------------------------------------------------
add("ic4a/spring", "ic4a_signature", {"trm": TRM, "tpk": TPK}, "[true,[],[]]")
t = c(TRM); t["HEADER"]["SIGNATURE"][0]["IMAGE_FORM"] = "D(position, time) = speed"
add("ic4a/image-differs", "ic4a_signature", {"trm": t, "tpk": TPK},
"[false,[IC4(a): SIGNATURE:time_derivative: FORM under the entries reads D(position,time)=velocity, not IMAGE_FORM D(position,time)=speed],[]]")
t = c(TRM); t["HEADER"]["SIGNATURE"][0]["IMAGE_FORM"] = "D( position , time ) = velocity"
add("ic4a/image-respelled", "ic4a_signature", {"trm": t, "tpk": TPK}, "[true,[],[]]")
t = c(TRM); t["ENTRIES"] = [e for e in t["ENTRIES"] if e["NAME"] != "E_t"]
add("ic4a/untied-dof-undecided", "ic4a_signature", {"trm": t, "tpk": TPK},
"[true,[],[IC4(a): SIGNATURE:time_derivative: DOF t untied, not decided]]")
t = c(TRM); del t["HEADER"]["SIGNATURE"][0]["FORM"]; del t["HEADER"]["SIGNATURE"][0]["IMAGE_FORM"]
add("ic4a/no-form", "ic4a_signature", {"trm": t, "tpk": TPK}, "[true,[],[]]")
t = c(TRM); t["HEADER"]["SIGNATURE"][0]["FORM"] = "D(x, t) ="
add("ic4a/parse-left-to-structure", "ic4a_signature", {"trm": t, "tpk": TPK}, "[true,[],[]]")
add("ic4a/not-an-object", "ic4a_signature", {"trm": "x", "tpk": TPK}, "[true,[],[]]")
# ---- DEPTH (tpc_form 0.1.1; expectations under the bounds of 0.2.0, D186.1) -----------
# Added by tpc_form 0.1.1 (explicit stack): each expectation derived by hand from the
# grammar and the canonical spelling, written as a Python expression, and matched to
# TPC-PHP's answer (the residence of record, D102) before it was first written.
# Under tpc_form 0.2.0 (D186.1) a form longer than 4096 code points or more than 64
# parentheses deep is refused before it is read: 30 of these 41 cases now expect that
# refusal (each carries a note naming its 0.1.1 answer); the 11 within the bounds are
# unchanged, and the chains among them (1,999 terms; 1,000 "not") still reach tree
# depths past Python's recursion limit, so the explicit stack stays exercised.
def op(n):
return "(" * n
def cl(n):
return ")" * n
NEST = "REFUSED more than 64 nested parentheses at %d"
LONG = "REFUSED the form is longer than 4096 code points"
def rf(expect): # the "[REFUSED,...]" of a non-parse function
return "[REFUSED," + expect[8:] + "]"
for n in (200, 1000): # 2n+1 and 2n+4 code points; the 65th "(" at 65
P("depth-paren-identifier-%d" % n, op(n) + "x" + cl(n), "expression", NEST % 65)
P("depth-paren-literal-%d" % n, op(n) + "0.50" + cl(n), "expression", NEST % 65)
P("depth-paren-identifier-10000", op(10000) + "x" + cl(10000), "expression", LONG)
P("depth-paren-literal-10000", op(10000) + "0.50" + cl(10000), "expression", LONG)
for cs in cases[-6:]:
cs["note"] = "D186.1; tpc_form 0.1.1 answered " + ("[OK,x]" if "identifier" in cs["id"] else "[OK,5e-1]")
P("depth-paren-D-1000", op(1000) + "D(x, t)" + cl(1000) + " = v", "equation", NEST % 65)
P("depth-paren-D-10000", op(10000) + "D(x, t)" + cl(10000) + " = v", "equation", LONG)
P("depth-paren-condition-10000", op(10000) + "x" + cl(10000) + " < 1", "predicate", LONG)
P("depth-pparen-condition-200", op(200) + "x < 1" + cl(200), "predicate", NEST % 65)
P("depth-pparen-condition-1000", op(1000) + "x < 1" + cl(1000), "predicate", NEST % 65)
for cs, was in zip(cases[-5:], ["[OK,D(x,t)=v]", "[OK,D(x,t)=v]", "[OK,x<1]", "[OK,x<1]", "[OK,x<1]"]):
cs["note"] = "D186.1; tpc_form 0.1.1 answered " + was
P("depth-inner-parens-kept-1000", "a*" + op(1000) + "b" + cl(1000), "expression", NEST % 67,
note="D186.1; the 65th ( follows a* at 67; tpc_form 0.1.1 answered the text unchanged")
P("depth-chain-plus-2000", "a" + "+a" * 1999, "expression", "a" + "+a" * 1999) # 3,999 code points
P("depth-chain-D-2000", "D(x,t)" + "+D(x,t)" * 1999 + "=v", "equation", LONG,
note="D186.1; 14,001 code points; tpc_form 0.1.1 answered the text unchanged")
P("depth-chain-and-2000", " and ".join(["x<1"] * 2000), "predicate", LONG,
note="D186.1; 15,995 code points; tpc_form 0.1.1 answered the text unchanged")
P("depth-not-1000", "not " * 1000 + "x<1", "predicate", "not " * 1000 + "x<1") # 4,003 code points
P("depth-negation-1000", "-(" * 1000 + "x" + cl(1000), "expression", NEST % 130,
note="D186.1; the k-th ( at 2k; tpc_form 0.1.1 answered the text unchanged")
P("depth-function-1000", "abs(" * 1000 + "x" + cl(1000), "expression", LONG,
note="D186.1; 5,001 code points; tpc_form 0.1.1 answered the text unchanged")
P("depth-inside-D-refused", "D(" + op(1000) + "x" + cl(1000) + ",t)", "expression", NEST % 66,
note="D186.1; D's ( is level 1 at 2, the 64th ( after it level 65 at 66; "
"tpc_form 0.1.1 answered [REFUSED,D is written D(x,t) or D(x,t,n) at 1]")
P("depth-unclosed-1000", op(1000) + "x" + cl(999), "expression", NEST % 65,
note="D186.1; tpc_form 0.1.1 answered [REFUSED,unexpected end]")
P("depth-overclosed-1000", op(1000) + "x" + cl(1001), "expression", NEST % 65,
note="D186.1; tpc_form 0.1.1 answered [REFUSED,unexpected token ) at 2002]")
add("names/depth-paren-1000", "form_names", {"text": op(1000) + "x" + cl(1000) + " = v", "mode": "equation"},
rf(NEST % 65), note="D186.1; tpc_form 0.1.1 answered [OK,[v,x]]")
D("depth-paren-1000", op(1000) + "x" + cl(1000) + "/t", "expression", NEST % 65)
cases[-1]["note"] = "D186.1; tpc_form 0.1.1 answered [OK,L1 T-1]"
D("depth-chain-2000", "x" + "+x" * 1999, "expression", "L1")
D("depth-function-1000", "abs(" * 1000 + "x" + cl(1000), "expression", LONG)
cases[-1]["note"] = "D186.1; tpc_form 0.1.1 answered [OK,L1]"
D("depth-paren-1000-fail", op(1000) + "x" + cl(1000) + "+t", "expression", NEST % 65)
cases[-1]["note"] = "D186.1; tpc_form 0.1.1 answered [REFUSED,+ joins L1 and T1]"
T("depth-pparen-guarded-1000", op(1000) + "a!=0 and 1/a<2" + cl(1000), rf(NEST % 65),
note="D186.1; tpc_form 0.1.1 answered [OK,[]]")
T("depth-guard-across-pparen-1000", "a!=0 and " + op(1000) + "1/a<2" + cl(1000), rf(NEST % 74),
note="D186.1; the 65th ( at 9+65; tpc_form 0.1.1 answered [OK,[]]")
T("depth-not-1000", "not " * 1000 + "1/a<2", "[OK,[uses / on a with no guard a != 0]]")
T("depth-chain-and-200", " and ".join(["1/a<2"] * 200), "[OK,[uses / on a with no guard a != 0]]")
_nest = ["a"] # "1/(" * k + "a" + ")" * k, k = 0..64
for _k in range(1, 65):
_nest.append("1/(" + _nest[-1] + ")")
T("depth-divisors-50", "1/(" + _nest[49] + ")<2",
"[OK,[" + ",".join(sorted("uses / on " + e + " with no guard " + e + " != 0" for e in _nest[:50])) + "]]",
note="every divisor needs its own guard; the fifty problems in code point order")
E("depth-paren-1000", op(1000) + "x" + cl(1000) + "*2=1", "equation", B(x=("0.5", "m")), rf(NEST % 65),
note="D186.1; tpc_form 0.1.1 answered [OK,1,1,none]")
E("depth-chain-2000", "x" + "+x" * 1999 + "=y", "equation", B(x=("0.5", "m"), y=("1000", "m")),
"[OK,1000,1000,none]", note="0.5 added 1,999 times to 0.5 is exact in binary64")
E("depth-function-1000", "abs(" * 1000 + "-x" + cl(1000), "expression", B(x=("3", "m")), rf(LONG),
note="D186.1; 5,002 code points; tpc_form 0.1.1 answered [OK,3,none]")
E("depth-negation-1001", "-(" * 1001 + "x" + cl(1001), "expression", B(x=("3", "m")), rf(NEST % 130),
note="D186.1; tpc_form 0.1.1 answered [OK,-3,none]")
t = c(TPK); law(t, "KIN")["EQUATION"] = op(1000) + "D(x, t)" + cl(1000) + " = v"
add("names_check/depth-1000", "names_check", {"tpk": t},
"[false,[LAW:KIN: EQUATION does not parse: more than 64 nested parentheses at 65]]",
note="D186.1: T1's finding; tpc_form 0.1.1 answered [true,[]]")
add("t4/depth-1000", "t4_homogeneity", {"tpk": t}, "[true,[]]",
note="D186.1: the form does not parse, so T4 skips it and T1 reports it (names_check/depth-1000)")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = op(1000) + "abs(x) < x_max" + cl(1000)
add("t6/depth-1000", "t6_totality", {"tpk": t}, "[true,[]]",
note="D186.1: the form does not parse, so T6 skips it and T1 reports it")
add("t3laws/depth-1000-true", "t3_laws",
{"tpk": tpk_consts([LW("L", "2*" + op(1000) + "a" + cl(1000) + " = a + a", ["a"])], [K("a", "L1", "1", "m")])},
"[true,[]]", note="D186.1: the form does not parse, so T3 skips it and T1 reports it")
add("t3laws/depth-1000-false", "t3_laws",
{"tpk": tpk_consts([LW("L", op(1000) + "a" + cl(1000) + " = b", ["a", "b"])],
[K("a", "L1", "1", "m"), K("b", "L1", "2", "m")])},
"[true,[]]", note="D186.1: the form does not parse, so T3 skips it and T1 reports it; tpc_form 0.1.1 "
"answered [false,[LAW:L: L evaluates 1 = 2 under the declared values (T3)]]")
t = c(TRM)
t["HEADER"]["SIGNATURE"][0]["FORM"] = "D(x, t) = 2*" + op(1000) + "v" + cl(1000)
t["HEADER"]["SIGNATURE"][0]["IMAGE_FORM"] = "D(position, time) = 2*" + op(1000) + "velocity" + cl(1000)
add("ic4a/depth-1000", "ic4a_signature", {"trm": t, "tpk": TPK}, "[true,[],[]]",
note="D186.1: the forms do not parse, so IC4 (a) skips them and the structural check reports them")
# ---- BOUNDS (tpc_form 0.2.0, D186.1) --------------------------------------------------
# An integer (an exponent, a rational exponent's p and q, D's order) is at most 4
# digits as written, a leading zero counted, as a DIMENSION exponent is (TPS 2.5.12);
# a form is at most 4096 code points of its canonical text (LF, then NFC; whitespace
# counted) and at most 64 parentheses deep (every "(" opens a level; a ")" with none
# open closes none). Order: length, depth, tokens, grammar (an integer's digits where
# the grammar reads it). Positions are 1-based code points. Hand-derived.
DIG = "REFUSED an integer of more than 4 digits at %d"
# -- the integer bound: at 4 digits and at 5, in each place an integer is read
P("bounds-exp-9999", "x^9999", "expression", "x^9999")
P("bounds-exp-10000", "x^10000", "expression", DIG % 3)
P("bounds-exp-neg-9999", "x^(-9999)", "expression", "x^(-9999)")
P("bounds-exp-neg-10000", "x^(-10000)", "expression", DIG % 5)
P("bounds-rational-p-4", "x^(9999/2)", "expression", "x^(9999/2)")
P("bounds-rational-p-5", "x^(10000/2)", "expression", DIG % 4)
P("bounds-rational-q-4", "x^(1/9999)", "expression", "x^(1/9999)")
P("bounds-rational-q-5", "x^(1/10000)", "expression", DIG % 6)
P("bounds-rational-both-4", "x^(-9999/9999)", "expression", "x^(-9999/9999)")
P("bounds-D-order-9999", "D(x, t, 9999)", "expression", "D(x,t,9999)")
P("bounds-D-order-10000", "D(x, t, 10000)", "expression", DIG % 9)
# -- leading zeros count as written (as in a DIMENSION exponent); the spelling drops them
P("bounds-leading-zero-4", "x^0009", "expression", "x^9")
P("bounds-leading-zero-5", "x^00009", "expression", DIG % 3)
P("bounds-leading-zero-rational-4", "x^(0009/0002)", "expression", "x^(9/2)")
P("bounds-leading-zero-rational-5", "x^(9/00002)", "expression", DIG % 6)
P("bounds-leading-zero-D-4", "D(x,t,0002)", "expression", "D(x,t,2)")
P("bounds-leading-zero-D-5", "D(x,t,00002)", "expression", DIG % 7)
P("bounds-D-order-zero-4", "D(x,t,0000)", "expression", "REFUSED D is written D(x,t) or D(x,t,n) at 1")
P("bounds-D-order-zero-5", "D(x,t,00000)", "expression", DIG % 7,
note="the digits are checked before the order's value")
P("bounds-rational-zero-q-4", "x^(1/0000)", "expression", "REFUSED a rational exponent needs a positive denominator at 2")
# -- beyond 64 bits: refused alike, never converted (PHP 0.1.1 saturated to 9223372036854775807)
P("bounds-exp-20-digits", "x^99999999999999999999", "expression", DIG % 3,
note="tpc_form 0.1.1: TPC-PY x^99999999999999999999, TPC-PHP x^9223372036854775807")
P("bounds-D-20-digits", "D(x,t,99999999999999999999)", "expression", DIG % 7,
note="tpc_form 0.1.1: TPC-PHP spelled the order 9223372036854775807")
P("bounds-rational-20-digits", "x^(1/99999999999999999999)", "expression", DIG % 6)
P("bounds-exp-4094-digits", "x^" + "9" * 4094, "expression", DIG % 3,
note="4,096 code points; tpc_form 0.1.1: TPC-PHP x^9223372036854775807")
P("bounds-exp-5000-digits", "x^" + "9" * 5000, "expression", LONG,
note="tpc_form 0.1.1: TPC-PY raised ValueError (int of more than 4300 digits), TPC-PHP answered x^0")
# -- a literal is not an integer place: its digits stay unbounded but for the length
P("bounds-literal-mantissa-30", "123456789012345678901234567890*x", "expression",
"12345678901234567890123456789e1*x")
# -- the integer bound in the dimension and evaluation walks
D("bounds-exp-9999", "x^9999", "expression", "L9999")
D("bounds-rational-9999", "(x^9999)^(1/9999)", "expression", "L1")
D("bounds-D-order-9999", "D(x,t,9999)", "expression", "L1 T-9999")
D("bounds-exp-10000", "x^10000", "expression", DIG % 3)
E("bounds-exp-9999-one", "x^9999", "expression", B(x=("1", "m")), "[OK,1,none]")
E("bounds-exp-neg-9999-one", "x^(-9999)", "expression", B(x=("1", "m")), "[OK,1,none]")
E("bounds-exp-9999-overflow", "x^9999", "expression", B(x=("2", "m")), "[REFUSED,not a finite double]",
note="2^9999 by repeated multiplication overflows to +inf")
E("bounds-exp-10000", "x^10000", "expression", B(x=("1", "m")), rf(DIG % 3))
# -- the length, in code points of the canonical text
P("bounds-size-4096", "x" + "+x" * 2047 + " ", "expression", "x" + "+x" * 2047)
P("bounds-size-4097-whitespace", "x" + "+x" * 2047 + " ", "expression", LONG,
note="whitespace counts toward the length; the spelling would be 4,095 code points")
P("bounds-size-4097", "x" + "+x" * 2048, "expression", LONG)
P("bounds-size-4096-cp-4097-bytes", " " * 4095 + "\u00e9", "expression", "REFUSED unexpected character \u00e9 at 4096",
note="4,096 code points, 4,097 UTF-8 bytes: within the length bound, refused by the tokens")
P("bounds-size-4096-cp-16384-bytes", "\U0001d465" * 4096, "expression", "REFUSED unexpected character \U0001d465 at 1",
note="U+1D465 (NFC-stable), 4 UTF-8 bytes each: 4,096 code points pass the length bound")
P("bounds-size-4097-cp-16388-bytes", "\U0001d465" * 4097, "expression", LONG)
P("bounds-size-nfc-4098-raw", "e\u0301" * 2049, "expression", "REFUSED unexpected character \u00e9 at 1",
note="4,098 code points as given, 2,049 after NFC: the canonical text is measured")
P("bounds-size-crlf-4096", "x" + "\r\n+x" * 1365, "expression", "x" + "+x" * 1365,
note="5,461 code points as given, 4,096 after CRLF becomes LF: accepted")
P("bounds-size-crlf-4097", "x" + "\r\n+x" * 1365 + " ", "expression", LONG)
# -- the depth: parentheses, function arguments, D, an exponent's, a predicate's
P("bounds-nest-paren-64", op(64) + "x" + cl(64), "expression", "x")
P("bounds-nest-paren-65", op(65) + "x" + cl(65), "expression", NEST % 65)
P("bounds-nest-function-64", "abs(" * 64 + "x" + cl(64), "expression", "abs(" * 64 + "x" + cl(64))
P("bounds-nest-function-65", "abs(" * 65 + "x" + cl(65), "expression", NEST % 260,
note="the k-th ( at 4k")
P("bounds-nest-D-64", "sqrt(" + op(62) + "D(x, t)" + cl(62) + ")", "expression", "sqrt(D(x,t))",
note="sqrt's ( is level 1, D's level 64; the spelling drops the argument's parentheses")
P("bounds-nest-D-65", "sqrt(" + op(63) + "D(x, t)" + cl(63) + ")", "expression", NEST % 70,
note="sqrt( at 1-5, 63 ( at 6-68, D at 69, its ( level 65 at 70")
P("bounds-nest-exponent-64", op(63) + "x^(1/2)" + cl(63), "expression", "x^(1/2)")
P("bounds-nest-exponent-65", op(64) + "x^(1/2)" + cl(64), "expression", NEST % 67)
P("bounds-nest-predicate-64", op(64) + "x < 1" + cl(64), "predicate", "x<1")
P("bounds-nest-predicate-65", op(65) + "x < 1" + cl(65), "predicate", NEST % 65)
P("bounds-nest-reopen-64", op(63) + "(x)+(y)" + cl(63), "expression", "(x)+(y)",
note="a closed level is reopened, never added to: the depth stays 64")
P("bounds-nest-sequential", "(x)+" * 100 + "(x)", "expression", "(x)+" * 100 + "(x)")
P("bounds-nest-stray-close-65", ")" + op(65) + "x" + cl(65), "expression", NEST % 66,
note="a ) with none open closes none")
P("bounds-nest-stray-close-64", ")" + op(64) + "x" + cl(64), "expression", "REFUSED unexpected token ) at 1")
add("names/bounds-nest-65", "form_names", {"text": op(65) + "x" + cl(65) + " = v", "mode": "equation"}, rf(NEST % 65))
T("bounds-divisors-64", "1/(" + _nest[63] + ")<2",
"[OK,[" + ",".join(sorted("uses / on " + e + " with no guard " + e + " != 0" for e in _nest[:64])) + "]]",
note="64 nested divisors, the most the depth bound admits: 64 problems in code point order")
T("bounds-divisors-65", "1/(" + _nest[64] + ")<2", rf(NEST % 195), note="the k-th ( at 3k")
T("bounds-divisors-1000", "1/(" * 1000 + "a" + cl(1000) + "<2", rf(NEST % 195),
note="4,003 code points; refused before the guard walk")
T("bounds-divisors-4000", "1/(" * 4000 + "a" + cl(4000) + "<2", rf(LONG),
note="16,003 code points; tpc_form 0.1.1 walked it (TPC-PHP 14.7 s on the gate host)")
# -- order: length, then depth, then tokens, then the grammar with its integers
P("bounds-order-length-before-tokens", "@" + "x" * 4096, "expression", LONG)
P("bounds-order-depth-before-tokens", "@" + op(65) + "x" + cl(65), "expression", NEST % 66)
P("bounds-order-length-before-depth", op(4097), "expression", LONG)
P("bounds-order-depth-before-integer", op(65) + "x^10000" + cl(65), "expression", NEST % 65)
P("bounds-order-tokens-before-integer", "x^10000+@", "expression", "REFUSED unexpected character @ at 9")
P("bounds-order-integers-as-read", "x^10000 + D(x,t,00000)", "expression", DIG % 3)
P("bounds-order-grammar-before-integer", "x^^10000", "expression",
"REFUSED ^ takes an integer or a parenthesized rational exponent at 2")
# -- T1 at the TPK: the reason reaches the names rule (part of T1) unchanged
t = c(TPK); law(t, "KIN")["EQUATION"] = "D(x, t, 10000) = v"
add("names_check/bounds-integer", "names_check", {"tpk": t},
"[false,[LAW:KIN: EQUATION does not parse: an integer of more than 4 digits at 9]]")
t = c(TPK); law(t, "KIN")["EQUATION"] = op(63) + "D(x, t)" + cl(63) + " = v"
add("names_check/bounds-nest-64", "names_check", {"tpk": t}, "[true,[]]")
add("t4/bounds-nest-64", "t4_homogeneity", {"tpk": t}, "[true,[]]")
t = c(TPK); law(t, "KIN")["EQUATION"] = op(64) + "D(x, t)" + cl(64) + " = v"
add("names_check/bounds-nest-65", "names_check", {"tpk": t},
"[false,[LAW:KIN: EQUATION does not parse: more than 64 nested parentheses at 66]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = op(63) + "abs(x) < x_max" + cl(63)
add("t6/bounds-nest-64", "t6_totality", {"tpk": t}, "[true,[]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "abs(x) < x_max" + " " * 4083
add("names_check/bounds-size-4097", "names_check", {"tpk": t},
"[false,[BOUNDARY:B_small: CONDITION does not parse: the form is longer than 4096 code points]]")
add("t3laws/bounds-chain-true", "t3_laws",
{"tpk": tpk_consts([LW("L", "a" + "+a" * 1999 + " = b", ["a", "b"])], [K("a", "L1", "1", "m"), K("b", "L1", "2000", "m")])},
"[true,[]]", note="4,003 code points; a chain of 2,000 terms is exact in binary64")
add("t3laws/bounds-chain-false", "t3_laws",
{"tpk": tpk_consts([LW("L", "a" + "+a" * 1999 + " = b", ["a", "b"])], [K("a", "L1", "1", "m"), K("b", "L1", "1999", "m")])},
"[false,[LAW:L: L evaluates 2000 = 1999 under the declared values (T3)]]")
t = c(TRM)
t["HEADER"]["SIGNATURE"][0]["FORM"] = "D(x, t) = 2*" + op(64) + "v" + cl(64)
t["HEADER"]["SIGNATURE"][0]["IMAGE_FORM"] = "D(position, time) = 2*" + op(64) + "velocity" + cl(64)
add("ic4a/bounds-nest-64", "ic4a_signature", {"trm": t, "tpk": TPK}, "[true,[],[]]",
note="64 levels in FORM and IMAGE_FORM: the rename walks them")
# ---- S14 (tpc_form 0.2.0): computed exponents ------------------------------------------
# T1, dimension-free: for every identifier and every D under nested powers and square
# roots, the exponent the form composes (the product of the enclosing exponents from the
# innermost, sqrt counting 1/2, abs 1; exp, ln, sin, cos and tan yield a pure number and
# end the product), in lowest terms, has a numerator and a denominator of at most 9999 at
# every power and root; else "a computed exponent beyond 9999 at N", N the position of
# that ^ or root. Dimension and KIND walks: every exponent read or computed lies within
# -9999..9999, as tpc_units requires of a UNIT's DIMENSION ("an exponent is out of
# range"; "a kind exponent is out of range"). Evaluation: a zero base under a negative
# rational exponent is refused as under a negative integer one. Hand-derived.
CMP = "REFUSED a computed exponent beyond 9999 at %d"
OOR = "REFUSED an exponent is out of range"
KOOR = "[REFUSED,a kind exponent is out of range]"
# -- T1: the composed exponent
P("s14-nested-power-5", "((((x^9999)^9999)^9999)^9999)^9999", "expression", CMP % 12,
note="the second ^ composes 99980001; before S14 TPC-PY spelled it and TPC-PHP raised in the dimension walk")
P("s14-composed-9999", "(x^99)^101", "expression", "(x^99)^101")
P("s14-composed-10000", "(x^100)^100", "expression", CMP % 8)
P("s14-composed-neg-9999", "(x^(-99))^101", "expression", "(x^(-99))^101")
P("s14-composed-neg-10000", "(x^(-100))^100", "expression", CMP % 11)
P("s14-rational-reduced-1", "(x^(9999/2))^(2/9999)", "expression", "(x^(9999/2))^(2/9999)",
note="19998/19998 in lowest terms is 1")
P("s14-rational-reduced-9999", "(x^(9999/3))^3", "expression", "(x^(9999/3))^3", note="29997/3 is 9999")
P("s14-rational-num-after-mult", "(x^(5000/3))^2", "expression", CMP % 13,
note="every written part within 4 digits; 10000/3 past the bound only after the product")
P("s14-rational-den", "(x^(1/9999))^(1/2)", "expression", CMP % 13, note="1/19998")
P("s14-rational-den-reduced", "(x^(2/9999))^(1/2)", "expression", "(x^(2/9999))^(1/2)", note="2/19998 is 1/9999")
P("s14-sqrt-counts-half", "(sqrt(x^9998))^2", "expression", "(sqrt(x^9998))^2", note="9998 x 1/2 x 2")
P("s14-sqrt-then-power", "(sqrt(x^9999))^3", "expression", CMP % 15, note="29997/2")
P("s14-sqrt-nested-13", "sqrt(" * 13 + "x" + cl(13), "expression", "sqrt(" * 13 + "x" + cl(13), note="1/8192")
P("s14-sqrt-nested-14", "sqrt(" * 14 + "x" + cl(14), "expression", CMP % 1,
note="1/16384 at the outermost sqrt, which completes last")
P("s14-abs-passes", "(abs(x^9999))^2", "expression", CMP % 14)
P("s14-function-ends", "(sin(x^9999)^9999)^9999", "expression", "(sin(x^9999)^9999)^9999",
note="sin yields a pure number: the outer powers compose no exponent of x")
P("s14-exp-ln-end", "(exp(x)^9999*ln(x)^9999)^9999", "expression", "(exp(x)^9999*ln(x)^9999)^9999")
P("s14-literal-no-leaf", "(2^9999)^9999", "expression", "(2^9999)^9999")
P("s14-D-leaf", "(D(x,t,9999)^9999)^2", "expression", CMP % 19)
P("s14-leaves-mixed", "((x^9999*y)^1)^2", "expression", CMP % 15, note="y composes 2, x 19998")
P("s14-zero-exponent", "((x^9999)^0)^9999", "expression", "((x^9999)^0)^9999")
P("s14-order-chained-first", "(x^9999)^9999^2", "expression", "REFUSED chained ^ needs parentheses at 14",
note="the grammar refuses the chained ^ before the power is complete")
D("s14-nested-power-5", "((((x^9999)^9999)^9999)^9999)^9999", "expression", CMP % 12)
E("s14-nested-power-kind", "(((a)^9999)^9999)", "expression", B(a=("1", "rad")), rf(CMP % 12))
t = c(TPK); law(t, "KIN")["EQUATION"] = "D(x, t) = (v^100)^100"
add("names_check/s14-composed", "names_check", {"tpk": t},
"[false,[LAW:KIN: EQUATION does not parse: a computed exponent beyond 9999 at 18]]")
# -- the dimension walk: an exponent read or computed past 9999 (T4, T6)
D("s14-value-9999", "f^9999", "expression", "T-9999")
D("s14-value-10000-mul", "f^9999*f", "expression", OOR)
D("s14-value-9999-mul", "f^9998*f", "expression", "T-9999")
D("s14-value-10000-div", "x^9999/x^(-1)", "expression", OOR)
D("s14-value-10000-D", "D(v,t,9999)", "expression", OOR, note="tpc_form 0.2.0 before S14 answered [OK,L1 T-10000]")
D("s14-value-D-sum", "D(x,t,9999)*D(x,t,1)", "expression", OOR)
D("s14-value-D-9999", "D(x,t,9998)*D(x,t,1)", "expression", "L2 T-9999")
D("s14-value-pow-10000", "k_s^5000", "expression", OOR)
D("s14-value-pow-9998", "k_s^4999", "expression", "M4999 T-9998")
D("s14-value-rational", "(k_s*k_s)^(5001/2)", "expression", OOR, note="composes 5001/2 (T1 passes); T -4 x 5001/2 = -10002")
D("s14-value-rational-9998", "(k_s*k_s)^(4999/2)", "expression", "M4999 T-9998")
add("dim/s14-read-19998", "form_dimension", {"text": "x", "mode": "expression", "dimensions": {"x": "L9999 L9999"}},
"[REFUSED,x has no DIMENSION]",
note="the exponents add to 19998: under S15 tpc_zone refuses the DIMENSION, so x has none (under S14 alone, "
"an exponent is out of range; before S14, [OK,L19998])")
add("dim/s14-read-9999", "form_dimension", {"text": "x", "mode": "expression", "dimensions": {"x": "L9999"}}, "[OK,L9999]")
add("dim/s14-mul-19998", "form_dimension", {"text": "x*x", "mode": "expression", "dimensions": {"x": "L9999"}}, rf(OOR))
add("t4/s14-value", "t4_homogeneity",
{"tpk": tpk_consts([LW("L", "D(z, t, 9999)*D(z, t, 1) = D(z, t, 9999)*D(z, t, 1)", ["z", "t"], "CONSTITUTIVE")], [])},
"[false,[LAW:L: EQUATION an exponent is out of range (T4)]]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "abs(x)^9999*x < x_max"
add("t6/s14-value", "t6_totality", {"tpk": t}, "[false,[BOUNDARY:B_small: CONDITION an exponent is out of range (T6)]]")
# -- the KIND walk (eval_form, T3)
E("s14-kind-read-10000", "x", "expression", B(x=("1", "sr5000")), KOOR,
note="sr counts as rad2; tpc_form 0.2.0 before S14 answered [OK,1,rad10000]")
E("s14-kind-mul-19998", "x*x", "expression", B(x=("1", "rad9999")), KOOR)
E("s14-kind-mul-9999", "x*y", "expression", B(x=("1", "rad9998"), y=("1", "rad")), "[OK,1,rad9999]")
E("s14-kind-pow-10000", "x^2", "expression", B(x=("1", "rad5000")), KOOR)
E("s14-kind-div-10000", "x/y", "expression", B(x=("1", "rad9999"), y=("1", "rad-1")), KOOR)
add("t3laws/s14-kind", "t3_laws",
{"tpk": tpk_consts([LW("L", "a*a = b", ["a", "b"])], [K("a", "1", "1", "rad9999"), K("b", "1", "1", "rad9999")])},
"[false,[LAW:L: EQUATION cannot be evaluated under the declared values: a kind exponent is out of range (T3)]]")
# -- evaluation: a zero base under a negative rational exponent
Z0 = "[REFUSED,0 under a negative exponent]"
E("s14-zero-neg-rational", "x^(-1/2)", "expression", B(x=("0", "m")), Z0,
note="tpc_form 0.2.0 before S14: TPC-PY raised ValueError (math domain error); TPC-PHP answered not a finite double")
E("s14-negzero-neg-rational", "(-x)^(-1/2)", "expression", B(x=("0", "m")), Z0, note="-0.0 is a zero base")
E("s14-zero-neg-integral-rational", "x^(-4/2)", "expression", B(x=("0", "m")), Z0)
E("s14-zero-neg-rational-downstream", "1/x^(-1/2)", "expression", B(x=("0", "m")), Z0,
note="tpc_form 0.2.0 before S14: TPC-PHP answered [OK,0,none]")
E("s14-zero-pos-rational", "x^(1/2)", "expression", B(x=("0", "m")), "[OK,0,none]")
E("s14-zero-zero-rational", "x^(0/2)", "expression", B(x=("0", "m")), "[OK,1,none]")
# ---- D177.1 (tpc_form 0.2.0, unreleased): the D variable ---------------------------------
# The D variable is the second argument s of D(x, s, n): a DOF of the TPK that no CONSTRAINT
# (FIX or REMOVE) targets, of any DIMENSION (the DIMENSION T1 requirement removed); under
# D_VARIABLES ONE (the TPK PARAMETERS; ONE when absent) every D of the TPK's forms uses one
# s, under SEVERAL any number (T1: d_variable_check). T4: D(x, s, n) has DIMENSION dim(x)
# less n times dim(s), integer exponents, the result within -9999..9999 (S14). Hand-derived.
D("d177-scaled-variable", "D(x,theta)", "expression", "L1", note="a dimensionless variable: L1 less 1")
D("d177-scaled-variable-order-2", "D(x,theta,2)", "expression", "L1")
D("d177-length-variable", "D(v,x)", "expression", "T-1", note="L1 T-1 less L1")
D("d177-length-variable-order-2", "D(x,y,2)", "expression", "L-1", note="L1 less 2 x L1")
D("d177-frequency-variable", "D(x,f)", "expression", "L1 T1", note="L1 less T-1")
D("d177-self", "D(f,f)", "expression", "1")
D("d177-time-order-3", "D(x,t,3)", "expression", "L1 T-3", note="the time variable reads as before")
D("d177-equation-length-variable", "D(v,x)*v=D(v,t)", "equation", "L1 T-2",
note="dv/dx times v is dv/dt: T-1 times L1 T-1 against L1 T-2")
D("d177-equation-mixed-fail", "D(x,theta)=v", "equation", "REFUSED sides have dimensions L1 and L1 T-1")
add("dim/d177-product-past-bound-result-within", "form_dimension",
{"text": "D(x,s,9999)", "mode": "expression", "dimensions": {"x": "L9999", "s": "L2"}}, "[OK,L-9999]",
note="n times dim(s) is L19998, not a result of any step; the result L9999 less L19998 is L-9999, within the bound")
add("dim/d177-result-out-of-range", "form_dimension",
{"text": "D(x,s,2)", "mode": "expression", "dimensions": {"x": "L1", "s": "L-5000"}}, rf(OOR),
note="L1 less 2 x L-5000 is L10001")
add("dim/d177-result-out-of-range-negative", "form_dimension",
{"text": "D(x,s,9999)", "mode": "expression", "dimensions": {"x": "L-1", "s": "L1"}}, rf(OOR),
note="L-1 less 9999 x L1 is L-10000")
add("dim/d177-result-at-bound", "form_dimension",
{"text": "D(x,s,9999)", "mode": "expression", "dimensions": {"x": "L0", "s": "L1 T-1"}}, "[OK,L-9999 T9999]")
add("dim/d177-variable-read-out-of-range", "form_dimension",
{"text": "D(x,s)", "mode": "expression", "dimensions": {"x": "L1", "s": "L9999 L1"}}, "[REFUSED,s has no DIMENSION]",
note="a DIMENSION tpc_zone refuses (S15) is none")
# T4 over a TPK whose D variable is not time
A21_TPK = {"DOF": [{"NAME": "X", "DIMENSION": "1"}, {"NAME": "V", "DIMENSION": "1"}, {"NAME": "tau", "DIMENSION": "1"}],
"LAW": [{"NAME": "KIN", "STATEMENT": "dX/dtau = V", "REFS": ["X", "V", "tau"], "ROLE": "EOM(X)",
"EQUATION": "D(X, tau) = V"},
{"NAME": "N2", "STATEMENT": "dV/dtau = -X", "REFS": ["X", "V", "tau"], "ROLE": "EOM(V)",
"EQUATION": "D(V, tau) = -X"}]}
add("t4/d177-scaled-time-A21", "t4_homogeneity", {"tpk": A21_TPK}, "[true,[]]",
note="out/A/suite/A21 with ROLEs added; before D177.1: [false,[LAW:KIN: EQUATION D needs a T1 variable, not tau of 1 "
"(T4),LAW:N2: EQUATION D needs a T1 variable, not tau of 1 (T4)]]")
t = c(A21_TPK); t["LAW"][1]["EQUATION"] = "D(V, tau, 2) = -X"
add("t4/d177-scaled-time-second-order", "t4_homogeneity", {"tpk": t}, "[true,[]]",
note="a dimensionless variable: every order has the operand's DIMENSION")
BEAM = {"DOF": [{"NAME": "w", "DIMENSION": "L1"}, {"NAME": "s", "DIMENSION": "L1"}],
"CONSTANT": [{"NAME": "M_b", "DIMENSION": "L2 M1 T-2"}, {"NAME": "E_y", "DIMENSION": "L-1 M1 T-2"},
{"NAME": "I_a", "DIMENSION": "L4"}],
"LAW": [{"NAME": "BEAM", "STATEMENT": "d2w/ds2 = M_b / (E_y I_a)", "REFS": ["w", "s", "M_b", "E_y", "I_a"],
"ROLE": "EOM(w)", "EQUATION": "D(w, s, 2) = M_b / (E_y * I_a)"}]}
add("t4/d177-beam-arc-length", "t4_homogeneity", {"tpk": BEAM}, "[true,[]]",
note="D(w,s,2): L1 less 2 x L1 = L-1; M_b/(E_y*I_a): L2 M1 T-2 less L-1 M1 T-2 less L4 = L-1")
t = c(BEAM); t["LAW"][0]["EQUATION"] = "D(w, s) = M_b / (E_y * I_a)"
add("t4/d177-beam-wrong-order", "t4_homogeneity", {"tpk": t},
"[false,[LAW:BEAM: EQUATION sides have dimensions 1 and L-1 (T4)]]")
# d_variables: the sorted distinct D variables of the TPK's forms (every LAW's EQUATION that parses)
TAU = c(TPK)
TAU["DOF"].append({"NAME": "tau", "DIMENSION": "T1"})
law(TAU, "KIN")["EQUATION"] = "D(x, tau) = v"; law(TAU, "KIN")["REFS"] = ["x", "v", "tau"]
add("dvars/spring", "d_variables", {"tpk": TPK}, "[t]")
add("dvars/two-clocks", "d_variables", {"tpk": TAU}, "[t,tau]")
add("dvars/scaled-time-A21", "d_variables", {"tpk": A21_TPK}, "[tau]")
add("dvars/beam", "d_variables", {"tpk": BEAM}, "[s]")
HEAT = {"DOF": [{"NAME": "u", "DIMENSION": "TH1"}, {"NAME": "X", "DIMENSION": "L1"}, {"NAME": "t", "DIMENSION": "T1"}],
"CONSTANT": [{"NAME": "alpha_d", "DIMENSION": "L2 T-1"}],
"LAW": [{"NAME": "HEAT", "STATEMENT": "du/dt = alpha d2u/dX2", "REFS": ["u", "t", "alpha_d", "X"],
"ROLE": "EOM(u)", "EQUATION": "D(u, t) = alpha_d * D(u, X, 2)"}]}
add("dvars/heat-one-law-two-variables", "d_variables", {"tpk": HEAT}, "[X,t]", note="code point order: X before t")
t = c(TPK)
for l in t["LAW"]:
del l["EQUATION"]
add("dvars/no-forms", "d_variables", {"tpk": t}, "[]")
t = c(TAU); law(t, "KIN")["EQUATION"] = "D(x, tau) ="
add("dvars/unparsed-form-uses-none", "d_variables", {"tpk": t}, "[t]")
t = c(TAU); law(t, "KIN")["EQUATION"] = "D(x, tau) = v\u202e"
add("dvars/hidden-character-uses-none", "d_variables", {"tpk": t}, "[t]")
t = c(TAU); law(t, "KIN")["EQUATION"] = 7
add("dvars/wrong-type-uses-none", "d_variables", {"tpk": t}, "[t]")
t = c(TAU); law(t, "KIN")["EQUATION"] = "abs(D(x, tau)) + 0*D(v, t, 2) = v"
add("dvars/nested", "d_variables", {"tpk": t}, "[t,tau]")
t = c(TPK); t["BOUNDARY"][0]["CONDITION"] = "D(x,tau)<1"
add("dvars/condition-holds-none", "d_variables", {"tpk": t}, "[t]",
note="a CONDITION cannot hold D (it does not parse); only LAW EQUATIONs are read")
add("dvars/not-an-object", "d_variables", {"tpk": "x"}, "[]")
t = c(TPK); t["LAW"] = "N2"
add("dvars/laws-not-a-list", "d_variables", {"tpk": t}, "[]")
# d_variable_check: T1's D-variable rules (a part of T1 beside names_check)
def with_params(tpk, pm):
out = {"PARAMETERS": pm}
out.update(c(tpk))
return out
ONE_2 = "TPK: D_VARIABLES is ONE (ONE when absent), but the forms use D variables t (LAW:FREE_Z, LAW:N2), tau (LAW:KIN)"
add("dvar_check/spring", "d_variable_check", {"tpk": TPK}, "[true,[]]")
add("dvar_check/two-clocks-default-one", "d_variable_check", {"tpk": TAU}, "[false,[" + ONE_2 + "]]")
add("dvar_check/two-clocks-explicit-one", "d_variable_check", {"tpk": with_params(TAU, {"D_VARIABLES": "ONE"})},
"[false,[" + ONE_2 + "]]")
add("dvar_check/two-clocks-empty-parameters", "d_variable_check", {"tpk": with_params(TAU, {})}, "[false,[" + ONE_2 + "]]")
add("dvar_check/two-clocks-several", "d_variable_check", {"tpk": with_params(TAU, {"D_VARIABLES": "SEVERAL"})}, "[true,[]]")
add("dvar_check/two-clocks-malformed-switch", "d_variable_check", {"tpk": with_params(TAU, {"D_VARIABLES": "TWO"})},
"[true,[]]", note="the count rule reads ONE or SEVERAL only; T1 refuses D_VARIABLES TWO as a field")
add("dvar_check/two-clocks-parameters-not-object", "d_variable_check", {"tpk": with_params(TAU, "ONE")}, "[true,[]]",
note="T1 refuses the PARAMETERS part; the count rule is not applied under it")
add("dvar_check/heat-default-one", "d_variable_check", {"tpk": HEAT},
"[false,[TPK: D_VARIABLES is ONE (ONE when absent), but the forms use D variables X (LAW:HEAT), t (LAW:HEAT)]]")
add("dvar_check/heat-several", "d_variable_check", {"tpk": with_params(HEAT, {"D_VARIABLES": "SEVERAL"})}, "[true,[]]")
add("dvar_check/scaled-time-A21", "d_variable_check", {"tpk": A21_TPK}, "[true,[]]",
note="a DOF of DIMENSION 1 is a D variable (the DIMENSION T1 requirement removed)")
t = c(TPK); law(t, "KIN")["EQUATION"] = "D(x, m) = v"; law(t, "KIN")["REFS"] = ["x", "v", "m"]
add("dvar_check/constant-under-several", "d_variable_check", {"tpk": with_params(t, {"D_VARIABLES": "SEVERAL"})},
"[false,[LAW:KIN: EQUATION's D variable m is not a DOF]]")
add("dvar_check/constant-under-one", "d_variable_check", {"tpk": t},
"[false,[LAW:KIN: EQUATION's D variable m is not a DOF,"
"TPK: D_VARIABLES is ONE (ONE when absent), but the forms use D variables m (LAW:KIN), t (LAW:FREE_Z, LAW:N2)]]")
t = c(TPK); law(t, "KIN")["EQUATION"] = "D(x, q) = v"
add("dvar_check/unresolved", "d_variable_check", {"tpk": with_params(t, {"D_VARIABLES": "SEVERAL"})},
"[false,[LAW:KIN: EQUATION's D variable q is not a DOF]]", note="REFS are not read here: T1 reports them")
t = c(TPK); law(t, "KIN")["EQUATION"] = "D(x, N2) = v"
add("dvar_check/names-a-law", "d_variable_check", {"tpk": with_params(t, {"D_VARIABLES": "SEVERAL"})},
"[false,[LAW:KIN: EQUATION's D variable N2 is not a DOF]]")
t = c(TPK); t["CONSTRAINT"].append({"NAME": "C_T", "TARGET": "t", "ACTION": "FIX", "VALUE": "0", "UNIT": "s", "STATEMENT": "t = 0"})
add("dvar_check/fix-target", "d_variable_check", {"tpk": t},
"[false,[LAW:FREE_Z: EQUATION's D variable t is the TARGET of CONSTRAINT:C_T,"
"LAW:KIN: EQUATION's D variable t is the TARGET of CONSTRAINT:C_T,"
"LAW:N2: EQUATION's D variable t is the TARGET of CONSTRAINT:C_T]]")
t = c(TPK); t["CONSTRAINT"] = [{"NAME": "C_TR", "TARGET": "t", "ACTION": "REMOVE", "STATEMENT": "no t"},
{"NAME": "C_TF", "TARGET": "t", "ACTION": "FIX", "VALUE": "1", "UNIT": "s", "STATEMENT": "t = 1"}]
t["LAW"] = [l for l in t["LAW"] if l["NAME"] == "KIN"]
add("dvar_check/two-targets", "d_variable_check", {"tpk": t},
"[false,[LAW:KIN: EQUATION's D variable t is the TARGET of CONSTRAINT:C_TF,"
"LAW:KIN: EQUATION's D variable t is the TARGET of CONSTRAINT:C_TR]]")
t = c(TPK); t["CONSTRAINT"].append({"NAME": "C_T", "TARGET": "t", "ACTION": "fix", "STATEMENT": "t held"})
add("dvar_check/any-action-counts", "d_variable_check", {"tpk": t},
"[false,[LAW:FREE_Z: EQUATION's D variable t is the TARGET of CONSTRAINT:C_T,"
"LAW:KIN: EQUATION's D variable t is the TARGET of CONSTRAINT:C_T,"
"LAW:N2: EQUATION's D variable t is the TARGET of CONSTRAINT:C_T]]",
note="a CONSTRAINT's TARGET counts whatever its ACTION; T1 refuses ACTION fix separately")
t = c(TPK); t["CONSTRAINT"] = [{"NAME": "C_X", "TARGET": ["t"], "ACTION": "FIX"}, "C_T", 5]
add("dvar_check/malformed-constraints-ignored", "d_variable_check", {"tpk": t}, "[true,[]]",
note="a TARGET that is not a string targets nothing; T1 reports the shapes")
t = c(TPK); t["CONSTRAINT"] = "C_T"
add("dvar_check/constraints-not-a-list", "d_variable_check", {"tpk": t}, "[true,[]]")
t = c(TPK); t["CONSTRAINT"].append({"TARGET": "t", "ACTION": "REMOVE", "STATEMENT": "no t"})
t["LAW"] = [l for l in t["LAW"] if l["NAME"] == "KIN"]; t["LAW"][0]["NAME"] = "K\u202eIN"
add("dvar_check/unnamed-and-hidden-escaped", "d_variable_check", {"tpk": t},
"[false,[LAW:K<U+202E>IN: EQUATION's D variable t is the TARGET of CONSTRAINT:?]]",
note="a quoted NAME escapes disallowed code points; an unnamed entry shows as ?")
t = c(TAU); law(t, "KIN")["EQUATION"] = "D(x, tau) ="
add("dvar_check/unparsed-form-uses-none", "d_variable_check", {"tpk": t}, "[true,[]]")
t = c(TAU); law(t, "KIN")["EQUATION"] = "D(x, tau) = v\u202e"
add("dvar_check/hidden-character-uses-none", "d_variable_check", {"tpk": t}, "[true,[]]")
t = c(TAU); del law(t, "KIN")["NAME"]
add("dvar_check/unnamed-law", "d_variable_check", {"tpk": t},
"[false,[TPK: D_VARIABLES is ONE (ONE when absent), but the forms use D variables t (LAW:FREE_Z, LAW:N2), tau (LAW:?)]]")
t = c(TPK); t["DOF"][3]["ROLE"] = "INPUT"
add("dvar_check/input-dof", "d_variable_check", {"tpk": t}, "[true,[]]")
add("dvar_check/not-an-object", "d_variable_check", {"tpk": "x"}, "[true,[]]")
# ---- S32: the parse tree, public (form_tree; tpc_form 0.2.0, unreleased) -------------
# form_tree returns ["OK", the tree the checks walk] or the refusal parse_form gives. The
# tree is as parsed: a parenthesis the canonical spelling drops stays a "paren" node; a
# literal is its canonical decimal; D's order is 1 when not written; a power's exponent is
# [p, q] as written. Every expectation hand-derived from the grammar in tpc_form's header.
def T(cid, text, mode, expect, **extra):
add("tree/" + cid, "form_tree", {"text": text, "mode": mode},
"[OK," + expect + "]" if not expect.startswith("REFUSED ") else "[REFUSED," + expect[8:] + "]", **extra)
T("law-N2", "m * D(v, t) = -k_s * x", "equation", "[eq,[bin,*,[id,m],[D,v,t,1]],[bin,*,[neg,[id,k_s]],[id,x]]]",
note="unary minus binds to its power, so -k_s * x is (-k_s)*x")
T("law-KIN", "D(x, t) = v", "equation", "[eq,[D,x,t,1],[id,v]]")
T("law-FREE_Z", "D(z, t, 2) = 0", "equation", "[eq,[D,z,t,2],[num,0]]")
T("law-EOM_Z", "m * D(z, t, 2) = 0", "equation", "[eq,[bin,*,[id,m],[D,z,t,2]],[num,0]]")
T("boundary-B_small", "abs(x) < x_max", "predicate", "[pred,[cmp,<,[fn,abs,[id,x]],[id,x_max]]]")
T("signature-form", "D(x, t) = v", "form", "[eq,[D,x,t,1],[id,v]]")
T("signature-operation", "D(x, t)", "form", "[expr,[D,x,t,1]]")
T("derivative-order-one-written", "D(x,t,1)", "expression", "[expr,[D,x,t,1]]",
note="D(x,t,1) and D(x,t) give one tree")
T("parens-kept", "((a+b))", "expression", "[expr,[paren,[paren,[bin,+,[id,a],[id,b]]]]]",
note="parse_form spells it a+b; the tree keeps both parentheses")
T("parens-each-side", "(a)=(b)", "equation", "[eq,[paren,[id,a]],[paren,[id,b]]]")
T("assoc-minus", "a-b-c", "expression", "[expr,[bin,-,[bin,-,[id,a],[id,b]],[id,c]]]")
T("assoc-div-mul", "a/b*c", "expression", "[expr,[bin,*,[bin,/,[id,a],[id,b]],[id,c]]]")
T("precedence-mul", "a+b*c", "expression", "[expr,[bin,+,[id,a],[bin,*,[id,b],[id,c]]]]")
T("unary-minus-power", "-a^2", "expression", "[expr,[neg,[pow,[id,a],[2,1]]]]")
T("exponents-as-written", "x^(-1)+x^(2/4)+x^02", "expression",
"[expr,[bin,+,[bin,+,[pow,[id,x],[-1,1]],[pow,[id,x],[2,4]]],[pow,[id,x],[2,1]]]]",
note="a rational exponent is kept as written, not reduced; an integer's leading zero is read away")
T("exponent-negative-rational", "x^(-3/2)", "expression", "[expr,[pow,[id,x],[-3,2]]]")
T("literals-canonical", "0.50*x+100-2.0+0.0", "expression",
"[expr,[bin,+,[bin,-,[bin,+,[bin,*,[num,5e-1],[id,x]],[num,1e2]],[num,2]],[num,0]]]")
T("functions", "sqrt(x^2)*exp(-t)", "expression", "[expr,[bin,*,[fn,sqrt,[pow,[id,x],[2,1]]],[fn,exp,[neg,[id,t]]]]]")
T("keywords-precedence", "x<1 or y>2 and z=3", "predicate",
"[pred,[or,[cmp,<,[id,x],[num,1]],[and,[cmp,>,[id,y],[num,2]],[cmp,=,[id,z],[num,3]]]]]")
T("not-predicate-paren", "not (x<1 and y>2)", "predicate",
"[pred,[not,[pparen,[and,[cmp,<,[id,x],[num,1]],[cmp,>,[id,y],[num,2]]]]]]")
T("expression-paren-in-predicate", "(x+1)<2", "predicate", "[pred,[cmp,<,[paren,[bin,+,[id,x],[num,1]]],[num,2]]]",
note="a parenthesis holding no comparison or keyword opens an expression")
T("nesting-at-bound", "(" * 64 + "x" + ")" * 64, "expression", "[expr," + "[paren," * 64 + "[id,x]" + "]" * 64 + "]",
note="64 parentheses deep, the D186.1 bound: admitted, every level a node")
T("refused-unexpected-end", "m * D(v, t) =", "equation", "REFUSED unexpected end")
T("refused-chained-power", "a^2^3", "expression", "REFUSED chained ^ needs parentheses at 4")
T("refused-equals-in-expression", "x = 1", "expression", "REFUSED unexpected token = at 3")
T("refused-no-equals", "x", "equation", "REFUSED the equation has no =")
T("refused-D-in-condition", "D(x,t)<1", "predicate", "REFUSED D is not permitted in a CONDITION at 1")
T("refused-empty", "", "expression", "REFUSED empty form")
T("refused-hidden-character", "x\u202e", "expression", "REFUSED unexpected character <U+202E> at 2",
note="the refusal escapes the code point, as parse_form's")
T("refused-integer-digits", "x^12345", "expression", "REFUSED an integer of more than 4 digits at 3")
T("refused-nesting", "(" * 65 + "x" + ")" * 65, "expression", "REFUSED more than 64 nested parentheses at 65")
T("refused-length", "x" + " " * 4096, "expression", "REFUSED the form is longer than 4096 code points")
T("refused-computed-exponent", "(x^9999)^2", "expression", "REFUSED a computed exponent beyond 9999 at 9")
add("tree/refused-not-a-string", "form_tree", {"text": 7, "mode": "expression"}, "[REFUSED,the form is not a string]")
add("tree/refused-unknown-mode", "form_tree", {"text": "x", "mode": "Equation"}, "[REFUSED,unknown mode Equation]")
# ---- self-check against the module, then write -------------------------------------
# ---- 0.5.1 (C-MS-5; increment 11): a JSON {} and a JSON [] are told apart -------------
# Expectations by hand from tpc_form's readers: a kind that is not a list holds no entry,
# a REFS that is not a list of names names nothing, a PARAMETERS part that is not an
# object applies no D_VARIABLES count, and an eval_form binding that is not an object
# binds nothing. Each case is one an assoc-array reading answered otherwise, or a valid
# empty object.
FX = {"NAME": "x", "DIMENSION": "L1"}
FT = {"NAME": "t", "DIMENSION": "T1"}
FS = {"NAME": "s", "DIMENSION": "L1"}
L_ZK = {"NAME": "L", "STATEMENT": "x moves as y", "REFS": ["x", "t"], "ROLE": "EOM(x)", "EQUATION": "D(x,t)=y"}
add("decode/names-check-kind-zero-keyed", "names_check", {"tpk": {"DOF": [FX, FT], "LAW": {"0": L_ZK}}}, "[true,[]]",
note="the LAW kind is not a list: no form is read (it read L and found y outside REFS)")
add("decode/names-check-kind-list", "names_check", {"tpk": {"DOF": [FX, FT], "LAW": [L_ZK]}},
"[false,[LAW:L: EQUATION names y, which is not in REFS]]", note="the same law as a list")
L_RZ = {"NAME": "L", "STATEMENT": "x is zero", "REFS": {"0": "x"}, "ROLE": "CONSTRAINT", "EQUATION": "x=0"}
add("decode/names-check-refs-zero-keyed", "names_check", {"tpk": {"DOF": [FX], "LAW": [L_RZ]}},
"[false,[LAW:L: EQUATION names x, which is not in REFS]]", note="REFS keyed 0 is not a list of names")
LD = {"NAME": "L", "STATEMENT": "a definition", "REFS": [], "ROLE": "DEFINITION"}
BD = {"NAME": "B", "PREDICATE": "always", "REFS": []}
add("decode/form-coverage-kinds-zero-keyed", "form_coverage", {"tpk": {"LAW": {"0": LD}, "BOUNDARY": {"0": BD}}},
"[[],[]]")
add("decode/form-coverage-kinds-list", "form_coverage", {"tpk": {"LAW": [LD], "BOUNDARY": [BD]}}, "[[L],[B]]")
add("decode/form-coverage-tpk-list", "form_coverage", {"tpk": []}, "[[],[]]")
L_T4 = {"NAME": "L", "STATEMENT": "x grows as x", "REFS": ["x", "t"], "ROLE": "EOM(x)", "EQUATION": "D(x,t)=x"}
add("decode/t4-kind-zero-keyed", "t4_homogeneity", {"tpk": {"DOF": [FX, FT], "LAW": {"0": L_T4}}}, "[true,[]]",
note="no law is read (it read L, whose sides are L1 T-1 and L1)")
B_T6 = {"NAME": "B", "PREDICATE": "x is positive", "REFS": ["x"], "CONDITION": "1/x>0"}
add("decode/t6-kind-zero-keyed", "t6_totality", {"tpk": {"DOF": [FX], "BOUNDARY": {"0": B_T6}}}, "[true,[]]",
note="no boundary is read")
CC = {"NAME": "c", "DIMENSION": "L1", "VALUE": "1", "UNIT": "m"}
L_T3 = {"NAME": "L", "STATEMENT": "c is twice c", "REFS": ["c"], "ROLE": "DEFINITION", "EQUATION": "c=2*c"}
add("decode/t3-laws-kind-zero-keyed", "t3_laws", {"tpk": {"CONSTANT": [CC], "LAW": {"0": L_T3}}}, "[true,[]]",
note="no law is read (it read L, false under c = 1 m)")
L1 = {"NAME": "L1", "STATEMENT": "x is still in t", "REFS": ["x", "t"], "ROLE": "EOM(x)", "EQUATION": "D(x,t)=0"}
L2 = {"NAME": "L2", "STATEMENT": "x is flat in s", "REFS": ["x", "s"], "ROLE": "CONSTITUTIVE", "EQUATION": "D(x,s)=0"}
DV_TPK = {"DOF": [FX, FT, FS], "LAW": [L1, L2]}
add("decode/dvar-parameters-list", "d_variable_check", {"tpk": dict(DV_TPK, PARAMETERS=[])}, "[true,[]]",
note="PARAMETERS [] is not an object: T1 refuses it, and no D_VARIABLES count applies here")
add("decode/dvar-parameters-empty-object", "d_variable_check", {"tpk": dict(DV_TPK, PARAMETERS={})},
"[false,[TPK: D_VARIABLES is ONE (ONE when absent), but the forms use D variables s (LAW:L2), t (LAW:L1)]]",
note="an empty PARAMETERS object: D_VARIABLES absent, so ONE")
add("decode/eval-bindings-list", "eval_form", {"text": "x", "mode": "expression", "bindings": [{"VALUE": "q", "UNIT": "m"}]},
"[UNBOUND,x]", note="bindings [] is not an object: nothing is bound (it read a binding 0 and refused its VALUE)")
add("decode/eval-binding-entry-list", "eval_form", {"text": "x", "mode": "expression", "bindings": {"x": []}},
"[UNBOUND,x]", note="a binding that is not an object binds nothing")
add("decode/eval-bindings-empty-object", "eval_form", {"text": "2", "mode": "expression", "bindings": {}},
"[OK,2,none]")
SIG = {"NAME": "sg", "OVER": ["x"], "IMAGE": "the position", "FORM": "x", "IMAGE_FORM": "pos"}
E_X = {"NAME": "E_x", "DOF": "x", "DOMAIN": "always", "ENVIRONMENT_QUANTITY": "position",
"IDENTIFICATION": "x is the position", "FALSIFIER": "a position off x", "FALSIFIER_CLASS": "F2",
"BEARS": [], "DIMENSION": "L1"}
HDR = {"ENVIRONMENT_INVENTORY": [{"ENVIRONMENT_QUANTITY": "position", "DIMENSION": "L1"}],
"SIGNATURE": {"0": SIG}, "TRANSFORMATIONS": []}
add("decode/ic4a-signature-zero-keyed", "ic4a_signature", {"trm": {"HEADER": HDR, "ENTRIES": [E_X]}, "tpk": {"DOF": [FX]}},
"[true,[],[]]", note="the SIGNATURE part is not a list: no signature is read")
add("decode/ic4a-signature-list", "ic4a_signature",
{"trm": {"HEADER": dict(HDR, SIGNATURE=[SIG]), "ENTRIES": [E_X]}, "tpk": {"DOF": [FX]}},
"[false,[IC4(a): SIGNATURE:sg: FORM under the entries reads position, not IMAGE_FORM pos],[]]",
note="the same signature as a list")
def dispatch(fn, i):
if fn == "form_tree": return F.form_tree(i["text"], i["mode"])
if fn == "parse_form": return F.parse_form(i["text"], i["mode"])
if fn == "form_names": return F.form_names(i["text"], i["mode"])
if fn == "form_dimension": return F.form_dimension(i["text"], i["mode"], i["dimensions"])
if fn == "form_totality": return F.form_totality(i["text"], i["dimensions"])
if fn == "eval_form": return F.eval_form(i["text"], i["mode"], i["bindings"])
if fn == "names_check": return F.names_check(i["tpk"])
if fn == "form_coverage": return F.form_coverage(i["tpk"])
if fn == "t4_homogeneity": return F.t4_homogeneity(i["tpk"])
if fn == "t6_totality": return F.t6_totality(i["tpk"])
if fn == "t3_laws": return F.t3_laws(i["tpk"])
if fn == "ic4a_signature": return F.ic4a_signature(i["trm"], i["tpk"])
if fn == "d_variables": return F.d_variables(i["tpk"])
if fn == "d_variable_check": return F.d_variable_check(i["tpk"])
if fn == "grammar_witness_count": return F.GRAMMAR_WITNESS_COUNT
raise KeyError(fn)
bad = 0
for cs in cases:
got = S.canon(dispatch(cs["fn"], cs["input"]))
if got != cs["expect"]:
bad += 1
print("MISMATCH", cs["id"], "\n expect", cs["expect"], "\n got ", got)
ids = [cs["id"] for cs in cases]
assert len(ids) == len(set(ids)), "duplicate case id"
if bad:
sys.exit("refusing to write: %d mismatches" % bad)
corpus = {
"meta": {
"name": "tpc_form_corpus", "version": "0.5.1",
"status": "increment 8 phase E, every slot of tpm_increment_8_phase_F 0.1.0 at Option 1 (2026-09-24); VERIFIED (both residences)",
"conforms_tps": "0.1.0 revision 4 (kernel tests T3, T4, T6 of TPS 2.2.3 and guide 3.6 over the D108.1 declared form; IC4 (a) of TPS 2.3.14 and guide 4.6, syntactic), with the bounds of D186.1 as drafted for TPS revision 6, 2.2.13 (proposed), and D177.1 as taken 2026-09-26 (TPS revision 6 text pending)",
"module": "tpc_form 0.2.1, proposed with TPC-PY 0.2.0, carrying D186.1, S14, D177.1, S32 and C-MS-5 (tpc_zone 0.5.1, schema 0.5.0; tpc_units 0.1.1; tpc_strike 0.2.1)",
"note": ("Every expectation is hand-derived. The spring fixture is the zone corpus's toy with a DOF t, an entry "
"E_t, and the forms of S1, S3 and S8; a test fixture, not physics under research. Evaluated values are "
"IEEE doubles compared through canon() at twelve significant digits. Both residences MUST reproduce "
"every expect. 0.2.0 adds the DEPTH cases (tpc_form 0.1.1): nesting to 10,000 and chains to 2,000 "
"terms, each expectation hand-derived and matched to TPC-PHP's answer before it was first written. 0.3.0 "
"(tpc_form 0.2.0, D186.1) adds the BOUNDS cases - an integer of at most 4 digits, a form of at most 4096 "
"code points and 64 nested parentheses, refused beyond in that order before the grammar reads the form - "
"and moves 30 DEPTH cases that lie beyond the bounds to the refusal, each noting its 0.1.1 answer; "
"and the S14 cases - the exponent a form composes under nested powers and roots at most 9999 in "
"lowest terms (T1), every exponent the dimension and KIND walks read or compute within -9999..9999, "
"and a zero base under a negative rational exponent refused. 0.4.0 (D177.1, 2026-09-26; schema 0.5.0): "
"the D variable is any DOF that no CONSTRAINT targets, one per TPK under D_VARIABLES ONE (the default) "
"and any number under SEVERAL (T1: d_variable_check; the list: d_variables); T4 reads D(x, s, n) as "
"dim(x) less n times dim(s); two earlier cases moved (dim/derivative-not-T1, "
"t4/derivative-variable-not-T1), each noting its former answer; every fixture LAW carries a ROLE. "
"0.5.0 (S32, 2026-09-26): form_tree, the public parse tree the checks walk, as parsed, with parse_form's "
"refusals; and S33: a LAW restating the motion of a FIXed DOF carries ROLE CONSTRAINT (no answer moves). "
"0.5.1 (C-MS-5, increment 11, 2026-09-28): 16 decode/ cases, a JSON {} and [] and an object keyed 0 "
"read as written in both residences, with their list controls; no earlier answer moves.")
},
"cases": cases
}
open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "vectors", "form_corpus.json"), "w", encoding="utf-8", newline="\n").write(
json.dumps(corpus, indent=1, ensure_ascii=True) + "\n")
print("wrote", len(cases), "form cases; all match hand-derived expectations")