baseline
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user