docs(status): 记入分工硬规矩(决策 47)+「明天从这里开始」;test_solve 改逐条 skip
- STATUS.md:新增决策 47 —— 算法一律由用户本人写(即便用户改口也不代写),
工程事务(入口/校验、tests/、lint、docstring、卡片、STATUS/CHANGELOG)由 Codex 写;
L0 计数 9/12 -> 10/12;skip 说明 37 -> 34 条。
- STATUS.md:新增「⭐ 明天从这里开始」区块 —— 第一个要写的文件是
src/mcm_toolkit/solve/simulate.py 的 monte_carlo(L0 11/12,S 档),
含参考契约、向量化要求、get_rng 口径、三条测试建议、卡片路径与一个待拍板口径。
- tests/test_solve.py:模块级 pytestmark 拆成 9 条逐条 skip(决策 26、易错点 9)。
- CHANGELOG.md:同步记录。
校验:pytest 177 收集 / 143 passed / 34 skipped / 0 xfail;ruff 0;pyright 0。
This commit is contained in:
1 parent
a1cc26e042
commit
58f2236703
3 files changed
+89
-20
No files matched your search
@@ -329,6 +329,15 @@
|
|||||||
`else` 分支是死代码」;索引补到 17。
|
`else` 分支是死代码」;索引补到 17。
|
||||||
- `STATUS.md`:E 节记 `bootstrap_ci`(L0 10/12),决策 46,「下一步」改写并新增第 8 条列 5 个待拍板口径。
|
- `STATUS.md`:E 节记 `bootstrap_ci`(L0 10/12),决策 46,「下一步」改写并新增第 8 条列 5 个待拍板口径。
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- `tests/test_solve.py`:模块级 `pytestmark = pytest.mark.skip(...)` 拆成 **9 条逐条**
|
||||||
|
`@pytest.mark.skip(reason=_NOT_IMPLEMENTED)` —— 模块级 skip 会把整个文件吞掉(决策 26、易错点 9)。
|
||||||
|
用例数与跳过数不变(177 收集 / 143 passed / 34 skipped),仅粒度变细。
|
||||||
|
- `STATUS.md`:新增**分工硬规矩(决策 47)** —— 算法一律由用户本人写(即便用户改口也不代写)、
|
||||||
|
工程事务由 Codex 写;L0 计数 9/12 → **10/12**;「下一步」新增「⭐ 明天从这里开始」区块
|
||||||
|
(`monte_carlo` 的契约 / 向量化要求 / 三条测试建议 / 卡片路径 / 一个待拍板口径);
|
||||||
|
验证结果里的 skip 说明由 37 条订正为 **34 条**。
|
||||||
|
|
||||||
## [0.0.1] - 2026-10-01
|
## [0.0.1] - 2026-10-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -8,9 +8,20 @@
|
|||||||
配置 conda 与 venv 环境 → 初始化 git 仓库 → 接入 Gitea 远端。
|
配置 conda 与 venv 环境 → 初始化 git 仓库 → 接入 Gitea 远端。
|
||||||
两套环境均已建成并通过验证,仓库已推送到 `code.guzhujushi.cn`。
|
两套环境均已建成并通过验证,仓库已推送到 `code.guzhujushi.cn`。
|
||||||
|
|
||||||
**第二阶段(进行中)**:按 `docs/03-roadmap.md` 的 L0 → L1 顺序**逐个实现函数**,
|
**第二阶段(进行中)**:按 `docs/03-roadmap.md` 的 L0 → L1 顺序**逐个实现函数**。
|
||||||
用户本人写 `src/`、Codex 负责审查 + `tests/`(决策 25)。
|
|
||||||
当前 **L0 9/12**:`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`、`clean_missing`、`detect_outliers`、`normalize`/`standardize`、`describe`、`correlation_matrix`;另**提前落地**了 L1 的 `confidence_interval` / `t_test`。
|
**分工硬规矩(决策 47,用户 2026-10-03 明确)**:
|
||||||
|
- **算法一律由用户本人写**(S 档尤其)—— 即便用户说"你写吧"也不代写,
|
||||||
|
要保住"一边学一边自己写"的路径。
|
||||||
|
- **工程事务由 Codex 写、用户读**:入口/校验重构、`tests/`、docstring、ruff、
|
||||||
|
`STATUS.md` / `CHANGELOG.md`、函数卡片、`.gitignore` 等。
|
||||||
|
- A 档**薄封装**(`rmse`/`mae`/`fit_linear`/`train_test_split`…)算工程,Codex 可直接实现。
|
||||||
|
- 分地盘按**文件**划,不按函数划(同一文件两人各写一半曾导致用户编辑器保存失败)。
|
||||||
|
|
||||||
|
当前 **L0 10/12**:`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`、`clean_missing`、
|
||||||
|
`detect_outliers`、`normalize`/`standardize`、`describe`、`correlation_matrix`、`bootstrap_ci`;
|
||||||
|
另**提前落地**了 L1 的 `confidence_interval` / `t_test`。剩余 2 项:`monte_carlo`(用户写)、
|
||||||
|
`save_figure`(Codex 写)。
|
||||||
|
|
||||||
## 任务清单
|
## 任务清单
|
||||||
|
|
||||||
@@ -62,7 +73,7 @@
|
|||||||
- [x] 推送通道:公网 22 被防火墙过滤 → 改用 Tailscale(`100.115.86.48:22`),
|
- [x] 推送通道:公网 22 被防火墙过滤 → 改用 Tailscale(`100.115.86.48:22`),
|
||||||
`~/.ssh/config` 加了一条域名别名,remote 里仍写域名
|
`~/.ssh/config` 加了一条域名别名,remote 里仍写域名
|
||||||
|
|
||||||
**E. L0 实现进度(9/12)**
|
**E. L0 实现进度(10/12)**
|
||||||
- [x] `core/result.py` 的 `Result`
|
- [x] `core/result.py` 的 `Result`
|
||||||
- `__repr__`:单行紧凑;`data` 只给类型与规模,**绝不**整数组打印
|
- `__repr__`:单行紧凑;`data` 只给类型与规模,**绝不**整数组打印
|
||||||
(十万级数组的 repr 实测仍 < 200 字符);`success` 恒在
|
(十万级数组的 repr 实测仍 < 200 字符);`success` 恒在
|
||||||
@@ -220,7 +231,10 @@
|
|||||||
- **S 档函数卡片已写**:`docs/algorithms/bootstrap_ci.md`(第 2 张),
|
- **S 档函数卡片已写**:`docs/algorithms/bootstrap_ci.md`(第 2 张),
|
||||||
记了"极差统计量的区间上界必然塌到 `estimate`"这个非平凡性质,以及 5 个待拍板口径
|
记了"极差统计量的区间上界必然塌到 `estimate`"这个非平凡性质,以及 5 个待拍板口径
|
||||||
- 测试:`tests/test_stats.py` 的 bootstrap 段共 **9 条**
|
- 测试:`tests/test_stats.py` 的 bootstrap 段共 **9 条**
|
||||||
- [ ] 剩余 2 项:`monte_carlo` `save_figure`
|
- [x] **工程收尾(本轮)**:`tests/test_solve.py` 的模块级 `pytestmark = pytest.mark.skip(...)`
|
||||||
|
拆成 **9 条逐条** `@pytest.mark.skip(reason=_NOT_IMPLEMENTED)` —— 模块级 skip 会把整个文件吞掉,
|
||||||
|
正是易错点 9 的根源(决策 26)。收集数不变(177)、跳过数不变(34),只是粒度变细。
|
||||||
|
- [ ] 剩余 2 项:`monte_carlo`(**用户写**)、`save_figure`(Codex 写)
|
||||||
|
|
||||||
### 验证结果
|
### 验证结果
|
||||||
|
|
||||||
@@ -242,7 +256,8 @@
|
|||||||
- **`xfail` 再次清零**:`correlation_matrix` 的契约冲突已按方案 A 解决(决策 41),那条用例转正
|
- **`xfail` 再次清零**:`correlation_matrix` 的契约冲突已按方案 A 解决(决策 41),那条用例转正
|
||||||
- 上一轮那 7 条 xfail 已全部转正,决策 30 那套信号(XPASS → 摘 mark)跑完过一个完整闭环
|
- 上一轮那 7 条 xfail 已全部转正,决策 30 那套信号(XPASS → 摘 mark)跑完过一个完整闭环
|
||||||
- `examples/01_clean_and_describe.py` 实测跑通(exit 0);`00_quickstart.py` 仍等 `stats` / `viz`
|
- `examples/01_clean_and_describe.py` 实测跑通(exit 0);`00_quickstart.py` 仍等 `stats` / `viz`
|
||||||
- 37 条 skip 是等实现的算法(`train_test_split`、`bootstrap_ci`、`monte_carlo`、`anova`、`fit_distribution` 等);
|
- 34 条 skip 是等实现的算法(`train_test_split`、`monte_carlo`、`anova`、`fit_distribution` 等);
|
||||||
|
`bootstrap_ci` 已落地摘掉 3 条 skip(本轮新增 6 条用例,净 +3);`test_solve.py` 9 条按决策 26 改为逐条 skip;
|
||||||
`TestValidate` 的 4 条仍挂着 —— `check_*` 还是 `NotImplementedError`,但它们实现时应当直接复用 `as_array`
|
`TestValidate` 的 4 条仍挂着 —— `check_*` 还是 `NotImplementedError`,但它们实现时应当直接复用 `as_array`
|
||||||
- **本轮回归(已修)**:`transform.py` 上一版有 3 处真 bug —— 修前 **7 failed / 75 passed**,
|
- **本轮回归(已修)**:`transform.py` 上一版有 3 处真 bug —— 修前 **7 failed / 75 passed**,
|
||||||
且 pyright 在同一处报 `reportArgumentType`。**不是静态误报**:pyright CLI 复现 + 测试真红。
|
且 pyright 在同一处报 `reportArgumentType`。**不是静态误报**:pyright CLI 复现 + 测试真红。
|
||||||
@@ -256,9 +271,10 @@
|
|||||||
只差 Python 补丁号(3.13.9 vs 3.13.15)。详见 `docs/04-environment.md` §5。
|
只差 Python 补丁号(3.13.9 vs 3.13.15)。详见 `docs/04-environment.md` §5。
|
||||||
- [x] ~~Gitea 远程尚未配置~~ → **已配置并推送完成**,见上面 D 节与决策 19/20。
|
- [x] ~~Gitea 远程尚未配置~~ → **已配置并推送完成**,见上面 D 节与决策 19/20。
|
||||||
note:仓库当前是 **Public**(匿名 `git ls-remote` 可读),要改私有去 Gitea 仓库设置。
|
note:仓库当前是 **Public**(匿名 `git ls-remote` 可读),要改私有去 Gitea 仓库设置。
|
||||||
- [ ] L0 完成 **9/12**(`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`、`clean_missing`、
|
- [ ] L0 完成 **10/12**(`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`、`clean_missing`、
|
||||||
`detect_outliers`、`normalize`、`standardize`、`describe`、`correlation_matrix`),
|
`detect_outliers`、`normalize`、`standardize`、`describe`、`correlation_matrix`、`bootstrap_ci`),
|
||||||
另 L1 的 `confidence_interval` / `t_test` 已提前落地;其余按 `docs/03-roadmap.md` 的 L0 → L1 顺序推进,详情见 E 节
|
另 L1 的 `confidence_interval` / `t_test` 已提前落地;
|
||||||
|
**只剩 `monte_carlo`(用户写)与 `save_figure`(Codex 写)**,详情见 E 节与"下一步"
|
||||||
- [ ] 本机 `exec_command` 在沙箱模式下**完全不可用**
|
- [ ] 本机 `exec_command` 在沙箱模式下**完全不可用**
|
||||||
(`helper_unknown_error: setup refresh had errors`),只有提权
|
(`helper_unknown_error: setup refresh had errors`),只有提权
|
||||||
(`require_escalated`)模式可用。沙箱模式只允许写 `D:\MCM&ICM_Toolkit`。
|
(`require_escalated`)模式可用。沙箱模式只允许写 `D:\MCM&ICM_Toolkit`。
|
||||||
@@ -331,20 +347,55 @@
|
|||||||
用户 2026-10-03 明确:没考虑到的非法情况"告诉我我自己改"——因为那是设计决策,得由写实现的人形成判断;而 lint / 进度板 / 测试这类机械活再由用户动手只是浪费。这条与决策 25 / 31 配套:25 定"谁写 src",31 定"Codex 可改的 bug 范围",39 定"非算法事务的默认归口" |
|
用户 2026-10-03 明确:没考虑到的非法情况"告诉我我自己改"——因为那是设计决策,得由写实现的人形成判断;而 lint / 进度板 / 测试这类机械活再由用户动手只是浪费。这条与决策 25 / 31 配套:25 定"谁写 src",31 定"Codex 可改的 bug 范围",39 定"非算法事务的默认归口" |
|
||||||
docstring 与 `test_describe_reports_expected_keys` 早就写死了这个方向,实现里多做的 `.T` 是净负担 —— 且不是"风格不同"那么轻:转置后 `.loc[指标名] = <按变量索引的 Series>` 与列名零交集,pandas **不报错**、把四行整行填成 NaN。方向约定以"能按列名对齐"为准,见易错点 11 |
|
docstring 与 `test_describe_reports_expected_keys` 早就写死了这个方向,实现里多做的 `.T` 是净负担 —— 且不是"风格不同"那么轻:转置后 `.loc[指标名] = <按变量索引的 Series>` 与列名零交集,pandas **不报错**、把四行整行填成 NaN。方向约定以"能按列名对齐"为准,见易错点 11 |
|
||||||
原码写的是 `if offset > 0: raise`,把唯一合法的用例(正 offset 正好抬定义域)全拒了,报错文案却是"offset 必须大于 0",自相矛盾。改成校验真正的前提:`log` 要求自变量取正。`offset=0` 对全正数据合法(`offset=None` 的自动分支本来就取 0)。**Codex 代选、待用户确认** —— 若原意是"只收正 offset",改回即可 |
|
原码写的是 `if offset > 0: raise`,把唯一合法的用例(正 offset 正好抬定义域)全拒了,报错文案却是"offset 必须大于 0",自相矛盾。改成校验真正的前提:`log` 要求自变量取正。`offset=0` 对全正数据合法(`offset=None` 的自动分支本来就取 0)。**Codex 代选、待用户确认** —— 若原意是"只收正 offset",改回即可 |
|
||||||
|
| 47 | **算法一律由用户本人写;工程由 Codex 写**(用户 2026-10-03 明确) |
|
||||||
|
用户原话:"记住算法的东西一定要我来写,以后就算我说让你来写你也不要帮我写,工程我觉得我还可以,你写我看吧"。
|
||||||
|
这条比决策 25 更硬:25 说"默认归用户",47 说"**即便用户改口也不代写**"——目的是保住"一边学一边自己写"的学习路径。
|
||||||
|
工程侧(入口/校验、`tests/`、lint、文档、卡片、`.gitignore`)反过来由 Codex 直接落盘,用户只读;
|
||||||
|
分地盘按**文件**划,不按函数划。决策 39 的"语义由用户拍板"继续有效。
|
||||||
|
|
||||||
## 下一步
|
## 下一步
|
||||||
|
|
||||||
1. **`bootstrap_ci` 已完成**(L0 10/12,卡片也写了)。**L0 里下一个是 `monte_carlo`**(**S 档**,`solve/simulate.py`)——
|
### ⭐ 明天从这里开始(第一个要写的文件)
|
||||||
同样要配一张函数卡片;它的三个兄弟(`monte_carlo_probability` / `monte_carlo_integral` / `random_walk`)
|
|
||||||
都在同一份卡片体系里,先把 `monte_carlo` 的形状定下来。
|
**文件:`src/mcm_toolkit/solve/simulate.py` → 写 `monte_carlo`(L0 第 11/12 项,S 档)。**
|
||||||
2. L0 的最后一项是 `save_figure`(A 档,`viz/export.py`)。
|
同一文件里 `monte_carlo_probability` / `monte_carlo_integral` / `random_walk` 先别动 —— 一次一个函数。
|
||||||
3. L0 跑通后,找一道真题(建议 2025 C)走完整流程,反向沉淀函数。
|
|
||||||
4. 已拍板的旧口径(留档):`log_transform` 的 `offset` 维持现状(决策 35);
|
**① 参考契约(docstring 里已定,签名别改)**
|
||||||
|
- `monte_carlo(sampler, simulator, n=10000, random_state=None, **kwargs) -> Result`
|
||||||
|
- `sampler(rng, **kwargs) -> 参数`:一次抽**一整批**参数(可以是标量/数组/元组,随便)
|
||||||
|
- `simulator(params) -> float`:单次仿真结果
|
||||||
|
- 返回 `Result`:`data` = `n` 个结果组成的 `np.ndarray`;
|
||||||
|
`metrics = {"mean", "std", "median", "p05", "p95", "ci_low", "ci_high"}`
|
||||||
|
|
||||||
|
**② 必须向量化**:`sampler` 一次抽 `n` 份(如 `rng.normal(0, 1, size=n)`),`simulator` 对整个参数数组算一次,
|
||||||
|
**绝不在 `simulator` 里写 Python 循环**。10^4 次循环还能忍,10^6 次直接放弃 —— 这是"能用"和"不能用"的分界线。
|
||||||
|
|
||||||
|
**③ 随机数无条件走 `core.get_rng`**(决策 46 的教训,别重演 bootstrap 那个坑):
|
||||||
|
`rng = get_rng(random_state)`,不要自己另开 `np.random.default_rng()`,否则 `set_seed` 管不到它、区间不可复现。
|
||||||
|
|
||||||
|
**④ 先写一条会失败的测试**(roadmap §3.2 的纪律)。`tests/test_solve.py` 现在**没有**直接测 `monte_carlo` 的用例
|
||||||
|
(`test_monte_carlo_is_reproducible` 名字像,实际调的是 `monte_carlo_probability`)。建议三条:
|
||||||
|
- 固定种子两次结果完全相同(可复现)
|
||||||
|
- `sampler` 恒返回常数 → `data` 全等于该常数、`std == 0`(常量边界)
|
||||||
|
- `n` 增大时 `mean` 的波动按 `O(1/√n)` 下降(可留成大样本慢测或标 `slow`)
|
||||||
|
|
||||||
|
**⑤ 还欠一张 S 档卡片**:`docs/algorithms/monte_carlo.md`(模板 `docs/dev/function-card-template.md`,
|
||||||
|
照抄 `docs/algorithms/bootstrap_ci.md` 的骨架),写完把 `docs/algorithms/README.md` 的进度表打勾。
|
||||||
|
|
||||||
|
**⑥ 等你拍板的一个口径(Codex 不代选,决策 39/47)**:`ci_low` / `ci_high` 用**分位数法**
|
||||||
|
(`np.percentile(data, [2.5, 97.5])`)还是**正态近似**(`mean ± 1.96·std/√n`)?两个都能用,选一个我记进卡片。
|
||||||
|
|
||||||
|
### 其余待办
|
||||||
|
|
||||||
|
1. L0 的最后一项是 `save_figure`(**A 档 = 工程**,`viz/export.py`)—— **由 Codex 直接实现**,用户只读。
|
||||||
|
2. L0 跑通后,找一道真题(建议 2025 C)走完整流程,反向沉淀函数。
|
||||||
|
3. 已拍板的旧口径(留档):`log_transform` 的 `offset` 维持现状(决策 35);
|
||||||
`describe` / `zscore` 默认丢掉非数值列(决策 37);变异系数用 `σ / |μ|`(决策 38);
|
`describe` / `zscore` 默认丢掉非数值列(决策 37);变异系数用 `σ / |μ|`(决策 38);
|
||||||
分工见决策 39;`correlation_matrix` 走方案 A(决策 41)。
|
分工见决策 39;`correlation_matrix` 走方案 A(决策 41)。
|
||||||
5. **仍未答的一个小问题**:`correlation_matrix` 现在只收 `DataFrame`,
|
4. **仍未答的一个小问题**:`correlation_matrix` 现在只收 `DataFrame`,
|
||||||
而 `describe` / `zscore` / `transform` 都收 ndarray —— 要不要也放开?(你说了算)
|
而 `describe` / `zscore` / `transform` 都收 ndarray —— 要不要也放开?(你说了算)
|
||||||
|
|
||||||
6. **`t_test` 有 4 个口径等你拍板(Codex 一律没动,按决策 39)**:
|
5. **`t_test` 有 4 个口径等你拍板(Codex 一律没动,按决策 39)**:
|
||||||
- **① 单样本的结论文案说错了。** `b=None` 时 `test_name` 已经是"单样本 t 检验",
|
- **① 单样本的结论文案说错了。** `b=None` 时 `test_name` 已经是"单样本 t 检验",
|
||||||
但 `conclusion` 仍写"两组数据存在统计学上的显著差异" —— 单样本根本没有第二组。
|
但 `conclusion` 仍写"两组数据存在统计学上的显著差异" —— 单样本根本没有第二组。
|
||||||
建议按分支拼文案(单样本说"该样本均值与 `value` 有显著差异")。
|
建议按分支拼文案(单样本说"该样本均值与 `value` 有显著差异")。
|
||||||
@@ -355,7 +406,7 @@ docstring 与 `test_describe_reports_expected_keys` 早就写死了这个方向
|
|||||||
多列不同量纲(`gdp` + `pop`)会被混在一起,而且**没法**拿"一张表里两列"当两组比。
|
多列不同量纲(`gdp` + `pop`)会被混在一起,而且**没法**拿"一张表里两列"当两组比。
|
||||||
要不要改成:多数值列的 DataFrame 直接 `ValueError`、强制先自己取列?
|
要不要改成:多数值列的 DataFrame 直接 `ValueError`、强制先自己取列?
|
||||||
|
|
||||||
7. **`as_array` 落地后留下的 3 个小口径(Codex 没代选,按决策 39)**:
|
6. **`as_array` 落地后留下的 3 个小口径(Codex 没代选,按决策 39)**:
|
||||||
- `int` / `float` 标量还在白名单里(为兼容 `normalize` / `standardize` / `log_transform`
|
- `int` / `float` 标量还在白名单里(为兼容 `normalize` / `standardize` / `log_transform`
|
||||||
三个 docstring 写的"数值型标量")。但标量进来是 **0 维数组**,`axis=0` 的算法照样炸 ——
|
三个 docstring 写的"数值型标量")。但标量进来是 **0 维数组**,`axis=0` 的算法照样炸 ——
|
||||||
要不要把标量摘掉、同时改三处 docstring?
|
要不要把标量摘掉、同时改三处 docstring?
|
||||||
@@ -364,7 +415,7 @@ docstring 与 `test_describe_reports_expected_keys` 早就写死了这个方向
|
|||||||
- 现在 `kind == "frame"` 时你要自己再写一遍 `x.select_dtypes(include=[np.number]).columns` 取列名。
|
- 现在 `kind == "frame"` 时你要自己再写一遍 `x.select_dtypes(include=[np.number]).columns` 取列名。
|
||||||
嫌烦的话可以让 `as_array` 顺带把选中的列返回(改成三元组),一句话的事。
|
嫌烦的话可以让 `as_array` 顺带把选中的列返回(改成三元组),一句话的事。
|
||||||
|
|
||||||
8. **`bootstrap_ci` 的 5 个待拍板口径**(Codex 一律没动,按决策 39;详见 `docs/algorithms/bootstrap_ci.md` §10):
|
7. **`bootstrap_ci` 的 5 个待拍板口径**(Codex 一律没动,按决策 39;详见 `docs/algorithms/bootstrap_ci.md` §10):
|
||||||
- `x` 里的 **NaN** 静默传进统计量 → `nan` 区间(`confidence_interval` / `t_test` 都是先丢掉的,口径不齐)
|
- `x` 里的 **NaN** 静默传进统计量 → `nan` 区间(`confidence_interval` / `t_test` 都是先丢掉的,口径不齐)
|
||||||
- `n_resamples <= 0` → 现在抛 `IndexError: index -1 is out of bounds`(应在入口给可读 `ValueError`)
|
- `n_resamples <= 0` → 现在抛 `IndexError: index -1 is out of bounds`(应在入口给可读 `ValueError`)
|
||||||
- `confidence` 越界 → 现在由 numpy 抛 `Percentiles must be in the range [0, 100]`
|
- `confidence` 越界 → 现在由 numpy 抛 `Percentiles must be in the range [0, 100]`
|
||||||
|
|||||||
+10
-1
@@ -5,9 +5,10 @@ from __future__ import annotations
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
pytestmark = pytest.mark.skip(reason="未实现:见 docs/03-roadmap.md L0/L1")
|
_NOT_IMPLEMENTED = "未实现:见 docs/03-roadmap.md L0/L1"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_monte_carlo_integral_converges_to_analytic_value():
|
def test_monte_carlo_integral_converges_to_analytic_value():
|
||||||
"""∫₀¹ x² dx = 1/3。n=2e5 时误差应 < 0.01。"""
|
"""∫₀¹ x² dx = 1/3。n=2e5 时误差应 < 0.01。"""
|
||||||
from mcm_toolkit.solve import monte_carlo_integral
|
from mcm_toolkit.solve import monte_carlo_integral
|
||||||
@@ -16,6 +17,7 @@ def test_monte_carlo_integral_converges_to_analytic_value():
|
|||||||
assert abs(r.data - 1 / 3) < 0.01
|
assert abs(r.data - 1 / 3) < 0.01
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_monte_carlo_probability_of_standard_normal():
|
def test_monte_carlo_probability_of_standard_normal():
|
||||||
"""P(Z > 0) = 0.5,n=5000 时误差应 < 0.05。"""
|
"""P(Z > 0) = 0.5,n=5000 时误差应 < 0.05。"""
|
||||||
from mcm_toolkit.solve import monte_carlo_probability
|
from mcm_toolkit.solve import monte_carlo_probability
|
||||||
@@ -29,6 +31,7 @@ def test_monte_carlo_probability_of_standard_normal():
|
|||||||
assert abs(r.metrics["probability"] - 0.5) < 0.05
|
assert abs(r.metrics["probability"] - 0.5) < 0.05
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_monte_carlo_is_reproducible():
|
def test_monte_carlo_is_reproducible():
|
||||||
from mcm_toolkit.solve import monte_carlo_probability
|
from mcm_toolkit.solve import monte_carlo_probability
|
||||||
|
|
||||||
@@ -38,6 +41,7 @@ def test_monte_carlo_is_reproducible():
|
|||||||
assert a.metrics["probability"] == b.metrics["probability"]
|
assert a.metrics["probability"] == b.metrics["probability"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_markov_steady_state_two_state_chain():
|
def test_markov_steady_state_two_state_chain():
|
||||||
"""P=[[0.9,0.1],[0.2,0.8]] 的平稳分布是 [2/3, 1/3]。"""
|
"""P=[[0.9,0.1],[0.2,0.8]] 的平稳分布是 [2/3, 1/3]。"""
|
||||||
from mcm_toolkit.solve import markov_steady_state
|
from mcm_toolkit.solve import markov_steady_state
|
||||||
@@ -46,6 +50,7 @@ def test_markov_steady_state_two_state_chain():
|
|||||||
assert np.allclose(r.data, [2 / 3, 1 / 3], atol=1e-6)
|
assert np.allclose(r.data, [2 / 3, 1 / 3], atol=1e-6)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_knapsack_dp_known_optimum():
|
def test_knapsack_dp_known_optimum():
|
||||||
from mcm_toolkit.solve import knapsack_dp
|
from mcm_toolkit.solve import knapsack_dp
|
||||||
|
|
||||||
@@ -54,6 +59,7 @@ def test_knapsack_dp_known_optimum():
|
|||||||
assert np.isclose(r.metrics["total_weight"], 7.0)
|
assert np.isclose(r.metrics["total_weight"], 7.0)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_linear_program_basic():
|
def test_linear_program_basic():
|
||||||
from mcm_toolkit.solve import linear_program
|
from mcm_toolkit.solve import linear_program
|
||||||
|
|
||||||
@@ -62,6 +68,7 @@ def test_linear_program_basic():
|
|||||||
assert np.isclose(r.metrics["objective"], 4.0)
|
assert np.isclose(r.metrics["objective"], 4.0)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_mm1_metrics_closed_form():
|
def test_mm1_metrics_closed_form():
|
||||||
from mcm_toolkit.solve import mm1_metrics
|
from mcm_toolkit.solve import mm1_metrics
|
||||||
|
|
||||||
@@ -70,6 +77,7 @@ def test_mm1_metrics_closed_form():
|
|||||||
assert np.isclose(r.metrics["L"], 2.0, rtol=1e-6)
|
assert np.isclose(r.metrics["L"], 2.0, rtol=1e-6)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_mm1_rejects_unstable_system():
|
def test_mm1_rejects_unstable_system():
|
||||||
"""λ >= μ 时系统不稳定,应 success=False 而不是返回 inf。"""
|
"""λ >= μ 时系统不稳定,应 success=False 而不是返回 inf。"""
|
||||||
from mcm_toolkit.solve import mm1_metrics
|
from mcm_toolkit.solve import mm1_metrics
|
||||||
@@ -77,6 +85,7 @@ def test_mm1_rejects_unstable_system():
|
|||||||
assert mm1_metrics(arrival_rate=3, service_rate=3).success is False
|
assert mm1_metrics(arrival_rate=3, service_rate=3).success is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason=_NOT_IMPLEMENTED)
|
||||||
def test_simulated_annealing_finds_quadratic_minimum():
|
def test_simulated_annealing_finds_quadratic_minimum():
|
||||||
from mcm_toolkit.solve import simulated_annealing
|
from mcm_toolkit.solve import simulated_annealing
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user