diff --git a/src/doxa/opinion.py b/src/doxa/opinion.py index baa9471..d76bb15 100644 --- a/src/doxa/opinion.py +++ b/src/doxa/opinion.py @@ -26,6 +26,13 @@ _BASE_RATE_CLAMP = (0.01, 0.99) +def _require_finite(**coordinates: float) -> None: + """Reject coordinates outside the finite real numbers.""" + for name, value in coordinates.items(): + if not math.isfinite(value): + raise ValueError(f"{name}={value} must be finite") + + def _clamp_base_rate(a: float) -> float: """Clamp a fused base rate to ``_BASE_RATE_CLAMP``.""" lo, hi = _BASE_RATE_CLAMP @@ -47,6 +54,7 @@ class Opinion: allow_dogmatic: bool = False def __post_init__(self) -> None: + _require_finite(b=self.b, d=self.d, u=self.u, a=self.a) for name, val in [("b", self.b), ("d", self.d), ("u", self.u)]: if val < -_TOL or val > 1.0 + _TOL: raise ValueError(f"{name}={val} not in [0, 1]") @@ -575,6 +583,7 @@ class BetaEvidence: a: float def __post_init__(self) -> None: + _require_finite(r=self.r, s=self.s, a=self.a) if self.r < 0: raise ValueError(f"r={self.r} must be >= 0") if self.s < 0: diff --git a/tests/test_opinion.py b/tests/test_opinion.py index 16a4418..da16609 100644 --- a/tests/test_opinion.py +++ b/tests/test_opinion.py @@ -95,6 +95,32 @@ def test_a_valid(self): assert 0.0 < o.a < 1.0 +class TestFiniteCoordinates: + @pytest.mark.parametrize("value", [math.nan, math.inf, -math.inf]) + @pytest.mark.parametrize("coordinate", ["b", "d", "u", "a"]) + def test_opinion_rejects_non_finite_coordinate(self, coordinate, value): + coordinates = {"b": 0.0, "d": 0.0, "u": 1.0, "a": 0.5} + coordinates[coordinate] = value + + with pytest.raises( + ValueError, + match=rf"^{coordinate}=.* must be finite$", + ): + Opinion(**coordinates) + + @pytest.mark.parametrize("value", [math.nan, math.inf, -math.inf]) + @pytest.mark.parametrize("coordinate", ["r", "s", "a"]) + def test_beta_evidence_rejects_non_finite_coordinate(self, coordinate, value): + coordinates = {"r": 0.0, "s": 0.0, "a": 0.5} + coordinates[coordinate] = value + + with pytest.raises( + ValueError, + match=rf"^{coordinate}=.* must be finite$", + ): + BetaEvidence(**coordinates) + + # --- 3. E(ω) = b + a*u is in [0, 1] --- class TestExpectation: