267 lines
14 KiB
Markdown
267 lines
14 KiB
Markdown
# 问题一算法说明:有界测向误差下的角域交会、直径与最小包围圆
|
||
|
||
> 本文按**当前仓库实现**重写,替代早期只描述理论方案的版本。
|
||
> 问题一生产入口为 `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`. 在线闭环中的保守信念、负观测与联合信念差异。
|