Repository navigation
fix: reject a non-positive cross_validation period instead of looping forever - #2770
NishchayMahor wants to merge 1 commit into
Conversation
|
Since this and #2760 both land on I applied each branch separately and ran the same three inputs through
The two do not overlap because they catch the value at different points. @Jason10191019999's They also do not conflict. I cherry-picked this commit onto #2760's branch: it applied with no conflict, and That independence is why the guard here sits in Worth being clear about the difference in kind, not quality: #2760 improves a message for input that already fails loudly and immediately. This one is about input that fails silently and indefinitely, which is the harder case to work out from the outside — a stuck process, full CPU, and no traceback to go on. |
cross_validationnever returns ifperiodis zero or negative.No error, no warning, no progress. The process sits at 100% CPU and grows memory until it is killed.
Why
generate_cutoffswalks backwards through the data oneperiodat a time:With
period = 0the subtraction is a no-op, socutoffnever moves and the loop condition never changes.result.appendstill runs on every pass, so memory climbs for as long as it is left alone. A negativeperiodis worse: the cutoff walks away from the terminating condition.Measured on 200 daily rows,
horizon=30d,initial=60d,period=0:Nothing validates
period.cross_validationdoesperiod = 0.5 * horizon if period is None else pd.Timedelta(period)and passes it straight through.Only
periodhas this property. I checked the other two durations against the same data, and both terminate even when zero or negative, so this fix is limited toperiod:period = 0period < 0horizon = 0horizon < 0initial = 0initial < 0Fix
A guard in
generate_cutoffs, immediately before the loop it protects.I put it there rather than in
cross_validationfor two reasons.generate_cutoffsalready raises its ownValueErrorfor'Less data than horizon.', so enforcing its own precondition is consistent with how it already behaves, and it covers callers who import it directly. The other reason is #2760: that PR is rewriting the exact lines incross_validationwhere a parameter check would otherwise go, and there is no need for these two to collide.One thing worth knowing
perioddefaults to0.5 * horizon, so a zero or negativehorizonwith no explicitperiodnow raisesperiod must be positive.rather than hanging. The hang is gone, which is the point, but the message names a parameter the caller did not set. I left it alone rather than guess at how you would rather word it. Happy to change it.Testing
test_cross_validation_nonpositive_period_raises, parametrised over"0 days"and"-7 days", going throughcross_validationwith the existingmake_cross_validation_model()fake so it needs no fitted model.The before/after here is unusual: without the fix the test does not fail, it hangs, so
pytest-timeoutis what turns it into an observable failure.diagnostics.py:2 failed, bothFailed: Timeout (>20.0s) from pytest-timeout, 40s of wall clock.2 passed in 0.05s.test_diagnostics.py: 31 passed. The rest ofpython/prophet/tests: 124 passed, 2 skipped.Not verified:
test_plot.pycannot be collected in my environment because matplotlib is not installed, so it is excluded from that count. It fails to collect identically on a cleanmain, and this branch touches onlydiagnostics.pyand its test. I also ran ruff and mypy over the touched files against bothmainand this branch and get identical counts, so nothing new is introduced, though I could not find a linter configured in CI to check against.Not related: #2357 also reports a freeze, but @tcuongd diagnosed that one as cmdstanpy temp files during large searches, and it does not look like this.