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

267 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 问题一算法说明:有界测向误差下的角域交会、直径与最小包围圆
> 本文按**当前仓库实现**重写,替代早期只描述理论方案的版本。
> 问题一生产入口为 `src/mcm26b/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`. 在线闭环中的保守信念、负观测与联合信念差异。