From 5ab913d0b44b8555b1dd2034b20f4d76c9400113 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 20:30:06 +0000 Subject: [PATCH] A fixed duration is fixed whatever numpy's rounding; an always-up mission to rounding The suite at every dependency's floor (numpy 2.0.0, new this cycle: the job tested only the oldest surpyval before) failed four tests on the release pull request (#353). Three refused a component maintained for an exactly known time: the duration is told fixed from its variance, a difference of two numbers about its square, against a tolerance of a billionth of it squared, a few units of rounding wide, and numpy 2.0 sums the moments to a variance of 1e-15 at a duration of 5. The tolerance is a millionth of the duration, which rounding cannot cross and no spread duration meets. The fourth asserted that an always-up unit's mission availability is exactly 1.0, where the integral of a constant sums the quadrature's weights: to rounding now. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_016Ng6hwUY8zznhm1jRfZJqZ --- CHANGELOG.md | 9 +++++++++ repyability/rbd/_point_availability.py | 5 ++++- repyability/tests/test_point_availability.py | 4 +++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea8cc3..39e74b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -526,6 +526,15 @@ and `rbd._sensitivity`'s `levers` and `Lever` are gone (use `levers()`, ### Fixed +- **A fixed maintenance duration is fixed whatever numpy's rounding.** A + duration known exactly (an `ExactEventTime`) is followed as a fixed + time, where a spread one is convolved; it was told from its variance, + a difference of two numbers about the duration squared, against a + tolerance a few units of rounding wide: on numpy 2.0 the variance came + out at 1e-15, and the exact and numerical analyses of a component + maintained for a fixed time refused ("its later age replacements ... + are too many ... to follow exactly"). The tolerance is a millionth of + the duration. - **A shut at an offset off the grid keeps its period (#319).** The grid's step for `NonRepairable.optimal_calendar_policy` was sized to put every period, offset and date on it, and fell back to the diff --git a/repyability/rbd/_point_availability.py b/repyability/rbd/_point_availability.py index 37223be..dd94b58 100644 --- a/repyability/rbd/_point_availability.py +++ b/repyability/rbd/_point_availability.py @@ -831,7 +831,10 @@ def __init__( mean, variance = _moments( sf, np.linspace(0.0, self.top, 4097), self.splits ) - if variance <= (1e-9 * self.top) ** 2: + # A fixed time, to rounding: the variance is a difference of two + # 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 return from scipy.signal import fftconvolve diff --git a/repyability/tests/test_point_availability.py b/repyability/tests/test_point_availability.py index 195e7cb..87353fb 100644 --- a/repyability/tests/test_point_availability.py +++ b/repyability/tests/test_point_availability.py @@ -491,7 +491,9 @@ def test_matches_the_simulation(name): def test_instant_repair_is_always_up(): rbd = alone(unit(W([100.0, 2.0]), "instant")) assert rbd.point_availability([0.0, 10.0, 1e4]).tolist() == [1, 1, 1] - assert rbd.mission_availability(100.0) == 1.0 + # To rounding: the integral of a constant 1 sums the quadrature's + # weights, exact to a few units of rounding in some numpy versions. + assert rbd.mission_availability(100.0) == pytest.approx(1.0, abs=1e-15) def test_units_dead_on_arrival_and_units_that_never_fail():