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

14 KiB
Raw Blame History

问题一算法说明:有界测向误差下的角域交会、直径与最小包围圆

本文按当前仓库实现重写,替代早期只描述理论方案的版本。 问题一生产入口为 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 坐标归一化与边界交点枚举

先对所有检测点做平移和统一缩放,使数值量级接近单位坐标;结果再换回原坐标。

  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. 伪代码

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. 在线闭环中的保守信念、负观测与联合信念差异。