From 849c5e8b730fd6c8b9812097a6d9b3f26069eb05 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 20:46:00 +0000 Subject: [PATCH] A fixed duration is its atom's time; integrated costs compared to rounding With the fixed-duration tolerance rounding cannot cross (#358), a time known exactly is told fixed on every numpy, but was given its mean, which numpy 2.0 sums to 1.9999999999999996 for 2: it is now the time of its one atom. The planned-outage test that compares a run's costs, the exact means integrated by quadrature, with whole numbers compares them to rounding: at the floors the integrals come out at 19.999999999999996 and 20.000000000000057 for 20. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_016Ng6hwUY8zznhm1jRfZJqZ --- repyability/rbd/_point_availability.py | 4 +++- .../tests/test_preventive_maintenance.py | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/repyability/rbd/_point_availability.py b/repyability/rbd/_point_availability.py index dd94b58..5ce57a7 100644 --- a/repyability/rbd/_point_availability.py +++ b/repyability/rbd/_point_availability.py @@ -835,7 +835,9 @@ def __init__( # numbers about ``top ** 2``, so it is uncertain by a few units of # rounding in them (numpy 2.0 sums them to 1e-15 at a top of 5). if variance <= (1e-6 * self.top) ** 2: - self.fixed = mean + # A time known exactly is its atom's, not the mean's rounding. + atoms = _atoms(lambda s: 1.0 - sf(s), self.splits, self.top) + self.fixed = atoms[0][0] if len(atoms) == 1 else mean return from scipy.signal import fftconvolve diff --git a/repyability/tests/test_preventive_maintenance.py b/repyability/tests/test_preventive_maintenance.py index e4c2e2f..7b4a229 100644 --- a/repyability/tests/test_preventive_maintenance.py +++ b/repyability/tests/test_preventive_maintenance.py @@ -138,16 +138,19 @@ def test_maintenance_that_takes_time_is_a_planned_outage(): assert per_run(result, result.system_restorations) == 9 assert result.system_failures == 0 assert result.mean_up_time == 40.0 - assert result.cost.by_category == { - "repair": 0.0, - "replace": 0.0, - "preventive": 50.0, - "inspection": 0.0, - "component_downtime": 60.0, - "system_downtime": 140.0, - "setup": 0.0, - } - assert result.cost.by_component == {"c": 110.0} + # The costs are the exact means, integrated: to rounding. + assert result.cost.by_category == pytest.approx( + { + "repair": 0.0, + "replace": 0.0, + "preventive": 50.0, + "inspection": 0.0, + "component_downtime": 60.0, + "system_downtime": 140.0, + "setup": 0.0, + } + ) + assert result.cost.by_component == pytest.approx({"c": 110.0}) fci = result.criticalities.failure_criticality_index # Planned outages are not failures. assert fci.per_system_failure.get("c", 0) == 0