@holoscript/framework 6.0.3
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.
- package/ALL-test-results.json +1 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/ROADMAP.md +175 -0
- package/dist/AgentManifest-CB4xM-Ma.d.cts +704 -0
- package/dist/AgentManifest-CB4xM-Ma.d.ts +704 -0
- package/dist/BehaviorTree-BrBFECv5.d.cts +103 -0
- package/dist/BehaviorTree-BrBFECv5.d.ts +103 -0
- package/dist/InvisibleWallet-BB6tFvRA.d.cts +1732 -0
- package/dist/InvisibleWallet-rtRrBOA8.d.ts +1732 -0
- package/dist/OrchestratorAgent-BvWgf9uw.d.cts +798 -0
- package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +798 -0
- package/dist/agents/index.cjs +4790 -0
- package/dist/agents/index.d.cts +1788 -0
- package/dist/agents/index.d.ts +1788 -0
- package/dist/agents/index.js +4695 -0
- package/dist/ai/index.cjs +5347 -0
- package/dist/ai/index.d.cts +1753 -0
- package/dist/ai/index.d.ts +1753 -0
- package/dist/ai/index.js +5244 -0
- package/dist/behavior.cjs +449 -0
- package/dist/behavior.d.cts +130 -0
- package/dist/behavior.d.ts +130 -0
- package/dist/behavior.js +407 -0
- package/dist/economy/index.cjs +3659 -0
- package/dist/economy/index.d.cts +747 -0
- package/dist/economy/index.d.ts +747 -0
- package/dist/economy/index.js +3617 -0
- package/dist/implementations-D9T3un9D.d.cts +236 -0
- package/dist/implementations-D9T3un9D.d.ts +236 -0
- package/dist/index.cjs +24550 -0
- package/dist/index.d.cts +1729 -0
- package/dist/index.d.ts +1729 -0
- package/dist/index.js +24277 -0
- package/dist/learning/index.cjs +219 -0
- package/dist/learning/index.d.cts +104 -0
- package/dist/learning/index.d.ts +104 -0
- package/dist/learning/index.js +189 -0
- package/dist/negotiation/index.cjs +970 -0
- package/dist/negotiation/index.d.cts +610 -0
- package/dist/negotiation/index.d.ts +610 -0
- package/dist/negotiation/index.js +931 -0
- package/dist/skills/index.cjs +1118 -0
- package/dist/skills/index.d.cts +289 -0
- package/dist/skills/index.d.ts +289 -0
- package/dist/skills/index.js +1079 -0
- package/dist/swarm/index.cjs +5268 -0
- package/dist/swarm/index.d.cts +2433 -0
- package/dist/swarm/index.d.ts +2433 -0
- package/dist/swarm/index.js +5221 -0
- package/dist/training/index.cjs +2745 -0
- package/dist/training/index.d.cts +1734 -0
- package/dist/training/index.d.ts +1734 -0
- package/dist/training/index.js +2687 -0
- package/extract-failures.js +10 -0
- package/package.json +82 -0
- package/src/__tests__/bounty-marketplace.test.ts +374 -0
- package/src/__tests__/delegation.test.ts +144 -0
- package/src/__tests__/distributed-claimer.test.ts +147 -0
- package/src/__tests__/done-log-audit.test.ts +342 -0
- package/src/__tests__/framework.test.ts +865 -0
- package/src/__tests__/goal-synthesizer.test.ts +236 -0
- package/src/__tests__/presence.test.ts +223 -0
- package/src/__tests__/protocol-agent.test.ts +254 -0
- package/src/__tests__/revenue-splitter.test.ts +114 -0
- package/src/__tests__/scenario-driven-todo.test.ts +197 -0
- package/src/__tests__/self-improve.test.ts +349 -0
- package/src/__tests__/service-lifecycle.test.ts +237 -0
- package/src/__tests__/skill-router.test.ts +121 -0
- package/src/agents/AgentManifest.ts +493 -0
- package/src/agents/AgentRegistry.ts +475 -0
- package/src/agents/AgentTypes.ts +585 -0
- package/src/agents/AgentWalletRegistry.ts +83 -0
- package/src/agents/AuthenticatedCRDT.ts +388 -0
- package/src/agents/CapabilityMatcher.ts +453 -0
- package/src/agents/CrossRealityHandoff.ts +305 -0
- package/src/agents/CulturalMemory.ts +454 -0
- package/src/agents/FederatedRegistryAdapter.ts +429 -0
- package/src/agents/NormEngine.ts +450 -0
- package/src/agents/OrchestratorAgent.ts +414 -0
- package/src/agents/SkillWorkflowEngine.ts +472 -0
- package/src/agents/TaskDelegationService.ts +551 -0
- package/src/agents/__tests__/AgentManifest.prod.test.ts +134 -0
- package/src/agents/__tests__/AgentManifest.test.ts +182 -0
- package/src/agents/__tests__/AgentModule.test.ts +864 -0
- package/src/agents/__tests__/AgentRegistry.prod.test.ts +125 -0
- package/src/agents/__tests__/AgentRegistry.test.ts +148 -0
- package/src/agents/__tests__/AgentTypes.test.ts +534 -0
- package/src/agents/__tests__/AgentWalletRegistry.test.ts +152 -0
- package/src/agents/__tests__/AuthenticatedCRDT.test.ts +558 -0
- package/src/agents/__tests__/CapabilityMatcher.prod.test.ts +117 -0
- package/src/agents/__tests__/CapabilityMatcher.test.ts +178 -0
- package/src/agents/__tests__/CrossRealityHandoff.test.ts +402 -0
- package/src/agents/__tests__/CulturalMemory.test.ts +200 -0
- package/src/agents/__tests__/FederatedRegistryAdapter.test.ts +409 -0
- package/src/agents/__tests__/NormEngine.test.ts +276 -0
- package/src/agents/__tests__/OrchestratorAgent.test.ts +182 -0
- package/src/agents/__tests__/SkillWorkflowEngine.test.ts +357 -0
- package/src/agents/__tests__/TaskDelegationService.test.ts +446 -0
- package/src/agents/index.ts +107 -0
- package/src/agents/spatial-comms/Layer1RealTime.ts +621 -0
- package/src/agents/spatial-comms/Layer2A2A.ts +661 -0
- package/src/agents/spatial-comms/Layer3MCP.ts +651 -0
- package/src/agents/spatial-comms/ProtocolTypes.ts +543 -0
- package/src/agents/spatial-comms/SpatialCommClient.ts +483 -0
- package/src/agents/spatial-comms/__tests__/performance-benchmark.test.ts +465 -0
- package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +409 -0
- package/src/agents/spatial-comms/index.ts +66 -0
- package/src/ai/AIAdapter.ts +313 -0
- package/src/ai/AICopilot.ts +331 -0
- package/src/ai/AIOutputValidator.ts +203 -0
- package/src/ai/BTNodes.ts +239 -0
- package/src/ai/BehaviorSelector.ts +135 -0
- package/src/ai/BehaviorTree.ts +153 -0
- package/src/ai/Blackboard.ts +165 -0
- package/src/ai/GenerationAnalytics.ts +461 -0
- package/src/ai/GenerationCache.ts +265 -0
- package/src/ai/GoalPlanner.ts +165 -0
- package/src/ai/HoloScriptGenerator.ts +580 -0
- package/src/ai/InfluenceMap.ts +180 -0
- package/src/ai/NavMesh.ts +168 -0
- package/src/ai/PerceptionSystem.ts +178 -0
- package/src/ai/PromptTemplates.ts +453 -0
- package/src/ai/SemanticSearchService.ts +80 -0
- package/src/ai/StateMachine.ts +196 -0
- package/src/ai/SteeringBehavior.ts +150 -0
- package/src/ai/SteeringBehaviors.ts +244 -0
- package/src/ai/TrainingDataGenerator.ts +1082 -0
- package/src/ai/UtilityAI.ts +145 -0
- package/src/ai/__tests__/AIAdapter.prod.test.ts +259 -0
- package/src/ai/__tests__/AIAdapter.test.ts +109 -0
- package/src/ai/__tests__/AICopilot.prod.test.ts +341 -0
- package/src/ai/__tests__/AICopilot.test.ts +178 -0
- package/src/ai/__tests__/AIOutputValidator.prod.test.ts +226 -0
- package/src/ai/__tests__/AIOutputValidator.test.ts +138 -0
- package/src/ai/__tests__/BTNodes.prod.test.ts +391 -0
- package/src/ai/__tests__/BTNodes.test.ts +263 -0
- package/src/ai/__tests__/BehaviorSelector.prod.test.ts +129 -0
- package/src/ai/__tests__/BehaviorSelector.test.ts +132 -0
- package/src/ai/__tests__/BehaviorTree.prod.test.ts +266 -0
- package/src/ai/__tests__/BehaviorTree.test.ts +216 -0
- package/src/ai/__tests__/Blackboard.prod.test.ts +339 -0
- package/src/ai/__tests__/Blackboard.test.ts +183 -0
- package/src/ai/__tests__/GenerationAnalytics.prod.test.ts +141 -0
- package/src/ai/__tests__/GenerationAnalytics.test.ts +165 -0
- package/src/ai/__tests__/GenerationCache.prod.test.ts +144 -0
- package/src/ai/__tests__/GenerationCache.test.ts +171 -0
- package/src/ai/__tests__/GoalPlanner.prod.test.ts +189 -0
- package/src/ai/__tests__/GoalPlanner.test.ts +137 -0
- package/src/ai/__tests__/GoalPlannerDepth.prod.test.ts +217 -0
- package/src/ai/__tests__/HoloScriptGenerator.test.ts +125 -0
- package/src/ai/__tests__/InfluenceMap.prod.test.ts +146 -0
- package/src/ai/__tests__/InfluenceMap.test.ts +149 -0
- package/src/ai/__tests__/NavMesh.prod.test.ts +141 -0
- package/src/ai/__tests__/NavMesh.test.ts +159 -0
- package/src/ai/__tests__/PerceptionSystem.prod.test.ts +135 -0
- package/src/ai/__tests__/PerceptionSystem.test.ts +250 -0
- package/src/ai/__tests__/PromptTemplates.prod.test.ts +313 -0
- package/src/ai/__tests__/PromptTemplates.test.ts +146 -0
- package/src/ai/__tests__/SemanticSearch.test.ts +37 -0
- package/src/ai/__tests__/StateMachine.prod.test.ts +162 -0
- package/src/ai/__tests__/StateMachine.test.ts +163 -0
- package/src/ai/__tests__/SteeringBehavior.prod.test.ts +251 -0
- package/src/ai/__tests__/SteeringBehavior.test.ts +135 -0
- package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +133 -0
- package/src/ai/__tests__/SteeringBehaviors.test.ts +151 -0
- package/src/ai/__tests__/TrainingDataGenerator.prod.test.ts +286 -0
- package/src/ai/__tests__/TrainingDataGenerator.test.ts +286 -0
- package/src/ai/__tests__/UtilityAI.prod.test.ts +207 -0
- package/src/ai/__tests__/UtilityAI.test.ts +155 -0
- package/src/ai/__tests__/adapters.prod.test.ts +263 -0
- package/src/ai/__tests__/adapters.test.ts +320 -0
- package/src/ai/adapters.ts +1585 -0
- package/src/ai/index.ts +130 -0
- package/src/behavior/BehaviorPresets.ts +140 -0
- package/src/behavior/BehaviorTree.ts +236 -0
- package/src/behavior/StateMachine.ts +176 -0
- package/src/behavior/StateTrait.ts +67 -0
- package/src/behavior/index.ts +8 -0
- package/src/behavior.ts +8 -0
- package/src/board/audit.ts +284 -0
- package/src/board/board-ops.ts +336 -0
- package/src/board/board-types.ts +302 -0
- package/src/board/index.ts +69 -0
- package/src/define-agent.ts +46 -0
- package/src/define-team.ts +33 -0
- package/src/delegation.ts +265 -0
- package/src/distributed-claimer.ts +228 -0
- package/src/economy/AgentBudgetEnforcer.ts +464 -0
- package/src/economy/BountyManager.ts +185 -0
- package/src/economy/CreatorRevenueAggregator.ts +460 -0
- package/src/economy/InvisibleWallet.ts +82 -0
- package/src/economy/KnowledgeMarketplace.ts +193 -0
- package/src/economy/PaymentWebhookService.ts +512 -0
- package/src/economy/RevenueSplitter.ts +156 -0
- package/src/economy/SubscriptionManager.ts +546 -0
- package/src/economy/UnifiedBudgetOptimizer.ts +635 -0
- package/src/economy/UsageMeter.ts +440 -0
- package/src/economy/_core-stubs.ts +219 -0
- package/src/economy/index.ts +100 -0
- package/src/economy/x402-facilitator.ts +1978 -0
- package/src/index.ts +348 -0
- package/src/knowledge/__tests__/knowledge-consolidator.test.ts +444 -0
- package/src/knowledge/__tests__/knowledge-store-vector.test.ts +291 -0
- package/src/knowledge/brain.ts +167 -0
- package/src/knowledge/consolidation.ts +581 -0
- package/src/knowledge/knowledge-consolidator.ts +510 -0
- package/src/knowledge/knowledge-store.ts +616 -0
- package/src/learning/MemoryConsolidator.ts +102 -0
- package/src/learning/MemoryScorer.ts +69 -0
- package/src/learning/ProceduralCompiler.ts +45 -0
- package/src/learning/SemanticClusterer.ts +66 -0
- package/src/learning/index.ts +8 -0
- package/src/llm/llm-adapter.ts +159 -0
- package/src/mesh/index.ts +309 -0
- package/src/negotiation/NegotiationProtocol.ts +694 -0
- package/src/negotiation/NegotiationTypes.ts +473 -0
- package/src/negotiation/VotingMechanisms.ts +691 -0
- package/src/negotiation/index.ts +49 -0
- package/src/protocol/goal-synthesizer.ts +317 -0
- package/src/protocol/implementations.ts +474 -0
- package/src/protocol/micro-phase-decomposer.ts +299 -0
- package/src/protocol/micro-step-decomposer.test.ts +306 -0
- package/src/protocol-agent.test.ts +353 -0
- package/src/protocol-agent.ts +670 -0
- package/src/self-improve/absorb-scanner.ts +252 -0
- package/src/self-improve/evolution-engine.ts +149 -0
- package/src/self-improve/framework-absorber.ts +214 -0
- package/src/self-improve/index.ts +50 -0
- package/src/self-improve/prompt-optimizer.ts +212 -0
- package/src/self-improve/test-generator.ts +175 -0
- package/src/skill-router.ts +186 -0
- package/src/skills/index.ts +5 -0
- package/src/skills/skill-md-bridge.ts +1699 -0
- package/src/swarm/ACOEngine.ts +261 -0
- package/src/swarm/CollectiveIntelligence.ts +383 -0
- package/src/swarm/ContributionSynthesizer.ts +481 -0
- package/src/swarm/LeaderElection.ts +393 -0
- package/src/swarm/PSOEngine.ts +206 -0
- package/src/swarm/QuorumPolicy.ts +173 -0
- package/src/swarm/SwarmCoordinator.ts +335 -0
- package/src/swarm/SwarmManager.ts +442 -0
- package/src/swarm/SwarmMembership.ts +456 -0
- package/src/swarm/VotingRound.ts +255 -0
- package/src/swarm/__tests__/ACOEngine.prod.test.ts +164 -0
- package/src/swarm/__tests__/ACOEngine.test.ts +117 -0
- package/src/swarm/__tests__/CollectiveIntelligence.prod.test.ts +296 -0
- package/src/swarm/__tests__/CollectiveIntelligence.test.ts +457 -0
- package/src/swarm/__tests__/ContributionSynthesizer.prod.test.ts +269 -0
- package/src/swarm/__tests__/ContributionSynthesizer.test.ts +254 -0
- package/src/swarm/__tests__/LeaderElection.prod.test.ts +196 -0
- package/src/swarm/__tests__/LeaderElection.test.ts +151 -0
- package/src/swarm/__tests__/PSOEngine.prod.test.ts +162 -0
- package/src/swarm/__tests__/PSOEngine.test.ts +106 -0
- package/src/swarm/__tests__/QuorumPolicy.prod.test.ts +216 -0
- package/src/swarm/__tests__/QuorumPolicy.test.ts +177 -0
- package/src/swarm/__tests__/SwarmCoordinator.prod.test.ts +186 -0
- package/src/swarm/__tests__/SwarmCoordinator.test.ts +167 -0
- package/src/swarm/__tests__/SwarmManager.prod.test.ts +308 -0
- package/src/swarm/__tests__/SwarmManager.test.ts +373 -0
- package/src/swarm/__tests__/SwarmMembership.prod.test.ts +273 -0
- package/src/swarm/__tests__/SwarmMembership.test.ts +264 -0
- package/src/swarm/__tests__/VotingRound.prod.test.ts +233 -0
- package/src/swarm/__tests__/VotingRound.test.ts +174 -0
- package/src/swarm/analytics/SwarmInspector.ts +476 -0
- package/src/swarm/analytics/SwarmMetrics.ts +449 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.prod.test.ts +366 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.test.ts +454 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.prod.test.ts +254 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.test.ts +370 -0
- package/src/swarm/analytics/index.ts +7 -0
- package/src/swarm/index.ts +69 -0
- package/src/swarm/messaging/BroadcastChannel.ts +509 -0
- package/src/swarm/messaging/GossipProtocol.ts +565 -0
- package/src/swarm/messaging/SwarmEventBus.ts +443 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +331 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.test.ts +333 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +356 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.test.ts +437 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +191 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +247 -0
- package/src/swarm/messaging/index.ts +8 -0
- package/src/swarm/spatial/FlockingBehavior.ts +462 -0
- package/src/swarm/spatial/FormationController.ts +500 -0
- package/src/swarm/spatial/Vector3.ts +170 -0
- package/src/swarm/spatial/ZoneClaiming.ts +509 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.prod.test.ts +239 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.test.ts +298 -0
- package/src/swarm/spatial/__tests__/FormationController.prod.test.ts +240 -0
- package/src/swarm/spatial/__tests__/FormationController.test.ts +297 -0
- package/src/swarm/spatial/__tests__/Vector3.prod.test.ts +283 -0
- package/src/swarm/spatial/__tests__/Vector3.test.ts +224 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.prod.test.ts +246 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.test.ts +374 -0
- package/src/swarm/spatial/index.ts +28 -0
- package/src/team.ts +1245 -0
- package/src/training/LRScheduler.ts +377 -0
- package/src/training/QualityScoringPipeline.ts +139 -0
- package/src/training/SoftDedup.ts +461 -0
- package/src/training/SparsityMonitor.ts +685 -0
- package/src/training/SparsityMonitorTypes.ts +209 -0
- package/src/training/SpatialTrainingDataGenerator.ts +1526 -0
- package/src/training/SpatialTrainingDataTypes.ts +216 -0
- package/src/training/TrainingPipelineConfig.ts +215 -0
- package/src/training/constants.ts +94 -0
- package/src/training/index.ts +138 -0
- package/src/training/schema.ts +147 -0
- package/src/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
- package/src/training/scripts/generate-spatial-dataset.ts +521 -0
- package/src/training/training/data/novel-use-cases.jsonl +153 -0
- package/src/training/training/data/spatial-reasoning-10k.jsonl +9354 -0
- package/src/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
- package/src/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
- package/src/training/trainingmonkey/index.ts +26 -0
- package/src/training/trait-mappings.ts +157 -0
- package/src/types/core-stubs.d.ts +113 -0
- package/src/types.ts +304 -0
- package/test-output.txt +0 -0
- package/test-result.json +1 -0
- package/tsc-errors.txt +4 -0
- package/tsc_output.txt +0 -0
- package/tsconfig.json +14 -0
- package/tsup-learning-esm.config.ts +12 -0
- package/tsup.config.ts +21 -0
- package/typescript-errors-2.txt +0 -0
- package/typescript-errors.txt +22 -0
- package/vitest-log-utf8.txt +268 -0
- package/vitest-log.txt +0 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SparsityMonitor.ts
|
|
3
|
+
*
|
|
4
|
+
* Monitors SNN (Spiking Neural Network) sparsity during simulation,
|
|
5
|
+
* tracking spike rates and activation sparsity across layers, calculating
|
|
6
|
+
* energy efficiency metrics, and detecting sparsity regime violations.
|
|
7
|
+
*
|
|
8
|
+
* Integrates with the self-improvement pipeline via:
|
|
9
|
+
* - SelfImproveHarvester: provides metrics for continuous quality monitoring
|
|
10
|
+
* - quality-history.json: outputs compatible entries for historical tracking
|
|
11
|
+
*
|
|
12
|
+
* Key threshold (W.041): SNN layers must maintain >= 93% activation sparsity.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ```ts
|
|
16
|
+
* const monitor = new SparsityMonitor({ sparsityThreshold: 0.93 });
|
|
17
|
+
*
|
|
18
|
+
* // Record layer activity during simulation
|
|
19
|
+
* monitor.recordLayerActivity('lif_hidden_1', {
|
|
20
|
+
* neuronCount: 1000,
|
|
21
|
+
* spikeCount: 50,
|
|
22
|
+
* timestep: 0,
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Take a snapshot
|
|
26
|
+
* const snapshot = monitor.takeSnapshot();
|
|
27
|
+
*
|
|
28
|
+
* // Check for violations
|
|
29
|
+
* const violations = monitor.getActiveViolations();
|
|
30
|
+
*
|
|
31
|
+
* // Get quality-history.json compatible entry
|
|
32
|
+
* const entry = monitor.toQualityHistoryEntry(1);
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @module training/SparsityMonitor
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import type {
|
|
39
|
+
SNNLayerMetrics,
|
|
40
|
+
SparsitySnapshot,
|
|
41
|
+
EnergyEfficiencyMetrics,
|
|
42
|
+
SparsityViolation,
|
|
43
|
+
SparsityMonitorConfig,
|
|
44
|
+
SparsityMonitorStats,
|
|
45
|
+
SparsityQualityHistoryEntry,
|
|
46
|
+
} from './SparsityMonitorTypes';
|
|
47
|
+
|
|
48
|
+
// =============================================================================
|
|
49
|
+
// DEFAULTS
|
|
50
|
+
// =============================================================================
|
|
51
|
+
|
|
52
|
+
const DEFAULT_CONFIG: SparsityMonitorConfig = {
|
|
53
|
+
sparsityThreshold: 0.93,
|
|
54
|
+
windowSize: 50,
|
|
55
|
+
perLayerTracking: true,
|
|
56
|
+
energyMetricsEnabled: true,
|
|
57
|
+
avgSynapsesPerNeuron: 100,
|
|
58
|
+
opsPerSynapse: 2,
|
|
59
|
+
criticalThreshold: 0.85,
|
|
60
|
+
maxViolationHistory: 1000,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// =============================================================================
|
|
64
|
+
// INPUT TYPE FOR RECORDING ACTIVITY
|
|
65
|
+
// =============================================================================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Input data for recording layer activity. The monitor computes
|
|
69
|
+
* derived fields (spikeRate, activationSparsity) from these inputs.
|
|
70
|
+
*/
|
|
71
|
+
export interface LayerActivityInput {
|
|
72
|
+
/** Total number of neurons in the layer */
|
|
73
|
+
neuronCount: number;
|
|
74
|
+
/** Number of neurons that spiked */
|
|
75
|
+
spikeCount: number;
|
|
76
|
+
/** Simulation timestep index */
|
|
77
|
+
timestep: number;
|
|
78
|
+
/** Optional: average membrane potential */
|
|
79
|
+
avgMembranePotential?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// =============================================================================
|
|
83
|
+
// SPARSITY MONITOR
|
|
84
|
+
// =============================================================================
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Monitors SNN activation sparsity across layers during simulation.
|
|
88
|
+
*
|
|
89
|
+
* Provides:
|
|
90
|
+
* 1. Per-layer spike rate and activation sparsity tracking
|
|
91
|
+
* 2. Energy efficiency calculation (theoretical ops saved via sparsity)
|
|
92
|
+
* 3. Sparsity regime violation detection (W.041: >= 93% threshold)
|
|
93
|
+
* 4. Integration with SelfImproveHarvester for continuous quality monitoring
|
|
94
|
+
* 5. Output compatible with quality-history.json format
|
|
95
|
+
*/
|
|
96
|
+
export class SparsityMonitor {
|
|
97
|
+
private config: SparsityMonitorConfig;
|
|
98
|
+
|
|
99
|
+
/** Current layer metrics indexed by layerId, latest values per layer */
|
|
100
|
+
private currentLayerMetrics: Map<string, SNNLayerMetrics> = new Map();
|
|
101
|
+
|
|
102
|
+
/** Historical layer metrics: layerId -> array of metrics over time */
|
|
103
|
+
private layerHistory: Map<string, SNNLayerMetrics[]> = new Map();
|
|
104
|
+
|
|
105
|
+
/** Snapshots taken over time */
|
|
106
|
+
private snapshots: SparsitySnapshot[] = [];
|
|
107
|
+
|
|
108
|
+
/** Detected violations */
|
|
109
|
+
private violations: SparsityViolation[] = [];
|
|
110
|
+
|
|
111
|
+
/** Rolling window of aggregate sparsity values for stats */
|
|
112
|
+
private sparsityWindow: number[] = [];
|
|
113
|
+
|
|
114
|
+
/** Total timesteps recorded across all layers */
|
|
115
|
+
private totalTimestepsRecorded = 0;
|
|
116
|
+
|
|
117
|
+
constructor(config: Partial<SparsityMonitorConfig> = {}) {
|
|
118
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// Recording
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Record activity for a single SNN layer at a given timestep.
|
|
127
|
+
*
|
|
128
|
+
* Computes spike rate and activation sparsity from the raw input,
|
|
129
|
+
* checks for threshold violations, and stores the metrics.
|
|
130
|
+
*
|
|
131
|
+
* @param layerId - Unique identifier for the layer
|
|
132
|
+
* @param input - Raw activity data (neuronCount, spikeCount, timestep)
|
|
133
|
+
* @returns The computed SNNLayerMetrics for this recording
|
|
134
|
+
*/
|
|
135
|
+
recordLayerActivity(layerId: string, input: LayerActivityInput): SNNLayerMetrics {
|
|
136
|
+
if (input.neuronCount <= 0) {
|
|
137
|
+
throw new Error(`neuronCount must be positive, got ${input.neuronCount}`);
|
|
138
|
+
}
|
|
139
|
+
if (input.spikeCount < 0) {
|
|
140
|
+
throw new Error(`spikeCount must be non-negative, got ${input.spikeCount}`);
|
|
141
|
+
}
|
|
142
|
+
if (input.spikeCount > input.neuronCount) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`spikeCount (${input.spikeCount}) cannot exceed neuronCount (${input.neuronCount})`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const spikeRate = input.spikeCount / input.neuronCount;
|
|
149
|
+
const activationSparsity = 1 - spikeRate;
|
|
150
|
+
|
|
151
|
+
const metrics: SNNLayerMetrics = {
|
|
152
|
+
layerId,
|
|
153
|
+
neuronCount: input.neuronCount,
|
|
154
|
+
spikeCount: input.spikeCount,
|
|
155
|
+
spikeRate: roundTo4(spikeRate),
|
|
156
|
+
activationSparsity: roundTo4(activationSparsity),
|
|
157
|
+
avgMembranePotential: input.avgMembranePotential,
|
|
158
|
+
timestep: input.timestep,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Store current metrics
|
|
162
|
+
this.currentLayerMetrics.set(layerId, metrics);
|
|
163
|
+
|
|
164
|
+
// Track history if per-layer tracking is enabled
|
|
165
|
+
if (this.config.perLayerTracking) {
|
|
166
|
+
if (!this.layerHistory.has(layerId)) {
|
|
167
|
+
this.layerHistory.set(layerId, []);
|
|
168
|
+
}
|
|
169
|
+
this.layerHistory.get(layerId)!.push(metrics);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.totalTimestepsRecorded++;
|
|
173
|
+
|
|
174
|
+
// Check for violations
|
|
175
|
+
this.checkViolation(metrics);
|
|
176
|
+
|
|
177
|
+
return metrics;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Record activity for multiple layers at the same timestep (batch recording).
|
|
182
|
+
*
|
|
183
|
+
* @param layerInputs - Map of layerId -> activity input
|
|
184
|
+
* @returns Array of computed metrics for each layer
|
|
185
|
+
*/
|
|
186
|
+
recordBatchActivity(
|
|
187
|
+
layerInputs: Map<string, LayerActivityInput> | Record<string, LayerActivityInput>
|
|
188
|
+
): SNNLayerMetrics[] {
|
|
189
|
+
const entries =
|
|
190
|
+
layerInputs instanceof Map ? Array.from(layerInputs.entries()) : Object.entries(layerInputs);
|
|
191
|
+
|
|
192
|
+
return entries.map(([layerId, input]) => this.recordLayerActivity(layerId, input));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Snapshots
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Take a point-in-time snapshot of all current layer metrics.
|
|
201
|
+
*
|
|
202
|
+
* The snapshot captures aggregate statistics across all tracked layers,
|
|
203
|
+
* computes energy efficiency, and checks for violations.
|
|
204
|
+
*
|
|
205
|
+
* @returns The snapshot, or null if no layer metrics have been recorded
|
|
206
|
+
*/
|
|
207
|
+
takeSnapshot(): SparsitySnapshot | null {
|
|
208
|
+
if (this.currentLayerMetrics.size === 0) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const layers = Array.from(this.currentLayerMetrics.values());
|
|
213
|
+
const totalNeurons = layers.reduce((sum, l) => sum + l.neuronCount, 0);
|
|
214
|
+
const totalSpikes = layers.reduce((sum, l) => sum + l.spikeCount, 0);
|
|
215
|
+
|
|
216
|
+
// Weighted aggregate sparsity (weighted by neuron count per layer)
|
|
217
|
+
const aggregateSparsity = totalNeurons > 0 ? roundTo4(1 - totalSpikes / totalNeurons) : 1;
|
|
218
|
+
|
|
219
|
+
const aggregateSpikeRate = totalNeurons > 0 ? roundTo4(totalSpikes / totalNeurons) : 0;
|
|
220
|
+
|
|
221
|
+
// Energy efficiency
|
|
222
|
+
const energyEfficiency = this.config.energyMetricsEnabled
|
|
223
|
+
? this.calculateEnergyEfficiency(layers)
|
|
224
|
+
: createZeroEnergyMetrics();
|
|
225
|
+
|
|
226
|
+
// Detect violations in this snapshot
|
|
227
|
+
const violations = this.detectViolationsForLayers(layers);
|
|
228
|
+
|
|
229
|
+
const snapshot: SparsitySnapshot = {
|
|
230
|
+
timestamp: new Date().toISOString(),
|
|
231
|
+
layers: layers.map((l) => ({ ...l })),
|
|
232
|
+
aggregateSparsity,
|
|
233
|
+
aggregateSpikeRate,
|
|
234
|
+
totalNeurons,
|
|
235
|
+
totalSpikes,
|
|
236
|
+
energyEfficiency,
|
|
237
|
+
violations,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
this.snapshots.push(snapshot);
|
|
241
|
+
|
|
242
|
+
// Update rolling sparsity window
|
|
243
|
+
this.sparsityWindow.push(aggregateSparsity);
|
|
244
|
+
if (this.sparsityWindow.length > this.config.windowSize) {
|
|
245
|
+
this.sparsityWindow.shift();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return snapshot;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ---------------------------------------------------------------------------
|
|
252
|
+
// Energy Efficiency
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Calculate theoretical energy efficiency metrics for the given layers.
|
|
257
|
+
*
|
|
258
|
+
* Dense ops = sum of (neuronCount * avgSynapsesPerNeuron * opsPerSynapse) per layer
|
|
259
|
+
* Sparse ops = sum of (spikeCount * avgSynapsesPerNeuron * opsPerSynapse) per layer
|
|
260
|
+
*
|
|
261
|
+
* The ratio of ops saved reflects the theoretical computational advantage
|
|
262
|
+
* of SNN sparsity over equivalent dense ANN computation.
|
|
263
|
+
*/
|
|
264
|
+
calculateEnergyEfficiency(layers: SNNLayerMetrics[]): EnergyEfficiencyMetrics {
|
|
265
|
+
const { avgSynapsesPerNeuron, opsPerSynapse } = this.config;
|
|
266
|
+
|
|
267
|
+
let denseOps = 0;
|
|
268
|
+
let sparseOps = 0;
|
|
269
|
+
|
|
270
|
+
for (const layer of layers) {
|
|
271
|
+
const layerDenseOps = layer.neuronCount * avgSynapsesPerNeuron * opsPerSynapse;
|
|
272
|
+
const layerSparseOps = layer.spikeCount * avgSynapsesPerNeuron * opsPerSynapse;
|
|
273
|
+
denseOps += layerDenseOps;
|
|
274
|
+
sparseOps += layerSparseOps;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const opsSaved = denseOps - sparseOps;
|
|
278
|
+
const efficiencyRatio = denseOps > 0 ? roundTo4(opsSaved / denseOps) : 0;
|
|
279
|
+
const energySavingsFactor = denseOps > 0 ? roundTo4(denseOps / Math.max(1, sparseOps)) : 1;
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
denseOps,
|
|
283
|
+
sparseOps,
|
|
284
|
+
opsSaved,
|
|
285
|
+
efficiencyRatio,
|
|
286
|
+
energySavingsFactor,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// Violation Detection
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Check a single layer's metrics against the sparsity threshold.
|
|
296
|
+
* If a violation is detected, it is recorded in the violations history.
|
|
297
|
+
*/
|
|
298
|
+
private checkViolation(metrics: SNNLayerMetrics): SparsityViolation | null {
|
|
299
|
+
if (metrics.activationSparsity >= this.config.sparsityThreshold) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const deficit = roundTo4(this.config.sparsityThreshold - metrics.activationSparsity);
|
|
304
|
+
const severity: SparsityViolation['severity'] =
|
|
305
|
+
metrics.activationSparsity < this.config.criticalThreshold ? 'critical' : 'warning';
|
|
306
|
+
|
|
307
|
+
const violation: SparsityViolation = {
|
|
308
|
+
layerId: metrics.layerId,
|
|
309
|
+
measuredSparsity: metrics.activationSparsity,
|
|
310
|
+
requiredThreshold: this.config.sparsityThreshold,
|
|
311
|
+
deficit,
|
|
312
|
+
severity,
|
|
313
|
+
detectedAt: new Date().toISOString(),
|
|
314
|
+
timestep: metrics.timestep,
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
this.violations.push(violation);
|
|
318
|
+
|
|
319
|
+
// Trim violation history if it exceeds the maximum
|
|
320
|
+
if (this.violations.length > this.config.maxViolationHistory) {
|
|
321
|
+
this.violations = this.violations.slice(-this.config.maxViolationHistory);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return violation;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Detect violations for an array of layer metrics (used in snapshots).
|
|
329
|
+
*/
|
|
330
|
+
private detectViolationsForLayers(layers: SNNLayerMetrics[]): SparsityViolation[] {
|
|
331
|
+
const snapshotViolations: SparsityViolation[] = [];
|
|
332
|
+
for (const layer of layers) {
|
|
333
|
+
if (layer.activationSparsity < this.config.sparsityThreshold) {
|
|
334
|
+
const deficit = roundTo4(this.config.sparsityThreshold - layer.activationSparsity);
|
|
335
|
+
const severity: SparsityViolation['severity'] =
|
|
336
|
+
layer.activationSparsity < this.config.criticalThreshold ? 'critical' : 'warning';
|
|
337
|
+
|
|
338
|
+
snapshotViolations.push({
|
|
339
|
+
layerId: layer.layerId,
|
|
340
|
+
measuredSparsity: layer.activationSparsity,
|
|
341
|
+
requiredThreshold: this.config.sparsityThreshold,
|
|
342
|
+
deficit,
|
|
343
|
+
severity,
|
|
344
|
+
detectedAt: new Date().toISOString(),
|
|
345
|
+
timestep: layer.timestep,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return snapshotViolations;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Get all violations currently affecting active layers
|
|
354
|
+
* (the most recent metric per layer that is below threshold).
|
|
355
|
+
*/
|
|
356
|
+
getActiveViolations(): SparsityViolation[] {
|
|
357
|
+
const active: SparsityViolation[] = [];
|
|
358
|
+
for (const [, metrics] of this.currentLayerMetrics) {
|
|
359
|
+
if (metrics.activationSparsity < this.config.sparsityThreshold) {
|
|
360
|
+
const deficit = roundTo4(this.config.sparsityThreshold - metrics.activationSparsity);
|
|
361
|
+
const severity: SparsityViolation['severity'] =
|
|
362
|
+
metrics.activationSparsity < this.config.criticalThreshold ? 'critical' : 'warning';
|
|
363
|
+
active.push({
|
|
364
|
+
layerId: metrics.layerId,
|
|
365
|
+
measuredSparsity: metrics.activationSparsity,
|
|
366
|
+
requiredThreshold: this.config.sparsityThreshold,
|
|
367
|
+
deficit,
|
|
368
|
+
severity,
|
|
369
|
+
detectedAt: new Date().toISOString(),
|
|
370
|
+
timestep: metrics.timestep,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return active;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Get all historical violations.
|
|
379
|
+
*/
|
|
380
|
+
getViolationHistory(): SparsityViolation[] {
|
|
381
|
+
return [...this.violations];
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
// Statistics
|
|
386
|
+
// ---------------------------------------------------------------------------
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Compute aggregate statistics across all recorded data.
|
|
390
|
+
*/
|
|
391
|
+
getStats(): SparsityMonitorStats {
|
|
392
|
+
const allSparsities: number[] = [];
|
|
393
|
+
const perLayerSums: Record<string, { sum: number; count: number }> = {};
|
|
394
|
+
|
|
395
|
+
for (const [layerId, history] of this.layerHistory) {
|
|
396
|
+
for (const m of history) {
|
|
397
|
+
allSparsities.push(m.activationSparsity);
|
|
398
|
+
if (!perLayerSums[layerId]) {
|
|
399
|
+
perLayerSums[layerId] = { sum: 0, count: 0 };
|
|
400
|
+
}
|
|
401
|
+
perLayerSums[layerId].sum += m.activationSparsity;
|
|
402
|
+
perLayerSums[layerId].count++;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// If no per-layer history, fall back to current metrics
|
|
407
|
+
if (allSparsities.length === 0) {
|
|
408
|
+
for (const [layerId, m] of this.currentLayerMetrics) {
|
|
409
|
+
allSparsities.push(m.activationSparsity);
|
|
410
|
+
perLayerSums[layerId] = { sum: m.activationSparsity, count: 1 };
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const meanSparsity =
|
|
415
|
+
allSparsities.length > 0
|
|
416
|
+
? roundTo4(allSparsities.reduce((a, b) => a + b, 0) / allSparsities.length)
|
|
417
|
+
: 0;
|
|
418
|
+
|
|
419
|
+
const minSparsity = allSparsities.length > 0 ? Math.min(...allSparsities) : 0;
|
|
420
|
+
|
|
421
|
+
const maxSparsity = allSparsities.length > 0 ? Math.max(...allSparsities) : 0;
|
|
422
|
+
|
|
423
|
+
const stdDevSparsity =
|
|
424
|
+
allSparsities.length > 1 ? roundTo4(standardDeviation(allSparsities)) : 0;
|
|
425
|
+
|
|
426
|
+
const perLayerMeanSparsity: Record<string, number> = {};
|
|
427
|
+
for (const [layerId, data] of Object.entries(perLayerSums)) {
|
|
428
|
+
perLayerMeanSparsity[layerId] = roundTo4(data.sum / data.count);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const warningCount = this.violations.filter((v) => v.severity === 'warning').length;
|
|
432
|
+
const criticalCount = this.violations.filter((v) => v.severity === 'critical').length;
|
|
433
|
+
|
|
434
|
+
// Mean energy efficiency from snapshots
|
|
435
|
+
const efficiencies = this.snapshots
|
|
436
|
+
.map((s) => s.energyEfficiency.efficiencyRatio)
|
|
437
|
+
.filter((e) => e > 0);
|
|
438
|
+
const meanEnergyEfficiency =
|
|
439
|
+
efficiencies.length > 0
|
|
440
|
+
? roundTo4(efficiencies.reduce((a, b) => a + b, 0) / efficiencies.length)
|
|
441
|
+
: 0;
|
|
442
|
+
|
|
443
|
+
const activeViolations = this.getActiveViolations();
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
totalTimesteps: this.totalTimestepsRecorded,
|
|
447
|
+
totalSnapshots: this.snapshots.length,
|
|
448
|
+
trackedLayers: this.currentLayerMetrics.size,
|
|
449
|
+
meanSparsity,
|
|
450
|
+
minSparsity,
|
|
451
|
+
maxSparsity,
|
|
452
|
+
stdDevSparsity,
|
|
453
|
+
totalViolations: this.violations.length,
|
|
454
|
+
violationsBySeverity: {
|
|
455
|
+
warning: warningCount,
|
|
456
|
+
critical: criticalCount,
|
|
457
|
+
},
|
|
458
|
+
perLayerMeanSparsity,
|
|
459
|
+
meanEnergyEfficiency,
|
|
460
|
+
inCompliance: activeViolations.length === 0,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// ---------------------------------------------------------------------------
|
|
465
|
+
// Quality History Integration
|
|
466
|
+
// ---------------------------------------------------------------------------
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Generate an entry compatible with the quality-history.json format.
|
|
470
|
+
*
|
|
471
|
+
* The composite score is based on the aggregate sparsity relative to
|
|
472
|
+
* the threshold: score = min(1, aggregateSparsity / threshold).
|
|
473
|
+
*
|
|
474
|
+
* @param cycle - The monitoring cycle number
|
|
475
|
+
* @returns A quality history entry with sparsity-specific metrics
|
|
476
|
+
*/
|
|
477
|
+
toQualityHistoryEntry(cycle: number): SparsityQualityHistoryEntry {
|
|
478
|
+
const stats = this.getStats();
|
|
479
|
+
const latestSnapshot =
|
|
480
|
+
this.snapshots.length > 0 ? this.snapshots[this.snapshots.length - 1] : null;
|
|
481
|
+
|
|
482
|
+
const aggregateSparsity = latestSnapshot?.aggregateSparsity ?? stats.meanSparsity;
|
|
483
|
+
const aggregateSpikeRate = latestSnapshot?.aggregateSpikeRate ?? 1 - stats.meanSparsity;
|
|
484
|
+
|
|
485
|
+
// Composite score: how well the system meets the sparsity threshold
|
|
486
|
+
// 1.0 = at or above threshold, scales linearly below
|
|
487
|
+
const composite = roundTo4(Math.min(1, aggregateSparsity / this.config.sparsityThreshold));
|
|
488
|
+
|
|
489
|
+
const grade = gradeFromComposite(composite);
|
|
490
|
+
|
|
491
|
+
const summary = this.generateSummary(stats, latestSnapshot, composite, grade);
|
|
492
|
+
|
|
493
|
+
return {
|
|
494
|
+
timestamp: new Date().toISOString(),
|
|
495
|
+
cycle,
|
|
496
|
+
composite,
|
|
497
|
+
grade,
|
|
498
|
+
focus: 'snn-sparsity',
|
|
499
|
+
summary,
|
|
500
|
+
sparsityMetrics: {
|
|
501
|
+
aggregateSparsity,
|
|
502
|
+
aggregateSpikeRate: roundTo4(aggregateSpikeRate),
|
|
503
|
+
energyEfficiencyRatio: stats.meanEnergyEfficiency,
|
|
504
|
+
violationCount: stats.totalViolations,
|
|
505
|
+
layerCount: stats.trackedLayers,
|
|
506
|
+
totalNeurons: latestSnapshot?.totalNeurons ?? 0,
|
|
507
|
+
inCompliance: stats.inCompliance,
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Generate a human-readable summary string for the quality history entry.
|
|
514
|
+
*/
|
|
515
|
+
private generateSummary(
|
|
516
|
+
stats: SparsityMonitorStats,
|
|
517
|
+
latestSnapshot: SparsitySnapshot | null,
|
|
518
|
+
composite: number,
|
|
519
|
+
grade: SparsityQualityHistoryEntry['grade']
|
|
520
|
+
): string {
|
|
521
|
+
const lines: string[] = [];
|
|
522
|
+
|
|
523
|
+
lines.push(`SNN Sparsity Monitor - Grade: ${grade} (${(composite * 100).toFixed(1)}%)`);
|
|
524
|
+
lines.push(`Layers: ${stats.trackedLayers}, Timesteps: ${stats.totalTimesteps}`);
|
|
525
|
+
lines.push(
|
|
526
|
+
`Mean Sparsity: ${(stats.meanSparsity * 100).toFixed(1)}% (threshold: ${(this.config.sparsityThreshold * 100).toFixed(0)}%)`
|
|
527
|
+
);
|
|
528
|
+
lines.push(
|
|
529
|
+
`Range: [${(stats.minSparsity * 100).toFixed(1)}%, ${(stats.maxSparsity * 100).toFixed(1)}%]`
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
if (latestSnapshot) {
|
|
533
|
+
const eff = latestSnapshot.energyEfficiency;
|
|
534
|
+
lines.push(
|
|
535
|
+
`Energy Efficiency: ${(eff.efficiencyRatio * 100).toFixed(1)}% ops saved (${eff.energySavingsFactor.toFixed(1)}x factor)`
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (stats.totalViolations > 0) {
|
|
540
|
+
lines.push(
|
|
541
|
+
`Violations: ${stats.totalViolations} (${stats.violationsBySeverity.critical} critical, ${stats.violationsBySeverity.warning} warning)`
|
|
542
|
+
);
|
|
543
|
+
} else {
|
|
544
|
+
lines.push('Compliance: All layers within threshold');
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return lines.join('\n');
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// ---------------------------------------------------------------------------
|
|
551
|
+
// Harvester Integration
|
|
552
|
+
// ---------------------------------------------------------------------------
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Get metrics formatted for integration with SelfImproveHarvester.
|
|
556
|
+
*
|
|
557
|
+
* Returns a record of key metrics that can be attached to harvest records
|
|
558
|
+
* as additional metadata for training data quality assessment.
|
|
559
|
+
*/
|
|
560
|
+
getHarvesterMetrics(): Record<string, number | boolean> {
|
|
561
|
+
const stats = this.getStats();
|
|
562
|
+
return {
|
|
563
|
+
snn_mean_sparsity: stats.meanSparsity,
|
|
564
|
+
snn_min_sparsity: stats.minSparsity,
|
|
565
|
+
snn_max_sparsity: stats.maxSparsity,
|
|
566
|
+
snn_violation_count: stats.totalViolations,
|
|
567
|
+
snn_energy_efficiency: stats.meanEnergyEfficiency,
|
|
568
|
+
snn_in_compliance: stats.inCompliance,
|
|
569
|
+
snn_tracked_layers: stats.trackedLayers,
|
|
570
|
+
snn_total_timesteps: stats.totalTimesteps,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// ---------------------------------------------------------------------------
|
|
575
|
+
// Accessors
|
|
576
|
+
// ---------------------------------------------------------------------------
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Get all recorded snapshots.
|
|
580
|
+
*/
|
|
581
|
+
getSnapshots(): SparsitySnapshot[] {
|
|
582
|
+
return [...this.snapshots];
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Get the most recent snapshot, or null if none have been taken.
|
|
587
|
+
*/
|
|
588
|
+
getLatestSnapshot(): SparsitySnapshot | null {
|
|
589
|
+
return this.snapshots.length > 0 ? { ...this.snapshots[this.snapshots.length - 1] } : null;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Get current layer metrics.
|
|
594
|
+
*/
|
|
595
|
+
getCurrentLayerMetrics(): Map<string, SNNLayerMetrics> {
|
|
596
|
+
return new Map(this.currentLayerMetrics);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Get history for a specific layer.
|
|
601
|
+
*/
|
|
602
|
+
getLayerHistory(layerId: string): SNNLayerMetrics[] {
|
|
603
|
+
return [...(this.layerHistory.get(layerId) ?? [])];
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Get the current configuration.
|
|
608
|
+
*/
|
|
609
|
+
getConfig(): SparsityMonitorConfig {
|
|
610
|
+
return { ...this.config };
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// ---------------------------------------------------------------------------
|
|
614
|
+
// Reset
|
|
615
|
+
// ---------------------------------------------------------------------------
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Reset all recorded data and start fresh.
|
|
619
|
+
*/
|
|
620
|
+
reset(): void {
|
|
621
|
+
this.currentLayerMetrics.clear();
|
|
622
|
+
this.layerHistory.clear();
|
|
623
|
+
this.snapshots = [];
|
|
624
|
+
this.violations = [];
|
|
625
|
+
this.sparsityWindow = [];
|
|
626
|
+
this.totalTimestepsRecorded = 0;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// =============================================================================
|
|
631
|
+
// HELPERS
|
|
632
|
+
// =============================================================================
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Round a number to 4 decimal places.
|
|
636
|
+
*/
|
|
637
|
+
function roundTo4(value: number): number {
|
|
638
|
+
return Math.round(value * 10000) / 10000;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Calculate standard deviation of an array of numbers.
|
|
643
|
+
*/
|
|
644
|
+
function standardDeviation(values: number[]): number {
|
|
645
|
+
if (values.length < 2) return 0;
|
|
646
|
+
const mean = values.reduce((a, b) => a + b, 0) / values.length;
|
|
647
|
+
const squaredDiffs = values.map((v) => (v - mean) ** 2);
|
|
648
|
+
const variance = squaredDiffs.reduce((a, b) => a + b, 0) / (values.length - 1);
|
|
649
|
+
return Math.sqrt(variance);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Convert a composite score to a letter grade.
|
|
654
|
+
*/
|
|
655
|
+
function gradeFromComposite(composite: number): SparsityQualityHistoryEntry['grade'] {
|
|
656
|
+
if (composite >= 0.95) return 'A';
|
|
657
|
+
if (composite >= 0.85) return 'B';
|
|
658
|
+
if (composite >= 0.7) return 'C';
|
|
659
|
+
if (composite >= 0.5) return 'D';
|
|
660
|
+
return 'F';
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Create zero-valued energy metrics (for when energy metrics are disabled).
|
|
665
|
+
*/
|
|
666
|
+
function createZeroEnergyMetrics(): EnergyEfficiencyMetrics {
|
|
667
|
+
return {
|
|
668
|
+
denseOps: 0,
|
|
669
|
+
sparseOps: 0,
|
|
670
|
+
opsSaved: 0,
|
|
671
|
+
efficiencyRatio: 0,
|
|
672
|
+
energySavingsFactor: 1,
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// =============================================================================
|
|
677
|
+
// FACTORY
|
|
678
|
+
// =============================================================================
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Create a new SparsityMonitor with optional configuration overrides.
|
|
682
|
+
*/
|
|
683
|
+
export function createSparsityMonitor(config?: Partial<SparsityMonitorConfig>): SparsityMonitor {
|
|
684
|
+
return new SparsityMonitor(config);
|
|
685
|
+
}
|