123
@@ -0,0 +1,71 @@
|
||||
# docs 索引
|
||||
|
||||
仓库文档分四类:**总览与流程**、**逐问算法**、**验证与对比**、**论文与插图**。
|
||||
阅读顺序建议按下面的表格从上到下。
|
||||
|
||||
## 总览与流程
|
||||
|
||||
| 文档 | 内容 |
|
||||
| --- | --- |
|
||||
| [`总体思路与流程图.md`](总体思路与流程图.md) | 四问主线、端到端流程图(mermaid)、执行步骤与执行时间速查、交付物与验收锚点 |
|
||||
| [`执行时间与执行步骤.md`](执行时间与执行步骤.md) | 计时模型、会话状态机与动作回合、附件示例逐步推演、实测日志分解、时间预算与安全阀 |
|
||||
| [`B题建模分析与实施计划.md`](B题建模分析与实施计划.md) | 四问建模取舍与 P0–P7 实施计划(最早的设计文档) |
|
||||
| [`协议规则表与状态机.md`](协议规则表与状态机.md) | 指令字段表、结果码、计时模型、状态机(P0 交付) |
|
||||
|
||||
## 逐问算法
|
||||
|
||||
| 文档 | 内容 |
|
||||
| --- | --- |
|
||||
| [`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` 最小命中集、位置×朝向联合信念、后备盲清 |
|
||||
|
||||
## 优化与验证
|
||||
|
||||
| 文档 | 内容 |
|
||||
| --- | --- |
|
||||
| [`第三四问架构优化与运行提速方案.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`) |
|
||||
| [`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) | 对比框架目录结构与运行方式 |
|
||||
|
||||
## 口径登记
|
||||
|
||||
同一事实在多份文档中出现时,以下列来源为准;发现不一致请先改文档,再复核图。
|
||||
|
||||
| 事实 | 权威来源 |
|
||||
| --- | --- |
|
||||
| 题面常量(Ω、速度、各动作耗时、源与频道范围) | `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` 生成) |
|
||||
|
||||
已知的两处需要随环境更新的引用:
|
||||
|
||||
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 引号混淆。
|
||||
@@ -0,0 +1,62 @@
|
||||
# docs/figures —— 论文插图
|
||||
|
||||
每张图只输出 PNG,由 `scripts/make_figures.py` 用 matplotlib 生成。
|
||||
`manifest.json` 记录每张图的数据来源(路径 + sha256 前 12 位 + 行数)与生成命令。
|
||||
|
||||
```bash
|
||||
uv run python scripts/make_figures.py # 全部 11 张
|
||||
uv run python scripts/make_figures.py --list # 图名
|
||||
uv run python scripts/make_figures.py --only geo-q3-seven-point-coverage
|
||||
uv run python scripts/make_figures.py --scale 1.5 # 整体放大(尺寸倍率)
|
||||
```
|
||||
|
||||
依赖:`matplotlib`、`Pillow`、`docs/paper/fonts/` 下的字体。
|
||||
`matplotlib` 缓存写入仓库内 `.mpl-cache/`,不污染用户目录。
|
||||
|
||||
## 约定
|
||||
|
||||
- 图内不放标题、图注与解释性文字,只保留坐标轴、图例与数据标注;
|
||||
图的含义由文件名与下表承担,解释写在论文正文。
|
||||
- 配色(`scripts/make_figures.py::C`):深蓝 `#1f4e79` 主流程与协议,
|
||||
砖红 `#b03a2e` 真值源与关键结论,墨绿 `#1e7a5f` 清除与通过项,
|
||||
土黄 `#b8860b` 后备与警示,灰色只用于网格与次要文字。
|
||||
- 字体:中文宋体 `SongtiSC-Regular/Bold`,标题黑体 `HeitiSC-Light/Medium`,
|
||||
数字与西文 Times New Roman,均取自 `docs/paper/fonts/`,与 `main.tex` 一致。
|
||||
- 输出为 PNG(`savefig.dpi = 200`,另有 `--scale` 倍率),按 160 mm 宽排版时
|
||||
与正文同字号。
|
||||
|
||||
## 图清单
|
||||
|
||||
| 文件 | 内容 | 数据来源 |
|
||||
| --- | --- | --- |
|
||||
| `flow-overall-architecture.png` | 总体思路:题面抽象、在线三层、四问主线、三条闭环 | `src/mcm26b/config.py`、`docs/B题建模分析与实施计划.md` |
|
||||
| `steps-state-machine.png` | 会话状态机(IDLE / 倒计时 / OPEN / CLOSED) | `docs/协议规则表与状态机.md`、`src/mcm26b/protocol/client.py` |
|
||||
| `timing-attachment-example-105-111-194-199.png` | 附件计时示例逐步推演 | `docs/协议规则表与状态机.md` |
|
||||
| `timing-measured-q3-10-sources.png` | 实测一局的虚拟时间分解(累计曲线 + 构成) | `referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl` |
|
||||
| `geo-q1-convex-intersection-zoom.png` | 问题一:角域交会总览 + 定位区域放大(直径圆与 MEC) | `output/q1/practice/U5ZW-P9KN-TCAG-R7ST_observations.json` |
|
||||
| `geo-q1-diameter-circle-counterexample.png` | 问题一:直径圆不覆盖的反例(等边三角形布站) | `examples/q1/triangle.json` |
|
||||
| `geo-q2-guaranteed-reception-disk.png` | 问题二:候选盘、截断角域外接圆、安全盘 `B(c, 1000−a)` | `src/mcm26b/config.py`、`docs/algo-2.md` |
|
||||
| `geo-q3-seven-point-coverage.png` | 问题三:七点覆盖(7 个 1000 m 接收盘的并集覆盖 Ω)与三套计划对比 | `src/mcm26b/planner/seven.py`、`docs/algo-3.md` |
|
||||
| `geo-q4-minimum-cover-31-points.png` | 问题四:31 点最小命中集与 `forward_half_disk` 语义 | `src/mcm26b/guarantee/plans/q4_mincover_v2.json` |
|
||||
| `replay-webui-q3-omnidirectional.png` | WebUI 回放画布复现(全向局,10 源全清) | `referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl` |
|
||||
| `replay-webui-q4-directional.png` | WebUI 回放画布复现(定向源局) | `referee-data/sessions/GM56-DFXZ-XKDM-XYV7/log.jsonl` |
|
||||
|
||||
后两张对应 WebUI 的预览功能:把回放器画布上的 Ω 与真值源、运动轨迹、
|
||||
检测示向度射线、清除标记,以及右侧事件流水与底部虚拟时间轴一起导出。
|
||||
|
||||
## 数据来源与复现
|
||||
|
||||
- `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` 现算;
|
||||
问题三、问题四直接读覆盖计划与证书,不手抄数字。
|
||||
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 65 KiB |
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"generator": "scripts/make_figures.py",
|
||||
"command": "uv run python scripts/make_figures.py",
|
||||
"palette": {
|
||||
"ink": "#1c2430",
|
||||
"muted": "#5c6673",
|
||||
"grid": "#e4e9ee",
|
||||
"primary": "#1f4e79",
|
||||
"primary_fill": "#dce6f1",
|
||||
"accent": "#b03a2e",
|
||||
"accent_fill": "#f6dcd8",
|
||||
"success": "#1e7a5f",
|
||||
"success_fill": "#d8ece5",
|
||||
"warn": "#b8860b",
|
||||
"warn_fill": "#f6ecd2",
|
||||
"violet": "#5b4b8a"
|
||||
},
|
||||
"fonts": {
|
||||
"dir": "docs/paper/fonts",
|
||||
"map": {
|
||||
"song": "SongtiSC-Regular.ttf",
|
||||
"song_bold": "SongtiSC-Bold.ttf",
|
||||
"hei": "HeitiSC-Light.ttf",
|
||||
"hei_bold": "HeitiSC-Medium.ttf",
|
||||
"times": "Times New Roman.ttf",
|
||||
"times_bold": "Times New Roman Bold.ttf"
|
||||
}
|
||||
},
|
||||
"figures": [
|
||||
{
|
||||
"stem": "flow-overall-architecture",
|
||||
"png": "docs/figures/flow-overall-architecture.png",
|
||||
"scale": 1.0,
|
||||
"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",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/协议规则表与状态机.md",
|
||||
"sha256_12": "27c8f7051b26",
|
||||
"lines": 215
|
||||
},
|
||||
{
|
||||
"path": "src/mcm26b/protocol/client.py",
|
||||
"sha256_12": "0e9797a85cd7",
|
||||
"lines": 333
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "timing-attachment-example-105-111-194-199",
|
||||
"png": "docs/figures/timing-attachment-example-105-111-194-199.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/协议规则表与状态机.md",
|
||||
"sha256_12": "27c8f7051b26",
|
||||
"lines": 215
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "geo-q1-convex-intersection-zoom",
|
||||
"png": "docs/figures/geo-q1-convex-intersection-zoom.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "output/q1/practice/U5ZW-P9KN-TCAG-R7ST_observations.json",
|
||||
"sha256_12": "d2cba13464fd",
|
||||
"lines": 87
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "geo-q1-diameter-circle-counterexample",
|
||||
"png": "docs/figures/geo-q1-diameter-circle-counterexample.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "examples/q1/triangle.json",
|
||||
"sha256_12": "eeb0c92ae21c",
|
||||
"lines": 29
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "geo-q2-guaranteed-reception-disk",
|
||||
"png": "docs/figures/geo-q2-guaranteed-reception-disk.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "src/mcm26b/config.py",
|
||||
"sha256_12": "c513450dc892",
|
||||
"lines": 213
|
||||
},
|
||||
{
|
||||
"path": "docs/algo-2.md",
|
||||
"sha256_12": "24f3e844deb9",
|
||||
"lines": 312
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "geo-q3-seven-point-coverage",
|
||||
"png": "docs/figures/geo-q3-seven-point-coverage.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "src/mcm26b/planner/seven.py",
|
||||
"sha256_12": "6ac65bd483f8",
|
||||
"lines": 113
|
||||
},
|
||||
{
|
||||
"path": "docs/algo-3.md",
|
||||
"sha256_12": "5638192b8669",
|
||||
"lines": 456
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "geo-q4-minimum-cover-31-points",
|
||||
"png": "docs/figures/geo-q4-minimum-cover-31-points.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "src/mcm26b/guarantee/plans/q4_mincover_v2.json",
|
||||
"sha256_12": "71e54616ae21",
|
||||
"lines": 162
|
||||
},
|
||||
{
|
||||
"path": "docs/algo-4.md",
|
||||
"sha256_12": "1774f8bf85db",
|
||||
"lines": 485
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "timing-measured-q3-10-sources",
|
||||
"png": "docs/figures/timing-measured-q3-10-sources.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl",
|
||||
"sha256_12": "5a308e53ed09",
|
||||
"lines": 133,
|
||||
"case_code": "BBM9-HZG2-77N5-NKKC",
|
||||
"module": "q3_practice"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "replay-webui-q3-omnidirectional",
|
||||
"png": "docs/figures/replay-webui-q3-omnidirectional.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "referee-data/sessions/BBM9-HZG2-77N5-NKKC/log.jsonl",
|
||||
"sha256_12": "5a308e53ed09",
|
||||
"lines": 133,
|
||||
"case_code": "BBM9-HZG2-77N5-NKKC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"stem": "replay-webui-q4-directional",
|
||||
"png": "docs/figures/replay-webui-q4-directional.png",
|
||||
"scale": 1.0,
|
||||
"sources": [
|
||||
{
|
||||
"path": "referee-data/sessions/GM56-DFXZ-XKDM-XYV7/log.jsonl",
|
||||
"sha256_12": "f498b2073cdf",
|
||||
"lines": 421,
|
||||
"case_code": "GM56-DFXZ-XKDM-XYV7"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,208 @@
|
||||
# 几何计算示意图册
|
||||
|
||||
> 本册逐图给出坐标口径、关键量与图中各元素的含义。插图位于 [`figures/`](figures/),复现命令:
|
||||
>
|
||||
> ```bash
|
||||
> uv run python scripts/make_figures.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$ 缩成一个点——这是**必须做局部放大**的原因。
|
||||
|
||||
**右(放大,视野 ±31.4 m)**:以最小包围圆圆心为中心:
|
||||
|
||||
- 浅蓝扇形 = 三个角域在放大框内的可见部分;三者**重叠成白色区域**= $P$;
|
||||
- 红色实线多边形 = $P$ 的顶点边界(与左图同一个集合);
|
||||
- 蓝色虚线圆 = **直径圆**,半径 $D/2=11.9984$ m,圆心是中点 $(-450.634,\ 508.944)$;
|
||||
- 绿色实线圆 = **最小包围圆(MEC)**,$\rho=12.0686$ m,圆心 $(-449.977,\ 507.953)$。
|
||||
|
||||
**关键量(图 (c) 栏)**
|
||||
|
||||
| 量 | 值 | 判定 |
|
||||
| --- | ---: | --- |
|
||||
| 直径 $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` 与正文。
|
||||
@@ -0,0 +1,178 @@
|
||||
# 总体思路与流程图
|
||||
|
||||
> 插图:[`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/make_figures.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)。
|
||||
@@ -0,0 +1,178 @@
|
||||
# 执行时间与执行步骤
|
||||
|
||||
> 配套插图:[`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/make_figures.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/make_figures.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/make_figures.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`。
|
||||