grg 0.2.2__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.
- grg/__init__.py +111 -0
- grg/cli.py +473 -0
- grg/config/grg-config.json +90 -0
- grg/config.py +120 -0
- grg/early_warning.py +272 -0
- grg/grg-config.json +90 -0
- grg/intervention.py +426 -0
- grg/metrics.py +921 -0
- grg-0.2.2.dist-info/METADATA +758 -0
- grg-0.2.2.dist-info/RECORD +14 -0
- grg-0.2.2.dist-info/WHEEL +5 -0
- grg-0.2.2.dist-info/entry_points.txt +2 -0
- grg-0.2.2.dist-info/licenses/LICENSE +21 -0
- grg-0.2.2.dist-info/top_level.txt +1 -0
grg/__init__.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GRG (Geometric Reasoning Governor) — Real-time structural integrity monitoring for LLM inference.
|
|
3
|
+
|
|
4
|
+
A Python package for monitoring and governing the structural integrity of LLM outputs
|
|
5
|
+
during token generation using Alpha-Drift Velocity (V_alpha) tracking.
|
|
6
|
+
|
|
7
|
+
Key Components:
|
|
8
|
+
- AlphaMomentumTracker: Core GRG class for real-time EMA-smoothed alpha tracking
|
|
9
|
+
- SGO Metrics: Structural Geometry Optimization metrics for evaluating binary-outcome systems
|
|
10
|
+
- Configuration: Profile-based configuration for different sensitivity requirements
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
from grg import AlphaMomentumTracker, evaluate_structural_geometry
|
|
14
|
+
from grg.config import get_config
|
|
15
|
+
|
|
16
|
+
# Real-time GRG tracking
|
|
17
|
+
tracker = AlphaMomentumTracker()
|
|
18
|
+
for token_logprob in token_stream:
|
|
19
|
+
alpha = compute_structural_alpha(token_logprob)
|
|
20
|
+
tracker.push(alpha)
|
|
21
|
+
stats = tracker.get_stats()
|
|
22
|
+
if stats["is_collapsing"]:
|
|
23
|
+
# Trigger thermal damping or e-stop
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
# Offline SGO evaluation
|
|
27
|
+
results = evaluate_structural_geometry(positive_outcomes, negative_outcomes)
|
|
28
|
+
print(f"Structural Alpha: {results['structural_alpha']:.4f}")
|
|
29
|
+
print(f"Ranking Score: {results['ranking_score']:.4f}")
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from grg.early_warning import EarlyWarningSystem, EWIReading
|
|
33
|
+
from grg.config import get_config
|
|
34
|
+
from grg.metrics import (
|
|
35
|
+
RANKING_PROFILES,
|
|
36
|
+
# Trackers (GRG Core)
|
|
37
|
+
AlphaMomentumTracker,
|
|
38
|
+
StructuralTracker,
|
|
39
|
+
# Utility
|
|
40
|
+
apply_utility_transformation,
|
|
41
|
+
calculate_cofactor_matrix,
|
|
42
|
+
# Entropy & Probability
|
|
43
|
+
calculate_entropy,
|
|
44
|
+
calculate_moment_sgo_metrics,
|
|
45
|
+
# Structural Metrics
|
|
46
|
+
calculate_normalized_structure_metrics,
|
|
47
|
+
calculate_positive_alpha_penalty,
|
|
48
|
+
calculate_probability_sgo_matrix,
|
|
49
|
+
# Ranking & Diagnostics
|
|
50
|
+
calculate_ranking_score,
|
|
51
|
+
calculate_regime_aware_ideal,
|
|
52
|
+
calculate_sgo_divergence,
|
|
53
|
+
compute_distributional_concentration,
|
|
54
|
+
# Core SGO Matrix Functions
|
|
55
|
+
compute_sgo_matrix,
|
|
56
|
+
evaluate_balance_diagnostics,
|
|
57
|
+
evaluate_cofactors_norm_diff_diagnostics,
|
|
58
|
+
# Distributional Analysis
|
|
59
|
+
evaluate_distributional_geometry,
|
|
60
|
+
evaluate_structural_geometry,
|
|
61
|
+
extract_matrix_alpha,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
from grg.intervention import (
|
|
65
|
+
CandidateBatch,
|
|
66
|
+
GenerationResult,
|
|
67
|
+
InterventionConfig,
|
|
68
|
+
InterventionSampler,
|
|
69
|
+
TokenTelemetry,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
# Core SGO Matrix Functions
|
|
74
|
+
"compute_sgo_matrix",
|
|
75
|
+
"calculate_moment_sgo_metrics",
|
|
76
|
+
"evaluate_structural_geometry",
|
|
77
|
+
# Structural Metrics
|
|
78
|
+
"calculate_normalized_structure_metrics",
|
|
79
|
+
"extract_matrix_alpha",
|
|
80
|
+
"calculate_cofactor_matrix",
|
|
81
|
+
"calculate_regime_aware_ideal",
|
|
82
|
+
# Ranking & Diagnostics
|
|
83
|
+
"calculate_ranking_score",
|
|
84
|
+
"calculate_positive_alpha_penalty",
|
|
85
|
+
"evaluate_balance_diagnostics",
|
|
86
|
+
"evaluate_cofactors_norm_diff_diagnostics",
|
|
87
|
+
# Entropy & Probability
|
|
88
|
+
"calculate_entropy",
|
|
89
|
+
"calculate_probability_sgo_matrix",
|
|
90
|
+
"calculate_sgo_divergence",
|
|
91
|
+
# Distributional Analysis
|
|
92
|
+
"evaluate_distributional_geometry",
|
|
93
|
+
"compute_distributional_concentration",
|
|
94
|
+
# Utility
|
|
95
|
+
"apply_utility_transformation",
|
|
96
|
+
# Trackers (GRG Core)
|
|
97
|
+
"AlphaMomentumTracker",
|
|
98
|
+
"StructuralTracker",
|
|
99
|
+
# Ranking Profiles
|
|
100
|
+
"RANKING_PROFILES",
|
|
101
|
+
# Config
|
|
102
|
+
"get_config",
|
|
103
|
+
# Intervention Sampler
|
|
104
|
+
"InterventionSampler",
|
|
105
|
+
"InterventionConfig",
|
|
106
|
+
"GenerationResult",
|
|
107
|
+
"TokenTelemetry",
|
|
108
|
+
"CandidateBatch",
|
|
109
|
+
"EarlyWarningSystem",
|
|
110
|
+
"EWIReading",
|
|
111
|
+
]
|
grg/cli.py
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"""CLI for GRG (Geometric Reasoning Governor) — System stats analysis and GRG monitoring."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
import numpy as np
|
|
9
|
+
import psutil
|
|
10
|
+
|
|
11
|
+
from grg import (
|
|
12
|
+
AlphaMomentumTracker,
|
|
13
|
+
calculate_entropy,
|
|
14
|
+
calculate_moment_sgo_metrics,
|
|
15
|
+
evaluate_structural_geometry,
|
|
16
|
+
get_config,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def collect_system_stats() -> dict[str, Any]:
|
|
21
|
+
"""Collect comprehensive system statistics."""
|
|
22
|
+
# CPU
|
|
23
|
+
cpu_percent = psutil.cpu_percent(interval=0.1, percpu=True)
|
|
24
|
+
cpu_freq = psutil.cpu_freq()
|
|
25
|
+
cpu_count_logical = psutil.cpu_count(logical=True)
|
|
26
|
+
cpu_count_physical = psutil.cpu_count(logical=False)
|
|
27
|
+
|
|
28
|
+
# Memory
|
|
29
|
+
mem = psutil.virtual_memory()
|
|
30
|
+
swap = psutil.swap_memory()
|
|
31
|
+
|
|
32
|
+
# Disk
|
|
33
|
+
disk = psutil.disk_usage("/")
|
|
34
|
+
|
|
35
|
+
# Network
|
|
36
|
+
net_io = psutil.net_io_counters()
|
|
37
|
+
|
|
38
|
+
# Process
|
|
39
|
+
process = psutil.Process()
|
|
40
|
+
proc_mem = process.memory_info()
|
|
41
|
+
proc_cpu = process.cpu_percent(interval=0.1)
|
|
42
|
+
|
|
43
|
+
# GPU (if available)
|
|
44
|
+
gpu_info = []
|
|
45
|
+
try:
|
|
46
|
+
import pynvml # type: ignore[import-not-found]
|
|
47
|
+
|
|
48
|
+
pynvml.nvmlInit()
|
|
49
|
+
device_count = pynvml.nvmlDeviceGetCount()
|
|
50
|
+
for i in range(device_count):
|
|
51
|
+
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
|
|
52
|
+
name = pynvml.nvmlDeviceGetName(handle)
|
|
53
|
+
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
|
|
54
|
+
util = pynvml.nvmlDeviceGetUtilizationRates(handle)
|
|
55
|
+
temp = pynvml.nvmlDeviceGetTemperature(handle, pynvml.NVML_TEMPERATURE_GPU)
|
|
56
|
+
gpu_info.append(
|
|
57
|
+
{
|
|
58
|
+
"index": i,
|
|
59
|
+
"name": name.decode() if isinstance(name, bytes) else name,
|
|
60
|
+
"memory_total_mb": mem_info.total / 1024**2,
|
|
61
|
+
"memory_used_mb": mem_info.used / 1024**2,
|
|
62
|
+
"memory_free_mb": mem_info.free / 1024**2,
|
|
63
|
+
"utilization_gpu": util.gpu,
|
|
64
|
+
"utilization_memory": util.memory,
|
|
65
|
+
"temperature_c": temp,
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
except Exception:
|
|
69
|
+
pass # GPU monitoring optional
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
"cpu": {
|
|
73
|
+
"percent_per_core": cpu_percent,
|
|
74
|
+
"percent_total": sum(cpu_percent) / len(cpu_percent) if cpu_percent else 0,
|
|
75
|
+
"frequency_mhz": cpu_freq.current if cpu_freq else None,
|
|
76
|
+
"count_logical": cpu_count_logical,
|
|
77
|
+
"count_physical": cpu_count_physical,
|
|
78
|
+
},
|
|
79
|
+
"memory": {
|
|
80
|
+
"total_gb": mem.total / 1024**3,
|
|
81
|
+
"available_gb": mem.available / 1024**3,
|
|
82
|
+
"used_gb": mem.used / 1024**3,
|
|
83
|
+
"percent": mem.percent,
|
|
84
|
+
},
|
|
85
|
+
"swap": {
|
|
86
|
+
"total_gb": swap.total / 1024**3,
|
|
87
|
+
"used_gb": swap.used / 1024**3,
|
|
88
|
+
"percent": swap.percent,
|
|
89
|
+
},
|
|
90
|
+
"disk": {
|
|
91
|
+
"total_gb": disk.total / 1024**3,
|
|
92
|
+
"used_gb": disk.used / 1024**3,
|
|
93
|
+
"free_gb": disk.free / 1024**3,
|
|
94
|
+
"percent": (disk.used / disk.total) * 100,
|
|
95
|
+
},
|
|
96
|
+
"network": {
|
|
97
|
+
"bytes_sent": net_io.bytes_sent,
|
|
98
|
+
"bytes_recv": net_io.bytes_recv,
|
|
99
|
+
"packets_sent": net_io.packets_sent,
|
|
100
|
+
"packets_recv": net_io.packets_recv,
|
|
101
|
+
},
|
|
102
|
+
"process": {
|
|
103
|
+
"pid": process.pid,
|
|
104
|
+
"memory_rss_mb": proc_mem.rss / 1024**2,
|
|
105
|
+
"memory_vms_mb": proc_mem.vms / 1024**2,
|
|
106
|
+
"cpu_percent": proc_cpu,
|
|
107
|
+
"num_threads": process.num_threads(),
|
|
108
|
+
},
|
|
109
|
+
"gpu": gpu_info,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def simulate_alpha_from_system_stats(stats: dict[str, Any], window_size: int = 20) -> list[float]:
|
|
114
|
+
"""
|
|
115
|
+
Simulate a sequence of alpha values from system stats.
|
|
116
|
+
This is a placeholder for actual LLM token-level alpha computation.
|
|
117
|
+
In practice, alpha would be computed from SGO matrix on token logprobs.
|
|
118
|
+
"""
|
|
119
|
+
# Create synthetic alpha sequence based on system load patterns
|
|
120
|
+
cpu_load = stats["cpu"]["percent_total"] / 100.0
|
|
121
|
+
mem_load = stats["memory"]["percent"] / 100.0
|
|
122
|
+
|
|
123
|
+
# Base alpha inversely related to system stress
|
|
124
|
+
base_alpha = 1.0 - (0.4 * cpu_load + 0.3 * mem_load)
|
|
125
|
+
base_alpha = max(0.1, min(0.95, base_alpha))
|
|
126
|
+
|
|
127
|
+
# Generate a sequence with some drift and noise
|
|
128
|
+
np.random.seed(42) # Reproducible for demo
|
|
129
|
+
alphas = []
|
|
130
|
+
current = base_alpha
|
|
131
|
+
for _ in range(window_size * 2):
|
|
132
|
+
# Add some drift (simulating token generation)
|
|
133
|
+
drift = np.random.normal(-0.001, 0.005) # Slight negative drift
|
|
134
|
+
noise = np.random.normal(0, 0.01)
|
|
135
|
+
current = max(0.05, min(0.98, current + drift + noise))
|
|
136
|
+
alphas.append(current)
|
|
137
|
+
|
|
138
|
+
return alphas
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def run_grg_analysis(
|
|
142
|
+
stats: dict[str, Any], profile: str = "default", verbose: bool = False
|
|
143
|
+
) -> dict[str, Any]:
|
|
144
|
+
"""Run GRG analysis on system stats."""
|
|
145
|
+
grg_config = get_config.get_grg_config(profile)
|
|
146
|
+
window_size = grg_config.get("window_size", 20)
|
|
147
|
+
ema_weight = grg_config.get("ema_weight", 0.3)
|
|
148
|
+
|
|
149
|
+
# Simulate alpha sequence (in practice, this comes from token logprobs)
|
|
150
|
+
alphas = simulate_alpha_from_system_stats(stats, window_size)
|
|
151
|
+
|
|
152
|
+
# Initialize GRG tracker
|
|
153
|
+
tracker = AlphaMomentumTracker(window_size=window_size, alpha_ema=ema_weight)
|
|
154
|
+
|
|
155
|
+
remediation_actions: list[dict[str, Any]] = []
|
|
156
|
+
tracker_states: list[dict[str, Any]] = []
|
|
157
|
+
|
|
158
|
+
results: dict[str, Any] = {
|
|
159
|
+
"profile": profile,
|
|
160
|
+
"grg_config": grg_config,
|
|
161
|
+
"alpha_sequence": alphas,
|
|
162
|
+
"tracker_states": tracker_states,
|
|
163
|
+
"final_stats": None,
|
|
164
|
+
"remediation_actions": remediation_actions,
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# Process each alpha
|
|
168
|
+
for i, alpha in enumerate(alphas):
|
|
169
|
+
tracker.push(alpha)
|
|
170
|
+
state = tracker.get_stats()
|
|
171
|
+
tracker_states.append(
|
|
172
|
+
{
|
|
173
|
+
"step": i,
|
|
174
|
+
"alpha": alpha,
|
|
175
|
+
"ema_alpha": state["alpha"],
|
|
176
|
+
"v_alpha": state["v_alpha"],
|
|
177
|
+
"m_alpha": state["m_alpha"],
|
|
178
|
+
"horizon": state["horizon"],
|
|
179
|
+
"is_collapsing": state["is_collapsing"],
|
|
180
|
+
"is_stable": state["is_stable"],
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Check for remediation triggers
|
|
185
|
+
if state["is_collapsing"] and not remediation_actions:
|
|
186
|
+
remediation_actions.append(
|
|
187
|
+
{
|
|
188
|
+
"step": i,
|
|
189
|
+
"trigger": "collapse_detected",
|
|
190
|
+
"action": "thermal_damping",
|
|
191
|
+
"v_alpha": state["v_alpha"],
|
|
192
|
+
"recommended_temp": max(0.0, 0.7 * (1.0 + 10.0 * state["v_alpha"])),
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
elif (
|
|
196
|
+
state["horizon"] < grg_config.get("e_stop_horizon", 5)
|
|
197
|
+
and state["horizon"] > 0
|
|
198
|
+
and not any(a["action"] == "e_stop" for a in results["remediation_actions"])
|
|
199
|
+
):
|
|
200
|
+
results["remediation_actions"].append(
|
|
201
|
+
{
|
|
202
|
+
"step": i,
|
|
203
|
+
"trigger": "horizon_breach",
|
|
204
|
+
"action": "structural_e_stop",
|
|
205
|
+
"horizon": state["horizon"],
|
|
206
|
+
"message": (
|
|
207
|
+
"Grounding check failed. Halting generation to prevent "
|
|
208
|
+
"structural hallucination."
|
|
209
|
+
),
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
results["final_stats"] = tracker.get_stats()
|
|
214
|
+
|
|
215
|
+
return results
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def run_sgo_analysis(stats: dict[str, Any], verbose: bool = False) -> dict[str, Any]:
|
|
219
|
+
"""Run SGO structural geometry analysis on system stats."""
|
|
220
|
+
# Create synthetic positive/negative outcomes from system metrics
|
|
221
|
+
cpu_load = stats["cpu"]["percent_total"] / 100.0
|
|
222
|
+
mem_load = stats["memory"]["percent"] / 100.0
|
|
223
|
+
disk_load = stats["disk"]["percent"] / 100.0
|
|
224
|
+
|
|
225
|
+
# Positive outcomes: healthy metrics (low load = good)
|
|
226
|
+
positive_outcomes = np.array(
|
|
227
|
+
[
|
|
228
|
+
1.0 - cpu_load,
|
|
229
|
+
1.0 - mem_load,
|
|
230
|
+
1.0 - disk_load,
|
|
231
|
+
stats["cpu"]["count_physical"] / 16.0, # Normalized CPU cores
|
|
232
|
+
stats["memory"]["available_gb"] / 32.0, # Normalized available memory
|
|
233
|
+
]
|
|
234
|
+
)
|
|
235
|
+
positive_outcomes = np.clip(positive_outcomes, 0.01, 1.0)
|
|
236
|
+
|
|
237
|
+
# Negative outcomes: stress indicators
|
|
238
|
+
negative_outcomes = np.array(
|
|
239
|
+
[
|
|
240
|
+
cpu_load,
|
|
241
|
+
mem_load,
|
|
242
|
+
disk_load,
|
|
243
|
+
0.1, # Baseline stress
|
|
244
|
+
]
|
|
245
|
+
)
|
|
246
|
+
negative_outcomes = np.clip(negative_outcomes, 0.01, 1.0)
|
|
247
|
+
|
|
248
|
+
# Run structural geometry evaluation
|
|
249
|
+
results = evaluate_structural_geometry(
|
|
250
|
+
positive_outcomes=positive_outcomes,
|
|
251
|
+
negative_outcomes=negative_outcomes,
|
|
252
|
+
utility_power=1.1,
|
|
253
|
+
ranking_profile="conservative",
|
|
254
|
+
regime_aware=True,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Also run moment SGO metrics
|
|
258
|
+
# Create outcome units (each metric as a "unit")
|
|
259
|
+
outcome_units = [positive_outcomes, -negative_outcomes]
|
|
260
|
+
moment_results = calculate_moment_sgo_metrics(outcome_units, utility_power=1.1)
|
|
261
|
+
|
|
262
|
+
# Entropy
|
|
263
|
+
all_outcomes = np.concatenate([positive_outcomes, -negative_outcomes])
|
|
264
|
+
entropy = calculate_entropy(all_outcomes)
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
"structural_geometry": results,
|
|
268
|
+
"moment_sgo": moment_results,
|
|
269
|
+
"entropy": entropy,
|
|
270
|
+
"summary": {
|
|
271
|
+
"structural_alpha": results["structural_alpha"],
|
|
272
|
+
"ranking_score": results["ranking_score"],
|
|
273
|
+
"normalized_structure_term": results["normalized_structure_term"],
|
|
274
|
+
"entropy": entropy,
|
|
275
|
+
"is_structurally_sound": results.get("is_structurally_sound", False),
|
|
276
|
+
"energy_ratio": results.get("energy_ratio", 0.0),
|
|
277
|
+
"credibility": results.get("credibility", 0.0),
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@click.group()
|
|
283
|
+
@click.version_option(version="0.1.0", prog_name="grg")
|
|
284
|
+
def main() -> None:
|
|
285
|
+
"""GRG (Geometric Reasoning Governor) — Real-time structural integrity
|
|
286
|
+
monitoring for LLM inference.
|
|
287
|
+
|
|
288
|
+
This CLI provides system stats analysis through the lens of GRG/SGO
|
|
289
|
+
metrics, useful for monitoring system health and demonstrating the
|
|
290
|
+
GRG framework.
|
|
291
|
+
"""
|
|
292
|
+
pass
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
@main.command()
|
|
296
|
+
@click.option(
|
|
297
|
+
"--profile",
|
|
298
|
+
"-p",
|
|
299
|
+
default="default",
|
|
300
|
+
help="GRG profile to use (default, high_sensitivity, low_latency, rag_grounded)",
|
|
301
|
+
)
|
|
302
|
+
@click.option("--output", "-o", type=click.Path(), help="Output JSON file path")
|
|
303
|
+
@click.option("--verbose", "-v", is_flag=True, help="Verbose output")
|
|
304
|
+
@click.option("--pretty", is_flag=True, help="Pretty print JSON output")
|
|
305
|
+
def analyze(profile: str, output: str | None, verbose: bool, pretty: bool) -> None:
|
|
306
|
+
"""Analyze system stats with GRG and SGO metrics."""
|
|
307
|
+
click.echo("🔍 Collecting system statistics...")
|
|
308
|
+
stats = collect_system_stats()
|
|
309
|
+
|
|
310
|
+
click.echo("📊 Running SGO structural geometry analysis...")
|
|
311
|
+
sgo_results = run_sgo_analysis(stats, verbose)
|
|
312
|
+
|
|
313
|
+
click.echo(f"🧠 Running GRG Alpha-drift tracking (profile: {profile})...")
|
|
314
|
+
grg_results = run_grg_analysis(stats, profile, verbose)
|
|
315
|
+
|
|
316
|
+
# Combine results
|
|
317
|
+
combined = {
|
|
318
|
+
"system_stats": stats,
|
|
319
|
+
"sgo_analysis": sgo_results,
|
|
320
|
+
"grg_analysis": grg_results,
|
|
321
|
+
"summary": {
|
|
322
|
+
"system_health": _assess_system_health(stats, sgo_results, grg_results),
|
|
323
|
+
"structural_alpha": sgo_results["summary"]["structural_alpha"],
|
|
324
|
+
"ranking_score": sgo_results["summary"]["ranking_score"],
|
|
325
|
+
"grg_state": grg_results["final_stats"],
|
|
326
|
+
"remediation_actions": grg_results["remediation_actions"],
|
|
327
|
+
},
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
# Output
|
|
331
|
+
indent = 2 if pretty else None
|
|
332
|
+
json_str = json.dumps(combined, indent=indent, default=str)
|
|
333
|
+
|
|
334
|
+
if output:
|
|
335
|
+
Path(output).write_text(json_str)
|
|
336
|
+
click.echo(f"✅ Results written to {output}")
|
|
337
|
+
else:
|
|
338
|
+
click.echo(json_str)
|
|
339
|
+
|
|
340
|
+
# Print human-readable summary
|
|
341
|
+
if verbose:
|
|
342
|
+
_print_summary(combined)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@main.command()
|
|
346
|
+
@click.option("--profile", "-p", default="default", help="GRG profile to use")
|
|
347
|
+
@click.option("--steps", "-s", default=50, help="Number of simulation steps")
|
|
348
|
+
@click.option("--output", "-o", type=click.Path(), help="Output JSON file path")
|
|
349
|
+
def simulate(profile: str, steps: int, output: str | None) -> None:
|
|
350
|
+
"""Run a simulated GRG tracking session with synthetic alpha decay."""
|
|
351
|
+
grg_config = get_config.get_grg_config(profile)
|
|
352
|
+
window_size = grg_config.get("window_size", 20)
|
|
353
|
+
ema_weight = grg_config.get("ema_weight", 0.3)
|
|
354
|
+
|
|
355
|
+
tracker = AlphaMomentumTracker(window_size=window_size, alpha_ema=ema_weight)
|
|
356
|
+
|
|
357
|
+
# Simulate alpha decay (mimicking hallucination onset)
|
|
358
|
+
np.random.seed(123)
|
|
359
|
+
alphas = []
|
|
360
|
+
current = 0.9
|
|
361
|
+
for i in range(steps):
|
|
362
|
+
# Gradual decay with noise
|
|
363
|
+
if i < steps // 3:
|
|
364
|
+
drift = np.random.normal(-0.001, 0.003)
|
|
365
|
+
elif i < 2 * steps // 3:
|
|
366
|
+
drift = np.random.normal(-0.005, 0.008) # Accelerating decay
|
|
367
|
+
else:
|
|
368
|
+
drift = np.random.normal(-0.015, 0.015) # Rapid collapse
|
|
369
|
+
current = max(0.0, min(1.0, current + drift))
|
|
370
|
+
alphas.append(current)
|
|
371
|
+
tracker.push(current)
|
|
372
|
+
|
|
373
|
+
final_stats = tracker.get_stats()
|
|
374
|
+
|
|
375
|
+
results = {
|
|
376
|
+
"profile": profile,
|
|
377
|
+
"steps": steps,
|
|
378
|
+
"alpha_sequence": alphas,
|
|
379
|
+
"final_stats": final_stats,
|
|
380
|
+
"collapse_detected": final_stats["is_collapsing"],
|
|
381
|
+
"structural_horizon": final_stats["horizon"],
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
indent = 2
|
|
385
|
+
json_str = json.dumps(results, indent=indent, default=str)
|
|
386
|
+
|
|
387
|
+
if output:
|
|
388
|
+
Path(output).write_text(json_str)
|
|
389
|
+
click.echo(f"✅ Simulation results written to {output}")
|
|
390
|
+
else:
|
|
391
|
+
click.echo(json_str)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
@main.command()
|
|
395
|
+
@click.option("--profile", "-p", default="default", help="GRG profile to display")
|
|
396
|
+
def config(profile: str) -> None:
|
|
397
|
+
"""Show current GRG configuration."""
|
|
398
|
+
grg_config = get_config.get_grg_config(profile)
|
|
399
|
+
global_config = get_config._data["global"]
|
|
400
|
+
|
|
401
|
+
click.echo(f"📋 GRG Configuration (profile: {profile})")
|
|
402
|
+
click.echo("=" * 50)
|
|
403
|
+
click.echo(f"Global ranking_profile: {global_config.get('ranking_profile', 'N/A')}")
|
|
404
|
+
click.echo()
|
|
405
|
+
click.echo("GRG Settings:")
|
|
406
|
+
for key, value in grg_config.items():
|
|
407
|
+
click.echo(f" {key}: {value}")
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@main.command()
|
|
411
|
+
def profiles() -> None:
|
|
412
|
+
"""List available GRG profiles."""
|
|
413
|
+
profiles_data = get_config._data.get("profiles", {})
|
|
414
|
+
click.echo("📋 Available GRG Profiles:")
|
|
415
|
+
click.echo("=" * 50)
|
|
416
|
+
for name, data in profiles_data.items():
|
|
417
|
+
grg = data.get("grg", {})
|
|
418
|
+
click.echo(f" {name}:")
|
|
419
|
+
for key, value in grg.items():
|
|
420
|
+
click.echo(f" {key}: {value}")
|
|
421
|
+
click.echo()
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _assess_system_health(stats: dict, sgo: dict, grg: dict) -> str:
|
|
425
|
+
"""Assess overall system health from metrics."""
|
|
426
|
+
cpu = stats["cpu"]["percent_total"]
|
|
427
|
+
mem = stats["memory"]["percent"]
|
|
428
|
+
alpha = sgo["summary"]["structural_alpha"]
|
|
429
|
+
collapsing = grg["final_stats"]["is_collapsing"]
|
|
430
|
+
|
|
431
|
+
if collapsing:
|
|
432
|
+
return "CRITICAL - Structural collapse detected"
|
|
433
|
+
elif cpu > 80 or mem > 85 or alpha < 0.3:
|
|
434
|
+
return "DEGRADED - High resource pressure"
|
|
435
|
+
elif cpu > 60 or mem > 70 or alpha < 0.5:
|
|
436
|
+
return "STRESSED - Elevated resource usage"
|
|
437
|
+
else:
|
|
438
|
+
return "HEALTHY - Normal operation"
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def _print_summary(results: dict[str, Any]) -> None:
|
|
442
|
+
"""Print human-readable summary."""
|
|
443
|
+
summary = results["summary"]
|
|
444
|
+
sgo = results["sgo_analysis"]["summary"]
|
|
445
|
+
grg = results["grg_analysis"]["final_stats"]
|
|
446
|
+
|
|
447
|
+
click.echo("\n" + "=" * 60)
|
|
448
|
+
click.echo("📋 GRG/SGO ANALYSIS SUMMARY")
|
|
449
|
+
click.echo("=" * 60)
|
|
450
|
+
click.echo(f"System Health: {summary['system_health']}")
|
|
451
|
+
click.echo(f"Structural Alpha: {summary['structural_alpha']:.4f}")
|
|
452
|
+
click.echo(f"Ranking Score: {summary['ranking_score']:.4f}")
|
|
453
|
+
click.echo(f"Entropy: {sgo['entropy']:.4f}")
|
|
454
|
+
click.echo(f"Energy Ratio: {sgo['energy_ratio']:.4f}")
|
|
455
|
+
click.echo(f"Credibility: {sgo['credibility']:.4f}")
|
|
456
|
+
click.echo()
|
|
457
|
+
click.echo("GRG State:")
|
|
458
|
+
click.echo(f" Alpha (EMA): {grg['alpha']:.4f}")
|
|
459
|
+
click.echo(f" V_alpha: {grg['v_alpha']:.6f}")
|
|
460
|
+
click.echo(f" M_alpha: {grg['m_alpha']:.6f}")
|
|
461
|
+
click.echo(f" Horizon: {grg['horizon']:.1f} tokens")
|
|
462
|
+
click.echo(f" Collapsing: {grg['is_collapsing']}")
|
|
463
|
+
click.echo(f" Stable: {grg['is_stable']}")
|
|
464
|
+
|
|
465
|
+
if summary["remediation_actions"]:
|
|
466
|
+
click.echo()
|
|
467
|
+
click.echo("🚨 Remediation Actions Triggered:")
|
|
468
|
+
for action in summary["remediation_actions"]:
|
|
469
|
+
click.echo(f" Step {action['step']}: {action['action']} ({action['trigger']})")
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
if __name__ == "__main__":
|
|
473
|
+
main()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"global": {
|
|
3
|
+
"ranking_profile": "conservative",
|
|
4
|
+
"grg": {
|
|
5
|
+
"window_size": 20,
|
|
6
|
+
"ema_weight": 0.3,
|
|
7
|
+
"warmup_steps": 50,
|
|
8
|
+
"lr_slash_factor": 0.1,
|
|
9
|
+
"lr_restore_factor": 1.0,
|
|
10
|
+
"thermal_damping_min_temp": 0.01,
|
|
11
|
+
"e_stop_horizon": 5,
|
|
12
|
+
"collapse_v_alpha_threshold": -0.02,
|
|
13
|
+
"stability_v_alpha_threshold": 0.005,
|
|
14
|
+
"trajectory_window_size": 500,
|
|
15
|
+
"trajectory_window_step": 50,
|
|
16
|
+
"v_alpha_panic_threshold": -0.02,
|
|
17
|
+
"alpha_safety_floor": 0.10
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"profiles": {
|
|
21
|
+
"default": {
|
|
22
|
+
"grg": {
|
|
23
|
+
"window_size": 20,
|
|
24
|
+
"ema_weight": 0.3,
|
|
25
|
+
"warmup_steps": 50,
|
|
26
|
+
"lr_slash_factor": 0.1,
|
|
27
|
+
"lr_restore_factor": 1.0,
|
|
28
|
+
"thermal_damping_min_temp": 0.01,
|
|
29
|
+
"e_stop_horizon": 5,
|
|
30
|
+
"collapse_v_alpha_threshold": -0.02,
|
|
31
|
+
"stability_v_alpha_threshold": 0.005,
|
|
32
|
+
"trajectory_window_size": 500,
|
|
33
|
+
"trajectory_window_step": 50,
|
|
34
|
+
"v_alpha_panic_threshold": -0.02,
|
|
35
|
+
"alpha_safety_floor": 0.10
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"high_sensitivity": {
|
|
39
|
+
"grg": {
|
|
40
|
+
"window_size": 16,
|
|
41
|
+
"ema_weight": 0.4,
|
|
42
|
+
"warmup_steps": 30,
|
|
43
|
+
"lr_slash_factor": 0.2,
|
|
44
|
+
"lr_restore_factor": 1.0,
|
|
45
|
+
"thermal_damping_min_temp": 0.02,
|
|
46
|
+
"e_stop_horizon": 3,
|
|
47
|
+
"collapse_v_alpha_threshold": -0.015,
|
|
48
|
+
"stability_v_alpha_threshold": 0.003,
|
|
49
|
+
"trajectory_window_size": 300,
|
|
50
|
+
"trajectory_window_step": 30,
|
|
51
|
+
"v_alpha_panic_threshold": -0.01,
|
|
52
|
+
"alpha_safety_floor": 0.15
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"low_latency": {
|
|
56
|
+
"grg": {
|
|
57
|
+
"window_size": 12,
|
|
58
|
+
"ema_weight": 0.5,
|
|
59
|
+
"warmup_steps": 20,
|
|
60
|
+
"lr_slash_factor": 0.5,
|
|
61
|
+
"lr_restore_factor": 1.0,
|
|
62
|
+
"thermal_damping_min_temp": 0.01,
|
|
63
|
+
"e_stop_horizon": 2,
|
|
64
|
+
"collapse_v_alpha_threshold": -0.025,
|
|
65
|
+
"stability_v_alpha_threshold": 0.008,
|
|
66
|
+
"trajectory_window_size": 200,
|
|
67
|
+
"trajectory_window_step": 20,
|
|
68
|
+
"v_alpha_panic_threshold": -0.03,
|
|
69
|
+
"alpha_safety_floor": 0.08
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"rag_grounded": {
|
|
73
|
+
"grg": {
|
|
74
|
+
"window_size": 24,
|
|
75
|
+
"ema_weight": 0.25,
|
|
76
|
+
"warmup_steps": 100,
|
|
77
|
+
"lr_slash_factor": 0.1,
|
|
78
|
+
"lr_restore_factor": 1.0,
|
|
79
|
+
"thermal_damping_min_temp": 0.005,
|
|
80
|
+
"e_stop_horizon": 8,
|
|
81
|
+
"collapse_v_alpha_threshold": -0.01,
|
|
82
|
+
"stability_v_alpha_threshold": 0.002,
|
|
83
|
+
"trajectory_window_size": 1000,
|
|
84
|
+
"trajectory_window_step": 100,
|
|
85
|
+
"v_alpha_panic_threshold": -0.005,
|
|
86
|
+
"alpha_safety_floor": 0.20
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|