graph-attention-engine 0.7.25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gae/__init__.py +367 -0
- gae/ablation.py +203 -0
- gae/batch_pipeline.py +404 -0
- gae/bootstrap.py +311 -0
- gae/calibration.py +874 -0
- gae/contracts.py +217 -0
- gae/convergence.py +1313 -0
- gae/covariance.py +277 -0
- gae/dk_estimator.py +272 -0
- gae/enrichment_advisor.py +80 -0
- gae/evaluation.py +304 -0
- gae/events.py +121 -0
- gae/evolution.py +557 -0
- gae/factors.py +129 -0
- gae/judgment.py +227 -0
- gae/kernel_selector.py +492 -0
- gae/kernels.py +345 -0
- gae/learning.py +689 -0
- gae/novelty.py +143 -0
- gae/oracle.py +245 -0
- gae/primitives.py +161 -0
- gae/profile_scorer.py +1345 -0
- gae/referral.py +345 -0
- gae/scoring.py +210 -0
- gae/shrinkage.py +81 -0
- gae/snr.py +313 -0
- gae/store.py +200 -0
- gae/synthetic.py +380 -0
- gae/two_phase.py +94 -0
- graph_attention_engine-0.7.25.dist-info/METADATA +214 -0
- graph_attention_engine-0.7.25.dist-info/RECORD +34 -0
- graph_attention_engine-0.7.25.dist-info/WHEEL +5 -0
- graph_attention_engine-0.7.25.dist-info/licenses/LICENSE +179 -0
- graph_attention_engine-0.7.25.dist-info/top_level.txt +1 -0
gae/__init__.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph Attention Engine (GAE) v0.7.25
|
|
3
|
+
Public API surface.
|
|
4
|
+
|
|
5
|
+
Core scoring:
|
|
6
|
+
ProfileScorer, ScoringResult, KernelType, build_profile_scorer
|
|
7
|
+
|
|
8
|
+
Oracle:
|
|
9
|
+
OracleProvider, GTAlignedOracle, BernoulliOracle, OracleResult
|
|
10
|
+
|
|
11
|
+
Evaluation:
|
|
12
|
+
EvaluationScenario, EvaluationReport, compute_ece, run_evaluation
|
|
13
|
+
|
|
14
|
+
Judgment:
|
|
15
|
+
JudgmentResult, compute_judgment, CONFIDENCE_HIGH, CONFIDENCE_MEDIUM
|
|
16
|
+
|
|
17
|
+
Ablation:
|
|
18
|
+
AblationResult, AblationReport, run_ablation
|
|
19
|
+
|
|
20
|
+
Calibration:
|
|
21
|
+
CalibrationProfile, soc_calibration_profile, s2p_calibration_profile
|
|
22
|
+
|
|
23
|
+
Primitives (Tier 1):
|
|
24
|
+
scaled_dot_product_attention, softmax
|
|
25
|
+
|
|
26
|
+
Learning:
|
|
27
|
+
LearningState, DimensionMetadata, PendingValidation, WeightUpdate,
|
|
28
|
+
ALPHA, EPSILON, LAMBDA_NEG, W_CLAMP
|
|
29
|
+
|
|
30
|
+
Convergence:
|
|
31
|
+
get_convergence_metrics
|
|
32
|
+
|
|
33
|
+
Infrastructure:
|
|
34
|
+
FactorComputedEvent, WeightsUpdatedEvent, ConvergenceEvent,
|
|
35
|
+
PropertySpec, EmbeddingContract, SchemaContract,
|
|
36
|
+
FactorComputer, assemble_factor_vector,
|
|
37
|
+
save_state, load_state
|
|
38
|
+
|
|
39
|
+
Kernels:
|
|
40
|
+
L2Kernel, DiagonalKernel, CovarianceEstimator, KernelSelector
|
|
41
|
+
|
|
42
|
+
Referral:
|
|
43
|
+
ReferralEngine, ReferralRule, ReferralDecision, ReferralReason, OverrideDetector
|
|
44
|
+
|
|
45
|
+
Deprecated (TD-029 — remove in a future release):
|
|
46
|
+
score_entity, score_alert, score_with_profile, ProfileScoringResult
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
from __future__ import annotations
|
|
50
|
+
|
|
51
|
+
__version__ = "0.7.25"
|
|
52
|
+
|
|
53
|
+
# ── Core Scoring ─────────────────────────────────────────────────────
|
|
54
|
+
from gae.dk_estimator import DKEstimator, CoordinateDescentEstimator
|
|
55
|
+
from gae.shrinkage import (
|
|
56
|
+
ShrinkageSchedule,
|
|
57
|
+
FixedAlpha,
|
|
58
|
+
LinearRampAlpha,
|
|
59
|
+
compute_effective_weights,
|
|
60
|
+
)
|
|
61
|
+
from gae.kernels import L2Kernel, DiagonalKernel
|
|
62
|
+
from gae.covariance import CovarianceEstimator
|
|
63
|
+
from gae.kernel_selector import KernelSelector, KernelRecommendation
|
|
64
|
+
from gae.novelty import NoveltyTracker, NearestNeighborNovelty
|
|
65
|
+
from gae.batch_pipeline import (
|
|
66
|
+
BatchCompositionPolicy,
|
|
67
|
+
NoveltyThresholdPolicy,
|
|
68
|
+
FixedIntervalPolicy,
|
|
69
|
+
PromotionGate,
|
|
70
|
+
DefaultPromotionGate,
|
|
71
|
+
GateVerdict,
|
|
72
|
+
BatchRecord,
|
|
73
|
+
BatchHistory,
|
|
74
|
+
)
|
|
75
|
+
from gae.referral import (
|
|
76
|
+
ReferralEngine,
|
|
77
|
+
ReferralRule,
|
|
78
|
+
ReferralDecision,
|
|
79
|
+
ReferralReason,
|
|
80
|
+
OverrideDetector,
|
|
81
|
+
)
|
|
82
|
+
from gae.profile_scorer import (
|
|
83
|
+
CentroidUpdate,
|
|
84
|
+
LearningStrategy,
|
|
85
|
+
ProfileScorer,
|
|
86
|
+
ScoringResult,
|
|
87
|
+
KernelType,
|
|
88
|
+
build_profile_scorer,
|
|
89
|
+
)
|
|
90
|
+
# Backward-compatible alias — ProfileScoringResult was the v4.x name
|
|
91
|
+
ProfileScoringResult = ScoringResult
|
|
92
|
+
|
|
93
|
+
# ── Oracle ───────────────────────────────────────────────────────────
|
|
94
|
+
from gae.oracle import (
|
|
95
|
+
OracleProvider,
|
|
96
|
+
OracleResult,
|
|
97
|
+
GTAlignedOracle,
|
|
98
|
+
BernoulliOracle,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# ── Evaluation ───────────────────────────────────────────────────────
|
|
102
|
+
from gae.evaluation import (
|
|
103
|
+
EvaluationScenario,
|
|
104
|
+
EvaluationReport,
|
|
105
|
+
compute_ece,
|
|
106
|
+
run_evaluation,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# ── Judgment ─────────────────────────────────────────────────────────
|
|
110
|
+
from gae.judgment import (
|
|
111
|
+
JudgmentResult,
|
|
112
|
+
compute_judgment,
|
|
113
|
+
CONFIDENCE_HIGH,
|
|
114
|
+
CONFIDENCE_MEDIUM,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# ── Ablation ─────────────────────────────────────────────────────────
|
|
118
|
+
from gae.ablation import (
|
|
119
|
+
AblationResult,
|
|
120
|
+
AblationReport,
|
|
121
|
+
run_ablation,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# ── Bootstrap ────────────────────────────────────────────────────────
|
|
125
|
+
from gae.bootstrap import (
|
|
126
|
+
BootstrapResult,
|
|
127
|
+
bootstrap_calibration,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# ── Calibration ──────────────────────────────────────────────────────
|
|
131
|
+
from gae.calibration import (
|
|
132
|
+
CalibrationProfile,
|
|
133
|
+
soc_calibration_profile,
|
|
134
|
+
s2p_calibration_profile,
|
|
135
|
+
# Conservation law primitives
|
|
136
|
+
ConservationCheck,
|
|
137
|
+
check_conservation,
|
|
138
|
+
compute_theta_min,
|
|
139
|
+
conservation_status,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# ── Primitives (Tier 1, Eq. 1) ───────────────────────────────────────
|
|
143
|
+
from gae.primitives import scaled_dot_product_attention, softmax
|
|
144
|
+
|
|
145
|
+
# ── Learning (Eq. 4b / 4c) ───────────────────────────────────────────
|
|
146
|
+
from gae.learning import (
|
|
147
|
+
ALPHA,
|
|
148
|
+
EPSILON,
|
|
149
|
+
LAMBDA_NEG,
|
|
150
|
+
W_CLAMP,
|
|
151
|
+
DimensionMetadata,
|
|
152
|
+
LearningState,
|
|
153
|
+
PendingValidation,
|
|
154
|
+
WeightUpdate,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# ── Convergence ──────────────────────────────────────────────────────
|
|
158
|
+
from gae.convergence import get_convergence_metrics
|
|
159
|
+
from gae.convergence import (
|
|
160
|
+
centroid_distance_to_canonical,
|
|
161
|
+
gamma_threshold,
|
|
162
|
+
phase2_effective_threshold,
|
|
163
|
+
ConvergenceTrace,
|
|
164
|
+
compute_reconvergence_ratio,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# ── Monitoring (observability only — no gating side-effects) ─────────
|
|
168
|
+
from gae.convergence import (
|
|
169
|
+
ConservationMonitor,
|
|
170
|
+
OLSMonitor,
|
|
171
|
+
VarQMonitor,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# ── Oracle separation / EXP-G1 experiment framework ──────────────────
|
|
175
|
+
from gae.synthetic import (
|
|
176
|
+
FactorVectorSample,
|
|
177
|
+
FactorVectorSampler,
|
|
178
|
+
CanonicalCentroid,
|
|
179
|
+
OracleSeparationExperiment,
|
|
180
|
+
GammaResult,
|
|
181
|
+
Phase1Result,
|
|
182
|
+
Phase2Result,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# ── Infrastructure — events, contracts, factors ──────────────────────
|
|
186
|
+
from gae.events import (
|
|
187
|
+
FactorComputedEvent,
|
|
188
|
+
WeightsUpdatedEvent,
|
|
189
|
+
ConvergenceEvent,
|
|
190
|
+
)
|
|
191
|
+
from gae.contracts import (
|
|
192
|
+
PropertySpec,
|
|
193
|
+
EmbeddingContract,
|
|
194
|
+
SchemaContract,
|
|
195
|
+
)
|
|
196
|
+
from gae.factors import FactorComputer, assemble_factor_vector
|
|
197
|
+
|
|
198
|
+
# ── Persistence ──────────────────────────────────────────────────────
|
|
199
|
+
from gae.store import save_state, load_state
|
|
200
|
+
|
|
201
|
+
# ── Evolution ledger (domain-agnostic variant lifecycle tracking) ────
|
|
202
|
+
from gae.evolution import (
|
|
203
|
+
VARIANT_CREATED,
|
|
204
|
+
SHADOW_STARTED,
|
|
205
|
+
SHADOW_RESULT,
|
|
206
|
+
PROMOTION_APPROVED,
|
|
207
|
+
PROMOTION_REJECTED,
|
|
208
|
+
ROLLBACK,
|
|
209
|
+
VALID_EVENT_TYPES,
|
|
210
|
+
ARTIFACT_ROUTING_RULE,
|
|
211
|
+
ARTIFACT_CONTEXT_POLICY,
|
|
212
|
+
ARTIFACT_EVIDENCE_ORDER,
|
|
213
|
+
ARTIFACT_SCORING_THRESHOLD,
|
|
214
|
+
ARTIFACT_PROMPT_MODULE,
|
|
215
|
+
VALID_ARTIFACT_TYPES,
|
|
216
|
+
record_evolution_event,
|
|
217
|
+
rebuild_shadow_index,
|
|
218
|
+
get_shadow_summary,
|
|
219
|
+
get_variant_history,
|
|
220
|
+
get_recent_events,
|
|
221
|
+
get_evolution_summary,
|
|
222
|
+
reset_evolution_ledger,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# ── Deprecated (TD-029 — remove in a future release) ────────────────
|
|
226
|
+
from gae.scoring import score_entity, score_alert, score_with_profile
|
|
227
|
+
|
|
228
|
+
__all__ = [
|
|
229
|
+
"__version__",
|
|
230
|
+
# Core scoring
|
|
231
|
+
"CentroidUpdate",
|
|
232
|
+
"LearningStrategy",
|
|
233
|
+
"ProfileScorer",
|
|
234
|
+
"ScoringResult",
|
|
235
|
+
"KernelType",
|
|
236
|
+
"build_profile_scorer",
|
|
237
|
+
"ProfileScoringResult", # backward-compat alias
|
|
238
|
+
"DKEstimator",
|
|
239
|
+
"CoordinateDescentEstimator",
|
|
240
|
+
"ShrinkageSchedule",
|
|
241
|
+
"FixedAlpha",
|
|
242
|
+
"LinearRampAlpha",
|
|
243
|
+
"compute_effective_weights",
|
|
244
|
+
# Oracle
|
|
245
|
+
"OracleProvider",
|
|
246
|
+
"OracleResult",
|
|
247
|
+
"GTAlignedOracle",
|
|
248
|
+
"BernoulliOracle",
|
|
249
|
+
# Evaluation
|
|
250
|
+
"EvaluationScenario",
|
|
251
|
+
"EvaluationReport",
|
|
252
|
+
"compute_ece",
|
|
253
|
+
"run_evaluation",
|
|
254
|
+
# Judgment
|
|
255
|
+
"JudgmentResult",
|
|
256
|
+
"compute_judgment",
|
|
257
|
+
"CONFIDENCE_HIGH",
|
|
258
|
+
"CONFIDENCE_MEDIUM",
|
|
259
|
+
# Ablation
|
|
260
|
+
"AblationResult",
|
|
261
|
+
"AblationReport",
|
|
262
|
+
"run_ablation",
|
|
263
|
+
# Calibration
|
|
264
|
+
"CalibrationProfile",
|
|
265
|
+
"soc_calibration_profile",
|
|
266
|
+
"s2p_calibration_profile",
|
|
267
|
+
# Conservation law primitives
|
|
268
|
+
"ConservationCheck",
|
|
269
|
+
"check_conservation",
|
|
270
|
+
"compute_theta_min",
|
|
271
|
+
"conservation_status",
|
|
272
|
+
# Primitives
|
|
273
|
+
"scaled_dot_product_attention",
|
|
274
|
+
"softmax",
|
|
275
|
+
# Learning
|
|
276
|
+
"ALPHA",
|
|
277
|
+
"EPSILON",
|
|
278
|
+
"LAMBDA_NEG",
|
|
279
|
+
"W_CLAMP",
|
|
280
|
+
"DimensionMetadata",
|
|
281
|
+
"LearningState",
|
|
282
|
+
"PendingValidation",
|
|
283
|
+
"WeightUpdate",
|
|
284
|
+
# Convergence
|
|
285
|
+
"get_convergence_metrics",
|
|
286
|
+
"centroid_distance_to_canonical",
|
|
287
|
+
"gamma_threshold",
|
|
288
|
+
"phase2_effective_threshold",
|
|
289
|
+
"ConvergenceTrace",
|
|
290
|
+
"compute_reconvergence_ratio",
|
|
291
|
+
# Oracle separation / EXP-G1 experiment framework
|
|
292
|
+
"FactorVectorSample",
|
|
293
|
+
"FactorVectorSampler",
|
|
294
|
+
"CanonicalCentroid",
|
|
295
|
+
"OracleSeparationExperiment",
|
|
296
|
+
"GammaResult",
|
|
297
|
+
"Phase1Result",
|
|
298
|
+
"Phase2Result",
|
|
299
|
+
# Monitoring (observability only — no gating side-effects)
|
|
300
|
+
"ConservationMonitor",
|
|
301
|
+
"OLSMonitor",
|
|
302
|
+
"VarQMonitor",
|
|
303
|
+
# Events
|
|
304
|
+
"FactorComputedEvent",
|
|
305
|
+
"WeightsUpdatedEvent",
|
|
306
|
+
"ConvergenceEvent",
|
|
307
|
+
# Contracts
|
|
308
|
+
"PropertySpec",
|
|
309
|
+
"EmbeddingContract",
|
|
310
|
+
"SchemaContract",
|
|
311
|
+
# Factors
|
|
312
|
+
"FactorComputer",
|
|
313
|
+
"assemble_factor_vector",
|
|
314
|
+
# Persistence
|
|
315
|
+
"save_state",
|
|
316
|
+
"load_state",
|
|
317
|
+
# Bootstrap
|
|
318
|
+
"BootstrapResult",
|
|
319
|
+
"bootstrap_calibration",
|
|
320
|
+
# Kernels
|
|
321
|
+
"L2Kernel",
|
|
322
|
+
"DiagonalKernel",
|
|
323
|
+
"CovarianceEstimator",
|
|
324
|
+
"KernelSelector",
|
|
325
|
+
"KernelRecommendation",
|
|
326
|
+
"NoveltyTracker",
|
|
327
|
+
"NearestNeighborNovelty",
|
|
328
|
+
"BatchCompositionPolicy",
|
|
329
|
+
"NoveltyThresholdPolicy",
|
|
330
|
+
"FixedIntervalPolicy",
|
|
331
|
+
"PromotionGate",
|
|
332
|
+
"DefaultPromotionGate",
|
|
333
|
+
"GateVerdict",
|
|
334
|
+
"BatchRecord",
|
|
335
|
+
"BatchHistory",
|
|
336
|
+
# Referral
|
|
337
|
+
"ReferralEngine",
|
|
338
|
+
"ReferralRule",
|
|
339
|
+
"ReferralDecision",
|
|
340
|
+
"ReferralReason",
|
|
341
|
+
"OverrideDetector",
|
|
342
|
+
# Evolution ledger
|
|
343
|
+
"VARIANT_CREATED",
|
|
344
|
+
"SHADOW_STARTED",
|
|
345
|
+
"SHADOW_RESULT",
|
|
346
|
+
"PROMOTION_APPROVED",
|
|
347
|
+
"PROMOTION_REJECTED",
|
|
348
|
+
"ROLLBACK",
|
|
349
|
+
"VALID_EVENT_TYPES",
|
|
350
|
+
"ARTIFACT_ROUTING_RULE",
|
|
351
|
+
"ARTIFACT_CONTEXT_POLICY",
|
|
352
|
+
"ARTIFACT_EVIDENCE_ORDER",
|
|
353
|
+
"ARTIFACT_SCORING_THRESHOLD",
|
|
354
|
+
"ARTIFACT_PROMPT_MODULE",
|
|
355
|
+
"VALID_ARTIFACT_TYPES",
|
|
356
|
+
"record_evolution_event",
|
|
357
|
+
"rebuild_shadow_index",
|
|
358
|
+
"get_shadow_summary",
|
|
359
|
+
"get_variant_history",
|
|
360
|
+
"get_recent_events",
|
|
361
|
+
"get_evolution_summary",
|
|
362
|
+
"reset_evolution_ledger",
|
|
363
|
+
# Deprecated (TD-029 — remove in a future release)
|
|
364
|
+
"score_entity",
|
|
365
|
+
"score_alert",
|
|
366
|
+
"score_with_profile",
|
|
367
|
+
]
|
gae/ablation.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GAE Ablation — factor importance measurement via leave-one-out ablation.
|
|
3
|
+
|
|
4
|
+
Measures how much each factor contributes to accuracy by zeroing out one
|
|
5
|
+
factor at a time and re-evaluating. A large accuracy drop when factor X
|
|
6
|
+
is zeroed means X is important.
|
|
7
|
+
|
|
8
|
+
Zero SOC knowledge. NumPy only.
|
|
9
|
+
Builds on gae/evaluation.py (run_evaluation, EvaluationScenario).
|
|
10
|
+
|
|
11
|
+
Reference: docs/gae_design_v10_6.md §20 (ablation framework); GAE-ABL-1.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
from gae.evaluation import EvaluationReport, EvaluationScenario, run_evaluation
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class AblationResult:
|
|
25
|
+
"""
|
|
26
|
+
Result of ablating one factor from the evaluation.
|
|
27
|
+
|
|
28
|
+
Reference: docs/gae_design_v10_6.md §20.1; GAE-ABL-1.
|
|
29
|
+
|
|
30
|
+
Attributes
|
|
31
|
+
----------
|
|
32
|
+
factor_index : int
|
|
33
|
+
Index of the ablated factor.
|
|
34
|
+
factor_name : str
|
|
35
|
+
Name of the ablated factor.
|
|
36
|
+
baseline_accuracy : float
|
|
37
|
+
Accuracy with all factors present.
|
|
38
|
+
ablated_accuracy : float
|
|
39
|
+
Accuracy with this factor zeroed out.
|
|
40
|
+
accuracy_drop : float
|
|
41
|
+
baseline_accuracy - ablated_accuracy.
|
|
42
|
+
Positive = factor helps. Negative = factor hurts (noise).
|
|
43
|
+
importance_rank : int
|
|
44
|
+
Rank by accuracy_drop (1 = most important).
|
|
45
|
+
Set after run_ablation() completes.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
factor_index: int
|
|
49
|
+
factor_name: str
|
|
50
|
+
baseline_accuracy: float
|
|
51
|
+
ablated_accuracy: float
|
|
52
|
+
accuracy_drop: float
|
|
53
|
+
importance_rank: int = 0
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class AblationReport:
|
|
58
|
+
"""
|
|
59
|
+
Full ablation study results across all factors.
|
|
60
|
+
|
|
61
|
+
Reference: docs/gae_design_v10_6.md §20.2; GAE-ABL-1.
|
|
62
|
+
|
|
63
|
+
Attributes
|
|
64
|
+
----------
|
|
65
|
+
baseline_accuracy : float
|
|
66
|
+
Accuracy with all factors present.
|
|
67
|
+
results : list[AblationResult]
|
|
68
|
+
AblationResult per factor, sorted by accuracy_drop descending.
|
|
69
|
+
most_important : str
|
|
70
|
+
Factor name with largest accuracy drop.
|
|
71
|
+
least_important : str
|
|
72
|
+
Factor name with smallest accuracy drop (or most negative — noise).
|
|
73
|
+
n_factors : int
|
|
74
|
+
Number of factors ablated.
|
|
75
|
+
n_scenarios : int
|
|
76
|
+
Number of evaluation scenarios used.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
baseline_accuracy: float
|
|
80
|
+
results: list[AblationResult]
|
|
81
|
+
most_important: str
|
|
82
|
+
least_important: str
|
|
83
|
+
n_factors: int
|
|
84
|
+
n_scenarios: int
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _zero_factor(
|
|
88
|
+
scenarios: list[EvaluationScenario],
|
|
89
|
+
factor_index: int,
|
|
90
|
+
) -> list[EvaluationScenario]:
|
|
91
|
+
"""
|
|
92
|
+
Return a copy of scenarios with factor_index zeroed out.
|
|
93
|
+
|
|
94
|
+
Does NOT modify original scenarios. Creates new EvaluationScenario
|
|
95
|
+
objects with copied factor arrays.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
scenarios: Original scenario list. Unchanged.
|
|
99
|
+
factor_index: Index into each scenario's factors vector to zero.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
New list of EvaluationScenario with factor_index set to 0.0.
|
|
103
|
+
|
|
104
|
+
Reference: docs/gae_design_v10_6.md §20.3; GAE-ABL-1.
|
|
105
|
+
"""
|
|
106
|
+
ablated = []
|
|
107
|
+
for s in scenarios:
|
|
108
|
+
f_copy = s.factors.copy()
|
|
109
|
+
f_copy[factor_index] = 0.0
|
|
110
|
+
ablated.append(EvaluationScenario(
|
|
111
|
+
scenario_id=s.scenario_id,
|
|
112
|
+
domain=s.domain,
|
|
113
|
+
category=s.category,
|
|
114
|
+
category_index=s.category_index,
|
|
115
|
+
factors=f_copy,
|
|
116
|
+
expected_action=s.expected_action,
|
|
117
|
+
expected_action_index=s.expected_action_index,
|
|
118
|
+
expected_dominant_factors=s.expected_dominant_factors,
|
|
119
|
+
confidence_tier=s.confidence_tier,
|
|
120
|
+
description=s.description,
|
|
121
|
+
learning_prerequisite=s.learning_prerequisite,
|
|
122
|
+
))
|
|
123
|
+
return ablated
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def run_ablation(
|
|
127
|
+
profile_scorer,
|
|
128
|
+
scenarios: list[EvaluationScenario],
|
|
129
|
+
factor_names: list[str],
|
|
130
|
+
) -> AblationReport:
|
|
131
|
+
"""
|
|
132
|
+
Run ablation study: evaluate accuracy with each factor zeroed.
|
|
133
|
+
|
|
134
|
+
Steps:
|
|
135
|
+
1. Compute baseline accuracy (all factors present).
|
|
136
|
+
2. For each factor i in range(n_factors):
|
|
137
|
+
a. Zero out factor i across all scenarios (_zero_factor).
|
|
138
|
+
b. Run evaluation on ablated scenarios.
|
|
139
|
+
c. Record accuracy_drop = baseline - ablated_accuracy.
|
|
140
|
+
3. Sort results by accuracy_drop descending.
|
|
141
|
+
4. Assign importance_rank (1 = most important).
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
profile_scorer: ProfileScorer instance. NOT modified.
|
|
145
|
+
scenarios: List of EvaluationScenario. NOT modified.
|
|
146
|
+
factor_names: Names for each factor dimension.
|
|
147
|
+
len(factor_names) must match factors vector length.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
AblationReport sorted by importance (most important first).
|
|
151
|
+
|
|
152
|
+
Raises:
|
|
153
|
+
ValueError: if scenarios is empty or factor_names is empty.
|
|
154
|
+
ValueError: if len(factor_names) != factors vector length.
|
|
155
|
+
|
|
156
|
+
Reference: docs/gae_design_v10_6.md §20.4; GAE-ABL-1.
|
|
157
|
+
"""
|
|
158
|
+
if not scenarios:
|
|
159
|
+
raise ValueError("scenarios must not be empty")
|
|
160
|
+
if not factor_names:
|
|
161
|
+
raise ValueError("factor_names must not be empty")
|
|
162
|
+
|
|
163
|
+
n_factors = len(scenarios[0].factors)
|
|
164
|
+
if len(factor_names) != n_factors:
|
|
165
|
+
raise ValueError(
|
|
166
|
+
f"factor_names length {len(factor_names)} != "
|
|
167
|
+
f"factors length {n_factors}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Step 1: baseline with all factors
|
|
171
|
+
baseline_report = run_evaluation(profile_scorer, scenarios)
|
|
172
|
+
baseline_accuracy = baseline_report.accuracy
|
|
173
|
+
|
|
174
|
+
# Step 2: ablate each factor
|
|
175
|
+
results: list[AblationResult] = []
|
|
176
|
+
for i, name in enumerate(factor_names):
|
|
177
|
+
ablated_scenarios = _zero_factor(scenarios, i)
|
|
178
|
+
ablated_report = run_evaluation(profile_scorer, ablated_scenarios)
|
|
179
|
+
drop = round(baseline_accuracy - ablated_report.accuracy, 4)
|
|
180
|
+
results.append(AblationResult(
|
|
181
|
+
factor_index=i,
|
|
182
|
+
factor_name=name,
|
|
183
|
+
baseline_accuracy=baseline_accuracy,
|
|
184
|
+
ablated_accuracy=ablated_report.accuracy,
|
|
185
|
+
accuracy_drop=drop,
|
|
186
|
+
))
|
|
187
|
+
|
|
188
|
+
# Step 3: sort by accuracy_drop descending, assign ranks
|
|
189
|
+
results.sort(key=lambda r: r.accuracy_drop, reverse=True)
|
|
190
|
+
for rank, result in enumerate(results, start=1):
|
|
191
|
+
result.importance_rank = rank
|
|
192
|
+
|
|
193
|
+
most_important = results[0].factor_name
|
|
194
|
+
least_important = results[-1].factor_name
|
|
195
|
+
|
|
196
|
+
return AblationReport(
|
|
197
|
+
baseline_accuracy=baseline_accuracy,
|
|
198
|
+
results=results,
|
|
199
|
+
most_important=most_important,
|
|
200
|
+
least_important=least_important,
|
|
201
|
+
n_factors=n_factors,
|
|
202
|
+
n_scenarios=len(scenarios),
|
|
203
|
+
)
|