fable-engine 1.3.1__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.
- fable_compressor.py +356 -0
- fable_engine/__init__.py +1 -0
- fable_engine/actions/__init__.py +291 -0
- fable_engine/actions/cas.py +182 -0
- fable_engine/actions/deliberation.py +523 -0
- fable_engine/actions/fleet.py +807 -0
- fable_engine/actions/lifecycle.py +298 -0
- fable_engine/actions/scrapers.py +116 -0
- fable_engine/actions/system3.py +815 -0
- fable_engine/browser.py +824 -0
- fable_engine/cas.py +974 -0
- fable_engine/fable_session.json +510 -0
- fable_engine/guards.py +283 -0
- fable_engine/schema.py +714 -0
- fable_engine/scrapers/__init__.py +32 -0
- fable_engine/scrapers/arxiv.py +115 -0
- fable_engine/scrapers/base.py +386 -0
- fable_engine/scrapers/github.py +129 -0
- fable_engine/scrapers/reddit.py +154 -0
- fable_engine/scrapers/web.py +120 -0
- fable_engine/scrapers/x.py +125 -0
- fable_engine/scrapers/youtube.py +132 -0
- fable_engine/server.py +414 -0
- fable_engine/session.py +1819 -0
- fable_engine/test_server.py +1362 -0
- fable_engine/updater.py +541 -0
- fable_engine-1.3.1.dist-info/LICENSE +22 -0
- fable_engine-1.3.1.dist-info/METADATA +173 -0
- fable_engine-1.3.1.dist-info/RECORD +104 -0
- fable_engine-1.3.1.dist-info/WHEEL +5 -0
- fable_engine-1.3.1.dist-info/entry_points.txt +5 -0
- fable_engine-1.3.1.dist-info/top_level.txt +6 -0
- fable_mode/__init__.py +3 -0
- fable_mode/__main__.py +4 -0
- fable_mode/adapters.py +1014 -0
- fable_mode/installer.py +553 -0
- fable_mode/launcher.py +437 -0
- fable_mode/manifest.py +142 -0
- fable_mode/resources.json +114 -0
- fable_mode/safety.py +103 -0
- fable_mode_entry.py +10 -0
- fable_v2/__init__.py +146 -0
- fable_v2/adapters.py +151 -0
- fable_v2/coder_fleet/__init__.py +100 -0
- fable_v2/coder_fleet/ast_tools.py +158 -0
- fable_v2/coder_fleet/compute.py +199 -0
- fable_v2/coder_fleet/design_engine.py +1316 -0
- fable_v2/coder_fleet/diagnostics.py +293 -0
- fable_v2/coder_fleet/fleet_dispatcher.py +214 -0
- fable_v2/coder_fleet/mock_auditor.py +306 -0
- fable_v2/coder_fleet/mutation.py +216 -0
- fable_v2/coder_fleet/property_oracle.py +260 -0
- fable_v2/coder_fleet/receipt_attestor.py +122 -0
- fable_v2/coder_fleet/red_team_swarm.py +908 -0
- fable_v2/coder_fleet/test_harness.py +198 -0
- fable_v2/coder_fleet/vector_engine.py +1287 -0
- fable_v2/coder_fleet/visual.py +357 -0
- fable_v2/coder_fleet/workspace.py +153 -0
- fable_v2/cortical/__init__.py +20 -0
- fable_v2/cortical/plasticity_engine.py +992 -0
- fable_v2/execution_broker.py +811 -0
- fable_v2/proof_engine.py +1141 -0
- fable_v2/protocol.py +485 -0
- fable_v2/runtime.py +1010 -0
- fable_v2/system3/__init__.py +204 -0
- fable_v2/system3/causal.py +558 -0
- fable_v2/system3/dialectical.py +577 -0
- fable_v2/system3/evolution.py +503 -0
- fable_v2/system3/executive.py +338 -0
- fable_v2/system3/free_energy.py +479 -0
- fable_v2/system3/hyperbolic.py +555 -0
- fable_v2/system3/induction.py +336 -0
- fable_v2/system3/kripke.py +548 -0
- fable_v2/system3/oracle.py +745 -0
- fable_v2/verifiers.py +72 -0
- tests/__init__.py +1 -0
- tests/test_anti_loop_circuit_breaker.py +64 -0
- tests/test_auto_updater.py +407 -0
- tests/test_coder_fleet.py +535 -0
- tests/test_delegation_compiler.py +54 -0
- tests/test_descriptor_boundaries.py +126 -0
- tests/test_design_engine.py +603 -0
- tests/test_epistemic_evidence_validator.py +66 -0
- tests/test_execution_broker.py +233 -0
- tests/test_fable_v2.py +406 -0
- tests/test_fleet_transitions.py +116 -0
- tests/test_fsm_redteam_evolution.py +406 -0
- tests/test_goal_rubric_and_pipeline.py +367 -0
- tests/test_hebbian_plasticity.py +585 -0
- tests/test_packaging_runtime.py +194 -0
- tests/test_proof_engine.py +259 -0
- tests/test_red_team_swarm.py +645 -0
- tests/test_redteam_remediation.py +169 -0
- tests/test_registration_transaction.py +375 -0
- tests/test_requested_regressions.py +467 -0
- tests/test_scrapers.py +370 -0
- tests/test_server_actions.py +93 -0
- tests/test_server_frontier_actions.py +269 -0
- tests/test_server_protocol.py +88 -0
- tests/test_stealth_browser.py +970 -0
- tests/test_system3.py +381 -0
- tests/test_system3_deep_integration.py +385 -0
- tests/test_system3_frontier.py +436 -0
- tests/test_vector_engine.py +608 -0
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
"""System 3 Evolutionary Paradigm Engine & 10D Pareto Frontier Optimizer.
|
|
2
|
+
|
|
3
|
+
Implements genetic algorithms, multi-objective NSGA-II non-dominated Pareto sorting,
|
|
4
|
+
crowding-distance diversity maintenance, and architectural genome mutation/crossover.
|
|
5
|
+
Zero external dependencies.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field, asdict
|
|
11
|
+
import copy
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import math
|
|
15
|
+
import random
|
|
16
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
PARETO_DIMENSIONS = [
|
|
20
|
+
"latency", # Speed / execution responsiveness (higher is better)
|
|
21
|
+
"throughput", # Concurrency / operations per second
|
|
22
|
+
"memory_efficiency", # Low footprint / bounded cache overhead
|
|
23
|
+
"fault_tolerance", # Resilience under faults / self-healing
|
|
24
|
+
"modularity", # Decoupling / clear component boundaries
|
|
25
|
+
"simplicity", # Low cognitive complexity / maintainability
|
|
26
|
+
"testability", # Ease of automated verification / determinism
|
|
27
|
+
"security", # Trust boundaries / isolation / attack surface
|
|
28
|
+
"determinism", # Reproducibility / zero race conditions
|
|
29
|
+
"token_compaction", # Compaction efficiency (CAS storage / grammar)
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
GENE_ALLELE_OPTIONS = {
|
|
33
|
+
"concurrency_model": [
|
|
34
|
+
"actor_model", "event_loop_async", "worker_thread_pool",
|
|
35
|
+
"lock_free_ring_buffer", "csp_channels", "speculative_dual_pass"
|
|
36
|
+
],
|
|
37
|
+
"state_persistence": [
|
|
38
|
+
"cas_immutable_store", "event_sourcing_log", "write_ahead_log",
|
|
39
|
+
"in_memory_sharded_lru", "cow_snapshot_tree", "hybrid_disk_mmap"
|
|
40
|
+
],
|
|
41
|
+
"synchronization": [
|
|
42
|
+
"optimistic_concurrency_cas", "single_writer_multi_reader",
|
|
43
|
+
"crdt_conflict_free", "pessimistic_rwlock", "message_passing_only"
|
|
44
|
+
],
|
|
45
|
+
"cache_hierarchy": [
|
|
46
|
+
"two_level_sharded_lru", "direct_mapped_cas",
|
|
47
|
+
"arc_adaptive_replacement", "write_through_memory_pool"
|
|
48
|
+
],
|
|
49
|
+
"error_recovery": [
|
|
50
|
+
"ooda_circuit_breaker", "erlang_supervisor_tree",
|
|
51
|
+
"exponential_backoff_jitter", "fail_fast_rollback", "shadow_consensus"
|
|
52
|
+
],
|
|
53
|
+
"data_layout": [
|
|
54
|
+
"columnar_structure_of_arrays", "row_array_of_structures",
|
|
55
|
+
"flat_buffer_varint", "chunked_composite_frames"
|
|
56
|
+
],
|
|
57
|
+
"execution_strategy": [
|
|
58
|
+
"subagent_fleet_pipeline", "hierarchical_director_worker",
|
|
59
|
+
"deterministic_single_pass", "mcts_branching_deliberation"
|
|
60
|
+
],
|
|
61
|
+
"network_topology": [
|
|
62
|
+
"hub_and_spoke_orchestrator", "peer_to_peer_mesh",
|
|
63
|
+
"ring_token_bus", "hierarchical_tree"
|
|
64
|
+
],
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class CognitiveGenome:
|
|
70
|
+
"""Genetic encoding of an architectural candidate paradigm."""
|
|
71
|
+
genome_id: str
|
|
72
|
+
paradigm_name: str
|
|
73
|
+
genes: Dict[str, Any] = field(default_factory=dict)
|
|
74
|
+
fitness_scores: Dict[str, float] = field(default_factory=dict)
|
|
75
|
+
generation: int = 0
|
|
76
|
+
pareto_rank: int = 1
|
|
77
|
+
crowding_distance: float = 0.0
|
|
78
|
+
lineage: List[str] = field(default_factory=list)
|
|
79
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
80
|
+
|
|
81
|
+
def dominates(self, other: "CognitiveGenome") -> bool:
|
|
82
|
+
"""
|
|
83
|
+
Pareto Dominance Check:
|
|
84
|
+
Returns True if self is >= other in all 10 dimensions AND strictly > in at least one.
|
|
85
|
+
"""
|
|
86
|
+
better_in_at_least_one = False
|
|
87
|
+
for dim in PARETO_DIMENSIONS:
|
|
88
|
+
score_self = self.fitness_scores.get(dim, 0.0)
|
|
89
|
+
score_other = other.fitness_scores.get(dim, 0.0)
|
|
90
|
+
if score_self < score_other:
|
|
91
|
+
return False
|
|
92
|
+
if score_self > score_other:
|
|
93
|
+
better_in_at_least_one = True
|
|
94
|
+
return better_in_at_least_one
|
|
95
|
+
|
|
96
|
+
def compute_scalar_fitness(self, weights: Optional[Dict[str, float]] = None) -> float:
|
|
97
|
+
"""Compute weighted scalar composite fitness score [0.0, 1.0]."""
|
|
98
|
+
w = weights or {dim: 1.0 / len(PARETO_DIMENSIONS) for dim in PARETO_DIMENSIONS}
|
|
99
|
+
total_w = sum(w.values()) or 1.0
|
|
100
|
+
score = sum(self.fitness_scores.get(dim, 0.0) * w.get(dim, 1.0) for dim in PARETO_DIMENSIONS)
|
|
101
|
+
return round(score / total_w, 4)
|
|
102
|
+
|
|
103
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
104
|
+
return asdict(self)
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def from_dict(cls, data: Dict[str, Any]) -> "CognitiveGenome":
|
|
108
|
+
return cls(**data)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def create_random_genome(
|
|
112
|
+
genome_id: str,
|
|
113
|
+
paradigm_name: str,
|
|
114
|
+
generation: int = 0,
|
|
115
|
+
seed: Optional[int] = None,
|
|
116
|
+
) -> CognitiveGenome:
|
|
117
|
+
"""Instantiate a valid randomized genome across the architectural dimensions."""
|
|
118
|
+
rng = random.Random(seed)
|
|
119
|
+
genes: Dict[str, Any] = {}
|
|
120
|
+
for gene_name, alleles in GENE_ALLELE_OPTIONS.items():
|
|
121
|
+
genes[gene_name] = rng.choice(alleles)
|
|
122
|
+
|
|
123
|
+
# Continuous parameters
|
|
124
|
+
genes["verification_depth"] = round(rng.uniform(0.5, 1.0), 3)
|
|
125
|
+
genes["compression_target"] = round(rng.uniform(0.001, 0.005), 5)
|
|
126
|
+
genes["concurrency_workers"] = rng.randint(2, 16)
|
|
127
|
+
|
|
128
|
+
# Default heuristic fitness initialization
|
|
129
|
+
fitness: Dict[str, float] = {}
|
|
130
|
+
for dim in PARETO_DIMENSIONS:
|
|
131
|
+
fitness[dim] = round(rng.uniform(0.5, 0.85), 3)
|
|
132
|
+
|
|
133
|
+
return CognitiveGenome(
|
|
134
|
+
genome_id=genome_id,
|
|
135
|
+
paradigm_name=paradigm_name,
|
|
136
|
+
genes=genes,
|
|
137
|
+
fitness_scores=fitness,
|
|
138
|
+
generation=generation,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class CognitiveGenePool:
|
|
143
|
+
"""
|
|
144
|
+
Population manager executing NSGA-II Multi-Objective Evolutionary Optimization
|
|
145
|
+
across the 10D Pareto frontier with elite preservation and crowding distance diversity.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
def __init__(
|
|
149
|
+
self,
|
|
150
|
+
population_size: int = 20,
|
|
151
|
+
mutation_rate: float = 0.15,
|
|
152
|
+
crossover_rate: float = 0.80,
|
|
153
|
+
random_seed: Optional[int] = 42,
|
|
154
|
+
):
|
|
155
|
+
self.population_size = max(4, population_size)
|
|
156
|
+
self.mutation_rate = max(0.01, min(1.0, mutation_rate))
|
|
157
|
+
self.crossover_rate = max(0.1, min(1.0, crossover_rate))
|
|
158
|
+
self.rng = random.Random(random_seed)
|
|
159
|
+
self.population: List[CognitiveGenome] = []
|
|
160
|
+
self.generation_count: int = 0
|
|
161
|
+
self.history: List[Dict[str, Any]] = []
|
|
162
|
+
|
|
163
|
+
def initialize_population(
|
|
164
|
+
self,
|
|
165
|
+
seed_paradigms: Optional[List[Dict[str, Any]]] = None,
|
|
166
|
+
) -> None:
|
|
167
|
+
"""Seed initial population with provided archetypes and generated variants."""
|
|
168
|
+
self.population = []
|
|
169
|
+
self.generation_count = 0
|
|
170
|
+
|
|
171
|
+
# Ingest custom seeds if provided
|
|
172
|
+
if seed_paradigms:
|
|
173
|
+
for idx, p in enumerate(seed_paradigms):
|
|
174
|
+
gid = p.get("genome_id", f"seed_{idx+1:03d}")
|
|
175
|
+
name = p.get("paradigm_name", f"Seed Paradigm #{idx+1}")
|
|
176
|
+
genes = p.get("genes", {})
|
|
177
|
+
# Fill missing genes
|
|
178
|
+
for k, v in GENE_ALLELE_OPTIONS.items():
|
|
179
|
+
if k not in genes:
|
|
180
|
+
genes[k] = self.rng.choice(v)
|
|
181
|
+
if "verification_depth" not in genes:
|
|
182
|
+
genes["verification_depth"] = 0.85
|
|
183
|
+
if "compression_target" not in genes:
|
|
184
|
+
genes["compression_target"] = 0.003
|
|
185
|
+
if "concurrency_workers" not in genes:
|
|
186
|
+
genes["concurrency_workers"] = 4
|
|
187
|
+
|
|
188
|
+
fitness = p.get("fitness_scores", {})
|
|
189
|
+
for dim in PARETO_DIMENSIONS:
|
|
190
|
+
if dim not in fitness:
|
|
191
|
+
fitness[dim] = 0.70
|
|
192
|
+
|
|
193
|
+
genome = CognitiveGenome(
|
|
194
|
+
genome_id=gid,
|
|
195
|
+
paradigm_name=name,
|
|
196
|
+
genes=genes,
|
|
197
|
+
fitness_scores=fitness,
|
|
198
|
+
generation=0,
|
|
199
|
+
)
|
|
200
|
+
self.population.append(genome)
|
|
201
|
+
|
|
202
|
+
# Fill remainder with diversified random archetypes
|
|
203
|
+
archetype_names = [
|
|
204
|
+
"Ultra-Low Latency Ring Engine",
|
|
205
|
+
"Resilient CAS-Immutable Actor Grid",
|
|
206
|
+
"Adaptive Neuro-Symbolic Pipeline",
|
|
207
|
+
"High-Throughput Varint Streamer",
|
|
208
|
+
"Hierarchical Supervisor Worktree",
|
|
209
|
+
"Zero-Allocation Columnar Engine",
|
|
210
|
+
"Speculative Dual-Pass MCTS",
|
|
211
|
+
"Event-Sourced Self-Healing Bus",
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
while len(self.population) < self.population_size:
|
|
215
|
+
idx = len(self.population) + 1
|
|
216
|
+
name = archetype_names[idx % len(archetype_names)] + f" (Gen 0 #{idx})"
|
|
217
|
+
genome = create_random_genome(f"g0_{idx:03d}", name, generation=0, seed=self.rng.randint(1, 1000000))
|
|
218
|
+
self.population.append(genome)
|
|
219
|
+
|
|
220
|
+
def evaluate_fitness(
|
|
221
|
+
self,
|
|
222
|
+
fitness_fn: Optional[Callable[[CognitiveGenome], Dict[str, float]]] = None,
|
|
223
|
+
) -> None:
|
|
224
|
+
"""
|
|
225
|
+
Evaluate 10D fitness scores for all genomes in the population.
|
|
226
|
+
If no custom evaluator provided, uses domain structural heuristics.
|
|
227
|
+
"""
|
|
228
|
+
for genome in self.population:
|
|
229
|
+
if fitness_fn:
|
|
230
|
+
scores = fitness_fn(genome)
|
|
231
|
+
genome.fitness_scores.update(scores)
|
|
232
|
+
else:
|
|
233
|
+
# Built-in structural heuristic evaluator based on gene synergies
|
|
234
|
+
g = genome.genes
|
|
235
|
+
scores: Dict[str, float] = {}
|
|
236
|
+
|
|
237
|
+
# Latency & Throughput heuristics
|
|
238
|
+
is_lock_free = g.get("concurrency_model") == "lock_free_ring_buffer"
|
|
239
|
+
is_cas_imm = g.get("state_persistence") == "cas_immutable_store"
|
|
240
|
+
is_soa = g.get("data_layout") == "columnar_structure_of_arrays"
|
|
241
|
+
|
|
242
|
+
scores["latency"] = min(0.98, 0.65 + (0.20 if is_lock_free else 0.05) + (0.10 if is_soa else 0.0))
|
|
243
|
+
scores["throughput"] = min(0.98, 0.60 + (0.15 if is_lock_free else 0.05) + (0.15 if g.get("concurrency_workers", 4) >= 8 else 0.05))
|
|
244
|
+
scores["memory_efficiency"] = min(0.98, 0.70 + (0.15 if is_cas_imm else 0.0) + (0.10 if is_soa else 0.0))
|
|
245
|
+
scores["fault_tolerance"] = min(0.98, 0.65 + (0.25 if g.get("error_recovery") == "ooda_circuit_breaker" else 0.10))
|
|
246
|
+
scores["modularity"] = min(0.98, 0.75 + (0.15 if g.get("execution_strategy") == "subagent_fleet_pipeline" else 0.05))
|
|
247
|
+
scores["simplicity"] = min(0.95, 0.85 - (0.15 if is_lock_free else 0.0) - (0.10 if g.get("concurrency_workers", 4) > 8 else 0.0))
|
|
248
|
+
scores["testability"] = min(0.98, 0.70 + (0.20 if g.get("synchronization") == "single_writer_multi_reader" else 0.05))
|
|
249
|
+
scores["security"] = min(0.98, 0.75 + (0.15 if is_cas_imm else 0.05))
|
|
250
|
+
scores["determinism"] = min(0.98, 0.80 + (0.15 if is_cas_imm else 0.0))
|
|
251
|
+
scores["token_compaction"] = min(0.99, 0.75 + (0.20 if g.get("data_layout") == "chunked_composite_frames" else 0.05))
|
|
252
|
+
|
|
253
|
+
for dim in PARETO_DIMENSIONS:
|
|
254
|
+
scores[dim] = round(max(0.1, min(0.99, scores.get(dim, 0.7))), 3)
|
|
255
|
+
|
|
256
|
+
genome.fitness_scores = scores
|
|
257
|
+
|
|
258
|
+
def fast_non_dominated_sort(self) -> List[List[CognitiveGenome]]:
|
|
259
|
+
"""
|
|
260
|
+
NSGA-II Fast Non-Dominated Sorting Algorithm.
|
|
261
|
+
Sorts the population into Pareto Fronts F_1, F_2, ... F_k.
|
|
262
|
+
Front 1 (rank 1) contains the strictly non-dominated solutions.
|
|
263
|
+
"""
|
|
264
|
+
fronts: List[List[CognitiveGenome]] = [[]]
|
|
265
|
+
domination_count: Dict[str, int] = {}
|
|
266
|
+
dominated_solutions: Dict[str, List[CognitiveGenome]] = {}
|
|
267
|
+
|
|
268
|
+
for p in self.population:
|
|
269
|
+
domination_count[p.genome_id] = 0
|
|
270
|
+
dominated_solutions[p.genome_id] = []
|
|
271
|
+
for q in self.population:
|
|
272
|
+
if p.dominates(q):
|
|
273
|
+
dominated_solutions[p.genome_id].append(q)
|
|
274
|
+
elif q.dominates(p):
|
|
275
|
+
domination_count[p.genome_id] += 1
|
|
276
|
+
|
|
277
|
+
if domination_count[p.genome_id] == 0:
|
|
278
|
+
p.pareto_rank = 1
|
|
279
|
+
fronts[0].append(p)
|
|
280
|
+
|
|
281
|
+
i = 0
|
|
282
|
+
while len(fronts[i]) > 0:
|
|
283
|
+
next_front: List[CognitiveGenome] = []
|
|
284
|
+
for p in fronts[i]:
|
|
285
|
+
for q in dominated_solutions[p.genome_id]:
|
|
286
|
+
domination_count[q.genome_id] -= 1
|
|
287
|
+
if domination_count[q.genome_id] == 0:
|
|
288
|
+
q.pareto_rank = i + 2
|
|
289
|
+
next_front.append(q)
|
|
290
|
+
i += 1
|
|
291
|
+
fronts.append(next_front)
|
|
292
|
+
|
|
293
|
+
# Remove trailing empty front
|
|
294
|
+
if fronts and not fronts[-1]:
|
|
295
|
+
fronts.pop()
|
|
296
|
+
|
|
297
|
+
return fronts
|
|
298
|
+
|
|
299
|
+
def calculate_crowding_distance(self, front: List[CognitiveGenome]) -> None:
|
|
300
|
+
"""
|
|
301
|
+
Compute crowding distance for genomes in a front to favor diversity along the frontier.
|
|
302
|
+
Boundary points receive infinite distance.
|
|
303
|
+
"""
|
|
304
|
+
l = len(front)
|
|
305
|
+
if l == 0:
|
|
306
|
+
return
|
|
307
|
+
if l <= 2:
|
|
308
|
+
for g in front:
|
|
309
|
+
g.crowding_distance = float("inf")
|
|
310
|
+
return
|
|
311
|
+
|
|
312
|
+
for g in front:
|
|
313
|
+
g.crowding_distance = 0.0
|
|
314
|
+
|
|
315
|
+
for dim in PARETO_DIMENSIONS:
|
|
316
|
+
# Sort front by current objective
|
|
317
|
+
front.sort(key=lambda g: g.fitness_scores.get(dim, 0.0))
|
|
318
|
+
front[0].crowding_distance = float("inf")
|
|
319
|
+
front[-1].crowding_distance = float("inf")
|
|
320
|
+
|
|
321
|
+
dim_min = front[0].fitness_scores.get(dim, 0.0)
|
|
322
|
+
dim_max = front[-1].fitness_scores.get(dim, 0.0)
|
|
323
|
+
denom = max(1e-6, dim_max - dim_min)
|
|
324
|
+
|
|
325
|
+
for i in range(1, l - 1):
|
|
326
|
+
if not math.isinf(front[i].crowding_distance):
|
|
327
|
+
prev_score = front[i - 1].fitness_scores.get(dim, 0.0)
|
|
328
|
+
next_score = front[i + 1].fitness_scores.get(dim, 0.0)
|
|
329
|
+
front[i].crowding_distance += (next_score - prev_score) / denom
|
|
330
|
+
|
|
331
|
+
def crossover(self, parent1: CognitiveGenome, parent2: CognitiveGenome) -> Tuple[CognitiveGenome, CognitiveGenome]:
|
|
332
|
+
"""Uniform & blended genetic crossover between two architectural genomes."""
|
|
333
|
+
if self.rng.random() > self.crossover_rate:
|
|
334
|
+
# Clone without crossover
|
|
335
|
+
return copy.deepcopy(parent1), copy.deepcopy(parent2)
|
|
336
|
+
|
|
337
|
+
genes1 = copy.deepcopy(parent1.genes)
|
|
338
|
+
genes2 = copy.deepcopy(parent2.genes)
|
|
339
|
+
|
|
340
|
+
for gene_key in list(genes1.keys()):
|
|
341
|
+
if self.rng.random() < 0.5:
|
|
342
|
+
# Swap discrete gene
|
|
343
|
+
genes1[gene_key], genes2[gene_key] = genes2.get(gene_key, genes1[gene_key]), genes1[gene_key]
|
|
344
|
+
|
|
345
|
+
# Blend continuous parameters
|
|
346
|
+
for cont_param in ["verification_depth", "compression_target"]:
|
|
347
|
+
v1 = genes1.get(cont_param, 0.8)
|
|
348
|
+
v2 = genes2.get(cont_param, 0.8)
|
|
349
|
+
alpha = self.rng.uniform(0.2, 0.8)
|
|
350
|
+
genes1[cont_param] = round(alpha * v1 + (1 - alpha) * v2, 4)
|
|
351
|
+
genes2[cont_param] = round((1 - alpha) * v1 + alpha * v2, 4)
|
|
352
|
+
|
|
353
|
+
gid1 = f"g{self.generation_count+1}_{self.rng.randint(100, 999)}"
|
|
354
|
+
gid2 = f"g{self.generation_count+1}_{self.rng.randint(100, 999)}"
|
|
355
|
+
|
|
356
|
+
child1 = CognitiveGenome(
|
|
357
|
+
genome_id=gid1,
|
|
358
|
+
paradigm_name=f"Hybrid({parent1.paradigm_name[:15]}+{parent2.paradigm_name[:15]})",
|
|
359
|
+
genes=genes1,
|
|
360
|
+
generation=self.generation_count + 1,
|
|
361
|
+
lineage=[parent1.genome_id, parent2.genome_id],
|
|
362
|
+
)
|
|
363
|
+
child2 = CognitiveGenome(
|
|
364
|
+
genome_id=gid2,
|
|
365
|
+
paradigm_name=f"Recombinant({parent2.paradigm_name[:15]}+{parent1.paradigm_name[:15]})",
|
|
366
|
+
genes=genes2,
|
|
367
|
+
generation=self.generation_count + 1,
|
|
368
|
+
lineage=[parent2.genome_id, parent1.genome_id],
|
|
369
|
+
)
|
|
370
|
+
return child1, child2
|
|
371
|
+
|
|
372
|
+
def mutate(self, genome: CognitiveGenome) -> CognitiveGenome:
|
|
373
|
+
"""Mutate genome discrete alleles and continuous variables."""
|
|
374
|
+
mutated_genes = copy.deepcopy(genome.genes)
|
|
375
|
+
|
|
376
|
+
for gene_name, alleles in GENE_ALLELE_OPTIONS.items():
|
|
377
|
+
if self.rng.random() < self.mutation_rate:
|
|
378
|
+
# Gene flip
|
|
379
|
+
new_val = self.rng.choice(alleles)
|
|
380
|
+
mutated_genes[gene_name] = new_val
|
|
381
|
+
|
|
382
|
+
# Continuous jitter
|
|
383
|
+
if self.rng.random() < self.mutation_rate:
|
|
384
|
+
depth = mutated_genes.get("verification_depth", 0.85)
|
|
385
|
+
mutated_genes["verification_depth"] = round(max(0.1, min(1.0, depth + self.rng.gauss(0, 0.05))), 3)
|
|
386
|
+
|
|
387
|
+
if self.rng.random() < self.mutation_rate:
|
|
388
|
+
workers = mutated_genes.get("concurrency_workers", 4)
|
|
389
|
+
mutated_genes["concurrency_workers"] = max(1, min(32, workers + self.rng.choice([-1, 1, 2])))
|
|
390
|
+
|
|
391
|
+
genome.genes = mutated_genes
|
|
392
|
+
return genome
|
|
393
|
+
|
|
394
|
+
def tournament_selection(self, k: int = 3) -> CognitiveGenome:
|
|
395
|
+
"""Crowded Tournament Selection based on Pareto Rank and Crowding Distance."""
|
|
396
|
+
candidates = self.rng.sample(self.population, min(k, len(self.population)))
|
|
397
|
+
# Winner has lower rank (better), or in tie has higher crowding distance
|
|
398
|
+
candidates.sort(key=lambda g: (g.pareto_rank, -g.crowding_distance))
|
|
399
|
+
return candidates[0]
|
|
400
|
+
|
|
401
|
+
def evolve_generation(
|
|
402
|
+
self,
|
|
403
|
+
fitness_fn: Optional[Callable[[CognitiveGenome], Dict[str, float]]] = None,
|
|
404
|
+
elite_ratio: float = 0.2,
|
|
405
|
+
) -> List[CognitiveGenome]:
|
|
406
|
+
"""
|
|
407
|
+
Execute one complete generation of NSGA-II Multi-Objective Evolution:
|
|
408
|
+
1. Evaluate fitness scores.
|
|
409
|
+
2. Fast non-dominated sorting into Pareto fronts.
|
|
410
|
+
3. Compute crowding distance.
|
|
411
|
+
4. Select elites from Front 1.
|
|
412
|
+
5. Generate offspring via tournament selection, crossover, and mutation.
|
|
413
|
+
6. Form new population and increment generation count.
|
|
414
|
+
"""
|
|
415
|
+
if not self.population:
|
|
416
|
+
self.initialize_population()
|
|
417
|
+
|
|
418
|
+
self.evaluate_fitness(fitness_fn)
|
|
419
|
+
fronts = self.fast_non_dominated_sort()
|
|
420
|
+
for front in fronts:
|
|
421
|
+
self.calculate_crowding_distance(front)
|
|
422
|
+
|
|
423
|
+
# Record history snapshot
|
|
424
|
+
front1 = fronts[0] if fronts else []
|
|
425
|
+
self.history.append({
|
|
426
|
+
"generation": self.generation_count,
|
|
427
|
+
"population_size": len(self.population),
|
|
428
|
+
"front1_size": len(front1),
|
|
429
|
+
"front1_best_scalar": max([g.compute_scalar_fitness() for g in front1]) if front1 else 0.0,
|
|
430
|
+
"front1_genomes": [g.genome_id for g in front1],
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
# Elite selection from top fronts
|
|
434
|
+
num_elites = max(2, int(self.population_size * elite_ratio))
|
|
435
|
+
next_population: List[CognitiveGenome] = []
|
|
436
|
+
|
|
437
|
+
for front in fronts:
|
|
438
|
+
if len(next_population) + len(front) <= num_elites:
|
|
439
|
+
next_population.extend([copy.deepcopy(g) for g in front])
|
|
440
|
+
else:
|
|
441
|
+
# Partial front fill based on crowding distance
|
|
442
|
+
sorted_front = sorted(front, key=lambda g: g.crowding_distance, reverse=True)
|
|
443
|
+
needed = num_elites - len(next_population)
|
|
444
|
+
next_population.extend([copy.deepcopy(g) for g in sorted_front[:needed]])
|
|
445
|
+
break
|
|
446
|
+
|
|
447
|
+
# Breed remaining offspring
|
|
448
|
+
while len(next_population) < self.population_size:
|
|
449
|
+
p1 = self.tournament_selection()
|
|
450
|
+
p2 = self.tournament_selection()
|
|
451
|
+
c1, c2 = self.crossover(p1, p2)
|
|
452
|
+
c1 = self.mutate(c1)
|
|
453
|
+
next_population.append(c1)
|
|
454
|
+
if len(next_population) < self.population_size:
|
|
455
|
+
c2 = self.mutate(c2)
|
|
456
|
+
next_population.append(c2)
|
|
457
|
+
|
|
458
|
+
self.generation_count += 1
|
|
459
|
+
self.population = next_population
|
|
460
|
+
self.evaluate_fitness(fitness_fn)
|
|
461
|
+
new_fronts = self.fast_non_dominated_sort()
|
|
462
|
+
for front in new_fronts:
|
|
463
|
+
self.calculate_crowding_distance(front)
|
|
464
|
+
|
|
465
|
+
return self.get_pareto_frontier()
|
|
466
|
+
|
|
467
|
+
def get_pareto_frontier(self) -> List[CognitiveGenome]:
|
|
468
|
+
"""Return the current Generation's Rank 1 non-dominated Pareto frontier."""
|
|
469
|
+
fronts = self.fast_non_dominated_sort()
|
|
470
|
+
return fronts[0] if fronts else []
|
|
471
|
+
|
|
472
|
+
def get_best_genome(self, weights: Optional[Dict[str, float]] = None) -> CognitiveGenome:
|
|
473
|
+
"""Return the highest-scoring genome according to scalar objective weighting."""
|
|
474
|
+
if not self.population:
|
|
475
|
+
self.initialize_population()
|
|
476
|
+
self.evaluate_fitness()
|
|
477
|
+
return max(self.population, key=lambda g: g.compute_scalar_fitness(weights))
|
|
478
|
+
|
|
479
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
480
|
+
"""Serialize GenePool to JSON dictionary."""
|
|
481
|
+
return {
|
|
482
|
+
"population_size": self.population_size,
|
|
483
|
+
"generation_count": self.generation_count,
|
|
484
|
+
"mutation_rate": self.mutation_rate,
|
|
485
|
+
"crossover_rate": self.crossover_rate,
|
|
486
|
+
"population": [g.to_dict() for g in self.population],
|
|
487
|
+
"history": self.history,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
@classmethod
|
|
491
|
+
def from_dict(cls, data: Dict[str, Any]) -> "CognitiveGenePool":
|
|
492
|
+
"""Deserialize GenePool from dictionary."""
|
|
493
|
+
pool = cls(
|
|
494
|
+
population_size=data.get("population_size", 20),
|
|
495
|
+
mutation_rate=data.get("mutation_rate", 0.15),
|
|
496
|
+
crossover_rate=data.get("crossover_rate", 0.80),
|
|
497
|
+
)
|
|
498
|
+
pool.generation_count = data.get("generation_count", 0)
|
|
499
|
+
pool.history = data.get("history", [])
|
|
500
|
+
pool.population = [
|
|
501
|
+
CognitiveGenome.from_dict(g) for g in data.get("population", [])
|
|
502
|
+
]
|
|
503
|
+
return pool
|