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 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
+ )