FIX: Handle LQMarkov beta limits based on shocks - #831
Conversation
|
Hello maintainers, I noticed the CI pipeline failed on the Looking closely at the logs, the failure is entirely isolated to Just leaving a note here for visibility. Looking forward to your review on the core changes! |
|
@HG-Cheng Thank you for the contribution! Do you know what is known to happen when beta > 1? (The current code does not prohibit |
|
@oyamad "Thanks for the review! |
|
@HG-Cheng Next question is: what is known to happen when beta = 1? For the instance in #508 (comment), it does not converge even with |
|
Hi @oyamad,Thanks for running that test! That actually makes perfect sense mathematically.If |
|
Hi @HG-Cheng — thanks so much for digging into this, and for the great back-and-forth with @oyamad in the thread! 🙌 The improved, context-aware message in There's one thing I think we should sort out before this is ready, though: the new construction-time guard is a bit too broad and would break valid uses of the plain The change adds this to both if beta >= 1.0:
raise ValueError("Discount factor beta cannot be greater than 1.")For
if (self.C != 0).any() and beta >= 1:
raise ValueError('beta must be strictly smaller than 1 if ' +
'T = None and C != 0.')So the new guard would make even The "β=1 diverges" reasoning holds specifically for the A possible path forward:
Two tiny nits in Thanks again for the contribution — this is close, and the diagnostic message is a real improvement! Let me know if anything's unclear. 😊 |
|
Thanks for the detailed feedback, @mmcky! I've updated the PR accordingly:
I also merged the latest upstream Thanks again! |
|
Thanks @HG-Cheng for the continued work on this, and @oyamad for the analysis in #508 (comment). Having gone through both carefully, I think this needs one more round of changes: the PR improves the error message, but it doesn't yet implement the fix Daisuke identified, so the underlying problem in #508 would remain (it was reopened for this reason). The key economic insightWhether Case 1 — with shocks (some Case 2 — no shocks (all Why the PR as it stands isn't enough — verified empiricallyI ran the relevant cases against the code in this PR (it doesn't touch
Requested changes
Thanks again for the effort here — the diagnostics improvement is welcome, and with the conditional guard and the |
|
Thanks for the detailed analysis, @mmcky and @oyamad! I've now implemented the requested root-cause fix:
I also synced with the latest upstream Could you please take another look when convenient? Thanks! |
oyamad
left a comment
There was a problem hiding this comment.
@HG-Cheng Thanks, this is a right implementation of #508 (comment).
A few more small requests. And also:
- Maybe add something like "Must be strictly smaller than 1 if any of the
Csis nonzero." to thebetaentry in theLQMarkovdocstring.
| # == Set up for iteration on Riccati equations system == # | ||
| error = tolerance + 1 | ||
| fail_msg = "Convergence failed after {} iterations." | ||
| if beta == 1.0: |
There was a problem hiding this comment.
| if beta == 1.0: | |
| if beta >= 1.0: |
| fail_msg = "Convergence failed after {} iterations." | ||
| if beta == 1.0: | ||
| fail_msg = ( | ||
| "Convergence failed after {} iterations. When beta=1, a " |
There was a problem hiding this comment.
| "Convergence failed after {} iterations. When beta=1, a " | |
| "Convergence failed after {} iterations. When beta>=1, a " |
(Also adjust the test accordingly.)
| m = Qs.shape[0] | ||
| k, n = Qs.shape[1], Rs.shape[1] | ||
| # Create the Ps matrices, initialize as identity matrix | ||
|
|
There was a problem hiding this comment.
Remove the blank line:
References
Fixes #508
Description
This PR fixes the handling of
LQMarkovmodels withbeta >= 1bydistinguishing between models with and without shocks.
Changes
beta >= 1at construction when any shock matrixC(s)isnonzero, since the recurring noise costs make the infinite-horizon
problem ill-posed.
beta >= 1; whether astationary solution exists in that case depends on stabilizability.
ds = np.zeros(m)directly when all shock matrices are zero,avoiding the singular linear solve for the constant term.
beta == 1Riccati-system failure message to explain thata stationary solution may not exist when the system cannot be
stabilized without discounting.
max_iterfor thebeta == 1case.beta = 1use cases in the plainLQclass.Tests
Regression tests cover:
LQMarkov(beta=1)for both one-state and two-state chains,including
ds == 0;beta >= 1when at least one shockmatrix is nonzero;
LQMarkovwithbeta > 1;beta == 1non-convergence message;LQconstruction with its defaultbeta=1.No changes are made to the Riccati iteration algorithm itself.
Validation
test_lqcontrol.py: 15 passedtest_matrix_eqn.py: 4 passedtest_lqnash.py: 2 passedgit diff --checkpassed