anhtld commited on
Commit
273ece9
·
verified ·
1 Parent(s): 6a89313

support markdown-free CTT summary

Browse files
Files changed (1) hide show
  1. scripts/summarize_ctt_runs.py +65 -10
scripts/summarize_ctt_runs.py CHANGED
@@ -27,6 +27,7 @@ COLUMNS = [
27
  "pptc_0p20",
28
  "pptc_0p40",
29
  "negative_near_0p20",
 
30
  "calibration_ece",
31
  "seeds",
32
  "ci",
@@ -38,9 +39,15 @@ def main(argv: list[str] | None = None) -> int:
38
  parser.add_argument("--run-root", type=Path, default=Path("runs"))
39
  parser.add_argument("--out-csv", type=Path, default=Path("runs/summary_ctt.csv"))
40
  parser.add_argument("--out-md", type=Path, default=Path("runs/summary_ctt.md"))
 
 
 
 
 
41
  args = parser.parse_args(argv)
42
 
43
  rows = []
 
44
  reproduce = args.run_root / "reproduce_v0" / "metrics.json"
45
  if reproduce.exists():
46
  rows.extend(_reproduce_rows(reproduce))
@@ -50,9 +57,11 @@ def main(argv: list[str] | None = None) -> int:
50
  "ctt_val_proxy_comparison",
51
  "dominance_calibrated_selector_eval",
52
  "learned_dominance_selector_eval",
 
53
  }:
54
  continue
55
  rows.append(_ctt_row(metrics_path))
 
56
  for metrics_path in sorted(args.run_root.glob("*memory*_val_proxy/metrics.json")):
57
  rows.append(_positive_memory_row(metrics_path))
58
  local_atlas = args.run_root / "local_atlas_val_proxy" / "metrics.json"
@@ -64,12 +73,30 @@ def main(argv: list[str] | None = None) -> int:
64
  utility = args.run_root / "utility_energy_smoke" / "metrics.json"
65
  if utility.exists():
66
  rows.append(_utility_row(utility))
67
- for metrics_path in sorted(args.run_root.glob("ctt_dominance*/metrics.json")):
68
- rows.append(_dominance_row(metrics_path))
69
- for metrics_path in sorted(args.run_root.glob("ctt_learned_dominance*/metrics.json")):
70
- rows.append(_dominance_row(metrics_path))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  for metrics_path in sorted(args.run_root.glob("ctt*_nonlinear_dominance*/metrics.json")):
 
 
72
  rows.append(_dominance_row(metrics_path))
 
73
 
74
  args.out_csv.parent.mkdir(parents=True, exist_ok=True)
75
  with args.out_csv.open("w", newline="") as handle:
@@ -77,8 +104,14 @@ def main(argv: list[str] | None = None) -> int:
77
  writer.writeheader()
78
  for row in rows:
79
  writer.writerow({column: row.get(column, "n/a") for column in COLUMNS})
80
- args.out_md.write_text(_markdown(rows) + "\n")
81
- print(json.dumps({"csv": str(args.out_csv), "md": str(args.out_md), "rows": len(rows)}, indent=2))
 
 
 
 
 
 
82
  return 0
83
 
84
 
@@ -113,6 +146,7 @@ def _reproduce_rows(path: Path) -> list[dict[str, str]]:
113
  "negative_near_0p20": _fmt(
114
  proxy.get("negative_near_at_0p20", proxy.get("negative_near_at_16_thr_0p2"))
115
  ),
 
116
  "calibration_ece": "n/a",
117
  "seeds": "3",
118
  "ci": "see run",
@@ -144,6 +178,7 @@ def _ctt_row(path: Path) -> dict[str, str]:
144
  "pptc_0p20": _summary_mean(summary, "pptc_at_16_thr_0p20"),
145
  "pptc_0p40": _summary_mean(summary, "pptc_at_16_thr_0p40"),
146
  "negative_near_0p20": _summary_mean(summary, "negative_near_at_16_thr_0p20"),
 
147
  "calibration_ece": "n/a",
148
  "seeds": _seed_count(path.parent),
149
  "ci": "see run",
@@ -172,6 +207,7 @@ def _positive_memory_row(path: Path) -> dict[str, str]:
172
  "pptc_0p20": _summary_mean(summary, "pptc_at_16_thr_0p20"),
173
  "pptc_0p40": _summary_mean(summary, "pptc_at_16_thr_0p40"),
174
  "negative_near_0p20": _summary_mean(summary, "negative_near_at_16_thr_0p20"),
 
175
  "calibration_ece": "n/a",
176
  "seeds": _seed_count(path.parent),
177
  "ci": "see run",
@@ -204,6 +240,7 @@ def _comparison_rows(path: Path) -> list[dict[str, str]]:
204
  "pptc_0p20": _fmt(item.get("pptc_0p20")),
205
  "pptc_0p40": _fmt(item.get("pptc_0p40")),
206
  "negative_near_0p20": _fmt(item.get("negative_near_0p20")),
 
207
  "calibration_ece": "n/a",
208
  "seeds": str(item.get("train_seeds", "unknown")),
209
  "ci": "aggregate over run means",
@@ -232,6 +269,7 @@ def _utility_row(path: Path) -> dict[str, str]:
232
  "pptc_0p20": "n/a",
233
  "pptc_0p40": "n/a",
234
  "negative_near_0p20": "n/a",
 
235
  "calibration_ece": _summary_mean(data.get("summary", {}), "pairwise_causal_calibration_ece"),
236
  "seeds": "train split",
237
  "ci": "see run",
@@ -248,6 +286,11 @@ def _dominance_row(path: Path) -> dict[str, str]:
248
  proposal_oracle = _as_float(summary.get("proposal_oracle_success"))
249
  success_support_gap = _as_float(summary.get("success_support_gap"))
250
  success_selector_gap = _as_float(summary.get("success_selector_gap"))
 
 
 
 
 
251
  seed_count = _dominance_seed_count(data)
252
  target = data.get("target")
253
  feature_set = data.get("feature_set")
@@ -285,12 +328,23 @@ def _dominance_row(path: Path) -> dict[str, str]:
285
  "pptc_0p20": "n/a",
286
  "pptc_0p40": "n/a",
287
  "negative_near_0p20": "n/a",
288
- "calibration_ece": "n/a",
 
289
  "seeds": str(seed_count),
290
  "ci": "see run",
291
  }
292
 
293
 
 
 
 
 
 
 
 
 
 
 
294
  def _dominance_method_name(path: Path, data: dict[str, Any]) -> str:
295
  if "nonlinear" in path.parent.name:
296
  target = data.get("target") or "positive_margin"
@@ -365,6 +419,7 @@ def _measured_ctt_row(path: Path, data: dict[str, Any]) -> dict[str, str]:
365
  "pptc_0p20": "n/a",
366
  "pptc_0p40": "n/a",
367
  "negative_near_0p20": "n/a",
 
368
  "calibration_ece": _fmt(ece),
369
  "seeds": str(seed_count),
370
  "ci": "see measured_metrics",
@@ -493,8 +548,8 @@ def _markdown(rows: list[dict[str, str]]) -> str:
493
  lines = [
494
  "# CTT Summary",
495
  "",
496
- "| Method | Status | Base | Selected | Proposal oracle | Hidden oracle | Utility support gap | Utility selector gap | Success support gap | Success selector gap | OutcomePTR | PPTC@0.20 | PPTC@0.40 | NegativeNear@0.20 | Calibration ECE | Run |",
497
- "| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |",
498
  ]
499
  for row in rows:
500
  lines.append(
@@ -502,7 +557,7 @@ def _markdown(rows: list[dict[str, str]]) -> str:
502
  "{proposal_oracle} | {hidden_oracle} | {support_gap} | {selector_gap} | "
503
  "{success_support_gap} | {success_selector_gap} | {outcome_ptr} | "
504
  "{pptc_0p20} | {pptc_0p40} | "
505
- "{negative_near_0p20} | {calibration_ece} | `{run_path}` |".format(**row)
506
  )
507
  lines.append("")
508
  lines.append(
 
27
  "pptc_0p20",
28
  "pptc_0p40",
29
  "negative_near_0p20",
30
+ "unsafe_execution",
31
  "calibration_ece",
32
  "seeds",
33
  "ci",
 
39
  parser.add_argument("--run-root", type=Path, default=Path("runs"))
40
  parser.add_argument("--out-csv", type=Path, default=Path("runs/summary_ctt.csv"))
41
  parser.add_argument("--out-md", type=Path, default=Path("runs/summary_ctt.md"))
42
+ parser.add_argument(
43
+ "--no-markdown-report",
44
+ action="store_true",
45
+ help="Do not write --out-md; the persistent prose summary lives in README.md.",
46
+ )
47
  args = parser.parse_args(argv)
48
 
49
  rows = []
50
+ seen_metric_paths: set[Path] = set()
51
  reproduce = args.run_root / "reproduce_v0" / "metrics.json"
52
  if reproduce.exists():
53
  rows.extend(_reproduce_rows(reproduce))
 
57
  "ctt_val_proxy_comparison",
58
  "dominance_calibrated_selector_eval",
59
  "learned_dominance_selector_eval",
60
+ "nonlinear_dominance_selector_eval",
61
  }:
62
  continue
63
  rows.append(_ctt_row(metrics_path))
64
+ seen_metric_paths.add(metrics_path)
65
  for metrics_path in sorted(args.run_root.glob("*memory*_val_proxy/metrics.json")):
66
  rows.append(_positive_memory_row(metrics_path))
67
  local_atlas = args.run_root / "local_atlas_val_proxy" / "metrics.json"
 
73
  utility = args.run_root / "utility_energy_smoke" / "metrics.json"
74
  if utility.exists():
75
  rows.append(_utility_row(utility))
76
+ for pattern in ("ctt_dominance*/metrics.json", "ctt*_dominance*/metrics.json"):
77
+ for metrics_path in sorted(args.run_root.glob(pattern)):
78
+ if metrics_path in seen_metric_paths:
79
+ continue
80
+ report_type = _report_type(metrics_path)
81
+ if report_type not in {
82
+ "dominance_calibrated_selector_eval",
83
+ "learned_dominance_selector_eval",
84
+ "nonlinear_dominance_selector_eval",
85
+ }:
86
+ continue
87
+ rows.append(_dominance_row(metrics_path))
88
+ seen_metric_paths.add(metrics_path)
89
+ for pattern in ("ctt_learned_dominance*/metrics.json", "ctt*_learned_dominance*/metrics.json"):
90
+ for metrics_path in sorted(args.run_root.glob(pattern)):
91
+ if metrics_path in seen_metric_paths:
92
+ continue
93
+ rows.append(_dominance_row(metrics_path))
94
+ seen_metric_paths.add(metrics_path)
95
  for metrics_path in sorted(args.run_root.glob("ctt*_nonlinear_dominance*/metrics.json")):
96
+ if metrics_path in seen_metric_paths:
97
+ continue
98
  rows.append(_dominance_row(metrics_path))
99
+ seen_metric_paths.add(metrics_path)
100
 
101
  args.out_csv.parent.mkdir(parents=True, exist_ok=True)
102
  with args.out_csv.open("w", newline="") as handle:
 
104
  writer.writeheader()
105
  for row in rows:
106
  writer.writerow({column: row.get(column, "n/a") for column in COLUMNS})
107
+ if args.no_markdown_report:
108
+ if args.out_md.exists():
109
+ args.out_md.unlink()
110
+ md_path: str | None = None
111
+ else:
112
+ args.out_md.write_text(_markdown(rows) + "\n")
113
+ md_path = str(args.out_md)
114
+ print(json.dumps({"csv": str(args.out_csv), "md": md_path, "rows": len(rows)}, indent=2))
115
  return 0
116
 
117
 
 
146
  "negative_near_0p20": _fmt(
147
  proxy.get("negative_near_at_0p20", proxy.get("negative_near_at_16_thr_0p2"))
148
  ),
149
+ "unsafe_execution": "n/a",
150
  "calibration_ece": "n/a",
151
  "seeds": "3",
152
  "ci": "see run",
 
178
  "pptc_0p20": _summary_mean(summary, "pptc_at_16_thr_0p20"),
179
  "pptc_0p40": _summary_mean(summary, "pptc_at_16_thr_0p40"),
180
  "negative_near_0p20": _summary_mean(summary, "negative_near_at_16_thr_0p20"),
181
+ "unsafe_execution": "n/a",
182
  "calibration_ece": "n/a",
183
  "seeds": _seed_count(path.parent),
184
  "ci": "see run",
 
207
  "pptc_0p20": _summary_mean(summary, "pptc_at_16_thr_0p20"),
208
  "pptc_0p40": _summary_mean(summary, "pptc_at_16_thr_0p40"),
209
  "negative_near_0p20": _summary_mean(summary, "negative_near_at_16_thr_0p20"),
210
+ "unsafe_execution": "n/a",
211
  "calibration_ece": "n/a",
212
  "seeds": _seed_count(path.parent),
213
  "ci": "see run",
 
240
  "pptc_0p20": _fmt(item.get("pptc_0p20")),
241
  "pptc_0p40": _fmt(item.get("pptc_0p40")),
242
  "negative_near_0p20": _fmt(item.get("negative_near_0p20")),
243
+ "unsafe_execution": "n/a",
244
  "calibration_ece": "n/a",
245
  "seeds": str(item.get("train_seeds", "unknown")),
246
  "ci": "aggregate over run means",
 
269
  "pptc_0p20": "n/a",
270
  "pptc_0p40": "n/a",
271
  "negative_near_0p20": "n/a",
272
+ "unsafe_execution": "n/a",
273
  "calibration_ece": _summary_mean(data.get("summary", {}), "pairwise_causal_calibration_ece"),
274
  "seeds": "train split",
275
  "ci": "see run",
 
286
  proposal_oracle = _as_float(summary.get("proposal_oracle_success"))
287
  success_support_gap = _as_float(summary.get("success_support_gap"))
288
  success_selector_gap = _as_float(summary.get("success_selector_gap"))
289
+ ece = _first_float(
290
+ _dominance_pairwise_ece(data, "eval"),
291
+ summary.get("pairwise_causal_calibration_ece"),
292
+ _metric_mean(metric_summary, "pairwise_causal_calibration_ece"),
293
+ )
294
  seed_count = _dominance_seed_count(data)
295
  target = data.get("target")
296
  feature_set = data.get("feature_set")
 
328
  "pptc_0p20": "n/a",
329
  "pptc_0p40": "n/a",
330
  "negative_near_0p20": "n/a",
331
+ "unsafe_execution": _fmt(summary.get("unsafe_execution_known")),
332
+ "calibration_ece": _fmt(ece),
333
  "seeds": str(seed_count),
334
  "ci": "see run",
335
  }
336
 
337
 
338
+ def _dominance_pairwise_ece(data: dict[str, Any], split: str) -> float | None:
339
+ payload = data.get("pairwise_causal_calibration", {})
340
+ if not isinstance(payload, dict):
341
+ return None
342
+ split_payload = payload.get(split, {})
343
+ if not isinstance(split_payload, dict):
344
+ return None
345
+ return _as_float(split_payload.get("ece"))
346
+
347
+
348
  def _dominance_method_name(path: Path, data: dict[str, Any]) -> str:
349
  if "nonlinear" in path.parent.name:
350
  target = data.get("target") or "positive_margin"
 
419
  "pptc_0p20": "n/a",
420
  "pptc_0p40": "n/a",
421
  "negative_near_0p20": "n/a",
422
+ "unsafe_execution": _summary_mean(summary, f"selected_unsafe_known_at_{k}"),
423
  "calibration_ece": _fmt(ece),
424
  "seeds": str(seed_count),
425
  "ci": "see measured_metrics",
 
548
  lines = [
549
  "# CTT Summary",
550
  "",
551
+ "| Method | Status | Base | Selected | Proposal oracle | Hidden oracle | Utility support gap | Utility selector gap | Success support gap | Success selector gap | OutcomePTR | PPTC@0.20 | PPTC@0.40 | NegativeNear@0.20 | Unsafe exec. | Calibration ECE | Run |",
552
+ "| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |",
553
  ]
554
  for row in rows:
555
  lines.append(
 
557
  "{proposal_oracle} | {hidden_oracle} | {support_gap} | {selector_gap} | "
558
  "{success_support_gap} | {success_selector_gap} | {outcome_ptr} | "
559
  "{pptc_0p20} | {pptc_0p40} | "
560
+ "{negative_near_0p20} | {unsafe_execution} | {calibration_ece} | `{run_path}` |".format(**row)
561
  )
562
  lines.append("")
563
  lines.append(