@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,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leader Election System
|
|
3
|
+
*
|
|
4
|
+
* Implements Raft-inspired leader election for agent clusters.
|
|
5
|
+
* Provides fault-tolerant leader selection with automatic failover.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ILeaderElection } from '@holoscript/core';
|
|
9
|
+
|
|
10
|
+
export interface LeaderElectionConfig {
|
|
11
|
+
electionTimeoutMin: number; // Min election timeout (ms)
|
|
12
|
+
electionTimeoutMax: number; // Max election timeout (ms)
|
|
13
|
+
heartbeatInterval: number; // Leader heartbeat interval (ms)
|
|
14
|
+
quorumSize?: number; // Override quorum calculation
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type ElectionRole = 'leader' | 'follower' | 'candidate';
|
|
18
|
+
|
|
19
|
+
export interface ElectionState {
|
|
20
|
+
term: number;
|
|
21
|
+
votedFor: string | null;
|
|
22
|
+
role: ElectionRole;
|
|
23
|
+
leaderId: string | null;
|
|
24
|
+
votes: Set<string>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const DEFAULT_CONFIG: LeaderElectionConfig = {
|
|
28
|
+
electionTimeoutMin: 150,
|
|
29
|
+
electionTimeoutMax: 300,
|
|
30
|
+
heartbeatInterval: 50,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Raft-inspired leader election for agent clusters
|
|
35
|
+
*/
|
|
36
|
+
export class LeaderElection implements ILeaderElection {
|
|
37
|
+
private nodeId: string;
|
|
38
|
+
private clusterMembers: string[];
|
|
39
|
+
private config: LeaderElectionConfig;
|
|
40
|
+
private state: ElectionState;
|
|
41
|
+
private electionTimer: ReturnType<typeof setTimeout> | null = null;
|
|
42
|
+
private heartbeatTimer: ReturnType<typeof setInterval> | null = null;
|
|
43
|
+
private callbacks: Set<(leaderId: string | null) => void> = new Set();
|
|
44
|
+
private messageHandler: ((from: string, message: ElectionMessage) => void) | null = null;
|
|
45
|
+
|
|
46
|
+
constructor(
|
|
47
|
+
nodeId: string,
|
|
48
|
+
clusterMembers: string[],
|
|
49
|
+
config: Partial<LeaderElectionConfig> = {}
|
|
50
|
+
) {
|
|
51
|
+
this.nodeId = nodeId;
|
|
52
|
+
this.clusterMembers = clusterMembers.filter((id) => id !== nodeId);
|
|
53
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
54
|
+
this.state = {
|
|
55
|
+
term: 0,
|
|
56
|
+
votedFor: null,
|
|
57
|
+
role: 'follower',
|
|
58
|
+
leaderId: null,
|
|
59
|
+
votes: new Set(),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Start participating in leader election
|
|
65
|
+
*/
|
|
66
|
+
async startElection(): Promise<string> {
|
|
67
|
+
this.becomeCandidate();
|
|
68
|
+
|
|
69
|
+
// Wait for election to complete
|
|
70
|
+
return new Promise((resolve) => {
|
|
71
|
+
const checkLeader = setInterval(() => {
|
|
72
|
+
if (this.state.leaderId !== null) {
|
|
73
|
+
clearInterval(checkLeader);
|
|
74
|
+
resolve(this.state.leaderId);
|
|
75
|
+
}
|
|
76
|
+
}, 10);
|
|
77
|
+
|
|
78
|
+
// Timeout safety
|
|
79
|
+
setTimeout(() => {
|
|
80
|
+
clearInterval(checkLeader);
|
|
81
|
+
resolve(this.state.leaderId ?? this.nodeId);
|
|
82
|
+
}, this.config.electionTimeoutMax * 3);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get current leader
|
|
88
|
+
*/
|
|
89
|
+
getLeader(): string | null {
|
|
90
|
+
return this.state.leaderId;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get this node's current role
|
|
95
|
+
*/
|
|
96
|
+
getRole(): ElectionRole {
|
|
97
|
+
return this.state.role;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Subscribe to leader changes
|
|
102
|
+
*/
|
|
103
|
+
onLeaderChange(callback: (leaderId: string | null) => void): () => void {
|
|
104
|
+
this.callbacks.add(callback);
|
|
105
|
+
return () => this.callbacks.delete(callback);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Handle incoming election message
|
|
110
|
+
*/
|
|
111
|
+
handleMessage(from: string, message: ElectionMessage): void {
|
|
112
|
+
switch (message.type) {
|
|
113
|
+
case 'request-vote':
|
|
114
|
+
this.handleVoteRequest(from, message);
|
|
115
|
+
break;
|
|
116
|
+
case 'vote-response':
|
|
117
|
+
this.handleVoteResponse(from, message);
|
|
118
|
+
break;
|
|
119
|
+
case 'heartbeat':
|
|
120
|
+
this.handleHeartbeat(from, message);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Set message handler for sending messages to other nodes
|
|
127
|
+
*/
|
|
128
|
+
setMessageHandler(handler: (from: string, message: ElectionMessage) => void): void {
|
|
129
|
+
this.messageHandler = handler;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Simulate receiving vote from another node (for testing/local clusters)
|
|
134
|
+
*/
|
|
135
|
+
receiveVote(voterId: string): void {
|
|
136
|
+
if (this.state.role === 'candidate') {
|
|
137
|
+
this.state.votes.add(voterId);
|
|
138
|
+
this.checkElectionWin();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Stop participating in election
|
|
144
|
+
*/
|
|
145
|
+
stop(): void {
|
|
146
|
+
if (this.electionTimer) {
|
|
147
|
+
clearTimeout(this.electionTimer);
|
|
148
|
+
this.electionTimer = null;
|
|
149
|
+
}
|
|
150
|
+
if (this.heartbeatTimer) {
|
|
151
|
+
clearInterval(this.heartbeatTimer);
|
|
152
|
+
this.heartbeatTimer = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Transition to candidate role and start election
|
|
158
|
+
*/
|
|
159
|
+
private becomeCandidate(): void {
|
|
160
|
+
this.state.term++;
|
|
161
|
+
this.state.role = 'candidate';
|
|
162
|
+
this.state.votedFor = this.nodeId;
|
|
163
|
+
this.state.votes = new Set([this.nodeId]); // Vote for self
|
|
164
|
+
|
|
165
|
+
this.resetElectionTimer();
|
|
166
|
+
this.requestVotes();
|
|
167
|
+
this.checkElectionWin();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Transition to leader role
|
|
172
|
+
*/
|
|
173
|
+
private becomeLeader(): void {
|
|
174
|
+
this.state.role = 'leader';
|
|
175
|
+
this.state.leaderId = this.nodeId;
|
|
176
|
+
|
|
177
|
+
if (this.electionTimer) {
|
|
178
|
+
clearTimeout(this.electionTimer);
|
|
179
|
+
this.electionTimer = null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Start sending heartbeats
|
|
183
|
+
this.heartbeatTimer = setInterval(() => {
|
|
184
|
+
this.sendHeartbeats();
|
|
185
|
+
}, this.config.heartbeatInterval);
|
|
186
|
+
|
|
187
|
+
this.notifyLeaderChange();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Transition to follower role
|
|
192
|
+
*/
|
|
193
|
+
private becomeFollower(leaderId: string, term: number): void {
|
|
194
|
+
const wasLeader = this.state.role === 'leader';
|
|
195
|
+
|
|
196
|
+
this.state.role = 'follower';
|
|
197
|
+
this.state.leaderId = leaderId;
|
|
198
|
+
this.state.term = term;
|
|
199
|
+
this.state.votedFor = null;
|
|
200
|
+
this.state.votes.clear();
|
|
201
|
+
|
|
202
|
+
if (this.heartbeatTimer) {
|
|
203
|
+
clearInterval(this.heartbeatTimer);
|
|
204
|
+
this.heartbeatTimer = null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.resetElectionTimer();
|
|
208
|
+
|
|
209
|
+
if (wasLeader || this.state.leaderId !== leaderId) {
|
|
210
|
+
this.notifyLeaderChange();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Request votes from all cluster members
|
|
216
|
+
*/
|
|
217
|
+
private requestVotes(): void {
|
|
218
|
+
const message: VoteRequestMessage = {
|
|
219
|
+
type: 'request-vote',
|
|
220
|
+
term: this.state.term,
|
|
221
|
+
candidateId: this.nodeId,
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// In a real implementation, this would send over network
|
|
225
|
+
// For now, simulate immediate responses from local cluster
|
|
226
|
+
if (this.messageHandler) {
|
|
227
|
+
for (const member of this.clusterMembers) {
|
|
228
|
+
this.messageHandler(member, message);
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
// Simulate local cluster - all nodes vote for first candidate
|
|
232
|
+
for (const member of this.clusterMembers) {
|
|
233
|
+
this.receiveVote(member);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Check if we've won the election
|
|
240
|
+
*/
|
|
241
|
+
private checkElectionWin(): void {
|
|
242
|
+
const quorum = this.getQuorumSize();
|
|
243
|
+
|
|
244
|
+
if (this.state.votes.size >= quorum && this.state.role === 'candidate') {
|
|
245
|
+
this.becomeLeader();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Send heartbeats to all followers
|
|
251
|
+
*/
|
|
252
|
+
private sendHeartbeats(): void {
|
|
253
|
+
if (this.state.role !== 'leader') return;
|
|
254
|
+
|
|
255
|
+
const message: HeartbeatMessage = {
|
|
256
|
+
type: 'heartbeat',
|
|
257
|
+
term: this.state.term,
|
|
258
|
+
leaderId: this.nodeId,
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
if (this.messageHandler) {
|
|
262
|
+
for (const member of this.clusterMembers) {
|
|
263
|
+
this.messageHandler(member, message);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Handle vote request from candidate
|
|
270
|
+
*/
|
|
271
|
+
private handleVoteRequest(from: string, message: VoteRequestMessage): void {
|
|
272
|
+
// If we've already voted in this term or candidate's term is old, reject
|
|
273
|
+
if (message.term < this.state.term) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// If candidate's term is newer, update our term
|
|
278
|
+
if (message.term > this.state.term) {
|
|
279
|
+
this.state.term = message.term;
|
|
280
|
+
this.state.votedFor = null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Grant vote if we haven't voted in this term
|
|
284
|
+
if (this.state.votedFor === null || this.state.votedFor === message.candidateId) {
|
|
285
|
+
this.state.votedFor = message.candidateId;
|
|
286
|
+
|
|
287
|
+
const response: VoteResponseMessage = {
|
|
288
|
+
type: 'vote-response',
|
|
289
|
+
term: this.state.term,
|
|
290
|
+
voteGranted: true,
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
if (this.messageHandler) {
|
|
294
|
+
this.messageHandler(from, response);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Handle vote response
|
|
301
|
+
*/
|
|
302
|
+
private handleVoteResponse(from: string, message: VoteResponseMessage): void {
|
|
303
|
+
if (message.term > this.state.term) {
|
|
304
|
+
this.becomeFollower(from, message.term);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (this.state.role === 'candidate' && message.voteGranted) {
|
|
309
|
+
this.state.votes.add(from);
|
|
310
|
+
this.checkElectionWin();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Handle heartbeat from leader
|
|
316
|
+
*/
|
|
317
|
+
private handleHeartbeat(from: string, message: HeartbeatMessage): void {
|
|
318
|
+
if (message.term >= this.state.term) {
|
|
319
|
+
this.becomeFollower(message.leaderId, message.term);
|
|
320
|
+
this.resetElectionTimer();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Reset election timeout
|
|
326
|
+
*/
|
|
327
|
+
private resetElectionTimer(): void {
|
|
328
|
+
if (this.electionTimer) {
|
|
329
|
+
clearTimeout(this.electionTimer);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const timeout = this.getRandomElectionTimeout();
|
|
333
|
+
|
|
334
|
+
this.electionTimer = setTimeout(() => {
|
|
335
|
+
if (this.state.role !== 'leader') {
|
|
336
|
+
this.becomeCandidate();
|
|
337
|
+
}
|
|
338
|
+
}, timeout);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Get random election timeout in configured range
|
|
343
|
+
*/
|
|
344
|
+
private getRandomElectionTimeout(): number {
|
|
345
|
+
const { electionTimeoutMin, electionTimeoutMax } = this.config;
|
|
346
|
+
return electionTimeoutMin + Math.random() * (electionTimeoutMax - electionTimeoutMin);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Calculate quorum size (majority)
|
|
351
|
+
*/
|
|
352
|
+
private getQuorumSize(): number {
|
|
353
|
+
if (this.config.quorumSize) {
|
|
354
|
+
return this.config.quorumSize;
|
|
355
|
+
}
|
|
356
|
+
const totalNodes = this.clusterMembers.length + 1; // Include self
|
|
357
|
+
return Math.floor(totalNodes / 2) + 1;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Notify all callbacks of leader change
|
|
362
|
+
*/
|
|
363
|
+
private notifyLeaderChange(): void {
|
|
364
|
+
for (const callback of this.callbacks) {
|
|
365
|
+
try {
|
|
366
|
+
callback(this.state.leaderId);
|
|
367
|
+
} catch (_error) {
|
|
368
|
+
// Ignore callback errors
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Message types
|
|
375
|
+
export type ElectionMessage = VoteRequestMessage | VoteResponseMessage | HeartbeatMessage;
|
|
376
|
+
|
|
377
|
+
export interface VoteRequestMessage {
|
|
378
|
+
type: 'request-vote';
|
|
379
|
+
term: number;
|
|
380
|
+
candidateId: string;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export interface VoteResponseMessage {
|
|
384
|
+
type: 'vote-response';
|
|
385
|
+
term: number;
|
|
386
|
+
voteGranted: boolean;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export interface HeartbeatMessage {
|
|
390
|
+
type: 'heartbeat';
|
|
391
|
+
term: number;
|
|
392
|
+
leaderId: string;
|
|
393
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Particle Swarm Optimization Engine
|
|
3
|
+
*
|
|
4
|
+
* Implements PSO algorithm for agent-task assignment optimization.
|
|
5
|
+
* Each particle represents a potential solution (task-to-agent mapping).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface PSOConfig {
|
|
9
|
+
populationSize: number;
|
|
10
|
+
maxIterations: number;
|
|
11
|
+
convergenceThreshold: number;
|
|
12
|
+
inertiaWeight: number;
|
|
13
|
+
cognitiveWeight: number;
|
|
14
|
+
socialWeight: number;
|
|
15
|
+
velocityClamp: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Particle {
|
|
19
|
+
position: number[];
|
|
20
|
+
velocity: number[];
|
|
21
|
+
personalBest: number[];
|
|
22
|
+
personalBestFitness: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PSOResult {
|
|
26
|
+
bestSolution: number[];
|
|
27
|
+
bestFitness: number;
|
|
28
|
+
converged: boolean;
|
|
29
|
+
iterations: number;
|
|
30
|
+
fitnessHistory: number[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const DEFAULT_CONFIG: PSOConfig = {
|
|
34
|
+
populationSize: 30,
|
|
35
|
+
maxIterations: 100,
|
|
36
|
+
convergenceThreshold: 0.001,
|
|
37
|
+
inertiaWeight: 0.729,
|
|
38
|
+
cognitiveWeight: 1.49445,
|
|
39
|
+
socialWeight: 1.49445,
|
|
40
|
+
velocityClamp: 4.0,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Particle Swarm Optimization engine for task assignment
|
|
45
|
+
*/
|
|
46
|
+
export class PSOEngine {
|
|
47
|
+
private config: PSOConfig;
|
|
48
|
+
|
|
49
|
+
constructor(config: Partial<PSOConfig> = {}) {
|
|
50
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Optimize task assignment using PSO
|
|
55
|
+
*
|
|
56
|
+
* @param agentCount Number of available agents
|
|
57
|
+
* @param taskCount Number of tasks to assign
|
|
58
|
+
* @param fitnessFunction Function to evaluate solution quality (higher is better)
|
|
59
|
+
* @returns Optimization result with best assignment
|
|
60
|
+
*/
|
|
61
|
+
async optimize(
|
|
62
|
+
agentCount: number,
|
|
63
|
+
taskCount: number,
|
|
64
|
+
fitnessFunction: (assignment: number[]) => number
|
|
65
|
+
): Promise<PSOResult> {
|
|
66
|
+
const { populationSize, maxIterations, convergenceThreshold } = this.config;
|
|
67
|
+
|
|
68
|
+
// Initialize swarm
|
|
69
|
+
const particles = this.initializeSwarm(populationSize, taskCount, agentCount);
|
|
70
|
+
|
|
71
|
+
// Track global best
|
|
72
|
+
let globalBest: number[] = [...particles[0].personalBest];
|
|
73
|
+
let globalBestFitness = particles[0].personalBestFitness;
|
|
74
|
+
|
|
75
|
+
// Find initial global best
|
|
76
|
+
for (const particle of particles) {
|
|
77
|
+
if (particle.personalBestFitness > globalBestFitness) {
|
|
78
|
+
globalBestFitness = particle.personalBestFitness;
|
|
79
|
+
globalBest = [...particle.personalBest];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const fitnessHistory: number[] = [globalBestFitness];
|
|
84
|
+
let converged = false;
|
|
85
|
+
let iteration = 0;
|
|
86
|
+
|
|
87
|
+
// Main optimization loop
|
|
88
|
+
for (iteration = 0; iteration < maxIterations; iteration++) {
|
|
89
|
+
const previousBest = globalBestFitness;
|
|
90
|
+
|
|
91
|
+
// Update each particle
|
|
92
|
+
for (const particle of particles) {
|
|
93
|
+
this.updateVelocity(particle, globalBest);
|
|
94
|
+
this.updatePosition(particle, agentCount);
|
|
95
|
+
|
|
96
|
+
// Evaluate new position
|
|
97
|
+
const fitness = fitnessFunction(this.discretize(particle.position, agentCount));
|
|
98
|
+
|
|
99
|
+
// Update personal best
|
|
100
|
+
if (fitness > particle.personalBestFitness) {
|
|
101
|
+
particle.personalBestFitness = fitness;
|
|
102
|
+
particle.personalBest = [...particle.position];
|
|
103
|
+
|
|
104
|
+
// Update global best
|
|
105
|
+
if (fitness > globalBestFitness) {
|
|
106
|
+
globalBestFitness = fitness;
|
|
107
|
+
globalBest = [...particle.personalBest];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fitnessHistory.push(globalBestFitness);
|
|
113
|
+
|
|
114
|
+
// Check convergence
|
|
115
|
+
const improvement = Math.abs(globalBestFitness - previousBest);
|
|
116
|
+
if (improvement < convergenceThreshold && iteration > 10) {
|
|
117
|
+
converged = true;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
bestSolution: this.discretize(globalBest, agentCount),
|
|
124
|
+
bestFitness: globalBestFitness,
|
|
125
|
+
converged,
|
|
126
|
+
iterations: iteration + 1,
|
|
127
|
+
fitnessHistory,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Initialize the particle swarm with random positions
|
|
133
|
+
*/
|
|
134
|
+
private initializeSwarm(
|
|
135
|
+
populationSize: number,
|
|
136
|
+
dimensions: number,
|
|
137
|
+
agentCount: number
|
|
138
|
+
): Particle[] {
|
|
139
|
+
const particles: Particle[] = [];
|
|
140
|
+
|
|
141
|
+
for (let i = 0; i < populationSize; i++) {
|
|
142
|
+
const position = Array.from({ length: dimensions }, () => Math.random() * agentCount);
|
|
143
|
+
const velocity = Array.from({ length: dimensions }, () => (Math.random() - 0.5) * 2);
|
|
144
|
+
|
|
145
|
+
particles.push({
|
|
146
|
+
position,
|
|
147
|
+
velocity,
|
|
148
|
+
personalBest: [...position],
|
|
149
|
+
personalBestFitness: -Infinity,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return particles;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Update particle velocity based on PSO equations
|
|
158
|
+
*/
|
|
159
|
+
private updateVelocity(particle: Particle, globalBest: number[]): void {
|
|
160
|
+
const { inertiaWeight, cognitiveWeight, socialWeight, velocityClamp } = this.config;
|
|
161
|
+
|
|
162
|
+
for (let d = 0; d < particle.position.length; d++) {
|
|
163
|
+
const r1 = Math.random();
|
|
164
|
+
const r2 = Math.random();
|
|
165
|
+
|
|
166
|
+
// PSO velocity update equation
|
|
167
|
+
const cognitive = cognitiveWeight * r1 * (particle.personalBest[d] - particle.position[d]);
|
|
168
|
+
const social = socialWeight * r2 * (globalBest[d] - particle.position[d]);
|
|
169
|
+
|
|
170
|
+
particle.velocity[d] = inertiaWeight * particle.velocity[d] + cognitive + social;
|
|
171
|
+
|
|
172
|
+
// Clamp velocity
|
|
173
|
+
particle.velocity[d] = Math.max(
|
|
174
|
+
-velocityClamp,
|
|
175
|
+
Math.min(velocityClamp, particle.velocity[d])
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Update particle position
|
|
182
|
+
*/
|
|
183
|
+
private updatePosition(particle: Particle, agentCount: number): void {
|
|
184
|
+
for (let d = 0; d < particle.position.length; d++) {
|
|
185
|
+
particle.position[d] += particle.velocity[d];
|
|
186
|
+
|
|
187
|
+
// Clamp to valid range [0, agentCount)
|
|
188
|
+
particle.position[d] = Math.max(0, Math.min(agentCount - 0.001, particle.position[d]));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Convert continuous positions to discrete agent indices
|
|
194
|
+
*/
|
|
195
|
+
private discretize(position: number[], agentCount: number): number[] {
|
|
196
|
+
return position.map((p) => Math.floor(Math.max(0, Math.min(agentCount - 1, p))));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get recommended population size for problem
|
|
201
|
+
*/
|
|
202
|
+
getRecommendedPopulation(problemSize: number): number {
|
|
203
|
+
// Heuristic: 10-50 particles based on problem size
|
|
204
|
+
return Math.min(50, Math.max(10, Math.ceil(problemSize * 1.5)));
|
|
205
|
+
}
|
|
206
|
+
}
|