This commit is contained in:
Horldsence
2026-09-12 16:58:25 +08:00
parent 1fa2264a17
commit 892451dca9
36 changed files with 8767 additions and 0 deletions
+150
View File
@@ -0,0 +1,150 @@
"""问题一同案配对对比:最优 vs 基线 vs 独立参考解。"""
from __future__ import annotations
from project.common import (Method, RESULTS_DIR, markdown_table, mean,
ratio, write_json, write_text)
from project.q1 import baseline, cases, optimal, reference
METHODS: tuple[Method, ...] = (optimal.METHOD, baseline.METHOD, reference.METHOD)
FINITE = ("point", "segment", "polygon")
def _run(case: dict) -> dict:
opt = optimal.solve_case(case)
base = baseline.solve_case(case)
ref = reference.solve_case(case)
finite = ref["status"] in FINITE and ref["diameter_m"] is not None
return {
"id": case["id"],
"name": case.get("name", case["id"]),
"source": case.get("source", "synthetic"),
"measurements": len(case["measurements"]),
"status_ref": ref["status"],
"status_opt": opt["status"],
"status_base": base["status"],
"status_opt_ok": opt["status"] == ref["status"],
"status_base_ok": base["status"] == ref["status"],
"diameter_ref_m": ref["diameter_m"],
"diameter_opt_m": opt["diameter_m"],
"diameter_base_m": base["diameter_m"],
"abs_err_opt_m": (round(abs(opt["diameter_m"] - ref["diameter_m"]), 4)
if finite and opt["diameter_m"] is not None else None),
"abs_err_base_m": (round(abs(base["diameter_m"] - ref["diameter_m"]), 4)
if finite and base["diameter_m"] is not None else None),
"covers_ref": ref["covers"],
"covers_opt": opt["covers"],
"covers_base": base["covers"],
"covers_opt_ok": (opt["covers"] == ref["covers"]
if ref["covers"] is not None and opt["covers"] is not None
else None),
"covers_base_ok": (base["covers"] == ref["covers"]
if ref["covers"] is not None and base["covers"] is not None
else None),
"mec_radius_opt_m": opt["mec_radius_m"],
"mec_radius_ref_m": ref["mec_radius_m"],
"outside_vertices_opt": opt["outside_vertex_count"],
"runtime_opt_ms": opt["runtime_ms"],
"runtime_base_ms": base["runtime_ms"],
"runtime_ref_ms": ref["runtime_ms"],
"reference_resolution_m": ref["resolution_m"],
}
def _aggregate(rows: list[dict]) -> dict:
polygon_rows = [r for r in rows if r["status_ref"] == "polygon"]
opt_errs = [r["abs_err_opt_m"] for r in polygon_rows
if r["abs_err_opt_m"] is not None]
base_errs = [r["abs_err_base_m"] for r in polygon_rows
if r["abs_err_base_m"] is not None]
cov_opt = [r["covers_opt_ok"] for r in rows if r["covers_opt_ok"] is not None]
cov_base = [r["covers_base_ok"] for r in rows if r["covers_base_ok"] is not None]
return {
"cases": len(rows),
"diameter_compared": len(opt_errs),
"status_accuracy_optimal": ratio(sum(r["status_opt_ok"] for r in rows), len(rows)),
"status_accuracy_baseline": ratio(sum(r["status_base_ok"] for r in rows), len(rows)),
"diameter_mae_optimal_m": mean(opt_errs),
"diameter_mae_baseline_m": mean(base_errs),
"diameter_max_err_optimal_m": round(max(opt_errs), 4) if opt_errs else 0.0,
"diameter_max_err_baseline_m": round(max(base_errs), 4) if base_errs else 0.0,
"coverage_compared": len(cov_opt),
"coverage_accuracy_optimal": ratio(sum(cov_opt), len(cov_opt)),
"coverage_accuracy_baseline": ratio(sum(cov_base), len(cov_base)),
"runtime_optimal_mean_ms": mean(r["runtime_opt_ms"] for r in rows),
"runtime_baseline_mean_ms": mean(r["runtime_base_ms"] for r in rows),
"runtime_reference_mean_ms": mean(r["runtime_ref_ms"] for r in rows),
}
def _render(rows: list[dict], aggregate: dict, title: str) -> str:
headers = ["算例", "来源", "参考状态", "最优状态", "基线状态",
"D参考(m)", "D最优(m)", "D基线(m)", "|ΔD|最优", "|ΔD|基线",
"覆盖参考", "覆盖最优", "覆盖基线"]
body = []
for r in rows:
body.append([
r["name"], r["source"], r["status_ref"], r["status_opt"], r["status_base"],
_fmt(r["diameter_ref_m"]), _fmt(r["diameter_opt_m"]),
_fmt(r["diameter_base_m"]),
_fmt(r["abs_err_opt_m"]), _fmt(r["abs_err_base_m"]),
_bool(r["covers_ref"]), _bool(r["covers_opt"]), _bool(r["covers_base"]),
])
text = [f"# {title}", "",
"参考解为独立的大框半平面裁剪 + 精确直径/MEC;",
"固定示例见 `examples/q1`,解析期望由 `tests/test_geometry*.py` 固化。",
"", markdown_table(headers, body), "",
"## 汇总", ""]
summary_rows = [
["状态判定准确率", _pct(aggregate["status_accuracy_optimal"]),
_pct(aggregate["status_accuracy_baseline"])],
["直径平均绝对误差 (m)", _fmt(aggregate["diameter_mae_optimal_m"], 3),
_fmt(aggregate["diameter_mae_baseline_m"], 3)],
["直径最大误差 (m)", _fmt(aggregate["diameter_max_err_optimal_m"], 3),
_fmt(aggregate["diameter_max_err_baseline_m"], 3)],
["覆盖判定准确率", _pct(aggregate["coverage_accuracy_optimal"]),
_pct(aggregate["coverage_accuracy_baseline"])],
["平均耗时 (ms)", _fmt(aggregate["runtime_optimal_mean_ms"], 3),
_fmt(aggregate["runtime_baseline_mean_ms"], 3)],
]
text.append(markdown_table(["指标", "最优", "基线"], summary_rows))
return "\n".join(text) + "\n"
def _fmt(value, digits: int = 2) -> str:
if value is None:
return "—"
if isinstance(value, bool):
return "是" if value else "否"
if isinstance(value, float):
return f"{value:.{digits}f}"
return str(value)
def _bool(value) -> str:
return "—" if value is None else ("是" if value else "否")
def _pct(value: float) -> str:
return f"{value*100:.1f}%"
def run(quick: bool = False) -> dict:
example_rows = [_run(case) for case in cases.load_examples()]
random_rows = [_run(case) for case in
cases.random_cases(12 if quick else 40)]
payload = {
"question": 1,
"methods": [m.__dict__ for m in METHODS],
"examples": example_rows,
"random": random_rows,
"aggregate_examples": _aggregate(example_rows),
"aggregate_random": _aggregate(random_rows),
}
write_json(RESULTS_DIR / "q1.json", payload)
text = _render(example_rows, payload["aggregate_examples"],
"问题一:固定示例对比")
text += "\n" + _render(random_rows, payload["aggregate_random"],
"问题一:随机交会算例对比")
write_text(RESULTS_DIR / "q1.md", text)
return payload