feat(solve): random_walk 的 step_sampler 契约改成"整数 size + 一维返回"(方案 B)
用户拍板方案 B(决策 55),Codex 代改。 - size 由 (n_paths, n_steps) 改成整数 n_paths * n_steps,必须返回一维; 内部 reshape(n_paths, n_steps)(行主序);二维返回一律判失败 - 动因:方阵时转置 (n_steps, n_paths) 与目标形状相同,形状校验天生分不出来(易错点 25) - 关键:不用 .ravel() 救场(会把转置摊平,歧义原样回来) - 红利:与 monte_carlo 的 sampler 契约(决策 48 的 size=n)统一,采样器可直接复用(实测) - docstring:step_sampler 契约与 Notes 同步(一维 / 行主序 / 二维必失败) - tests:转置那条改成 rejects_2d_step_sampler(含方阵),新增"整数 size + 行主序"契约测试;solve 段 43 条 - 验证:210 收集 / 179 passed / 31 skipped / 0 xfail,ruff 0,pyright 0 - docs:STATUS 决策 55 + random_walk 待办全部办结;CHANGELOG
This commit is contained in:
1 parent
cd6f613568
commit
9368dd91cb
4 files changed
+73
-38
No files matched your search
+25
-7
@@ -335,19 +335,37 @@ def test_random_walk_rejects_bad_arguments():
|
||||
random_walk(n_steps=10, start="a") # type: ignore[arg-type] # 就是要传错
|
||||
|
||||
|
||||
def test_random_walk_failure_returns_result_not_exception():
|
||||
"""失败也要返回带 params 的 Result,不能把异常抛给调用方 —— 包装层引用未赋值变量那次就靠它拦住。"""
|
||||
def test_random_walk_rejects_2d_step_sampler():
|
||||
"""`step_sampler` 必须返回**一维** —— 二维返回(含方阵)一律判失败(易错点 25 的根治)。"""
|
||||
from mcm_toolkit.solve import random_walk
|
||||
|
||||
def transposed(rng, size):
|
||||
return rng.normal(0, 1, (size[1], size[0]))
|
||||
return rng.normal(0, 1, (4, 3)) # 无论要多少,一律给二维
|
||||
|
||||
r = random_walk(n_steps=4, n_paths=6, step_sampler=transposed, random_state=0)
|
||||
assert r.success is False
|
||||
assert "形状" in r.message
|
||||
assert r.params["n_paths"] == 6 # 失败也要留下追溯信息
|
||||
r = random_walk(n_steps=4, n_paths=3, step_sampler=transposed, random_state=0)
|
||||
assert r.success is False # 失败也要返回 Result,不能抛给调用方
|
||||
assert "长度" in r.message
|
||||
assert r.params["n_paths"] == 3 # 失败也要留下追溯信息
|
||||
assert r.data is None
|
||||
|
||||
# 旧方案在 n_paths == n_steps 时对"转置"完全无感;现在同样拦住
|
||||
assert random_walk(n_steps=3, n_paths=3, step_sampler=transposed, random_state=0).success is False
|
||||
|
||||
|
||||
def test_random_walk_step_sampler_gets_flat_size_and_is_row_major():
|
||||
"""契约:`size` 是整数 `n_paths * n_steps`,一维增量按**行主序**切成 n_paths 行。"""
|
||||
from mcm_toolkit.solve import random_walk
|
||||
|
||||
seen = {}
|
||||
|
||||
def sampler(rng, size):
|
||||
seen["size"] = size
|
||||
return np.arange(1, size + 1, dtype=float) # 1, 2, 3, 4, 5, 6
|
||||
|
||||
r = random_walk(n_steps=3, n_paths=2, step_sampler=sampler, random_state=0)
|
||||
assert seen["size"] == 6 # 整数,不是 (n_paths, n_steps)
|
||||
assert r.data.tolist() == [[0, 1, 3, 6], [0, 4, 9, 15]] # cumsum(1,2,3) / cumsum(4,5,6)
|
||||
|
||||
|
||||
def test_random_walk_rejects_nan_steps():
|
||||
"""增量含 NaN 判失败 —— 与 monte_carlo 的 NaN 口径(决策 48)一致。"""
|
||||
|
||||
Reference in new issue
Block a user