baseline
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
"""问题一基线实现:网格采样 + 轴对齐包围盒(bbox)代理。
|
||||
|
||||
这是"先上手"的朴素做法,常见于直接对可行点打网格再读包围盒:
|
||||
|
||||
1. 在固定大框上按步长采样,保留满足全部角域约束的点;
|
||||
2. 直径用包围盒对角线代理 —— 只要区域是斜的/细长的就会系统性高估;
|
||||
3. 覆盖判断用"包围盒中心 + 代理直径"的圆 —— 因为包围盒自身对其中心对称,
|
||||
该判据几乎恒为"能覆盖",从而丢掉问题一真正要考的反例。
|
||||
|
||||
本实现刻意保留这些结构性缺陷,作为``optimal.py``的对照;它不读取最优实现的
|
||||
任何中间量,两条代码路径完全独立。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from time import perf_counter
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mcm26b.geometry.localization import Measurement, halfplanes
|
||||
|
||||
from project.common import Method
|
||||
|
||||
METHOD = Method(
|
||||
key="baseline",
|
||||
name="网格采样 + bbox 对角线代理",
|
||||
kind="baseline",
|
||||
note="轴对齐包围盒近似直径与覆盖,O(盒面积/步长²),与参考解同分辨率",
|
||||
)
|
||||
|
||||
BOX_M = 2600.0
|
||||
STEP_M = 5.0
|
||||
|
||||
|
||||
def solve_case(case: dict) -> dict:
|
||||
start = perf_counter()
|
||||
measurements = [Measurement(row["x"], row["y"], row["bearing_deg"],
|
||||
row.get("half_angle_deg", 1.0))
|
||||
for row in case["measurements"]]
|
||||
planes = [plane for m in measurements for plane in halfplanes(m)]
|
||||
|
||||
xs = np.arange(-BOX_M, BOX_M + STEP_M, STEP_M)
|
||||
grid_x, grid_y = np.meshgrid(xs, xs) # 行=y,列=x
|
||||
mask = np.ones(grid_x.shape, dtype=bool)
|
||||
for a, b, c in planes:
|
||||
mask &= (a * grid_x + b * grid_y <= c)
|
||||
|
||||
result = _evaluate(mask, xs)
|
||||
result["method"] = METHOD.key
|
||||
result["runtime_ms"] = round((perf_counter() - start) * 1000.0, 4)
|
||||
result["algorithm"] = METHOD.name
|
||||
return result
|
||||
|
||||
|
||||
def _evaluate(mask: np.ndarray, axis: np.ndarray) -> dict:
|
||||
if not mask.any():
|
||||
return _empty("empty")
|
||||
# 可行点触到采样框边界 => 区域至少延伸到框外,判无界
|
||||
if (mask[0, :].any() or mask[-1, :].any()
|
||||
or mask[:, 0].any() or mask[:, -1].any()):
|
||||
return _empty("unbounded")
|
||||
|
||||
rows, cols = np.nonzero(mask)
|
||||
x_min, x_max = axis[cols].min(), axis[cols].max()
|
||||
y_min, y_max = axis[rows].min(), axis[rows].max()
|
||||
width, height = x_max - x_min, y_max - y_min
|
||||
diameter = math.hypot(width, height) # 包围盒对角线代理
|
||||
center = ((x_min + x_max) / 2.0, (y_min + y_max) / 2.0)
|
||||
px = axis[cols]
|
||||
py = axis[rows]
|
||||
max_distance = float(np.max(np.hypot(px - center[0], py - center[1])))
|
||||
return {
|
||||
"status": "polygon" if mask.sum() >= 2 else "point",
|
||||
"diameter_m": diameter,
|
||||
"diameter_infinite": False,
|
||||
"covers": bool(max_distance <= diameter / 2.0 + 1e-9),
|
||||
"mec_radius_m": None,
|
||||
"max_excess_m": round(max_distance - diameter / 2.0, 6),
|
||||
"outside_vertex_count": None,
|
||||
"vertex_count": int(mask.sum()),
|
||||
"bbox_width_m": round(width, 3),
|
||||
"bbox_height_m": round(height, 3),
|
||||
"runtime_ms": None,
|
||||
}
|
||||
|
||||
|
||||
def _empty(status: str) -> dict:
|
||||
return {
|
||||
"status": status,
|
||||
"diameter_m": None,
|
||||
"diameter_infinite": status == "unbounded",
|
||||
"covers": None,
|
||||
"mec_radius_m": None,
|
||||
"max_excess_m": None,
|
||||
"outside_vertex_count": None,
|
||||
"vertex_count": 0,
|
||||
}
|
||||
Reference in New Issue
Block a user