anhtld commited on
Commit
3bb00d1
·
verified ·
1 Parent(s): cf03209

auto-sync 2026-07-04T07:48:09Z workspace (part 4)

Browse files
workspace/scripts/build_selector_diagnostic_sweep.py CHANGED
@@ -18,6 +18,7 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
18
 
19
  DEFAULT_PATTERNS = (
20
  "runs/ctt_base_context_obs_learned_dominance_chartcompat_obs_utility_task_envclip_k16_train_to_test/metrics.json",
 
21
  "runs/ctt_base_context_obs_dominance_envclip_k16_train_to_test/metrics.json",
22
  "runs/ctt_base_context_obs_dominance_envclip_k16_train_to_test_tau0/metrics.json",
23
  "runs/ctt_dominance_utility_energy_val_to_test_seed*/metrics.json",
 
18
 
19
  DEFAULT_PATTERNS = (
20
  "runs/ctt_base_context_obs_learned_dominance_chartcompat_obs_utility_task_envclip_k16_train_to_test/metrics.json",
21
+ "runs/ctt_base_context_obs_learned_dominance_*bundle*_envclip_k16_train_to_test/metrics.json",
22
  "runs/ctt_base_context_obs_dominance_envclip_k16_train_to_test/metrics.json",
23
  "runs/ctt_base_context_obs_dominance_envclip_k16_train_to_test_tau0/metrics.json",
24
  "runs/ctt_dominance_utility_energy_val_to_test_seed*/metrics.json",
workspace/scripts/eval_learned_dominance_selector.py CHANGED
@@ -92,12 +92,37 @@ SCORE_SHAPE_NAMES = [
92
  "candidate_score_percentile",
93
  "candidate_score_top_margin",
94
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  FEATURE_SET_CHOICES = (
96
  "basic",
97
  "tangent",
98
  "context",
99
  "context_tangent",
100
  "score_context",
 
 
 
 
101
  "source_evidence",
102
  "tangent_source_evidence",
103
  "context_source_evidence",
@@ -106,8 +131,11 @@ FEATURE_SET_CHOICES = (
106
  "chart_tangent_compat",
107
  "score_chart_compat",
108
  "score_context_chart_compat",
 
 
109
  "chart_source_compat",
110
  "chart_tangent_source_compat",
 
111
  )
112
 
113
 
@@ -456,6 +484,7 @@ def _candidate_dataset(
456
  score_mean = sum(scores) / len(scores)
457
  score_std = math.sqrt(sum((score - score_mean) ** 2 for score in scores) / len(scores)) + 1.0e-6
458
  score_shape = _score_shape_matrix(scores)
 
459
  for candidate_index, score in enumerate(scores):
460
  source_chart_id = str(source_chart_ids[candidate_index]) if candidate_index < len(source_chart_ids) else ""
461
  tangent = np.asarray(
@@ -489,6 +518,7 @@ def _candidate_dataset(
489
  chart_feature_mode=selector_chart_feature_mode,
490
  ),
491
  score_shape=score_shape[candidate_index],
 
492
  num_candidates=len(scores),
493
  feature_set=feature_set,
494
  )
@@ -554,6 +584,8 @@ def _feature_names(feature_set: str) -> list[str]:
554
  names.extend(SOURCE_EVIDENCE_NAMES)
555
  if _uses_chart_compat(feature_set):
556
  names.extend(CHART_COMPAT_NAMES)
 
 
557
  if feature_set in FEATURE_SET_CHOICES:
558
  return names
559
  raise ValueError(f"unknown feature_set: {feature_set}")
@@ -574,6 +606,7 @@ def _candidate_feature(
574
  source_evidence: np.ndarray | None = None,
575
  chart_compat: np.ndarray | None = None,
576
  score_shape: np.ndarray | None = None,
 
577
  ) -> np.ndarray:
578
  tangent = np.asarray(tangent, dtype=float).reshape(-1)
579
  if tangent.size < 21:
@@ -616,6 +649,10 @@ def _candidate_feature(
616
  if chart_compat is None:
617
  chart_compat = np.zeros(len(CHART_COMPAT_NAMES), dtype=float)
618
  parts.append(np.asarray(chart_compat, dtype=float).reshape(-1))
 
 
 
 
619
  if feature_set in FEATURE_SET_CHOICES:
620
  return np.concatenate(parts)
621
  raise ValueError(f"unknown feature_set: {feature_set}")
@@ -629,6 +666,8 @@ def _uses_context(feature_set: str) -> bool:
629
  "context_tangent_source_evidence",
630
  "score_context",
631
  "score_context_chart_compat",
 
 
632
  }
633
 
634
 
@@ -637,6 +676,8 @@ def _uses_score_shape(feature_set: str) -> bool:
637
  "score_context",
638
  "score_chart_compat",
639
  "score_context_chart_compat",
 
 
640
  }
641
 
642
 
@@ -648,6 +689,7 @@ def _uses_tangent(feature_set: str) -> bool:
648
  "context_tangent_source_evidence",
649
  "chart_tangent_compat",
650
  "chart_tangent_source_compat",
 
651
  }
652
 
653
 
@@ -659,6 +701,7 @@ def _uses_source_evidence(feature_set: str) -> bool:
659
  "context_tangent_source_evidence",
660
  "chart_source_compat",
661
  "chart_tangent_source_compat",
 
662
  }
663
 
664
 
@@ -668,8 +711,23 @@ def _uses_chart_compat(feature_set: str) -> bool:
668
  "chart_tangent_compat",
669
  "score_chart_compat",
670
  "score_context_chart_compat",
 
 
671
  "chart_source_compat",
672
  "chart_tangent_source_compat",
 
 
 
 
 
 
 
 
 
 
 
 
 
673
  }
674
 
675
 
@@ -957,6 +1015,111 @@ def _score_shape_matrix(scores: list[float]) -> np.ndarray:
957
  return np.asarray(rows, dtype=float)
958
 
959
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
960
  def _context_feature(context: dict[str, Any]) -> np.ndarray:
961
  target_task = str(context.get("target_task_id", ""))
962
  source_task = str(context.get("source_task_id", ""))
 
92
  "candidate_score_percentile",
93
  "candidate_score_top_margin",
94
  ]
95
+ BUNDLE_CONSENSUS_NAMES = [
96
+ "bundle_num_candidates_log",
97
+ "bundle_neighbor_count_r020",
98
+ "bundle_neighbor_count_r040",
99
+ "bundle_neighbor_frac_r020",
100
+ "bundle_neighbor_frac_r040",
101
+ "bundle_mean_peer_rms",
102
+ "bundle_min_peer_rms",
103
+ "bundle_medoid_rms",
104
+ "bundle_is_medoid",
105
+ "bundle_peer_score_mean_r020",
106
+ "bundle_peer_score_max_r020",
107
+ "bundle_peer_score_mean_r040",
108
+ "bundle_peer_score_max_r040",
109
+ "bundle_unique_source_count_r040",
110
+ "bundle_unique_source_frac_r040",
111
+ "bundle_unique_task_count_r040",
112
+ "bundle_same_source_frac_r040",
113
+ "bundle_score_density_r040",
114
+ "bundle_rank_density_r040",
115
+ ]
116
  FEATURE_SET_CHOICES = (
117
  "basic",
118
  "tangent",
119
  "context",
120
  "context_tangent",
121
  "score_context",
122
+ "bundle_consensus",
123
+ "score_bundle_consensus",
124
+ "context_bundle_consensus",
125
+ "context_tangent_bundle_consensus",
126
  "source_evidence",
127
  "tangent_source_evidence",
128
  "context_source_evidence",
 
131
  "chart_tangent_compat",
132
  "score_chart_compat",
133
  "score_context_chart_compat",
134
+ "chart_bundle_consensus",
135
+ "score_chart_bundle_consensus",
136
  "chart_source_compat",
137
  "chart_tangent_source_compat",
138
+ "chart_source_bundle_consensus",
139
  )
140
 
141
 
 
484
  score_mean = sum(scores) / len(scores)
485
  score_std = math.sqrt(sum((score - score_mean) ** 2 for score in scores) / len(scores)) + 1.0e-6
486
  score_shape = _score_shape_matrix(scores)
487
+ bundle_consensus = _bundle_consensus_matrix(tangents, scores, source_chart_ids, source_task_ids)
488
  for candidate_index, score in enumerate(scores):
489
  source_chart_id = str(source_chart_ids[candidate_index]) if candidate_index < len(source_chart_ids) else ""
490
  tangent = np.asarray(
 
518
  chart_feature_mode=selector_chart_feature_mode,
519
  ),
520
  score_shape=score_shape[candidate_index],
521
+ bundle_consensus=bundle_consensus[candidate_index],
522
  num_candidates=len(scores),
523
  feature_set=feature_set,
524
  )
 
584
  names.extend(SOURCE_EVIDENCE_NAMES)
585
  if _uses_chart_compat(feature_set):
586
  names.extend(CHART_COMPAT_NAMES)
587
+ if _uses_bundle_consensus(feature_set):
588
+ names.extend(BUNDLE_CONSENSUS_NAMES)
589
  if feature_set in FEATURE_SET_CHOICES:
590
  return names
591
  raise ValueError(f"unknown feature_set: {feature_set}")
 
606
  source_evidence: np.ndarray | None = None,
607
  chart_compat: np.ndarray | None = None,
608
  score_shape: np.ndarray | None = None,
609
+ bundle_consensus: np.ndarray | None = None,
610
  ) -> np.ndarray:
611
  tangent = np.asarray(tangent, dtype=float).reshape(-1)
612
  if tangent.size < 21:
 
649
  if chart_compat is None:
650
  chart_compat = np.zeros(len(CHART_COMPAT_NAMES), dtype=float)
651
  parts.append(np.asarray(chart_compat, dtype=float).reshape(-1))
652
+ if _uses_bundle_consensus(feature_set):
653
+ if bundle_consensus is None:
654
+ bundle_consensus = np.zeros(len(BUNDLE_CONSENSUS_NAMES), dtype=float)
655
+ parts.append(np.asarray(bundle_consensus, dtype=float).reshape(-1))
656
  if feature_set in FEATURE_SET_CHOICES:
657
  return np.concatenate(parts)
658
  raise ValueError(f"unknown feature_set: {feature_set}")
 
666
  "context_tangent_source_evidence",
667
  "score_context",
668
  "score_context_chart_compat",
669
+ "context_bundle_consensus",
670
+ "context_tangent_bundle_consensus",
671
  }
672
 
673
 
 
676
  "score_context",
677
  "score_chart_compat",
678
  "score_context_chart_compat",
679
+ "score_bundle_consensus",
680
+ "score_chart_bundle_consensus",
681
  }
682
 
683
 
 
689
  "context_tangent_source_evidence",
690
  "chart_tangent_compat",
691
  "chart_tangent_source_compat",
692
+ "context_tangent_bundle_consensus",
693
  }
694
 
695
 
 
701
  "context_tangent_source_evidence",
702
  "chart_source_compat",
703
  "chart_tangent_source_compat",
704
+ "chart_source_bundle_consensus",
705
  }
706
 
707
 
 
711
  "chart_tangent_compat",
712
  "score_chart_compat",
713
  "score_context_chart_compat",
714
+ "chart_bundle_consensus",
715
+ "score_chart_bundle_consensus",
716
  "chart_source_compat",
717
  "chart_tangent_source_compat",
718
+ "chart_source_bundle_consensus",
719
+ }
720
+
721
+
722
+ def _uses_bundle_consensus(feature_set: str) -> bool:
723
+ return feature_set in {
724
+ "bundle_consensus",
725
+ "score_bundle_consensus",
726
+ "context_bundle_consensus",
727
+ "context_tangent_bundle_consensus",
728
+ "chart_bundle_consensus",
729
+ "score_chart_bundle_consensus",
730
+ "chart_source_bundle_consensus",
731
  }
732
 
733
 
 
1015
  return np.asarray(rows, dtype=float)
1016
 
1017
 
1018
+ def _bundle_consensus_matrix(
1019
+ tangents: Any,
1020
+ scores: list[float],
1021
+ source_chart_ids: Any,
1022
+ source_task_ids: Any,
1023
+ ) -> np.ndarray:
1024
+ """Deployment-visible CTT bundle self-consistency features.
1025
+
1026
+ These features are computed only from the generated transported tangents,
1027
+ their inference-time scores, and train-source identifiers already present
1028
+ in the candidate row. They deliberately do not inspect target positive or
1029
+ negative tangent sets, measured candidate utilities, or hidden outcomes.
1030
+ """
1031
+
1032
+ num_candidates = len(scores)
1033
+ if num_candidates == 0:
1034
+ return np.zeros((0, len(BUNDLE_CONSENSUS_NAMES)), dtype=float)
1035
+ tangent_matrix = _candidate_tangent_matrix(tangents, num_candidates)
1036
+ score_array = np.asarray(scores, dtype=float).reshape(-1)
1037
+ if score_array.size < num_candidates:
1038
+ score_array = np.pad(score_array, (0, num_candidates - score_array.size))
1039
+ score_array = score_array[:num_candidates]
1040
+ source_ids = _string_list(source_chart_ids, num_candidates)
1041
+ task_ids = _string_list(source_task_ids, num_candidates)
1042
+
1043
+ diff = tangent_matrix[:, None, :] - tangent_matrix[None, :, :]
1044
+ distances = np.sqrt(np.mean(diff * diff, axis=2))
1045
+ nonself = ~np.eye(num_candidates, dtype=bool)
1046
+ peer_denominator = max(1.0, float(num_candidates - 1))
1047
+ peer_distances = np.where(nonself, distances, np.nan)
1048
+ mean_peer = np.nanmean(peer_distances, axis=1) if num_candidates > 1 else np.zeros(num_candidates)
1049
+ min_peer = np.nanmin(peer_distances, axis=1) if num_candidates > 1 else np.zeros(num_candidates)
1050
+ mean_peer = np.nan_to_num(mean_peer, nan=0.0, posinf=0.0, neginf=0.0)
1051
+ min_peer = np.nan_to_num(min_peer, nan=0.0, posinf=0.0, neginf=0.0)
1052
+ medoid_index = int(np.argmin(mean_peer)) if num_candidates else 0
1053
+ medoid_distances = distances[:, medoid_index] if num_candidates else np.zeros(0)
1054
+
1055
+ rows: list[list[float]] = []
1056
+ for index in range(num_candidates):
1057
+ peers_020 = [j for j in range(num_candidates) if j != index and distances[index, j] <= 0.20]
1058
+ peers_040 = [j for j in range(num_candidates) if j != index and distances[index, j] <= 0.40]
1059
+ group_040 = [index, *peers_040]
1060
+ unique_sources = {source_ids[j] for j in group_040 if source_ids[j]}
1061
+ unique_tasks = {task_ids[j] for j in group_040 if task_ids[j]}
1062
+ same_source_peers = [
1063
+ j for j in peers_040 if source_ids[index] and source_ids[j] == source_ids[index]
1064
+ ]
1065
+ score_mean_020, score_max_020 = _score_stats(score_array, peers_020)
1066
+ score_mean_040, score_max_040 = _score_stats(score_array, peers_040)
1067
+ density_weights = np.exp(-np.clip(distances[index], 0.0, 10.0) / 0.40)
1068
+ density_weights[index] = 0.0
1069
+ score_density = float(np.dot(density_weights, score_array) / max(1.0e-12, density_weights.sum()))
1070
+ rank_density = float(sum(1.0 for j in peers_040 if score_array[j] >= score_array[index]))
1071
+ rows.append(
1072
+ [
1073
+ math.log1p(num_candidates),
1074
+ float(len(peers_020)),
1075
+ float(len(peers_040)),
1076
+ float(len(peers_020)) / peer_denominator,
1077
+ float(len(peers_040)) / peer_denominator,
1078
+ float(mean_peer[index]),
1079
+ float(min_peer[index]),
1080
+ float(medoid_distances[index]),
1081
+ float(index == medoid_index),
1082
+ score_mean_020,
1083
+ score_max_020,
1084
+ score_mean_040,
1085
+ score_max_040,
1086
+ float(len(unique_sources)),
1087
+ float(len(unique_sources)) / max(1.0, float(len(group_040))),
1088
+ float(len(unique_tasks)),
1089
+ float(len(same_source_peers)) / max(1.0, float(len(peers_040))),
1090
+ score_density,
1091
+ rank_density / max(1.0, float(len(peers_040))),
1092
+ ]
1093
+ )
1094
+ output = np.asarray(rows, dtype=float)
1095
+ return np.nan_to_num(output, nan=0.0, posinf=0.0, neginf=0.0)
1096
+
1097
+
1098
+ def _candidate_tangent_matrix(tangents: Any, num_candidates: int) -> np.ndarray:
1099
+ rows: list[np.ndarray] = []
1100
+ tangent_list = list(tangents or [])
1101
+ for index in range(num_candidates):
1102
+ tangent = np.asarray(tangent_list[index] if index < len(tangent_list) else [], dtype=float).reshape(-1)
1103
+ if tangent.size < 21:
1104
+ tangent = np.pad(tangent, (0, 21 - tangent.size))
1105
+ elif tangent.size > 21:
1106
+ tangent = tangent[:21]
1107
+ rows.append(tangent.astype(float, copy=False))
1108
+ return np.stack(rows, axis=0)
1109
+
1110
+
1111
+ def _string_list(values: Any, length: int) -> list[str]:
1112
+ raw = list(values or [])
1113
+ return [str(raw[index]) if index < len(raw) else "" for index in range(length)]
1114
+
1115
+
1116
+ def _score_stats(scores: np.ndarray, indices: list[int]) -> tuple[float, float]:
1117
+ if not indices:
1118
+ return 0.0, 0.0
1119
+ values = scores[indices]
1120
+ return float(values.mean()), float(values.max())
1121
+
1122
+
1123
  def _context_feature(context: dict[str, Any]) -> np.ndarray:
1124
  target_task = str(context.get("target_task_id", ""))
1125
  source_task = str(context.get("source_task_id", ""))