Preserve observed progression steps in exercise forecasts

This commit is contained in:
Peter Stockings
2026-09-06 22:46:07 +10:00
parent dc0f41cd27
commit 9612d322eb
5 changed files with 58 additions and 8 deletions
+21
View File
@@ -47,6 +47,27 @@ class ForecastTests(unittest.TestCase):
f=forecast(rows([(50,8)]*16),52)
self.assertTrue(all(p['projected_weight']==50 and p['projected_repetitions']==8 for p in f['points']))
def test_mixed_observed_load_steps_are_preserved(self):
m = TransitionModel(rows([(100,7),(100.5,7),(101.5,7),(102,7),(104,7)]))
w, r, p = m.outcomes([104], [7], [0])
increases = set(np.round(w[(w > 104) & (p > 0)] - 104, 3))
self.assertEqual(increases, {0.5, 1.0, 2.0})
def test_ceiling_does_not_turn_rep_gains_into_stall_evidence(self):
m = TransitionModel(rows([(100,6),(100,7),(101,6),(101,7),(102,6),(102,7)]))
w, r, p = m.outcomes([102], [7], [0])
# At the ceiling only the explicit prior can repeat this set;
# the observed rep-building transitions contribute no probability.
self.assertAlmostEqual(float(p[(w == 102) & (r == 7)].sum()), float(p[0,0]))
self.assertTrue(np.any((w > 102) & (p > 0)))
w, r, p = m.outcomes([102], [6], [0])
self.assertTrue(np.any((w == 102) & (r == 7) & (p > 0)))
def test_large_load_jump_is_not_reused_as_routine_progression(self):
m = TransitionModel(rows([(50,7),(50.5,7),(51,7),(100,7)]))
w, r, p = m.outcomes([100], [7], [0])
self.assertEqual(set(w[(w > 100) & (p > 0)]), {100.5})
def test_months_off_excludes_old_performance(self):
older=rows([(150,10)]*12,start=date(2024,1,1))
fresh=rows([(50,6),(50,7),(50,7),(50,8)], start=date(2026,1,1))