generate/rate_comprehension/solver.py: solve_rate computes the one unknown — quantity=rate×time (always integer), rate=quantity÷time, time=quantity÷rate (exact division or REFUSE non_integer_solution, never rounds). Confirms compound-unit composition via the R3a algebra (defensive; a RateProblem's units compose by construction). answer_unit gives the answer's unit. No floats. Ties to the gold: solves all 6 solved fixtures to gold; refuses both solver_refuses with non_integer_solution. Meaningful-fail: 100÷3 refuses (not 33), 99÷3=33. Off-serving. 5 tests.
43 lines
2 KiB
Python
43 lines
2 KiB
Python
"""Tests for the exact integer single-rate solver (R3c).
|
|
|
|
Ties the solver to the R3 gold: every ``solved`` fixture computes its ``gold``; every
|
|
``solver_refuses`` fixture refuses with the gold-claimed reason. Exact-or-refuse, never rounds.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from evals.rate_oracle.runner import _load_rate_gold, gold_to_problem
|
|
from generate.meaning_graph.reader import Refusal
|
|
from generate.rate_comprehension.model import RateProblem
|
|
from generate.rate_comprehension.solver import answer_unit, solve_rate
|
|
from generate.rate_comprehension.units import RateUnit
|
|
|
|
|
|
def test_solver_solves_every_solved_fixture() -> None:
|
|
for fx in (f for f in _load_rate_gold() if f["expect"] == "solved"):
|
|
assert solve_rate(gold_to_problem(fx)) == fx["gold"], fx["id"]
|
|
|
|
|
|
def test_solver_refuses_every_solver_refuse_fixture_with_reason() -> None:
|
|
for fx in (f for f in _load_rate_gold() if f["expect"] == "solver_refuses"):
|
|
out = solve_rate(gold_to_problem(fx))
|
|
assert isinstance(out, Refusal) and out.reason == fx["solver_reason"], fx["id"]
|
|
|
|
|
|
def test_forward_product_is_always_integer() -> None:
|
|
assert solve_rate(RateProblem(RateUnit("mile", "hour"), 7, 9, None, "quantity")) == 63
|
|
|
|
|
|
def test_non_exact_inverse_refuses_never_rounds() -> None:
|
|
# 100 mile ÷ 3 hour = 33.3… → refuse (not 33).
|
|
out = solve_rate(RateProblem(RateUnit("mile", "hour"), None, 3, 100, "rate"))
|
|
assert isinstance(out, Refusal) and out.reason == "non_integer_solution"
|
|
# one less mile is exact → 99 ÷ 3 = 33.
|
|
assert solve_rate(RateProblem(RateUnit("mile", "hour"), None, 3, 99, "rate")) == 33
|
|
|
|
|
|
def test_answer_unit_by_query() -> None:
|
|
rp = lambda q, **kw: RateProblem(RateUnit("mile", "hour"), kw.get("rate"), kw.get("time"), kw.get("quantity"), q) # noqa: E731
|
|
assert answer_unit(rp("quantity", rate=60, time=3)) == "mile"
|
|
assert answer_unit(rp("time", rate=60, quantity=180)) == "hour"
|
|
assert answer_unit(rp("rate", time=3, quantity=180)) == RateUnit("mile", "hour")
|