14 KiB
问题一算法说明:有界测向误差下的角域交会、直径与最小包围圆
本文按当前仓库实现重写,替代早期只描述理论方案的版本。 问题一生产入口为
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 个随机交会算例的配对结果 |
.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 坐标归一化与边界交点枚举
先对所有检测点做平移和统一缩放,使数值量级接近单位坐标;结果再换回原坐标。
- 生成
k=3n条半平面。 - 枚举全部边界直线对(
\binom{k}{2}对),用行列式\Delta=ae-bd求交点;仅在\Delta恰为0时跳过,近平行对也保留, 因为其交点可能是细长区域的合法远端顶点。 - 保留满足全部约束的交点;可行性判定使用随坐标量级缩放的位置容差
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. 伪代码
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 含圆盘和距离上界,边界可能含圆弧。
参考文献
- 全国大学生数学建模竞赛组委会. 2026 年高教社杯全国大学生数学建模竞赛 B 题:无线电干扰源的快速自动定位与清除[Z]. 2026. 本地题面
issue/B题.pdf。 - BOYD S, VANDENBERGHE L. Convex Optimization[M]. Cambridge University Press, 2004. 凸集、半平面与凸组合背景。
- WELZL E. Smallest enclosing disks (balls and ellipsoids)[C]//New Results and New Trends in Computer Science, LNCS 555, 1991: 359–370. 随机增量最小包围圆。
- 本项目.
docs/algo-2.md(问题二当前实现). 问题二对本文半平面语义与最小圆的复用说明。 - 本项目.
docs/algo-3.md、docs/algo-4.md. 在线闭环中的保守信念、负观测与联合信念差异。