fix(solve): monte_carlo_integral 入口收口 + 失败 message 不再被覆盖

三项待办由用户本人改定;Codex 只补 ruff / docstring / tests / 文档。

- bounds 形状校验:`[0, 1]` 从裸 IndexError 变成可读 ValueError(带形状提示);
  空 / 非 list-tuple / 参差不齐一并收口
- 失败 message:改成 if result.success / else 两支,success=False 时不再出现"成功"文案
- n 注解放宽为 int | np.integer;event 注解 Callable[..., bool] -> Callable[..., Any]
  (决策 50 的遗留清零;pyright 复测不再拒绝向量化事件函数)
- 工程侧:清掉 2 行 ruff W293;docstring 的 bounds / Raises 同步;
  非法 bounds 测试 1 类扩到 4 类,新增失败 message 语义与 np.int64 两条
- 验证:199 收集 / 168 passed / 31 skipped / 0 xfail,ruff 0,pyright 0
- docs:决策 52 + 2 条新口径(bounds 收不收 ndarray、if/else 三行重复);CHANGELOG
This commit is contained in:
guzhujushi committed 2026-10-05 16:04:39 +08:00
1 parent ed1f9f0c53
commit dcda080be4
4 files changed
+99 -35

No files matched your search

+21 -8
View File
@@ -132,7 +132,7 @@ def monte_carlo(
def monte_carlo_probability(
event: Callable[..., bool],
event: Callable[..., Any],
sampler: Callable[..., Any],
n: int | np.integer = 10000,
confidence: float = 0.95,
@@ -246,7 +246,7 @@ def monte_carlo_probability(
def monte_carlo_integral(
func: Callable[..., Any],
bounds: Any,
n: int = 10000,
n: int | np.integer = 10000,
random_state: int | None = None,
) -> Any:
"""用蒙特卡洛求多重积分。
@@ -257,7 +257,7 @@ def monte_carlo_integral(
`f(X) -> 一批函数值`。`X` 是形状 `(n, d)` 的样本矩阵(一行一个样本),
返回长度 `n` 的数组(写成 `X[:, 0] ** 2` 这种逐行写法,不要写 Python 循环)。
bounds:
`[(lo, hi), ...]`,维度即积分重数,要求每个 `lo < hi`。
`[(lo, hi), ...]`(非空 list / tuple),维度即积分重数;要求每项都是二元组且 `lo < hi`。
n:
模拟次数,正整数。
random_state:
@@ -272,7 +272,7 @@ def monte_carlo_integral(
Raises
------
ValueError:
`bounds` 里出现 `lo >= hi`。
`bounds` 不是非空 list / tuple、形状不是 `(d, 2)`(例如漏括号写成 `[0, 1]`),或某个 `lo >= hi`。
Notes
-----
@@ -286,8 +286,14 @@ 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 必须是非空的列表或元组")
bounds_arr = np.asarray(bounds)
if bounds_arr.ndim != 2 or bounds_arr.shape[1] != 2:
raise ValueError(f"bounds 必须形如 [(lo, hi), ...],当前形状为 {bounds_arr.shape},请检查是否漏了括号")
lows = bounds_arr[:, 0]
highs = bounds_arr[:, 1]
d = len(lows)
@@ -313,10 +319,17 @@ def monte_carlo_integral(
n=n,
random_state=random_state,
)
result.name = "monte_carlo_integral"
result.params["bounds"] = bounds
result.params["dimension"] = d
result.message = f"蒙特卡洛多重积分成功:维度 {d},体积 {volume:.4f},模拟 {n} 次。"
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