Files
mcm-26-b/docs/algo-3.md
T
2026-09-13 08:29:30 +08:00

457 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 问题三算法说明:全向多源搜索的覆盖证明、贝叶斯闭环与任务调度(当前实现)
> 本文汇总当前仓库中问题三的全部实际算法,生产默认策略为
> `src/mcm26b/planner/bayes_loop.py::BayesLoop`(CLI 策略名 `bayes`)。
> `grid`(`OmnidirectionalLoop`,49 点)与 `seven`
> (`SevenBatch`,七点解析覆盖 + 本站批量)保留为可复现对照。
> 问题三当前生产不包含任何机器学习策略;历史 HRL/RL 代码已移除,
> 自建消融中手写基线稳定优于学习策略(见 `docs/第三四问架构优化与运行提速方案.md`)。
## 1. 问题定位与策略族
问题三中每局有 $10\sim16$ 个全向干扰源,位置未知、频道互异(1..20),
源位于 $\Omega=B(0,1800)$ 内;有效接收半径 $r_{\rm eff}$ 未知,但满足
$1000\le r_{\rm eff}\le1500$ m。策略端只能看到协议响应
(`direction` / `near` / `no_signal`),目标是发现、定位并清除全部源,
使虚拟总耗时尽量小,同时给出“不存在漏源”的证明或明确未完成。
| 策略 | 类 | 发现保证 | 定位/决策 | 角色 |
| --- | --- | --- | --- | --- |
| `grid` | `OmnidirectionalLoop` | 700 m 方格 49 点,单元对角 $700\sqrt2\approx989.95\le1000$ | 发现后立即就近定位,无信息增益 | 历史基线 |
| `seven` | `SevenBatch` | 原点 + 半径 1200 m 六等分环,解析覆盖界 968.90 m | 本站先扫频,再按候选集 MEC 圆心最近服务队列 | A2 中间对照 |
| `bayes` | `BayesLoop` | 七站环(默认半径 1159.7 m,界 984.54 m)+ PF 负观测 | 网格粒子滤波 + 信息增益选点 + 滚动任务排序 | **生产默认** |
七站族还有 `SevenImmediate`(A1,发现即离站)与 `SevenSweep`
(A3,先扫完全域再统一服务)。它们的差异只在发现/定位的调度顺序,
七点覆盖证明与距离语义相同。
### 1.1 统一计时模型
忽略微秒量化时,一次动作回合的虚拟耗时为
$$
T=\frac{L}{5}+5N_m+N_s+5N_c^++3N_c^-,
$$
其中 $L$ 为移动距离(速度 5 m/s),$N_m$ 为检测次数,$N_s$ 为换频次数,
$N_c^+$ 为成功清除次数,$N_c^-$ 为失败清除次数。`/clear` 本身不切换
测向频道,`/exit` 不增加虚拟时间,访问顺序是起点固定、终点自由的**开放
路径问题**,不是必须回到原点的 TSP 回路。官方内部按整数微秒累计,项目用
`evaluation.recompute_virtual_time` 逐动作复算并校验。
## 2. 三层在线架构
`BayesLoop` 在 `OmnidirectionalLoop` 的会话/预算/收尾骨架上重构为三层:
1. **保证层**:七点覆盖账本 `CoverageLedger` + 解析覆盖定理;负责
“全测无信号 $\Rightarrow$ 该频道不存在源”。
2. **信念层**:
- 凸候选集 `CandidateRegion`(正观测方向/近距离约束,用于清除证书);
- 网格幸存集 `ChannelParticles`(正/负观测统一更新,用于缺席证明、
跳测与信息增益);
- 两者同读一套响应流,任何一方证毕即结束该频道。
3. **决策层**:统一任务表(站点扫频 / 定位测量 / 清除),开放路径
最近邻 + 2-opt 滚动重排;每执行一个任务后用真实响应重规划。
问题三不复用问题四的(位置 × 朝向)联合信念;`no_signal` 在全向源上
可以排除 $B(s,1000)$。
## 3. 证据层:逐频道候选集与负观测
### 3.1 凸候选集 `CandidateRegion`
对每个已收到过有效信号的频道 $c$ 维护凸多边形 $P_c^{\rm out}$:
- 初始为 $\Omega$ 的 192 边外切正多边形;
- 每次 `direction`:
1. 与 $B(s,1500)$(192 边外切多边形)求交;
2. 与角域 $W(s,\theta,\delta_{\rm eff})$ 求交,$\delta_{\rm eff}=1^\circ+0.005^\circ$;
- `near`:与 $B(s,5)$ 外切多边形求交;
- `no_signal`:**不收缩凸候选集**。对全向源,负观测信息由 `ChannelParticles`
处理;让凸表示保留所有正观测候选,可以避免因模型误差误删真源。
圆盘外切多边形的径向超出逐次累加到 `slack_m`,所有裁剪容差只向
“保留更多候选”的方向倾斜,因此真源始终包含在 $P_c^{\rm out}$ 内。
清除证书使用 $P_c^{\rm out}$ 的最小包围圆 $B(m_c,\rho_c)$:
$$
\rho_c+\text{slack}_c+0.5\le20
\quad\Longrightarrow\quad
\text{在 }m_c\text{ 处一次 `/clear` 必命中真源}.
$$
其中 $0.5$ m 是工程余量,slack 是外包多边形的半径余量;该判据是保守的
充分条件,而不是“必须达到的最优半径”。
### 3.2 网格幸存集 `ChannelParticles`
每个频道维护 $\Omega$ 外扩裕量上的方格网格,间距
$h=14.65$ m,约 4.7 万格;Voronoi 裕量
$$
m=\frac{\sqrt2}{2}h\approx10.359\ {\rm m}
$$
是格心到格内任一点的最大距离。所有删除判定都内缩 $m$:**只有整个格子与
可行集不相交时才删除该格**。
| 观测 | 位置/距离更新 | 实现 |
| --- | --- | --- |
| `no_signal` @ $s$ | 距离 $>r_{\rm eff}\ge1000$,删除格心距 $s\le1000-m$ 的格 | `_kill_disk(s,1000-m)` |
| `direction` @ $s$,读数 $\theta$ | 距离 $\le1500$;角向偏差不超过 $\delta_{\rm eff}$ + 格内角裕量 | 先删距 $s>1500+m$ 的格,再删角向超出的格 |
| `near` @ $s$ | 距离 $\le5$ | 删格心距 $s>5+m$ 的格 |
**定理(真源保留).** 真源 $P$ 所在格的格心 $g$ 满足
$|g-P|\le m$;与真值一致的观测不会让该格与可行集完全不相交,因此
“整格不相交”判定永不删除该格。于是:
- **缺席证明**:幸存集为空 $\Longrightarrow$ 可行集为空
$\Longrightarrow$ 该频道无源;
- **跳测规则**:若某测点到所有幸存格心的最小距离 $>1500+m$,则在该点
测量必为 `no_signal` 且不产生任何新排除,可直接跳过,省 5 秒检测和
1 秒换频;
- **PF 清除证书**:若幸存集 MEC 半径 $\rho_{\rm pf}$ 满足
$\rho_{\rm pf}+m+0.5\le20$,则以该 MEC 圆心清除必命中真源。
`BayesLoop` 在每次测量后同步更新凸候选集与 PF,PF 只在频道尚未
CLEARED/ABSENT 时接收新证据。
### 3.3 数量上界证明
题面给定每局源总数 $10\sim16$ 且每频道至多一个源。若
`DETECTED`/`CLEARED` 的不同频道数达到 16,则所有仍未出现有效信号的
`UNKNOWN` 频道都不可能有源,可直接标记为 `ABSENT`,证据来源记为
`count_bound`。这条规则与位置无关,是严格计数证明,不需要等七站扫完。
`summary.completion_basis` 会区分 `count_cap` 与 `per_channel_proof`,
避免把“达到数量上界”误读成“逐频道缺席证明”。
## 4. 发现保证:七点解析覆盖与覆盖账本
### 4.1 `full_disk` 语义
全向源在测点 $s$ 返回 `no_signal`,意味着真实距离严格大于
$r_{\rm eff}\ge1000$。因此若集合 $S$ 满足
$$
\Omega\subseteq\bigcup_{s\in S}B(s,1000),
$$
则任何合法源必在某个 $s\in S$ 的 1000 m 内,在该点不可能返回
`no_signal`。于是“某频道在全部 $S$ 点都测得 `no_signal`”构成严格的
缺席证明。
`CoverageLedger` 按 `(channel, point_index)` 二维记录,只有所有点都已测
(或显式跳过)才允许 `coverage_complete(channel)=True`;“路过某点”不算
“测过某频道”。
### 4.2 七点构造与解析界
取原点加半径 $a$ 的六等分环:
$$
S(a)=\{(0,0)\}\cup\left\{a(\cos(k\pi/3),\sin(k\pi/3)):\ k=0,\dots,5\right\}.
$$
**定理 1.** 当 $0<a/\sqrt3\le R$ 时,
$$
\max_{g\in\Omega}\min_{s\in S(a)}\lVert g-s\rVert
\le D(a):=
\max\left\{\frac a{\sqrt3},\ \sqrt{R^2+a^2-\sqrt3Ra}\right\},
$$
其中 $R=1800$。证明:任意 $g=(r\cos\varphi,r\sin\varphi)$ 与最近环站的
夹角不超过 $\pi/6$。若 $r\le a/\sqrt3$,选原点;否则选最近环站,由
余弦定理和 $\cos\varphi\ge\cos(\pi/6)=\sqrt3/2$ 得
$\lVert g-s\rVert^2\le r^2+a^2-\sqrt3ar$。右端关于 $r$ 是凸二次函数,
在区间端点取最大值,分别得 $a^2/3$ 和 $R^2+a^2-\sqrt3Ra$。证毕。
代入可验证:$a=1200$ 时 $D=968.901572$ m;当前 `bayes` 默认
`station_ring_radius_m=1159.7` m 时 $D=984.539136$ m;两者都小于 1000,
从站上有 15.5 m 以上的几何余量。$a$ 的可行下界为
$a_{\min}\approx1122.955832$ m(零余量)或 $1125.254906$ m(1 m 余量)。
七点巡回长度 $6a$;$a=1200$ 时纯覆盖路线约 7200 m。
### 4.3 49 点基线
网格 $S=\{(700i,700j):i,j\in[-3,3]\}$ 覆盖 $[-2100,2100]^2\supseteq\Omega$;
每个单元的对角线 $700\sqrt2\approx989.95\le1000$,因此任意源都在某个
网格点的 1000 m 内。该证明不需要朝向信息,对问题三的七点方案是更强的
充分条件,但会发现阶段检测次数多一个数量级(频道 × 49 次);问题四仍
需要它作为 legacy 对照(见 `algo-4.md`)。
### 4.4 计划可验证性
`guarantee/cover.py` 提供两套校核:
- `verify_full_disk(points)`:在 $\Omega$ 内按网格采样,校核
“每个采样位置都在某个点的 1000 m 内”;
- `verify_forward_half_disk(...)`:第四问语义,问题三不使用。
七点计划走解析证明;49 点计划走 `full_disk` 校核。运行期不使用未校核的
点集来宣称“已证明无源”。
## 5. 定位与清除
### 5.1 问题二选点器的推广(基线与安全后备)
`planner.select_measurement_point` 对**任意** `CandidateRegion` 工作:
给定当前后验外包多边形 $P$,令其 MEC 为 $B(m,\rho)$,则安全接收盘为
$$
B\left(m,\ 1000-\rho-10^{-3}\right)
$$
($\rho>1000$ 时退化为探索 MEC 圆心,可能 `no_signal`)。盘内取
37 个候选点(圆心 + 3 环 × 12 方向),以“边界见证点 × 读数区间端点 +
near 分支”的最坏后验 MEC 半径为主指标、移动时间为次指标;选出后再按
1/4 间距加密复核。该函数最初为问题二实现,在问题三中服务于
`SevenBatch`、`OmnidirectionalLoop` 的定位子循环,以及 `BayesLoop`
的阻塞式安全后备 `_localize_and_clear`。
### 5.2 `bayes` 的信息增益选点
`BayesLoop._select_point` 在 PF 幸存集上选择定位测点,候选集分两种:
- 凸候选集安全盘非空:取 `select_measurement_point` 的环形候选,并额外
加入以当前位置到 MEC 圆心方向为轴的对称候选,以及零移动的当前位置;
- $\rho>1000$、无保证安全盘:取 PF MEC 的 $1.0/1.5/2.0$ 倍探索环和
PF MEC 圆心。
对候选 $q$,默认评分模式 `entropy` 是期望对数幸存占比:
$$
\text{score}(q)=
\mathbb E[\log(\text{后验幸存占比})]
+\lambda\left(\frac{\lVert p-q\rVert}{5}
+\frac{\lVert q-m_{\rm MEC}\rVert}{5}\right),
\qquad \lambda=0.05.
$$
其中期望对代表假设(从幸存格均匀抽样)和 $r_{\rm eff}\sim U(1000,1500)$
解析积分:
- `no_signal` 分支(概率 $(d-1000)/500$):幸存格收缩到
$B(q,1000-m)$ 之外;
- `direction` 分支:以代表点方位为期望读数,用 $\pm\delta_{\rm eff}$
角域裁剪后的子采样估计幸存占比;
- `near` 分支($d\le5+m$):后验为 5 m 盘,占比趋近零。
可选 `score_mode=radius` 直接最小化期望后验 MEC 半径。
`score_subsample=800`、`mc_representatives=7` 是工程参数;均匀源分布、
零误差代表读数和 $r_{\rm eff}$ 均匀分布都只是**选点评分假设**,不参与
任何安全证明。安全证明只使用题面给定的 $\pm1.005^\circ$ 角域与距离界。
当前配置中以下“更强的耦合”均已实现但实测为净负收益,默认关闭:
`fuse_localize_into_tour=False`(站点顺带定位)、`exact_order_limit=0`
(Held-Karp 精确任务序)、`route_aware_probe=False`(路线感知探点)。
代码与开关保留,便于复现与后续研究。
### 5.3 清除动作
`BayesLoop._best_certificate` 的优先级:
1. **凸证书**:`clear_certificate(region)`;
2. **PF 证书**(`grid_cert_enabled=True`):负观测挖洞使 PF 幸存集更紧时,
若 PF MEC 半径 $+m+0.5\le20$,用 PF MEC 圆心作为清除点。
得到证书后,`_near_clear_target` 还会把清除点从证书圆心向当前位置方向
平移一小段:设当前证书半径 $r$、限值 $limit$,最多平移
$\Delta=\min(\text{当前距离},limit-r-10^{-6})$,新目标点仍保证所有候选
源在 $r+\Delta\le limit$ 内。该平移可省去最后一段接近路程,不放松证书。
定位子循环每频道最多 `max_localize_steps=8` 次追加测量;若在安全接收盘内
出现 `no_signal`,记录异常 `no_signal_in_safe_disk`,不静默忽略。
## 6. 决策层:统一任务表与滚动重排
### 6.1 任务类型
`BayesLoop._build_tasks` 在每次决策点构建:
| 任务 | 位置 | 服务时间 | 触发条件 |
| --- | --- | --- | --- |
| `station` | 七站之一 | $5\times$待测频道数 + 换频 | 该站仍有 `UNKNOWN` 频道未测,且跳测规则未排除 |
| `locate` | 信息增益选点 | 5 s + 可能的换频 | 频道 `DETECTED` 且暂无清除证书,且未委托给站点 |
| `clear` | 证书中心(可平移) | 5 s 成功(失败 3 s) | 频道有清除证书且未处于“清除失败后待补测”状态 |
站点任务的服务时间计算当前频道优先:若机器人当前测向频道包含在待测集合,
则少一次换频。清除动作不改变测向频道。
### 6.2 跳测规则
`guaranteed_no_signal(station)`:若该频道所有幸存格心到站点的距离都
大于 $1500+m$,则该次测量必为 `no_signal` 且不会产生新排除,任务构造时
直接跳过。跳测缓存按 PF `version` 生效;幸存集单调收缩,因此判定单调。
这条规则是负观测给问题三带来的主要检测节省之一。
### 6.3 开放路径排序
任务表规模通常为 6~12 项,代价包含移动、检测、换频,终点自由。默认:
1. 最近邻构造初始序;
2. 开放路径 2-opt 改进,最多 `two_opt_passes=4` 轮;
3. 换频代价按实际频道状态沿路径逐步传递,而不是固定服务费;
4. 执行排序后的**第一个任务**,拿到响应后立即回到决策点重新构建/排序
(滚动时域)。
可选的 Held-Karp 精确 DP(含“已访问集合 × 结束时频道”状态)与
`route_aware_probe` 路线感知精修均已实现;在当前冻结基准集上,
精确 DP 与 2-opt 差距在噪声内(甚至略差),默认关闭。
### 6.4 已停靠位置的机会测量
`_measure_at_stop` 在每次决策点评估当前位置是否值得顺带补测已发现频道:
只对尚未在该 0.5 m 点测过、无证书、到凸候选集所有顶点距离均不超过
$1000-10^{-3}$ m、且预测后验半径至少收缩
`opportunistic_radius_ratio=0.5` 的频道追加一次测量。每次仍支付 5 秒与
实际换频成本,只是省去移动;它不是“免费检测”。
## 7. 停止、预算与异常收尾
### 7.1 完成证明
循环停止后,`summary.completed` 的依据分两类:
- `count_cap`:清除数达到 16(题面源数上界);
- `per_channel_proof`:每个频道状态都是 `CLEARED` 或 `ABSENT`。
缺席证据在 `summary.absence_evidence` 中逐频道记录来源:
| 证据 | 条件 | 严格性 |
| --- | --- | --- |
| `pf_empty` | 某频道 PF 幸存集为空 | 严格(Voronoi 真源保留) |
| `coverage` | 七点/49 点全部测得 `no_signal`(或计划上显式跳过) | 严格(解析/校核覆盖) |
| `count_bound` | 已有 16 个不同频道的有效存在证据 | 严格(题面数量上界) |
`persistent_search` **默认 False**:一旦“每频道已清除或证明不存在”就立即
`/exit`,因为虚拟时间是成绩口径。显式 `--persistent` 会继续复扫未清除
频道直到清除数达 16、实机预算耗尽或虚拟安全余量不足;历史官方演练证明
无条件复扫会浪费大量时间,因此该项目只作为可审计的保险开关保留。
### 7.2 预算与中断
- 虚拟安全余量 `virtual_reserve_s=10000` s:剩余虚拟时间不足以完成
一个保守单动作上界时停止发起新动作,避免触及 100 小时上限;
- 现实预算以服务器 `/enter` 返回的 `remaining_real_duration_s` 为准;
`DeadlineExceeded` 时 stop_reason 记为 `real_budget_exhausted`;
- 传输、协议或守恒性异常都会尽力 `/exit` 并输出未完成 summary,
不静默丢会话;`completed=False` 与具体 `stop_reason` 同时留档。
## 8. 基线与自建消融
### 8.1 调度变体
| 版本 | 发现/定位关系 | 说明 |
| --- | --- | --- |
| A0 `grid` | 49 点,发现后立即离站定位 | 历史生产基线 |
| A1 `SevenImmediate` | 七点,发现后立即离站定位 | 只替换覆盖点 |
| A2 `SevenBatch` | 七点,本站先扫完再按最近候选圆心服务队列 | 中间对照,曾用于官方演练 |
| A3 `SevenSweep` | 七点,先扫完全部必要站点再统一服务 | 批量调度的另一极端 |
A2 相对 A0 的收益主要来自“减少站间往返 + 每站批量扫频 + 无源频道只需
7 次而不是 49 次检测”。在早期 12 个自建场景上,A0/A1/A2/A3 平均虚拟
时间分别为 13788.04 / 7476.09 / 5496.20 / 6094.73 秒,A2 逐局平均降幅
58.55%;更晚的 14 场景消融中,`bayes` 相对 A2 再降 30.0%
(3726.2 s vs 5352.7 s)。这些数字来自自建模拟器与固定误差场,不是官方成绩。
### 8.2 冻结基准集当前结果
`project/q3` 在 18 个冻结 core 场景(seeds 100–105 × 10/13/16 源,
`harness/suites.py` 版本化清单)上的配对结果:
| 方法 | 有效局 | 全清率 | 虚拟时间均值 | 中位 | 最大 | 检测均值 | 请求均值 | 位移均值 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| `bayes` | 18/18 | 100% | **3188.7 s** | 3111.3 s | 3663.7 s | 111.1 | 124.1 | 12338 m |
| `seven` | 18/18 | 100% | 5361.7 s | 5367.5 s | 6462.4 s | 100.8 | 113.8 | 23508 m |
| `grid` | 18/18 | 100% | 14935.7 s | 15275.1 s | 16691.4 s | 430.6 | 443.6 | 61550 m |
配对变化:`bayes` 相对 `grid` 虚拟时间 **−78.4%**,18/18 场景更快;
所有 54 局零缺席误判、零异常、正常退出且计时复算一致。另有边界场景
(源在 $\Omega$ 边界、$r_{\rm eff}=1000$)验证七点覆盖的扇区接缝。
### 8.3 官方演练记录(历史口径)
- 旧 49 点实现通过官方问题三演练案例 `DHFK-PHD2-SR2P-FXK9`:
10/10 全清、540 次检测、10 次清除,虚拟总时间 16217.45 s,
现实 7.629 s;
- A2 七点批量通过官方案例 `J4ER-Y9EP-Q379-UPFA`:12/12 全清、
109 次检测、虚拟 5232.13 s、现实 3.406 s;
- 后续一次官方问题三演练(`3BW5-9R54-NZNA-MYB9`)记录 13/13 全清、
虚拟 4058.71 s。
以上案例的源场景、实现版本、误差场均不同,不能直接横向比较,也不能把
历史官方数字当成当前 `bayes` 同案例重跑结果。当前默认 `bayes` 的官方向
成绩仍需新的演练验证。
## 9. 复杂度、参数与保守性边界
| 模块 | 计算量(近似) |
| --- | --- |
| PF 更新 | 与删除格/角向扫描的幸存格数相关;粗格索引与向量化(numpy 可选)控制常数 |
| 七点覆盖 | 最多 $7\times20=140$ 个 `(站, 频道)` 记录 |
| 任务排序 | 最近邻 $O(n^2)$ + 2-opt $O(n^2)$/轮;精确 DP 为 $O(2^nn\cdot|C|)$,默认关闭 |
| 凸候选集 | 192 边形外切 + $O(m)$ Sutherland–Hodgman 裁剪;MEC 用 Welzl |
| 选点评分 | $O(N_q\times(\text{子采样}))$;候选约 37 个,子采样 800 |
保守性边界:
- 所有“证毕”结论依赖题面观测语义和保守外包/内缩;若接口语义、
接收半径范围或误差界改变,必须重新校核;
- 性能结论依赖自建场景分布、固定误差场和排序启发式,不构成对全部合法
场景的最坏时间保证;
- PF 的均匀先验与信息增益评分是选点启发式,不是官方概率模型;
- `persistent_search` 关闭时,如果官方场景违反题面数量上界或存在模型外
行为,不能由本算法保证发现;官方接口语义变化时必须记录异常而不是
强行把未完成解释为成功。
## 10. 与问题一、二、四当前实现的复用关系和差异(核对结果)
| 复用/差异 | 具体情况 |
| --- | --- |
| 问题一几何内核 | `belief/__init__.py` 与 `particles.py` 只从 `geometry.localization` 导入 `smallest_enclosing_circle`;在线 `clip_wedge` 复刻同一半平面公式,但工作在凸多边形裁剪流程,不调用 `solve` |
| 问题二选点器 | `select_measurement_point` 直接从问题二推广而来,问题三用它做基线定位与安全后备;`safe_disk_radius` 同样复用 |
| 问题一没有的 | 负观测 `no_signal`、PF 非凸挖洞、覆盖缺席证明、数量上界、任务排序、滚动时域、预算/异常治理 |
| 问题二没有的 | 多频道数据关联、发现覆盖、清除动作、在线顺序决策;问题二只做一次第二点选择 |
| 问题四的差异 | 问题四不能用七点 `full_disk` 缺席证明;`no_signal` 可能由朝向遮挡造成,因此改用 `forward_half_disk` 31 点覆盖 +(位置 × 朝向)联合信念 + 预算化后备清除(见 `algo-4.md`) |
一句话概括:**问题三 = 问题一的保守几何 + 问题二的保证接收选点 + 逐频道非凸负观测 + 覆盖/数量缺席证明 + 开放路径滚动调度**。
## 11. 复现与参考
```bash
# 冻结基准集:bayes vs seven_batch(runner 内置策略名)
uv run python scripts/run_suite.py --problem 3 --suite core --jobs 6 \
--variants bayes,seven_batch --label q3-core
# 项目对比框架(含 grid 基线,生成 project/results/q3.{md,json})
uv run python -m project.run --question 3
# 回归测试
uv run pytest tests/test_particles.py tests/test_bayes_loop_q3.py \
tests/test_planner.py tests/test_coverage_plan.py tests/test_safety_valves.py -q
```
主要文件:
- `src/mcm26b/planner/bayes_loop.py`:`bayes` 决策层;
- `src/mcm26b/planner/__init__.py`:`OmnidirectionalLoop`、问题二选点器、清除证书;
- `src/mcm26b/planner/seven.py`:七点策略族与覆盖校验;
- `src/mcm26b/particles.py`:网格幸存集与信息增益;
- `src/mcm26b/belief/__init__.py`:凸候选集;
- `src/mcm26b/coverage/__init__.py`、`src/mcm26b/guarantee/cover.py`:覆盖账本与校核;
- `src/mcm26b/routing.py`:开放路径 DP/2-opt/MST 下界;
- `src/mcm26b/planner/bayes_loop.py::_exact_order`:可选 Held-Karp。
延伸阅读:`docs/algo-3-bayes.md`(早期贝叶斯闭环设计与消融细节)、
`docs/第三四问架构优化与运行提速方案.md`(运行历史与瓶颈)、
`docs/第三四问图论与动态规划优化方案.md`(图论/DP 轮实测与负面结论)。
## 参考文献
1. 全国大学生数学建模竞赛组委会. 2026 年高教社杯全国大学生数学建模竞赛 B 题[Z]. 2026. 本地题面 `issue/B题.pdf`。
2. 模拟器配套材料. 附件 1《模拟器使用说明》、附件 2《通信接口说明及编程指南》[Z]. 2026. 本地 `issue/附件/`。
3. 本项目. `docs/algo-1.md`、`docs/algo-2.md`、`docs/algo-4.md`。
4. 本项目. `docs/算法审核与优化-20260911.md`、`docs/第三四问架构优化与运行提速方案.md`、`docs/第三四问图论与动态规划优化方案.md`。