31 KiB
第三、四问:图论与动态规划算法引入方案
- 版本:2026-09-12
- 前置文档:第三四问架构优化与运行提速方案(架构与 P0–P2 项)、 algo-3-bayes.md(现役第三问策略)、algo-3.md(七点覆盖证明)
- 范围:只讨论"用图论 / 动态规划类算法进一步压低虚拟耗时"这一件事; 题面约束、协议语义、保守性不变量全部不动
- 本文所有数字均为本轮新增实测(自建内存回环、冻结场景、现役代码), 复现命令见 §7
0. 结论先行
可以,而且第四问的空间远大于第三问;但真正的收益不在"把巡回排得更短",而在 "把不必要的往返与盲清从决策层消掉"。
| 判断 | 证据 | 可回收 |
|---|---|---|
| 第三问路由已接近最优,纯图论排线几乎无空间 | 对同一批实际作业点求离线最优开放回路:2308 s vs 实测移动 2458 s,只剩 6.1%(151 s) | ≤ 150 s |
| 第三问仍有空间,但在探测次数(序贯决策),不在排线 | 30.8 次探测 / 13 源,且 0 次 no_signal——每次都在有效收缩,但次数仍偏多 |
−150 ~ −250 s |
| 第四问路由有 20% 空间,但那是被定位/清除绕行"拖"出来的 | 离线最优 4998 s vs 实测移动 6257 s(20.1%);而覆盖点巡回的投影顺序 4365 s 已接近离线 31 点最优 4181 s(+4.4%) | −400 ~ −700 s |
| 第四问最大单点是定向源定位失败导致的后备盲清 | 平均每局 131 次清除只有 13 次成功,fallback_clear_attempts=125.7,清除动作 419 s + 清除段移动 798 s ≈ 1220 s/局(14% T) |
−800 ~ −1100 s |
| 第四问第二点是探测本身 | 平均 69 次探测 ≈ 2224 s/局(26% T),其中 32 s/次的移动占 1880 s | −400 ~ −800 s |
| 覆盖点集已经最小,不要再压 | 27 点方案在 75 m/24 档"通过",但在 25 m/48 档有 298 个 (p,h) 缺口 → 是采样过拟合的假解;在细网格上直接搜索的最小命中集仍是 31 点 | 0(见 §5.1 的正确性风险) |
一句话:第三问的目标是"把 30.8 次探测压到 ~26 次并把序排到最优",第四问的目标是 "把 125 次盲清变成 3 次有保证的探测"。 两者都是 DP / 序贯决策问题, 不是经典的 TSP 排线问题。
1. 目标函数的图论化
题面计时模型(config.CostConfig,已由 evaluation.recompute_virtual_time 逐微秒复算验证):
T = L/5 + 5·N_measure + 1·N_switch + 5·N_clear⁺ + 3·N_clear⁻
把它写成图上的路径代价,后面所有算法都在这张图上做:
- 节点 = 一次"停靠"(覆盖站点、定位测点、清除点);
- 边权
w(a,b)=dist(a,b)/5(移动秒); - 节点服务费 =
5·(该点要测的频道数) + 1·(换频次数)或5/3(清除)。 - 于是整局 = 一条开放路径(起点原点、终点自由),目标是最小化
Σ边权 + Σ服务费 + Σ动作惩罚。
四类图问题分别对应四个子决策:
| 子决策 | 图问题 | 现役做法 | 目标做法 |
|---|---|---|---|
| 站点/任务排序 | 开放 TSP(小 n 精确) | NN + 2-opt(滚动) | Held-Karp 精确 DP(n ≤ 14,含换频状态) |
| 定位测点选择 | 带邻域的 TSP / 定向问题(TSPN/OP) | 每任务独立选点 + 全表重排 | 覆盖骨架 + 最便宜插入;测点作为"邻域"参与联合优化 |
| 定向源定位 | POMDP / 随机最短路 | 一步贪心 prob_detect/时间 |
2–3 步 rollout,值函数 = 期望后验 MEC 半径 |
| 后备清除 | 区域覆盖路径(Covering Path) | 格心最近邻 | 割草机 + 转向点 DP / 格心集 Or-opt |
2. 本轮实测基线(现役代码,冻结场景)
场景集:harness/suites.py,第三问 core 的 seed 100–105 × 13 源;
第四问 core 全部 9 场(10/13/16 源 × 3 定向占比)。配置为现役默认。
2.1 第三问(bayes,13 源,6 场)
| 指标 | 数值 |
|---|---|
| 平均虚拟时间 | 3197 s |
| 移动 | 12292 m = 2458 s(77%) |
| 覆盖点检测 | 83.5 次 = 501 s(其中 69.8 次 no_signal,属缺席证明) |
| 定位探测 | 30.8 次 = 185 s(0 次 no_signal) |
| 清除动作 | 65 s |
| 离线最优开放回路(同一批作业点) | 2308 s |
| 路由可回收 | 151 s(移动的 6.1%,T 的 4.7%) |
| 作业点数(去重) | 35–50 |
2.2 第四问(directional + q4_mincover_v1,9 场)
| 指标 | 数值 |
|---|---|
| 平均虚拟时间 | 8676 s |
| 移动合计 | 6257 s(72%) |
| ├ 覆盖段移动 | 3579 s |
| ├ 探测移动 | 1880 s |
| └ 清除移动 | 798 s |
| 动作耗时 | 2149 s(覆盖 1386 / 探测 344 / 清除 419) |
| 探测次数 | 69.0 次(no_signal 4–12 次) |
| 清除次数 / 成功 | 131.1 / 13.0 → 118 次失败 |
fallback_clear_attempts |
125.7 次/局 |
| 后备盲清格数(单次) | 3 ~ 210 格,全部以 cleared 结束 |
| 离线最优开放回路(同一批作业点) | 4998 s |
| 路由可回收 | 1259 s(移动的 20.1%,T 的 14.5%) |
| 覆盖投影顺序 vs 离线 31 点 2-opt | 4365 s vs 4181 s(+4.4%) |
2.3 成本地板估计
| 问题 | 不可压缩部分 | 现状 | 真实可压缩 |
|---|---|---|---|
| 第三问 | 七点环 1392 s + 覆盖检测 501 s + 清除动作 65 s + 每源必经的接近/清除移动 + 每源 ≥2 次探测 | 3197 s | ~300–450 s(10–14%) |
| 第四问 | 31 点巡回 ~4180 s + 缺席检测 ~1386 s + 每源 ≥3 次探测与一次清除 | 8676 s | ~2000–2800 s(23–32%) |
第四问的 4000 s 验收线依然不可达(单是 31 点巡回 + 缺席检测就 ≈5566 s), 这与前置文档 §6.2 的结论一致;本方案只承诺把 8676 s 压向 6500 s 量级。
3. 算法设计
3.1 D1(第四问最高优先):定向源的"抵近 + 交会"滚动时域 DP
问题本质:±1° 示向度误差在距离 d 处给出的横向不确定度约 d·tan(1°) ≈ 0.0175 d。
d = 1000 m 时单条方位线的横向约束只有 ±17.5 m;两条方位线的交会角 θ 决定最终尺度
≈ 0.0175 d / sin θ。要压到 20 m 清除证书,必须同时满足:交会角大、距离近。
现役 _visibility_probe 只最大化 prob_detect(q)/(移动+6),天然偏好"近且可见",
与"交会角大"无关;远距离又永远收敛不到 20 m,于是退化到 20 m 网格盲清。
形式化(这就是一个 POMDP):
- 状态
b=JointBelief(位置 × 24 档朝向的可行集,见belief/joint.py), 再叠加r_eff ~ U[1000,1500]的不确定度; - 动作
q∈ 候选测点(保证接收点 ∪ 对跖点 ∪ 三圈环探 ∪ 朝 MEC 圆心的抵近点); - 观测
o ∈ {direction, near, no_signal},由每条粒子(p, h, r_eff)解析预测; - 代价
c(q) = 6 s + dist(pos,q)/5; - 终止:
MEC(b).radius ≤ 20 − margin(可一次清除); - 值函数:
V(b) = min_q E_o[ c(q) + V(b') ]。
实现选择(按代价递增):
- 一步期望后验半径(最小改动,复用 Q3 已有内核的二维推广):
对候选
q,按粒子权重模拟三分支结果,用幸存子集的 MEC 半径近似V(b'), 取E[radius] + λ·c(q)最小者。把particles.py::expected_posterior_radius的向量化实现在JointBelief上重写一份(numpy 可用时广播)。 - 2–3 步 rollout:对前 K=8 个候选各展开一层,深度 2;墙钟预算 ≤ 0.3 s/决策。
- 交会角代理(解析、零墙钟):若一步法来不及落地,先用
score(q) = −E[radius] · sin(Δbearing(q, 既有方位线)) / dist(q, center)的确定性代理,实验证明有效后再换 rollout。
关键结构性改动:把候选点集从"绕 MEC 的固定环"扩展为含抵近点,
即允许 q 落在 center + α·(pos − center) 上、α 从 0.6 到 1.0 采样。
这样当远距离无法收敛时,策略会主动抵近并以一次正常角域证书收尾,
而不是把 200 格盲清当作唯一出路。后备清除保留为安全网,但目标是触发次数下降 ≥ 80%。
验收:fallback_clear_attempts ≤ 15/局(现 125.7);定向频道平均探测次数
≤ 全向频道的 1.5 倍;清除成功率 ≥ 90%;9 场景全清率 100%。
预期:−800 ~ −1100 s。
3.2 D2:覆盖骨架 + 最便宜插入(TSPN 的在线近似)
问题本质:31 个覆盖点是必须在场的(缺席证明),但探测点与清除点是
临时产生的。现役做法把两类点混在一张任务表里,每次从零做 NN + 2-opt
(bayes_loop._order_tasks),等于让临时任务把骨架顺序"打散"。
实测投影顺序 4365 s vs 离线最优 4181 s,说明骨架顺序本身没坏,
坏在绕行开销——而绕行开销正是插入位置没优化。
形式化:这是 TSP with Neighborhoods / Generalized TSP:
- 骨架:离线求覆盖点集的近优开放回路
S(7点用解析证明;31点用 Or-opt/3-opt,n ≤ 16时可直接 Held-Karp 精确); - 在线:给定当前任务
q与其邻域(clear任务的邻域是C₂₀(K),locate任务的邻域是候选测点集),求Δ(i,j) = dist(a_i, q) + dist(q, a_{j}) − dist(a_i, a_j)最小的插入位置(i,j);这正是"图上的最便宜插入",O(|S|²)每任务。
实施:
guarantee/cover.py增加optimize_tour(points, seed_tour, passes)(Or-opt + 2-opt), 把nn_tour_m从"上界"变成"已优化值",并写入证书tour_virtual_s。planner/bayes_loop.py新增_skeleton(覆盖点顺序)与_insert_task(task, neighborhood);_order_tasks退化为"骨架遍历 + 已插入任务",保留现有 2-opt 作为兜底开关。clear任务的邻域用C₂₀(K)内离插入点最近的点(见 3.4),使插入代价与 清除目标联合最小。
验收:第四问移动 ≤ 5000 s(现 6257 s);路由相对离线最优的 gap
(新增回归指标 route_gap_vs_offline)从 20.1% 降到 ≤ 10%。
预期:−400 ~ −700 s。
3.3 D3:后备清除的覆盖路径(若 D1 后仍触发)
后备清除是"用 20 m 圆盘覆盖残差区域 R 直到命中真源"——即 Covering Path Problem。
- 当前
_fallback_clear对格心做 nearest-first 扫描,等价于格心集上的 NN 开放路径, 典型约为最优的 1.2–1.3 倍; - 改进:对格心集做 Or-opt + 2-opt(
k ≤ 400,O(k²)一次约 0.1 s,且只在 极少数局触发); - 上界更优解:凸区域上的割草机(boustrophedon)扫描,用 DP 在扫描线方向选择 转向点可精确最优;对一般多边形用梯形分解 + DP。
验收:后备触发时移动 ≤ 现值的 80%(单次);触发次数本身由 D1 压到 ≤ 15/局。 预期:−100 ~ −200 s(D1 未完全消除时的兜底)。
3.4 T1/T3:第三问的精确排线、换频 DP 与清除点选择
(a) Held-Karp 精确任务序(含换频状态)
现役 _two_opt 是启发式且被 4 轮上限截断。任务表典型只有 6–12 项,
可以精确求解:
dp[S][j][c] = 已访问任务集 S、停在任务 j、测向频道为 c 的最小代价
转移:dp[S∪{k}][k][c'] = dp[S][j][c] + dist(pos_j, pos_k)/5 + service(k, c, c')
- 规模:
|T| ≤ 12时2^12 × 12 × 20 ≈ 1.0M状态,纯 Python 约 0.1–0.3 s/次; 滚动重排每步一次会吃掉预算,因此只在任务表新增/删除任务时重解, 或在|T| ≤ 9时默认启用、否则回退 2-opt + Or-opt。 - 换频代价精确化:
service依赖进入/离开频道,把c并入状态即可精确; 现役_path_cost用"按频道排序"的贪心近似,会低估/高估 1–3 s/站。 - 附图论下界:对当前点集算 MST 权重(
O(n²)Prim), 得到开放路径最优值的下界,写入summary.route_lower_bound_s, 用于在线后悔值审计与回归("本步排序距最优 ≤ x%")。
验收:route_gap_vs_offline ≤ 3%;单局墙钟增量 ≤ 0.2 s。
预期:−120 ~ −200 s。
(b) 探测的 2 步 rollout(T2)
现役 _select_point 是一步贪心(期望 log 幸存占比 + λ·移动)。
把它扩成深度 2 的 rollout:对前 K=8 个候选,各展开一次测量的三分支
(direction / near / no_signal),取 E[V] 最小者。
V 沿用现有 expected_survival。这属于滚动时域 DP,不改任何安全性判定。
验收:探测次数 30.8 → ≤ 26;墙钟 ≤ 0.3 s/决策。 预期:−150 ~ −250 s。
(c) 清除点选在 C₂₀(K) 内离当前位置最近处(T3)
C₂₀(K) = ∩_{g∈K} B(g, 20) 是凸集(圆盘之交)。求其内离当前点最近点是一个
凸可行性/投影问题(对小规模可枚举多边形顶点 + 圆盘投影,或直接迭代投影)。
现役 _near_clear_target 只沿一维方向平移,与最优之差 ≤ 0.74 m(前置文档 P1-1 已复核),
收益主要来自与 3.2 插入代价的耦合:先定插入位置、再选清除点,比反过来省更多。
验收:清除段移动下降 ≥ 5%。 预期:−50 ~ −150 s。
(d) 七点环半径(T4):1159.7 → 1122.9(可证明下界),−44 s。
仅作为"证明性"改动落地,不作为收益项。
4. 实施路线
| 阶段 | 内容 | 交付物 | 验收门槛 | 依赖 |
|---|---|---|---|---|
| S0 基线冻结(0.5 天) | 把近期 sweep 的最优参数(route_aware_probe=false、lambda_move_s≈0.06、opportunistic_radius_ratio≈0.4–0.5)回填为基准,跑满 core+boundary 并归档 |
output/suite/q3-baseline、q4-baseline |
现有 valid 口径 100% |
无 |
| S1 度量补全(0.5 天) | 在 scripts/run_suite.py 增加 route_gap_vs_offline、route_lower_bound_s、distinct_service_points、coverage_actual_visited 四列 |
runner 改动 + 回归 | 与本文 §2 实测复现一致 | S0 |
| S2 覆盖证书硬化(1 天,正确性优先) | 证书分辨率 75 m/24 → 20 m/72;设计裕量 r_design ≤ 960 m 或细网格直接搜索;保留 10% 保险点预算 |
guarantee/cover.py、plans/*.json、正/负例测试 |
细网格(15 m/72)缺口 = 0;故意删点必须被检出 | S1 |
| S3 第四问 D1(2–3 天) | belief/joint.py 增加期望后验半径 / rollout 选点;planner/__init__.py::_probe_candidates 增加抵近点;后备降级为安全网 |
belief/joint.py、planner/__init__.py、测试 |
fallback_clear_attempts ≤ 15;全清 100%;墙钟 ≤ 1.0 s/局 |
S2 |
| S4 第四问 D2/D3(2 天) | 覆盖骨架 + 最便宜插入;C₂₀ 邻域;后备 Or-opt |
planner/*、guarantee/cover.py |
移动 ≤ 5000 s;route_gap ≤ 10% |
S3 |
| S5 第三问 T1/T2/T3(2 天) | Held-Karp(含换频)+ MST 下界;探测 2 步 rollout;C₂₀ 最近点 |
planner/bayes_loop.py、plan/* |
探测 ≤ 26;route_gap ≤ 3%;T ≤ 2900 s |
S1 |
| S6 收口(1 天) | 全量配对、论文数据表、消融图 | 报告 + docs/paper 数据 |
与 S0 配对全部 valid,无退化场景 |
S4/S5 |
顺序约束:S1(度量)先于任何算法改动,否则"更快"不可证;S2(证书)先于 第四问算法改动,否则可能在错误的安全基线上做优化。
5. 风险与明确不做的部分
5.1 本轮发现的正确性风险(必须先处置)
现役 q4_mincover_v1(31 点)与 square49(49 点)在粗采样下缺口为 0,
但把校核分辨率从 75 m/24 档提到 25 m/48 档:
| 点集 | 点数 | 75 m/24 缺口 | 25 m/48 缺口 | 15 m/72 缺口 | 最坏命中@75 m | 最坏命中@25 m |
|---|---|---|---|---|---|---|
square49 |
49 | 0 | 0 | 0 | 760.3 m | 760.3 m |
q4_mincover_v1(现役) |
31 | 0 | 125 | 566 | 999.1 m | 1000.0 m |
| 细网格重搜最小集 | 31 | 0 | 0 | 35 | 983.0 m | 996.2 m |
| 贪心 27 点(75 m 档最优) | 27 | 0 | 298 | 1117 | 986.5 m | 1000.0 m |
结论:
- 31 点很可能就是实际下界附近:多起点随机贪心 + 冗余剪枝在 25 m/48 细网格上 直接搜索的最小解仍是 31 点(尚未做 LP 松弛下界,但连贪心都下不去); 之前看到的 27 点是采样过拟合的假解,不可采纳;
q4_mincover_v1的安全裕量几乎为 0(999.1 m),存在"真源恰落在细缝 +r_eff取下界" 的漏检窗口,现役测试没暴露是因为随机场景未命中细缝且r_eff通常 > 1000;square49裕量充足但巡回 36.4 km,不可回退;- 正确做法是细网格重搜 + 设计裕量(S2),代价约 0–150 s,先保安全再谈提速。
5.2 其他风险
| 风险 | 影响 | 缓解 |
|---|---|---|
| POMDP rollout 墙钟超预算 | 单局计算 > 1 s | 深度 2、候选截断 K=8、--profile 纳入基准必报列;超预算自动退回一步法 |
| Held-Karp 状态爆炸(任务表变长) | 单步计算抖动 | 仅在 ` |
| 抵近点破坏可见性保证 | 探测反而 no_signal 变多 |
抵近点仍以 prob_detect > 0 过滤;no_signal 是合法负观测,不破坏守恒性 |
| 骨架插入与"找全即停"冲突 | 为走骨架而多绕行 | 骨架只提供顺序,不新增必须访问的点;任务表为空即停 |
| 细网格证书重搜耗时 | 离线 3–5 min | 一次性离线搜索 + 运行期按计划名缓存校验(沿用 load_plan lru_cache) |
5.3 明确不做
- 不重引入 PPO/HRL(前置文档已用 109 776 步的负面结果排除);
- 不引入新的运行时依赖(仍只有
requests;numpy仅作可选加速后端,networkx/scipy不进入运行时路径); - 不改变停止条件(
unresolved_channels的口径取舍属于评分方式问题, 须先与题面评分方式核对,本轮不作为默认行为); - 不承诺第四问 4000 s(成本地板 ≈5566 s,见 §2.3)。
6. 验收与度量
6.1 有效性定义(沿用,不得放宽)
valid := 全部真源被清除 ∧ 缺席频道与真值一致 ∧ 正常 /exit
∧ 零算法异常 ∧ 逐微秒计时复算一致
6.2 新增必报列(写入 scripts/run_suite.py 逐局行与 aggregate)
| 列 | 定义 | 用途 |
|---|---|---|
route_gap_vs_offline |
实测移动 − 离线最优开放回路(同作业点集) / 实测移动 |
区分"排线不够好"与"点选得不对" |
route_lower_bound_s |
当前任务集 MST 权重 / 速度 | 在线后悔值审计 |
distinct_service_points |
去重作业点数 | 探测是否真的在减少 |
coverage_actual_visited |
实际测过的覆盖点数 | 缺席证明是否提前结束 |
probe_no_signal_ratio |
探测中 no_signal 占比 |
D1 的效果指标 |
fallback_clear_attempts |
已有 | D1 的主验收指标 |
6.3 目标(vs §2 基线)
| 指标 | Q3 现 | Q3 目标 | Q4 现 | Q4 目标 |
|---|---|---|---|---|
| core 平均虚拟时间 | 3197 s | ≤ 2900 s | 8676 s | ≤ 6500 s |
| 移动 | 2458 s | ≤ 2250 s | 6257 s | ≤ 5000 s |
| 探测次数 | 30.8 | ≤ 26 | 69.0 | ≤ 45 |
| 后备盲清次数 | 0 | 0 | 125.7 | ≤ 15 |
route_gap_vs_offline |
6.1% | ≤ 3% | 20.1% | ≤ 10% |
fallback 清除成功率 |
— | — | 10% | ≥ 90% |
| 单局计算墙钟 | 1.0 s | ≤ 1.2 s | 1.0 s | ≤ 1.5 s |
| 细网格证书缺口(15 m/72) | — | 0(Q3 解析) | 566 | 0 |
6.4 回归
uv run pytest(当前 232 项)必须全过;新增:
CoveragePlan细网格正/负例(删掉任一点必须被检出);JointBelief的期望后验半径与真源保留性质对拍(随机(p,h)× 随机观测序列);Held-Karp与2-opt在同一小任务集上的最优性对拍(DP 结果必须 ≤ 2-opt);C₂₀投影的三角不等式性质(投影点距候选集任一点仍 ≤ 20);- 逐位一致性:numpy 与纯 Python 两条路径在同一动作序列下
actions_sha256相同。
7. 复现命令(本轮实测)
# 度量基线(§2.1/§2.2/§2.3):作业点分解 + 离线最优回归 + 成本地板
uv run python /tmp/analyze_headroom.py # 路由 gap:Q3 6.1%,Q4 20.1%
uv run python /tmp/decompose.py # Q4 三段移动 + 动作 + 清除成功率
uv run python /tmp/q3stats.py # Q3 探测/覆盖检测/跳测统计
# 覆盖证书分辨率(§5.1)
uv run python /tmp/verify_margin.py # 现役 31 点在 25 m/48 档缺口 125
uv run python /tmp/hitset_fine.py # 细网格最小解仍是 31 点
# 既有常驻工具
uv run python scripts/run_suite.py --problem 4 --suite all --jobs 6 \
--variants directional@q4_mincover_v1 --label q4-baseline
uv run python scripts/verify_q4_cover.py --out output/q4/cover-certificate.json
uv run python scripts/analyze_run_timing.py <log.jsonl>
上述
/tmp/*.py为一次性分析脚本,S1 阶段应把其中的route_gap_vs_offline、offline_opt_open_path、mst_lower_bound三个函数并入scripts/run_suite.py(或新建scripts/analyze_routing.py)常驻入库, 使"虚拟时间花在哪"与"覆盖集是否合法"一样成为可随时重跑的回归项。
8. 本轮实测回填(2026-09-12 实施结果)
本节记录 S1–S5 全部落地后的实测结果与负面结论。所有数字均为冻结基准集
(harness/suites.py)配对复跑,口径与 §6.1 完全一致;复现命令见 §8.6。
8.1 交付物清单
| 项 | 位置 | 状态 |
|---|---|---|
| 图论/DP 工具箱(精确开放路径、2-opt/Or-opt、MST 下界、路由度量) | src/mcm26b/routing.py |
✅ 新增 |
S1 必报列(route_gap_vs_offline、route_lower_bound_s、distinct_service_points、coverage_actual_visited、probe_no_signal_ratio、plan_verify_wall_s) |
scripts/run_suite.py |
✅ 新增 |
| S2 设计裕量覆盖计划 + 细网格证书 + 精细剪枝 | guarantee/cover.py、scripts/verify_q4_cover.py、plans/q4_mincover_v2.json |
✅ 新增并设为默认 |
| S3/D1 期望后验半径值函数 + 可见性过滤 + 抵近点 | belief/joint.py、planner/__init__.py |
✅ 新增(默认口径见 §8.3) |
| S4/D3 后备清除路径改进 | planner/__init__.py::_fallback_order |
⚠️ 已实现,实测负收益,默认关闭 |
| S5/T1 Held-Karp 精确任务序(含换频状态) | planner/bayes_loop.py::_exact_order |
⚠️ 已实现,实测负收益,默认关闭 |
| 回归测试 | tests/test_routing.py、tests/test_joint_belief.py、tests/test_coverage_plan.py |
✅ 新增,uv run pytest 268 项全过 |
8.2 最终成绩(vs S0 基线)
| 指标 | Q3 基线 | Q3 现 | Q4 基线 | Q4 现 | 目标 |
|---|---|---|---|---|---|
| core 平均虚拟时间 | 3210.3 s | 3188.7 s(−0.7%) | 8676.1 s | 8602.0 s(−0.9%) | 2900 / 6500 ✗ |
| core 最大虚拟时间 | 3798.5 s | 3663.7 s(−3.5%) | 10890.8 s | 9630.4 s(−11.6%) | — |
| 移动 | 12446.8 m | 12338.1 m(−0.9%) | 31286.4 m | 32891.1 m(+5.1%) | 2250 / 5000 ✗ |
| 检测次数 | 111.0 | 111.1 | 346.0 | 333.7 | — |
| 后备盲清次数 | 0 | 0 | 125.7 | 4.3(−96.6%) | ≤15 ✅ |
route_gap_vs_offline |
8.67% | 8.07% | 18.9% | 24.3% | ≤3% / ≤10% ✗ |
| 单局计算墙钟 | 1.29 s | 1.04 s | 5.29 s | 4.09 s | ≤1.2 / ≤1.5 ⚠️ Q4 超标 |
| 覆盖计划运行期校验 | — | 0.42 s | — | 4.80 s(15 m/72 一次性) | — |
| 细网格证书缺口(15 m/72) | — | 0(解析) | 566 | 0 | 0 ✅ |
| 有效局 | 18/18 | 20/20(含边界) | 9/9 | 11/11(含边界) | 100% ✅ |
结论:本轮的硬收益是第四问后备盲清被消除(125.7 → 4.3 次/局,最坏局 10890.8 → 9630.4 s)与覆盖证书的正确性(细网格缺口 566 → 0);虚拟时间只有 0.7–0.9% 的均值改善(中位 −2.0%),远未达到方案 §6.3 的目标。 第三问的改善落在噪声内(中位相对变化 0.0005)。§2 的成本地板估计(Q3 可压缩 10–14%、Q4 23–32%)过于乐观,实测只回收了约 1%。
8.3 定向源探点(D1):先负后正,最终只保留"可见 + 就近"
D1 的完整实现(期望后验 MEC 半径值函数 + 抵近点 + 遮挡点剔除)在修正联合 信念朝向规则之前配对为:后备 125.7 → 53.8 次,但探测移动 +5.6 km,虚拟时间 8676 → 9411 s(净负)。原因有两个:
- 后备清除在命中真源时立即结束,"整条路径最短"不是它的目标函数, §3.2/§3.3 的插入代价模型在这里并不成立;
- 更关键的是:联合信念的
no_signal朝向规则被写反了(§8.4),prob_detect/ 期望半径因此系统性地高估"被遮挡点可见",选点必然跑偏。
修正后重测(9 场景 core):
probe_score_mode |
λ | 后备次数 | T 均值 | 移动 | 计算墙钟 |
|---|---|---|---|---|---|
visibility(旧) |
— | 125.6 | 9224.6 s | 33595 m | 11.6 s |
expected_radius |
0.05 | 6.8 | 9740.5 s | 38824 m | 9.6 s |
expected_radius |
5.0 | 4.3 | 8604.3 s | 32893 m | 3.7 s |
nearest_visible(默认) |
— | 4.3 | 8602.0 s | 32891 m | 3.4 s |
λ 越大越优说明本题的探点问题里"看得见且少走路"比"单步信息量最大"更重要; λ→∞ 的极限(可见候选中移动最省)就是默认口径。值函数代码与其对拍测试保留, 供后续研究(例如配合真正的多步 rollout)。
8.4 本轮发现的正确性缺陷(已修复)
belief/joint.py 的 no_signal 朝向裁剪规则反向:keep=False 分支用了
"确定覆盖"掩码做交集,等价于保留"必然看得见"的档、删掉"确定看不见"的档;
keep=True 分支又漏计了格内角裕量 asin(margin/max(dist−margin,1))。
两者都会删掉真源的朝向档(tests/test_joint_belief.py::test_true_source_survives_consistent_observations
在随机观测序列上直接复现)。修复后:
keep=False 改用 _far_mask(与 _cover_mask 互补)并把距离阈值收紧为
r_eff_min − margin,keep=True/False 都计入格内角裕量。
修复本身是净成本:在旧 visibility 探点口径下 Q4 core 由 8676 → 9225 s;
换成 §8.3 的新探点口径后回落到 8602 s,同时后备清除降 96.6%。
换言之,本轮第四问的成绩改善主要来自"修好信念 + 换探点口径"这一组合,
而不是 §3 预期的插入/排线优化。
8.5 覆盖证书硬化(S2)
现役 q4_mincover_v1(31 点)在粗采样(75 m/24)下缺口 0,但细网格复检:
| 点集 | 点数 | 25 m/48 缺口 | 20 m/72 缺口 | 15 m/72 缺口 | 最坏命中 | NN 巡回 |
|---|---|---|---|---|---|---|
q4_mincover_v1(旧) |
31 | 125 | 336 | 566 | 1000.0 m | 22.9 km |
q4_mincover_v2(默认) |
31 | 0 | 0 | 0 | 990.0 m | 23.9 km |
| 严格连续空间证书备选 | 36 | 0 | 0 | 0 | 973.7 m | 25.4 km |
q4_mincover_v2 的生成方式:搜索分辨率 50 m/48 档、设计裕量 r_design=965 m、
前向角裕量 5°,再做证书分辨率(15 m/72)精细剪枝(每次删点都用同一证书口径
复核),因此点数与旧计划相同而缺口归零,没有付出点数代价。
严格连续空间界需要
r_verify + 15·√2/2 ≤ 1000(即 ≤989.4 m)且角裕量 ≥2.5°; 满足该条件的 36 点方案最坏命中 973.7 m,但代价 +5 点(约 +1000 s), 已落盘为output/q4/cover-certificate-v3.json备用。默认方案在 15 m/72 采样下最坏 990.0 m,与严格界的差 0.65 m 属采样边界效应,作为已知残余风险登记。
8.6 负面结论与复现命令
| 优化项 | 实测 | 结论 |
|---|---|---|
| S4/D3 后备清除 Or-opt | 后备失败 125.7 → 161.4 次(T 8676 → 8940 s) | ❌ 目标函数错位:命中即停,路径最短反而把真源推后 |
| S5/T1 Held-Karp 精确任务序 | 3203.2 s vs 2-opt 3193.1 s(18 场景) | ❌ 滚动时域下"当前任务表逐位最优"反而略差;默认 0 |
route_aware_probe |
3210.3 s vs 关闭 3193.1 s | ❌ 权重 1e-3 的路线项无净收益;默认关闭 |
| Q4 融合巡回(站点顺带定位) | 12711 s vs 10809 s | ❌ 与 P0-1 在第三问的负面结论一致 |
opportunistic_radius_ratio |
0.65 → 0.5:3210.3 → 3205.4 s | ✅ 采纳(弱收益) |
# S1 度量基线(含路由 gap / MST 下界 / 作业点/静默率)
uv run python scripts/run_suite.py --problem 4 --suite core --jobs 6 \
--variants directional --label q4-baseline --out output/suite
uv run python scripts/run_suite.py --problem 3 --suite core --jobs 6 \
--variants bayes --label q3-baseline --out output/suite
# S2 覆盖证书(生成 + 细网格校核;--fine-prune 走证书分辨率剪枝)
uv run python scripts/verify_q4_cover.py --spacing 100 --radius 2850 \
--target-step 50 --headings 48 --design-radius 965 --heading-margin 5 \
--verify-step 15 --verify-headings 72 --fine-prune \
--write-plan q4_mincover_v2 --out output/q4/cover-certificate-v2.json
# S3/D1 口径配对(可见性/值函数/极限三档)
uv run python scripts/run_suite.py --problem 4 --suite core --jobs 6 \
--variants "directional#search.probe_score_mode=visibility,\
directional#search.probe_score_mode=expected_radius;search.probe_lambda_move_s=5,\
directional#search.probe_score_mode=nearest_visible" --label q4-probe-ab
# 回归
uv run pytest -q # 268 项
8.7 仍未达标项的处置建议
| 未达标 | 差距 | 建议 |
|---|---|---|
| Q3 ≤2900 s | −9% | 已无低风险空间:七站巡回 1392 s + 覆盖检测 501 s + 每源 ≥2 次探测是成本地板;需要改停止条件或覆盖语义才能继续下降 |
| Q4 ≤6500 s | −24% | 31 点巡回 + 缺席检测 ≈5566 s 是地板,与 §2.3 一致;只能改"逐频道缺席证明"口径 |
route_gap Q4 24.3% |
— | 该指标在"作业点数随决策变化"时口径不稳(本方案把后备格换成探测点后作业点从 206 降到 110);建议改为"覆盖骨架段"与"临时任务段"分别报 gap |
| Q4 计算墙钟 4.1 s(目标 1.5 s) | 2.7 s | 热点在 belief 凸多边形与 select_measurement_point(D1 之前的基线即 5.3 s),属 P0-4b 表示层张量化,与本方案无关 |
| 严格连续空间覆盖证书 | 0.65 m | 若要正式采用 36 点严格方案:--verify-radius 989 --verify-heading-margin 2.5,代价约 +1000 s |