去敏感提交
This commit is contained in:
@@ -1,191 +0,0 @@
|
||||
# 2026 高教社杯 B 题(无线电干扰源快速自动定位与清除)问题 3、4 相关论文列表
|
||||
|
||||
> 排序原则:与问题 3/4 直接应用方案越相关,排名越靠前。
|
||||
> 标注:【Q3】主要支撑问题 3(全向干扰源:搜索→交会定位→逼近清除的整体策略);【Q4】主要支撑问题 4(定向干扰源、方向未知);【Q3·Q4】两者通用。
|
||||
|
||||
---
|
||||
|
||||
## 一、无线电信号源的移动机器人搜索与定位(与赛题任务框架最直接对应)
|
||||
|
||||
1. **Simultaneous Localization of Multiple Unknown and Transient Radio Sources Using a Mobile Robot** 【Q3】
|
||||
D. Song, C. Y. Kim, J. Yi. *IEEE Transactions on Robotics*, 2012(被引 75)
|
||||
移动机器人沿路径采集 RSS,在线同时定位**多个未知无线电源**——与问题 3“干扰源个数未知、机器狗边走边测”的设定几乎同构,可直接借鉴其多源数据关联与定位框架。
|
||||
https://ieeexplore.ieee.org/abstract/document/6145760/ | [PDF](http://coewww.rutgers.edu/~jgyi/pdfs/IEEE_TRO_2012.pdf)
|
||||
|
||||
2. **Cooperative Search of Multiple Unknown Transient Radio Sources Using Multiple Paired Mobile Robots** 【Q3】
|
||||
C. Y. Kim, D. Song, Y. Xu, J. Yi, X. Wu. *IEEE Transactions on Robotics*, 2014(被引 67)
|
||||
上文的协同多机器人版本:成对机器人搜索多个未知瞬态无线电源,含**源匿名(信号不可区分)**处理——对应本题不同频道区分信号的思路对照。
|
||||
https://ieeexplore.ieee.org/abstract/document/6857360/ | [PDF](https://jingangyi.rutgers.edu/pdfs/IEEE_TRO_2014.pdf)
|
||||
|
||||
3. **RSS Gradient-Assisted Frontier Exploration and Radio Source Localization** 【Q3·Q4】
|
||||
J. N. Twigg, J. R. Fink, L. Y. Paul, B. M. Sadler. *ICRA*, 2012(被引 77)
|
||||
用 RSS 梯度引导前沿探索(frontier exploration),让机器人高效逼近信号源而避免盲目遍历——可直接支撑问题 3/4 中“初探→逼近”的两阶段搜索策略设计。
|
||||
https://ieeexplore.ieee.org/abstract/document/6225059/
|
||||
|
||||
4. **Radio Source Localization Using Sparse Signal Measurements from Uncrewed Ground Vehicles** 【Q3】
|
||||
A. Perera, V. P. Tran, S. Anavatti, K. Kasmarik, et al. *arXiv:2312.03493*, 2023
|
||||
地面无人车(与机器狗同类平台)在室外区域以稀疏采样定位无线电源,含完整仿真评估流程——与用模拟器演练测试的实验设计直接可参照。
|
||||
https://arxiv.org/abs/2312.03493 | [PDF](https://arxiv.org/pdf/2312.03493)
|
||||
|
||||
5. **Particle Filter Based Localization of Access Points Using Direction of Arrival on Mobile Robots** 【Q3·Q4】
|
||||
R. Parashar, R. Parasuraman. *IEEE VTC*, 2020(被引 13)
|
||||
移动机器人利用**到达方向(DOA,即示向度)**+ 粒子滤波递推定位无线电源——对应本题“多次测向→逐步缩小定位区域”的序贯定位算法。
|
||||
https://ieeexplore.ieee.org/abstract/document/9348813/
|
||||
|
||||
6. **Online Methods for Radio Signal Mapping with Mobile Robots** 【Q3】
|
||||
J. Fink, V. Kumar. *ICRA*, 2010(被引 166)
|
||||
移动机器人边走边在线构建信号场强地图并估计源位置,可支撑本题“场强仅随距离衰减”假设下的快速粗定位与路径在线修正。
|
||||
https://ieeexplore.ieee.org/abstract/document/5509574/
|
||||
|
||||
7. **Distributed Algorithms for Stochastic Source Seeking with Mobile Robot Networks** 【Q3】
|
||||
N. A. Atanasov, J. Le Ny, et al. *ASME JDSMC*, 2015(被引 117)
|
||||
随机源搜索的分布式算法,以无线电源定位为应用背景,理论保证强,可作为逼近清除阶段的收敛性依据。
|
||||
https://arxiv.org/pdf/1402.0051
|
||||
|
||||
8. **Cooperative Multi-Robot Estimation and Control for Radio Source Localization** 【Q3】
|
||||
B. Charrow, N. Michael, V. Kumar. *IJRR*, 2014(被引 84)
|
||||
仅测距射频下的多机器人协同估计与控制,信息论驱动( mutual information )选择测量动作——可迁移为“选哪个频道、去哪测”的决策准则。
|
||||
https://journals.sagepub.com/doi/abs/10.1177/0278364913500542
|
||||
|
||||
9. **A Review of Radio Frequency Based Localisation for Aerial and Ground Robots with 5G Future Perspectives** 【Q3·Q4】
|
||||
M. Kabiri, C. Cimarelli, H. Bavle, et al. *Sensors*, 2022(被引 48)
|
||||
综述:RSS/AOA 等 RF 定位手段在空地机器人上的比较,适合写论文的“研究现状”部分并帮助选型。
|
||||
https://www.mdpi.com/1424-8220/23/1/188
|
||||
|
||||
---
|
||||
|
||||
## 二、测向(Bearing-only/AOA)交会定位与观测点优化(第二检测点选择、定位区域收缩)
|
||||
|
||||
10. **Gathering Bearing Data for Target Localization** 【Q3】
|
||||
H. Bayram, J. Vander Hook, V. Isler. *IEEE Robotics and Automation Letters*, 2016(被引 38)
|
||||
给定若干潜在目标区域与不确定度要求,规划采集方位数据的机器人路径,归结为 **TSP with Neighborhoods 的信息路径规划**——与问题 3“多个待清除目标 + 逐个交会定位 + 总时间最短”的任务排序高度吻合。
|
||||
https://ieeexplore.ieee.org/abstract/document/7390217/ | [PDF](https://conservancy.umn.edu/bitstreams/ff2d34bf-0056-4a29-be84-eb7355b527e4/download)
|
||||
|
||||
11. **Relationship Between Error Ellipse and Error Quadrilateral in Bearing-Only Localization** 【Q3·Q4】
|
||||
B. Wang, Y. Hu, C. Yu, et al. *IEEE Access*, 2026
|
||||
直接研究双站测向定位的**误差四边形**(即题目中的“定位区域”)与误差椭圆的关系,论证几何构型与精度的关系——与问题 1 的定位区域、问题 2/3 的测点选择理论完全对口。
|
||||
https://ieeexplore.ieee.org/abstract/document/11677056/
|
||||
|
||||
12. **Bearing-Only Active Target Localization Strategies for a System of Two Communicating Mobile Robots** 【Q3】
|
||||
J. Vander Hook, P. Tokekar. 技术报告, 2013
|
||||
主动测向定位:规划“去哪测”以最优压缩目标位置不确定性,给出最优双机器人测量构型——第二检测点选择策略的系统性理论。
|
||||
https://conservancy.umn.edu/items/38693c39-7a3b-400b-8926-f9aa194a8824
|
||||
|
||||
13. **Multi-UAV Trajectory Optimization for Bearing-Only Localization in GPS Denied Environments** 【Q3】
|
||||
A. Sciacchitano, L. Mudrik, S. Kragelund, et al. *arXiv:2602.11116*, 2026
|
||||
面向测向定位的轨迹优化,在视场等约束下优化测量构型——可借鉴其代价函数与滚动优化框架设计机器狗的测点序列。
|
||||
https://arxiv.org/abs/2602.11116 | [PDF](https://arxiv.org/pdf/2602.11116)
|
||||
|
||||
14. **Optimal Sensor Placement for Multi-Source AOA Localisation with Distance-Dependent Noise Model** 【Q3·Q4】
|
||||
M. Hamdollahzadeh, R. Amiri, et al. *IET Radar, Sonar & Navigation*, 2019(被引 37)
|
||||
**多源** AOA 定位的最优布点,含递推 CRLB 表示——支撑多干扰源场景下测点位置的全局优化。
|
||||
https://ietresearch.onlinelibrary.wiley.com/doi/abs/10.1049/iet-rsn.2018.5426
|
||||
|
||||
15. **Optimal Sensor Placement for Target Localization Using Hybrid RSS, AOA and TOA Measurements** 【Q3】
|
||||
S. Xu, et al. *IEEE Communications Letters*, 2020(被引 110)
|
||||
混合量测下最小化 tr(CRLB) 的最优传感器-目标几何,可用于论证“交会角接近 90°”等构型结论的严谨性。
|
||||
https://ieeexplore.ieee.org/abstract/document/9097832/
|
||||
|
||||
16. **Geometry Influence on GDOP in TOA and AOA Positioning Systems** 【Q3·Q4】
|
||||
X. Lv, K. Liu, P. Hu. *ICNSC*, 2010(被引 58)
|
||||
基于 CRLB 分析新增观测点对 GDOP 的影响——回答“再加一个检测点值不值、放在哪”的定量依据。
|
||||
https://ieeexplore.ieee.org/abstract/document/5480336/
|
||||
|
||||
17. **定向交叉定位配站问题与定位精度分析**(中文)【Q3·Q4】
|
||||
张艳花. 《电讯技术》, 2008(被引 2)
|
||||
中文文献,专门讨论测向交叉定位的配站(交会角)与精度关系,便于直接引用“交会角 90° 最优、30°~150° 可用”类结论。
|
||||
(《电讯技术》2008 年刊,可通过知网/万方检索全文)
|
||||
|
||||
18. **Trajectory Planning for Multiple Robots in Bearing-Only Target Localisation** 【Q3】
|
||||
C. Leung, S. Huang, G. Dissanayake, et al. *IROS*, 2005(被引 16)
|
||||
早期经典:以定位精度为目标做测向机器人轨迹规划,适合作为主动定位问题的建模起点引用。
|
||||
https://ieeexplore.ieee.org/abstract/document/1545322/
|
||||
|
||||
19. **Observer Path Planning for Bearings-Only Localization Considering Limited Field of View** 【Q3】
|
||||
A. Nayebi Astaneh, N. Pariz, M. O. Naghibi Sistani. *Journal of Control*, 2014
|
||||
考虑传感器视场约束的观测者实时路径规划——对应测向机需旋转天线搜索示向度的过程约束。
|
||||
https://joc.kntu.ac.ir/browse.php?a_id=37&sid=1&slc_lang=en&ftxt=1
|
||||
|
||||
---
|
||||
|
||||
## 三、多目标搜索理论与任务规划(10–16 个未知目标的区域搜索框架)
|
||||
|
||||
20. **Multi-Vehicle Bayesian Search for Multiple Lost Targets** 【Q3·Q4】
|
||||
E. M. Wong, F. Bourgault, T. Furukawa. *ICRA*, 2005(被引 193)
|
||||
多目标贝叶斯搜索经典:概率图 + 贝叶斯更新 + 搜索资源分配——问题 3“干扰源个数未知、需确保全部清除”的终止判据与覆盖率论证可由此构建。
|
||||
https://ieeexplore.ieee.org/abstract/document/1570598/
|
||||
|
||||
21. **MPC-Based Cooperative Multiagent Search for Multiple Targets Using a Bayesian Framework** 【Q3】
|
||||
H. Xiao, R. Cui, D. Xu, Y. Li. *Journal of Field Robotics*, 2024(被引 9)
|
||||
模型预测控制 + 贝叶斯框架的多目标搜索路径规划,滚动时域决策——适合借鉴为本题“边测边重规划”的在线策略。
|
||||
https://onlinelibrary.wiley.com/doi/abs/10.1002/rob.22382
|
||||
|
||||
22. **Multi-Agent Informed Path Planning Using the Probability Hypothesis Density** 【Q3·Q4】
|
||||
J. Olofsson, G. Hendeby, T. R. Lauknes, T. A. Johansen. *Autonomous Robots*, 2020(被引 27)
|
||||
用 PHD(随机有限集)表示**目标个数与位置均未知**的场景并做信息路径规划——与“干扰源总数 10–16 但具体未知”的设定直接对应。
|
||||
https://link.springer.com/article/10.1007/s10514-020-09904-1 | [PDF](https://torarnj.folk.ntnu.no/AURO2020a.pdf)
|
||||
|
||||
23. **Probabilistic Search for Tracking Targets: Theory and Modern Applications** 【Q3·Q4】
|
||||
E. Kagan, I. Ben-Gal. Wiley, 2013(被引 27)
|
||||
搜索论专著:最优搜索策略、马尔可夫决策模型,为搜索策略提供理论根基(Stone 最优搜索理论的应用版)。
|
||||
https://onlinelibrary.wiley.com/doi/abs/10.1002/9781118596593
|
||||
|
||||
24. **Efficient Multi-Robot Search for a Moving Target** 【Q3】
|
||||
G. Hollinger, S. Singh, J. Djugash, A. Kehagias. *IJRR*, 2009(被引 254)
|
||||
多机器人高效搜索路径规划(ESPP)并提出可证明性能的近似算法;本题目标虽静止,其“最大化截获概率”的建模与保证思路可迁移。
|
||||
https://journals.sagepub.com/doi/abs/10.1177/0278364908099853
|
||||
|
||||
---
|
||||
|
||||
## 四、定向干扰源定位(问题 4 特有:覆盖角 180°、方向未知)
|
||||
|
||||
25. **UAV-Based Efficient Joint Estimation of Directional Emitter Position and Transmission Orientation** 【Q4】
|
||||
T. Ruan, Y. Huang, L. Zhou, Q. Wu, et al. *IEEE Wireless Communications Letters*, 2024(被引 2)
|
||||
**联合估计定向发射源的位置与发射方向**(RSS-AOA 混合量测)——问题 4“定向方向未知”的最直接对应文献。
|
||||
https://ieeexplore.ieee.org/abstract/document/10802920/
|
||||
|
||||
26. **Efficient Localization of Directional Emitters via Joint Beampattern Estimation** 【Q4】
|
||||
F. Williams, A. Pemasiri, D. Jayalath, T. Martin, et al. *arXiv:2411.04364*, 2024
|
||||
联合波束方向图估计实现定向发射源高效定位,并分析波束宽度/朝向对定位的灵敏度(CRLB)——可支撑定向源需从侧向多点探测的策略设计。
|
||||
https://arxiv.org/abs/2411.04364 | [PDF](https://arxiv.org/pdf/2411.04364)
|
||||
|
||||
27. **Location Errors of Directional Emitters in AOA System for Non-Line-of-Sight Conditions** 【Q4】
|
||||
J. M. Kelner, C. Ziółkowski, et al. *SPIE*, 2019
|
||||
分析发射天线朝向对 AOA 示向度误差的影响——定向干扰源场景下误差建模的参考。
|
||||
https://www.spiedigitallibrary.org/conference-proceedings-of-spie/11055/110551G/Location-errors-of-directional-emitters-in-AOA-system-for-non/10.1117/12.2525060.short
|
||||
|
||||
28. **ALRD: AoA Localization with RSSI Differences of Directional Antennas for Wireless Sensor Networks** 【Q4】
|
||||
J. R. Jiang, C. M. Lin, F. Y. Lin, et al. *Int. J. of Distributed Sensor Networks*, 2013(被引 133)
|
||||
利用定向天线朝向差分的 RSSI 做定位,对“信号只在 180° 覆盖角内可被接收”的探测盲区分析与补盲路径设计有参考价值。
|
||||
https://journals.sagepub.com/doi/abs/10.1155/2013/529489
|
||||
|
||||
---
|
||||
|
||||
## 五、信息路径规划方法与综述(通用方法库)
|
||||
|
||||
29. **Information-Driven Path Planning** 【Q3·Q4】
|
||||
S. Bai, T. Shan, F. Chen, L. Liu, B. Englot. *Current Robotics Reports*, 2021(被引 53)
|
||||
信息驱动路径规划综述,梳理目标函数(信息增益、熵减)与平台约束,适合搭建问题 3 的总体算法框架。
|
||||
https://link.springer.com/article/10.1007/s43154-021-00045-6
|
||||
|
||||
30. **Adaptive Informative Path Planning in Metric Spaces** 【Q3】
|
||||
Z. W. Lim, D. Hsu, W. S. Lee. *IJRR*, 2016(被引 101)
|
||||
带自适应性的信息路径规划,具次模性与近似保证——为“总时间越短越好”的目标函数设计提供理论工具。
|
||||
https://journals.sagepub.com/doi/abs/10.1177/0278364915596378
|
||||
|
||||
31. **Informative Path Planning for Active Field Mapping Under Localization Uncertainty** 【Q3】
|
||||
M. Popović, T. Vidal-Calleja, J. J. Chung, et al. *ICRA*, 2020(被引 62)
|
||||
不确定性感知的信息路径规划,平衡探索与精度——对应本题“检测耗时 vs 路径耗时”的权衡。
|
||||
https://ieeexplore.ieee.org/abstract/document/9197034/
|
||||
|
||||
32. **基于深度强化学习的短波自主检测与定位方法**(中文)【Q3】
|
||||
冯祺玥, 唐涛, 张昀普, 王鼎, 吴志东. 《通信学报》, 2026
|
||||
中文文献:多站测角交会定位 + 深度强化学习自主检测定位,提供国内无线电监测定位的表述与流程范式。
|
||||
https://www.joconline.com.cn/rc-pub/front/front-article/download/155129217/lowqualitypdf/%E5%9F%BA%E4%BA%8E%E6%B7%B1%E5%BA%A6%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0%E7%9A%84%E7%9F%AD%E6%B3%A2%E8%87%AA%E4%B8%BB%E6%A3%80%E6%B5%8B%E4%B8%8E%E5%AE%9A%E4%BD%8D%E6%96%B9%E6%B3%95.pdf
|
||||
|
||||
---
|
||||
|
||||
### 使用建议
|
||||
- **问题 3 算法主线**:以 1、3、10、20、22 为核心——贝叶斯概率图搜索(20/22)确定探测顺序与终止条件,DOA 序贯定位(5)+ 交会几何优化(10/11/15/17)选测点,RSS 梯度逼近(3)完成 20 m 内清除前逼近。
|
||||
- **问题 4 增量**:在问题 3 框架上叠加 25/26 的“位置 + 方向”联合估计,并用 28 的思路设计覆盖角盲区的补测路径。
|
||||
- **论文写作**:现状综述引用 9、29、32;精度理论引用 11、14、15、16。
|
||||
+20
-64
@@ -1,71 +1,27 @@
|
||||
# docs 索引
|
||||
|
||||
仓库文档分四类:**总览与流程**、**逐问算法**、**验证与对比**、**论文与插图**。
|
||||
阅读顺序建议按下面的表格从上到下。
|
||||
论文本身已完整给出四问的模型、推导与结果分析,因此本目录不再保留算法说明文档,
|
||||
只留下复现所需的说明与材料。
|
||||
|
||||
## 总览与流程
|
||||
|
||||
| 文档 | 内容 |
|
||||
| 入口 | 内容 |
|
||||
| --- | --- |
|
||||
| [`总体思路与流程图.md`](总体思路与流程图.md) | 四问主线、端到端流程图(mermaid)、执行步骤与执行时间速查、交付物与验收锚点 |
|
||||
| [`执行时间与执行步骤.md`](执行时间与执行步骤.md) | 计时模型、会话状态机与动作回合、附件示例逐步推演、实测日志分解、时间预算与安全阀 |
|
||||
| [`B题建模分析与实施计划.md`](B题建模分析与实施计划.md) | 四问建模取舍与 P0–P7 实施计划(最早的设计文档) |
|
||||
| [`协议规则表与状态机.md`](协议规则表与状态机.md) | 指令字段表、结果码、计时模型、状态机(P0 交付) |
|
||||
| [`../README.md`](../README.md) | **总入口**:环境、运行程序、复现论文数据与插图、编译论文 |
|
||||
| [`paper/README.md`](paper/README.md) | 论文工程说明:数据分工、重算与编译步骤、VS Code 配方 |
|
||||
| [`paper/REWRITE_NOTES.md`](paper/REWRITE_NOTES.md) | 论文各轮修订与验证记录(含演练数据重采与问题修复) |
|
||||
| [`paper/main.tex`](paper/main.tex) | 论文 LaTeX 源文件(正文与附录) |
|
||||
| [`paper/data/`](paper/data) | 论文引用的全部数据、宏与整表(由脚本生成) |
|
||||
| [`figures/README.md`](figures/README.md) | 论文插图清单:每张图的数据来源与生成命令 |
|
||||
| [`figures/manifest.json`](figures/manifest.json) | 插图来源清单(可机读) |
|
||||
|
||||
## 逐问算法
|
||||
## 复现顺序
|
||||
|
||||
| 文档 | 内容 |
|
||||
| --- | --- |
|
||||
| [`algo-1.md`](algo-1.md) | 问题一实现口径:半平面交、顶点对直径、直径圆充要判定、MEC 清除证书 |
|
||||
| [`问题一解答.md`](问题一解答.md) | 问题一论文式解答:模型边界、算法可复现步骤、反例构造、演练验证 |
|
||||
| [`algo-2.md`](algo-2.md) | 问题二:候选集 K1、保证接收盘、安全盘 B(c, 1000−a)、最坏后验选点 |
|
||||
| [`algo-3.md`](algo-3.md) | 问题三:三层在线架构、七点解析覆盖、覆盖账本、任务调度与停止条件 |
|
||||
| [`algo-3-bayes.md`](algo-3-bayes.md) | 问题三 `bayes` 策略:网格幸存集滤波、信息增益选点、动态 TSP、Optuna 调参 |
|
||||
| [`algo-4.md`](algo-4.md) | 问题四:`forward_half_disk` 最小命中集、位置×朝向联合信念、后备盲清 |
|
||||
```bash
|
||||
python scripts/build_practice_data.py # 演练局复算 → 宏与表格
|
||||
python scripts/audit_paper_formal.py --snapshot docs/paper/data/formal-results.json
|
||||
python scripts/build_paper_support.py # 附录正式数据表(--package 另出支撑包)
|
||||
uv run python scripts/plot_paper_figures.py
|
||||
cd docs/paper && latexmk -xelatex -interaction=nonstopmode -halt-on-error -outdir=build main.tex
|
||||
```
|
||||
|
||||
## 优化与验证
|
||||
|
||||
| 文档 | 内容 |
|
||||
| --- | --- |
|
||||
| [`第三四问架构优化与运行提速方案.md`](第三四问架构优化与运行提速方案.md) | 运行历史复核、分层目标架构、P0–P2 优化项与实施路线 |
|
||||
| [`第三四问图论与动态规划优化方案.md`](第三四问图论与动态规划优化方案.md) | 图论/DP 引入方案与实测回填(含未采用的改动与原因) |
|
||||
| [`算法审核与优化-20260911.md`](算法审核与优化-20260911.md) | 一次外部口径的算法审核记录与结论 |
|
||||
| [`最优与基线实现对比.md`](最优与基线实现对比.md) | 1–4 问「最优实现 / 基线实现」对比框架与结果(论文口径说明) |
|
||||
| [`B题问题3-4相关论文列表.md`](B题问题3-4相关论文列表.md) | 题 3、4 相关文献清单 |
|
||||
|
||||
## 论文与插图
|
||||
|
||||
| 路径 | 内容 |
|
||||
| --- | --- |
|
||||
| [`paper/main.tex`](paper/main.tex) | 论文正文(`latexmk -xelatex main.tex`);插图经 `\graphicspath` 取自 [`figures/`](figures/README.md) |
|
||||
| [`paper/README.md`](paper/README.md) | 论文编译方式、目录结构与待办标记 |
|
||||
| [`figures/README.md`](figures/README.md) | 插图清单、配色与字体约定、数据来源与复现命令 |
|
||||
| [`figures/manifest.json`](figures/manifest.json) | 每张图的数据来源与 sha256、生成命令 |
|
||||
| [`../project/README.md`](../project/README.md) | 对比框架目录结构与运行方式;结果表由 `scripts/build_paper_support.py` 转入论文第 11 节 |
|
||||
|
||||
## 口径登记
|
||||
|
||||
同一事实在多份文档中出现时,以下列来源为准;发现不一致请先改文档,再复核图。
|
||||
|
||||
| 事实 | 权威来源 |
|
||||
| --- | --- |
|
||||
| 题面常量(Ω、速度、各动作耗时、源与频道范围) | `src/mcm26b/config.py`(带 `[题面]` / `[工程]` 标注) |
|
||||
| 指令字段与结果码 | `src/mcm26b/protocol/rules.py` + [`协议规则表与状态机.md`](协议规则表与状态机.md) |
|
||||
| 问题一数值(D、ρ、E) | `mcm26b.geometry.solve` 的返回,或 [`问题一解答.md`](问题一解答.md) |
|
||||
| 覆盖计划与证书 | `src/mcm26b/guarantee/plans/*.json`(`q4_mincover_v2.json` 为默认) |
|
||||
| 实测虚拟时间 | 行为日志 `virtual_time_s` 字段与 `evaluation.recompute_virtual_time` |
|
||||
| 冻结基准集对比结果 | `project/results/*.md`(由 `uv run python -m project.run` 生成);论文表格为 `docs/paper/data/project-*.tex`,由 `scripts/build_paper_support.py` 生成 |
|
||||
|
||||
已知的两处需要随环境更新的引用:
|
||||
|
||||
1. [`问题一解答.md`](问题一解答.md) 引用的 `output/q1/figures/*.png` 属于早期
|
||||
离线插图(`output/` 未入库);现行插图在 [`figures/`](figures/README.md)。
|
||||
2. 多份文档提到的官方演练报告位于 `output/q3/practice/`、`output/q4/`,
|
||||
同样未入库;需要时用 `scripts/verify_q3_practice.py` 对留档目录复算。
|
||||
|
||||
## 写作约定
|
||||
|
||||
- 只写结论与依据,不使用比喻、排比与自评式措辞(例如「唯一权威」「关键洞察」)。
|
||||
- 数字必须能在代码或数据中找到出处;图内不放标题与解释段落,
|
||||
说明写在正文,图名与清单见 [`figures/README.md`](figures/README.md)。
|
||||
- 中文引号统一使用「」,避免与代码中的 ASCII 引号混淆。
|
||||
> `docs/paper/data/*.tex` 由脚本生成,一律使用 LF 换行:CRLF 会让 `\input` 进表格的行
|
||||
> 在 TeX 缓冲中提前 `\par` 化,触发 booktabs 的 “Misplaced \noalign”。
|
||||
|
||||
-266
@@ -1,266 +0,0 @@
|
||||
# 问题一算法说明:有界测向误差下的角域交会、直径与最小包围圆
|
||||
|
||||
> 本文按**当前仓库实现**重写,替代早期只描述理论方案的版本。
|
||||
> 问题一生产入口为 `src/mcm26b/geometry/localization.py::solve`,CLI 为
|
||||
> `python -m mcm26b.geometry`;问题二至四只复用其中的
|
||||
> `smallest_enclosing_circle` 与同一套角域半平面语义,并不直接调用
|
||||
> `solve`(复用与差异见 §7)。
|
||||
|
||||
## 1. 问题与实现入口
|
||||
|
||||
同一频道的同一静止干扰源,在若干检测点 $s_i=(s_{ix},s_{iy})$ 处得到示向度
|
||||
$\theta_i$。题设测向误差不超过 $\pm1^\circ$,同一地点重复测量误差不变;
|
||||
示向度从正东逆时针计量。问题一要求定位区域的直径,并判断“以该直径为
|
||||
直径的圆”能否覆盖定位区域。
|
||||
|
||||
| 层次 | 文件 | 内容 |
|
||||
| --- | --- | --- |
|
||||
| 生产内核 | `src/mcm26b/geometry/localization.py` | `Measurement`、`halfplanes`、`convex_hull`、`diameter`、`smallest_enclosing_circle`、`solve` |
|
||||
| CLI | `src/mcm26b/geometry/__main__.py` | 读 JSON、可加两位小数舍入裕量、输出结果 |
|
||||
| 统一入口 | `src/mcm26b/cli.py` | `mcm26b q1` |
|
||||
| 对比框架 | `project/q1/{optimal,baseline,reference,cases,compare}.py` | 生产实现 / 朴素基线 / 独立大框参考解 |
|
||||
| 回归 | `tests/test_geometry.py`、`tests/test_geometry_certificates.py` | 解析形状、真值保留、随机对拍、证书边界 |
|
||||
| 结果 | `examples/q1/*.json`、`project/results/q1.md` | 固定解析算例与 40 个随机交会算例的配对结果 |
|
||||
|
||||
```bash
|
||||
.venv/bin/python -m mcm26b.geometry examples/q1/triangle.json
|
||||
.venv/bin/python -m mcm26b.geometry examples/q1/normal.json --rounding-margin-deg 0.005
|
||||
```
|
||||
|
||||
`--rounding-margin-deg` 默认 $0$;库内在线求解默认把服务器两位小数舍入的
|
||||
$\le0.005^\circ$ 偏差计入有效半角,这是**实现口径**,不是题面新增误差。
|
||||
问题一 CLI 只有显式传参才附加该裕量,以便同时报告纯 $1^\circ$ 与
|
||||
$1.005^\circ$ 两套敏感性结果。
|
||||
|
||||
## 2. 模型:把角域写成半平面交
|
||||
|
||||
令方向向量 $u(\alpha)=(\cos\alpha,\sin\alpha)$,二维叉积
|
||||
$[a,b]=a_xb_y-a_yb_x$。设误差半角为 $\delta$(题设主模型 $\delta=1^\circ$),
|
||||
真实源 $g$ 属于闭前向角域
|
||||
|
||||
$$
|
||||
W(s,\theta,\delta)=\{g:\ [u(\theta-\delta),g-s]\ge0,\
|
||||
[u(\theta+\delta),g-s]\le0,\ u(\theta)\cdot(g-s)\ge0\}.
|
||||
$$
|
||||
|
||||
对应实现中的三条半平面 $a x+b y\le c$ 为
|
||||
|
||||
| 约束 | $a$ | $b$ | $c$ |
|
||||
| --- | --- | --- | --- |
|
||||
| 下边界左侧 | $\sin(\theta-\delta)$ | $-\cos(\theta-\delta)$ | $a s_x+b s_y$ |
|
||||
| 上边界右侧 | $-\sin(\theta+\delta)$ | $\cos(\theta+\delta)$ | $a s_x+b s_y$ |
|
||||
| 前向 | $-\cos\theta$ | $-\sin\theta$ | $a s_x+b s_y$ |
|
||||
|
||||
第三条前向约束在 $0<\delta<90^\circ$ 时冗余,但在 $\delta=0$ 时必须保留,
|
||||
否则两条边界只确定一条直线而非一条射线。角域顶点按闭集处理;这是保守的
|
||||
几何含义,不表示边界点仍能返回方向读数。
|
||||
|
||||
$P=\bigcap_i W_i$ 是有限条闭半平面之交,因而是闭凸集;可能为空、单点、
|
||||
线段、有界多边形或无界多边形。实现不做正态、均匀或独立误差假设,
|
||||
只使用题面给定的有界误差。
|
||||
|
||||
## 3. 精确算法流程
|
||||
|
||||
`solve(measurements, eps)` 的步骤如下。
|
||||
|
||||
### 3.1 坐标归一化与边界交点枚举
|
||||
|
||||
先对所有检测点做平移和统一缩放,使数值量级接近单位坐标;结果再换回原坐标。
|
||||
|
||||
1. 生成 $k=3n$ 条半平面。
|
||||
2. 枚举全部边界直线对($\binom{k}{2}$ 对),用行列式
|
||||
$\Delta=ae-bd$ 求交点;仅在 $\Delta$ 恰为 $0$ 时跳过,近平行对也保留,
|
||||
因为其交点可能是细长区域的合法远端顶点。
|
||||
3. 保留满足全部约束的交点;可行性判定使用随坐标量级缩放的位置容差
|
||||
`eps * max(1, |x|, |y|)`,避免大坐标下绝对残差被误判为不可行。
|
||||
|
||||
### 3.2 空集、有界与无界
|
||||
|
||||
- 无观测:$P=\mathbb R^2$,返回 `unbounded`。
|
||||
- 没有任何可行边界交点:返回 `empty`。
|
||||
- 否则检查衰退锥 $\mathcal R=\{d:Ad\le0\}$ 是否存在非零方向。二维情况下
|
||||
该锥若非零必含一条与某条有效边界平行的极射线;实现只需检查每条约束的
|
||||
两个切向 $(b,-a)$、$(-b,a)$ 是否满足全部齐次不等式
|
||||
$a d_x+b d_y\le 2\times10^{-14}$。阈值取得比位置容差紧得多,避免把
|
||||
极细长有界区域误判成无界。
|
||||
- 存在非零衰退方向时返回 `unbounded`,直径为 `null` 且显式置
|
||||
`diameter_infinite=true`,不伪造有限数值。
|
||||
|
||||
### 3.3 凸包与状态分类
|
||||
|
||||
将可行交点去重后,用 Andrew 单调链求凸包(逆时针、无重复首尾点)。
|
||||
按顶点数与维数返回:
|
||||
|
||||
| `status` | 含义 | 直径 | 最小包围圆 |
|
||||
| --- | --- | --- | --- |
|
||||
| `empty` | 观测不相容 | 未定义(`null`) | 不计算 |
|
||||
| `unbounded` | 存在非零衰退方向 | $+\infty$(`null` + 标志) | 不计算 |
|
||||
| `point` | 单点 | 0 | 半径 0 |
|
||||
| `segment` | 线段 | 两端点距离 | 半径 = 直径 / 2 |
|
||||
| `polygon` | 二维有界凸多边形 | 见 §3.4 | 见 §3.6 |
|
||||
|
||||
### 3.4 直径:只需枚举顶点对(已证明)
|
||||
|
||||
**定理 1.** 若 $P=\operatorname{conv}(V)$ 非空有界,则
|
||||
$D(P)=\max_{v_i,v_j\in V}\lVert v_i-v_j\rVert$。
|
||||
|
||||
证明:任一 $x,y\in P$ 写成凸组合后,
|
||||
$x-y=\sum_{i,j}\lambda_i\mu_j(v_i-v_j)$,由三角不等式有
|
||||
$\lVert x-y\rVert\le\max_{i,j}\lVert v_i-v_j\rVert$,而最远顶点对本身
|
||||
属于 $P$,故上界可达。实现直接枚举顶点对,复杂度 $O(m^2)$;单点返回 0,
|
||||
线段返回端点距离。
|
||||
|
||||
### 3.5 直径圆覆盖:唯一候选圆心是直径中点(已证明)
|
||||
|
||||
**定理 2.** 取任意一组最远顶点 $a,b$,$D=\lVert a-b\rVert$,
|
||||
$o=(a+b)/2$。存在直径为 $D$ 的覆盖圆,当且仅当所有顶点 $v_i$ 满足
|
||||
$\lVert v_i-o\rVert\le D/2$。
|
||||
|
||||
证明:若半径 $D/2$ 的圆心 $z$ 同时包含 $a,b$,则
|
||||
$D\le\lVert a-z\rVert+\lVert z-b\rVert\le D$,两个不等式都必须取等号,
|
||||
故 $z$ 只能在两点中点。圆盘是凸集,检查全部顶点即检查整个凸包。
|
||||
|
||||
实现输出 `diameter_circle`:圆心、半径、全部顶点到圆心的最大距离、
|
||||
`covers` 布尔值、最大超出量 `max_excess_m`、圆外顶点索引
|
||||
`outside_vertex_indices` 和反例顶点 `witness_vertex`。`witness_vertex`
|
||||
是一份可独立复核的覆盖失败证据;`max_excess_m` 不能为负,因为最远顶点
|
||||
本身在圆周上(精确算术下)。
|
||||
|
||||
### 3.6 最小包围圆与 20 m 清除证书
|
||||
|
||||
对凸包求最小包围圆 $\rho(P)$。实现采用 Welzl 随机增量算法的显式栈版本:
|
||||
固定随机种子使结果可复现;三个强制边界点使用外接圆;输出前再对全部
|
||||
顶点复核一次。内部有 $O(m^4)$ 的 1/2/3 点支撑圆枚举参考实现
|
||||
(`_enclosing_circle_reference`)用于单测对拍。
|
||||
|
||||
在最小包围圆中心 $m$、半径 $\rho$ 处,若
|
||||
$\rho+\varepsilon_m\le20$,则可直接以 $m$ 为清除点:任意真源
|
||||
$g\in P\subseteq B(m,\rho)$,到 $m$ 的距离不超过 $\rho$。实现输出
|
||||
`minimum_enclosing_circle`、`guaranteed_clearable_at_mec_center` 以及
|
||||
`clearance_certificate`(含数值余量和剩余裕量)。
|
||||
|
||||
注意:直径 $D\le40$ 只是“可能一次清除”的必要条件,**不是充分条件**;
|
||||
三角形反例中 $D=40$ 而 $\rho=23.094>20$。
|
||||
|
||||
## 4. 伪代码
|
||||
|
||||
```text
|
||||
solve(measurements):
|
||||
if measurements 为空: return unbounded
|
||||
平移/缩放,生成每条读数的三条半平面
|
||||
V = []
|
||||
for 每一对边界直线:
|
||||
求交点 p
|
||||
if p 满足全部半平面: V.append(p)
|
||||
if V 为空: return empty
|
||||
if 存在非零衰退切向 d: return unbounded
|
||||
H = convex_hull(V)
|
||||
D, (a,b) = argmax_{v_i,v_j∈H} |v_i-v_j|
|
||||
o = (a+b)/2
|
||||
covers = max_{v∈H} |v-o| <= D/2
|
||||
输出 diameter、diameter_circle、witness
|
||||
(m,rho) = Welzl_MEC(H)
|
||||
输出 minimum_enclosing_circle 与 rho+eps<=20 清除证书
|
||||
```
|
||||
|
||||
## 5. 复杂度与数值实现
|
||||
|
||||
| 步骤 | 复杂度 |
|
||||
| --- | --- |
|
||||
| 生成半平面 | $O(k)$,$k=3n$ |
|
||||
| 边界交点枚举与可行性判定 | $O(k^3)$ |
|
||||
| 凸包 | $O(k^2\log k)$ 最坏 |
|
||||
| 直径 | $O(m^2)$ |
|
||||
| 直径圆检查 | $O(m)$ |
|
||||
| Welzl 最小圆 | 随机排列下期望 $O(m)$;固定排列不声称最坏线性 |
|
||||
|
||||
主要数值约定:
|
||||
|
||||
- 坐标归一化后计算,输出换回原坐标并重新复核包含性;
|
||||
- 仅对**精确平行**直线对跳过求交;近平行对保留;
|
||||
- 位置可行性容差随坐标幅值缩放;衰退锥判定使用独立紧阈值;
|
||||
- `solve` 主动限制最多 100 个检测点,超过时要求改用半平面交算法;
|
||||
- 所有输出用 `null`/显式标志表示空集和无界,不写非法 JSON 浮点数。
|
||||
|
||||
## 6. 已验证算例与结果
|
||||
|
||||
固定解析算例(`examples/q1`,当前代码实测):
|
||||
|
||||
| 算例 | 状态 | 直径 (m) | MEC 半径 (m) | 直径圆覆盖 | 最大超出 (m) | MEC 可直接清除 |
|
||||
| --- | --- | ---: | ---: | --- | ---: | --- |
|
||||
| `normal` 三点交会 | polygon | 26.986 | 13.943 | 否(2 个圆外顶点) | 3.964 | 是 |
|
||||
| `triangle` 等边三角形反例 | polygon | 40.000 | 23.094 | 否(1 个圆外顶点) | 14.641 | 否 |
|
||||
| `segment` 零误差退化线段 | segment | 100.000 | 50.000 | 是 | 0.000 | 否 |
|
||||
| `poor` 近共线检测点 | unbounded | — | — | — | — | — |
|
||||
| `empty` 不相容观测 | empty | — | — | — | — | — |
|
||||
|
||||
`triangle` 的三个顶点是 $(0,0)$、$(40,0)$、$(20,20\sqrt3)$:以直径
|
||||
$AB$ 为直径的圆圆心 $(20,0)$、半径 20,到 $C$ 的距离为 $20\sqrt3>20$,
|
||||
故不能覆盖;最小包围圆半径 $40/\sqrt3\approx23.094$,也不能一次清除。
|
||||
其中 $A=(0,0)$ 坐标是浮点下的 $-6.4\times10^{-13}$,上表按解析值取整。
|
||||
|
||||
既有官方演练观测(案例 `U5ZW-P9KN-TCAG-R7ST`,不公开源坐标、未执行清除)
|
||||
的复算结果:
|
||||
|
||||
| 误差半角 | 直径 (m) | MEC 半径 (m) | 直径圆最大超出 (m) |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| $1^\circ$ | 23.996723 | 12.068583 | 0.604002 |
|
||||
| $1.005^\circ$ | 24.119088 | 12.130377 | 0.608486 |
|
||||
|
||||
两种口径下直径圆都不覆盖定位区域,MEC 半径都小于 20 m,但该演练没有
|
||||
真实清除动作,不能据此声称实测定位误差或全清成功率。
|
||||
|
||||
`project/q1` 的 40 个随机交会算例(冻结算例与独立参考解对拍):
|
||||
|
||||
| 方法 | 状态准确率 | 直径平均绝对误差 | 直径圆覆盖准确率 | 平均耗时 |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| 生产 `solve` | 100% | 0.000 m | 100% | 0.086 ms |
|
||||
| 朴素基线(网格 + 包围盒对角线) | 100% | 4.583 m | 52.5% | 15.932 ms |
|
||||
|
||||
## 7. 与问题二/三/四当前实现的复用关系和差异(核对结果)
|
||||
|
||||
问题一给出的几何内核是后续所有几何决策的基础,但**复用方式是“语义 + 最小圆函数”,
|
||||
不是直接调用 `solve`**。代码层面的核对结果如下。
|
||||
|
||||
| 后续问题 | 实际复用了什么 | 实际没有复用 / 做了什么替换 |
|
||||
| --- | --- | --- |
|
||||
| 问题二(`planner.select_second_point`) | 同一套角域半平面语义;`smallest_enclosing_circle` 求候选集 MEC;用 MEC 半径构造保证接收盘 | 不调用 `solve`;候选集不是纯角域交,而是 $K_1=\Omega\cap W\cap B(s,1500)$;用 192 边形外包圆盘 + Sutherland–Hodgman 裁剪,而不是枚举直线交点;不计算直径,也不使用“直径中点圆”判据 |
|
||||
| 问题三(`belief.CandidateRegion`、`planner.bayes_loop`) | 复用 `smallest_enclosing_circle`;角域边界公式与问题一相同;MEC 作为清除证书 | 在线信念是有界凸外包多边形,圆盘边界是外切多边形而非精确曲线;不再判无界;no_signal 的负观测由网格粒子滤波处理(问题一模型里没有负观测);不用直径,而用“MEC 半径 + 外包余量 + 工程余量 $\le20$” |
|
||||
| 问题四(`planner.DirectionalExtension`、`belief.joint`) | 继续复用问题一的 MEC 与角域语义;(位置 × 朝向)联合信念也建立在同一网格上 | 定向源的 no_signal 不能排除位置,不能沿用问题一/三的纯角度或全向距离解释;覆盖语义改为 `forward_half_disk`(见 `algo-4.md`) |
|
||||
|
||||
代码证据:
|
||||
|
||||
- `src/mcm26b/belief/__init__.py` 只从 `geometry.localization` 导入
|
||||
`smallest_enclosing_circle`;
|
||||
- `src/mcm26b/particles.py` 同样只导入 `smallest_enclosing_circle`;
|
||||
- `生产/运行代码中 `geometry.localization.solve` 的调用者只有
|
||||
`geometry/__main__.py` 和 `project/q1/optimal.py`,即问题一 CLI 与其
|
||||
对比框架;测试文件会直接调用它做解析与随机对拍,不在此列;
|
||||
- 在线 `clip_wedge` 的半平面系数与问题一 `halfplanes` 一致,但作用在
|
||||
凸多边形裁剪流程上;`solve` 的“纯角域 + 精确顶点枚举 + 无界判定”
|
||||
是针对问题一的一站式分析工具,不适合直接嵌入带圆盘、负观测和状态更新
|
||||
的在线闭环。
|
||||
|
||||
**差异一句话总结:** 问题一回答“固定角域观测下源可能在哪里、直径圆能否覆盖”,
|
||||
是纯几何精确解;问题二至四把其中的角域半平面和最小圆升级为“带距离先验的
|
||||
保守信念 + 主动动作 + 证据证明”的闭环,问题三再加非凸负观测,问题四再加
|
||||
朝向维度。
|
||||
|
||||
## 8. 结论与适用边界
|
||||
|
||||
问题一的当前实现是:三条半平面 → 可行顶点枚举/凸包 → 衰退锥判有界 →
|
||||
顶点对精确直径 → 任意直径中点唯一候选的覆盖检验 → Welzl 最小包围圆与
|
||||
20 m 证书。其结论只依赖题面有界误差,不引入误差分布假设。空集、无界、
|
||||
点、线段和多边形状态都有明确输出。
|
||||
|
||||
未解决问题一的数值敏感性时,不应把在线闭环里的外包多边形半径直接当成
|
||||
问题一的精确直径;两者口径不同。反过来,在线闭环也不能把 `solve` 直接套在
|
||||
$K_1$ 上,因为 $K_1$ 含圆盘和距离上界,边界可能含圆弧。
|
||||
|
||||
## 参考文献
|
||||
|
||||
1. 全国大学生数学建模竞赛组委会. 2026 年高教社杯全国大学生数学建模竞赛 B 题:无线电干扰源的快速自动定位与清除[Z]. 2026. 本地题面 `issue/B题.pdf`。
|
||||
2. BOYD S, VANDENBERGHE L. Convex Optimization[M]. Cambridge University Press, 2004. 凸集、半平面与凸组合背景。
|
||||
3. WELZL E. Smallest enclosing disks (balls and ellipsoids)[C]//New Results and New Trends in Computer Science, LNCS 555, 1991: 359–370. 随机增量最小包围圆。
|
||||
4. 本项目. `docs/algo-2.md`(问题二当前实现). 问题二对本文半平面语义与最小圆的复用说明。
|
||||
5. 本项目. `docs/algo-3.md`、`docs/algo-4.md`. 在线闭环中的保守信念、负观测与联合信念差异。
|
||||
-312
@@ -1,312 +0,0 @@
|
||||
# 问题二算法说明:保证接收的第二检测点选择(当前实现)
|
||||
|
||||
> 本文按**当前仓库实际运行路径**重写。生产入口是
|
||||
> `src/mcm26b/planner.select_second_point`,其核心选点器是
|
||||
> `select_measurement_point`;`src/mcm26b/geometry/planning.py` 中的
|
||||
> `first_bearing_candidate_disk` 是解析充分证书与独立校核工具,
|
||||
> 并不在运行时被 `select_second_point` 调用(见 §6 核对结果)。
|
||||
|
||||
## 1. 问题、实现入口与交付物
|
||||
|
||||
问题二给定一个全向干扰源的首次有效示向度 $(s,\theta)$,要求给出第二个
|
||||
检测点 $q$ 的选择策略、定位效果与候选区域。两个约束必须同时满足:
|
||||
|
||||
1. **接收保证**:$q$ 到所有仍可能为真源的位置都不超过有效接收半径下界
|
||||
$R_-=1000$ m,否则第二次测量可能返回 `no_signal`,几何收益落空;
|
||||
2. **定位效果**:在保证接收的候选点中,使第二次测量后的保守位置集合
|
||||
尽量小。当前实现以“最坏后验最小包围半径”为主指标,以移动耗时为次指标。
|
||||
|
||||
| 层次 | 文件 | 内容 |
|
||||
| --- | --- | --- |
|
||||
| 在线入口 | `src/mcm26b/planner/__init__.py::select_second_point` | 由首次 `direction` 构造 $K_1$,返回 `SecondPointPlan` |
|
||||
| 核心选点 | 同文件 `select_measurement_point` | 任意候选集的保证接收盘内选点 |
|
||||
| 几何证书 | `src/mcm26b/geometry/planning.py::first_bearing_candidate_disk` | 截断角域解析外包圆与安全候选盘 |
|
||||
| 信念构造 | `src/mcm26b/belief/__init__.py::BeliefState`、`CandidateRegion` | $K_1$ 的保守凸外包与更新 |
|
||||
| 对比框架 | `project/q2/{optimal,baseline,reference,region,cases,compare}.py` | 生产选点器 / 两种朴素基线 / 保证盘内网格参考 |
|
||||
| 回归 | `tests/test_planner.py`、`tests/test_geometry_certificates.py`、`tests/test_belief.py` | 接收保证、后验收缩、near 分支、解析证书 |
|
||||
| 结果 | `project/results/q2.{md,json}` | 30 个随机首次示向度算例配对结果 |
|
||||
|
||||
## 2. 首次观测后的候选集 $K_1$
|
||||
|
||||
### 2.1 精确定义
|
||||
|
||||
记首次检测点为 $s$、首次示向度为 $\theta$、误差半角
|
||||
$\delta_{\rm eff}=1^\circ+0.005^\circ$(题设误差 + 两位小数舍入裕量),
|
||||
有效接收半径上界 $R_+=1500$ m,源位置圆域 $\Omega=B(0,1800)$。则
|
||||
|
||||
$$
|
||||
K_1=\Omega\cap W(s,\theta,\delta_{\rm eff})\cap B(s,R_+).
|
||||
$$
|
||||
|
||||
真实源在合法观测下必属于 $K_1$。注意 $B(s,R_+)$ 的半径是**接收半径上界**:
|
||||
`direction` 读数本身就隐含测得距离不超过 $R_+$;而 $B(s,R_-)$ 不在 $K_1$
|
||||
之中,因为第二次是否收到信号正是本问要保证的事。
|
||||
|
||||
### 2.2 实际保守表示
|
||||
|
||||
在线实现不直接处理圆弧边界,而用以下外切多边形表示 $K_1$:
|
||||
|
||||
- 先取 $\Omega$ 的 192 边外切正多边形 $P_M(0,1800)$;
|
||||
- 再与 $B(s,1500)$ 的 192 边外切正多边形求交;
|
||||
- 最后用 Sutherland–Hodgman 逐半平面裁剪两条测向边界。
|
||||
|
||||
设圆盘外切多边形相对圆盘的最大径向超出为 $R(1-\cos(\pi/M))$。实现把每次
|
||||
圆盘裁剪的该量累加到 `CandidateRegion.slack_m`,因此维护的多边形满足
|
||||
$K_1\subseteq P_{\rm out}$,且 `slack_m` 是可审计的外包半径余量。
|
||||
|
||||
这条路径与问题一的区别:问题一在纯角域上枚举边界直线交点,精确处理
|
||||
空集/无界;问题二候选集一开始就被 $\Omega$ 和 $B(s,R_+)$ 限成有界集,
|
||||
因此可以只用凸多边形裁剪。角域系数与问题一 `halfplanes` 完全一致:
|
||||
$\sin(\theta-\delta)x-\cos(\theta-\delta)y\le c$ 与
|
||||
$-\sin(\theta+\delta)x+\cos(\theta+\delta)y\le c$。
|
||||
|
||||
## 3. 保证接收区域
|
||||
|
||||
### 3.1 一般集合形式
|
||||
|
||||
对非空紧候选集 $K$,定义
|
||||
|
||||
$$
|
||||
F_K(q)=\max_{g\in K}\lVert q-g\rVert,\qquad
|
||||
\mathcal Q(K)=\{q:F_K(q)\le R_-\}=\bigcap_{g\in K}B(g,R_-).
|
||||
$$
|
||||
|
||||
$F_K$ 是凸函数且 1-Lipschitz,$\mathcal Q(K)$ 是闭凸集。
|
||||
|
||||
**定理 1.** $\mathcal Q(K)\ne\varnothing$ 当且仅当
|
||||
$\rho(K)=\min_q F_K(q)\le R_-$,其中 $\rho(K)$ 是 $K$ 的最小包围半径。
|
||||
|
||||
证明:$\min_q F_K(q)$ 就是最小包围半径;存在 $q$ 使 $F_K(q)\le R_-$ 与
|
||||
其最小值不超过 $R_-$ 等价。证毕。
|
||||
|
||||
### 3.2 多边形外包给出的充分安全盘
|
||||
|
||||
设在线维护的多边形 $P_{\rm out}\supseteq K$,其最小包围圆为
|
||||
$B(m,\rho_{\rm out})$。任取
|
||||
|
||||
$$
|
||||
q\in B(m,\ R_- - \rho_{\rm out}-\eta),\qquad \eta=10^{-3}\ {\rm m},
|
||||
$$
|
||||
|
||||
则对任意真源 $g\in K$:
|
||||
|
||||
$$
|
||||
\lVert q-g\rVert\le\lVert q-m\rVert+\lVert m-g\rVert
|
||||
\le (R_--\rho_{\rm out}-\eta)+\rho_{\rm out}
|
||||
=R_--\eta<1000.
|
||||
$$
|
||||
|
||||
实现中 `safe_disk_radius(region)` 直接返回
|
||||
$R_--\rho_{\rm out}-10^{-3}$;因为 $\rho_{\rm out}$ 已是包含真实候选集
|
||||
的多边形最小包围半径,这个盘内的点到真实源的三角不等式上界严格小于
|
||||
1000 m。1 mm 的数值余量避免浮点贴边被 $r_{\rm eff}=1000$ 的源判成
|
||||
`no_signal`。若该半径 $<0$,说明当前凸外包的 MEC 半径已超过 1000 m:
|
||||
|
||||
- 这**不能**证明真实 $\mathcal Q(K)$ 为空,只说明这个充分证书不够紧;
|
||||
- 实现退化为探索 MEC 圆心,并在 `reason` 中明确标注“可能 `no_signal`”。
|
||||
|
||||
### 3.3 首次截断角域的解析候选盘
|
||||
|
||||
完全去掉 $\Omega$ 后,完整的截断角域
|
||||
$S=W(s,\theta,\delta)\cap B(s,R_+)$ 有一个精确最小包围圆:
|
||||
|
||||
$$
|
||||
c=s+a\,u(\theta),\qquad a=\frac{R_+}{2\cos\delta},\qquad
|
||||
S\subseteq B(c,a),
|
||||
$$
|
||||
|
||||
对 $0\le\delta\le45^\circ$ 成立。简证:设
|
||||
$g=s+t\,u(\theta+\varphi)$,$0\le t\le R_+$,
|
||||
$|\varphi|\le\delta$,则
|
||||
$\lVert g-c\rVert^2=t^2+a^2-2at\cos\varphi$。固定 $\varphi$ 时该式
|
||||
关于 $t$ 是凸二次函数,最大值在 $t=0$ 或 $t=R_+$ 处:前者为 $a^2$,
|
||||
后者不超过 $R_+^2+a^2-2aR_+\cos\delta=a^2$(代入
|
||||
$a=R_+/(2\cos\delta)$),故 $S\subseteq B(c,a)$。最小性由三点
|
||||
$s$、$s+R_+u(\theta\pm\delta)$ 的加权距离恒等式给出:权重
|
||||
$\lambda_\pm=1/(4\cos^2\delta)$、
|
||||
$\lambda_0=1-1/(2\cos^2\delta)$ 非负且和为 1,且
|
||||
$c=\lambda_0s+\lambda_+p_++\lambda_-p_-$,故任何覆盖这三点的圆半径
|
||||
至少为 $a$。于是
|
||||
|
||||
$$
|
||||
\mathcal Q_0=B(c,\ R_- - a)
|
||||
$$
|
||||
|
||||
是保证接收的充分候选区域。题设 $\delta_{\rm eff}\le1.005^\circ$ 时:
|
||||
|
||||
| 误差半角 | 轴向中心距离 $a$ / m | 安全候选半径 $R_- - a$ / m |
|
||||
| --- | ---: | ---: |
|
||||
| $1^\circ$ | 750.114246 | 249.885754 |
|
||||
| $1.005^\circ$ | 750.115391 | 249.884609 |
|
||||
|
||||
该解析盘由 `first_bearing_candidate_disk` 实现并测试。它给出的是
|
||||
$S$ 的最小圆;由于 $K_1\subseteq S$,$B(c,R_- - a)\subseteq\mathcal Q(K_1)$
|
||||
是严格充分的。实际在线路径使用比 $S$ 更紧的 $K_1$ 凸外包,因此其安全盘
|
||||
通常大于该解析下界(例:`q2-4200` 的 $\rho_{\rm out}=674.59$ m,
|
||||
安全盘半径 325.41 m,而解析下界约 249.89 m)。
|
||||
|
||||
## 4. 实际选点算法
|
||||
|
||||
### 4.1 入口伪代码
|
||||
|
||||
```text
|
||||
select_second_point(client, s, theta):
|
||||
region = CandidateRegion.initial(s) # Ω ∩ B(s,1500) 的外包
|
||||
region.clip_wedge(s, theta, 1.005°) # 交入首次角域
|
||||
return select_measurement_point(region, client.position)
|
||||
|
||||
select_measurement_point(region, from_position):
|
||||
(m, rho) = region.mec() # Welzl 最小包围圆
|
||||
safe = 1000 - rho - 1e-3
|
||||
if safe < 0: return MEC 圆心(探索,可能 no_signal)
|
||||
候选 = {m} ∪ {m + f*safe*(cos ψ, sin ψ)}
|
||||
f ∈ {0.4, 0.75, 1.0}, ψ 取 12 个均匀方向
|
||||
对每个候选 q:
|
||||
最坏后验 = max( 方向分支、near 分支 )
|
||||
分数 = (最坏后验, 移动时间)
|
||||
取分数最小的 q
|
||||
用 1/4 间距加密复核 q 的最坏后验
|
||||
return q、最坏后验半径、移动耗时、理由
|
||||
```
|
||||
|
||||
当前 `search.candidate_rings=(0.0,0.4,0.75,1.0)`、`candidate_angles=12`,
|
||||
去重后实际是 **37 个候选点**(圆心 + 3 环 × 12 方向)。所有点严格属于
|
||||
保证接收盘,因此第二次测量不会因距离不足返回 `no_signal`。
|
||||
|
||||
### 4.2 最坏后验评估
|
||||
|
||||
对候选点 $q$,最坏后验半径按以下有限枚举计算:
|
||||
|
||||
1. 在候选集边界上以 `witness_spacing_m=60` m 采样见证点
|
||||
$g$(`region.witnesses`,含全部顶点);
|
||||
2. 对每个 $g$,真实方位 $\phi=\operatorname{bearing}(q,g)$,枚举允许的
|
||||
读数区间端点 $\phi\pm\delta_{\rm eff}$;
|
||||
3. 对每个端点,复制候选多边形并用 `clip_wedge(q, 读数, δ_eff)` 得到后验
|
||||
凸外包,记录其 MEC 半径;
|
||||
4. 额外处理 `near` 分支:以 $B(q,5)$ 裁剪候选集,若交集非空,记录其 MEC
|
||||
半径;它代表“源离第二点不超过 5 m,直接光学定位清除”的分支;
|
||||
5. 以上全部有效半径取最大值,就是该候选点的评估值。
|
||||
|
||||
该评估是**启发式上界近似**:它只对目标边界采样和读数区间端点取值,
|
||||
没有覆盖连续集合上所有可能读数;但它可在候选点之间做一致比较。
|
||||
1/4 间距(15 m)的加密复核只提高输出数值的可信度,不改变“采样启发式”
|
||||
这一事实。定理 1 保证接收,选点最优性没有全局证明。
|
||||
|
||||
### 4.3 清除与 `near`
|
||||
|
||||
若第二次测量返回 `near`,源在 $q$ 的 5 m 内。由 `clear_certificate`:
|
||||
候选集 $B(q,5)$ 的 MEC 半径至多略大于 5 m(外包多边形余量很小),
|
||||
工程余量后仍远小于 20 m,因此可以在当前位置直接 `/clear`,不需要再取
|
||||
第三个测向读数。若返回 `direction`,则用新角域更新 $K$ 并继续按
|
||||
问题三/四的定位流程处理;后验半径若仍大于 20 m,**不能**声称两次定位
|
||||
已经完成。
|
||||
|
||||
## 5. 参数与复杂度
|
||||
|
||||
| 参数 | 默认值 | 作用 |
|
||||
| --- | ---: | --- |
|
||||
| `polygon_sides` | 192 | 圆盘外切多边形边数;$\Omega$ 处径向超出约 0.24 m |
|
||||
| `bearing_rounding_margin_deg` | 0.005° | 两位小数舍入的显式裕量 |
|
||||
| `witness_spacing_m` | 60 m | 粗评边界见证间距 |
|
||||
| `candidate_rings` | (0, 0.4, 0.75, 1.0) | 安全盘内半径比例 |
|
||||
| `candidate_angles` | 12 | 每环方向数;连同圆心共 37 个候选 |
|
||||
| `near_radius_m` | 5 m | `near` 分支判定 |
|
||||
| `clear_margin_m` | 0.5 m | 清除证书的额外工程余量 |
|
||||
|
||||
若候选集顶点数为 $m$、候选点数为 $N_q$、边界见证数为 $N_g$,单次选点的
|
||||
粗评估约为 $O(N_qN_g\cdot{\rm clip}+N_q{\rm MEC})$,`clip` 为
|
||||
Sutherland–Hodgman 裁剪的 $O(m)$ 代价;再加一次 1/4 间距加密复核。
|
||||
这是明显可并行/缓存的小规模在线计算,不追求全局最优。
|
||||
|
||||
## 6. 实现核对结果:文档旧说法与当前运行路径的差异
|
||||
|
||||
早期说明只写到 `geometry/planning.py` 的解析候选盘,容易让人误以为
|
||||
`select_second_point` 直接调用它。当前代码的实际情况是:
|
||||
|
||||
- `select_second_point` 构造 `CandidateRegion`($\Omega\cap B(s,1500)$ 的
|
||||
192 边形外包)并用 `clip_wedge` 交入首次角域;
|
||||
- 真正的选点发生在 `select_measurement_point`:它在上述凸外包的 MEC
|
||||
保证盘内做 37 点候选评估;
|
||||
- `first_bearing_candidate_disk` 是解析证书函数,用于证明
|
||||
$B(s+au,1000-a)$ 的充分性,并被
|
||||
`tests/test_geometry_certificates.py` 以稠密角域采样校核;
|
||||
- 生产路径不调用 `first_bearing_candidate_disk`,但两者给出同一性质的
|
||||
保证:选出的点必能收到 `direction`/`near`。生产路径通常比解析盘更紧,
|
||||
因为它利用了 $K_1$ 完整形状而不是仅用其外包扇区。
|
||||
|
||||
因此,问题二的**严格保证**来自“安全盘点到候选集所有点的距离 $\le R_-$”,
|
||||
解析盘是充分但不唯一的一种实现方式;**最优性**来自有限候选评估,
|
||||
两者必须在说明中分开陈述。
|
||||
|
||||
## 7. 已验证结果
|
||||
|
||||
`project/q2` 在 30 个随机首次示向度算例上,用同一 $K_1$、同一评估器
|
||||
对四种方法配对比较(初始 $\rho$ 均值 681.47 m):
|
||||
|
||||
| 方法 | 保证接收率 | 最坏后验均值 | 终值比 $\rho'/\rho$ | 平均移动 | 结论 |
|
||||
| --- | ---: | ---: | ---: | ---: | --- |
|
||||
| 生产选点器(保证盘内最小最坏后验) | **100%** | **73.89 m** | **0.104** | 170.4 s | 保证接收且后验最小 |
|
||||
| 基线① 垂直 1000 m 最大交会角 | **0%** | 80.11 m | 0.116 | 200.0 s | 忽略接收距离,真源在远端必 `no_signal` |
|
||||
| 基线② 直接取 MEC 圆心 | 100% | 340.75 m | 0.500 | 136.3 s | 保证接收但几乎不收缩 |
|
||||
| 独立参考:保证盘内 9×9 网格枚举 | 100% | 75.63 m | 0.106 | 170.3 s | 生产采样接近网格最优 |
|
||||
|
||||
代表性单例 `q2-4200`:
|
||||
|
||||
| 指标 | 数值 |
|
||||
| --- | ---: |
|
||||
| $K_1$ MEC 圆心 | (1172.85, −225.68) |
|
||||
| $K_1$ MEC 半径 $\rho$ | 674.59 m |
|
||||
| 保证接收盘半径 | 325.41 m |
|
||||
| 选中第二点 | (1257.07, 88.64) |
|
||||
| 最坏后验半径 | 54.45 m |
|
||||
| 移动耗时 | 181.42 s |
|
||||
|
||||
## 8. 与问题一及问题三/四的关系(核对结果)
|
||||
|
||||
| 对比 | 问题一 | 问题二(本文) | 问题三/四中的去向 |
|
||||
| --- | --- | --- | --- |
|
||||
| 信息模型 | 纯角域 $W$ | 角域 $W$ + 距离先验 $K_1=\Omega\cap W\cap B(s,R_+)$ | 问题三在任意后验 $K_c$ 上重复使用;问题四再叠加朝向维度 |
|
||||
| 求解方式 | 枚举半平面边界交点、凸包、精确直径 | 圆盘外切多边形 + Sutherland–Hodgman 裁剪 | 问题三/四沿用 `CandidateRegion` 凸外包 |
|
||||
| 决策类型 | 对固定观测做几何分析 | 主动选择下一个测量点 | 问题三是多源闭环;问题四是混合源闭环 |
|
||||
| 主要输出 | 直径与直径圆覆盖 | `SecondPointPlan`(位置、最坏后验、移动耗时) | 问题三把它推广到定位子过程;问题四把它作为联合信念选点的基础候选之一 |
|
||||
| 保证口径 | 几何精确(在输入模型内) | 接收严格保证;最坏后验是采样启发式 | 清除证书严格;选点与调度是启发式 |
|
||||
|
||||
关键区别:
|
||||
|
||||
1. 问题二不直接复用问题一的 `solve`,而是复用其角域语义和
|
||||
`smallest_enclosing_circle`;候选集多出圆盘和距离上界,不能当作
|
||||
“纯角域问题一”处理。
|
||||
2. 问题一的输出是直径和直径圆,问题二的清除判断改用最小包围半径
|
||||
$\rho\le20$;直径圆本身不参与在线清除。
|
||||
3. 问题三对同一个 `select_measurement_point` 做任意后验集上的复用,
|
||||
但同时引入网格粒子滤波处理 $K$ 无法表示的负观测(`no_signal`);
|
||||
问题二没有负观测更新,因为它假设第二次测量点已在保证接收盘内。
|
||||
4. 问题四不能直接使用“安全盘内必收到信号”的结论:定向源在安全盘内
|
||||
也可能因朝向遮挡返回 `no_signal`。问题四保留问题二的安全盘作为
|
||||
基础候选,但新增(位置 × 朝向)联合信念来判断可见性(见
|
||||
`algo-4.md`)。
|
||||
|
||||
## 9. 结论
|
||||
|
||||
问题二的当前实现可以概括为:
|
||||
|
||||
- **候选集**:$K_1=\Omega\cap W(s,\theta,\delta_{\rm eff})\cap B(s,R_+)$,
|
||||
用 192 边形外包圆盘 + 半平面裁剪保守维护;
|
||||
- **保证接收**:$B(m,R_--\rho_{\rm out}-10^{-3})$ 内的点必不返回
|
||||
`no_signal`;解析扇区最小圆给出可独立复核的充分候选盘
|
||||
$B(s+au,1000-a)$,$a=1500/(2\cos\delta)$;
|
||||
- **选点**:在保证盘内取 37 个候选,以边界见证点 × 读数端点的最坏后验
|
||||
包围半径为第一指标、移动时间为第二指标,选出后再做 1/4 间距加密复核;
|
||||
- **清除**:若第二次返回 `near`,直接就地清除;否则把新角域交入后验,
|
||||
未达到 20 m 证书前继续测量。
|
||||
|
||||
严格保证与启发式性能优化在文档和代码中始终分开:接收保证有证明,
|
||||
全局最优性没有证明;后者依赖自建的有限候选与固定评估口径。
|
||||
|
||||
## 参考文献
|
||||
|
||||
1. 全国大学生数学建模竞赛组委会. 2026 年高教社杯全国大学生数学建模竞赛 B 题[Z]. 2026. 本地题面 `issue/B题.pdf`。
|
||||
2. 模拟器配套材料. 附件 2:模拟器通信接口说明及编程指南[Z]. 2026. 本地附件 `issue/附件/附件2.docx`。
|
||||
3. BOYD S, VANDENBERGHE L. Convex Optimization[M]. Cambridge University Press, 2004. 凸性、最坏情形与鲁棒可行性背景。
|
||||
4. 本项目. `docs/algo-1.md`(问题一当前实现与复用差异)。
|
||||
5. 本项目. `docs/algo-3.md`、`docs/algo-4.md`(选点器在后续问题中的推广与边界)。
|
||||
@@ -1,144 +0,0 @@
|
||||
# 算法说明:问题3 贝叶斯闭环(`bayes` 策略)
|
||||
|
||||
> **历史补充文档.** 当前规范算法、最新默认参数与现行成绩口径见
|
||||
> [`algo-3.md`](algo-3.md);本文保留 2026-09-11 的设计与消融细节,
|
||||
> 其中 `lambda_move_s=0.0105`、站点环半径 1200 m 等数字可能已被
|
||||
> 后续回填(现行默认见 `config.BayesConfig`,λ=0.05、环半径 1159.7 m)。
|
||||
> 两者冲突时以代码与 `algo-3.md` 为准。
|
||||
|
||||
对应实现:`src/mcm26b/particles.py`(感知层)、`src/mcm26b/planner/bayes_loop.py`
|
||||
(决策层)、`scripts/benchmark_q3_bayes.py`(消融)、`scripts/tune_q3_bayes.py`
|
||||
(Optuna 调参)。基线对比:`docs/algo-3.md` 的七点批量(`seven`,A2)。
|
||||
|
||||
## 1. 建模定位
|
||||
|
||||
问题3是部分可观察的在线决策问题:频道数未知(10–16/20)、位置未知、有效
|
||||
接收半径未知(1000–1500m)、测向误差 ±1°(服务器保留两位小数)。策略层
|
||||
只能拿到 `/measure` 与 `/clear` 的响应,目标是最小化"发现—定位—清除"的
|
||||
虚拟总时间。`bayes` 策略把它分解为三层滚动时域闭环:
|
||||
|
||||
1. **感知层**:每频道一个贝叶斯后验(网格幸存集),融合全部正/负观测;
|
||||
2. **决策层**:站点扫频、定位测量、清除三类任务统一建表,开放路径
|
||||
最近邻 + 2-opt 排序,每个动作后滚动重排(动态 TSP);
|
||||
3. **选点层**:默认按期望log幸存占比和“到检测点、再接近源”的移动代价评分。
|
||||
已停靠位置可逐频道补交会观测,真实清除始终由完整角域证书批准。
|
||||
|
||||
2026-09-11 当前修订的审核与配对验收见 [三四问算法审核与优化](算法审核与优化-20260911.md)。
|
||||
本文件第5节是早期版本的历史结果,不应当作当前默认参数的复算结果。
|
||||
|
||||
## 2. 网格幸存集滤波与真源保留定理
|
||||
|
||||
每频道维护 Ω 上间距 h 的网格(h=14.65m,约 4.7 万格),`alive` 为幸存格
|
||||
集合。Voronoi 裕量 m = √2/2·h 是格心到格内任一点的最大距离;所有删除
|
||||
判定都内缩 m,即**仅当整格与可行集不相交时才删格**:
|
||||
|
||||
| 观测 | 题面语义 | 删除判定 |
|
||||
|---|---|---|
|
||||
| `no_signal`@s | 距离 > r_eff ≥ 1000 | 删格心距 s ≤ 1000 − m 的格 |
|
||||
| `direction`@s | 距离 ≤ 1500,\|读数−真值\| ≤ δ_eff | 删角向超出 δ_eff + asin(m/(d−m)) 或距 s > 1500 + m 的格 |
|
||||
| `near`@s | 距离 ≤ 5 | 删格心距 s > 5 + m 的格 |
|
||||
|
||||
**定理(真源保留)**:真源 P 满足全部题面约束;P 所在格的格心 g 满足
|
||||
|g−P| ≤ m,故"整格不相交"判定永不命中该格。因此任意观测序列后 P ∈
|
||||
幸存格的并集,且:
|
||||
|
||||
- **缺席证明**:幸存集为空 ⟹ 可行集为空 ⟹ 该频道无源(严格);
|
||||
- **清除证书**:MEC(幸存).R + m ≤ 20 − 工程余量 ⟹ 真源距清除点 ≤ 20;
|
||||
- **跳测规则**:幸存格到测点最小距离 > 1500 + m ⟹ 该测量必 no_signal
|
||||
且无新排除,可跳过。
|
||||
|
||||
性质测试:`tests/test_particles.py`(随机源 × 随机测点 × 随机合法误差,
|
||||
真源格永不被删;`tests/test_bayes_loop_q3.py` 端到端零异常)。
|
||||
|
||||
与 `belief.CandidateRegion`(保守凸外包)的分工:凸表示负责**清除证书**
|
||||
(精确角域裁剪、收敛后触发),网格负责凸表示做不到的三件事——非凸负
|
||||
观测挖洞(no_signal 排除盘)、缺席提前证毕、跳测判定。两者同读一套
|
||||
响应流(`_record_measure`),任何一方证毕即收尾。
|
||||
|
||||
## 3. 信息增益选点
|
||||
|
||||
候选点集(二选一,按保证接收盘是否非空):
|
||||
|
||||
- **保证接收盘** B(MEC_poly 圆心, 1000 − ρ_poly)(盘内必收 direction/near,
|
||||
几何同 `docs/algo-2.md` 定理1):环形采样(`search.candidate_rings`×12 方向);
|
||||
- **宽候选集**(ρ_poly > 1000 时):PF MEC 的 1.0/1.5/2.0 倍探索环。
|
||||
|
||||
评分(`BayesConfig.score_mode`):
|
||||
|
||||
- `radius`(可选):期望后验半径 —— 对 K 个代表假设(幸存格均匀抽样)
|
||||
各自模拟一次测量的幸存分支,分支半径用幸存子采样的质心最大距离近似,
|
||||
r_eff~U(1000,1500) 的不确定性解析积分(p_no_signal = (d−1000)/500);
|
||||
总分 = E[半径] + λ·移动秒数(λ=0.1);
|
||||
- `entropy`(当前默认,λ=0.0105):期望log幸存占比,加上λ乘以
|
||||
当前点→候选检测点→候选源中心的移动秒数。来向对称候选补充固定全局方向网格。
|
||||
|
||||
这里的均匀先验、零误差代表读数和均匀接收半径是选点评分的工程假设,
|
||||
不属于题面给定的概率模型;只有完整±1.005°角域与距离界参与安全证明。
|
||||
|
||||
λ 与半径同量纲,量级必须小:λ 过大时终局阶段"走 300m"的代价压过
|
||||
"半径 35m→25m"的收益,选点器原地重测、收敛停滞(消融实测 λ≥0.5 时
|
||||
单源定位步数翻倍)。
|
||||
|
||||
## 4. 统一任务循环(动态 TSP)
|
||||
|
||||
每个决策点构建任务表并排序执行首个任务,随后滚动重排:
|
||||
|
||||
- **站点任务**:七站(原点 + 当前1159.7m环六点)上的UNKNOWN频道;
|
||||
构造时验证全向覆盖解析界小于1000m,跳测规则与覆盖账本过滤;
|
||||
- **定位任务**:DETECTED 且无证书的频道,位置由信息增益选点产生;
|
||||
- **清除任务**:有证书(凸或网格)的频道,可沿当前位置方向移动证书圆心,
|
||||
但平移量与原半径之和不得超过清除证书阈值,节省最后一段接近路程。
|
||||
|
||||
排序 = 开放路径最近邻打底 + 2-opt 改进(`two_opt_passes` 轮,成本含
|
||||
移动 + 换频 + 动作耗时;换频按路径顺序逐步传递当前频道,clear保持频道;
|
||||
终点自由不回起点)。这是 A2"站内最近邻服务
|
||||
队列"的推广:消融显示距离缩短约 24% 是主要收益来源。
|
||||
|
||||
停止条件与基线一致:清满 16(数量上界)或全部频道 CLEARED/ABSENT,
|
||||
`stop_reason=all_resolved` 即停并 `/exit`——**虚拟时间即评测成绩口径**
|
||||
[用户决策修订 2026-09-11]。复扫保险模式(`mcm26b run --persistent`,
|
||||
原默认行为):找全后继续只复扫未清除频道直到清除数达 16、实机预算
|
||||
耗尽或虚拟安全余量(`search.virtual_reserve_s=10000s`)不足,供需要
|
||||
"防缺席证明假设偏差"保险的场景显式开启。
|
||||
|
||||
## 5. 消融结果(自建模拟器,persistent 关,对齐找全口径)
|
||||
|
||||
12 随机场景(6 种子 × 10/16 源)+ 2 边界场景,与 SevenBatch 配对;
|
||||
bayes 参数为 Optuna 回填后的库默认值:
|
||||
|
||||
| 指标 | SevenBatch | bayes |
|
||||
|---|---|---|
|
||||
| 有效运行(全清+缺席正确+零异常+正常退出) | 14/14 | **14/14** |
|
||||
| 平均虚拟时间 | 5352.7s | **3726.2s(−30.0%)** |
|
||||
| 配对降幅(最差 / 最好) | — | +7% / −41% |
|
||||
| 平均移动距离 | 23413m | **15050m(−36%)** |
|
||||
| 平均检测次数 | 102.4 | 110.0 |
|
||||
| 单局实机计算墙钟 | 1.3s | 1.9s |
|
||||
|
||||
复现:`uv run python scripts/benchmark_q3_bayes.py --seeds 0,1,2,3,4,5`
|
||||
(逐场景数据与场景 JSON 见 `output/q3/bayes-ablation/`)。
|
||||
|
||||
## 6. Optuna 调参
|
||||
|
||||
`scripts/tune_q3_bayes.py`:TPE(dev 依赖 `optuna`,缺失时自动退化为
|
||||
随机搜索),目标 = 场景子集平均虚拟时间 + 10⁶×失败惩罚。搜索空间:
|
||||
λ、代表点数、子采样规模、网格间距、站点环半径、2-opt 轮数、评分模式。
|
||||
最优组合(entropy 评分、λ=0.0105、h=14.65m、代表点 7、2-opt 4 轮)
|
||||
已按验收流程回填为 `config.BayesConfig` 默认值:全量基准 3726s/−30.0%
|
||||
优于回填前的 4277s/−19.5%。两处人工修订:
|
||||
- `station_ring_radius_m` 保留 1200(Optuna 建议 1159.7 虽再快约 60s,
|
||||
但七站排除盘对最外圈格心的覆盖差 3.3m,PF 无法独立证明缺席,
|
||||
只能靠覆盖账本兜底——设计性质优先于 1.7% 的均值差异);
|
||||
- 评分模式在 entropy(信息增益)与 radius(期望后验半径)之间由调参
|
||||
数据决定,两者实现均保留(`BayesConfig.score_mode`)。
|
||||
调参记录见 `output/q3/bayes-tuning/best_params.json`。
|
||||
|
||||
## 7. 已知边界
|
||||
|
||||
- 检测次数略多于 A2(109.6 vs 102.4):定位收敛多用 1-2 次测量换距离
|
||||
大幅缩短,净收益为正;跳测规则在 UNKNOWN 阶段(先验全域)暂无收益
|
||||
面,收益集中在定位与复扫阶段;
|
||||
- 网格清除证书(h=25m 时阈值 ≤1.8m)极少触发,作为凸证书的补位保险;
|
||||
- 调参与消融基于自建模拟器(逐点固定 ±1° 误差场),不代表官方误差
|
||||
分布;真源保留定理只依赖题面界(±1°、r_eff∈[1000,1500]),不依赖
|
||||
误差分布假设。
|
||||
-456
@@ -1,456 +0,0 @@
|
||||
# 问题三算法说明:全向多源搜索的覆盖证明、贝叶斯闭环与任务调度(当前实现)
|
||||
|
||||
> 本文汇总当前仓库中问题三的全部实际算法,生产默认策略为
|
||||
> `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`。
|
||||
-485
@@ -1,485 +0,0 @@
|
||||
# 问题四算法说明:混合全向/定向源搜索与清除闭环(当前实现)
|
||||
|
||||
> 本文汇总当前仓库中问题四的全部实际算法。生产策略是
|
||||
> `src/mcm26b/planner/__init__.py::DirectionalExtension`,CLI 策略名
|
||||
> `directional`,入口为 `mcm26b run --problem 4`。
|
||||
> 与问题三不同,问题四的源可能包含定向源;`no_signal` 不再等价于
|
||||
> “距离超过接收半径”,因此问题三的七站全向缺席证明**不能直接搬用**。
|
||||
> 当前仓库尚无官方问题四演练记录;本文性能数字均来自自建
|
||||
> `LocalSimulator` 冻结基准集,明确标注为测试假设。
|
||||
|
||||
## 1. 问题定位与核心难点
|
||||
|
||||
问题四每局有 $10\sim16$ 个源,其中一部分为定向源,其余为全向源;
|
||||
位置在 $\Omega=B(0,1800)$ 内,频道互异。定向源有一个朝向
|
||||
$h$,只有当接收点位于其**前向半平面**内、且距离不超过 $r_{\rm eff}$
|
||||
时才可能返回有效读数:
|
||||
|
||||
$$
|
||||
r=\lVert q-P\rVert\le r_{\rm eff}\quad\text{且}\quad
|
||||
\operatorname{angular\_gap}\big(\operatorname{bearing}(P\to q),h\big)
|
||||
\le90^\circ .
|
||||
$$
|
||||
|
||||
其中 $r_{\rm eff}$ 对每个源未知,满足 $1000\le r_{\rm eff}\le1500$ m。
|
||||
若 $r>r_{\rm eff}$ 或朝向不覆盖接收点,结果为 `no_signal`;若可见且
|
||||
$r\le5$ m,结果为 `near`;若可见且 $r>5$ m,结果为 `direction`,
|
||||
数值为接收点到源的方位加有界误差。
|
||||
|
||||
因此问题四的困难不是一般的“覆盖搜索”,而是两个额外的证明/决策问题:
|
||||
|
||||
1. **发现**:如何用有限的访问点证明“某个频道没有源”,即使该源是
|
||||
朝外发射的定向源;
|
||||
2. **定位与清除**:定向源的 `no_signal` 可能只是朝向遮挡,不能像全向源
|
||||
那样删除位置候选;需要推理“源可能朝哪边”,并在定位停滞时仍能可靠
|
||||
清除。
|
||||
|
||||
当前实现的办法是:
|
||||
|
||||
- 发现层用 `forward_half_disk` 语义的 31 点最小命中集覆盖计划
|
||||
(`q4_mincover_v2`);
|
||||
- 感知层在原有位置网格上叠加 24 档朝向掩码,得到(位置 × 朝向)联合
|
||||
可行集 `JointBelief`;
|
||||
- 决策层用联合信念的可见性概率筛选探点,失败时按预算进入 ≤20 m 的
|
||||
有限格后备清除;
|
||||
- 调度层用“本站批量扫频 + 按候选 MEC 圆心最近服务队列”的滚动顺序,
|
||||
避免发现后立即远行、再返回同站扫描的往返。
|
||||
|
||||
| 层次 | 文件/类 | 作用 |
|
||||
| --- | --- | --- |
|
||||
| 覆盖计划 | `src/mcm26b/guarantee/cover.py`、`guarantee/plans/q4_mincover_v2.json` | `forward_half_disk` 最小命中集与运行期校核 |
|
||||
| 位置网格 | `src/mcm26b/particles.py::ChannelParticles` | 位置幸存集与 Voronoi 保守裕量 |
|
||||
| 朝向联合信念 | `src/mcm26b/belief/joint.py::JointBelief` | 每格 24 档朝向掩码、可见性/期望后验半径 |
|
||||
| 决策闭环 | `src/mcm26b/planner/__init__.py::DirectionalExtension` | 批量扫频、可见性探点、后备清除、收尾 |
|
||||
| 对比框架 | `project/q4/{optimal,baseline,compare}.py` | `directional` vs `bayes`/`grid` 直接搬用 |
|
||||
| 回归 | `tests/test_loop_q4.py`、`tests/test_joint_belief.py`、`tests/test_coverage_plan.py` | 真源保留、朝外边界源、后备纪律、证书校核 |
|
||||
| 结果 | `project/results/q4.{md,json}` | 11 个 core+boundary 场景配对结果 |
|
||||
|
||||
## 2. 发现覆盖:`forward_half_disk` 与最小命中集
|
||||
|
||||
### 2.1 覆盖语义
|
||||
|
||||
设访问点集合为 $S$。对全向源,`no_signal` 在 $s$ 处排除 $B(s,1000)$,
|
||||
因此完整覆盖只需
|
||||
|
||||
$$
|
||||
\Omega\subseteq\bigcup_{s\in S}B(s,1000).
|
||||
$$
|
||||
|
||||
对定向源,还需要朝向条件。严格的缺席证明要求:
|
||||
|
||||
$$
|
||||
\forall P\in\Omega,\ \forall h\in\mathbb S^1,\quad
|
||||
\exists s\in S:\quad
|
||||
\lVert s-P\rVert\le1000
|
||||
\ \wedge\ (s-P)\cdot u(h)\ge0 .
|
||||
$$
|
||||
|
||||
也就是说,对任意位置和任意朝向,至少有一个被访问点同时落在该源的
|
||||
1000 m 距离内和 90° 前向半平面内。这个语义称为 `forward_half_disk`。
|
||||
问题三的七站环不满足该语义:`tests/test_coverage_plan.py` 中有专门用例
|
||||
验证“七站点集在 `forward_half_disk` 下有缺口”。
|
||||
|
||||
### 2.2 49 点 legacy 充分条件
|
||||
|
||||
旧实现使用 $S=\{(700i,700j):i,j\in[-3,3]\}$ 的 49 个点:
|
||||
|
||||
- 任意 $P\in[-2100,2100]^2$ 到某个网格点的欧氏距离不超过
|
||||
$700\sqrt2\approx989.95\le1000$;
|
||||
- 因此对该网格点,无论源朝向如何(前向半平面总是 $180^\circ$),
|
||||
距离条件都成立。
|
||||
|
||||
这是 49 点充分条件,保证发现但代价很高:最近邻开放巡回约 36.4 km;
|
||||
对无源频道还要在 49 个点各测一次。它现在保留为 legacy 对照与回退计划
|
||||
`square49`。
|
||||
|
||||
### 2.3 31 点最小命中集 `q4_mincover_v2`
|
||||
|
||||
当前默认计划由离线贪心集合覆盖搜索得到,并带有可运行期校验证书。
|
||||
生成参数:搜索分辨率 50 m / 48 档,设计距离裕量
|
||||
$r_{\rm design}=965$ m,前向角裕量 $5^\circ$;随后用证书分辨率
|
||||
15 m / 72 档($3\,256\,200$ 个 $(P,h)$ 采样)做精细剪枝,每删一个点都
|
||||
用同一证书口径复核。
|
||||
|
||||
`q4_mincover_v2` 的证书摘要:
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | ---: |
|
||||
| 点数 | 31 |
|
||||
| 覆盖语义 | `forward_half_disk` |
|
||||
| 校核分辨率 | 15 m / 72 朝向档 |
|
||||
| 采样目标数 | 3 256 200 |
|
||||
| 缺口数 | 0 |
|
||||
| 最坏命中距离 | 990.051 m |
|
||||
| 最近邻开放巡回 | 23 883.8 m(约 4776.8 s 虚拟移动) |
|
||||
| 生成器 SHA-256 | `adf4fe6e…434c0e1d`(完整值见 JSON) |
|
||||
|
||||
旧 `q4_mincover_v1`(31 点)在粗采样 75 m/24 档下看似零缺口,但在
|
||||
25 m/48 档有 125 个缺口、15 m/72 档有 566 个缺口,属于采样过拟合;
|
||||
`q4_mincover_v2` 修正了这一点,点数不变而细网格缺口归零。
|
||||
|
||||
**严格连续空间证书的已知残余风险.** 15 m/72 采样格上的零缺口加上设计
|
||||
裕量可以覆盖相邻未采样 $(P,h)$,但默认 v2 的最坏命中距离 990.051 m
|
||||
略高于严格连续界要求的约 989.4 m(需满足
|
||||
$r_{\rm verify}+15\sqrt2/2\le1000$,即 $r_{\rm verify}\le989.4$ m)。
|
||||
仓库另有 36 点备选计划(最坏命中 973.7 m、巡回约 25.4 km,见
|
||||
`output/q4/cover-certificate-v3.json`)可关闭该连续性缺口;当前默认的
|
||||
v2 在 15 m/72 离散证书上零缺口,连续空间残余约 0.65 m,已作为已知
|
||||
风险登记。若论文要求严格连续证明,应改用 36 点方案并重新验收性能。
|
||||
|
||||
### 2.4 运行期校验
|
||||
|
||||
`load_plan(name, verify=True)` 会读取计划 JSON 中的证书字段,并用
|
||||
**证书自带的采样分辨率**重新校核;缺口不为 0 直接拒绝启动。默认
|
||||
`search.verify_coverage_plan=True`。校核成本在进程内按计划名缓存一次,
|
||||
15 m/72 档约数秒(见 `scripts/run_suite.py` 的 `plan_verify_wall_s`)。
|
||||
运行期不会用比证书更粗的采样去“自证”。
|
||||
|
||||
## 3. (位置 × 朝向)联合信念 `JointBelief`
|
||||
|
||||
### 3.1 网格与朝向档
|
||||
|
||||
位置维度复用 `ChannelParticles`:间距 $h=14.65$ m、Voronoi 裕量
|
||||
$m=\sqrt2/2\,h\approx10.359$ m;朝向维度把整周分为
|
||||
24 档(每档 $15^\circ$,半档 $7.5^\circ$)。每个位置格附带一个 24 位
|
||||
掩码,表示该格仍可能具有的朝向;缺省掩码为全档。
|
||||
|
||||
联合集合的保守性目标是:**真源 (位置, 朝向) 永不被删除**(在该离散
|
||||
表示意义下,即真源所在格的朝向至少保留一档,且位置格不被删)。因此
|
||||
所有判定都向“保留更多”的一侧取整,并计入格内角裕量
|
||||
|
||||
$$
|
||||
\alpha_{\rm cell}=\arcsin\!\left(\frac{m}{\max(d-m,1)}\right),
|
||||
$$
|
||||
|
||||
即格内任一点相对格心到测点方位的最大偏差上界。
|
||||
|
||||
### 3.2 观测更新规则
|
||||
|
||||
| 观测 | 位置维度 | 朝向维度 |
|
||||
| --- | --- | --- |
|
||||
| `direction` @ $s$,读数 $\beta$ | 删除距 $s>1500+m$ 的格;删除角向偏离读数超过 $\delta_{\rm eff}+\alpha_{\rm cell}$ 的格 | 朝向必须**可能覆盖** $s$:保留与方位 $\operatorname{bearing}(g\to s)$ 夹角不超过 $90^\circ+7.5^\circ+1.5^\circ+\alpha_{\rm cell}$ 的档 |
|
||||
| `near` @ $s$ | 删除距 $s>5+m$ 的格 | 同 `direction`:朝向必须可能覆盖 $s$ |
|
||||
| `no_signal` @ $s$ | **位置不删**(可能是距离不足或朝向遮挡) | 仅对“整格必在 $r_{\rm eff,min}=1000$ 圆盘内”的格,保留与方位夹角大于 $90^\circ-7.5^\circ-1.5^\circ-\alpha_{\rm cell}$ 的档,即只保留**确定看不见** $s$ 的朝向档;掩码变空则删除该位置格 |
|
||||
|
||||
其中 `1.5°` 是朝向查表分辨率带来的保守余量,$7.5^\circ$ 是半档。
|
||||
`no_signal` 的距离阈值使用 $1000-m$(保守侧):只有在确信整格都在
|
||||
1000 m 内时,才把静默解释为朝向遮挡;否则保留全部朝向档,避免删掉
|
||||
真源。
|
||||
|
||||
> 2026-09-12 修复记录:早期实现把 `no_signal` 分支的朝向掩码方向写反,
|
||||
> 会删除真源朝向档;现已改为“只保留确定看不见的档”,并由
|
||||
> `tests/test_joint_belief.py::test_true_source_survives_consistent_observations`
|
||||
> 以随机观测序列固化。
|
||||
|
||||
联合集一旦为空(所有位置格都被删除),就给出该频道不存在的严格缺席
|
||||
证明,`absence_evidence` 记为 `joint_empty`。这与覆盖证明是两类独立证据。
|
||||
|
||||
### 3.3 可见性与值函数
|
||||
|
||||
`JointBelief` 提供两个只用于选点排序的启发式量:
|
||||
|
||||
1. `prob_detect(q)`:在测点 $q$ 能看见该频道任一可行
|
||||
(位置, 朝向) 的概率质量。对抽样格心 $P$:
|
||||
- 距离概率:$d\le1000$ 时为 1;$d\ge1500$ 时为 0;中间线性插值
|
||||
(对应 $r_{\rm eff}\sim U[1000,1500]$);
|
||||
- 朝向覆盖比例:该格掩码中与“$P\to q$ 方位”夹角不超过
|
||||
$90^\circ$ 的档位占比;
|
||||
- 两者相乘后对格取平均。
|
||||
2. `expected_posterior_radius(q)`:一次测量后的期望后验 MEC 半径(D1
|
||||
值函数)。对每个代表格:
|
||||
|
||||
$$
|
||||
p_{\rm vis}=(1-p_{\rm silent\_range})\cdot\text{cover\_ratio},
|
||||
\quad
|
||||
p_{\rm ns}=1-p_{\rm vis},
|
||||
$$
|
||||
|
||||
- `direction` 分支:后验半径用“以 $P\to q$ 方位为读数、$\pm\delta_{\rm eff}$
|
||||
角域裁剪后的子采样质心最大距离”近似;
|
||||
- `no_signal` 分支:位置候选**不缩小**,半径保持当前 PF MEC 半径;
|
||||
- `near` 分支:后验为 5 m 盘。
|
||||
最后对代表假设取平均。
|
||||
|
||||
这两个量的先验(均匀格点、$r_{\rm eff}$ 均匀分布)是工程假设,不承担
|
||||
任何安全责任;安全责任由覆盖证书、清除证书和联合真源保留定理承担。
|
||||
|
||||
## 4. 决策闭环 `DirectionalExtension`
|
||||
|
||||
### 4.1 覆盖阶段:本站批量扫频 + 最近队列服务
|
||||
|
||||
```text
|
||||
while 未达到数量上界且未停止:
|
||||
index = 尚有 UNKNOWN 待测的最近覆盖点(31 点计划)
|
||||
if 不存在: break
|
||||
pending = 该点尚未测过的 UNKNOWN 频道
|
||||
pending 按“当前测向频道优先”排序
|
||||
for channel in pending:
|
||||
outcome = /measure(point, channel)
|
||||
observe(channel, point, outcome) # 更新凸信念 + JointBelief
|
||||
if outcome == near 且候选集有清除证书:
|
||||
就地 /clear
|
||||
queue = 所有 DETECTED 且无证书的频道
|
||||
while queue:
|
||||
channel = 距其候选集 MEC 圆心最近的频道
|
||||
从 queue 移除并调用 _localize_and_clear(channel)
|
||||
```
|
||||
|
||||
与问题三 `SevenBatch` 的结构类似,但覆盖点集、缺席语义和定位逻辑完全不同。
|
||||
`observe` 对 `direction`/`near` 更新凸候选集和联合信念;对 `no_signal`
|
||||
只更新联合信念的朝向维度,绝不用于删除凸候选集的位置。
|
||||
|
||||
覆盖阶段结束后(所有计划点上的 `UNKNOWN` 频道都测过):
|
||||
`_mark_absent_after_coverage` 把覆盖账本完整的 `UNKNOWN` 频道标为
|
||||
`ABSENT`;然后 `_resolve_detected` 再对剩余 `DETECTED` 频道做第二轮
|
||||
定位。
|
||||
|
||||
### 4.2 定位子循环
|
||||
|
||||
`DirectionalExtension._localize_and_clear(channel)`:
|
||||
|
||||
```text
|
||||
步数 steps = 0,被遮挡探点表 blocked = []
|
||||
while steps < max_localize_steps=8:
|
||||
if 凸/PF 清除证书已成立: 尝试 /clear;成功则返回
|
||||
if len(blocked) >= max_blocked_probes=4: break # 定位停滞 -> 后备
|
||||
q = _next_probe(region, channel)
|
||||
within_range = (|q - region.MEC 圆心| <= safe_disk_radius(region))
|
||||
outcome = /measure(q, channel)
|
||||
observe(...)
|
||||
if outcome == no_signal:
|
||||
if within_range: 标记 directional_observed
|
||||
blocked.append(q); continue # 不消耗 steps
|
||||
else: # direction 或 near
|
||||
blocked.clear(); steps += 1
|
||||
循环结束后再检查证书;若仍不可清除 -> _fallback_clear(channel)
|
||||
```
|
||||
|
||||
要点:
|
||||
|
||||
- 只有**在保证接收盘内**出现 `no_signal` 才标记“观测到定向”,避免把
|
||||
距离不足误诊为朝向遮挡;
|
||||
- 被遮挡探点不重复选取;最多 4 次,随后转入后备清除;
|
||||
- `direction`/`near` 读数才计入定位步数;
|
||||
- 每一步后都重新评估证书,滚动推进。
|
||||
|
||||
### 4.3 `_next_probe`:联合信念选点与后备梯子
|
||||
|
||||
候选点族 `_probe_candidates` 包含:
|
||||
|
||||
1. `select_measurement_point` 给出的保证接收盘内最坏后验最优候选
|
||||
(复用问题二/问题三的选点器);
|
||||
2. 若已有被遮挡点,取关于 MEC 圆心的对跖方向点,并裁进保证接收盘;
|
||||
3. 抵近点序列 `center + α*(current-center)`(代码保留,默认
|
||||
`approach_fractions=()` 未启用);
|
||||
4. 以 MEC 圆心为心、半径 $0.5\rho,\ 1.0\rho,\ 1.5\rho$ 的 8 方向环探。
|
||||
|
||||
候选去重到 0.5 m,并可排除已测过且被遮挡的点。
|
||||
|
||||
若联合信念可用,优先调用 `_visibility_probe`(默认口径
|
||||
`probe_score_mode=nearest_visible`):
|
||||
|
||||
1. 对每个候选计算 `prob_detect(q)`;
|
||||
2. 只保留概率不低于最大值 0.7 倍的候选
|
||||
(`probe_visibility_ratio=0.7`),避免选中“期望上有点信息、实际必被
|
||||
朝向遮挡”的点;
|
||||
3. 在保留候选中选择
|
||||
$\text{move}(p\to q)+\text{move}(q\to m_{\rm MEC})+6$ 秒最小者
|
||||
(6 = 检测 5 s + 换频 1 s)。
|
||||
|
||||
若联合信念不可用/为空或候选为空,则退回确定性梯子:
|
||||
未被遮挡过用最坏后验选点器;第一次被遮挡用对跖点;之后绕 MEC 圆心
|
||||
半径 $\rho$ 的环上每次 +45° 试探。几何边界必须如实说明:环上可见弧
|
||||
没有正的下界(源可在环上且朝向沿外切线,可见集退化为切点),因此
|
||||
梯子只是提高命中概率,**完备性由后备清除兜底**。
|
||||
|
||||
### 4.4 后备清除:有限格盲清
|
||||
|
||||
定位停滞时,`_fallback_clear` 对凸候选多边形生成 20 m 格心的有限覆盖:
|
||||
|
||||
1. 用全局 20 m 半开网格与候选多边形求交(带正容差,宁可多保留格);
|
||||
2. 格内任一点到格心不超过 $10\sqrt2\approx14.14\le20$ m,因此若真源
|
||||
仍在候选多边形内,逐格 `/clear` 至少命中一次;
|
||||
3. 格数上界
|
||||
$(\lceil w/20\rceil+2)(\lceil h/20\rceil+2)$;
|
||||
4. 若格数超过 `fallback_max_cells=400`,记录
|
||||
`fallback_cell_cap_exceeded` 并跳过,不硬扫;
|
||||
5. 若现实剩余预算不足以覆盖
|
||||
`格数 × real_rtt_p95_s + reserve_exit_s`,记录 `skipped_budget`
|
||||
并跳过;
|
||||
6. 通过检查时,按最近邻开放路径逐格 `/clear`;命中成功即标记清除;
|
||||
全部失败则记录 `fallback_exhausted_without_success`,**不删除候选集**。
|
||||
|
||||
后备清除只依赖“清除与朝向无关”这一题面事实,是定向源定位失败时唯一
|
||||
不依赖可见性的完备性底线;但它受格数上限和现实预算约束,预算不足时
|
||||
会诚实地保持未完成。`fallback_optimize_tour=False` 为默认:实测把
|
||||
格间路径排得更短反而会让“命中即停”的真源顺序变差,故不启用。
|
||||
|
||||
## 5. 调度、完成条件与预算
|
||||
|
||||
### 5.1 与问题三调度层的关系
|
||||
|
||||
`DirectionalExtension` 继承 `OmnidirectionalLoop` 的会话、预算、异常
|
||||
和 summary 骨架,但不使用 `BayesLoop` 的统一任务表/信息增益调度;
|
||||
它采用“每站批量扫频 + 本站服务队列”的滚动策略(类似 A2 的推广)。
|
||||
因此:
|
||||
|
||||
- 检测/换频/清除的计时口径与问题三完全一致;
|
||||
- 覆盖点、缺席证据、定位方法、清除证书不同;
|
||||
- 默认不启用 Held-Karp/2-opt 任务表;后备清除走最近邻。
|
||||
|
||||
### 5.2 完成条件
|
||||
|
||||
- 清除数达到 16:直接停止并按 `count_cap` 完成;
|
||||
- 否则要求每个频道 `CLEARED` 或 `ABSENT`,按 `per_channel_proof` 完成;
|
||||
- 缺席证据来源:
|
||||
- `coverage`:该频道在 31 点计划上全部测得 `no_signal`;
|
||||
- `joint_empty`:联合可行集为空;
|
||||
- 定位/清除尚未完成或预算耗尽:`completed=False`,
|
||||
`stop_reason=unresolved_channels` / `real_budget_exhausted` /
|
||||
`virtual_time_cap` 等,不把未完成说成成功。
|
||||
|
||||
## 6. 关键参数
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
| --- | ---: | --- |
|
||||
| `q4_coverage_plan` | `q4_mincover_v2` | 31 点定向最小命中集 |
|
||||
| `verify_coverage_plan` | `True` | 运行期按证书分辨率校核 |
|
||||
| `directional_joint_belief` | `True` | 启用(位置 × 朝向)联合信念 |
|
||||
| `probe_score_mode` | `nearest_visible` | 可见性过滤 + 移动最省 |
|
||||
| `probe_visibility_ratio` | 0.7 | 可见概率保留比例 |
|
||||
| `probe_exclude_blocked` | `True` | 不重复测已遮挡点 |
|
||||
| `approach_fractions` | `()` | 抵近点默认关闭 |
|
||||
| `max_localize_steps` | 8 | 每轮定位成功读数上限 |
|
||||
| `max_blocked_probes` | 4 | 被遮挡探点上限,超限转后备 |
|
||||
| `fallback_clear_grid_m` | 20 m | 后备清除格边长;$10\sqrt2<20$ |
|
||||
| `fallback_max_cells` | 400 | 后备格数硬顶 |
|
||||
| `fallback_optimize_tour` | `False` | 后备走格 NP+2-opt 默认关闭 |
|
||||
| `persistent_search` | `False` | 找全证明后立即退出 |
|
||||
|
||||
## 7. 已验证结果与失效机理
|
||||
|
||||
### 7.1 冻结基准集
|
||||
|
||||
`project/q4` 在 11 个冻结 core+boundary 场景上的配对结果:
|
||||
|
||||
| 方法 | 有效局 | 全清率 | 缺席误判 | 虚拟时间均值 | 中位 | 最大 | 后备清除均值 |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||
| `directional` | 11/11 | **100%** | **0** | 9069.9 s | 8803.3 s | 12081.1 s | 24.8 |
|
||||
| `bayes` 直接搬用 | 0/11 | 77% | **24** | 3890.8 s | 3646.2 s | 5054.4 s | 0 |
|
||||
| `grid` 直接搬用 | 0/11 | 67% | 0 | 18179.2 s | 18345.2 s | 20457.9 s | 0 |
|
||||
|
||||
两条搬用基线的失效机理不同:
|
||||
|
||||
- `bayes` 使用七站**全向**缺席证明;在朝外发射、$r_{\rm eff}=1000$ m 的
|
||||
边界定向源场景中会把真源直接判成 `ABSENT`。它“快而错”,累计 24 次
|
||||
缺席误判,虚拟时间不能作为有效优势;
|
||||
- `grid` 的 49 点覆盖对定向源发现是完备的,但没有朝向推理与后备清除,
|
||||
定位停滞时只能停在 `DETECTED`,属于“稳而不全”。
|
||||
|
||||
`directional` 在 11/11 场景全清、零缺席误判;代价是时间更长,平均
|
||||
24.8 次后备清除。纯 core 9 场景(不含朝外边界压力)的均值约 8602.0 s、
|
||||
最大 9630.4 s、后备 4.3 次/局;boundary 场景(朝外发射源)会把后备
|
||||
推到数十至上百次,单局最大 12081.1 s(16 源 8 定向边界场景)。
|
||||
因此第四问的时间对“源是否背离圆心发射”非常敏感,不存在对所有合法
|
||||
场景的均匀性能保证。
|
||||
|
||||
### 7.2 覆盖计划消融
|
||||
|
||||
| 计划 | 点数 | 15 m/72 缺口 | 最坏命中 | NN 巡回 |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| `square49` | 49 | 0 | ≤1000 m(构造) | 36.4 km |
|
||||
| `q4_mincover_v1` | 31 | 566 | 1000.0 m | 22.9 km |
|
||||
| `q4_mincover_v2`(默认) | 31 | **0** | 990.051 m | 23.9 km |
|
||||
| 36 点严格连续备选 | 36 | 0 | 973.7 m | 25.4 km |
|
||||
|
||||
改用最小命中集后,覆盖点减少了 37%,巡回长度从 36.4 km 降到 23.9 km;
|
||||
但第四问时间的大头仍是 23.9 km 巡回(约 4776.8 s)和逐频道缺席检测。
|
||||
把七站式的“有源提前停止”规则用于 31 点计划可在一定程度上减少检测,
|
||||
但最小命中集的巡回与检测开销仍是该问题的成本地板(详见
|
||||
`docs/第三四问图论与动态规划优化方案.md` §2、§8)。
|
||||
|
||||
### 7.3 回归测试
|
||||
|
||||
问题四相关测试覆盖:
|
||||
|
||||
- 联合信念真源 (位置, 朝向) 在随机观测序列后不丢;
|
||||
- 朝外发射的边界定向源不漏、不被误判缺席;
|
||||
- 保证接收盘内 `no_signal` 不删空间候选、判向不越界;
|
||||
- 后备清除格覆盖候选多边形每个见证点;格数上限/预算检查跳过而非硬扫;
|
||||
- 全清、零异常、逐微秒计时复算一致。
|
||||
|
||||
当前全仓 `pytest` **268 项通过**(2026-09-12 本轮复核)。
|
||||
|
||||
## 8. 与问题一、二、三当前实现的复用关系和差异(核对结果)
|
||||
|
||||
| 对比 | 复用 | 差异 |
|
||||
| --- | --- | --- |
|
||||
| 问题一 | 角域半平面语义、Welzl 最小包围圆 `smallest_enclosing_circle`、MEC 清除证书思路 | 问题四不计算直径/直径圆;`no_signal` 不能解释为距离排除;覆盖语义是 `forward_half_disk` 而非纯角度交集 |
|
||||
| 问题二 | `select_measurement_point`、`safe_disk_radius` 作为基础候选与“是否在保证接收盘内”的判据;清除点可向当前位置平移 | 定向源在安全盘内仍可能因朝向 `no_signal`,因此问题二的“盘内必收到信号”保证不成立;新增联合信念和可见性筛选 |
|
||||
| 问题三 | PF 网格位置维度、覆盖账本、会话/预算/异常 summary、清除动作 | 问题三的负观测可删位置候选(`full_disk` 七点缺席证明);问题四的负观测只约束朝向,覆盖计划改用 31 点 `forward_half_disk`,不使用七站全向缺席证明;问题四也不使用 `BayesLoop` 的信息增益任务表 |
|
||||
| 问题四独有 | — | 24 档朝向掩码、可见性概率选点、对跖/环探后备梯子、20 m 格后备清除及其格数/预算纪律 |
|
||||
|
||||
关键结论:**问题四不是“问题三加一点朝向”,而是发现证明、负观测语义和
|
||||
清除兜底三处都必须重做**。直接套用问题三的 `bayes`(七站缺席证明)会在
|
||||
朝外定向源上产生缺席误判;直接套用 `grid`(49 点全向)可以发现但无法
|
||||
可靠定位清除。当前 `directional` 的路线是:最小命中集保证发现、
|
||||
联合信念推理可见性、预算化后备清除保证清除底线。
|
||||
|
||||
## 9. 适用边界与风险声明
|
||||
|
||||
- **覆盖证书**:默认 v2 是 15 m/72 档离散证书加设计裕量,零缺口;
|
||||
严格连续空间证书还存在约 0.65 m 的已知残余,正式论文若要求严格连续
|
||||
证明应改用 36 点备选计划;
|
||||
- **联合信念**:真源保留证明依赖评测机观测语义与题面误差界一致;
|
||||
先验分布、朝向均匀抽样和可见性概率都只是决策启发式;
|
||||
- **后备清除**:完备性只在格数不超过 400、现实预算足够且候选集确实
|
||||
包含真源时成立;任一条件不满足就诚实地保持未完成;
|
||||
- **性能**:11/11 全清来自自建模拟器与冻结场景,不是官方成绩;
|
||||
当前仓库尚无官方问题四演练。第四问对定向源朝向分布敏感,不能把
|
||||
core 均值 8602 s 或边界均值 9069.9 s 外推为官方期望;
|
||||
- **调度**:站点批量与最近队列是贪心,不是全局最优;图论/DP 方案
|
||||
中的插入、Or-opt、精确任务序等在本场景实测为负收益或未推广到问题四,
|
||||
默认关闭。
|
||||
|
||||
## 10. 复现
|
||||
|
||||
```bash
|
||||
# 冻结基准集:directional vs 问题三策略直接搬用
|
||||
uv run python scripts/run_suite.py --problem 4 --suite all --jobs 6 \
|
||||
--variants directional --label q4-current
|
||||
|
||||
# 项目对比框架(生成 project/results/q4.{md,json})
|
||||
uv run python -m project.run --question 4
|
||||
|
||||
# 覆盖证书生成与细网格校核(默认计划的来源)
|
||||
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
|
||||
|
||||
# 回归
|
||||
uv run pytest tests/test_joint_belief.py tests/test_loop_q4.py \
|
||||
tests/test_coverage_plan.py tests/test_particles.py -q
|
||||
```
|
||||
|
||||
主要文件:
|
||||
|
||||
- `src/mcm26b/planner/__init__.py::DirectionalExtension`、`fallback_clear_cells`、
|
||||
`fallback_cell_bound`:闭环、探点与后备清除;
|
||||
- `src/mcm26b/belief/joint.py`:联合信念;
|
||||
- `src/mcm26b/particles.py`:位置幸存集;
|
||||
- `src/mcm26b/guarantee/cover.py`、`guarantee/plans/q4_mincover_v2.json`:
|
||||
覆盖计划与证书;
|
||||
- `src/mcm26b/routing.py`:后备/离线巡回度量。
|
||||
|
||||
延伸阅读:`docs/第三四问架构优化与运行提速方案.md`(第四问失败机理与
|
||||
P0-2/P0-3 实测)、`docs/第三四问图论与动态规划优化方案.md`(联合信念
|
||||
修复记录与 D1 探点口径消融)、`docs/algo-3.md`(问题三全向闭环)。
|
||||
|
||||
## 参考文献
|
||||
|
||||
1. 全国大学生数学建模竞赛组委会. 2026 年高教社杯全国大学生数学建模竞赛 B 题[Z]. 2026. 本地题面 `issue/B题.pdf`。
|
||||
2. 模拟器配套材料. 附件 2《通信接口说明及编程指南》[Z]. 2026. 本地附件 `issue/附件/附件2.docx`。
|
||||
3. 本项目. `docs/algo-1.md`、`docs/algo-2.md`、`docs/algo-3.md`。
|
||||
4. 本项目. `docs/第三四问架构优化与运行提速方案.md`、`docs/第三四问图论与动态规划优化方案.md`、`docs/算法审核与优化-20260911.md`。
|
||||
+32
-57
@@ -1,74 +1,49 @@
|
||||
# docs/figures —— 论文插图
|
||||
|
||||
每张图只输出 PNG。正文插图统一由 scripts/plot_paper_figures.py 使用 matplotlib 生成,
|
||||
数据直接读取 docs/paper/data/practice-results.json(演练局复算)、
|
||||
practice-geometry.json(问题一交会算例)、正式统计快照与第四问覆盖计划;
|
||||
manifest.json 记录图片生成命令与来源。
|
||||
本目录的 10 张 PNG 全部进入论文:`docs/paper/main.tex` 用
|
||||
`\graphicspath{{../figures/}}` 直接引用,论文不重绘、也不手抄图内任何数字。
|
||||
全部插图由同一脚本生成:
|
||||
|
||||
本目录的 15 张 PNG 进入论文:`docs/paper/main.tex` 用
|
||||
`\graphicspath{{../figures/}}` 直接引用,不在论文里重绘,也不手抄图内数字。
|
||||
正文使用演练局数据生成的插图(问题一至四的算例、路径、时间分布与耗时构成),
|
||||
正式测试的两张图(`formal-*.png`)只出现在附录 A 的效果验证中。
|
||||
论文图注均为中文,并标注数据来源是演练局还是正式测试。
|
||||
|
||||
```
|
||||
python scripts/plot_paper_figures.py # 生成正文全部 matplotlib 插图
|
||||
```bash
|
||||
uv run python scripts/plot_paper_figures.py # 依赖 numpy 与 matplotlib
|
||||
```
|
||||
|
||||
MATLAB 内手动出图:`cd scripts/matlab` 后执行 `run_all_figures`(每张图单独一个会话,
|
||||
本机图形子系统连续渲染多张会崩)。
|
||||
|
||||
依赖:`numpy` 与 `matplotlib`。
|
||||
数据来自 `docs/paper/data/` 下的复算结果(`practice-results.json`、
|
||||
`practice-geometry.json`、正式统计快照)与第四问覆盖计划;
|
||||
逐图来源见 `manifest.json`。图注为中文,并注明数据取自演练局还是正式测试。
|
||||
|
||||
## 约定
|
||||
|
||||
- **除回放画布(点运动图 `replay-webui-*`)外,全部使用 MATLAB 默认图形样式**:
|
||||
默认配色(`defaultAxesColorOrder`)、默认字体与字号、默认坐标轴与图例;
|
||||
不引入自定义调色板,不手绘图例色块。
|
||||
- 图内不放标题、图注与解释性文字,只保留坐标轴、图例与必要的元素标注;
|
||||
图的含义由文件名与下表承担,解释写在论文正文。
|
||||
- 图例一律用 MATLAB `legend` 放在坐标区外(`southoutside`),不压数据;
|
||||
散点标签按候选方位自动避让,保证互不重叠。
|
||||
- 输出 PNG(`exportgraphics`,300 dpi、白底),导出前关闭坐标轴工具条。
|
||||
- 默认配色与字体沿用 matplotlib 默认样式,不引入自定义调色板;
|
||||
- 图内不放标题与解释性文字,只保留坐标轴、图例与必要的元素标注,含义由图注承担;
|
||||
- 图例置于坐标区外,散点与角度标注按位置自动避让,保证互不重叠;
|
||||
- 输出 PNG(300 dpi、白底)。
|
||||
|
||||
## 图清单
|
||||
|
||||
| 文件 | 内容 | 数据来源 | 论文位置 |
|
||||
| --- | --- | --- | --- |
|
||||
| `flow-overall-architecture.png` | 四层主线:题面抽象(L0)、在线三层(L1)、四问主线(L2)、三条闭环(L3) | `src/mcm26b/config.py`、`docs/B题建模分析与实施计划.md` | 图 1(问题分析) |
|
||||
| `steps-state-machine.png` | 会话状态机(IDLE / 倒计时 / OPEN / CLOSED) | `docs/协议规则表与状态机.md`、`src/mcm26b/protocol/client.py` | 图 2(计时模型) |
|
||||
| `timing-attachment-example-105-111-194-199.png` | 附件计时示例:逐动作耗时构成与单步合计 | `docs/协议规则表与状态机.md` | 图 3(计时模型) |
|
||||
| `timing-measured-q3-10-sources.png` | 实测一局:累计虚拟时间按动作类型的堆叠构成 | `referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl` | 图 11(时间分解,演练局) |
|
||||
| `geo-q1-convex-intersection-zoom.png` | 问题一:角域交会总览 + 定位区域放大(直径圆与最小包围圆) | `output/q1/practice/U5ZW-P9KN-TCAG-R7ST_observations.json` | 图 4(a)(问题一,演练观测) |
|
||||
| `geo-q1-diameter-circle-counterexample.png` | 问题一:直径圆不覆盖定位区域的反例(等边三角形布站) | `examples/q1/triangle.json` | 图 4(b)(问题一解析反例) |
|
||||
| `geo-q2-guaranteed-reception-disk.png` | 问题二:截断角域外接圆 `B(c, a)` 与安全候选盘 `B(c, 1000 − a)`,右侧为半径分解 | `src/mcm26b/config.py`、`docs/algo-2.md` | 图 5(问题二) |
|
||||
| `geo-q3-seven-point-coverage.png` | 问题三:七个 1000 m 接收盘覆盖 Ω,标出最差点 | `src/mcm26b/planner/seven.py`、`docs/algo-3.md` | 图 6(问题三) |
|
||||
| `geo-q4-minimum-cover-31-points.png` | 问题四:31 点最小命中集与 ±90° 前向半盘语义 | `src/mcm26b/guarantee/plans/q4_mincover_v2.json` | 图 8(问题四) |
|
||||
| `replay-webui-q3-omnidirectional.png` | 回放画布(点运动图,全向局):世界视图 + 事件流水 + 虚拟时间轴 | `referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl` | 图 7(问题三,演练局) |
|
||||
| `replay-webui-q4-directional.png` | 回放画布(点运动图,定向源局):世界视图(含定向源 ±90° 前向半盘)+ 事件流水 + 虚拟时间轴 | `referee-data/sessions/GHSN-M38E-74GD-YLUD/log.jsonl` | 图 9(问题四,演练局) |
|
||||
| `framework-decision-loop.png` | 观测—候选集—任务—动作的闭环决策过程 | 论文问题分析的结构 | 图 1 |
|
||||
| `steps-state-machine.png` | 会话状态机(未进入 / 倒计时 / 接口开放 / 关闭) | `src/mcm26b/protocol/client.py` | 图 2 |
|
||||
| `timing-attachment-example-105-111-194-199.png` | 附件计时示例:逐动作耗时构成与单步合计 | 题面附件 2 的计时示例 | 图 3 |
|
||||
| `geo-q1-geometry.png` | 问题一三幅几何:角域交会、定位区域放大(直径圆与最小包围圆)、等边三角形反例 | `practice-geometry.json`(演练局观测复算)、`examples/q1/triangle.json` | 图 4 |
|
||||
| `geo-q2-guaranteed-reception-disk.png` | 问题二:截断角域外接圆与安全候选盘,右侧为半径分解 | `src/mcm26b/config.py` | 图 5 |
|
||||
| `geo-q4-minimum-cover-31-points.png` | 问题四:31 点最小命中集分布与定向源读图约定 | `src/mcm26b/guarantee/plans/q4_mincover_v2.json` | 图 6 |
|
||||
| `selfbuilt-q3-search-clear-path.png` | 问题三演练局:全向源搜索与清除路径(含每次检测的位置、结果与示向度射线) | `referee-data/sessions/<问题三主局>/log.jsonl` | 图 7 |
|
||||
| `selfbuilt-q4-search-clear-path.png` | 问题四演练局:混合源路径(含定向源朝向、±90° 可见范围与检测点) | `referee-data/sessions/<问题四主局>/log.jsonl` | 图 8 |
|
||||
| `practice-virtual-time.png` | 44 局演练的总虚拟时间分布与全清局均值 | `practice-results.json` | 图 9 |
|
||||
| `formal-time-bars.png` | 六次正式测试的累计虚拟耗时分解 | `formal-results.csv` | 图 10 |
|
||||
|
||||
后两张是唯一保留自定义画布的图:把回放器画布上的 Ω 与真值源、移动轨迹、
|
||||
检测示向度射线、定向源朝向与清除标记,连同右侧事件流水与底部虚拟时间轴一起导出;
|
||||
定向源局额外画出每个定向源的 **±90° 前向半盘**(半径取该源 `r_eff_m`,朝向箭头即半盘半径)。
|
||||
论文主局案例编码不写死在脚本里:`plot_paper_figures.py` 读取
|
||||
`docs/paper/data/practice-macros.tex` 中的 `PractQThreeMainCase` /
|
||||
`PractQFourMainCase`,与正文口径同源。
|
||||
|
||||
q4 回放固定用演练局 `GHSN-M38E-74GD-YLUD`(`build_figure_data.py::Q4_REPLAY_CASE`);
|
||||
本机没有该局留档时回退到自动挑选,因此 `examples/replay/` 里归档了这一局。
|
||||
|
||||
## 数据来源与复现
|
||||
|
||||
- `timing-measured-*`、`replay-webui-*` 读评测机行为日志(JSONL,含真值)。
|
||||
`referee-data/` 被 `.gitignore` 忽略,因此另归档两局到 `examples/replay/`;
|
||||
没有评测机数据时脚本自动改读归档,图一致。
|
||||
|
||||
```bash
|
||||
uv run python scripts/archive_replay_logs.py --list # 本机有哪些局
|
||||
uv run python scripts/archive_replay_logs.py <案例编码> # 追加归档
|
||||
```
|
||||
|
||||
- `geo-q1-convex-intersection-zoom.png` 读官方演练留档
|
||||
`output/q1/practice/*_observations.json`(同样被忽略)。文件缺失时改读
|
||||
`examples/q1/triangle.json` 反例算例,图仍可用,只是案例不同。
|
||||
- 问题一的几何量由生产求解器 `mcm26b.geometry.solve` 现算;
|
||||
问题三、问题四直接读覆盖计划与证书,不手抄数字。
|
||||
## 归档与回放
|
||||
|
||||
`examples/replay/` 归档了论文主局的行为日志副本,便于在没有 `referee-data/` 时仍能绘图;
|
||||
`scripts/archive_replay_logs.py` 用于把新的演练局追加归档:
|
||||
|
||||
```bash
|
||||
uv run python scripts/archive_replay_logs.py --list # 本机有哪些局
|
||||
uv run python scripts/archive_replay_logs.py <案例编码> # 追加归档
|
||||
```
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB |
@@ -3,30 +3,13 @@
|
||||
"command": "python scripts/plot_paper_figures.py",
|
||||
"manual": "Matplotlib PNGs are generated directly; the legacy MATLAB scripts are no longer used by the paper.",
|
||||
"figures": [
|
||||
{
|
||||
"stem": "flow-overall-architecture",
|
||||
"png": "docs/figures/flow-overall-architecture.png",
|
||||
"matlab": "scripts/matlab/fig_flow_overall.m",
|
||||
"sources": [
|
||||
{
|
||||
"path": "src/mcm26b/config.py",
|
||||
"sha256_12": "c513450dc892",
|
||||
"lines": 213
|
||||
},
|
||||
{
|
||||
"path": "docs/B题建模分析与实施计划.md",
|
||||
"sha256_12": "537aaa5790f3",
|
||||
"lines": 237
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "steps-state-machine",
|
||||
"png": "docs/figures/steps-state-machine.png",
|
||||
"matlab": "scripts/matlab/fig_steps_state_machine.m",
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/协议规则表与状态机.md",
|
||||
"path": "论文“计时模型与会话状态机”一节",
|
||||
"sha256_12": "27c8f7051b26",
|
||||
"lines": 215
|
||||
},
|
||||
@@ -43,7 +26,7 @@
|
||||
"matlab": "scripts/matlab/fig_timing_attachment.m",
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/协议规则表与状态机.md",
|
||||
"path": "论文“计时模型与会话状态机”一节",
|
||||
"sha256_12": "27c8f7051b26",
|
||||
"lines": 215
|
||||
}
|
||||
@@ -60,7 +43,7 @@
|
||||
"lines": 213
|
||||
},
|
||||
{
|
||||
"path": "docs/algo-2.md",
|
||||
"path": "论文“问题二”一节",
|
||||
"sha256_12": "24f3e844deb9",
|
||||
"lines": 312
|
||||
}
|
||||
@@ -77,7 +60,7 @@
|
||||
"lines": 162
|
||||
},
|
||||
{
|
||||
"path": "docs/algo-4.md",
|
||||
"path": "论文“问题四”一节",
|
||||
"sha256_12": "1774f8bf85db",
|
||||
"lines": 485
|
||||
}
|
||||
|
||||
+14
-12
@@ -1,6 +1,8 @@
|
||||
# 论文与支撑材料
|
||||
|
||||
论文依据 issue 题目、2026 年格式规范及所给往届参考 PDF 编写,四问算法对应 docs/algo-1.md 至 algo-4.md。版式采用项目原始 mcm26b-paper.cls。
|
||||
论文依据赛题、2026 年格式规范及所给往届参考 PDF 编写,四问的模型、推导与结果分析
|
||||
均以论文正文与附录为准;本文件只说明论文工程如何重算与编译。
|
||||
版式采用项目原始 `mcm26b-paper.cls`。
|
||||
|
||||
## 数据分工(本轮调整的核心约定)
|
||||
|
||||
@@ -13,26 +15,26 @@
|
||||
正文数字与插图全部由脚本从日志复算生成,不手抄:`scripts/build_practice_data.py` 复算演练局,
|
||||
`scripts/plot_paper_figures.py` 据同一份数据绘图;复算累计虚拟时间与评测机日志记录的最大偏差为 0.000000 s。
|
||||
|
||||
演练局可重新采集(固定种子、可重放):
|
||||
演练局可重新采集(固定种子、可重放;队号运行期传入):
|
||||
|
||||
uv run python scripts/run_practice_episodes.py --problem 3 --counts 10,13,16 --seeds 300-314
|
||||
uv run python scripts/run_practice_episodes.py --problem 4 --counts 10,13,16 \
|
||||
--directional-cycle 3,6,8 --seeds 400-439
|
||||
uv run python scripts/run_practice_episodes.py --problem 3 --robot-id <队号> \
|
||||
--counts 10,13,16 --seeds 300-314
|
||||
uv run python scripts/run_practice_episodes.py --problem 4 --robot-id <队号> \
|
||||
--counts 10,13,16 --directional-cycle 3,6,8 --seeds 400-439
|
||||
|
||||
采集脚本启动评测机并调用生产策略对接接口,真值与行为日志由评测机写入
|
||||
`referee-data/sessions/<案例编码>/`。判定标准为
|
||||
`清完全部源 ∧ 无缺席误判 ∧ 主动退出 ∧ 零异常 ∧ 零失败清除`:
|
||||
只看“是否清完”会放过“清完了但中途大量 /clear 打空”的脏数据,
|
||||
这类局的总虚拟时间被无效试探撑大,必须排除。
|
||||
被排除的局保留在 `referee-data/rejected-sessions/`,历史留档保留在
|
||||
`referee-data/superseded-sessions/`;`build_practice_data.py` 按案例编码白名单
|
||||
只统计论文声明的批次。
|
||||
只看“是否清完”会放过“清完了但中途大量 /clear 打空”的无效局,
|
||||
这类局的总虚拟时间被无效试探撑大,故不纳入统计。
|
||||
被排除的局保留在 `referee-data/rejected-sessions/`;
|
||||
`build_practice_data.py` 按案例编码白名单只统计论文声明的批次。
|
||||
|
||||
## 交付文件
|
||||
|
||||
- main.pdf:论文、演练局数据清单、正式数据清单与四问核心函数代码附录。
|
||||
- main.tex、sections/:可编辑 LaTeX 源文件。
|
||||
- data/practice-results.json、practice-results.csv:25 局演练局的结构化复算结果。
|
||||
- data/practice-results.json、practice-results.csv:44 局演练局的结构化复算结果。
|
||||
- data/formal-results.json、formal-results.csv、audit.md:六份正式测试数据、复算结果与校验说明。
|
||||
- support-materials.zip:源码、自建模拟器、演练局与正式日志、统计快照、论文工程及逐文件哈希清单。
|
||||
- REWRITE_NOTES.md:本次修订及验证说明。
|
||||
@@ -64,7 +66,7 @@
|
||||
latexmk -xelatex -interaction=nonstopmode -halt-on-error -outdir=build main.tex # 产物 build/main.pdf
|
||||
|
||||
两条口令都完成交叉引用所需的多遍编译,输出均为 57 页。
|
||||
需要 TeX Live 的 XeLaTeX、ctex、TikZ,以及原项目 docs/paper/fonts/ 目录。
|
||||
需要 TeX Live 的 XeLaTeX、ctex、TikZ,字体已随仓库提供于 `docs/paper/fonts/`。
|
||||
|
||||
### VS Code(LaTeX Workshop)
|
||||
|
||||
|
||||
@@ -1,6 +1,64 @@
|
||||
# 本次修订与验证
|
||||
|
||||
## VS Code 配方与图 1/图 2 箭头(本轮)
|
||||
## 目录清理、去敏与文档合并(本轮)
|
||||
|
||||
### 身份信息去敏(队号改为运行期参数)
|
||||
|
||||
队号属身份信息,不再出现在代码、测试、示例与文档中:
|
||||
|
||||
- `src/mcm26b/cli.py`:`sim-check` 的 `--robot-id` 默认值由真实队号改为与赛事无关的
|
||||
`SIMCHECK`;`run` 子命令本就 `required=True`。**对接官方模拟器的队号一律由命令行传入**。
|
||||
- `src/mcm26b/harness/simulator.py`、`referee/src/referee/simulator.py`:
|
||||
`robot_id` 由带默认值改为**必填**,杜绝把队号固化进可提交代码。
|
||||
- `scripts/run_practice_episodes.py`:`--robot-id` 改为必填。
|
||||
- `scripts/build_core_notebook.py` 及重新生成的 `mcm26b-核心代码.ipynb`:
|
||||
离线自检单元用中性标识 `OFFLINE`;命令示例同步为 `python -m mcm26b.cli run`。
|
||||
- 测试、`README.md`、`referee/README.md`、referee WebUI 提示文本:
|
||||
真实队号统一替换为中性占位符 `TEAM-0001`。
|
||||
- `referee-data/` 与 `examples/replay/` 下的演练/正式日志(共 110 个文件):
|
||||
`robot_id` 字段统一为中性占位符,**位置、示向度、时间等证据字段原样未动**;
|
||||
改后复算结果完全一致(44 局全清、计时偏差仍为 0.000000 s)。
|
||||
|
||||
### 清理无用文件
|
||||
|
||||
- 删除本机工作区 `tmp/`(43 MB,含历史留档、截图与中间草稿)、`.zcode/`;
|
||||
- 删除论文不再使用的 MATLAB 出图链路:`scripts/matlab/`(17 个文件)、
|
||||
`scripts/build_figure_data.py`、`scripts/render_q1_figures.py`;
|
||||
论文插图现全部由 `scripts/plot_paper_figures.py` 生成;
|
||||
- 删除 LaTeX 陈旧产物(`main-updated.pdf`、`main-check.*`、`main copy.*`)与
|
||||
未被引用的 `docs/paper/sections/comparison.tex`;
|
||||
- 删除 `docs/figures/flow-overall-architecture.png` 及其生成函数:
|
||||
对应的四层主线图已从论文中移除,不再有插图引用它。
|
||||
|
||||
### 优化 .gitignore
|
||||
|
||||
按"只跟踪可复现结果所需的最小集合"重写,补齐 Python/构建/编辑器/操作系统条目,
|
||||
新增忽略 `docs/paper/support-materials.zip`(脚本产物)、`.piptmp/`、`uv-temp/`、`pip-temp/`、
|
||||
`.idea/`、`.zcode/`;保留 `referee-data/` 的版本控制并注明其身份信息已去敏。
|
||||
|
||||
### 文档合并到 README
|
||||
|
||||
论文已完整给出四问的模型、推导与结果分析,故删除 13 份算法与设计说明文档
|
||||
(`docs/algo-*.md`、两份优化方案、示意图册、总体思路、执行时间、协议规则表、
|
||||
最优与基线对比、论文列表),只保留复现所必需的说明:
|
||||
|
||||
- 根 `README.md` 重写为单一操作手册:环境 → 运行程序 → 自建模拟器 →
|
||||
复现论文数据 → 复现插图 → 编译论文 → 单文件核心代码与测试 → 目录结构;
|
||||
- `docs/README.md` 改为最小索引;
|
||||
- `docs/paper/README.md` 与 `docs/figures/README.md` 同步更新(数据分工、重算与编译步骤、
|
||||
插图清单与来源)。
|
||||
- 源码/测试/脚本中原先指向被删文档的注释,统一改为指向论文对应章节,不留悬空引用。
|
||||
|
||||
### 验证
|
||||
|
||||
- `uv run pytest tests referee/tests`:**263 passed, 5 skipped**
|
||||
(5 项为需要 `output/q1/practice` 官方演练采集的可选夹具,缺失时按 skip 处理);
|
||||
- `python scripts/build_practice_data.py`:44 局复算,计时偏差 0.000000 s;
|
||||
- `scripts/build_paper_support.py --package`:278 个文件、3.6 MB,未超 20 MB;
|
||||
- `latexmk -xelatex -outdir=build`:56 页,无未解析引用、无超宽表格;
|
||||
- 绘图脚本无告警,`docs/figures/` 只保留论文实际引用的 10 张 PNG。
|
||||
|
||||
## VS Code 配方与图 2 箭头(前轮)
|
||||
|
||||
- **LaTeX Workshop 默认配方换成与本项目编译口令一致的配方**:
|
||||
`.vscode/settings.json` 现提供三个配方,默认
|
||||
|
||||
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
% This section is intentionally not input by main.tex.
|
||||
% Formal direct metrics are reported in sections/results.tex.
|
||||
Binary file not shown.
@@ -1,208 +0,0 @@
|
||||
# 几何计算示意图册
|
||||
|
||||
> 本册逐图给出坐标口径、关键量与图中各元素的含义。插图位于 [`figures/`](figures/),复现命令:
|
||||
>
|
||||
> ```bash
|
||||
> uv run python scripts/build_figure_data.py --only geo-q1-convex-intersection-zoom,\
|
||||
> geo-q1-diameter-circle-counterexample,geo-q2-guaranteed-reception-disk,\
|
||||
> geo-q3-seven-point-coverage,geo-q4-minimum-cover-31-points
|
||||
> ```
|
||||
>
|
||||
> 图中的数字由脚本现算:问题一调用生产求解器,问题三、四直接读覆盖计划与证书;
|
||||
> 来源与 sha256 记在 [`figures/manifest.json`](figures/manifest.json)。
|
||||
|
||||
统一的坐标与符号约定:
|
||||
|
||||
- 世界坐标以 Ω 圆心为原点,$x$ 轴向右、$y$ 轴向上,单位**米**;
|
||||
- Ω 是半径 $R=1800$ m 的圆盘;源的有效接收半径 $r_{\rm eff}\in[1000,1500]$ m;
|
||||
- 示向度 $\theta$ 以 $+x$ 轴为 $0°$ 逆时针为正,误差半角 $\delta=1°$;
|
||||
- 清除半径 $r_{\rm clear}=20$ m;
|
||||
- "可保证清除" ⟺ 存在一点使整个候选区域落在该点 20 m 内 ⟺ $\rho\le 20$ m(充分)。
|
||||
|
||||
---
|
||||
|
||||
## 图 1 问题一:角域交会与定位区域
|
||||
|
||||

|
||||
|
||||
**左(总览)**:三个检测点(官方演练案例 `U5ZW-P9KN-TCAG-R7ST`,频道 9)
|
||||
各自的**前向角域** $W_i=\{p:\angle(p-s_i)-\theta_i\in[-1°,+1°]\}$ 画成窄扇形
|
||||
(2° 宽,图中放大成可见宽度);三者交集就是定位区域 $P$。检测点相距 600~900 m,
|
||||
而 $P$ 的直径只有 24 m,所以左图里 $P$ 缩成一个点——这是**必须做局部放大**的原因。
|
||||
|
||||
**右(放大,视野 ±20.6 m)**:以定位区域为中心:
|
||||
|
||||
- 浅蓝扇形 = 三个角域在放大框内的可见部分;**橙色多边形** = 三者交集,即定位区域 $P$;
|
||||
- 左图里 $P$ 的直径只有 24 m,缩成一个红色方块,放大后才看得到形状;
|
||||
- 蓝色虚线圆 = **直径圆**,半径 $D/2=11.9984$ m,圆心是中点 $(-450.634,\ 508.944)$;
|
||||
- 绿色实线圆 = **最小包围圆(MEC)**,$\rho=12.0686$ m,圆心 $(-449.977,\ 507.953)$。
|
||||
|
||||
**关键量**
|
||||
|
||||
| 量 | 值 | 判定 |
|
||||
| --- | ---: | --- |
|
||||
| 直径 $D(P)$ | 23.9967 m | 顶点对枚举(凸集上最远点必为顶点) |
|
||||
| MEC 半径 $\rho$ | 12.0686 m | Welzl 算法 + 支撑点枚举对照 |
|
||||
| 直径圆最大超出 $E$ | +0.6040 m | $E>0$ ⇒ **直径圆不覆盖** $P$ |
|
||||
| $\rho\le20$ m | 成立 | ⇒ **存在可保证清除的点**(取 MEC 圆心) |
|
||||
|
||||
> 这两个结论不矛盾:题目问"直径圆能否覆盖"(答案:不能,$E>0$)
|
||||
> 与"能否保证清除"(答案:能,$\rho\le20$ m)是**两个不同的问题**。
|
||||
> $E$ 的定义:$E=\max_i\lVert v_i-o\rVert-D/2$,$o$ 为直径中点;
|
||||
> 精确算术下最远顶点对就在圆周上,故 $E\ge0$,$E>0$ 即覆盖失败,
|
||||
> 达到最大值的顶点就是可独立复核的失败证据。
|
||||
|
||||
---
|
||||
|
||||
## 图 2 问题一:直径圆不覆盖的反例
|
||||
|
||||

|
||||
|
||||
等边三角形布站($S_1(-1000,0)$、$S_2(540,-866)$、$S_3(520,901)$,示向度
|
||||
$1°,121°,241°$,误差半角 $1°$)。三条 2° 宽的角域交出一个**等边三角形**
|
||||
$P$:顶点 $(0,0)$、$(40,0)$、$(20,34.641)$。
|
||||
|
||||
- 直径 $D=40.0000$ m,最远点对是底边两端 ⇒ 直径圆圆心 $(20,0)$、半径 20 m;
|
||||
- 到第三个顶点 $(20,34.641)$ 的距离是 $20\sqrt3\approx34.6410$ m > 20 m,
|
||||
故**直径圆不覆盖**:$E=+14.6410$ m;
|
||||
- 该反例的最小包围圆半径 $\rho=40/\sqrt3\approx23.0940$ m **> 20 m**,
|
||||
属于"覆盖失败且无法保证清除"的更坏情形。
|
||||
|
||||
> 反例是**符合题设测向条件**的:把真实源放在三角形中心 $(20,20\sqrt3/3)$,
|
||||
> 三个检测点的真实方位与读数偏差均小于 $1°$,且三个检测距离都小于 1500 m,
|
||||
> 所以它不是"脱离测向模型的任意图形"。构造与证明见
|
||||
> [`问题一解答.md`](问题一解答.md) 第六节。
|
||||
|
||||
---
|
||||
|
||||
## 图 3 问题二:保证接收的候选盘与安全盘
|
||||
|
||||

|
||||
|
||||
**候选集**(首次观测之后可能的位置集合):
|
||||
|
||||
$$
|
||||
K_1=\Omega\ \cap\ W(s_1,\theta_1\pm\delta)\ \cap\ B(s_1,\ 1500),
|
||||
$$
|
||||
|
||||
即"Omega 内、首次角域内、且距离不超过最大接收半径"的三者之交。
|
||||
|
||||
**解析安全盘**:截断角域(扇形,半径 $R_{\max}=1500$ m、半角 $\delta=1°$)
|
||||
的最小包围圆恰为 $B(c,a)$,其中 $c=s_1+a\boldsymbol u$($\boldsymbol u$ 为示向度单位向量),
|
||||
|
||||
$$
|
||||
a=\frac{R_{\max}}{2\cos\delta}=\frac{1500}{2\cos1°}=750.1142\ \text{m}.
|
||||
$$
|
||||
|
||||
于是对安全盘内任一点 $q$、扇形内任一点 $p$:
|
||||
|
||||
$$
|
||||
\lVert q-p\rVert\le a+(1000-a)=1000\ \text{m}
|
||||
\ \Longrightarrow\ q\ \text{必然收到源的信号},
|
||||
$$
|
||||
|
||||
$$
|
||||
\boxed{\ \text{安全盘半径}=1000-a=249.8858\ \text{m}\ }
|
||||
$$
|
||||
|
||||
(严格非空;图中绿色实心圆,圆心 $c=(649.62,\ 375.06)$)。
|
||||
第二检测点就在该盘内选,目标是**最小化最坏保守后验包围半径**,
|
||||
移动与检测成本作次目标;交会角只用于同分筛选与可解释性说明。
|
||||
|
||||
> 图中 $a$ 与 1000 m 两个圆几乎重合是可预期的:$\delta$ 只有 $1°$,
|
||||
> $a=R_{\max}/(2\cos\delta)$ 与 $R_{\max}/2$ 相差 0.0114%,
|
||||
> 因此**安全盘的"安全"主要来自角域约束,而不是圆心位置**。
|
||||
|
||||
---
|
||||
|
||||
## 图 4 问题三:七点解析覆盖
|
||||
|
||||

|
||||
|
||||
**站点集**:原点 + 半径 $a$ 的六等分环,
|
||||
$S(a)=\{(0,0)\}\cup\{a(\cos k\pi/3,\ \sin k\pi/3):k=0,\dots,5\}$。
|
||||
|
||||
**定理(`algo-3.md` §4.2)** 当 $0<a/\sqrt3\le R$ 时
|
||||
|
||||
$$
|
||||
\max_{g\in\Omega}\min_{s\in S(a)}\lVert g-s\rVert
|
||||
\le D(a):=\max\Bigl\{\frac{a}{\sqrt3},\ \sqrt{R^2+a^2-\sqrt3Ra}\Bigr\}.
|
||||
$$
|
||||
|
||||
代入默认 $a=1159.7$ m、$R=1800$ m:
|
||||
|
||||
$$
|
||||
D(a)=984.5391\ \text{m}<1000\ \text{m}
|
||||
\quad(\text{几何余量 }15.46\ \text{m}).
|
||||
$$
|
||||
|
||||
**图上看到的就是这个证明**:7 个半径 1000 m 的接收盘(浅绿)的
|
||||
并集**完全覆盖** Ω,最坏点出现在 $(0,-1800)$(Ω 正下方边界,图中圈出),
|
||||
到最近站点 $1159.7$ m(正下方环站)的距离恰为 984.54 m。
|
||||
|
||||
数值复核(脚本内 20 m 网格):Ω 内 25445 个采样点全部被覆盖,**缺口 0**——
|
||||
解析上界与数值结果一致到小数点后 3 位。
|
||||
|
||||
**代价对比**:七点每轮 7 次检测即可证明"无源",49 点网格要 49 次;
|
||||
巡回长度 $6a\approx6.96$ km(对照 49 点的 NN 巡回约 36.4 km)。
|
||||
$a$ 的可行下界 $a_{\min}\approx1122.9558$ m(零余量),默认配置留 15 m 以上余量。
|
||||
|
||||
**为什么能"发现即证明"**:某频道若在**全部**站点都测得 `no_signal`,
|
||||
由覆盖定理知该频道必无源(负观测只能排除该站点 1000 m 圆盘,而 $r_{\rm eff}\ge1000$ m),
|
||||
于是可以安全销账;所有频道销账 ⇒ 完成证明成立 ⇒ 立即 `/exit`。
|
||||
|
||||
---
|
||||
|
||||
## 图 5 问题四:定向源的 31 点最小命中集与联合信念
|
||||
|
||||

|
||||
|
||||
**覆盖语义变了**:定向源只向**朝向 $\pm90°$ 的前向半球**辐射,
|
||||
所以"某站点附近一定收到"这件事必须同时考虑**源的位置与朝向**:
|
||||
|
||||
$$
|
||||
\text{站点 }s\text{ 能发现源}\iff
|
||||
\lVert s-\text{pos}\rVert\le r_{\rm eff}\ \wedge\
|
||||
\angle\bigl(\text{heading},\ s-\text{pos}\bigr)\le90°.
|
||||
$$
|
||||
|
||||
这个语义记作 `forward_half_disk`(图中右侧示意)。
|
||||
|
||||
**31 点最小命中集**(`q4_mincover_v2`,图中红点):
|
||||
|
||||
| 项 | 值 |
|
||||
| --- | --- |
|
||||
| 点数 | 31(离线贪心最小命中集,取代 49 点网格) |
|
||||
| 设计参数 | $r_{\rm design}=965$ m + 前向角裕量 $5°$ |
|
||||
| 运行期证书 | 15 m / 72 朝向档,325.62 万个 (位置, 朝向) 采样格,**缺口 0** |
|
||||
| 最坏命中距离 | 990.051 m |
|
||||
| 最近邻巡回 | 23.9 km ≈ 4776.8 s 虚拟时间 |
|
||||
| 旧计划对照 | `q4_mincover_v1` 在 15 m/72 档下有 **566** 个缺口(粗采样过拟合) |
|
||||
|
||||
**位置 × 朝向联合信念**:负观测(`no_signal`)在问题四里**只约束朝向**——
|
||||
它只能排除"朝向正对本站点"的那些朝向档,位置信息几乎不更新。
|
||||
因此证据层维护网格 × 朝向档的联合分布,可见性判据必须与引擎一致
|
||||
(距离 $\le r_{\rm eff}$ 且夹角 $\le90°$),并按格内角裕量保守裁剪。
|
||||
当信念坍缩到有限格时启用**后备盲清**:就近到可疑格 `/clear`,
|
||||
把盲清次数从 125.7 次/局压到 **4.3 次/局**。
|
||||
|
||||
> **本轮修复的正确性缺陷**:旧版 `no_signal` 的朝向裁剪规则反向、且漏计格内角裕量,
|
||||
> 会删掉真源所在的朝向档。已修复,并由
|
||||
> `tests/test_joint_belief.py` 的随机观测序列保留性测试固化。
|
||||
|
||||
---
|
||||
|
||||
## 附:把图接进论文
|
||||
|
||||
`docs/paper/main.tex` 目前用表格承载结论,插图按下例插入即可:
|
||||
|
||||
```latex
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\includegraphics[width=0.95\textwidth]{figures/geo-q1-convex-intersection-zoom.png}
|
||||
\caption{问题一:角域交会得到的定位区域,以及直径圆与最小包围圆的关系。}
|
||||
\label{fig:geo-q1}
|
||||
\end{figure}
|
||||
```
|
||||
|
||||
图片按 160 mm 宽排版。图内不含标题与图注,说明写在 `\caption` 与正文。
|
||||
@@ -1,215 +0,0 @@
|
||||
# 协议规则表、字段表与状态机(P0 交付)
|
||||
|
||||
依据:`issue/附件/附件1.docx`《模拟器使用说明》、`issue/附件/附件2.docx`《模拟器通信接口说明及编程指南》。
|
||||
本文是人类可读版本;**可执行版本**是 `src/mcm26b/protocol/rules.py`(字段表与错误语义)、
|
||||
`src/mcm26b/protocol/timing.py`(计时模型)与 `src/mcm26b/config.py`(全部常量),
|
||||
三者由 `tests/test_protocol_timing.py`、`tests/test_protocol_client.py` 固化验收。
|
||||
|
||||
## 1. 动作与耗时规则表
|
||||
|
||||
| 动作 | 指令 | 虚拟耗时 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| 开始 | `POST /enter` | 0 | 初始位置 (0,0),初始频道 1;虚拟/程序时钟开始 |
|
||||
| 检测 | `POST /measure` | 5 + 移动 + 换频道 | 无论结果(no_signal/near/direction)均为 5s |
|
||||
| 清除 | `POST /clear` | 未发现 3 / 成功 5 + 移动 | 5 = 光学定位 3 + 激光清除 2;**不切换测向频道** |
|
||||
| 结束 | `POST /exit` | 0 | 成功响应中 exit_reason 固定 `user_exit` |
|
||||
| 切换频道 | 无独立指令 | 1 | 只由合法 `/measure` 的 channel 变化推断 |
|
||||
| 移动 | 无独立指令 | 直线距离/5(m/s) | 由 `/measure` 或 `/clear` 的 position 推断 |
|
||||
|
||||
派生事实(易错点):
|
||||
- 一次合法 `/measure` 完成后,测向机频道更新为本次检测频道;
|
||||
- `/clear` 的 channel 只是目标频道,既不切频道、也不产生切换耗时,因此
|
||||
"清除后原地再测"的耗时只取决于上一次 **/measure** 的频道;
|
||||
- 只有 accepted=true 的请求推进虚拟时钟;`accepted=false` 的 virtual_time_s=0 不是当前时刻;
|
||||
- 5 秒检测只是虚拟耗时,不要求现实等待。
|
||||
|
||||
## 2. 字段表
|
||||
|
||||
公共请求字段(4 条指令都必填):
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| arena_id | string | 必须为 `"default"` |
|
||||
| robot_id | string | 逐字节等于登录参赛队号;UTF-8 长度 1..64;无控制字符 |
|
||||
| request_id | string | 会话内幂等键;UTF-8 长度 1..128;无控制字符 |
|
||||
|
||||
动作字段(实现见 `rules.ACTION_FIELDS`):
|
||||
|
||||
| 指令 | 字段 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| /enter | (无附加) | |
|
||||
| /measure | position{x,y}, channel | x/y 有限数值且 \|v\|<=2,000,000;channel 整数 1..20(1.0 亦接受,1.5 拒绝) |
|
||||
| /clear | position{x,y}, channel | 同上;channel 是目标频道 |
|
||||
| /exit | (无附加) | |
|
||||
|
||||
响应字段:
|
||||
|
||||
| 场景 | 字段 |
|
||||
| --- | --- |
|
||||
| 所有响应 | accepted, real_timestamp_ms, virtual_time_s |
|
||||
| accepted=false | 仅上述 3 个字段(virtual_time_s=0) |
|
||||
| /enter 成功 | + max_virtual_duration_s, max_real_duration_s, remaining_real_duration_s |
|
||||
| /measure 成功 | + measure_result ∈ {no_signal, near, direction};direction 时另有 svd_deg(保留两位小数) |
|
||||
| /clear 成功 | + clear_result ∈ {success, no_target_in_range} |
|
||||
| /exit 成功 | + exit_reason = "user_exit" |
|
||||
|
||||
错误语义(必须同时检查 HTTP 状态与 accepted):
|
||||
|
||||
| 情形 | 结果 | 对 request_id 的影响 |
|
||||
| --- | --- | --- |
|
||||
| JSON 语法/重复键/缺字段/类型/坐标频道范围 | HTTP 400 | 不占用,修正后可复用 |
|
||||
| 未知字段(含 position 下)、arena/robot 不匹配、测试状态拒绝 | HTTP 200, accepted=false | 不占用 |
|
||||
| 动作被接受 | HTTP 200, accepted=true | 占用 |
|
||||
| 同 ID 不同内容,或并发不同动作 | HTTP 409 | — |
|
||||
| 网络失败重试同一动作 | 复用原 ID+原内容,服务器回放首次响应 | 不重复生效 |
|
||||
| 429/500 | 可原样重试 | — |
|
||||
| 404/405/413/415 | 确定性错误,不得重试 | — |
|
||||
|
||||
物理规则速查:Ω 半径 1800m;源数 10–16;频道 1–20;接收半径 [1000,1500]m(逐源未知);
|
||||
near 阈值 5m;清除半径 20m(与定向朝向无关);定向覆盖 = 朝向两侧各 90°(含边界);
|
||||
示向度误差幅度 ±1°,保留两位小数;虚拟限时 360000s;程序限时 1200s(以 /enter 的
|
||||
remaining_real_duration_s 为准,不得假定恒为 1200);测试窗口 25 分钟。
|
||||
|
||||
## 3. 状态机
|
||||
|
||||
机器狗会话状态(`protocol.state.RobotState` + 客户端会话标志):
|
||||
|
||||
```
|
||||
/enter accepted /exit accepted
|
||||
[未进入] ───────────────▶ [已进入] ───────────────▶ [已退出]
|
||||
│ accepted=false │ accepted=false │ 任何动作 accepted=false
|
||||
└── 不变 └── 不变 └── 不变
|
||||
```
|
||||
|
||||
[已进入] 状态内跟踪:position、测向机 channel、virtual_time_s。转移规则:
|
||||
|
||||
| 事件 | position | channel | virtual_time_s |
|
||||
| --- | --- | --- | --- |
|
||||
| /enter accepted | (0,0) | 1 | 0 |
|
||||
| /measure accepted | ← 本次 position | ← 本次 channel | ← 响应值(=旧值+移动+切换+5) |
|
||||
| /clear accepted | ← 本次 position | **不变** | ← 响应值(=旧值+移动+3或5) |
|
||||
| /exit accepted | 不变 | 不变 | ← 响应值 |
|
||||
| accepted=false / 网络 / 400 | 不变 | 不变 | 不变 |
|
||||
|
||||
虚拟时刻以最近一次 accepted=true 的响应为准;本地预测(timing 模块)只用于
|
||||
规划与一致性核对,偏差记入 `RobotState.mismatches` 并写日志(strict 模式抛错)。
|
||||
|
||||
## 4. 计时示例逐步推演(附件1表2 = 附件2第10节)
|
||||
|
||||
| 步 | 指令 | 移动 | 换频道 | 动作 | 本步 | 累计 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| 1 | /enter | 0 | 0 | 0 | 0 | **0** |
|
||||
| 2 | /measure (300,400) ch1 | 500m→100s | 0(初始即1) | 5 | 105 | **105** |
|
||||
| 3 | /measure (300,400) ch2 | 0 | 1 | 5 | 6 | **111** |
|
||||
| 4 | /clear (300,0) 目标ch3 | 400m→80s | 0(clear不切频道) | 3(未发现) | 83 | **194** |
|
||||
| 5 | /measure (300,0) ch2 | 0 | 0(第3步后已是2,clear未改) | 5 | 5 | **199** |
|
||||
| 6 | /exit | 0 | 0 | 0 | 0 | **199** |
|
||||
|
||||
验收:`uv run mcm26b sim-check` 通过完整客户端→本地模拟器链路复现
|
||||
`[105, 111, 194, 199]`;`tests/test_protocol_timing.py::TimingModelTests`
|
||||
逐步断言每个分项。
|
||||
|
||||
## 5. 客户端设计要点(P1 交付)
|
||||
|
||||
- **串行**:完全同步,一个动作未决不发下一个;
|
||||
- **幂等重试**:请求体一次性序列化为 bytes,网络失败/429/500 时原样重发
|
||||
(同 request_id 同内容),最多 `max_attempts` 次,指数退避;400/404/405/409/413/415 立即失败;
|
||||
- **accepted=false**:抛 `ActionRejected`,状态不更新;virtual_time_s=0 不入时钟;
|
||||
- **现实预算**:/enter 成功后 `deadline = monotonic() + remaining_real_duration_s`;
|
||||
新动作前检查 `剩余 > reserve_exit_s`(默认 60s [工程]),/exit 豁免;
|
||||
- **日志**:`SessionLog` 逐事件追加 JSONL(attempt/transport_error/accepted),
|
||||
进程崩溃不丢已发记录,回放测试与 evaluation 复算共用同一格式;
|
||||
- **本地预校验**:channel 范围、坐标有限性与 2e6 上限、robot_id/request_id 格式
|
||||
在发送前拒绝(与服务器 400 语义一致,省一次往返)。
|
||||
|
||||
## 6. 策略层如何使用本协议(P3/P4 交付)
|
||||
|
||||
第 5 节的客户端是策略层唯一的事实来源;`belief`(候选集)、`planner`(选点与闭环)
|
||||
不绕开它直接发请求。衔接约定:
|
||||
|
||||
- **串行不变**:闭环每个决策步只发一个动作,`measure`/`clear` 的返回值
|
||||
(`MeasureOutcome`/`ClearOutcome`)是 belief 更新的唯一输入;
|
||||
- **状态同步**:机器人位置/测向频道/虚拟时刻一律读 `client.state`,
|
||||
频道规则(§3 状态机表)由状态机自动维护,策略层不自行推算;
|
||||
- **预算驱动退出**:`DeadlineExceeded` 只在 `/exit` 之外的动作前抛出;
|
||||
闭环捕获后立即 `/exit`(豁免检查),并把该局记为"未证明完成",
|
||||
不与全清成功混记;
|
||||
- **选点的接收保证**:选点器只在保证接收盘 B(mec, 1000-ρ) 内取点,
|
||||
盘内任一点到候选集每点距离 < 1000 ≤ 最小接收半径,因此定位阶段
|
||||
不会浪费 `no_signal`(ρ>1000 的一般候选集退化为探索 MEC 圆心,允许
|
||||
no_signal,理由字段中如实标注);
|
||||
- **清除证书**:候选集外包多边形半径(含近似误差与工程余量)
|
||||
≤ 20m 才发起 `/clear`;证书有效但清除失败视为异常,先补测再重试,
|
||||
不在同一证书上重复消耗 3 秒/次的失败清除;
|
||||
- **停止条件与完成判定**(2026-09-11 用户决策后):找全证明达成
|
||||
(每频道均"已清除或覆盖证明不存在",或清除数达 16 数量上界)后
|
||||
**不提前退出**:按 `search.persistent_search`(默认开)只复扫未清除
|
||||
频道,直到清除数达 16、实机预算耗尽或虚拟安全余量
|
||||
(`virtual_reserve_s`,防触及附件2 §4.5 的 100 小时上限;
|
||||
本地模拟器对达限后的动作以 accepted=false 兜底)不足——"扫到限时为止"。
|
||||
summary 中 `completed` 表示任务证明完成(无中断且结束时每频道
|
||||
CLEARED/ABSENT,或 16 清除);`accounted_virtual_time_s` 记录首次
|
||||
证明找全的虚拟时刻(计算"平均定位清除时间"建议用它,而非复扫
|
||||
耗尽后的最终时刻);`stop_reason` 记录循环结束原因。发现若干源、
|
||||
连续 no_signal、候选采样为空都不是停止条件;
|
||||
- **每步计时留痕**(同上决策):客户端每个被接受动作写一条 `step`
|
||||
事件(实机墙钟耗时 `real_elapsed_s`/`real_since_enter_s` + 比赛虚拟
|
||||
耗时分项 `virtual_cost`:移动=直线距离/5、切频道 1s、检测 5s、
|
||||
清除成功 5s/未发现 3s),summary 以 `steps` 数组与 `step_totals`
|
||||
汇总,并给出题面口径的 `avg_locate_clear_time_s`;
|
||||
- **验收**:`tests/test_loop_q3.py` 在自建模拟器上覆盖 10/16/0 源、
|
||||
近边界源、预算耗尽与故障注入;`uv run mcm26b run --robot-id <队号>
|
||||
--self-test` 可离线复跑随机场景,正式模式去掉 `--self-test` 即对接
|
||||
模拟器(日志用 `--log` 落盘,格式同 §5 JSONL)。
|
||||
|
||||
## 7. 定向扩展如何使用本协议(P5 交付)
|
||||
|
||||
问题4的定向源在**协议字段上与全向源完全不可区分**:`/measure` 仍只返回
|
||||
no_signal/near/direction(direction 附 svd_deg),`/clear` 仍只看 20m 半径。
|
||||
"该源是定向的"无法从报文读出,只能由观测推理。因此 §5/§6 的协议用法全部
|
||||
照用,定向性只改变策略层的解释与决策:
|
||||
|
||||
- **发现阶段零改动**:49 点覆盖保证对定向源同样成立——源位于某网格单元
|
||||
凸包内时,任意发射半平面(朝向 ±90°,含边界)必含至少一个顶点,且该
|
||||
顶点距离 ≤ 700√2 ≈ 989.95 < 1000 ≤ 最小接收半径,覆盖阶段无需知道
|
||||
源类型;
|
||||
- **no_signal 联合约束基线**:定向源的 no_signal 约束的是"位置×半径×朝向"
|
||||
联合假设,单独维护空间候选会被误删,基线**不据此删任何候选**
|
||||
(`belief.update_measure` 对 no_signal 无操作);缺席证明仍只由完整覆盖
|
||||
给出。唯一启用的推理:若 no_signal 发生在保证接收盘 B(mec, 1000-ρ) 内
|
||||
(该盘内任一全向源必然可收),则只能由朝向遮挡解释 [观测推理]——该频道
|
||||
记为"观测到定向",进入探点升级梯子:对 MEC 圆心取对跖方向复核(偏移
|
||||
裁进保证接收盘),再绕 MEC、半径 = ρ 的圆环按 45° 步进探点。**几何边界
|
||||
必须如实陈述**:环上可见弧没有下界——源可位于环上(|g−c| = ρ)且朝向
|
||||
沿外切线,此时可见集退化为单个切点,固定步进环探可以全部漏过。梯子
|
||||
只提高提前命中概率,不构成接收或命中保证;完备性完全由后备清除兜底。
|
||||
被遮挡探点不消耗定位步数,单轮被遮挡探点(首次选点、对跖复核、环探
|
||||
合计)达 `max_blocked_probes`(4 [工程])即转后备清除;
|
||||
- **后备清除的协议用法**:定位停滞(候选集有界但未达 §6 清除证书)时,
|
||||
对候选外包多边形构造 20m 有限圆盘覆盖(`fallback_clear_cells`:全局
|
||||
半开网格索引、相交判定带正容差,格内任一点距某格心 ≤ 10√2 < 20m),
|
||||
按"距机器人最近优先"逐格发 `/clear`(同频道、不同位置)——清除与朝向
|
||||
无关 [题面],是定向源不依赖可见性的完备后备。两条预算硬门槛(任一
|
||||
不满足即跳过并留痕,绝不盲扫):
|
||||
- 格数上界:N ≤ `fallback_max_cells`(400 [工程]);外包框枚举先按
|
||||
(⌈w/20⌉+2)(⌈h/20⌉+2) 做规模检查,宽候选集(如仅一次读数的 750m
|
||||
截断角域,数千格)必须继续定位而非硬扫;
|
||||
- 现实预算:N × `real_rtt_p95_s` + `reserve_exit_s` ≤ 剩余现实时间。
|
||||
虚拟耗时上界 ≈ 移动 L/5 + 3N(全失败)或 3(N-1)+5(末次成功)。
|
||||
后备 /clear 请求**计入总请求口径**:summary 的 `total_requests`
|
||||
(measures+clears)与 `fallback_clear_attempts`(后备逐格尝试数)
|
||||
如实上报——仅统计检测次数会明显低估现实耗时;
|
||||
- **真源不误删**:no_signal、失败的 `/clear`(含后备逐格全失败)均不删
|
||||
空间候选;后备全失败按守恒性破坏记异常(格心距格内任一点 < 20m,
|
||||
理论上必命中);
|
||||
- **停止条件与预算语义不变**:仍是清除数达 16、每频道均"已清除或覆盖
|
||||
证明不存在"、现实预算耗尽(记未证明完成)三种;断连/协议错误/
|
||||
守恒性破坏中断时同样尽力 /exit 并产出未完成 summary(`stop_reason`
|
||||
记 `transport_failure`/`protocol_error`/`inconsistent_belief` 等,
|
||||
附逐频道状态快照),不静默丢失会话;
|
||||
- **验收**:`tests/test_loop_q4.py`(15 项:覆盖格无空洞与格线两侧保留、
|
||||
退化多边形、格数上界公式;混合 10/16 源全清、朝向背离圆心的近边界源
|
||||
不漏、批量种子回归;no_signal 不删候选;格数硬顶与预算跳过;后备
|
||||
正路径命中与全失败异常留痕);`uv run mcm26b run --robot-id <队号>
|
||||
--problem 4 --self-test` 可离线复跑混合场景(`--directional` 指定
|
||||
定向源数),正式模式同 §6。
|
||||
@@ -1,178 +0,0 @@
|
||||
# 总体思路与流程图
|
||||
|
||||
> 插图:[`figures/flow-overall-architecture.png`](figures/flow-overall-architecture.png)(总体思路与算法主线)、
|
||||
> [`figures/steps-state-machine.png`](figures/steps-state-machine.png)(执行步骤)、
|
||||
> [`figures/timing-attachment-example-105-111-194-199.png`](figures/timing-attachment-example-105-111-194-199.png)(附件计时示例)。
|
||||
> 复现:`uv run python scripts/build_figure_data.py --only flow-overall-architecture,steps-state-machine,timing-attachment-example-105-111-194-199`
|
||||
|
||||
本文给出四问的思路、端到端流程图、执行步骤与执行时间。
|
||||
算法细节指向 [`algo-1.md`](algo-1.md)~[`algo-4.md`](algo-4.md),
|
||||
协议细节指向 [`协议规则表与状态机.md`](协议规则表与状态机.md)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 主线
|
||||
|
||||
把题面约束写成可计算的几何集合和计时账本,四问共用一套「证据 — 决策 — 执行」结构,
|
||||
每问都给出可验证的保证:
|
||||
|
||||
| 问 | 保证 |
|
||||
| --- | --- |
|
||||
| 1 | 直径由顶点对枚举给出;最小包围圆半径 $\rho\le20$ m 时存在可保证清除的点 |
|
||||
| 2 | 第二检测点取在解析安全盘 $B(c,1000-a)$(半径 249.8858 m)内,必然收到信号 |
|
||||
| 3 | 七点计划覆盖整个 Ω(解析上界 984.5391 m < 1000 m),据此可判定频道无源 |
|
||||
| 4 | 31 点最小命中集在 15 m / 72 朝向档证书下缺口为 0 |
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 2. 四层结构
|
||||
|
||||
| 层 | 内容 | 作用 |
|
||||
| --- | --- | --- |
|
||||
| L0 题面抽象 | Ω 半径 1800 m;移动 5 m/s、检测 5 s、换频 1 s、清除 5 s / 3 s;观测 `direction/no_signal/near`;源 10~16 个,频道 1~20,定向源覆盖 ±90° | 后续推导只用这些量,不引入题面之外的信息 |
|
||||
| L1 在线三层 | 证据层(候选集与粒子)、决策层(选点与任务表)、执行层(串行客户端) | 依赖单向向下,几何结论与调度启发式可分别测试 |
|
||||
| L2 四问 | Q1 定位解算 → Q2 第二点选择 → Q3 全向搜索 → Q4 混合定向 | 后一问复用前一问的内核 |
|
||||
| L3 三条闭环 | 发现、定位、清除 | 每环有明确的进入与退出条件 |
|
||||
|
||||
L0 的常量集中在 `src/mcm26b/config.py`,带 `[题面]` / `[工程]` 标注。
|
||||
证据层只给出「可能在哪里」,决策层只读证据并产出动作,
|
||||
执行层负责发送动作并维护虚拟时钟。
|
||||
|
||||
---
|
||||
|
||||
## 3. 四问思路
|
||||
|
||||
### 问题一
|
||||
|
||||
1. 检测点 $s_i$ 与示向度 $\theta_i$ 给出前向角域
|
||||
$W_i=\{p:\angle(p-s_i)-\theta_i\in[-1°,+1°]\}$,定位区域是半平面交 $P=\bigcap_i W_i$;
|
||||
2. 直径 $D(P)=\max_{i,j}\lVert v_i-v_j\rVert$ 只需枚举顶点对(凸集上最远点必为顶点);
|
||||
3. 直径圆能否覆盖 $P$:唯一候选圆心是最远顶点对的中点。若 $a,b$ 同在该圆内,
|
||||
三角不等式两处同时取等,圆心只能是 $ab$ 中点,因此只需在该点检查全部顶点;
|
||||
4. 能否保证清除:最小包围圆半径 $\rho\le20$ m 时,停在 MEC 圆心即可清除。
|
||||
这是充分条件,不是必要条件。
|
||||
|
||||
结论:直径圆不一定覆盖定位区域,见 [`geo-q1-counterexample.png`](figures/geo-q1-diameter-circle-counterexample.png);
|
||||
官方演练案例是「覆盖失败但 $\rho=12.07$ m $\le20$ m,可保证清除」。
|
||||
|
||||
### 问题二
|
||||
|
||||
候选集 $K_1=\Omega\cap W(s_1,\theta_1\pm\delta)\cap B(s_1,1500)$。
|
||||
截断角域(扇形)的最小包围圆为 $B(c,a)$,$a=R_{\max}/(2\cos\delta)=750.1142$ m,
|
||||
故安全盘 $B(c,1000-a)$ 的半径为 249.8858 m,盘内任一点到扇形内任一点的距离
|
||||
不超过 1000 m,即必然收到信号。在该盘内以最坏保守后验包围半径为主目标选点,
|
||||
移动与检测成本作次目标,交会角只用于同分筛选。详见 [`algo-2.md`](algo-2.md)。
|
||||
|
||||
### 问题三
|
||||
|
||||
发现保证用七点计划(原点 + 半径 $a=1159.7$ m 的六等分环):解析上界
|
||||
$D(a)=\max\{a/\sqrt3,\ \sqrt{R^2+a^2-\sqrt3Ra}\}=984.5391$ m < 1000 m,
|
||||
Ω 内任意位置的源都在某站点 1000 m 内。证据层按频道维护候选集与粒子幸存集,
|
||||
负观测按 `full_disk` 语义排除 1000 m 圆盘;决策层用信息增益选点,
|
||||
任务表包含检测、定位、清除三类任务,排序为开放路径问题;
|
||||
所有频道销账即完成证明成立,立即 `/exit`。
|
||||
|
||||
### 问题四
|
||||
|
||||
定向源只向朝向 ±90° 的前向半球辐射,覆盖语义改为 `forward_half_disk`。
|
||||
七点在该语义下有缺口,改用离线贪心得到的 31 点最小命中集(设计半径 965 m,
|
||||
前向角裕量 5°),并以 15 m / 72 朝向档的运行期证书校核(325.62 万个采样格,缺口 0,
|
||||
最坏命中 990.05 m)。负观测只约束朝向,因此维护位置 × 朝向联合信念,
|
||||
信念坍缩到有限格时使用后备盲清。详见 [`algo-4.md`](algo-4.md)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 端到端流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S([开始:/enter 成功<br/>现实预算 1200 s 起算]) --> P0[读配置 ProblemConfig]
|
||||
P0 --> PLAN{按问题选择覆盖计划}
|
||||
PLAN -->|问题 3| S7[七点全向计划<br/>解析上界 984.54 m]
|
||||
PLAN -->|问题 4| S31[31 点最小命中集<br/>forward_half_disk 证书]
|
||||
S7 --> LOOP
|
||||
S31 --> LOOP
|
||||
|
||||
subgraph LOOP[主循环:动作回合]
|
||||
direction TB
|
||||
NEXT[选下一个任务<br/>信息增益 / 最坏后验半径<br/>滚动 2-opt 排序] --> SEND[/发送动作/]
|
||||
SEND --> RESP{accepted?}
|
||||
RESP -->|false| FIX[不更新状态<br/>记录并重排任务]
|
||||
RESP -->|true| CLK[更新虚拟时钟、位置、频道]
|
||||
FIX --> NEXT
|
||||
CLK --> OBS{观测类型}
|
||||
OBS -->|direction| HIT[登记新源<br/>同频道安排第二点交会]
|
||||
OBS -->|no_signal| NEG[负观测裁剪<br/>位置候选或朝向档]
|
||||
OBS -->|near| SKIP[距离过近,换点重测]
|
||||
HIT --> DONE{该频道 ρ ≤ 20 m?}
|
||||
NEG --> DONE
|
||||
SKIP --> DONE
|
||||
DONE -->|是| CLR[/清除动作/]
|
||||
DONE -->|否| NEXT
|
||||
CLR --> LEDGER[覆盖账本销账]
|
||||
LEDGER --> FIN{全部频道销账?}
|
||||
FIN -->|否| NEXT
|
||||
end
|
||||
|
||||
FIN -->|是| EXITQ[完成证明成立,立即 /exit]
|
||||
EXITQ --> REP[日志复算与统计]
|
||||
REP --> END([结束:虚拟时间即成绩])
|
||||
|
||||
classDef main fill:#dce6f1,stroke:#1f4e79,color:#1c2430
|
||||
classDef acc fill:#f6dcd8,stroke:#b03a2e,color:#1c2430
|
||||
classDef ok fill:#d8ece5,stroke:#1e7a5f,color:#1c2430
|
||||
class NEXT,SEND,RESP,CLK,OBS main
|
||||
class CLR,FIN,EXITQ acc
|
||||
class LEDGER,REP ok
|
||||
```
|
||||
|
||||
会话状态机与单次动作回合见 [`figures/steps-state-machine.png`](figures/steps-state-machine.png),
|
||||
逐步计时示例见 [`figures/timing-attachment-example-105-111-194-199.png`](figures/timing-attachment-example-105-111-194-199.png)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 执行步骤与执行时间
|
||||
|
||||
一次动作回合:本地预校验 → 发送 → 等响应计时 → 按响应更新状态。
|
||||
异常时同 `request_id` 同内容重发,400 与 409 立即失败。
|
||||
|
||||
| 动作 | 虚拟耗时 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `/enter`、`/exit` | 0 s | 不改变虚拟时刻,`/exit` 不切频道 |
|
||||
| 移动 | 直线距离 / 5 m·s⁻¹ | 同点不动为 0 s |
|
||||
| 换测向频道 | 1 s | 仅 `/measure` 触发,`/clear` 不切换 |
|
||||
| 检测 `/measure` | 5 s | 与返回结果无关 |
|
||||
| 清除 `/clear` | 5 s / 3 s | 成功 5 s,未发现 3 s |
|
||||
|
||||
实测样例(评测机日志 `BBM9-HZG2-77N5-NKKC`,问题三演练,10 源全清):
|
||||
|
||||
| 项 | 数值 |
|
||||
| --- | --- |
|
||||
| 总虚拟时间 | 3134.643 s |
|
||||
| 移动(里程 11.9 km) | 2379.6 s |
|
||||
| 检测与清除动作(119 + 10 次) | 645.0 s |
|
||||
| 换频(110 次) | 110.0 s |
|
||||
| 现实耗时 | 1.889 s |
|
||||
|
||||
三项之和等于响应中的 `virtual_time_s`,与 `evaluation.recompute_virtual_time` 口径一致。
|
||||
分解图见 [`figures/timing-measured-q3-10-sources.png`](figures/timing-measured-q3-10-sources.png),
|
||||
定向局(`GM56-…`,虚拟 8703.766 s,现实 3.397 s)与复现命令见
|
||||
[`执行时间与执行步骤.md`](执行时间与执行步骤.md)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 交付物与验收锚点
|
||||
|
||||
| 问 | 算法文档 | 主要实现 | 锚点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | [`algo-1.md`](algo-1.md)、[`问题一解答.md`](问题一解答.md) | `src/mcm26b/geometry/` | 演练复算 $D=23.9967$ m、$\rho=12.0686$ m、$E=+0.6040$ m |
|
||||
| 2 | [`algo-2.md`](algo-2.md) | `geometry/`、`belief/`、`planner/` | 安全盘半径 249.8858 m |
|
||||
| 3 | [`algo-3.md`](algo-3.md)、[`algo-3-bayes.md`](algo-3-bayes.md) | `planner/bayes_loop.py`、`planner/seven.py` | 七点上界 984.5391 m < 1000 m |
|
||||
| 4 | [`algo-4.md`](algo-4.md) | `planner/directional.py`、`belief/joint.py` | 证书缺口 0,最坏命中 990.05 m |
|
||||
| 1–4 | [`最优与基线实现对比.md`](最优与基线实现对比.md) | `project/` | `uv run python -m project.run` |
|
||||
|
||||
优化过程与未采用的改动见
|
||||
[`第三四问架构优化与运行提速方案.md`](第三四问架构优化与运行提速方案.md)、
|
||||
[`第三四问图论与动态规划优化方案.md`](第三四问图论与动态规划优化方案.md)。
|
||||
@@ -1,178 +0,0 @@
|
||||
# 执行时间与执行步骤
|
||||
|
||||
> 配套插图:[`figures/steps-state-machine.png`](figures/steps-state-machine.png)(状态机与动作回合)、
|
||||
> [`figures/timing-attachment-example-105-111-194-199.png`](figures/timing-attachment-example-105-111-194-199.png)(附件示例逐步推演)、
|
||||
> [`figures/timing-measured-q3-10-sources.png`](figures/timing-measured-q3-10-sources.png)(实测一局的时序分解)。
|
||||
> 复现:`uv run python scripts/build_figure_data.py --only steps-state-machine,timing-attachment-example-105-111-194-199,timing-measured-q3-10-sources`
|
||||
|
||||
本文说明每一步做什么、每步花多少虚拟时间、这些数字如何验证。
|
||||
规则原文见 `issue/` 下附件1 表1、表2 与附件2 第 4、10 节;
|
||||
可执行表格在 `src/mcm26b/protocol/rules.py` 与 `src/mcm26b/config.py` 的 `CostConfig`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 计时模型
|
||||
|
||||
忽略微秒量化时,一次会话的总虚拟时间为
|
||||
|
||||
$$
|
||||
T=\underbrace{\frac{L}{5}}_{\text{移动}}+\underbrace{5N_m}_{\text{检测}}
|
||||
+\underbrace{N_s}_{\text{换频}}+\underbrace{5N_c^{+}}_{\text{清除成功}}
|
||||
+\underbrace{3N_c^{-}}_{\text{清除未发现}},
|
||||
\qquad L=\text{路径长度(米)},\ 5\ \text{m/s}.
|
||||
$$
|
||||
|
||||
规则:
|
||||
|
||||
- 移动按两点间直线距离计,不计加减速;
|
||||
- 换频只在 `/measure` 触发,任意两频道间固定 1 s,`/clear` 不切换频道;
|
||||
- 检测固定 5 s,与结果无关,`direction` 与 `no_signal` 同价;
|
||||
- 清除成功 5 s(光学定位 3 s + 激光清除 2 s),未发现目标 3 s(仅光学定位);
|
||||
- `/enter`、`/exit` 不产生虚拟时间;
|
||||
- 访问顺序是开放路径问题,起点固定、终点自由,不必回到起点。
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 2. 执行步骤
|
||||
|
||||
### 2.1 会话级状态机
|
||||
|
||||
| 状态 | 进入条件 | 允许的动作 | 退出条件 |
|
||||
| --- | --- | --- | --- |
|
||||
| `IDLE` | 界面待机(演练不限次 / 正式各 3 次) | — | 点击"开始测试" |
|
||||
| `COUNTDOWN` | 数据准备完成 | —(接口未开放) | 5 s 倒计时结束 |
|
||||
| `OPEN` | 倒计时结束,接口在 `:2026` 开放 | `/enter` → `/measure` `/clear` → `/exit` | 25 分钟窗口到期 / 源全清后主动 `/exit` / 中止 |
|
||||
| `CLOSED` | 窗口到期或进程退出 | —(连接关闭,已登记动作可完成) | — |
|
||||
|
||||
现实预算与现实窗口是两条独立时钟:`/enter` 成功后 `max_real_duration_s = 1200 s`
|
||||
起算(程序侧),测试窗口 `test_window_s = 1500 s`(服务端侧)。
|
||||
客户端维护本地截止时钟,剩余不足 60 s(`reserve_exit_s`,工程参数)时不再发起新动作,
|
||||
只保证 `/exit` 能发出去。
|
||||
|
||||
### 2.2 单次动作回合(严格串行)
|
||||
|
||||

|
||||
|
||||
1. 本地预校验:`channel ∈ [1,20]`、坐标有限且 $\lvert x\rvert,\lvert y\rvert\le 2\times10^6$、
|
||||
`request_id` 长度与字符集,与服务器 400 语义一致,省一次往返;
|
||||
2. 串行发送:同一时刻只有一个未决请求,不并发(并发会得到 409);
|
||||
3. 等服务端计时:`accepted=true` 才更新状态,虚拟时刻取响应中的 `virtual_time_s`,
|
||||
不做本地累加;`accepted=false` 抛 `ActionRejected`,状态不更新,
|
||||
`virtual_time_s=0` 不计入时钟;
|
||||
4. 更新本地状态:位置、当前频道、剩余现实预算,追加 JSONL 会话日志;
|
||||
5. 异常处理:网络错误、429、500 时同 `request_id` 同内容重发
|
||||
(请求体一次性序列化,最多 `max_attempts` 次,指数退避);
|
||||
400、404、405、409、413、415 立即失败。
|
||||
|
||||
重发不会重复计时,服务端按 `request_id` 幂等。
|
||||
|
||||
### 2.3 任务类型
|
||||
|
||||
| 任务 | 触发 | 动作序列 | 虚拟成本 |
|
||||
| --- | --- | --- | --- |
|
||||
| 覆盖扫描 | 某频道尚未被任何站点覆盖 | 移动到覆盖点 → `/measure` | 距离/5 + 5 s(+ 换频 1 s) |
|
||||
| 定位交会 | 某频道收到 `direction` | 移动到第二检测点 → `/measure` | 距离/5 + 5 s(+ 1 s) |
|
||||
| 清除 | 同频道候选区域 ρ ≤ 20 m | 移动到 MEC 圆心附近 → `/clear` | 距离/5 + 5 s 或 3 s |
|
||||
| 后备盲清(问题四) | 联合信念坍缩到有限格 | 依次到可疑格 `/clear` | 距离/5 + 3 s 或 5 s |
|
||||
| 机会测量 | 已停靠且该频道待测 | 原地 `/measure` | 5 s |
|
||||
|
||||
任务表排序是开放路径问题,默认用滚动 2-opt 与 Or-opt;
|
||||
精确 Held-Karp 与路线感知探点在本模拟器上为负收益,默认关闭,见
|
||||
[`第三四问图论与动态规划优化方案.md`](第三四问图论与动态规划优化方案.md) §8.6。
|
||||
|
||||
---
|
||||
|
||||
## 3. 附件计时示例逐步推演(105 / 111 / 194 / 199)
|
||||
|
||||
| 步 | 指令 | 移动 | 换频 | 动作 | 本步 | 累计 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| 1 | `/enter` | 0 | 0 | 0 | 0 | 0 |
|
||||
| 2 | `/measure (300,400) ch1` | 500 m → 100 s | 0(初始即 1) | 5 | 105 | 105 |
|
||||
| 3 | `/measure (300,400) ch2` | 0 | 1 | 5 | 6 | 111 |
|
||||
| 4 | `/clear (300,0) ch3` | 400 m → 80 s | 0 | 3(未发现) | 83 | 194 |
|
||||
| 5 | `/measure (300,0) ch2` | 0 | 0(第 3 步后已是 2) | 5 | 5 | 199 |
|
||||
| 6 | `/exit` | 0 | 0 | 0 | 0 | 199 |
|
||||
|
||||

|
||||
|
||||
验证方式:
|
||||
|
||||
```bash
|
||||
uv run mcm26b sim-check # 客户端 → 本地模拟器链路,输出 [105, 111, 194, 199]
|
||||
uv run pytest tests/test_protocol_timing.py -q # 逐步断言移动、换频、动作三个分项
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 实测时序分解
|
||||
|
||||
对评测机留档的每一局,`scripts/build_figure_data.py` 按与 `referee.simulator`
|
||||
同源的规则逐动作复算,并检查分项之和是否等于响应中的 `virtual_time_s`。
|
||||
|
||||
### 4.1 问题三演练局 `BBM9-HZG2-77N5-NKKC`(10 源全清)
|
||||
|
||||
| 项 | 数值 | 占比 |
|
||||
| --- | ---: | ---: |
|
||||
| 总虚拟时间 | 3134.643 s | 100% |
|
||||
| 移动(里程 11.9 km) | 2379.6 s | 75.9% |
|
||||
| 检测与清除动作(119 + 10 次) | 645.0 s | 20.6% |
|
||||
| 换频(110 次) | 110.0 s | 3.5% |
|
||||
| 现实耗时 | 1.889 s | — |
|
||||
|
||||
### 4.2 问题四演练局 `GM56-DFXZ-XKDM-XYV7`(12 源,含 3 个定向源)
|
||||
|
||||
| 项 | 数值 | 占比 |
|
||||
| --- | ---: | ---: |
|
||||
| 总虚拟时间 | 8703.766 s | 100% |
|
||||
| 移动(里程 32.4 km) | 6489.8 s | 74.6% |
|
||||
| 检测与清除动作(338 + 79 次) | 1951.0 s | 22.4% |
|
||||
| 换频(263 次) | 263.0 s | 3.0% |
|
||||
| 现实耗时 | 3.397 s | — |
|
||||
|
||||

|
||||
|
||||
### 4.3 结论
|
||||
|
||||
1. 移动占约 75%,优化重点是路径长度,这解释了七点计划(7 点、6.96 km 巡回)
|
||||
优于 49 点网格的原因;
|
||||
2. 动作占约 21%,检测 5 s 是下限,因此找全后立即退出比复扫更省时间;
|
||||
3. 现实耗时与成绩无关,本地回环为毫秒级,官方口径取虚拟时间,
|
||||
程序预算(1200 s)只用于限制计算耗时。
|
||||
|
||||
### 4.4 复现命令
|
||||
|
||||
```bash
|
||||
# 用评测机留档重画(含真值)
|
||||
uv run python scripts/build_figure_data.py --only timing-measured-q3-10-sources,\
|
||||
replay-webui-q3-omnidirectional,replay-webui-q4-directional
|
||||
|
||||
# 归档新日志,评测机数据被清理后仍可复现插图
|
||||
uv run python scripts/archive_replay_logs.py --list
|
||||
uv run python scripts/archive_replay_logs.py BBM9-HZG2-77N5-NKKC
|
||||
|
||||
# 按官方口径逐微秒复算(接受客户端 JSONL 或评测机 log.jsonl)
|
||||
uv run python scripts/analyze_run_timing.py referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl
|
||||
uv run python scripts/analyze_run_timing.py examples/replay/*.jsonl --json /tmp/timing.json
|
||||
uv run python scripts/verify_q3_practice.py output/q3/practice/<本局目录>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 时间预算与安全阀
|
||||
|
||||
| 约束 | 值 | 来源 | 客户端行为 |
|
||||
| --- | --- | --- | --- |
|
||||
| 移动速度 | 5 m/s | 题面 | 路径长度决定虚拟时间 |
|
||||
| 检测 / 换频 | 5 s / 1 s | 题面 | 避免高频扫频 |
|
||||
| 清除成功 / 未发现 | 5 s / 3 s | 题面 | 盲清代价可控 |
|
||||
| 测试窗口 | 1500 s(现实) | 题面 | 窗口到期接口关闭 |
|
||||
| 程序预算 | 1200 s(现实) | 题面 | `/enter` 后本地时钟起算 |
|
||||
| 退出预留 | 60 s | 工程 | 剩余不足时只允许 `/exit` |
|
||||
| 虚拟世界限时 | 360000 s | 题面 | 实测最坏为 1e4 量级,未触及 |
|
||||
| 行为日志上限 | 2 MB | 题面 | 控制请求数 |
|
||||
|
||||
安全阀见 [`algo-3.md`](algo-3.md) §7.2 与 [`algo-4.md`](algo-4.md) §5.2:
|
||||
预算将尽、连续无新发现或联合信念长时间不收敛时,转入最低成本收尾,
|
||||
先清除并登记已有发现,再 `/exit`,并写入 `stop_reason`。
|
||||
@@ -1,131 +0,0 @@
|
||||
# 问题一至四:最优实现与基线实现对比
|
||||
|
||||
本文件是四问"最优实现 / 基线实现"对比的**论文口径说明**。代码与可复现
|
||||
产物在仓库根目录 `project/`,运行 `uv run python -m project.run` 一次生成
|
||||
`project/results/summary.md` 与逐问 `q1.md … q4.md`。本文件只摘录设计与结论,
|
||||
数字以后者为唯一来源。
|
||||
|
||||
## 1. 交付物与目录
|
||||
|
||||
```text
|
||||
project/
|
||||
├── README.md 设计原则、各问对比设计、口径与边界
|
||||
├── common.py 方法描述 / 指标聚合 / 落盘 / 闭环装配
|
||||
├── run.py 统一入口(--question/--quick)
|
||||
├── results/ 自动生成:q1.md/json … q4.md/json + summary.md
|
||||
├── q1/ optimal.py baseline.py reference.py cases.py compare.py
|
||||
├── q2/ optimal.py baseline.py reference.py region.py cases.py compare.py
|
||||
├── q3/ optimal.py baseline.py compare.py
|
||||
└── q4/ optimal.py baseline.py compare.py
|
||||
```
|
||||
|
||||
角色边界:
|
||||
|
||||
- **最优实现**:直接适配 `src/mcm26b` 中已由 pytest 固化的生产实现,
|
||||
不重写算法;
|
||||
- **基线实现**:同题下更朴素、但能独立跑通的对照,不共享最优实现的关键步骤;
|
||||
- **独立参考**:与分析算法正交的数值/枚举标准,用于判定谁对谁错。
|
||||
|
||||
第三、四问统一走 `LocalSimulator` 内存回环(与官方 HTTP 协议同一边界),
|
||||
真值只在评测机侧;有效性判定沿用项目口径:
|
||||
**全清 ∧ 无缺席误判 ∧ 正常 `/exit` ∧ 零异常 ∧ 逐微秒计时复算一致**。
|
||||
|
||||
## 2. 四问方法设计对照
|
||||
|
||||
| 问 | 最优实现 | 基线实现 | 独立参考 | 主要指标 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | 半平面交 + 顶点对精确直径 + Welzl MEC + 覆盖反例 | 网格采样 + **包围盒对角线**代理直径/覆盖 | 大框半平面裁剪 + 暴力直径/MEC | 状态、直径误差、覆盖准确率、耗时 |
|
||||
| 2 | 保证接收盘内最小最坏后验半径(生产选点器) | ① 垂直 1000 m 最大交会角;② 候选集 MEC 圆心 | 保证接收盘内 9×9 网格枚举 | 保证接收率、最坏后验半径、移动时间 |
|
||||
| 3 | `bayes`:粒子滤波 + 信息增益 + 滚动 2-opt | `grid`:49 点网格 + 就近服务;`seven`:七点批量 | 冻结基准集 + 真值全清校验 | 全清率、虚拟时间及其分布 |
|
||||
| 4 | `directional`:31 点定向覆盖 + 联合信念 + 后备清除 | 问题三策略直接搬用(`bayes` / `grid`) | 冻结基准集(core+boundary) | 全清率、**缺席误判**、虚拟时间 |
|
||||
|
||||
## 3. 对比结果
|
||||
|
||||
### 3.1 问题一(40 个随机交会算例)
|
||||
|
||||
| 指标 | 最优 | 基线 |
|
||||
| --- | --- | --- |
|
||||
| 状态判定准确率 | 100% | 100% |
|
||||
| 直径平均绝对误差 | **0.000 m** | 4.583 m(最大 14.60 m) |
|
||||
| 直径圆覆盖判定准确率 | **100%** | 52.5% |
|
||||
| 平均耗时 | **0.11 ms** | 22.35 ms |
|
||||
|
||||
固定示例进一步给出结构性反例(`examples/q1`,解析期望由
|
||||
`tests/test_geometry*.py` 固化):
|
||||
|
||||
- `normal`:直径 26.99 m,**直径圆不覆盖**定位区域(最优判否、基线判是);
|
||||
- `triangle`:直径 40.00 m 的等边三角形反例,最小包围圆半径 23.09 m > 20 m,
|
||||
直径圆不覆盖;基线因"包围盒中心 + 对角线"恒判覆盖;
|
||||
- `poor`:近共线检测点 → 无界,最优/基线/参考一致判无界;
|
||||
- `segment`:零误差退化线段,最优判线段 D=100 m 且覆盖成立,基线退化为点;
|
||||
- `empty`:观测不相容 → 空集。
|
||||
|
||||
> 基线的两处结构性缺陷:直径用包围盒对角线在斜/细长区域系统性高估;
|
||||
> 覆盖用包围盒中心圆则恒判"能覆盖",恰好丢掉问题一要考的反例。
|
||||
|
||||
### 3.2 问题二(30 个随机首次示向度,初始 ρ 均值 681.5 m)
|
||||
|
||||
| 方法 | 保证接收率 | 最坏后验均值 | 终值比 ρ'/ρ | 移动均值 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 最优(保证盘内最小最坏后验) | 100% | **73.89 m** | 0.104 | 170.4 s |
|
||||
| 基线① 垂直 1000 m 最大交会角 | **0%** | 80.11 m | 0.116 | 200.0 s |
|
||||
| 基线② MEC 圆心 | 100% | 340.75 m | 0.500 | 136.3 s |
|
||||
| 参考(保证盘内网格枚举) | 100% | 75.63 m | 0.106 | 170.3 s |
|
||||
|
||||
> 基线①说明"只追交会角"会在本题失败:首次角域可延伸到 1500 m,
|
||||
> 真源在远端时第二点距离超过 1000 m,测量直接 `no_signal`。
|
||||
> 基线②保证接收但后验几乎不收缩(≈0.5ρ)。最优在同等保证下把后验压到 0.10ρ,
|
||||
> 且与网格参考几乎重合(生产采样质量足够)。
|
||||
|
||||
### 3.3 问题三(18 个冻结 core 场景,全向 10/13/16 源)
|
||||
|
||||
| 方法 | 有效局 | 全清率 | 虚拟时间均值 | 中位 | 检测均值 | 请求均值 | 位移均值 |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 最优 `bayes` | 18/18 | 100% | **3188.7 s** | 3111.3 s | 111.1 | 124.1 | 12338 m |
|
||||
| 中间 `seven` | 18/18 | 100% | 5361.7 s | 5367.5 s | 100.8 | 113.8 | 23508 m |
|
||||
| 基线 `grid` | 18/18 | 100% | 14935.7 s | 15275.1 s | 430.6 | 443.6 | 61550 m |
|
||||
|
||||
配对变化:`bayes` 相对 `grid` 虚拟时间 **−78.4%**(18/18 场景更快),
|
||||
`seven` 相对 `grid` −63.7%。全部 54 局零异常、计时复算一致。
|
||||
|
||||
### 3.4 问题四(11 个冻结 core+boundary 场景,含朝外发射的边界定向源)
|
||||
|
||||
| 方法 | 有效局 | 全清率 | 缺席误判 | 虚拟时间均值 | 后备清除均值 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 最优 `directional` | 11/11 | **100%** | **0** | 9069.9 s | 24.8 |
|
||||
| 基线 `grid`(49 点全向) | 0/11 | 67% | 0 | 18179.2 s | 0 |
|
||||
| 基线 `bayes`(七站全向缺席证明) | 0/11 | 77% | **24** | 3890.8 s | 0 |
|
||||
|
||||
> 两条搬用基线的失效机理不同:
|
||||
> `bayes` 用七站环的**全向**缺席证明,遇到背离圆心发射的边界定向源时
|
||||
> 会把真源直接判成 ABSENT(累计 24 次 **缺席误判**,属"快而错",其虚拟时间
|
||||
> 不可与最优直接比较);`grid` 的 49 点覆盖对定向源发现是完备的,但缺少
|
||||
> 定向观测推理与 ≤20 m 后备清除,定位停滞只能停在 DETECTED("稳而不全")。
|
||||
> 最优 `directional` 两种工况都是 11/11 全清、零误判,代价是多花时间与
|
||||
> 平均 24.8 次后备清除。
|
||||
|
||||
## 4. 结论
|
||||
|
||||
1. 问题一:生产几何内核对状态、直径、覆盖三项与独立参考**逐案一致**;
|
||||
朴素包围盒基线在覆盖判定上只有约 52% 准确率,且对固定反例全错。
|
||||
2. 问题二:只有在"保证接收"约束内优化后验才既安全又有效;最优相对保守
|
||||
基线把最坏后验半径从 0.5ρ 降到 0.10ρ,且与网格参考几乎重合。
|
||||
3. 问题三:`bayes` 在相同全清率下把虚拟时间降到 `grid` 的约 1/5,
|
||||
且逐场景配对 18/18 更快,说明"负观测感知 + 信息增益选点 + 全局排序"
|
||||
三步都产生净收益。
|
||||
4. 问题四:定向源的难点不是"发现"而是"证明缺席"与"失去信号后的清除";
|
||||
直接搬用第三问策略会得到 24 次缺席误判,不可接受。`directional` 的
|
||||
联合信念 + 后备清除是 11/11 全清的关键。
|
||||
|
||||
写论文时建议按"基线为什么错 → 最优补了哪一步 → 独立参考如何判定"的三段式
|
||||
展开,并声明:随机分布是测试假设;基线时间快于最优的场景(如问题四 `bayes`)
|
||||
不构成有效性优势,因为该局基线未完成全清任务。
|
||||
|
||||
## 5. 复现
|
||||
|
||||
```bash
|
||||
uv run python -m project.run # 四问全部(约 3–4 分钟)
|
||||
uv run python -m project.run --question 1 # 只跑问题一
|
||||
uv run python -m project.run --quick # 缩小算例/基准集规模
|
||||
uv run pytest tests/test_geometry.py tests/test_geometry_certificates.py -q # 几何回归
|
||||
```
|
||||
@@ -1,516 +0,0 @@
|
||||
# 第三、四问:图论与动态规划算法引入方案
|
||||
|
||||
- 版本:2026-09-12
|
||||
- 前置文档:[第三四问架构优化与运行提速方案](第三四问架构优化与运行提速方案.md)(架构与 P0–P2 项)、
|
||||
[algo-3-bayes.md](algo-3-bayes.md)(现役第三问策略)、[algo-3.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') ]`。
|
||||
|
||||
**实现选择(按代价递增)**:
|
||||
|
||||
1. **一步期望后验半径**(最小改动,复用 Q3 已有内核的二维推广):
|
||||
对候选 `q`,按粒子权重模拟三分支结果,用幸存子集的 MEC 半径近似 `V(b')`,
|
||||
取 `E[radius] + λ·c(q)` 最小者。把 `particles.py::expected_posterior_radius`
|
||||
的向量化实现在 `JointBelief` 上重写一份(numpy 可用时广播)。
|
||||
2. **2–3 步 rollout**:对前 K=8 个候选各展开一层,深度 2;墙钟预算 ≤ 0.3 s/决策。
|
||||
3. **交会角代理(解析、零墙钟)**:若一步法来不及落地,先用
|
||||
`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|²)` 每任务。
|
||||
|
||||
**实施**:
|
||||
|
||||
1. `guarantee/cover.py` 增加 `optimize_tour(points, seed_tour, passes)`(Or-opt + 2-opt),
|
||||
把 `nn_tour_m` 从"上界"变成"已优化值",并写入证书 `tour_virtual_s`。
|
||||
2. `planner/bayes_loop.py` 新增 `_skeleton`(覆盖点顺序)与 `_insert_task(task, neighborhood)`;
|
||||
`_order_tasks` 退化为"骨架遍历 + 已插入任务",保留现有 2-opt 作为兜底开关。
|
||||
3. `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 |
|
||||
|
||||
结论:
|
||||
1. **31 点很可能就是实际下界附近**:多起点随机贪心 + 冗余剪枝在 25 m/48 细网格上
|
||||
直接搜索的最小解仍是 31 点(尚未做 LP 松弛下界,但连贪心都下不去);
|
||||
之前看到的 27 点是**采样过拟合的假解**,不可采纳;
|
||||
2. `q4_mincover_v1` 的安全裕量几乎为 0(999.1 m),存在"真源恰落在细缝 + `r_eff` 取下界"
|
||||
的漏检窗口,现役测试没暴露是因为随机场景未命中细缝且 `r_eff` 通常 > 1000;
|
||||
3. `square49` 裕量充足但巡回 36.4 km,不可回退;
|
||||
4. 正确做法是**细网格重搜 + 设计裕量**(S2),代价约 0–150 s,**先保安全再谈提速**。
|
||||
|
||||
### 5.2 其他风险
|
||||
|
||||
| 风险 | 影响 | 缓解 |
|
||||
| --- | --- | --- |
|
||||
| POMDP rollout 墙钟超预算 | 单局计算 > 1 s | 深度 2、候选截断 K=8、`--profile` 纳入基准必报列;超预算自动退回一步法 |
|
||||
| Held-Karp 状态爆炸(任务表变长) | 单步计算抖动 | 仅在 `|T| ≤ 9` 默认启用,`> 9` 回退 2-opt + Or-opt |
|
||||
| 抵近点破坏可见性保证 | 探测反而 `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. 复现命令(本轮实测)
|
||||
|
||||
```bash
|
||||
# 度量基线(§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(净负)。原因有两个:
|
||||
|
||||
1. 后备清除在命中真源时**立即结束**,"整条路径最短"不是它的目标函数,
|
||||
§3.2/§3.3 的插入代价模型在这里并不成立;
|
||||
2. 更关键的是:**联合信念的 `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 | ✅ 采纳(弱收益) |
|
||||
|
||||
```bash
|
||||
# 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 |
|
||||
@@ -1,595 +0,0 @@
|
||||
# 第三、四问系统性架构优化与运行提速方案
|
||||
|
||||
- 版本:2026-09-12
|
||||
- 依据:本仓库运行历史(`session.jsonl`、`practice-p3-*.jlog`、`referee-data/sessions/*`、
|
||||
`output/hrl/ui/q3-main/*`、`docs/` 全部性能记录)+ 本文档新增的复跑与离线校核实验
|
||||
- 范围:第三问(全向源)与第四问(混合定向源)的**闭环架构、算法分解、运行治理**,
|
||||
不改动题面约束、协议层语义与既有保守性不变量
|
||||
- 结论先行:**虚拟时间的 75–83% 是移动**,移动里约一半不是覆盖巡回而是定位/清除往返;
|
||||
**第四问的全部失败来自定向源**;旧机器学习层已被证明不如手写基线。
|
||||
因此本轮优化的主线是"**把定位并入覆盖巡回 + 把发现集压到最小命中集 + 给定向源建位置×朝向联合信念**",
|
||||
而不是再堆学习算法。
|
||||
|
||||
---
|
||||
|
||||
## 0. 摘要(TL;DR)
|
||||
|
||||
### 0.1 三个待解的结构性浪费
|
||||
|
||||
| 编号 | 现象 | 直接证据 | 估计可回收 |
|
||||
| --- | --- | --- | --- |
|
||||
| W1 | Q3 定位探点往返 5741 m / 1148 s,与覆盖巡回(6960 m / 1392 s)相当 | 本次复跑(13 源,seed 0):24 次探点,均值 442 m/次 | **−900 ~ −1100 s/局** |
|
||||
| W2 | Q4 发现集是 700 m 方格 49 点,巡回 36.4 km;同一保证下贪心最小命中集只要 31 点、22.9 km | `scripts/verify_q4_cover.py`:43 032 个 (p,h) 采样,两组点集均 100% 覆盖 | **−2700 s(巡回)+ −1140 s(检测)** |
|
||||
| W3 | Q4 定向源没有"位置×朝向"联合信念,只能阶梯探点,最后退化到 ≤400 格盲清 | referee 两局:全向 17/17 清除,定向仅 2/6;4/4 漏检全是定向 | **−1500 ~ −3000 s/局** |
|
||||
|
||||
### 0.2 预期收益(自建模拟器,同一冻结基准集,配对口径)
|
||||
|
||||
| 指标 | Q3 现状 | Q3 目标 | Q4 现状 | Q4 目标 |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| 平均虚拟时间 | 3707 s(本次 6 场景)/ 3536 s(13 源单局) | **≤ 2700 s** | 13 652 s(10 源 3 定向单局)/ 13 165 s(4 场景均值) | **≤ 9000 s** |
|
||||
| 最大虚拟时间 | 4628 s | **≤ 4000 s** | > 17 000 s(边界压力) | ≤ 12 000 s |
|
||||
| 每局计算墙钟 | 2.9–6.5 s | **≤ 0.8 s** | 6.5 s | **≤ 1.0 s** |
|
||||
| 有效局(全清+缺席无误判+零异常+正常退出+计时复算一致) | 6/6 | 基准集 100% | 4/4 | 基准集 100% |
|
||||
|
||||
> 4000 s 是本项目 `docs/算法审核与优化-20260911.md` 自设的验收线,不是题面评分线;
|
||||
> 第四问在 10 源场景下**不承诺**达成 4000 s,理由见 §6.2。
|
||||
|
||||
### 0.3 明确不做的事
|
||||
|
||||
- 不重新引入 PPO/HRL。运行历史支持"保留手写基线":HRL 训练 4007.9 s / 109 776 步后
|
||||
仍被 `bayes` 稳定压制 4.3–5.0%(17–18/20 场景,符号检验 p=0.0001),且 94% 的差距来自
|
||||
多走的移动;其评估集 20 个场景**全部是单源全向**,无法支撑任何第四问结论。
|
||||
- 不引入新的第三方运行时依赖(仍是 `requests`;`numpy` 仅作**可选加速后端**,缺失时回退纯 Python)。
|
||||
|
||||
### 0.4 实施进展与实测回填(2026-09-12)
|
||||
|
||||
冻结基准集 `harness/suites.py`(第三问 18 主场景 + 2 边界;第四问 9 + 2),
|
||||
并行 runner `scripts/run_suite.py`,配对口径同场景同误差种子。
|
||||
|
||||
| 项 | 状态 | 实测 | 结论 |
|
||||
| --- | --- | --- | --- |
|
||||
| P1-4 安全阀 | ✅ 已实现 | `summary` 新增 `completion_basis` / `absence_evidence` / `redundant_rescan_measures` / `virtual_reserve_s`;`--persistent` 输出单轮上界告警 | 采纳(5 项测试) |
|
||||
| P0-2 最小命中集 | ✅ 已实现并默认开启 | 第四问 11 场景配对:**14003.0 → 10975.5 s**(均值 −19.3%、中位 −25.4%、10/11 更快);检测 444.5→319.2;请求 569.5→395.6;位移 54.9→44.2 km;最大 17007→12919 s;11/11 valid | **采纳** |
|
||||
| P0-4 感知层向量化 | ✅ 已实现 | 单局计算 **3.10 → 1.00 s(3.08×)**,最大 5.84 → 1.30 s;20 场景的虚拟时间与动作序列**逐位一致** | **采纳**(目标 ≤0.8 s 未达,余下为 belief 表示层) |
|
||||
| P0-1 融合巡回 | ❌ 实测无效,已回退默认 | 仅追加站点方位线:3454.6 vs 3426.9 s(+0.8%,检测 +10.8 次、位移仅 −188 m);追加 + 抑制专用探点:**4989.0 vs 3426.9 s(+45.6%,20/20 更慢)** | 关闭(保留开关与代码) |
|
||||
| P1-1 C₂₀ 最近清除点 | ⊘ 复核后降为非项 | 现有 `_near_clear_target` 已取安全球 `B(c, limit−ρ)` 内离当前位置最远点;与完整 C₂₀ 最优之差 ≤ slack+margin ≈ 0.74 m | 不改 |
|
||||
| P1-3 基准集/并行 | ✅ 已实现 | 20 场景 × 3 变体 = 60 局 **26.5 s**(6 进程);20 局 **3.9 s** | 采纳 |
|
||||
| P0-3 联合信念 | ✅ 已实施并于 2026-09-12 修正 | 网格粒子 × 24 档朝向 bin + 可见性选点;**发现并修复 `no_signal` 朝向规则反向缺陷**(原会删掉真源朝向档);配套 D1 探点口径使第四问后备盲清 **125.7 → 4.3 次/局** | 采纳(结论与实测见[图论与 DP 优化方案 §8](第三四问图论与动态规划优化方案.md)) |
|
||||
|
||||
**P0-1 为什么失败(重要负面结论)**:七站环上通常只有 2–3 个站能对同一源取得
|
||||
有效方位线,且站间交会角不足以直接换到 20 m 证书,专用信息增益探点仍然必要;
|
||||
"顺路测量"于是退化为平白多花检测,一旦抑制专用探点则会白等巡回、远端绕行。
|
||||
**结论:第三问的定位往返不是可回收的浪费,`bayes` 的滚动时域调度已在做正确的事。**
|
||||
|
||||
**第四问现状与目标差距(2026-09-12 图论/DP 轮回填)**:启用硬化覆盖计划
|
||||
`q4_mincover_v2` 与 D1 探点口径后,第四问 11 场景(core + boundary)均值为
|
||||
**9069.9 s**、最大 12081.1 s、后备盲清 24.8 次/局(core 9 场景 8602.0 s /
|
||||
4.3 次),仍远高于 4000 s 验收线。剩余成本主要是最小命中集巡回
|
||||
(23.9 km ≈ 4777 s)与缺席频道检测,二者都是覆盖证明的固有代价;
|
||||
本方案 §2.3 的"可压缩 23–32%"在本模拟器上只回收了约 1%(详见图论与 DP 方案 §8)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 运行历史复核
|
||||
|
||||
### 1.1 数据资产清单(本次实际读取)
|
||||
|
||||
| 资产 | 内容 | 可用信息 |
|
||||
| --- | --- | --- |
|
||||
| `session.jsonl`(31 011 行) | 官方第三问演练 J2WH-2K7D-5ZXS-DNK6 的客户端日志 | 10 323 次 `/measure`、12 次 `/clear`、逐动作计时 |
|
||||
| `practice-p3-*.jlog` | 同一局的官方行为日志封装 | 仅明文信封(题号 3、队号、案例码);载荷 AES-256-GCM + RSA-OAEP,不可解 |
|
||||
| `referee-data/sessions/*`(6 局,5 局完整) | 本地评测机 q3×3、q4×2、截断×1 | 逐请求响应、真值、summary、step 事件 |
|
||||
| `output/hrl/ui/q3-main/` | HRL 训练(109 776 步)+ `eval/at-40k`、`eval/at-final` | monitor CSV、模型元数据、20 场景配对评估 |
|
||||
| `docs/算法审核与优化-20260911.md`、`docs/algo-3.md`、`docs/algo-3-bayes.md` | 历史 KPI 与消融 | 官方/自建成绩、验证集分档 |
|
||||
| 本次新增复跑 | `scripts/benchmark_q3_bayes.py`(6 场景)、Q3/Q4 单局计时分解、`cProfile`、站点三角化可行性 | §1.3 中标注"本次复跑"的数字 |
|
||||
| 本次新增工具(已入库) | `scripts/analyze_run_timing.py`(任意会话日志的计时分相复算)、`scripts/verify_q4_cover.py`(第四问覆盖证书 + 最小命中集搜索) | F4、F9 可复现 |
|
||||
|
||||
### 1.2 先确认度量可信(否则一切优化都是自欺)
|
||||
|
||||
官方计时模型:`T = L/5 + 5·N_measure + N_switch + 5·N_clear⁺ + 3·N_clear⁻`,
|
||||
其中 `L` 为累计直线位移,`/clear` **不计**换频。`scripts/verify_q3_practice.py` 对 5 局完整
|
||||
评测机日志逐微秒复算,与服务器返回的 `virtual_time_s` 完全一致(例:BBM9 复算 3134.642907 = 记录 3134.642907)。
|
||||
结论:**后续所有"虚拟时间"结论都可用动作日志独立复算**,这是本项目最可靠的一条工程资产,必须保留。
|
||||
|
||||
### 1.3 关键事实(F1–F13)
|
||||
|
||||
| 编号 | 事实 | 出处 |
|
||||
| --- | --- | --- |
|
||||
| F1 | 虚拟时间构成:**移动 75–83%|检测动作 15–21%|换频 2.3–3.7%** | 官方会话 82.30/14.76/2.94;referee q3 80.50/16.78/2.71、q4 78.39/18.63/2.98;本次复跑 Q3 79.9/17.3/2.9、Q4 75.2/21.1/3.7 |
|
||||
| F2 | 官方第三问演练 J2WH 总虚拟 350 227.7 s,其中 **346 169.9 s(98.84%)是空复扫**:7 个固定站点 × 8 个未清除频道 × 183 轮,0 检出,结束点正好落在 `virtual_reserve_s=10 000` 边界 | `session.jsonl` 相位切分;`planner/__init__.py:236`、`config.py:99` |
|
||||
| F3 | **第四问的全部失败来自定向源**:referee 两局全向 17/17 清除,定向仅 2/6;4/4 漏检全是定向;每清除源 356.4 s(Q3 274.0 s,+30%) | `referee-data/sessions/{6X58,BAU8}`;`{BBM9,RM7Y,VQKB}` |
|
||||
| F4 | 本次复跑 Q3(13 源,seed 0):3535.9 s / 109 次检测 / 13 清除;**七站巡回 6960 m(1392 s,39%)+ 探点往返 5741 m(1148 s)+ 清除移动 3668 m(734 s)** | 本次复跑(方法见附录 A) |
|
||||
| F4b | 评测机 Q3 单局 BBM9:**21 次专用探点占 1138.7 s 移动,等于该局虚拟时间的 36.3%**,而站点扫频 98 次只占 991.2 s | `scripts/analyze_run_timing.py referee-data/sessions/BBM9-.../log.jsonl --plan seven` |
|
||||
| F5 | 本次复跑 Q4(10 源 3 定向,seed 0):13 652.1 s / 560 次检测 / 18 次清除(8 次失败)/ 51 356 m | 本次复跑 |
|
||||
| F6 | 感知层是墙钟热点:单局计算 6.04 s;`cProfile` 下 `expected_survival` 占累计时间 **72%**(2808 次调用),`apply_measure` ≈ 20%,`_kill_outside_wedge` 触发 498 万次 `angular_gap` | 本次 `cProfile`(13 源单局) |
|
||||
| F7 | HRL 运行:109 776/200 000 步、4007.9 s、**27.0 steps/s(6.75/env)**、1.51 s 墙钟/局;被 SIGTERM 截断时回报仍在上升(Q1 1.05 → Q4 6.20) | `output/hrl/ui/q3-main/q3.json` + 4 份 monitor CSV |
|
||||
| F8 | HRL 评估:20 场景**全部单源全向**;`bayes` 比 HRL 快 4.3–5.0%(17–18/20,p=0.0001),**94% 的差距是多走的移动**;40k→109k 步仅再改善 0.7% | `eval/at-40k|at-final/aggregate.*`、`eval/manifest.json` |
|
||||
| F9 | 现役 Q4 发现集:700 m 方格 49 点、NN 巡回 **36.4 km**;满足同一"前向半盘命中"保证的贪心最小集 **31 点、22.9 km(−37%)**,覆盖校核 100% | `scripts/verify_q4_cover.py`;本文附录 A |
|
||||
| F10 | Q3 七站巡回**已经最优**:6 × 1159.7 = 6958 m(观测 6960 m),无可压缩空间;把环半径降到覆盖下界 1122.9 m 仅省 222 m(44 s) | 几何计算 + 本次复跑 |
|
||||
| F11 | 站点三角化可行:**99.28% 的源位置有 ≥2 个站在 1500 m 内**;最佳交会角 5 分位 58.5°、中位 122.9°;只有 0.72% 的源位置仅 1 个站在射程内 | 本次离线采样(20 000 点) |
|
||||
| F12 | 墙钟量级差三个数量级:内存回放 **0.22–0.25 ms/请求**(≈0.35 s/局),官方接口 **9.42 ms 均值/请求**(104.49 s / 10 337 请求);本地评测机 24.5–97.9 ms/请求 | referee `session_end`、`runs/*/summary.json`、`session.jsonl elapsed_s` |
|
||||
| F13 | 历史 KPI 参照:Q3 官方最好 4058.71 s(3BW5,13/13)、5232.13 s(J4ER,12/12);自建 `bayes` 3707.3 s(本次 6 场景)/ 3726.2 s(14 场景消融)/ 验证集 3315.89 s;Q4 自建 13 164.7 s,**无官方第四问演练记录** | `docs/算法审核与优化-20260911.md`、`docs/algo-3-bayes.md`、`README.md:135` |
|
||||
|
||||
### 1.4 由事实导出的六处结构性瓶颈
|
||||
|
||||
| 编号 | 瓶颈 | 支撑事实 | 归属层 |
|
||||
| --- | --- | --- | --- |
|
||||
| B1 | 定位/清除移动没有并入覆盖巡回,探点按"信息增益"选,移动权重 λ=0.0105 几乎不惩罚绕行 | F1、F4、F4b、F11 | 决策层 |
|
||||
| B2 | Q4 发现集冗余 63%(49 点 vs 30 点),且每个"真缺席"频道要在全部 49 点各测一次 | F5、F9 | 保证层 |
|
||||
| B3 | Q4 定向源缺少位置×朝向联合信念:`no_signal` 只记"被遮挡过几次",选点靠固定 45° 阶梯,收敛失败后退化到 ≤400 格 20 m 盲清(≤1200 s + ≤400 请求) | F3、`planner/__init__.py:691-768` | 感知层 + 决策层 |
|
||||
| B4 | 感知层全 Python 容器:每局 20 个频道各建 ~6.1 万格 `set`,`_kill_outside_wedge` 每次遍历全部幸存格,评分核 `expected_survival` 为 7×800 的纯 Python 双循环 | F6 | 感知层 |
|
||||
| B5 | 研发吞吐低:场景串行、单进程;一局 0.35–6.5 s;HRL 27 steps/s;14–52 场景的配对基准要跑几分钟到十几分钟 | F6、F7、F12 | 实验层 |
|
||||
| B6 | 运行治理缺失:单源评估集使指标退化(`avg_locate_clear_time_s ≡ virtual_time_s`)、`eval/manifest.json` 三份重复且与 `output/hrl/ui/manifest.json` 不一致(后者缺失)、`persistent_search=True` 可造成 98.84% 的无效开销且无硬性告警 | F2、F8、F13 | 遥测/实验层 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标架构
|
||||
|
||||
### 2.1 分层与依赖方向(依赖只能向下)
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────┐
|
||||
L6 实验/遥测 │ bench/ 冻结基准集·并行 runner·配对统计 │
|
||||
│ telemetry/ manifest·step log·replay·summary │
|
||||
└───────────────▲───────────────────────────────┘
|
||||
│ 只读观测
|
||||
┌───────────────┴───────────────────────────────┐
|
||||
L5 执行/安全 │ exec/ 动作账本·预算守卫·安全阀·幂等客户端 │
|
||||
└───────────────▲───────────────────────────────┘
|
||||
│ Action 请求
|
||||
┌───────────────┴───────────────────────────────┐
|
||||
L4 决策 │ plan/ 任务表·滚动时域排序·信息/时间评分 │
|
||||
└───────────────▲───────────────────────────────┘
|
||||
│ Task[]
|
||||
┌───────────────┴───────────────────────────────┐
|
||||
L3 保证 │ guarantee/ 命中集覆盖计划·清除证书·缺席证明 │
|
||||
└───────────────▲───────────────────────────────┘
|
||||
│ 候选集/幸存集
|
||||
┌───────────────┴───────────────────────────────┐
|
||||
L2 信念 │ belief/ BeliefBackend:OccupancyTensor(Q3) │
|
||||
│ JointTensor(位置×朝向, Q4) │
|
||||
└───────────────▲───────────────────────────────┘
|
||||
│ Observation
|
||||
┌───────────────┴───────────────────────────────┐
|
||||
L1 观测模型 │ model/ 可见性半平面·r_eff 带·有界误差·舍入裕量 │
|
||||
└───────────────▲───────────────────────────────┘
|
||||
│ 原始响应
|
||||
┌───────────────┴───────────────────────────────┐
|
||||
L0 协议/时钟 │ protocol/ 规则表·计时模型·状态机·客户端(冻结)│
|
||||
└───────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
与现状的差别:**用组合取代继承**。现状是
|
||||
`OmnidirectionalLoop → SevenBatch → BayesLoop → DirectionalExtension` 的单继承链,
|
||||
调度、信念、清除、预算、报表五种职责混在同一族类里(`planner/__init__.py` 818 行 +
|
||||
`planner/bayes_loop.py` 513 行),任何一处改动都会跨层影响其它三问。
|
||||
目标形态是
|
||||
|
||||
```python
|
||||
Episode(
|
||||
client = SimulatorClient(...), # L0,冻结
|
||||
belief = OccupancyTensor(...) | JointTensor(...), # L2
|
||||
plan = CoveragePlan.points, # L3
|
||||
scorer = InfoGainPerSecond(...), # L4
|
||||
policy = FusedTourPolicy(...) | DirectionalPolicy(...), # L4
|
||||
certifier= Certificate(...), # L3
|
||||
ledger = Telemetry(...), # L6
|
||||
)
|
||||
```
|
||||
|
||||
三层保证策略矩阵只差**三个可替换部件**,其余代码共享:
|
||||
|
||||
| 问题 | 信念后端 | 覆盖计划 | 选点策略 |
|
||||
| --- | --- | --- | --- |
|
||||
| Q3 | `OccupancyTensor`(全向) | 七站环(已经最优,冻结) | 融合巡回 |
|
||||
| Q4 | `JointTensor`(位置×朝向) | **最小命中集**(30 点,离线搜索 + 运行期校验证书) | 可见性约束选点 |
|
||||
|
||||
### 2.2 接口契约(关键签名)
|
||||
|
||||
```python
|
||||
# L1 model/observation.py —— 只此一处定义"什么算看见"
|
||||
@dataclass(frozen=True)
|
||||
class ObservationModel:
|
||||
r_eff_min_m: float; r_eff_max_m: float
|
||||
near_radius_m: float; half_angle_deg: float
|
||||
directional_half_deg: float = 90.0 # 含边界
|
||||
|
||||
def visible(self, src: Vec2, heading_deg: float | None, reader: Vec2) -> bool: ...
|
||||
def detectable(self, src: Vec2, heading_deg: float | None, reader: Vec2) -> bool: ...
|
||||
|
||||
# L2 belief/base.py —— 两种后端实现同一协议
|
||||
class BeliefBackend(Protocol):
|
||||
def apply(self, channel: int, reader: Vec2, result: str,
|
||||
svd_deg: float | None) -> None: ...
|
||||
def alive(self, channel: int) -> int: ...
|
||||
def is_absent(self, channel: int) -> bool: ... # 幸存集为空
|
||||
def certificate(self, channel: int) -> ClearCertificate | None: ...
|
||||
def guaranteed_no_signal(self, channel: int, reader: Vec2) -> bool: ...
|
||||
def prob_detect(self, channel: int, reader: Vec2) -> float: ... # 决策用
|
||||
def version(self, channel: int) -> int: ... # 派生量缓存键
|
||||
|
||||
# L3 guarantee/cover.py —— 覆盖计划是"可离线搜索、可在运行期校验"的一等对象
|
||||
@dataclass(frozen=True)
|
||||
class CoveragePlan:
|
||||
problem: int # 3 | 4
|
||||
points: tuple[Vec2, ...]
|
||||
certificate: CoverCertificate # 采样分辨率、缺失数、最坏裕量、脚本哈希
|
||||
version: str
|
||||
def verify(self, model: ObservationModel, tol_m: float) -> CoverCertificate: ...
|
||||
|
||||
# L4 plan/policy.py
|
||||
class Policy(Protocol):
|
||||
def tasks(self, belief: BeliefBackend, state: RobotState) -> list[Task]: ...
|
||||
def order(self, tasks: list[Task], state: RobotState) -> list[Task]: ...
|
||||
def measured_at_point(self, point: Vec2) -> tuple[int, ...]: ... # 一停多测
|
||||
```
|
||||
|
||||
### 2.3 四条设计原则
|
||||
|
||||
1. **保守性不变量不动**:真源永不被删;清除证书始终基于完整 ±1.005° 角域与题面距离带;
|
||||
所有启发式(均匀先验、朝向先验、信息增益)**只用于选点,不用于安全证明**。
|
||||
Q4 的朝向联合信念必须自带"朝向未观测时退化为全向"的保守分支。
|
||||
2. **保证 = 离线搜索 + 运行期校验**:覆盖集、清除点、巡回顺序都可以离线用数值搜索优化,
|
||||
但运行期必须用同一份 `ObservationModel` 重新校验证书(点集、分辨率、裕量),
|
||||
校验失败即拒绝启动,而不是相信一个写死的点表。
|
||||
3. **一个事实一个来源**:题面常量、`r_eff` 带、清除半径、动作耗时只在 `config.py`;
|
||||
可见性语义只在 `model/observation.py`;训练/部署若将来共存,必须共用同一控制器模块
|
||||
(这是旧 HRL 用 13 000 行换来的教训:v1 的 5 个特征索引错位、BC 激活函数不一致、
|
||||
旧基准把 `completed` 当全清)。
|
||||
4. **每个优化都必须可配对、可复算、可回归**:冻结基准集 + 逐局 `manifest` + 动作日志
|
||||
+ 逐微秒复算;任何"更快"的声明必须给出配对分布(均值/中位/最大/更快场数),
|
||||
而不是单个最优场景。
|
||||
|
||||
### 2.4 迁移映射(现状 → 目标)
|
||||
|
||||
| 现状 | 目标 | 处理 |
|
||||
| --- | --- | --- |
|
||||
| `protocol/*`、`evaluation/recompute_virtual_time` | 不变 | 冻结,作为度量基准 |
|
||||
| `belief/__init__.py`(凸外包) | `belief/convex.py` | 原样搬迁,继续负责精确角域证书 |
|
||||
| `particles.py`(网格幸存集) | `belief/occupancy.py`(numpy 张量 + 纯 Python 回退) | 重写热核,语义不变,保留 `tests/test_particles.py` 的真源保留性质测试 |
|
||||
| — | `belief/joint.py`(位置×朝向) | 新增,Q4 专用 |
|
||||
| `coverage/` | `guarantee/cover.py` | 49 点常量表 → 可校验的 `CoveragePlan` |
|
||||
| `planner/bayes_loop.py` 的 `_build_tasks/_order_tasks` | `plan/tasks.py`、`plan/schedule.py` | 抽出,Q3/Q4 共用 |
|
||||
| `planner/bayes_loop.py::_select_point` | `plan/score.py` | 抽出 + 向量化评分 |
|
||||
| `planner/__init__.py::DirectionalExtension` | `plan/policy.py::DirectionalPolicy` + `belief/joint.py` | 保留后备清除作为最终兜底,但目标是不再触发 |
|
||||
| `planner/seven.py` | `guarantee/plans.py::SEVEN` | 保留解析证明 |
|
||||
| 4 个 benchmark 脚本 | `bench/` 统一 runner(并行 + manifest + 配对统计) | 合并,消除指标口径分叉 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 优化项
|
||||
|
||||
### P0-1 第三问:发现—定位融合巡回(消除探点往返)
|
||||
|
||||
**现状**:每次收到 `direction` 后进入独立定位子循环,由信息增益选点器在同一站点之外
|
||||
另选探点;13 源单局共 24 次探点、5741 m 往返、1148 s,与整个覆盖巡回(6960 m / 1392 s)同量级;
|
||||
评测机单局 BBM9 更极端:**21 次探点花掉 1138.7 s 移动 = 全局限时时间的 36.3%**(F4b)。
|
||||
评分函数 `score = E[log 幸存占比] + 0.0105 × 移动秒数`,移动项几乎不影响排名。
|
||||
|
||||
**方案**:把"已发现未定证"的频道加入**每一个覆盖站点**的批量扫频清单,
|
||||
使第二/第三条方位线在巡回途中顺路取得;只有站点三角化不成立时才回退到专用探点。
|
||||
|
||||
- 巡回仍由 `plan/schedule.py` 滚动排序(现有最近邻 + 2-opt 已足够,`bayes` 的 −39.5% 移动
|
||||
主要来自这里),新增"同点顺路测量"任务类型:`Task(kind="station", channels=(未知, 未定证))`。
|
||||
- 站点任务的固有耗时按 `6 s × 频道数 + 1 s × 换频次数` 记账(现有 `_path_cost` 已支持)。
|
||||
- 保底:`F11` 显示 0.72% 的源位置只有 1 个站在 1500 m 内,对这类频道保留
|
||||
`_select_point` 的专用探点路径;判定用 `belief.prob_detect` 而非硬编码。
|
||||
|
||||
**预期收益(已被实测推翻)**:原估 F4 的 1148 s 探点移动可回收 70–80%,
|
||||
即 −800 ~ −900 s。**实测结果相反**:仅追加站点方位线 +0.8%,追加并抑制专用探点
|
||||
+45.6%(20/20 场景更慢),见 §0.4。原因是站间交会角不足以保证 20 m 证书,
|
||||
专用信息增益探点仍然必要;抑制它只会白等巡回。**本项不采纳,默认关闭。**
|
||||
|
||||
**验收**:18 场景验证集平均 ≤ 2700 s、最大 ≤ 4000 s;`measures` 增幅 ≤ 20%;
|
||||
`move_distance_m` 降幅 ≥ 25%;全部 `valid`。
|
||||
|
||||
**风险**:站点距离最远 2 × 1159.7 = 2319 m,可能出现 `no_signal` 浪费 5 s。
|
||||
缓解:仅在 `prob_detect > 0` 时顺路测量;`no_signal` 同样是有效负观测(进信念,不算异常)。
|
||||
|
||||
---
|
||||
|
||||
### P0-2 第四问:用最小命中集替换 49 点发现集(离线搜索 + 运行期校验)
|
||||
|
||||
**现状**:`coverage_points()` 生成 700 m 方格 49 点(±2100),依据是"单元内任一点到 4 顶点
|
||||
≤ 700√2 ≈ 989.95 ≤ 1000"。该条件是**充分但远非必要**:它要求单元内任意位置、任意朝向都由
|
||||
**同一个**顶点命中。实际上,第四问的保证是"对 ∀(p,h) ∈ Ω×S¹,存在被访点位于其前向半盘内",
|
||||
允许由**多个**顶点共同围住 p。
|
||||
|
||||
**方案**:把它当作一个显式的**击中集(hitting set)问题**离线求解,运行期校验:
|
||||
|
||||
1. 目标空间离散:`p` 取 Ω 内 75 m 网格,`h` 取 24 个方向 → 43 032 个 (p,h) 单元;
|
||||
2. 候选点:半径 2850 m 圆盘内 200–300 m 网格(641/293 个候选);
|
||||
3. 贪心集合覆盖 + 局部改进,**同时把巡回长度作为次级目标**(641/293 个候选中取 31/30 个,
|
||||
仍有大量同覆盖度的等价解可用于缩短巡回);
|
||||
4. 生成 `CoveragePlan(points, certificate)`,`certificate` 记录采样分辨率、未覆盖数、
|
||||
最坏裕量、生成脚本哈希;`CoveragePlan.verify()` 在每次运行前用同一 `ObservationModel`
|
||||
重新校核,未通过即拒绝启动。
|
||||
|
||||
**本次离线校核结果**(附录 A 可复现):
|
||||
|
||||
| 点集 | 点数 | (p,h) 覆盖 | NN 巡回 | 折算移动 |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| 现役 700 m 方格 ±2100 | 49 | 100% | 36.4 km | 7280 s |
|
||||
| 三角格 1000 m(半径 2800 盘) | 31 | 100% | 34.3 km | 6863 s |
|
||||
| **贪心最小命中集(200 m 候选)** | **31** | **100%** | **22.9 km** | **4587 s** |
|
||||
| **贪心最小命中集(300 m 候选)** | **30** | **100%** | **23.6 km** | **4719 s** |
|
||||
|
||||
**实测收益(2026-09-12,11 场景配对)**:均值 **14003.0 → 10975.5 s(−19.3%)**,
|
||||
中位 −25.4%,10/11 场景更快;检测 444.5 → 319.2,请求 569.5 → 395.6,
|
||||
位移 54.9 → 44.2 km,后备清除尝试 113.3 → 64.1,11/11 valid。
|
||||
低于原估的 −26%,差额来自"缺席频道省下的检测"被定位探点部分抵消。
|
||||
|
||||
**验收**:`CoveragePlan.verify()` 通过;10/13/16 源 × 定向 1/半数/仅一个全向 × 边界朝外压力
|
||||
场景全部全清;请求数、日志体积仍满足 1200 s / 2 MB 预算。
|
||||
|
||||
**风险**:数值采样证书弱于解析证明。缓解:(a) 保留解析七站证明用于 Q3;
|
||||
(b) 证书采样分辨率与裕量写入 summary 并随日志归档;(c) 保留 10% 的额外"保险点"预算,
|
||||
若演练观测到任何漏检立即回退到 49 点表。
|
||||
|
||||
---
|
||||
|
||||
### P0-3 第四问:位置×朝向联合信念与可见性选点
|
||||
|
||||
**现状**:定向源只被当作"候选空间集合",`no_signal` 只用于累计 `blocked_probes`
|
||||
(`planner/__init__.py:663-677`),选点沿固定 45° 阶梯试探;梯子用尽后调用
|
||||
`_fallback_clear`,对候选外包多边形做 20 m 网格覆盖逐格 `/clear`(≤400 格、≤1200 s、≤400 请求)。
|
||||
运行历史显示这正是第四问的失败点:定向源 2/6 清除,4/4 漏检全是定向。
|
||||
|
||||
**方案**:为第四问频道维护 **(x, y, heading) 联合可行集**,把"看不看得见"变成可推理的量:
|
||||
|
||||
- 表示:`JointTensor` —— 复用 Q3 的占用网格,每格附加 24 个朝向 bin 的可行性位掩码
|
||||
(uint8 位域,20 频道 × 6.1 万格 × 3 B ≈ 3.7 MB,可接受)。
|
||||
- 更新规则(全部保守,仅删"必然看不见"的格):
|
||||
- `direction`@s:位置删 `>1500`、角向删 `|gap| > δ_eff + 角裕量`;朝向删
|
||||
"以该格为源、朝向不覆盖 s" 的半盘(保留 ±90° 含边界)。
|
||||
- `no_signal`@s:对 `|g−s| ≤ 1000` 的格,朝向**只能**落在背向 s 的半盘;
|
||||
对 `1000 < |g−s| ≤ 1500` 的格,朝向要么背向 s,要么源实际半径 < |g−s|(保持不确定);
|
||||
对 `|g−s| > 1500` 的格不删。
|
||||
- `near`@s:位置收缩到 5 m 盘,朝向置为全向(近场无遮挡语义)。
|
||||
- 决策:`prob_detect(channel, reader)` = 该点能看到该频道任一可行 (p,h) 的概率质量;
|
||||
选点直接最大化 `prob_detect / (移动秒数 + 6)`,即**保证有信号的信息增益/秒**。
|
||||
- 定位收敛:位置由多条 `direction` 的角域交会收缩(与 Q3 相同);朝向在 2 次
|
||||
"一次被遮挡 + 一次可见"后通常已被压到很窄的楔形,此时可**主动选择必然可见的探点**,
|
||||
用一个正常角域证书结束,而不再进入 400 格盲清。
|
||||
- 后备清除**保留**(`fallback_clear_cells` 已有格数与预算双硬顶),但目标变为
|
||||
"只在证书无法建立时触发",并在 summary 中把触发次数作为回归指标。
|
||||
|
||||
**预期收益(未实测)**:定向频道的探点次数与后备清除触发次数大幅下降。参考量级:
|
||||
后备清除上限 400 格 × 3 s = 1200 s + 400 请求/频道;`docs` 记录的 Q4 改进版每局后备
|
||||
尝试 616/4 局 ≈ 154 次。保守估计 **−1500 ~ −3000 s/局**。
|
||||
|
||||
**验收**:10 源 3 定向场景全清率 100%(现状 referee 仅 2/6 定向);
|
||||
`fallback_clear_attempts` 相对基线下降 ≥ 70%;定向信道平均检测次数 ≤ 全向信道的 1.5 倍。
|
||||
|
||||
**风险**:朝向均匀先验是工程假设,官方分布未知。缓解:先验只影响选点顺序,
|
||||
不影响任何安全性判定;朝向不确定时自动退化为全向分支(`prob_detect` 取全向值)。
|
||||
|
||||
---
|
||||
|
||||
### P0-4 感知层向量化与并行(研发运行速度)
|
||||
|
||||
**现状**(F6):`expected_survival` 占单局 CPU 的 72%,2808 次调用 × (7 代表点 × 800 子采样)
|
||||
≈ 1570 万次纯 Python 距离/角度运算;`apply_measure` 另有 20%,其中 `_kill_outside_wedge`
|
||||
每次遍历全部幸存格(498 万次 `angular_gap`)。
|
||||
|
||||
**方案**:
|
||||
|
||||
1. `belief/occupancy.py` 用 `numpy` 布尔/整数张量替换 `set[int]`:
|
||||
每频道 248×248 uint8(≈61 KB),20 频道 ≈ 1.2 MB;盘/楔删除用切片 + 布尔掩码,
|
||||
粗格索引用 `np.add.reduceat`;`numpy` 缺失时回退现有纯 Python 实现(测试保证两条路径同结果)。
|
||||
2. 采样评分向量化:把 `subsample` 与 `representatives` 预转 `(n,2)` 数组,
|
||||
一次广播算完距离、角度、角向 gap,`expected_survival` 由 5600 次标量循环变成 2–3 条向量指令。
|
||||
3. 站点级编译缓存:`(station, channel, version)` → 掩码结果,`version` 不变直接复用;
|
||||
当前 `_skip_cache` 只缓存"必 no_signal"布尔,可扩展到整块删除掩码。
|
||||
4. MEC 增量维护:当前 `mec()` 每次版本变化重算全部幸存点(最多 6 万点);改为
|
||||
版本变化时只对新增删除点做包围圆增量更新,或按 1/8 子采样给出候选、证书判定用精确值。
|
||||
5. 批量基准并行化:`bench/runner.py` 用 `concurrent.futures.ProcessPoolExecutor`
|
||||
按场景分发(每进程独立 `LocalSimulator`,真值仍只进测试端),Mac M 系列 8 核可得 ~6–8×。
|
||||
6. 观测/遥测:单局 summary 写入 `compute_wall_s`、`profile_top`(可选 `--profile`),
|
||||
纳入基准表的必填列,防止"虚拟时间变快、墙钟悄悄变慢"。
|
||||
|
||||
**实测收益(2026-09-12)**:单局计算 **3.10 → 1.00 s(3.08×)**,最坏 5.84 → 1.30 s;
|
||||
20 场景基准集 12.2 → 3.9 s。虚拟时间与动作序列**逐位一致**(纯 Python 回退路径保留,
|
||||
`MCM26B_NO_NUMPY=1` 可强制)。未达 ≤0.8 s 的目标:剩余开销在
|
||||
`apply_measure` 的网格删除与 `ChannelParticles.__init__`,需要 P0-4b(表示层张量化)。
|
||||
|
||||
**验收**:`tests/test_particles.py`、`tests/test_bayes_loop_q3.py` 全过;
|
||||
纯 Python 与 numpy 两条路径在同一动作日志下产出逐位相同的 summary(`actions_sha256` 相同);
|
||||
单局 `compute_wall_s` ≤ 0.8 s。
|
||||
|
||||
---
|
||||
|
||||
### P1-1 清除点选在 C₂₀(K) 内离当前位置最近处
|
||||
|
||||
现状 `_near_clear_target` 只沿"当前位置 → 候选圆心"方向平移,平移量受
|
||||
`limit − radius` 限制,是被证明的一维特例。一般解是
|
||||
`C₂₀(K) = ∩_{g∈K} B(g, 20)`,取其内离当前位置最近的点:
|
||||
- 对凸多边形候选集,`C₂₀(K)` 仍是凸集(若干圆盘之交),可用"到当前点的最近点"的
|
||||
简单迭代/投影求得;
|
||||
- 若 `C₂₀(K)` 非空,则从该点清除的移动代价最小,且三角不等式保证仍在 20 m 内。
|
||||
|
||||
**预期收益**:Q3 单局清除移动 3668 m(734 s)中回收 20–35%(**−150 ~ −260 s**);
|
||||
Q4 同步受益。
|
||||
**风险**:`C₂₀` 空时退回现有 MEC 圆心逻辑(已实现)。
|
||||
|
||||
---
|
||||
|
||||
### P1-2 覆盖几何参数改为"离线搜索 + 运行期校验"
|
||||
|
||||
- Q3:`station_ring_radius_m` 由 1159.7 的可证明下界 1122.9 重算,并在 `validate_seven_coverage`
|
||||
中同时校验 **PF 网格覆盖**(现行文档已记录 1159.7 与 Optuna 建议值差 3.3 m 的取舍)。
|
||||
收益很小(≈44 s),但把"设计性质 vs 1.7% 均值差异"的取舍写成可复算脚本,而不是口口相传。
|
||||
- Q4:见 P0-2,覆盖集与巡回联合优化(在等价覆盖解中选巡回最短者,
|
||||
预期可在 23.6 km 基础上再降 5–10%)。
|
||||
- 所有覆盖计划产物落 `output/<problem>/coverage/<version>.json` + 证书,纳入版本管理。
|
||||
|
||||
---
|
||||
|
||||
### P1-3 评估与遥测重构(消除 B6)
|
||||
|
||||
1. **冻结基准集**(`bench/suites/`,一题一份、版本化、写入 `manifest.json`):
|
||||
- Q3:10/13/16 源 × 8 个种子 + 2 个圆周边界场景(`r_eff=1000`,扇区接缝);
|
||||
- Q4:10 源 3 定向、13 源 6 定向、16 源 8 定向 × 每种 3 个种子 + 朝外边界压力场景;
|
||||
- 场景与真值只进模拟器与校验器,策略端看不到(真值隔离不变量保持不变)。
|
||||
2. **统一 runner + 逐局 artifact**:`manifest.json` / `results.json` / `aggregate.{json,csv}` /
|
||||
`runs/<scene>/<variant>/summary.json` + `session.jsonl`,任何一局无效则 `all_valid=false` 且非零退出。
|
||||
3. **指标口径去重**:目前 `avg_locate_clear_time_s ≡ virtual_time_s`(单源评估集下二者必然相等),
|
||||
必须在多源基准集上重新定义并标注:
|
||||
`T_total`(整场虚拟时间)、`T_accounted`(首次证明找全时刻)、`T_last_clear`、
|
||||
`T_total / cleared`、`T_total / truth`。
|
||||
4. **运行历史持久化**:`output/` 目前不纳入 git,导致 `output/rl/review-20260911/`、
|
||||
`output/q3/optimization-20260911/` 等证据在 revert 后无法追溯。
|
||||
本轮起把**基准集的 summary/aggregate/manifest(压缩,不含大日志)**纳入版本管理,
|
||||
官方 jlog/日志仍按题面要求单独归档。
|
||||
|
||||
---
|
||||
|
||||
### P1-4 安全阀与退出可解释性
|
||||
|
||||
| 阀门 | 现状 | 改进 |
|
||||
| --- | --- | --- |
|
||||
| `persistent_search` | 默认已关闭,但没有任何"这会浪费多少"的提示;历史上已造成一次 346 170 s(98.84%)的无效演练 | 显式开启时输出预估上限(未清除频道数 × 站点数 × 6 s)并要求二次确认;`summary` 记录 `redundant_rescan_measures` |
|
||||
| `virtual_reserve_s` | 10 000 s 固定 | 改为 `max(10 000, 2 × 最远单动作上界)`,并在接近时把 `stop_reason` 与剩余预算写入 summary |
|
||||
| 完成判定 | `completed = 无中断 ∧ (清除数≥16 ∨ 每频道 CLEARED/ABSENT)` | 增加 `completion_basis ∈ {count_cap, per_channel_proof}` 字段,避免把"数量上界"与"逐频道证明"混为一谈 |
|
||||
| 缺席证明 | 覆盖账本 + PF 双通道 | summary 增加 `absence_evidence[channel] ∈ {pf_empty, coverage, count_cap}`,供论文与审计逐条追溯 |
|
||||
|
||||
---
|
||||
|
||||
### P2-1 选点评分的解析化/查表化
|
||||
|
||||
`expected_survival` 的物理含义可用解析近似替代:对给定测点 q 与候选集,
|
||||
`E[log 幸存占比]` 的一阶近似只依赖 (候选集到 q 的距离分布, 角向展布)。
|
||||
先在离线基准上验证解析近似与采样评分选出的点一致率 ≥ 90%,再切默认实现。
|
||||
预计再省 30–50% 的评分开销(P0-4 之后已不是瓶颈,列入 P2)。
|
||||
|
||||
---
|
||||
|
||||
### P2-2 是否重启学习类方法的门控条件
|
||||
|
||||
只有在**下列四条同时满足**时才考虑把 ML 重新引入,且只允许替换"任务排序"这一个部件:
|
||||
|
||||
1. P0-1/P0-2/P0-3 全部落地并通过基准集验收;
|
||||
2. 手写基线仍有 ≥ 10% 的可测改进空间,且已定位到具体的排序子问题;
|
||||
3. 训练与部署共用同一控制器模块,并有逐状态一致性测试(旧 HRL 的 13 000 行里最有价值的
|
||||
就是这条纪律:`HRLControllerMixin` 被 env 与 runtime 逐字节共用);
|
||||
4. 评估集包含多源与定向场景(现役 20 场景单源评估集不足以支撑任何结论)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 实施路线图
|
||||
|
||||
| 阶段 | 内容 | 交付物 | 验收门槛 | 依赖 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **S1(P0,2–3 天)** | P0-2 最小命中集 + P0-4 并行基准;P1-3 冻结基准集 + manifest;P1-4 安全阀 | `guarantee/cover.py`、`bench/runner.py`、`bench/suites/*`、`docs/` 更新 | Q4 巡回 ≤ 25 km;基准集并行跑完 ≤ 60 s;全部 `valid` | 无 |
|
||||
| **S2(P0,2–3 天)** | P0-1 融合巡回(Q3);P1-1 清除点 | `plan/schedule.py`、`plan/score.py`、`Episode` 组合化重构 | Q3 均值 ≤ 2700 s、最大 ≤ 4000 s;移动 −25% | S1 的 runner |
|
||||
| **S3(P0/P1,3–5 天)** | P0-4 信念层 numpy 化;P0-3 联合信念 + 可见性选点(Q4) | `belief/occupancy.py`、`belief/joint.py`、`plan/policy.py` | 单局计算 ≤ 0.8 s;Q4 定向全清 100%、后备触发 −70% | S2 的接口 |
|
||||
| **S4(P1/P2,2–3 天)** | P1-2 覆盖参数搜索固化;P2-1 评分解析化;论文数据表 | 覆盖计划证书、`docs/paper` 数据 | 与 S3 结果配对不退化 | S3 |
|
||||
| **S5(演练)** | 官方演练:Q3 用全向、Q4 用混合;先实测单请求延迟与总请求数,核对 1200 s / 2 MB | 官方日志与报告 | 全清 + 正常退出 + 计时复算一致 | 团队排期 |
|
||||
|
||||
**顺序约束**:S1 的基准集必须先于任何算法改动落地,否则无法配对;否则"更快"不可证。
|
||||
|
||||
---
|
||||
|
||||
## 5. 验收与度量
|
||||
|
||||
### 5.1 有效局定义(沿用现有基准脚本,不得放宽)
|
||||
|
||||
```
|
||||
valid := 全部真实源被清除
|
||||
∧ 被判缺席的频道都与真值一致(无误判)
|
||||
∧ 正常 /exit(exit_reason == user_exit)
|
||||
∧ 零算法异常(anomalies == [])
|
||||
∧ 逐动作虚拟时间复算与服务器返回逐微秒一致
|
||||
```
|
||||
|
||||
### 5.2 必报指标(每个变体、每个场景,落盘 + 汇总)
|
||||
|
||||
- 虚拟时间:`T_total`、`T_accounted`、`T_last_clear`、`T_total/cleared`,以及
|
||||
均值/中位/最大/P90 与 **< 4000 s 场次比例**;
|
||||
- 动作:`measures`、`clears`、`failed_clears`、`fallback_clear_attempts`、
|
||||
`redundant_rescan_measures`、`total_requests`;
|
||||
- 移动:`move_distance_m`,以及 move/action/switch 三分项占比;
|
||||
- 墙钟:`compute_wall_s`、请求吞吐(ms/请求)、批量基准总时长、训练 steps/s(若涉及);
|
||||
- 配对比较:同场景同误差种子下 `1 − T_variant / T_baseline` 的均值、
|
||||
更快场数、以及对场景做 10 000 次 bootstrap 的 95% 区间(参照 `summarize_rl_revision.py` 的做法)。
|
||||
|
||||
### 5.3 回归
|
||||
|
||||
`uv run pytest`(当前 232 项)必须全过;新增:
|
||||
- `CoveragePlan.verify()` 的正/负例(故意删一个点必须被检出);
|
||||
- 联合信念的真源保留性质测试(随机 (p,h) × 随机观测序列,真源 (p,h) 永不被删);
|
||||
- 融合巡回的"每源至少一条站点方位线"性质测试;
|
||||
- 逐位一致性测试:numpy 后端与纯 Python 后端在同一动作序列下 summary 完全相同。
|
||||
|
||||
---
|
||||
|
||||
## 6. 风险与明确不承诺的部分
|
||||
|
||||
### 6.1 风险登记
|
||||
|
||||
| 风险 | 影响 | 缓解 |
|
||||
| --- | --- | --- |
|
||||
| 最小命中集证书依赖数值采样,官方分布未知 | 极端 (p,h) 漏检 → 漏源 | 保留解析七站证明(Q3);Q4 证书采样分辨率/裕量写入 summary;保留 10% 保险点预算与 49 点回退开关 |
|
||||
| 站点三角化在 0.72% 源位置上只有 1 站在射程内 | 这些场景仍需专用探点 | `prob_detect` 触发回退路径,保留现有 `_select_point` |
|
||||
| 朝向先验为工程假设 | 选点次优 | 先验只影响顺序;不确定时退化为全向;安全性由 20 m 证书 + 覆盖证明负责 |
|
||||
| numpy 化引入浮点路径差异 | 真源保留性质被破坏 | 两条后端同时保留并对拍;保持整数微秒复算计时 |
|
||||
| 并行基准引入进程/端口/临时目录问题 | 基准不稳定 | 每进程独立内存回环;不共用端口;`manifest` 记录随机种子 |
|
||||
|
||||
### 6.2 不承诺的部分
|
||||
|
||||
- **第四问 4000 s**:10 源场景下,仅"发现 + 缺席证明"就约需
|
||||
最小命中集巡回 4719 s + 缺席检测 ≈1900 s ≈ 6600 s,加之定位清除,4000 s 不可达。
|
||||
若必须逼近该线,需要改变停止条件(例如接受 `unresolved_channels` 而非逐频道缺席证明),
|
||||
那是**成绩口径的取舍**,必须先与题面评分方式核对,本轮不作为代码默认行为。
|
||||
- 本文所有收益数字都是**自建模拟器上的估计或本次复跑观测**,不是官方成绩;
|
||||
官方分布、r_eff 分布、误差场分布仍是测试假设。
|
||||
- 不声称 P0-1/P0-3 已在官方演练验证——需新的演练记录。
|
||||
|
||||
---
|
||||
|
||||
## 附录 A 复现命令与本次新增实验
|
||||
|
||||
```bash
|
||||
# 1) 基线配对(本次复跑:bayes 3707.3 s vs seven_batch 5581.8 s,局部 −32.1%)
|
||||
uv run python scripts/benchmark_q3_bayes.py --seeds 0,1 --out /tmp/mcmopt/q3
|
||||
|
||||
# 2) 运行历史计时分解(已入库):任意会话日志 → 移动/检测/换频分相 + 重复复扫检测
|
||||
uv run python scripts/analyze_run_timing.py session.jsonl --plan seven
|
||||
uv run python scripts/analyze_run_timing.py referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl --plan seven
|
||||
uv run python scripts/analyze_run_timing.py referee-data/sessions/6X58-XQ7U-CJ24-JQQR/log.jsonl --plan 49
|
||||
# 实测输出(与服务器记录最大偏差 0.000000 s,证明复算口径正确):
|
||||
# session.jsonl 350227.692 s,移动 82.3%,检测 10323 次,重复率 96.4,
|
||||
# 末次清除后仍花 346169.9 s / 10225 次空复扫
|
||||
# BBM9 (Q3) 3134.643 s,移动 75.9%,探点 21 次 / 1138.7 s
|
||||
# 6X58 (Q4) 3251.021 s,移动 78.3%,检测 112 次
|
||||
|
||||
# 3) 第四问覆盖证书与最小命中集(已入库)
|
||||
uv run python scripts/verify_q4_cover.py --out output/q4/cover-certificate.json
|
||||
# 实测输出:目标空间 43032 个 (p,h)
|
||||
# 现役 49 点方格:缺口 0,NN 巡回 36.4 km(7280 s 移动)
|
||||
# 贪心最小命中集:31 点,缺口 0,NN 巡回 22.9 km(4587 s 移动)
|
||||
|
||||
# 4) 感知层剖面(单局 6.04 s 计算中 expected_survival 占 ~72%)
|
||||
python -m cProfile -s cumulative <单局驱动脚本>
|
||||
```
|
||||
|
||||
> 第 2、3 项已作为常驻工具入库,使"虚拟时间花在哪"与"覆盖集是否仍然合法"
|
||||
> 成为可随时重跑的回归项;第 1、4 项仍是一次性分析,建议在 S1 阶段并入
|
||||
> `bench/runner.py` 的必报指标(`compute_wall_s`、`profile_top`)。
|
||||
|
||||
## 附录 B 数字出处索引
|
||||
|
||||
| 数字 | 出处 |
|
||||
| --- | --- |
|
||||
| 移动 80.50% / 16.78% / 2.71%(Q3) | `referee-data/sessions/{BBM9,RM7Y,VQKB}/log.jsonl` 按 `verify_q3_practice.py` 模型复算 |
|
||||
| 移动 82.30%(官方 J2WH) | `session.jsonl` 求和 |
|
||||
| 346 169.9 s 空复扫 | `session.jsonl` `/exit` 时刻 350 227.691846 s 减去 12 源首轮清除的 4 057.839 s |
|
||||
| Q4 定向 2/6、漏检 4/4 全为定向 | `referee-data/sessions/{6X58,BAU8}/meta.json` + `log.jsonl` |
|
||||
| bayes 3707.3 / seven 5581.8 | 本次复跑 `benchmark_q3_bayes.py --seeds 0,1` |
|
||||
| 3535.9 s / 109 检测 / 6960 m 巡回 / 5741 m 探点 | 本次复跑计时分解 |
|
||||
| 13652.1 s / 560 检测 / 51 356 m(Q4) | 本次复跑单局 |
|
||||
| `expected_survival` 72% | 本次 `cProfile` 单局 |
|
||||
| HRL 27.0 steps/s、4007.9 s、109 776 步 | `output/hrl/ui/q3-main/q3.json` + `*.monitor.csv` |
|
||||
| bayes 比 HRL 快 4.3–5.0%、94% 差距为移动 | `output/hrl/ui/q3-main/eval/at-final/aggregate.json` + `runs/*/summary.json` |
|
||||
| 站点三角化 99.28%、交会角 5 分位 58.5° | 本次离线采样 20 000 点 |
|
||||
| 49 点 vs 30 点覆盖集 | 本次贪心击中集计算(附录 A 第 5 项) |
|
||||
Reference in New Issue
Block a user