From f8725fbc38422fa8a860700c0bb042fedcb1bd52 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Sat, 13 Jun 2026 10:37:22 +0200 Subject: [PATCH] Give the comparison families a one-letter portable prefix (tEq/eEq/aEq) Split the single comparison family into temporalComparison, everComparison and alwaysComparison, each carrying the canonical portable bare names (#/?/% prefix -> t/e/a; =/<>//>= suffix -> Eq/Ne/Lt/Le/Gt/Ge), and move ever/always out of the already-canonical patterns now that they have explicit bare names. Update the mapping and parity tests to the new 41-name family set. --- meta/portable-aliases.json | 64 +++++++++++++---------------------- tests/test_portable.py | 27 ++++++++------- tests/test_portable_parity.py | 10 +++--- 3 files changed, 43 insertions(+), 58 deletions(-) diff --git a/meta/portable-aliases.json b/meta/portable-aliases.json index cf8f456..0512c36 100644 --- a/meta/portable-aliases.json +++ b/meta/portable-aliases.json @@ -98,35 +98,33 @@ } ], "temporalComparison": [ - { - "operator": "#=", - "bareName": "teq" - }, - { - "operator": "#<>", - "bareName": "tne" - }, - { - "operator": "#<", - "bareName": "tlt" - }, - { - "operator": "#<=", - "bareName": "tle" - }, - { - "operator": "#>", - "bareName": "tgt" - }, - { - "operator": "#>=", - "bareName": "tge" - } + { "operator": "#=", "bareName": "tEq" }, + { "operator": "#<>", "bareName": "tNe" }, + { "operator": "#<", "bareName": "tLt" }, + { "operator": "#<=", "bareName": "tLe" }, + { "operator": "#>", "bareName": "tGt" }, + { "operator": "#>=", "bareName": "tGe" } + ], + "everComparison": [ + { "operator": "?=", "bareName": "eEq" }, + { "operator": "?<>", "bareName": "eNe" }, + { "operator": "?<", "bareName": "eLt" }, + { "operator": "?<=", "bareName": "eLe" }, + { "operator": "?>", "bareName": "eGt" }, + { "operator": "?>=", "bareName": "eGe" } + ], + "alwaysComparison": [ + { "operator": "%=", "bareName": "aEq" }, + { "operator": "%<>", "bareName": "aNe" }, + { "operator": "%<", "bareName": "aLt" }, + { "operator": "%<=", "bareName": "aLe" }, + { "operator": "%>", "bareName": "aGt" }, + { "operator": "%>=", "bareName": "aGe" } ], "distance": [ { "operator": "<->", - "bareName": "tdistance" + "bareName": "tDistance" }, { "operator": "|=|", @@ -141,22 +139,6 @@ ] }, "alreadyCanonical": [ - { - "kind": "family", - "family": "ever", - "operators": [ - "?=" - ], - "pattern": "ever_*" - }, - { - "kind": "family", - "family": "always", - "operators": [ - "%=" - ], - "pattern": "always_*" - }, { "kind": "functions", "functions": [ diff --git a/tests/test_portable.py b/tests/test_portable.py index 5c11397..5eef798 100644 --- a/tests/test_portable.py +++ b/tests/test_portable.py @@ -19,7 +19,8 @@ SCHEMA = ROOT / "meta" / "portable-aliases.schema.json" _EXPECTED_FAMILY_SIZES = { "topology": 4, "timePosition": 4, "spaceX": 4, "spaceY": 4, - "spaceZ": 4, "temporalComparison": 6, "distance": 2, "same": 1, + "spaceZ": 4, "temporalComparison": 6, "everComparison": 6, + "alwaysComparison": 6, "distance": 2, "same": 1, } @@ -39,11 +40,12 @@ def test_known_mappings_verbatim(self): for op, bn in [("&&", "overlaps"), ("@>", "contains"), ("-|-", "adjacent"), ("<<#", "before"), ("#&>", "overafter"), ("|&>", "overabove"), - ("/&>", "overback"), ("#=", "teq"), ("#<>", "tne"), + ("/&>", "overback"), ("#=", "tEq"), ("#<>", "tNe"), + ("?=", "eEq"), ("%=", "aEq"), ("|=|", "nearestApproachDistance"), ("~=", "same")]: self.assertEqual(flat[op], bn) - self.assertEqual(sum(_EXPECTED_FAMILY_SIZES.values()), 29) - self.assertEqual(len(flat), 29) + self.assertEqual(sum(_EXPECTED_FAMILY_SIZES.values()), 41) + self.assertEqual(len(flat), 41) def test_scope_correction_no_exclusion(self): # The corrected 100%-parity rule: these are IN scope, never deferred. @@ -72,10 +74,11 @@ def test_already_canonical_has_kind_discriminator(self): self.assertIn("functions", entry) def test_already_canonical_and_provenance(self): - pats = {a.get("pattern") for a in self.d["alreadyCanonical"] - if a.get("kind") == "family"} - self.assertIn("ever_*", pats) - self.assertIn("always_*", pats) + funcs = {f for a in self.d["alreadyCanonical"] + if a.get("kind") == "functions" + for f in a["functions"]} + self.assertIn("eIntersects", funcs) + self.assertIn("atTime", funcs) self.assertEqual(self.d["provenance"]["nativePR"][:14], "MobilityDB#107") @@ -102,13 +105,13 @@ class AttachTests(unittest.TestCase): def test_attach_and_derive(self): idl = attach_portable_aliases({"functions": []}, MAP) pa = idl["portableAliases"] - self.assertEqual(pa["count"], 29) + self.assertEqual(pa["count"], 41) self.assertEqual(pa["byOperator"]["&&"], "overlaps") self.assertEqual(pa["byBareName"]["overlaps"], "&&") self.assertEqual(pa["bareNames"], sorted(pa["byBareName"])) - # bijective: 29 distinct operators and 29 distinct bare names - self.assertEqual(len(pa["byOperator"]), 29) - self.assertEqual(len(pa["byBareName"]), 29) + # bijective: 41 distinct operators and 41 distinct bare names + self.assertEqual(len(pa["byOperator"]), 41) + self.assertEqual(len(pa["byBareName"]), 41) self.assertIn("cbuffer", pa["scope"]["inScopeTypeFamilies"]) self.assertEqual(pa["explicitBacking"], {"nearestApproachDistance": ["nad"]}) diff --git a/tests/test_portable_parity.py b/tests/test_portable_parity.py index eacefda..eef548f 100644 --- a/tests/test_portable_parity.py +++ b/tests/test_portable_parity.py @@ -35,7 +35,7 @@ def test_backed_vs_needs_explicit(self): "nad_tfloat_tfloat", # explicit backing ]) # of nearestApproach… r = build_parity(cat) - self.assertEqual(r["total"], 29) + self.assertEqual(r["total"], 41) self.assertEqual(r["byBareName"]["overlaps"]["status"], "backed") self.assertEqual(r["byBareName"]["overlaps"]["via"], "prefix") self.assertEqual(r["byBareName"]["overlaps"]["backedBy"], 2) @@ -47,13 +47,13 @@ def test_backed_vs_needs_explicit(self): self.assertEqual(nad["via"], "explicit") self.assertNotIn("nearestApproachDistance", r["unbacked"]) self.assertEqual(r["byBareName"]["overlaps"]["family"], "topology") - self.assertEqual(r["byBareName"]["teq"]["operator"], "#=") + self.assertEqual(r["byBareName"]["tEq"]["operator"], "#=") def test_every_bare_name_classified(self): r = build_parity(_catalog([])) # nothing backs anything - self.assertEqual(r["total"], 29) + self.assertEqual(r["total"], 41) self.assertEqual(r["backed"], 0) - self.assertEqual(len(r["unbacked"]), 29) # all flagged, 0 dropped + self.assertEqual(len(r["unbacked"]), 41) # all flagged, 0 dropped self.assertTrue(all(v["status"] in ("backed", "needs-explicit-backing") for v in r["byBareName"].values())) @@ -72,7 +72,7 @@ def test_no_bare_name_silently_dropped(self): r = build_parity(cat) self.assertEqual( r["backed"] + r["needsExplicitBacking"], r["total"]) - self.assertEqual(r["total"], 29) + self.assertEqual(r["total"], 41) if __name__ == "__main__":