feat(solve): random_walk 落地;修默认采样器真 bug(integers 不收 float)

random_walk 由用户本人写;Codex 改一处真 bug + 工程侧。

- 真 bug:默认采样器 rng.integers(0, 2, size=size, dtype=float) 被 numpy 拒掉
  (Unsupported dtype dtype(float64) for integers),默认路径 100% success=False、
  data=None,连 docstring 的 Examples 都跑不通。改成 integers(size=size) * 2 - 1,
  由后面的 np.asarray(..., dtype=float) 转 float;实测 (5,101)、步长恒 ±1、同种子可复现
- 工程:ruff W293 x2;docstring 补全(n_steps/n_paths/start/random_state + Returns /
  Raises / Notes,写清 step_sampler 收二维 size=(n_paths, n_steps))
- tests:random_walk 首次有测试,新增 6 条(形状 + start、步长恒 ±1、可复现、自定义
  高斯采样器、3 类非法入参、docstring Example)
- monte_carlo_integral:用户第二轮已收 ndarray + 把三行提出 if/else(决策 52)
- 验证:205 收集 / 174 passed / 31 skipped / 0 xfail,ruff 0,pyright 0
- docs:STATUS 决策 53 + random_walk 4 条待办;CHANGELOG;易错点 24/25,第 18 条复发 +1
This commit is contained in:
guzhujushi committed 2026-10-05 17:04:52 +08:00
1 parent dcda080be4
commit 8ec08ea9ce
5 files changed
+254 -32

No files matched your search

+80 -14
View File
@@ -286,10 +286,13 @@ def monte_carlo_integral(
>>> abs(r.metrics["mean"] - 1 / 3) < 0.01 # ∫₀¹ x² dx = 1/3
True
"""
if not isinstance(bounds, (list, tuple)) or len(bounds) == 0:
raise ValueError("bounds 必须是非空的列表或元组")
if not isinstance(bounds, np.ndarray):
if not isinstance(bounds, (list, tuple)) or len(bounds) == 0:
raise ValueError("bounds 必须是非空的列表或元组")
bounds_arr = np.asarray(bounds)
bounds_arr = np.asarray(bounds)
else:
bounds_arr = bounds.copy()
if bounds_arr.ndim != 2 or bounds_arr.shape[1] != 2:
raise ValueError(f"bounds 必须形如 [(lo, hi), ...],当前形状为 {bounds_arr.shape},请检查是否漏了括号")
@@ -320,15 +323,12 @@ def monte_carlo_integral(
random_state=random_state,
)
result.name = "monte_carlo_integral"
result.params["bounds"] = bounds
result.params["dimension"] = d
if result.success:
result.name = "monte_carlo_integral"
result.params["bounds"] = bounds
result.params["dimension"] = d
result.message = f"蒙特卡洛多重积分成功:维度 {d},体积 {volume:.4f},模拟 {n} 次。"
else:
result.name = "monte_carlo_integral"
result.params["bounds"] = bounds
result.params["dimension"] = d
result.message = f"蒙特卡洛多重积分失败:维度 {d},体积 {volume:.4f},模拟 {n} 次。{result.message}"
return result
@@ -341,25 +341,91 @@ def random_walk(
start: float = 0.0,
random_state: int | None = None,
) -> Any:
"""随机游走轨迹。
"""随机游走轨迹:一次抽完整批增量,再 `cumsum` 成路径。
Parameters
----------
n_steps:
每条路径的步数,正整数。`data` 的列数是 `n_steps + 1`(多出的那一列是起点)。
n_paths:
路径条数,正整数,默认 1 条。
step_sampler:
`f(rng, size) -> 增量`,默认为 ±1 等概率(对称随机游走)。
`f(rng, size) -> 一批增量`。批量大小由本函数以 `size=(n_paths, n_steps)` 传入,
必须返回形状 `(n_paths, n_steps)` 的数组(契约同 `monte_carlo` 的 `sampler`,只是这里是二维)。
默认 ±1 等概率(对称随机游走)。
start:
起点,写进每条路径的第 0 列。
random_state:
随机种子。`None` 时跟随 `core.set_seed` 的全局流,见 `core.random.get_rng`。
Returns
-------
`Result`:`data` 形状 `(n_paths, n_steps + 1)`。
`Result`:`data` 形状 `(n_paths, n_steps + 1)`,第 0 列恒为 `start`,之后是逐列累加出来的位置;
`metrics={"n_steps", "n_paths"}`。
Raises
------
ValueError:
`n_steps` / `n_paths` 不是正整数。
TypeError:
`start` 不是数值。
Notes
-----
随机游走是"平方根扩散"的原型:位置的标准差随步数按 `√t` 增长,所以典型图形是 `±√t` 的喇叭口。
本函数只负责 `cumsum`;**建模差异全在 `step_sampler` 里** —— 换成 `rng.normal(0, 1, size)` 就是高斯游走,
换成带正漂移的增量就是有趋势的游走。
Examples
--------
>>> import numpy as np
>>> r = random_walk(n_steps=100, n_paths=5, random_state=0)
>>> r.data.shape
(5, 101)
>>> bool(np.all(np.abs(np.diff(r.data, axis=1)) == 1)) # 默认步长恒为 1
True
"""
# TODO(L1)
raise NotImplementedError
if isinstance(n_steps, bool) or not isinstance(n_steps, (int, np.integer)) or n_steps <= 0:
raise ValueError(f"n_steps 必须是正整数,你传入了 {n_steps}")
if isinstance(n_paths, bool) or not isinstance(n_paths, (int, np.integer)) or n_paths <= 0:
raise ValueError(f"n_paths 必须是正整数,你传入了 {n_paths}")
if not isinstance(start, (int, float, np.number)):
raise TypeError(f"start 必须是数值,你传入了 {type(start).__name__}")
rng = get_rng(random_state)
if step_sampler is None:
def _default_step_sampler(rng, size):
return rng.integers(0, 2, size=size) * 2 - 1
step_sampler = _default_step_sampler
try:
steps = np.asarray(step_sampler(rng, size=(n_paths, n_steps)), dtype=float)
cumsum = np.cumsum(steps, axis=1)
paths = np.zeros((n_paths, n_steps + 1), dtype=float)
paths[:, 0] = start
paths[:, 1:] = start + cumsum
return Result(
name="random_walk",
params={"n_steps": n_steps, "n_paths": n_paths, "start": start},
metrics={"n_steps": n_steps, "n_paths": n_paths},
data=paths,
success=True,
message=f"随机游走模拟成功:生成了 {n_paths} 条路径,每条路径 {n_steps} 步。"
)
except Exception as e:
return Result(
name="random_walk",
params={"n_steps": n_steps, "n_paths": n_paths, "start": start},
metrics={},
data=None,
success=False,
message=f"随机游走模拟失败:{type(e).__name__} - {str(e)}"
)
def markov_simulate(