feat(solve): 审查 markov_steady_state:工程侧收口 + 8 条测试
用户实现的 markov_steady_state 经探针实测算法本体正确(3 状态与特征分解逐位一致、 200x200 一致到 1.9e-12 且只用 6 次迭代 / 0.10s),本次只动工程侧,未改任何算法行: - ruff 5 条 W293 全清;mm1_metrics 前 4 个空行 -> 2;失败文案改成全角冒号 - docstring 补 max_iter / tol 两个参数与 Raises,写清 tol 是相邻差口径 (实测慢混合链 tol=1e-10 -> 实际误差 4.6e-9,被 1/(1-|lambda2|) 放大约 50 倍) - Notes 修正"周期链会不收敛"的说法:可约链的实情是平稳分布不唯一, 迭代法给的是离初值最近的那个(均匀初值对双随机矩阵本身就是不动点) - tests/test_solve.py:摘掉 1 条 skip + 新增 7 条(该函数共 8 条实跑) - STATUS.md 新增决策 57(6 条待拍板口径)与第六轮「下一步」;CHANGELOG;易错点 28 校验:pytest 196 passed / 30 skipped(226 收集);ruff 0;pyright 0
This commit is contained in:
1 parent
dd9bd638b8
commit
0955890010
5 files changed
+263
-27
No files matched your search
@@ -590,23 +590,42 @@ def markov_simulate(
|
||||
)
|
||||
|
||||
|
||||
def markov_steady_state(transition: Any, max_iter: int = 10000, tol: float = 1e-10) -> Any:
|
||||
"""平稳分布。
|
||||
def markov_steady_state(transition: Any, max_iter: int | np.integer = 10000, tol: float = 1e-10) -> Any:
|
||||
"""迭代法求马尔可夫链的平稳分布(`v @ P` 反复推进,直到相邻两次几乎不变)。
|
||||
|
||||
Parameters
|
||||
----------
|
||||
transition:
|
||||
行随机矩阵(每行和为 1)。
|
||||
行随机矩阵(每行和为 1)的二维方阵。
|
||||
max_iter:
|
||||
迭代上限,正整数,默认 10000。
|
||||
tol:
|
||||
收敛阈值,正数,默认 1e-10。判据是**相邻两次迭代的最大分量差**
|
||||
`max|v_k+1 - v_k| < tol`,不是"到不动点的距离",见 Notes。
|
||||
|
||||
Returns
|
||||
-------
|
||||
`Result`:`data` 是平稳分布向量,`metrics={"converged", "iterations"}`。
|
||||
`Result`:`data` 是一维平稳分布向量(和为 1);
|
||||
`metrics={"converged", "iterations"}`(是否在 `max_iter` 内向容、实际迭代次数)。
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError:
|
||||
`transition` 不是二维方阵、或某一行和不等于 1.0;
|
||||
`max_iter` 不是正整数;`tol` 不是正数。
|
||||
|
||||
Notes
|
||||
-----
|
||||
用迭代法而不是特征分解:迭代法能顺便告诉你"收敛快不快",
|
||||
而收敛速度本身就是论文里值得写一句的性质。
|
||||
**不可约 + 非周期**才有唯一平稳分布,周期链会不收敛,要检查。
|
||||
初值是**均匀分布** `1/s`;**不可约 + 非周期**才有唯一平稳分布。
|
||||
可约链(如单位阵 `eye(2)`)的平稳分布不唯一,迭代法给出的是"离初值最近的那个"
|
||||
—— 均匀初值对双随机矩阵本身就是不动点,所以 `converged=True, iterations=1` 只说明"初值恰是不动点",
|
||||
不代表这条链有唯一平稳分布;周期链从一般初值出发会一直振荡、`converged=False`。
|
||||
|
||||
`tol` 是**相邻差**口径,实际误差约被 `1 / (1 - |λ2|)` 放大:实测双状态慢混合链
|
||||
`[[0.999, 0.001], [0.02, 0.98]]`(`|λ2| = 0.979`)用默认 `tol=1e-10` 停在第 867 次,
|
||||
与特征向量相差 `4.6e-9`(约 50 倍)。慢混合链要更准,把 `tol` 压小即可。
|
||||
|
||||
Examples
|
||||
--------
|
||||
@@ -616,8 +635,57 @@ def markov_steady_state(transition: Any, max_iter: int = 10000, tol: float = 1e-
|
||||
>>> bool(np.allclose(r.data, [2 / 3, 1 / 3], atol=1e-6))
|
||||
True
|
||||
"""
|
||||
# TODO(L1)
|
||||
raise NotImplementedError
|
||||
arr, _ = as_array(transition)
|
||||
if arr.ndim != 2 or arr.shape[0] != arr.shape[1]:
|
||||
raise ValueError(f"transition 必须是二维方阵,你传入的形状是 {arr.shape}")
|
||||
if not np.allclose(arr.sum(axis=1), 1.0):
|
||||
raise ValueError("transition 每一行的和必须是 1.0")
|
||||
|
||||
s = arr.shape[0]
|
||||
v = np.full(s, 1.0 / s)
|
||||
|
||||
iterations = 0
|
||||
converged = False
|
||||
|
||||
if isinstance(max_iter, bool) or not isinstance(max_iter, (int, np.integer)) or max_iter <= 0:
|
||||
raise ValueError(f"max_iter 必须是正整数,你传入了 {max_iter}")
|
||||
if not isinstance(tol, (int, float)) or tol <= 0:
|
||||
raise ValueError(f"tol 必须是正数,你传入了 {tol}")
|
||||
|
||||
try:
|
||||
for _ in range(max_iter):
|
||||
v_next = v @ arr
|
||||
error = np.max(np.abs(v_next - v))
|
||||
v = v_next
|
||||
iterations += 1
|
||||
|
||||
if error < tol:
|
||||
converged = True
|
||||
break
|
||||
|
||||
metrics = {
|
||||
"converged": converged,
|
||||
"iterations": iterations
|
||||
}
|
||||
|
||||
return Result(
|
||||
name="markov_steady_state",
|
||||
params={"max_iter": max_iter, "tol": tol},
|
||||
metrics=metrics,
|
||||
data=v,
|
||||
success=True,
|
||||
message=f"平稳分布求解{'成功' if converged else '未完全收敛'},迭代 {iterations} 次。"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return Result(
|
||||
name="markov_steady_state",
|
||||
params={"max_iter": max_iter, "tol": tol},
|
||||
metrics={},
|
||||
data=None,
|
||||
success=False,
|
||||
message=f"平稳分布求解失败:{type(e).__name__} - {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
def mm1_metrics(arrival_rate: float, service_rate: float) -> Any:
|
||||
|
||||
Reference in new issue
Block a user