Download src/python/tom_learner06/oracle.py from c0mbatduckzz/TOMK: direct link, hf CLI and curl.
- Browser
- Download file 10.2 kB
-
https://huggingface.co/c0mbatduckzz/TOMK/resolve/main/src/python/tom_learner06/oracle.py
- Command line
-
hf download hf://c0mbatduckzz/TOMK/src/python/tom_learner06/oracle.py
-
curl -L -o oracle.py https://huggingface.co/c0mbatduckzz/TOMK/resolve/main/src/python/tom_learner06/oracle.py
10.2 kB
| from __future__ import annotations | |
| """Independent exact oracle for the finite Learner 0.2 registry. | |
| This module deliberately does not invoke :mod:`tomagi.formal` or reuse the | |
| formal expression tree. It is a separately implemented falsification oracle | |
| using :class:`fractions.Fraction` and ordinary finite enumeration. | |
| """ | |
| from dataclasses import dataclass | |
| from fractions import Fraction | |
| import copy | |
| from typing import Any, Iterable, Mapping | |
| from tomagi.canonical import attach_hash, content_hash, verify_hash | |
| class OracleError(ValueError): | |
| pass | |
| def frac(value: Any) -> Fraction: | |
| if isinstance(value, bool): | |
| raise OracleError("boolean is not an exact rational") | |
| if isinstance(value, int): | |
| return Fraction(value, 1) | |
| if isinstance(value, Mapping) and set(value) == {"num", "den"}: | |
| n, d = value["num"], value["den"] | |
| if isinstance(n, bool) or isinstance(d, bool) or not isinstance(n, int) or not isinstance(d, int): | |
| raise OracleError("rational words must be integers") | |
| if d <= 0: | |
| raise OracleError("rational denominator must be positive") | |
| f = Fraction(n, d) | |
| if f.numerator != n or f.denominator != d: | |
| raise OracleError("rational must be reduced") | |
| return f | |
| raise OracleError(f"not an exact rational: {value!r}") | |
| def q(value: Fraction | int) -> dict[str, int]: | |
| f = value if isinstance(value, Fraction) else Fraction(value, 1) | |
| return {"num": f.numerator, "den": f.denominator} | |
| def _eval_tree(node: Mapping[str, Any], x: Fraction, depth: int = 0) -> Fraction: | |
| if depth > 2: | |
| raise OracleError("expression tree exceeds depth 2") | |
| op = node.get("op") | |
| if op == "x": | |
| return x | |
| if op == "const": | |
| return frac(node["value"]) | |
| if op in {"neg", "abs", "square"}: | |
| value = _eval_tree(node["arg"], x, depth + 1) | |
| if op == "neg": | |
| return -value | |
| if op == "abs": | |
| return abs(value) | |
| return value * value | |
| if op in {"add", "sub", "mul"}: | |
| left = _eval_tree(node["left"], x, depth + 1) | |
| right = _eval_tree(node["right"], x, depth + 1) | |
| if op == "add": | |
| return left + right | |
| if op == "sub": | |
| return left - right | |
| return left * right | |
| raise OracleError(f"unknown expression-tree op {op!r}") | |
| def predict(candidate: Mapping[str, Any], observation: Mapping[str, Any]) -> tuple[bool, Any]: | |
| family = candidate.get("family_id") | |
| x_value = observation.get("input") | |
| if family == "family:polynomial:0.2": | |
| x = frac(x_value) | |
| coeffs = candidate["coefficients"] | |
| return True, q(frac(coeffs[0]) + frac(coeffs[1]) * x + frac(coeffs[2]) * x * x) | |
| if family == "family:piecewise-affine:0.2": | |
| x = frac(x_value) | |
| side = candidate["left"] if x <= frac(candidate["breakpoint"]) else candidate["right"] | |
| return True, q(frac(side["slope"]) * x + frac(side["intercept"])) | |
| if family == "family:transition-table:0.2": | |
| matches = [entry for entry in candidate["entries"] if entry["input"] == x_value] | |
| if len(matches) != 1: | |
| return False, None | |
| return True, copy.deepcopy(matches[0]["output"]) | |
| if family == "family:expression-tree:0.2": | |
| return True, q(_eval_tree(candidate["tree"], frac(x_value))) | |
| raise OracleError(f"unknown candidate family {family!r}") | |
| def _matches(candidate: Mapping[str, Any], observation: Mapping[str, Any]) -> bool: | |
| defined, value = predict(candidate, observation) | |
| if not defined: | |
| return False | |
| target = observation["target"] | |
| numeric = isinstance(target, int) or isinstance(target, Mapping) | |
| if numeric: | |
| try: | |
| return frac(value) == frac(target) | |
| except OracleError: | |
| return False | |
| return value == target | |
| def _partition(dataset: Mapping[str, Any], name: str) -> list[Mapping[str, Any]]: | |
| ids = dataset["partitions"][name] | |
| by_id = {observation["id"]: observation for observation in dataset["observations"]} | |
| return [by_id[item] for item in ids] | |
| def _contradictions(observations: Iterable[Mapping[str, Any]]) -> list[dict[str, Any]]: | |
| rows = list(observations) | |
| out: list[dict[str, Any]] = [] | |
| for left_index, left in enumerate(rows): | |
| for right in rows[left_index + 1:]: | |
| if left["input"] == right["input"] and left["target"] != right["target"]: | |
| out.append(attach_hash({ | |
| "schema": "TOM-LEARNER-0.2-CONTRADICTION-1.0", | |
| "left_observation": left["content_hash"], | |
| "right_observation": right["content_hash"], | |
| "input": copy.deepcopy(left["input"]), | |
| "left_target": copy.deepcopy(left["target"]), | |
| "right_target": copy.deepcopy(right["target"]), | |
| })) | |
| return out | |
| def _family_candidates(registry: Mapping[str, Any], dataset: Mapping[str, Any]) -> list[Mapping[str, Any]]: | |
| eligible = set(dataset["eligible_families"]) | |
| out: list[Mapping[str, Any]] = [] | |
| for family in registry["families"]: | |
| if family["id"] in eligible: | |
| if len(family["candidates"]) > family["search_budget"]["max_candidates"]: | |
| raise OracleError("family candidate registry exceeds declared search budget") | |
| out.extend(family["candidates"]) | |
| return out | |
| def _fit_hash(dataset: Mapping[str, Any], registry: Mapping[str, Any]) -> str: | |
| train = _partition(dataset, "train") | |
| return content_hash({ | |
| "schema": "TOM-LEARNER-0.2-TRAIN-FIT-INPUT-1.0", | |
| "dataset_id": dataset["id"], | |
| "family_registry_hash": registry["content_hash"], | |
| "eligible_families": dataset["eligible_families"], | |
| "train_observations": [item["content_hash"] for item in train], | |
| }) | |
| def _regression_impact(selected: Mapping[str, Any] | None, dataset: Mapping[str, Any], | |
| prior: Mapping[str, Any]) -> dict[str, Any]: | |
| supersedes = dataset.get("supersedes") | |
| found = supersedes is None | |
| results: list[dict[str, Any]] = [] | |
| for definition in prior["definitions"]: | |
| replacement = definition["model"] | |
| replaced = supersedes == definition["content_hash"] | |
| if replaced: | |
| found = True | |
| if selected is not None: | |
| replacement = selected | |
| case_results = [] | |
| for case in definition["regression_cases"]: | |
| observation = {"input": case["input"], "target": case["expected"]} | |
| passed = _matches(replacement, observation) | |
| case_results.append({"case_id": case["id"], "passed": passed}) | |
| results.append({ | |
| "definition_hash": definition["content_hash"], | |
| "replaced": replaced, | |
| "passed": all(item["passed"] for item in case_results), | |
| "cases": case_results, | |
| }) | |
| all_pass = found and all(item["passed"] for item in results) | |
| return attach_hash({ | |
| "schema": "TOM-LEARNER-0.2-REGRESSION-IMPACT-1.0", | |
| "dataset_id": dataset["id"], | |
| "supersedes": supersedes, | |
| "superseded_definition_found": found, | |
| "tested_definitions": len(results), | |
| "all_pass": all_pass, | |
| "results": results, | |
| }) | |
| def evaluate_dataset(dataset: Mapping[str, Any], registry: Mapping[str, Any], | |
| prior: Mapping[str, Any]) -> dict[str, Any]: | |
| if not verify_hash(dict(dataset)) or not verify_hash(dict(registry)) or not verify_hash(dict(prior)): | |
| raise OracleError("oracle input content hash mismatch") | |
| train = _partition(dataset, "train") | |
| validation = _partition(dataset, "validation") | |
| holdout = _partition(dataset, "holdout") | |
| candidates = _family_candidates(registry, dataset) | |
| survivors = [candidate for candidate in candidates if all(_matches(candidate, row) for row in train)] | |
| contradictions = _contradictions(dataset["observations"]) | |
| selected = survivors[0] if len(survivors) == 1 else None | |
| validation_failures = [] if selected is None else [row for row in validation if not _matches(selected, row)] | |
| holdout_failures = [] if selected is None else [row for row in holdout if not _matches(selected, row)] | |
| regression = _regression_impact(selected, dataset, prior) | |
| accepted = ( | |
| len(survivors) == 1 | |
| and not contradictions | |
| and not validation_failures | |
| and not holdout_failures | |
| and regression["all_pass"] | |
| ) | |
| if len(survivors) > 1: | |
| reason = "ambiguous-train-survivors" | |
| elif len(survivors) == 0: | |
| reason = "no-exact-train-candidate" | |
| elif contradictions: | |
| reason = "contradiction" | |
| elif validation_failures: | |
| reason = "validation-counterexample" | |
| elif holdout_failures: | |
| reason = "holdout-counterexample" | |
| elif not regression["all_pass"]: | |
| reason = "regression-impact" | |
| else: | |
| reason = "accepted" | |
| return { | |
| "dataset_id": dataset["id"], | |
| "accepted": accepted, | |
| "reason": reason, | |
| "candidate_count": len(candidates), | |
| "survivor_hashes": [item["content_hash"] for item in survivors], | |
| "selected_candidate_hash": None if selected is None else selected["content_hash"], | |
| "fit_input_hash": _fit_hash(dataset, registry), | |
| "validation_failures": [item["id"] for item in validation_failures], | |
| "holdout_failures": [item["id"] for item in holdout_failures], | |
| "contradiction_count": len(contradictions), | |
| "regression_all_pass": regression["all_pass"], | |
| "supersedes": dataset.get("supersedes"), | |
| } | |
| def evaluate_all(datasets: list[Mapping[str, Any]], registry: Mapping[str, Any], | |
| prior: Mapping[str, Any]) -> dict[str, Any]: | |
| rows = [evaluate_dataset(dataset, registry, prior) for dataset in datasets] | |
| return { | |
| "dataset_count": len(rows), | |
| "accepted_count": sum(row["accepted"] for row in rows), | |
| "rejected_count": sum(not row["accepted"] for row in rows), | |
| "ambiguous_count": sum(row["reason"] == "ambiguous-train-survivors" for row in rows), | |
| "rows": rows, | |
| } | |