auto-sync 2026-07-04T00:30:01Z workspace (part 6)
Browse files
workspace/scripts/eval_learned_dominance_selector.py
CHANGED
|
@@ -110,6 +110,15 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 110 |
"candidate success to prioritize the lexicographic success/progress utility."
|
| 111 |
),
|
| 112 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
parser.add_argument("--bootstrap-samples", type=int, default=1000)
|
| 114 |
args = parser.parse_args(argv)
|
| 115 |
|
|
@@ -158,7 +167,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 158 |
target=args.target,
|
| 159 |
source_evidence=source_evidence,
|
| 160 |
)
|
| 161 |
-
best = _fit_select_ridge(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
eval_cases = _evaluate_dataset(eval_dataset, best["weights"], best["mean"], best["std"], tau=best["tau"])
|
| 163 |
calibration_cases = _evaluate_dataset(
|
| 164 |
calibration_dataset,
|
|
@@ -192,6 +205,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 192 |
"k": args.k,
|
| 193 |
"feature_set": args.feature_set,
|
| 194 |
"target": args.target,
|
|
|
|
| 195 |
"chart_feature_mode": chart_feature_mode,
|
| 196 |
"feature_names": _feature_names(args.feature_set),
|
| 197 |
"ridge_lambdas": lambdas,
|
|
@@ -235,7 +249,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 235 |
(out_dir / "train.log").write_text(
|
| 236 |
"trained ridge dominance calibrator on calibration measured rows only\n"
|
| 237 |
f"selected_lambda={best['lambda']}\n"
|
| 238 |
-
f"tau={best['tau']
|
| 239 |
f"calibration_input={args.calibration_input}\n"
|
| 240 |
)
|
| 241 |
(out_dir / "eval.log").write_text(
|
|
@@ -609,7 +623,12 @@ def _target_value(
|
|
| 609 |
raise ValueError(f"unknown target: {target}")
|
| 610 |
|
| 611 |
|
| 612 |
-
def _fit_select_ridge(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 613 |
samples = dataset["samples"]
|
| 614 |
if not samples:
|
| 615 |
raise ValueError("cannot fit learned dominance selector without candidates")
|
|
@@ -627,7 +646,11 @@ def _fit_select_ridge(dataset: dict[str, Any], *, lambdas: list[float]) -> dict[
|
|
| 627 |
penalty[0, 0] = 0.0
|
| 628 |
weights = np.linalg.pinv(x_norm.T @ x_norm + penalty) @ (x_norm.T @ y)
|
| 629 |
predictions = x_norm @ weights
|
| 630 |
-
tau, selection =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 631 |
key = (
|
| 632 |
float(selection["selected_success"]),
|
| 633 |
float(selection["selected_utility"]),
|
|
@@ -648,6 +671,27 @@ def _fit_select_ridge(dataset: dict[str, Any], *, lambdas: list[float]) -> dict[
|
|
| 648 |
return best
|
| 649 |
|
| 650 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 651 |
def _choose_tau(dataset: dict[str, Any], predictions: np.ndarray) -> tuple[float, dict[str, float | None]]:
|
| 652 |
candidates = sorted(float(value) for value in predictions)
|
| 653 |
thresholds = [min(candidates) - 1.0, *candidates, max(candidates) + 1.0]
|
|
@@ -676,7 +720,7 @@ def _evaluate_dataset(
|
|
| 676 |
mean: np.ndarray,
|
| 677 |
std: np.ndarray,
|
| 678 |
*,
|
| 679 |
-
tau: float,
|
| 680 |
) -> list[dict[str, Any]]:
|
| 681 |
x = np.stack([sample["feature"] for sample in dataset["samples"]], axis=0)
|
| 682 |
x_norm = (x - mean) / std
|
|
@@ -684,14 +728,20 @@ def _evaluate_dataset(
|
|
| 684 |
return _evaluate_predictions(dataset, x_norm @ weights, tau=tau)
|
| 685 |
|
| 686 |
|
| 687 |
-
def _evaluate_predictions(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 688 |
samples = dataset["samples"]
|
| 689 |
rows: list[dict[str, Any]] = []
|
| 690 |
for row_index, sample_indices in sorted(dataset["by_row"].items()):
|
| 691 |
best_index = max(sample_indices, key=lambda index: float(predictions[index]))
|
| 692 |
sample = samples[best_index]
|
| 693 |
predicted_margin = float(predictions[best_index])
|
| 694 |
-
|
|
|
|
| 695 |
selected_utility = (
|
| 696 |
float(sample["candidate_utility"]) if execute else float(sample["base_utility"])
|
| 697 |
)
|
|
@@ -708,7 +758,7 @@ def _evaluate_predictions(dataset: dict[str, Any], predictions: np.ndarray, *, t
|
|
| 708 |
"train_seed": sample["train_seed"],
|
| 709 |
"selected_candidate_index": int(sample["candidate_index"]),
|
| 710 |
"predicted_margin": predicted_margin,
|
| 711 |
-
"tau":
|
| 712 |
"execute_generated": float(execute),
|
| 713 |
"coverage": float(execute),
|
| 714 |
"fallback_rate": float(not execute),
|
|
@@ -736,6 +786,56 @@ def _evaluate_predictions(dataset: dict[str, Any], predictions: np.ndarray, *, t
|
|
| 736 |
return rows
|
| 737 |
|
| 738 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 739 |
def _simple_summary(rows: list[dict[str, Any]]) -> dict[str, float | None]:
|
| 740 |
keys = [
|
| 741 |
"base_success",
|
|
@@ -819,7 +919,8 @@ def _report(metrics: dict[str, Any]) -> str:
|
|
| 819 |
f"Calibration rows: `{metrics['num_calibration_rows']}`",
|
| 820 |
f"Eval rows: `{metrics['num_eval_rows']}`",
|
| 821 |
f"Selected ridge lambda: `{metrics['selected_lambda']}`",
|
| 822 |
-
f"Tau: `{metrics['tau']
|
|
|
|
| 823 |
f"Feature set: `{metrics['feature_set']}`",
|
| 824 |
f"Target: `{metrics['target']}`",
|
| 825 |
"",
|
|
@@ -899,6 +1000,14 @@ def _fmt(value: Any) -> str:
|
|
| 899 |
return f"{float(value):.4f}"
|
| 900 |
|
| 901 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 902 |
def _run(command: list[str]) -> str:
|
| 903 |
try:
|
| 904 |
return subprocess.check_output(command, cwd=PROJECT_ROOT, text=True).strip()
|
|
|
|
| 110 |
"candidate success to prioritize the lexicographic success/progress utility."
|
| 111 |
),
|
| 112 |
)
|
| 113 |
+
parser.add_argument(
|
| 114 |
+
"--threshold-scope",
|
| 115 |
+
choices=("global", "task"),
|
| 116 |
+
default="global",
|
| 117 |
+
help=(
|
| 118 |
+
"Calibrate one global execute/fallback threshold or a Mondrian "
|
| 119 |
+
"threshold per visible task_id bucket using calibration rows only."
|
| 120 |
+
),
|
| 121 |
+
)
|
| 122 |
parser.add_argument("--bootstrap-samples", type=int, default=1000)
|
| 123 |
args = parser.parse_args(argv)
|
| 124 |
|
|
|
|
| 167 |
target=args.target,
|
| 168 |
source_evidence=source_evidence,
|
| 169 |
)
|
| 170 |
+
best = _fit_select_ridge(
|
| 171 |
+
calibration_dataset,
|
| 172 |
+
lambdas=lambdas,
|
| 173 |
+
threshold_scope=args.threshold_scope,
|
| 174 |
+
)
|
| 175 |
eval_cases = _evaluate_dataset(eval_dataset, best["weights"], best["mean"], best["std"], tau=best["tau"])
|
| 176 |
calibration_cases = _evaluate_dataset(
|
| 177 |
calibration_dataset,
|
|
|
|
| 205 |
"k": args.k,
|
| 206 |
"feature_set": args.feature_set,
|
| 207 |
"target": args.target,
|
| 208 |
+
"threshold_scope": args.threshold_scope,
|
| 209 |
"chart_feature_mode": chart_feature_mode,
|
| 210 |
"feature_names": _feature_names(args.feature_set),
|
| 211 |
"ridge_lambdas": lambdas,
|
|
|
|
| 249 |
(out_dir / "train.log").write_text(
|
| 250 |
"trained ridge dominance calibrator on calibration measured rows only\n"
|
| 251 |
f"selected_lambda={best['lambda']}\n"
|
| 252 |
+
f"tau={_format_tau(best['tau'])}\n"
|
| 253 |
f"calibration_input={args.calibration_input}\n"
|
| 254 |
)
|
| 255 |
(out_dir / "eval.log").write_text(
|
|
|
|
| 623 |
raise ValueError(f"unknown target: {target}")
|
| 624 |
|
| 625 |
|
| 626 |
+
def _fit_select_ridge(
|
| 627 |
+
dataset: dict[str, Any],
|
| 628 |
+
*,
|
| 629 |
+
lambdas: list[float],
|
| 630 |
+
threshold_scope: str = "global",
|
| 631 |
+
) -> dict[str, Any]:
|
| 632 |
samples = dataset["samples"]
|
| 633 |
if not samples:
|
| 634 |
raise ValueError("cannot fit learned dominance selector without candidates")
|
|
|
|
| 646 |
penalty[0, 0] = 0.0
|
| 647 |
weights = np.linalg.pinv(x_norm.T @ x_norm + penalty) @ (x_norm.T @ y)
|
| 648 |
predictions = x_norm @ weights
|
| 649 |
+
tau, selection = _choose_thresholds(
|
| 650 |
+
dataset,
|
| 651 |
+
predictions,
|
| 652 |
+
threshold_scope=threshold_scope,
|
| 653 |
+
)
|
| 654 |
key = (
|
| 655 |
float(selection["selected_success"]),
|
| 656 |
float(selection["selected_utility"]),
|
|
|
|
| 671 |
return best
|
| 672 |
|
| 673 |
|
| 674 |
+
def _choose_thresholds(
|
| 675 |
+
dataset: dict[str, Any],
|
| 676 |
+
predictions: np.ndarray,
|
| 677 |
+
*,
|
| 678 |
+
threshold_scope: str,
|
| 679 |
+
) -> tuple[float | dict[str, float], dict[str, float | None]]:
|
| 680 |
+
if threshold_scope == "global":
|
| 681 |
+
return _choose_tau(dataset, predictions)
|
| 682 |
+
if threshold_scope != "task":
|
| 683 |
+
raise ValueError(f"unknown threshold_scope: {threshold_scope}")
|
| 684 |
+
global_tau, _global_summary = _choose_tau(dataset, predictions)
|
| 685 |
+
task_taus: dict[str, float] = {"__global__": float(global_tau)}
|
| 686 |
+
for task_id, row_indices in _rows_by_task(dataset).items():
|
| 687 |
+
subset = _subset_dataset_rows(dataset, row_indices)
|
| 688 |
+
subset_predictions = _predictions_for_subset(dataset, predictions, subset)
|
| 689 |
+
task_tau, _task_summary = _choose_tau(subset, subset_predictions)
|
| 690 |
+
task_taus[task_id] = float(task_tau)
|
| 691 |
+
cases = _evaluate_predictions(dataset, predictions, tau=task_taus)
|
| 692 |
+
return task_taus, _simple_summary(cases)
|
| 693 |
+
|
| 694 |
+
|
| 695 |
def _choose_tau(dataset: dict[str, Any], predictions: np.ndarray) -> tuple[float, dict[str, float | None]]:
|
| 696 |
candidates = sorted(float(value) for value in predictions)
|
| 697 |
thresholds = [min(candidates) - 1.0, *candidates, max(candidates) + 1.0]
|
|
|
|
| 720 |
mean: np.ndarray,
|
| 721 |
std: np.ndarray,
|
| 722 |
*,
|
| 723 |
+
tau: float | dict[str, float],
|
| 724 |
) -> list[dict[str, Any]]:
|
| 725 |
x = np.stack([sample["feature"] for sample in dataset["samples"]], axis=0)
|
| 726 |
x_norm = (x - mean) / std
|
|
|
|
| 728 |
return _evaluate_predictions(dataset, x_norm @ weights, tau=tau)
|
| 729 |
|
| 730 |
|
| 731 |
+
def _evaluate_predictions(
|
| 732 |
+
dataset: dict[str, Any],
|
| 733 |
+
predictions: np.ndarray,
|
| 734 |
+
*,
|
| 735 |
+
tau: float | dict[str, float],
|
| 736 |
+
) -> list[dict[str, Any]]:
|
| 737 |
samples = dataset["samples"]
|
| 738 |
rows: list[dict[str, Any]] = []
|
| 739 |
for row_index, sample_indices in sorted(dataset["by_row"].items()):
|
| 740 |
best_index = max(sample_indices, key=lambda index: float(predictions[index]))
|
| 741 |
sample = samples[best_index]
|
| 742 |
predicted_margin = float(predictions[best_index])
|
| 743 |
+
row_tau = _tau_for_sample(sample, tau)
|
| 744 |
+
execute = predicted_margin > row_tau
|
| 745 |
selected_utility = (
|
| 746 |
float(sample["candidate_utility"]) if execute else float(sample["base_utility"])
|
| 747 |
)
|
|
|
|
| 758 |
"train_seed": sample["train_seed"],
|
| 759 |
"selected_candidate_index": int(sample["candidate_index"]),
|
| 760 |
"predicted_margin": predicted_margin,
|
| 761 |
+
"tau": row_tau,
|
| 762 |
"execute_generated": float(execute),
|
| 763 |
"coverage": float(execute),
|
| 764 |
"fallback_rate": float(not execute),
|
|
|
|
| 786 |
return rows
|
| 787 |
|
| 788 |
|
| 789 |
+
def _tau_for_sample(sample: dict[str, Any], tau: float | dict[str, float]) -> float:
|
| 790 |
+
if isinstance(tau, dict):
|
| 791 |
+
return float(tau.get(str(sample.get("task_id", "")), tau.get("__global__", 0.0)))
|
| 792 |
+
return float(tau)
|
| 793 |
+
|
| 794 |
+
|
| 795 |
+
def _rows_by_task(dataset: dict[str, Any]) -> dict[str, list[int]]:
|
| 796 |
+
grouped: dict[str, list[int]] = defaultdict(list)
|
| 797 |
+
for row_index, sample_indices in dataset["by_row"].items():
|
| 798 |
+
if not sample_indices:
|
| 799 |
+
continue
|
| 800 |
+
task_id = str(dataset["samples"][sample_indices[0]].get("task_id", "unknown"))
|
| 801 |
+
grouped[task_id].append(int(row_index))
|
| 802 |
+
return grouped
|
| 803 |
+
|
| 804 |
+
|
| 805 |
+
def _subset_dataset_rows(dataset: dict[str, Any], row_indices: list[int]) -> dict[str, Any]:
|
| 806 |
+
wanted = set(int(row) for row in row_indices)
|
| 807 |
+
old_to_new_sample: dict[int, int] = {}
|
| 808 |
+
samples: list[dict[str, Any]] = []
|
| 809 |
+
by_row: dict[int, list[int]] = {}
|
| 810 |
+
for old_row in sorted(wanted):
|
| 811 |
+
if old_row not in dataset["by_row"]:
|
| 812 |
+
continue
|
| 813 |
+
new_row = len(by_row)
|
| 814 |
+
by_row[new_row] = []
|
| 815 |
+
for old_sample_index in dataset["by_row"][old_row]:
|
| 816 |
+
old_to_new_sample[old_sample_index] = len(samples)
|
| 817 |
+
sample = dict(dataset["samples"][old_sample_index])
|
| 818 |
+
sample["row_index"] = new_row
|
| 819 |
+
by_row[new_row].append(len(samples))
|
| 820 |
+
samples.append(sample)
|
| 821 |
+
return {
|
| 822 |
+
"samples": samples,
|
| 823 |
+
"by_row": by_row,
|
| 824 |
+
"num_rows": len(by_row),
|
| 825 |
+
"_old_to_new_sample": old_to_new_sample,
|
| 826 |
+
}
|
| 827 |
+
|
| 828 |
+
|
| 829 |
+
def _predictions_for_subset(
|
| 830 |
+
dataset: dict[str, Any],
|
| 831 |
+
predictions: np.ndarray,
|
| 832 |
+
subset: dict[str, Any],
|
| 833 |
+
) -> np.ndarray:
|
| 834 |
+
old_to_new = subset.get("_old_to_new_sample", {})
|
| 835 |
+
ordered_old_indices = sorted(old_to_new, key=lambda old: old_to_new[old])
|
| 836 |
+
return np.asarray([float(predictions[old]) for old in ordered_old_indices], dtype=float)
|
| 837 |
+
|
| 838 |
+
|
| 839 |
def _simple_summary(rows: list[dict[str, Any]]) -> dict[str, float | None]:
|
| 840 |
keys = [
|
| 841 |
"base_success",
|
|
|
|
| 919 |
f"Calibration rows: `{metrics['num_calibration_rows']}`",
|
| 920 |
f"Eval rows: `{metrics['num_eval_rows']}`",
|
| 921 |
f"Selected ridge lambda: `{metrics['selected_lambda']}`",
|
| 922 |
+
f"Tau: `{_format_tau(metrics['tau'])}`",
|
| 923 |
+
f"Threshold scope: `{metrics.get('threshold_scope', 'global')}`",
|
| 924 |
f"Feature set: `{metrics['feature_set']}`",
|
| 925 |
f"Target: `{metrics['target']}`",
|
| 926 |
"",
|
|
|
|
| 1000 |
return f"{float(value):.4f}"
|
| 1001 |
|
| 1002 |
|
| 1003 |
+
def _format_tau(value: Any) -> str:
|
| 1004 |
+
if isinstance(value, dict):
|
| 1005 |
+
return json.dumps({key: round(float(val), 6) for key, val in sorted(value.items())})
|
| 1006 |
+
if isinstance(value, (int, float)) and math.isfinite(float(value)):
|
| 1007 |
+
return f"{float(value):.6f}"
|
| 1008 |
+
return str(value)
|
| 1009 |
+
|
| 1010 |
+
|
| 1011 |
def _run(command: list[str]) -> str:
|
| 1012 |
try:
|
| 1013 |
return subprocess.check_output(command, cwd=PROJECT_ROOT, text=True).strip()
|
workspace/scripts/summarize_ctt_runs.py
CHANGED
|
@@ -41,6 +41,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 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))
|
|
@@ -53,6 +54,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 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"
|
|
@@ -65,11 +67,21 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 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 |
-
|
| 70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|
|
|
|
| 41 |
args = parser.parse_args(argv)
|
| 42 |
|
| 43 |
rows = []
|
| 44 |
+
seen_metric_paths: set[Path] = set()
|
| 45 |
reproduce = args.run_root / "reproduce_v0" / "metrics.json"
|
| 46 |
if reproduce.exists():
|
| 47 |
rows.extend(_reproduce_rows(reproduce))
|
|
|
|
| 54 |
}:
|
| 55 |
continue
|
| 56 |
rows.append(_ctt_row(metrics_path))
|
| 57 |
+
seen_metric_paths.add(metrics_path)
|
| 58 |
for metrics_path in sorted(args.run_root.glob("*memory*_val_proxy/metrics.json")):
|
| 59 |
rows.append(_positive_memory_row(metrics_path))
|
| 60 |
local_atlas = args.run_root / "local_atlas_val_proxy" / "metrics.json"
|
|
|
|
| 67 |
if utility.exists():
|
| 68 |
rows.append(_utility_row(utility))
|
| 69 |
for metrics_path in sorted(args.run_root.glob("ctt_dominance*/metrics.json")):
|
| 70 |
+
if metrics_path in seen_metric_paths:
|
| 71 |
+
continue
|
| 72 |
rows.append(_dominance_row(metrics_path))
|
| 73 |
+
seen_metric_paths.add(metrics_path)
|
| 74 |
+
for pattern in ("ctt_learned_dominance*/metrics.json", "ctt*_learned_dominance*/metrics.json"):
|
| 75 |
+
for metrics_path in sorted(args.run_root.glob(pattern)):
|
| 76 |
+
if metrics_path in seen_metric_paths:
|
| 77 |
+
continue
|
| 78 |
+
rows.append(_dominance_row(metrics_path))
|
| 79 |
+
seen_metric_paths.add(metrics_path)
|
| 80 |
for metrics_path in sorted(args.run_root.glob("ctt*_nonlinear_dominance*/metrics.json")):
|
| 81 |
+
if metrics_path in seen_metric_paths:
|
| 82 |
+
continue
|
| 83 |
rows.append(_dominance_row(metrics_path))
|
| 84 |
+
seen_metric_paths.add(metrics_path)
|
| 85 |
|
| 86 |
args.out_csv.parent.mkdir(parents=True, exist_ok=True)
|
| 87 |
with args.out_csv.open("w", newline="") as handle:
|