Skip to main content

microscope_memory/
morphogenesis.rs

1//! Morphogenesis — Biológiai Mintákon Alapuló Generatív Architektúra-Tenyésztés
2
3//!
4
5//! Ez a modul a természet növekedési mintáit használja szoftverarchitektúrák generálására:
6
7//! - Gombafonalak (mycelium) → elosztott P2P hálózatok
8
9//! - Kapilláris elágazások → adatfolyam pipeline-ok
10
11//! - Nyálkpenész (slime mold) → útvonal optimalizálás
12
13//! - L-system fraktálok → self-similar struktúrák
14
15//!
16
17//! ## Alapelvek (Morphogenetic Design)
18
19//!
20
21//! A hagyományos architektúra-tervezés dobozokat és nyilakat rajzol (top-down).
22
23//! A morphogenesis alulról felfelé (bottom-up) növeszti a struktúrákat:
24
25//!
26
27//! 1. **Seed** — egyetlen kiinduló pont (szolgáltatás, adatforrás, trigger)
28
29//! 2. **Morphogen Field** — koncentráció-gradiens, ami vezeti a növekedést
30
31//! 3. **Growth** — a seed-ből kiindulva, a morfogén mezőt követve nő a struktúra
32
33//! 4. **Pruning** — gyenge ágak elhalnak, erősek megerősödnek (use-it-or-lose-it)
34
35//! 5. **Expression** — a kinőtt struktúra leképezése Architecture típusra
36
37//!
38
39//! Kapcsolódások:
40
41//! - `architecture_generator.rs` → Architecture, SimulationMetrics
42
43//! - `architecture_simulator.rs` → Architecture, Component, Connection
44
45//! - `mental_sandbox.rs` → szimulációs környezet
46
47//! - `neuroplasticity.rs` → szinaptikus kapcsolatok megerősítése
48
49//! - `vagus.rs` → stressz trigger → növekedés indukálása
50
51//! - `federation.rs` → fingerprint-ek exportálása globális rezonanciához
52
53use std::collections::HashMap;
54
55use std::sync::{Arc, RwLock};
56
57// ─── Növekedési Minták ───────────────────────────────────────────────────────
58
59/// Növekedési algoritmus típusok
60#[derive(Debug, Clone, Copy, PartialEq, Hash)]
61
62pub enum GrowthPattern {
63    /// Gombafonalszerű elágazó hálózat (P2P overlay, elosztott rendszerek)
64    Mycelium,
65
66    /// Kapilláris fraktál-elágazás (adatfolyam pipeline-ok, hierarchikus cache)
67    Capillary,
68
69    /// Nyálkpenész útvonal optimalizálás (CDN, routing, mesh hálózatok)
70    SlimeMold,
71
72    /// L-system self-similar struktúrák (mikro-szolgáltatás hierarchiák)
73    FractalLSystem,
74
75    /// Hibrid: több minta kombinációja
76    Hybrid,
77}
78
79/// Csomópont típusok a kinőtt struktúrában
80#[derive(Debug, Clone, PartialEq, Hash)]
81
82pub enum NodeType {
83    /// Gyökér csomópont (kiindulási pont)
84    Root,
85
86    /// Szolgáltatás / feldolgozó egység
87    Service,
88
89    /// Adatbázis vagy storage node
90    Database,
91
92    /// Cache réteg
93    Cache,
94
95    /// API Gateway / bejárati pont
96    Gateway,
97
98    /// Terheléselosztó
99    LoadBalancer,
100
101    /// Üzenetsor / buffer
102    Queue,
103
104    /// Levél csomópont (végpont, nincs további elágazás)
105    Leaf,
106
107    /// Egyedi típus
108    Custom(String),
109}
110
111/// Kapcsolat típusa
112#[derive(Debug, Clone, PartialEq, Hash)]
113
114pub enum ConnectionType {
115    /// Adatfolyam (data plane)
116    DataFlow,
117
118    /// Vezérlő jelzés (control plane)
119    Control,
120
121    /// Replikáció (adat másolás)
122    Replication,
123
124    /// Backup / helyreállítás
125    Backup,
126}
127
128// ─── Core Adatszerkezetek ───────────────────────────────────────────────────
129
130/// Seed — kiinduló "mag" a növekedéshez
131#[derive(Debug, Clone)]
132
133pub struct Seed {
134    /// Egyedi azonosító
135    pub id: String,
136
137    /// Pozíció a 3D térben (morfogén mező koordináták)
138    pub position: (f64, f64, f64),
139
140    /// Kezdeti energia (maximális növekedési potenciál)
141    pub energy: f64,
142
143    /// Típus címke (pl. "database", "api", "cache")
144    pub type_tag: String,
145
146    /// Növekedési preferencia
147    pub preferred_pattern: Option<GrowthPattern>,
148}
149
150impl Seed {
151    pub fn new(id: &str, x: f64, y: f64, z: f64, type_tag: &str) -> Self {
152        Self {
153            id: id.to_string(),
154
155            position: (x, y, z),
156
157            energy: 100.0,
158
159            type_tag: type_tag.to_string(),
160
161            preferred_pattern: None,
162        }
163    }
164
165    pub fn with_energy(mut self, energy: f64) -> Self {
166        self.energy = energy;
167
168        self
169    }
170
171    pub fn with_pattern(mut self, pattern: GrowthPattern) -> Self {
172        self.preferred_pattern = Some(pattern);
173
174        self
175    }
176
177    /// Deterministic RNG derived from the seed identity, so growth is
178    /// reproducible across runs (same seed → same organism).
179    pub fn rng(&self) -> rand::rngs::StdRng {
180        use rand::SeedableRng;
181        let mut h = 0xcbf29ce484222325u64;
182        for b in self.id.as_bytes() {
183            h ^= *b as u64;
184            h = h.wrapping_mul(0x100000001b3);
185        }
186        h = h.wrapping_mul(31).wrapping_add(self.position.0.to_bits());
187        h = h.wrapping_mul(31).wrapping_add(self.position.1.to_bits());
188        h = h.wrapping_mul(31).wrapping_add(self.position.2.to_bits());
189        rand::rngs::StdRng::seed_from_u64(h)
190    }
191}
192
193/// Morfogén koncentráció mező — biológiai "illat" gradiensek
194#[derive(Debug, Clone)]
195
196pub struct MorphogenField {
197    /// Koncentráció értékek a 3D rácsban
198    pub gradients: HashMap<(i32, i32, i32), f64>,
199
200    /// Gradiens források (vonzó és taszító pontok)
201    pub attractors: Vec<(f64, f64, f64, f64)>, // (x, y, z, strength)
202
203    pub repellents: Vec<(f64, f64, f64, f64)>,
204
205    /// Diffúziós ráta (mennyire terjed szét a gradiens)
206    pub diffusion_rate: f64,
207
208    /// Párolgási ráta (mennyire gyengül idővel)
209    pub evaporation_rate: f64,
210}
211
212impl Default for MorphogenField {
213    fn default() -> Self {
214        Self::new()
215    }
216}
217
218impl MorphogenField {
219    pub fn new() -> Self {
220        Self {
221            gradients: HashMap::new(),
222
223            attractors: Vec::new(),
224
225            repellents: Vec::new(),
226
227            diffusion_rate: 0.1,
228
229            evaporation_rate: 0.01,
230        }
231    }
232
233    /// Koncentráció lekérése egy adott pontban (tricubic interpoláció)
234    pub fn concentration_at(&self, x: f64, y: f64, z: f64) -> f64 {
235        let gx = x.floor() as i32;
236
237        let gy = y.floor() as i32;
238
239        let gz = z.floor() as i32;
240
241        let mut total = 0.0;
242
243        for dx in -1..=1 {
244            for dy in -1..=1 {
245                for dz in -1..=1 {
246                    if let Some(val) = self.gradients.get(&(gx + dx, gy + dy, gz + dz)) {
247                        let dist = ((x - (gx + dx) as f64).powi(2)
248                            + (y - (gy + dy) as f64).powi(2)
249                            + (z - (gz + dz) as f64).powi(2))
250                        .sqrt()
251                        .max(0.001);
252
253                        total += val / dist;
254                    }
255                }
256            }
257        }
258
259        // Attraktorok hozzáadása
260
261        for (ax, ay, az, strength) in &self.attractors {
262            let dist = ((x - ax).powi(2) + (y - ay).powi(2) + (z - az).powi(2))
263                .sqrt()
264                .max(0.001);
265
266            total += strength / dist;
267        }
268
269        // Repellensek kivonása
270
271        for (rx, ry, rz, strength) in &self.repellents {
272            let dist = ((x - rx).powi(2) + (y - ry).powi(2) + (z - rz).powi(2))
273                .sqrt()
274                .max(0.001);
275
276            total -= strength / dist;
277        }
278
279        total
280    }
281
282    /// Új attraktor hozzáadása
283    pub fn add_attractor(&mut self, x: f64, y: f64, z: f64, strength: f64) {
284        self.attractors.push((x, y, z, strength));
285
286        let key = (x.floor() as i32, y.floor() as i32, z.floor() as i32);
287
288        *self.gradients.entry(key).or_insert(0.0) += strength;
289    }
290
291    /// Gradiens diffúzió egy lépése
292    pub fn diffuse(&mut self) {
293        let old = self.gradients.clone();
294
295        for ((x, y, z), val) in &old {
296            if *val < 0.001 {
297                continue;
298            }
299
300            for dx in -1..=1 {
301                for dy in -1..=1 {
302                    for dz in -1..=1 {
303                        if dx == 0 && dy == 0 && dz == 0 {
304                            continue;
305                        }
306
307                        let spread = val * self.diffusion_rate / 26.0;
308
309                        *self
310                            .gradients
311                            .entry((x + dx, y + dy, z + dz))
312                            .or_insert(0.0) += spread;
313                    }
314                }
315            }
316        }
317    }
318
319    /// Párologtatás (gyenge gradiensek eltüntetése)
320    pub fn evaporate(&mut self) {
321        self.gradients.retain(|_, v| {
322            *v *= 1.0 - self.evaporation_rate;
323
324            *v > 0.001
325        });
326    }
327}
328
329/// Növekedési konfigurációs paraméterek
330#[derive(Debug, Clone)]
331
332pub struct GrowthConfig {
333    /// Növekedési minta
334    pub pattern: GrowthPattern,
335
336    /// Maximum node-ok száma
337    pub max_nodes: usize,
338
339    /// Elágazási valószínűség (0.0 - 1.0)
340    pub branching_probability: f64,
341
342    /// Elágazási szög (radián)
343    pub branching_angle: f64,
344
345    /// Energia bomlási ráta (mennyit veszít egy ág hosszegységenként)
346    pub energy_decay: f64,
347
348    /// Minimum energia az elágazáshoz
349    pub min_energy_for_branch: f64,
350
351    /// Maximális növekedési mélység (hány generáció)
352    pub max_depth: u32,
353
354    /// Anastomosis (fúzió) valószínűsége
355    pub anastomosis_probability: f64,
356
357    /// Pruning threshold (mennyi ideig használatlan ág haljon el)
358    pub prune_idle_cycles: u32,
359
360    /// Slime mold specifikus: nyom megőrzési ráta
361    pub trail_persistence: f64,
362
363    /// Slime mold specifikus: nyom párolgási ráta
364    pub trail_evaporation: f64,
365
366    /// L-system specifikus: produkciós szabályok
367    pub lsystem_rules: Vec<(char, String)>,
368}
369
370impl Default for GrowthConfig {
371    fn default() -> Self {
372        Self {
373            pattern: GrowthPattern::Mycelium,
374
375            max_nodes: 500,
376
377            branching_probability: 0.3,
378
379            branching_angle: 0.6,
380
381            energy_decay: 0.1,
382
383            min_energy_for_branch: 30.0,
384
385            max_depth: 20,
386
387            anastomosis_probability: 0.05,
388
389            prune_idle_cycles: 10,
390
391            trail_persistence: 0.9,
392
393            trail_evaporation: 0.05,
394
395            lsystem_rules: vec![('A', "AB".to_string()), ('B', "A[B]A".to_string())],
396        }
397    }
398}
399
400impl GrowthConfig {
401    pub fn mycelium_default() -> Self {
402        Self {
403            pattern: GrowthPattern::Mycelium,
404
405            branching_probability: 0.35,
406
407            branching_angle: 0.8,
408
409            energy_decay: 0.08,
410
411            min_energy_for_branch: 25.0,
412
413            anastomosis_probability: 0.08,
414
415            ..Self::default()
416        }
417    }
418
419    pub fn capillary_default() -> Self {
420        Self {
421            pattern: GrowthPattern::Capillary,
422
423            branching_probability: 0.5,
424
425            branching_angle: 0.4,
426
427            energy_decay: 0.15,
428
429            min_energy_for_branch: 20.0,
430
431            max_depth: 12,
432
433            ..Self::default()
434        }
435    }
436
437    pub fn slime_mold_default() -> Self {
438        Self {
439            pattern: GrowthPattern::SlimeMold,
440
441            max_nodes: 300,
442
443            trail_persistence: 0.9,
444
445            trail_evaporation: 0.01,
446
447            ..Self::default()
448        }
449    }
450
451    pub fn fractal_lsystem_default() -> Self {
452        Self {
453            pattern: GrowthPattern::FractalLSystem,
454
455            branching_angle: 0.5,
456
457            max_depth: 8,
458
459            lsystem_rules: vec![('F', "FF+[+F-F-F]-[-F+F+F]".to_string())],
460
461            ..Self::default()
462        }
463    }
464}
465
466/// Csomópont a kinőtt struktúrában
467#[derive(Debug, Clone)]
468
469pub struct MorphNode {
470    pub id: usize,
471
472    pub position: (f64, f64, f64),
473
474    pub node_type: NodeType,
475
476    pub name: String,
477
478    pub latency_base_ms: f64,
479
480    pub capacity: f64,
481
482    pub energy: f64,
483
484    pub depth: u32,
485
486    pub metadata: HashMap<String, String>,
487}
488
489/// Kapcsolat két csomópont között
490#[derive(Debug, Clone)]
491
492pub struct MorphConnection {
493    pub id: usize,
494
495    pub from_node: usize,
496
497    pub to_node: usize,
498
499    pub weight: f64,
500
501    pub bandwidth: f64,
502
503    pub protocol: String,
504
505    pub latency_ms: f64,
506
507    pub connection_type: ConnectionType,
508
509    pub is_active: bool,
510
511    pub age_cycles: u32,
512}
513
514/// Növekedési statisztikák
515#[derive(Debug, Clone)]
516
517pub struct GrowthMetrics {
518    pub node_count: usize,
519
520    pub connection_count: usize,
521
522    pub max_depth: u32,
523
524    pub avg_branching_factor: f64,
525
526    pub fractal_dimension: f64,
527
528    pub total_energy: f64,
529
530    pub redundancy_score: f64,
531
532    pub avg_path_length: f64,
533}
534
535/// Organizmus — a teljes kinőtt struktúra
536#[derive(Debug, Clone)]
537
538pub struct Organism {
539    pub id: String,
540
541    pub name: String,
542
543    pub nodes: Vec<MorphNode>,
544
545    pub connections: Vec<MorphConnection>,
546
547    pub growth_pattern: GrowthPattern,
548
549    pub generation: u32,
550
551    pub fitness_score: f64,
552
553    pub age_cycles: u32,
554
555    pub seed: Seed,
556
557    pub metrics: Option<GrowthMetrics>,
558
559    pub metadata: HashMap<String, String>,
560}
561
562impl Organism {
563    pub fn new(id: &str, name: &str, seed: Seed, pattern: GrowthPattern) -> Self {
564        Self {
565            id: id.to_string(),
566
567            name: name.to_string(),
568
569            nodes: Vec::new(),
570
571            connections: Vec::new(),
572
573            growth_pattern: pattern,
574
575            generation: 0,
576
577            fitness_score: 0.0,
578
579            age_cycles: 0,
580
581            seed,
582
583            metrics: None,
584
585            metadata: HashMap::new(),
586        }
587    }
588
589    /// Statisztikák számítása
590    pub fn calculate_metrics(&mut self) -> GrowthMetrics {
591        let node_count = self.nodes.len();
592
593        let connection_count = self.connections.len();
594
595        let max_depth = self.nodes.iter().map(|n| n.depth).max().unwrap_or(0);
596
597        // Átlagos elágazási faktor
598
599        let branching = if node_count > 1 {
600            let internal_nodes = self
601                .nodes
602                .iter()
603                .filter(|n| {
604                    self.connections
605                        .iter()
606                        .filter(|c| c.from_node == n.id)
607                        .count()
608                        > 1
609                })
610                .count();
611
612            internal_nodes as f64 / node_count.max(1) as f64
613        } else {
614            0.0
615        };
616
617        // Redundancia: kapcsolatok száma / minimálisan szükséges kapcsolatok
618
619        let redundancy = if node_count > 1 {
620            connection_count as f64 / (node_count - 1).max(1) as f64
621        } else {
622            0.0
623        };
624
625        // Átlagos útvonal hossz (egyszerű becslés)
626
627        let avg_path = if connection_count > 0 && node_count > 1 {
628            (node_count as f64).ln() / (redundancy.max(0.1)).ln()
629        } else {
630            0.0
631        };
632
633        let total_energy: f64 = self.nodes.iter().map(|n| n.energy).sum();
634
635        let metrics = GrowthMetrics {
636            node_count,
637
638            connection_count,
639
640            max_depth,
641
642            avg_branching_factor: branching,
643
644            fractal_dimension: (node_count as f64).ln() / ((max_depth.max(2)) as f64).ln(),
645
646            total_energy,
647
648            redundancy_score: redundancy,
649
650            avg_path_length: avg_path,
651        };
652
653        self.metrics = Some(metrics.clone());
654
655        metrics
656    }
657
658    /// Energia szint ellenőrzése
659    pub fn is_alive(&self) -> bool {
660        self.nodes.iter().any(|n| n.energy > 0.0)
661    }
662
663    /// Életkor növelése
664    pub fn age_one_cycle(&mut self) {
665        self.age_cycles += 1;
666
667        for node in &mut self.nodes {
668            node.energy *= 0.99; // Természetes energia vesztés
669        }
670    }
671}
672
673// ─── Növekedési Algoritmusok ─────────────────────────────────────────────────
674
675// Segédfüggvény: véletlen vektor egy gömb felületén
676
677use rand::Rng;
678
679fn random_direction(rng: &mut impl Rng) -> (f64, f64, f64) {
680    let theta = rng.gen::<f64>() * std::f64::consts::TAU;
681
682    let phi = (rng.gen::<f64>() * 2.0 - 1.0).acos();
683
684    (
685        theta.sin() * phi.cos(),
686        theta.sin() * phi.sin(),
687        theta.cos(),
688    )
689}
690
691/// Mycelium (gombafonalszerű) növekedés
692/// Indul egy seed-ből, hifák nőnek ki véletlen irányokba elágazva.
693/// A hifák követik a morfogén gradienseket.
694/// Két hifa találkozásakor anastomosis (fúzió) történhet.
695pub fn mycelium_growth(seed: &Seed, field: &MorphogenField, config: &GrowthConfig) -> Organism {
696    let mut rng = seed.rng();
697    let mut organism = Organism::new(
698        &format!("mycelium_{}", rng.gen::<u32>()),
699        &format!("Mycelium_{}", seed.type_tag),
700        seed.clone(),
701        GrowthPattern::Mycelium,
702    );
703
704    // Gyökér csomópont
705
706    organism.nodes.push(MorphNode {
707        id: 0,
708
709        position: seed.position,
710
711        node_type: NodeType::Root,
712
713        name: format!("root_{}", seed.type_tag),
714
715        latency_base_ms: 1.0,
716
717        capacity: 100.0,
718
719        energy: seed.energy,
720
721        depth: 0,
722
723        metadata: HashMap::new(),
724    });
725
726    // Aktív hifa csúcsok (tip)
727
728    struct HyphaTip {
729        node_id: usize,
730
731        position: (f64, f64, f64),
732
733        direction: (f64, f64, f64),
734
735        energy: f64,
736
737        depth: u32,
738
739        idle_cycles: u32,
740    }
741
742    let mut tips: Vec<HyphaTip> = vec![HyphaTip {
743        node_id: 0,
744
745        position: seed.position,
746
747        direction: random_direction(&mut rng),
748
749        energy: seed.energy,
750
751        depth: 0,
752
753        idle_cycles: 0,
754    }];
755
756    let mut next_node_id = 1;
757
758    let mut next_conn_id = 1;
759
760    let mut grown = 0;
761
762    while grown < config.max_nodes && !tips.is_empty() {
763        let mut new_tips = Vec::new();
764
765        let mut dead_indices = Vec::new();
766
767        for (idx, tip) in tips.iter_mut().enumerate() {
768            if tip.energy <= 0.0 || tip.depth >= config.max_depth {
769                dead_indices.push(idx);
770
771                continue;
772            }
773
774            // Gradiens követés: a morfogén mező irányába igazítjuk az irányt
775
776            let (cx, cy, cz) = tip.position;
777
778            let current_conc = field.concentration_at(cx, cy, cz);
779
780            let step = 0.5;
781
782            let (gx, gy, gz) = if current_conc > 0.01 {
783                let forward = field.concentration_at(
784                    cx + tip.direction.0 * step,
785                    cy + tip.direction.1 * step,
786                    cz + tip.direction.2 * step,
787                );
788
789                if forward > current_conc {
790                    tip.direction // már jó irány
791                } else {
792                    // Próbáljunk jobb irányt
793
794                    let mut best_dir = tip.direction;
795
796                    let mut best_conc = forward;
797
798                    for _ in 0..8 {
799                        let test_dir = random_direction(&mut rng);
800
801                        let tc = field.concentration_at(
802                            cx + test_dir.0 * step,
803                            cy + test_dir.1 * step,
804                            cz + test_dir.2 * step,
805                        );
806
807                        if tc > best_conc {
808                            best_conc = tc;
809
810                            best_dir = test_dir;
811                        }
812                    }
813
814                    best_dir
815                }
816            } else {
817                tip.direction
818            };
819
820            // Elágazás
821
822            if rng.gen::<f64>() < config.branching_probability
823                && tip.energy > config.min_energy_for_branch
824                && grown < config.max_nodes - 1
825            {
826                let branch_dir = random_direction(&mut rng);
827
828                let branch_energy = tip.energy * 0.6;
829
830                let new_id = next_node_id;
831
832                next_node_id += 1;
833
834                grown += 1;
835
836                organism.nodes.push(MorphNode {
837                    id: new_id,
838
839                    position: tip.position,
840
841                    node_type: NodeType::Service,
842
843                    name: format!("hypha_{}", new_id),
844
845                    latency_base_ms: 2.0 + rng.gen::<f64>() * 5.0,
846
847                    capacity: 30.0 + rng.gen::<f64>() * 70.0,
848
849                    energy: branch_energy,
850
851                    depth: tip.depth + 1,
852
853                    metadata: HashMap::new(),
854                });
855
856                organism.connections.push(MorphConnection {
857                    id: next_conn_id,
858
859                    from_node: tip.node_id,
860
861                    to_node: new_id,
862
863                    weight: 0.5,
864
865                    bandwidth: 1000.0 + rng.gen::<f64>() * 9000.0,
866
867                    protocol: "gRPC".to_string(),
868
869                    latency_ms: 1.0,
870
871                    connection_type: ConnectionType::DataFlow,
872
873                    is_active: true,
874
875                    age_cycles: 0,
876                });
877
878                next_conn_id += 1;
879
880                new_tips.push(HyphaTip {
881                    node_id: new_id,
882
883                    position: tip.position,
884
885                    direction: branch_dir,
886
887                    energy: branch_energy,
888
889                    depth: tip.depth + 1,
890
891                    idle_cycles: 0,
892                });
893
894                tip.energy *= 0.5;
895            }
896
897            // Növekedés előre
898
899            let nx = cx + gx * step;
900
901            let ny = cy + gy * step;
902
903            let nz = cz + gz * step;
904
905            tip.position = (nx, ny, nz);
906
907            tip.energy -= config.energy_decay;
908
909            tip.idle_cycles += 1;
910
911            // Anastomosis: ha egy másik node közelében vagyunk
912
913            for node in &organism.nodes {
914                if node.id == tip.node_id {
915                    continue;
916                }
917
918                let dist = ((nx - node.position.0).powi(2)
919                    + (ny - node.position.1).powi(2)
920                    + (nz - node.position.2).powi(2))
921                .sqrt();
922
923                if dist < 0.8 && rng.gen::<f64>() < config.anastomosis_probability {
924                    organism.connections.push(MorphConnection {
925                        id: next_conn_id,
926
927                        from_node: tip.node_id,
928
929                        to_node: node.id,
930
931                        weight: 0.7,
932
933                        bandwidth: 2000.0 + rng.gen::<f64>() * 8000.0,
934
935                        protocol: "gRPC".to_string(),
936
937                        latency_ms: 0.5,
938
939                        connection_type: ConnectionType::DataFlow,
940
941                        is_active: true,
942
943                        age_cycles: 0,
944                    });
945
946                    next_conn_id += 1;
947
948                    dead_indices.push(idx);
949
950                    break;
951                }
952            }
953        }
954
955        // Halott tippek eltávolítása
956
957        dead_indices.sort_unstable();
958
959        dead_indices.dedup();
960
961        for i in dead_indices.into_iter().rev() {
962            if i < tips.len() {
963                tips.remove(i);
964            }
965        }
966
967        tips.extend(new_tips);
968
969        // Idle pruning
970
971        tips.retain(|t| t.idle_cycles < config.prune_idle_cycles);
972    }
973
974    organism.calculate_metrics();
975
976    organism
977}
978
979/// Kapilláris fraktál-elágazás
980/// Hierarchikus elágazás: gyökér → artéria → arteriole → kapilláris.
981/// Minden elágazásnál a kapacitás oszlik meg az ágak között.
982/// A kapilláris szinten történik az adatcsere (leaf node-ok).
983pub fn capillary_growth(seed: &Seed, field: &MorphogenField, config: &GrowthConfig) -> Organism {
984    let mut rng = seed.rng();
985    let mut organism = Organism::new(
986        &format!("capillary_{}", rng.gen::<u32>()),
987        &format!("Capillary_{}", seed.type_tag),
988        seed.clone(),
989        GrowthPattern::Capillary,
990    );
991
992    // Gyökér csomópont
993
994    organism.nodes.push(MorphNode {
995        id: 0,
996
997        position: seed.position,
998
999        node_type: NodeType::Root,
1000
1001        name: format!("root_{}", seed.type_tag),
1002
1003        latency_base_ms: 0.5,
1004
1005        capacity: 1000.0,
1006
1007        energy: seed.energy,
1008
1009        depth: 0,
1010
1011        metadata: HashMap::new(),
1012    });
1013
1014    let mut next_node_id = 1;
1015
1016    let mut next_conn_id = 1;
1017
1018    // Rekurzív elágazás építése
1019
1020    #[allow(clippy::too_many_arguments)]
1021    fn branch(
1022        organism: &mut Organism,
1023
1024        parent_id: usize,
1025
1026        parent_pos: (f64, f64, f64),
1027
1028        parent_capacity: f64,
1029
1030        depth: u32,
1031
1032        max_depth: u32,
1033
1034        angle: f64,
1035
1036        field: &MorphogenField,
1037
1038        next_node_id: &mut usize,
1039
1040        next_conn_id: &mut usize,
1041    ) {
1042        if depth >= max_depth || *next_node_id >= 500 {
1043            // Leaf node
1044
1045            organism.nodes.push(MorphNode {
1046                id: *next_node_id,
1047
1048                position: parent_pos,
1049
1050                node_type: NodeType::Leaf,
1051
1052                name: format!("capillary_{}", *next_node_id),
1053
1054                latency_base_ms: 10.0 + depth as f64 * 2.0,
1055
1056                capacity: parent_capacity * 0.1,
1057
1058                energy: 100.0 - depth as f64 * 5.0,
1059
1060                depth,
1061
1062                metadata: HashMap::new(),
1063            });
1064
1065            organism.connections.push(MorphConnection {
1066                id: *next_conn_id,
1067
1068                from_node: parent_id,
1069
1070                to_node: *next_node_id,
1071
1072                weight: 0.5,
1073
1074                bandwidth: parent_capacity * 0.1,
1075
1076                protocol: if depth > 3 {
1077                    "local".to_string()
1078                } else {
1079                    "HTTP/2".to_string()
1080                },
1081
1082                latency_ms: 1.0 + depth as f64,
1083
1084                connection_type: ConnectionType::DataFlow,
1085
1086                is_active: true,
1087
1088                age_cycles: 0,
1089            });
1090
1091            *next_node_id += 1;
1092
1093            *next_conn_id += 1;
1094
1095            return;
1096        }
1097
1098        // Két ágra osztódás
1099
1100        let directions = [
1101            (angle.cos(), angle.sin(), 0.0),
1102            (angle.cos(), -angle.sin(), 0.0),
1103        ];
1104
1105        // 3D: néha Z irányba is
1106
1107        let use_z = if depth > 2 && depth.is_multiple_of(2) {
1108            [
1109                (angle.cos(), 0.0, angle.sin()),
1110                (0.0, angle.cos(), angle.sin()),
1111            ]
1112        } else {
1113            directions
1114        };
1115
1116        let step = 1.0 / (depth + 1) as f64;
1117
1118        let child_capacity = parent_capacity * 0.6;
1119
1120        for (i, &(dx, dy, dz)) in use_z.iter().enumerate() {
1121            let child_pos = (
1122                parent_pos.0 + dx * step,
1123                parent_pos.1 + dy * step,
1124                parent_pos.2 + dz * step,
1125            );
1126
1127            // Gradiens hatás: vonzódás az attraktorok felé
1128
1129            let attr_conc = field.concentration_at(child_pos.0, child_pos.1, child_pos.2);
1130
1131            let adjusted_pos = if attr_conc > 0.1 {
1132                (
1133                    child_pos.0 + attr_conc * 0.1,
1134                    child_pos.1 + attr_conc * 0.1,
1135                    child_pos.2 + attr_conc * 0.1,
1136                )
1137            } else {
1138                child_pos
1139            };
1140
1141            let child_id = *next_node_id;
1142
1143            *next_node_id += 1;
1144
1145            let node_type = if depth < 2 {
1146                NodeType::Gateway
1147            } else if depth < 4 {
1148                NodeType::LoadBalancer
1149            } else if depth < 6 {
1150                NodeType::Service
1151            } else {
1152                NodeType::Cache
1153            };
1154
1155            organism.nodes.push(MorphNode {
1156                id: child_id,
1157
1158                position: adjusted_pos,
1159
1160                node_type,
1161
1162                name: format!("branch_{}_{}", depth, i),
1163
1164                latency_base_ms: 1.0 + depth as f64 * 1.5,
1165
1166                capacity: child_capacity,
1167
1168                energy: 100.0 - depth as f64 * 3.0,
1169
1170                depth,
1171
1172                metadata: HashMap::new(),
1173            });
1174
1175            organism.connections.push(MorphConnection {
1176                id: *next_conn_id,
1177
1178                from_node: parent_id,
1179
1180                to_node: child_id,
1181
1182                weight: 0.6 - depth as f64 * 0.02,
1183
1184                bandwidth: child_capacity,
1185
1186                protocol: if depth < 3 {
1187                    "HTTP/2".to_string()
1188                } else {
1189                    "gRPC".to_string()
1190                },
1191
1192                latency_ms: 1.0 + depth as f64 * 0.5,
1193
1194                connection_type: ConnectionType::DataFlow,
1195
1196                is_active: true,
1197
1198                age_cycles: 0,
1199            });
1200
1201            *next_conn_id += 1;
1202
1203            // Rekurzió
1204
1205            branch(
1206                organism,
1207                child_id,
1208                adjusted_pos,
1209                child_capacity,
1210                depth + 1,
1211                max_depth,
1212                angle * 0.85,
1213                field,
1214                next_node_id,
1215                next_conn_id,
1216            );
1217        }
1218
1219        // Visszirányú kapcsolat (redundancia)
1220
1221        if depth > 1 && depth < 4 && use_z.len() >= 2 {
1222            let from_id = *next_node_id - 1;
1223
1224            let to_id = *next_node_id - 2;
1225
1226            organism.connections.push(MorphConnection {
1227                id: *next_conn_id,
1228
1229                from_node: from_id,
1230
1231                to_node: to_id,
1232
1233                weight: 0.2,
1234
1235                bandwidth: child_capacity * 0.3,
1236
1237                protocol: "backup".to_string(),
1238
1239                latency_ms: 5.0,
1240
1241                connection_type: ConnectionType::Replication,
1242
1243                is_active: true,
1244
1245                age_cycles: 0,
1246            });
1247
1248            *next_conn_id += 1;
1249        }
1250    }
1251
1252    branch(
1253        &mut organism,
1254        0,
1255        seed.position,
1256        1000.0,
1257        1,
1258        config.max_depth,
1259        config.branching_angle,
1260        field,
1261        &mut next_node_id,
1262        &mut next_conn_id,
1263    );
1264
1265    organism.calculate_metrics();
1266
1267    organism
1268}
1269
1270/// Nyálkpenész (Physarum polycephalum) szimuláció
1271/// Rács alapú szimuláció: részecskék mozognak a rácson, nyomot hagynak maguk után.
1272/// A nyom vonzza a többi részecskét (autokatalízis).
1273/// A párolgás gyengíti a régi nyomokat.
1274/// Tápanyag források = seed pozíciók.
1275/// Az eredmény: optimális útvonal hálózat a források között.
1276pub fn slime_mold_growth(seed: &Seed, field: &MorphogenField, config: &GrowthConfig) -> Organism {
1277    let mut rng = seed.rng();
1278    let mut organism = Organism::new(
1279        &format!("slime_{}", rng.gen::<u32>()),
1280        &format!("SlimeMold_{}", seed.type_tag),
1281        seed.clone(),
1282        GrowthPattern::SlimeMold,
1283    );
1284
1285    // Rács inicializálása
1286
1287    let grid_size = 64;
1288
1289    let mut trail: Vec<Vec<f64>> = vec![vec![0.0; grid_size]; grid_size];
1290
1291    let mut particles: Vec<(f64, f64, f64)> = Vec::new(); // (x, y, angle)
1292
1293    // Tápanyag források a seed körül
1294
1295    let food_sources: Vec<(usize, usize)> = (0..8)
1296        .map(|i| {
1297            let fx = ((seed.position.0 + (i as f64 * 3.0).sin() * 20.0) as usize)
1298                .clamp(0, grid_size - 1);
1299
1300            let fy = ((seed.position.1 + (i as f64 * 3.0).cos() * 20.0) as usize)
1301                .clamp(0, grid_size - 1);
1302
1303            trail[fy][fx] = 1.0; // Food marker
1304
1305            (fx, fy)
1306        })
1307        .collect();
1308
1309    // Részecskék indítása a seed-ből
1310
1311    for _ in 0..50 {
1312        let angle = rng.gen::<f64>() * std::f64::consts::TAU;
1313
1314        particles.push((
1315            seed.position.0.max(0.0).min(grid_size as f64 - 1.0),
1316            seed.position.1.max(0.0).min(grid_size as f64 - 1.0),
1317            angle,
1318        ));
1319    }
1320
1321    // Szimulációs lépések
1322
1323    let sensor_angle = std::f64::consts::FRAC_PI_4; // 45 fok
1324
1325    let sensor_distance = 3.0;
1326
1327    let rotation_angle = std::f64::consts::FRAC_PI_6; // 30 fok
1328
1329    let step_size = 1.0;
1330
1331    let mut grid_attractors: HashMap<(i32, i32), f64> = HashMap::new();
1332
1333    for _step in 0..1000 {
1334        for particle in &mut particles {
1335            let (px, py, angle) = *particle;
1336
1337            // Szenzorok: előre, balra, jobbra
1338
1339            let sensors = [
1340                (angle, 1.0),                      // előre
1341                (angle - sensor_angle, 1.0),       // balra
1342                (angle + sensor_angle, 1.0),       // jobbra
1343                (angle - sensor_angle * 2.0, 0.8), // balra távolabb
1344                (angle + sensor_angle * 2.0, 0.8), // jobbra távolabb
1345            ];
1346
1347            let mut best_conc = -1.0;
1348
1349            let mut best_angle = angle;
1350
1351            for (sensor_angle, weight) in &sensors {
1352                let sensor_x = (px + sensor_angle.cos() * sensor_distance) as usize;
1353
1354                let sensor_y = (py + sensor_angle.sin() * sensor_distance) as usize;
1355
1356                if sensor_x < grid_size && sensor_y < grid_size {
1357                    let trail_val = trail[sensor_y][sensor_x];
1358
1359                    let conc = trail_val * weight;
1360
1361                    // Field hatás
1362
1363                    let field_val = field.concentration_at(sensor_x as f64, sensor_y as f64, 0.0);
1364
1365                    let total = conc + field_val * 0.3;
1366
1367                    if total > best_conc {
1368                        best_conc = total;
1369
1370                        best_angle = *sensor_angle;
1371                    }
1372                }
1373            }
1374
1375            // Irány váltás a legjobb szenzor felé
1376
1377            let new_angle = if best_conc < 0.0 {
1378                angle + (rng.gen::<f64>() - 0.5) * rotation_angle * 2.0
1379            } else {
1380                let diff = best_angle - angle;
1381
1382                if diff.abs() > rotation_angle {
1383                    angle + rotation_angle.copysign(diff)
1384                } else {
1385                    best_angle
1386                }
1387            };
1388
1389            // Mozgás
1390
1391            let new_x = px + new_angle.cos() * step_size;
1392
1393            let new_y = py + new_angle.sin() * step_size;
1394
1395            // Grid határok ellenőrzése
1396
1397            if new_x >= 0.0
1398                && new_x < grid_size as f64 - 1.0
1399                && new_y >= 0.0
1400                && new_y < grid_size as f64 - 1.0
1401            {
1402                particle.0 = new_x;
1403
1404                particle.1 = new_y;
1405
1406                particle.2 = new_angle;
1407
1408                // Nyom lerakása
1409
1410                let gx = new_x as usize;
1411
1412                let gy = new_y as usize;
1413
1414                trail[gy][gx] = (trail[gy][gx] + config.trail_persistence).min(1.0);
1415
1416                // Grid attraktorok gyűjtése a struktúrához
1417
1418                let key = (gx as i32, gy as i32);
1419
1420                *grid_attractors.entry(key).or_insert(0.0) += 0.01;
1421            }
1422        }
1423
1424        // Párolgás
1425
1426        for row in trail.iter_mut() {
1427            for cell in row.iter_mut() {
1428                *cell *= 1.0 - config.trail_evaporation;
1429
1430                if *cell < 0.01 {
1431                    *cell = 0.0;
1432                }
1433            }
1434        }
1435    }
1436
1437    // Grid attraktorok → node-ok és kapcsolatok
1438
1439    let mut id_map: HashMap<(i32, i32), usize> = HashMap::new();
1440
1441    let mut next_id = 0;
1442
1443    let mut next_conn = 1;
1444
1445    // Erős nyomokból node-ok
1446
1447    for (y, row) in trail.iter().enumerate() {
1448        for (x, &cell) in row.iter().enumerate() {
1449            if cell > 0.15 {
1450                let node_id = next_id;
1451
1452                next_id += 1;
1453
1454                id_map.insert((x as i32, y as i32), node_id);
1455
1456                let node_type = if food_sources.contains(&(x, y)) {
1457                    NodeType::Root
1458                } else if trail[y][x] > 0.8 {
1459                    NodeType::Gateway
1460                } else if trail[y][x] > 0.5 {
1461                    NodeType::Service
1462                } else {
1463                    NodeType::Cache
1464                };
1465
1466                organism.nodes.push(MorphNode {
1467                    id: node_id,
1468
1469                    position: (x as f64, y as f64, 0.0),
1470
1471                    node_type,
1472
1473                    name: format!("slime_{}", node_id),
1474
1475                    latency_base_ms: 5.0 - trail[y][x] * 3.0,
1476
1477                    capacity: trail[y][x] * 100.0,
1478
1479                    energy: trail[y][x] * 50.0,
1480
1481                    depth: 0,
1482
1483                    metadata: HashMap::new(),
1484                });
1485            }
1486        }
1487    }
1488
1489    // Kapcsolatok a szomszédos node-ok között
1490
1491    for (&(x, y), &from_id) in &id_map {
1492        for (dx, dy) in &[(1, 0), (0, 1), (1, 1), (-1, 1)] {
1493            let nx = x + dx;
1494
1495            let ny = y + dy;
1496
1497            if let Some(&to_id) = id_map.get(&(nx, ny)) {
1498                let avg_trail =
1499                    (trail[y as usize][x as usize] + trail[ny as usize][nx as usize]) / 2.0;
1500
1501                organism.connections.push(MorphConnection {
1502                    id: next_conn,
1503
1504                    from_node: from_id,
1505
1506                    to_node: to_id,
1507
1508                    weight: avg_trail,
1509
1510                    bandwidth: avg_trail * 10000.0,
1511
1512                    protocol: "gRPC".to_string(),
1513
1514                    latency_ms: (1.0 - avg_trail).max(0.1) * 10.0,
1515
1516                    connection_type: ConnectionType::DataFlow,
1517
1518                    is_active: true,
1519
1520                    age_cycles: 0,
1521                });
1522
1523                next_conn += 1;
1524            }
1525        }
1526    }
1527
1528    organism.calculate_metrics();
1529
1530    organism
1531}
1532
1533/// L-system fraktál növekedés
1534/// Turtle-graphics szimuláció 3D-ben.
1535/// Axióma + produkciós szabályok iteratív alkalmazása.
1536/// Minden szimbólum egy node típust és növekedési irányt reprezentál.
1537pub fn fractal_growth(seed: &Seed, _field: &MorphogenField, config: &GrowthConfig) -> Organism {
1538    let mut rng = seed.rng();
1539    let mut organism = Organism::new(
1540        &format!("fractal_{}", rng.gen::<u32>()),
1541        &format!("Fractal_{}", seed.type_tag),
1542        seed.clone(),
1543        GrowthPattern::FractalLSystem,
1544    );
1545
1546    // L-system generálás
1547
1548    let axiom = if seed.type_tag.contains("cache") {
1549        "F[+F][-F]F"
1550    } else if seed.type_tag.contains("database") {
1551        "F[+F[+F][-F]][-F[+F][-F]]"
1552    } else {
1553        "F+F+F+F"
1554    };
1555
1556    let mut current = axiom.to_string();
1557
1558    for _gen in 0..config.max_depth {
1559        let mut next = String::new();
1560
1561        for ch in current.chars() {
1562            let mut replaced = false;
1563
1564            for (rule_from, rule_to) in &config.lsystem_rules {
1565                if ch == *rule_from {
1566                    next.push_str(rule_to);
1567
1568                    replaced = true;
1569
1570                    break;
1571                }
1572            }
1573
1574            if !replaced {
1575                next.push(ch);
1576            }
1577        }
1578
1579        current = next;
1580
1581        if current.len() > 2000 {
1582            break;
1583        } // Limit a túlcsordulás ellen
1584    }
1585
1586    // Turtle graphics interpreter
1587
1588    struct TurtleState {
1589        x: f64,
1590        y: f64,
1591        z: f64,
1592
1593        angle_xy: f64,
1594
1595        angle_z: f64,
1596    }
1597
1598    let mut turtle = TurtleState {
1599        x: seed.position.0,
1600
1601        y: seed.position.1,
1602
1603        z: seed.position.2,
1604
1605        angle_xy: 0.0,
1606
1607        angle_z: 0.0,
1608    };
1609
1610    let mut node_stack: Vec<(usize, TurtleState)> = Vec::new();
1611
1612    let mut next_node_id = 0;
1613
1614    let mut next_conn_id = 1;
1615
1616    // Root node
1617
1618    organism.nodes.push(MorphNode {
1619        id: next_node_id,
1620
1621        position: (turtle.x, turtle.y, turtle.z),
1622
1623        node_type: NodeType::Root,
1624
1625        name: "fractal_root".to_string(),
1626
1627        latency_base_ms: 0.5,
1628
1629        capacity: 100.0,
1630
1631        energy: 100.0,
1632
1633        depth: 0,
1634
1635        metadata: HashMap::new(),
1636    });
1637
1638    let mut last_node_id = next_node_id;
1639
1640    next_node_id += 1;
1641
1642    for ch in current.chars() {
1643        if next_node_id >= config.max_nodes {
1644            break;
1645        }
1646
1647        match ch {
1648            'F' | 'A' | 'B' => {
1649                // Előre lépés és új node
1650
1651                let step = 1.0;
1652
1653                let nx = turtle.x + turtle.angle_xy.cos() * turtle.angle_z.cos() * step;
1654
1655                let ny = turtle.y + turtle.angle_xy.sin() * turtle.angle_z.cos() * step;
1656
1657                let nz = turtle.z + turtle.angle_z.sin() * step;
1658
1659                let node_type = match ch {
1660                    'A' => NodeType::Gateway,
1661
1662                    'B' => NodeType::Database,
1663
1664                    _ => NodeType::Service,
1665                };
1666
1667                let node_id = next_node_id;
1668
1669                next_node_id += 1;
1670
1671                organism.nodes.push(MorphNode {
1672                    id: node_id,
1673
1674                    position: (nx, ny, nz),
1675
1676                    node_type,
1677
1678                    name: format!("fnode_{}", node_id),
1679
1680                    latency_base_ms: 2.0,
1681
1682                    capacity: 50.0,
1683
1684                    energy: 80.0,
1685
1686                    depth: node_stack.len() as u32,
1687
1688                    metadata: HashMap::new(),
1689                });
1690
1691                organism.connections.push(MorphConnection {
1692                    id: next_conn_id,
1693
1694                    from_node: last_node_id,
1695
1696                    to_node: node_id,
1697
1698                    weight: 0.5,
1699
1700                    bandwidth: 5000.0,
1701
1702                    protocol: "HTTP/2".to_string(),
1703
1704                    latency_ms: 1.0,
1705
1706                    connection_type: ConnectionType::DataFlow,
1707
1708                    is_active: true,
1709
1710                    age_cycles: 0,
1711                });
1712
1713                next_conn_id += 1;
1714
1715                turtle.x = nx;
1716
1717                turtle.y = ny;
1718
1719                turtle.z = nz;
1720
1721                last_node_id = node_id;
1722            }
1723
1724            '+' => {
1725                turtle.angle_xy += config.branching_angle;
1726            }
1727
1728            '-' => {
1729                turtle.angle_xy -= config.branching_angle;
1730            }
1731
1732            '[' => {
1733                // Push: elágazás kezdete
1734
1735                node_stack.push((
1736                    last_node_id,
1737                    TurtleState {
1738                        x: turtle.x,
1739
1740                        y: turtle.y,
1741
1742                        z: turtle.z,
1743
1744                        angle_xy: turtle.angle_xy,
1745
1746                        angle_z: turtle.angle_z,
1747                    },
1748                ));
1749            }
1750
1751            ']' => {
1752                // Pop: vissza az elágazási ponthoz
1753
1754                if let Some((saved_node, saved_turtle)) = node_stack.pop() {
1755                    turtle = saved_turtle;
1756
1757                    last_node_id = saved_node;
1758                }
1759            }
1760
1761            '^' => {
1762                turtle.angle_z += config.branching_angle * 0.5;
1763            }
1764
1765            'v' => {
1766                turtle.angle_z -= config.branching_angle * 0.5;
1767            }
1768
1769            _ => {}
1770        }
1771    }
1772
1773    organism.calculate_metrics();
1774
1775    organism
1776}
1777
1778// ─── Fitness Célok ───────────────────────────────────────────────────────────
1779
1780/// Fitness célok az evolúciós szelekcióhoz
1781#[derive(Debug, Clone, PartialEq)]
1782
1783pub enum FitnessObjective {
1784    /// Minimális késleltetés
1785    MinimizeLatency,
1786
1787    /// Maximális áteresztőképesség
1788    MaximizeThroughput,
1789
1790    /// Minimális költség (legkevesebb node)
1791    MinimizeCost,
1792
1793    /// Maximális redundancia (hibatűrés)
1794    MaximizeRedundancy,
1795
1796    /// Kiegyensúlyozott (alapértelmezett)
1797    Balanced,
1798
1799    /// Egyedi célfüggvény
1800    Custom(String),
1801}
1802
1803/// Fitness eredmény
1804#[derive(Debug, Clone)]
1805
1806pub struct FitnessResult {
1807    pub score: f64,
1808
1809    pub latency_score: f64,
1810
1811    pub throughput_score: f64,
1812
1813    pub cost_score: f64,
1814
1815    pub redundancy_score: f64,
1816
1817    pub detail: String,
1818}
1819
1820/// Fitness függvény kiértékelése
1821pub fn evaluate_fitness(organism: &Organism, objective: &FitnessObjective) -> FitnessResult {
1822    let metrics = organism.metrics.as_ref().cloned().unwrap_or_else(|| {
1823        let mut o = organism.clone();
1824
1825        o.calculate_metrics()
1826    });
1827
1828    let node_count = metrics.node_count.max(1) as f64;
1829
1830    let conn_count = metrics.connection_count.max(1) as f64;
1831
1832    let _avg_depth = metrics.max_depth.max(1) as f64;
1833
1834    let redundancy = metrics.redundancy_score;
1835
1836    // Latency score: kevesebb = jobb
1837
1838    let avg_latency: f64 = if organism.connections.is_empty() {
1839        50.0
1840    } else {
1841        organism
1842            .connections
1843            .iter()
1844            .map(|c| c.latency_ms)
1845            .sum::<f64>()
1846            / conn_count
1847    };
1848
1849    let latency_score = (100.0 / (avg_latency + 10.0)).min(1.0);
1850
1851    // Throughput score: több kapcsolat és kapacitás = jobb
1852
1853    let avg_bandwidth: f64 = if organism.connections.is_empty() {
1854        0.0
1855    } else {
1856        organism
1857            .connections
1858            .iter()
1859            .map(|c| c.bandwidth)
1860            .sum::<f64>()
1861            / conn_count
1862    };
1863
1864    let throughput_score = (avg_bandwidth / 20000.0).min(1.0);
1865
1866    // Cost score: kevesebb node = olcsóbb
1867
1868    let cost_score = (1.0 - (node_count / 20.0).min(1.0)).max(0.05);
1869
1870    // Redundancy: több kapcsolat = robusztusabb
1871
1872    let redundancy_score = (redundancy / 3.0).min(1.0);
1873
1874    // Fractal efficiency
1875
1876    let fractal_efficiency = (metrics.fractal_dimension / 3.0).min(1.0);
1877
1878    // Complexity penalty: dense graphs cost more
1879    let complexity_penalty = ((conn_count / node_count.max(1.0)) / 3.0).min(1.0) * 0.15;
1880
1881    let score = match objective {
1882        FitnessObjective::MinimizeLatency => {
1883            latency_score * 0.6 + throughput_score * 0.2 + cost_score * 0.1 + redundancy_score * 0.1
1884        }
1885
1886        FitnessObjective::MaximizeThroughput => {
1887            throughput_score * 0.5 + latency_score * 0.2 + redundancy_score * 0.2 + cost_score * 0.1
1888        }
1889
1890        FitnessObjective::MinimizeCost => {
1891            cost_score * 0.6 + latency_score * 0.2 + throughput_score * 0.1 + redundancy_score * 0.1
1892        }
1893
1894        FitnessObjective::MaximizeRedundancy => {
1895            redundancy_score * 0.5 + latency_score * 0.2 + throughput_score * 0.2 + cost_score * 0.1
1896        }
1897
1898        FitnessObjective::Balanced => {
1899            latency_score * 0.3 + throughput_score * 0.3 + cost_score * 0.2 + redundancy_score * 0.2
1900        }
1901
1902        FitnessObjective::Custom(_) => {
1903            (latency_score + throughput_score + cost_score + redundancy_score) / 4.0
1904        }
1905    };
1906
1907    FitnessResult {
1908        score: (score * fractal_efficiency * (1.0 - complexity_penalty)).clamp(0.0, 1.0),
1909
1910        latency_score,
1911
1912        throughput_score,
1913
1914        cost_score,
1915
1916        redundancy_score,
1917
1918        detail: format!(
1919            "nodes={}, conns={}, avg_lat={:.1}ms, avg_bw={:.0}, redund={:.2}",
1920            node_count, conn_count, avg_latency, avg_bandwidth, redundancy
1921        ),
1922    }
1923}
1924
1925// ─── Morphogenesis Engine ────────────────────────────────────────────────────
1926
1927/// A fő morfogenetikus motor
1928pub struct MorphogenesisEngine {
1929    /// Konfiguráció
1930    pub config: Arc<RwLock<GrowthConfig>>,
1931
1932    /// Organizmus populáció
1933    pub organisms: Arc<RwLock<Vec<Organism>>>,
1934
1935    /// Morfogén mező
1936    pub field: Arc<RwLock<MorphogenField>>,
1937
1938    /// Generációs számláló
1939    pub generation: Arc<RwLock<u32>>,
1940
1941    /// Evolúciós történet (legjobb fitness per generáció)
1942    pub evolution_history: Arc<RwLock<Vec<f64>>>,
1943}
1944
1945impl Default for MorphogenesisEngine {
1946    fn default() -> Self {
1947        Self::new()
1948    }
1949}
1950
1951impl MorphogenesisEngine {
1952    /// Létrehoz egy új motort
1953    pub fn new() -> Self {
1954        Self {
1955            config: Arc::new(RwLock::new(GrowthConfig::default())),
1956
1957            organisms: Arc::new(RwLock::new(Vec::new())),
1958
1959            field: Arc::new(RwLock::new(MorphogenField::new())),
1960
1961            generation: Arc::new(RwLock::new(0)),
1962
1963            evolution_history: Arc::new(RwLock::new(Vec::new())),
1964        }
1965    }
1966
1967    /// Konfiguráció beállítása
1968    pub fn set_config(&self, config: GrowthConfig) {
1969        *crate::sync_guard::write_lock(&self.config) = config;
1970    }
1971
1972    /// Morfogén mező beállítása
1973    pub fn set_field(&self, field: MorphogenField) {
1974        *crate::sync_guard::write_lock(&self.field) = field;
1975    }
1976
1977    /// Organizmus növesztése egy seed-ből
1978    pub fn grow_from_seed(&self, seed: &Seed, pattern: Option<GrowthPattern>) -> Organism {
1979        let config = crate::sync_guard::read_lock(&self.config).clone();
1980
1981        let pattern = pattern.or(seed.preferred_pattern).unwrap_or(config.pattern);
1982
1983        let field = crate::sync_guard::read_lock(&self.field).clone();
1984
1985        let organism = match pattern {
1986            GrowthPattern::Mycelium => mycelium_growth(seed, &field, &config),
1987
1988            GrowthPattern::Capillary => capillary_growth(seed, &field, &config),
1989
1990            GrowthPattern::SlimeMold => slime_mold_growth(seed, &field, &config),
1991
1992            GrowthPattern::FractalLSystem => fractal_growth(seed, &field, &config),
1993
1994            GrowthPattern::Hybrid => {
1995                // Hibrid: mycelium + kapilláris kombináció
1996
1997                let mycelium = mycelium_growth(seed, &field, &config);
1998
1999                if mycelium.fitness_score > 0.3 {
2000                    mycelium
2001                } else {
2002                    capillary_growth(seed, &field, &config)
2003                }
2004            }
2005        };
2006
2007        let fitness = evaluate_fitness(&organism, &FitnessObjective::Balanced);
2008
2009        let mut org = organism;
2010
2011        org.fitness_score = fitness.score;
2012
2013        crate::sync_guard::write_lock(&self.organisms).push(org.clone());
2014
2015        org
2016    }
2017
2018    /// Populáció evolúciója generációkon keresztül
2019    /// Minden generáció:
2020    /// 1. Fitness kiértékelés
2021    /// 2. Szelekció (legjobb N marad)
2022    /// 3. Keresztezés (seed paraméterek keverése)
2023    /// 4. Mutáció (növekedési paraméterek véletlenszerű változtatása)
2024    /// 5. Új organizmusok növesztése
2025    pub fn evolve_population(
2026        &self,
2027
2028        seeds: &[Seed],
2029
2030        generations: u32,
2031
2032        objective: &FitnessObjective,
2033
2034        population_size: usize,
2035    ) -> Vec<Organism> {
2036        if seeds.is_empty() {
2037            return Vec::new();
2038        }
2039
2040        let _config = crate::sync_guard::read_lock(&self.config).clone();
2041
2042        let patterns = [
2043            GrowthPattern::Mycelium,
2044            GrowthPattern::Capillary,
2045            GrowthPattern::SlimeMold,
2046            GrowthPattern::FractalLSystem,
2047        ];
2048
2049        // Kezdeti populáció létrehozása
2050
2051        let mut population: Vec<Organism> = seeds
2052            .iter()
2053            .flat_map(|seed| {
2054                patterns
2055                    .iter()
2056                    .map(|pattern| {
2057                        let field = crate::sync_guard::read_lock(&self.field).clone();
2058
2059                        let config = crate::sync_guard::read_lock(&self.config).clone();
2060
2061                        let mut org = match pattern {
2062                            GrowthPattern::Mycelium => mycelium_growth(seed, &field, &config),
2063
2064                            GrowthPattern::Capillary => capillary_growth(seed, &field, &config),
2065
2066                            GrowthPattern::SlimeMold => slime_mold_growth(seed, &field, &config),
2067
2068                            GrowthPattern::FractalLSystem => fractal_growth(seed, &field, &config),
2069
2070                            GrowthPattern::Hybrid => unreachable!(),
2071                        };
2072
2073                        let fitness = evaluate_fitness(&org, objective);
2074
2075                        org.fitness_score = fitness.score;
2076
2077                        org
2078                    })
2079                    .collect::<Vec<_>>()
2080            })
2081            .collect();
2082
2083        // Evolúciós ciklusok
2084
2085        for gen in 0..generations {
2086            *crate::sync_guard::write_lock(&self.generation) = gen + 1;
2087
2088            // 1. Fitness alapú rendezés
2089
2090            population.sort_by(|a, b| b.fitness_score.total_cmp(&a.fitness_score));
2091
2092            // Legjobb fitness mentése
2093
2094            if let Some(best) = population.first() {
2095                crate::sync_guard::write_lock(&self.evolution_history).push(best.fitness_score);
2096            }
2097
2098            // 2. Szelekció: top 30% marad
2099
2100            let keep_count = (population_size / 3).max(population.len() / 3);
2101
2102            let survivors: Vec<Organism> = population.into_iter().take(keep_count).collect();
2103
2104            // 3-4-5. Új generáció: mutáció és keresztezés
2105
2106            let mut new_population = survivors.clone();
2107
2108            // Deterministic per-generation RNG, so the whole evolution run is
2109            // reproducible for the same initial seeds.
2110            let mut rng = {
2111                use rand::SeedableRng;
2112                rand::rngs::StdRng::seed_from_u64(
2113                    0x9E37_79B9_7F4A_7C15 ^ (gen as u64).wrapping_mul(0x100000001b3),
2114                )
2115            };
2116
2117            let mut rng_idx = 0;
2118
2119            while new_population.len() < population_size {
2120                let parent = &survivors[rng_idx % survivors.len()];
2121
2122                rng_idx += 1;
2123
2124                // Mutált seed
2125
2126                let mutation_factor = 0.8 + rng.gen::<f64>() * 0.4;
2127
2128                let mutated_seed = Seed {
2129                    id: format!("evo_{}_{}", gen, new_population.len()),
2130
2131                    position: (
2132                        parent.seed.position.0 + (rng.gen::<f64>() - 0.5) * 5.0,
2133                        parent.seed.position.1 + (rng.gen::<f64>() - 0.5) * 5.0,
2134                        parent.seed.position.2 + (rng.gen::<f64>() - 0.5) * 5.0,
2135                    ),
2136
2137                    energy: parent.seed.energy * mutation_factor,
2138
2139                    type_tag: parent.seed.type_tag.clone(),
2140
2141                    preferred_pattern: Some(patterns[rng.gen::<usize>() % patterns.len()]),
2142                };
2143
2144                let field = crate::sync_guard::read_lock(&self.field).clone();
2145
2146                let config = crate::sync_guard::read_lock(&self.config).clone();
2147
2148                let pattern = mutated_seed.preferred_pattern.unwrap_or(config.pattern);
2149
2150                let mut child = match pattern {
2151                    GrowthPattern::Mycelium => mycelium_growth(&mutated_seed, &field, &config),
2152
2153                    GrowthPattern::Capillary => capillary_growth(&mutated_seed, &field, &config),
2154
2155                    GrowthPattern::SlimeMold => slime_mold_growth(&mutated_seed, &field, &config),
2156
2157                    GrowthPattern::FractalLSystem => fractal_growth(&mutated_seed, &field, &config),
2158
2159                    GrowthPattern::Hybrid => unreachable!(),
2160                };
2161
2162                child.generation = gen + 1;
2163
2164                let fitness = evaluate_fitness(&child, objective);
2165
2166                child.fitness_score = fitness.score;
2167
2168                new_population.push(child);
2169            }
2170
2171            population = new_population;
2172        }
2173
2174        // Final rendezés és tárolás
2175
2176        population.sort_by(|a, b| b.fitness_score.total_cmp(&a.fitness_score));
2177
2178        let top: Vec<Organism> = population.into_iter().take(population_size / 2).collect();
2179
2180        *crate::sync_guard::write_lock(&self.organisms) = top.clone();
2181
2182        top
2183    }
2184
2185    /// Pruning: gyenge ágak eltávolítása
2186    pub fn prune_weak(&self, organism: &mut Organism, threshold: f64) -> usize {
2187        let before = organism.connections.len();
2188
2189        // Inaktív kapcsolatok eltávolítása
2190
2191        organism
2192            .connections
2193            .retain(|c| c.is_active && c.weight > threshold);
2194
2195        // Elszigetelt node-ok eltávolítása
2196
2197        let connected_nodes: std::collections::HashSet<usize> = organism
2198            .connections
2199            .iter()
2200            .flat_map(|c| vec![c.from_node, c.to_node])
2201            .collect();
2202
2203        organism.nodes.retain(|n| connected_nodes.contains(&n.id));
2204
2205        before - organism.connections.len()
2206    }
2207
2208    /// Topológiai elemzés
2209    pub fn analyze_topology(organism: &Organism) -> HashMap<String, f64> {
2210        let mut analysis = HashMap::new();
2211
2212        let n = organism.nodes.len() as f64;
2213
2214        let e = organism.connections.len() as f64;
2215
2216        // Átlagos fokszám
2217
2218        if n > 0.0 {
2219            analysis.insert("avg_degree".to_string(), (e * 2.0 / n).round());
2220        }
2221
2222        // Kapcsolati sűrűség
2223
2224        if n > 1.0 {
2225            let max_edges = n * (n - 1.0) / 2.0;
2226
2227            analysis.insert(
2228                "density".to_string(),
2229                (e / max_edges * 100.0 * 100.0).round() / 100.0,
2230            );
2231        }
2232
2233        // Elágazási arány
2234
2235        let internal = organism
2236            .nodes
2237            .iter()
2238            .filter(|n| organism.connections.iter().any(|c| c.from_node == n.id))
2239            .count() as f64;
2240
2241        if internal > 0.0 {
2242            analysis.insert(
2243                "branching_ratio".to_string(),
2244                (n / internal * 100.0).round() / 100.0,
2245            );
2246        }
2247
2248        // Átlagos késleltetés
2249
2250        if !organism.connections.is_empty() {
2251            let avg_lat: f64 = organism
2252                .connections
2253                .iter()
2254                .map(|c| c.latency_ms)
2255                .sum::<f64>()
2256                / e;
2257
2258            analysis.insert(
2259                "avg_latency_ms".to_string(),
2260                (avg_lat * 100.0).round() / 100.0,
2261            );
2262        }
2263
2264        // Redundancia index
2265
2266        if n > 1.0 {
2267            analysis.insert(
2268                "redundancy".to_string(),
2269                (e / (n - 1.0) * 100.0).round() / 100.0,
2270            );
2271        }
2272
2273        analysis
2274    }
2275
2276    /// Legjobb organizmus lekérése
2277    pub fn get_best_organism(&self) -> Option<Organism> {
2278        let organisms = crate::sync_guard::read_lock(&self.organisms);
2279
2280        organisms
2281            .iter()
2282            .max_by(|a, b| a.fitness_score.total_cmp(&b.fitness_score))
2283            .cloned()
2284    }
2285
2286    /// Evolúciós történet lekérése
2287    pub fn evolution_summary(&self) -> Vec<(u32, f64)> {
2288        let history = crate::sync_guard::read_lock(&self.evolution_history);
2289
2290        history
2291            .iter()
2292            .enumerate()
2293            .map(|(i, s)| (i as u32 + 1, *s))
2294            .collect()
2295    }
2296}
2297
2298// ─── Expresszió: Organizmus → Architecture leképezés ────────────────────────
2299
2300/// Organizmus kifejezése szimulálható Architecture-vé
2301#[cfg(not(target_arch = "wasm32"))]
2302pub fn express_as_architecture(organism: &Organism) -> crate::architecture_simulator::Architecture {
2303    let mut components = std::collections::HashMap::new();
2304
2305    let mut connections = Vec::new();
2306
2307    for node in &organism.nodes {
2308        let comp_type = match node.node_type {
2309            NodeType::Root | NodeType::Gateway => {
2310                crate::architecture_simulator::ComponentType::Software
2311            }
2312
2313            NodeType::Database | NodeType::Cache => {
2314                crate::architecture_simulator::ComponentType::Storage
2315            }
2316
2317            NodeType::LoadBalancer | NodeType::Queue => {
2318                crate::architecture_simulator::ComponentType::Network
2319            }
2320
2321            NodeType::Service | NodeType::Leaf => {
2322                crate::architecture_simulator::ComponentType::Software
2323            }
2324
2325            NodeType::Custom(_) => {
2326                crate::architecture_simulator::ComponentType::Custom(node.node_type.to_string())
2327            }
2328        };
2329
2330        let mut capacity = std::collections::HashMap::new();
2331
2332        capacity.insert("memory_mb".to_string(), node.capacity);
2333
2334        components.insert(
2335            node.id.to_string(),
2336            crate::architecture_simulator::Component {
2337                id: node.id.to_string(),
2338
2339                name: node.name.clone(),
2340
2341                component_type: comp_type,
2342
2343                capacity,
2344
2345                load: 0.0,
2346
2347                error_rate: 0.01,
2348
2349                latency_ms: node.latency_base_ms,
2350            },
2351        );
2352    }
2353
2354    for conn in &organism.connections {
2355        if !conn.is_active {
2356            continue;
2357        }
2358
2359        connections.push(crate::architecture_simulator::Connection {
2360            from: conn.from_node.to_string(),
2361
2362            to: conn.to_node.to_string(),
2363
2364            bandwidth: conn.bandwidth,
2365
2366            protocol: conn.protocol.clone(),
2367
2368            latency_ms: conn.latency_ms,
2369
2370            packet_loss: 0.001,
2371        });
2372    }
2373
2374    crate::architecture_simulator::Architecture {
2375        id: format!("morph_{}", organism.id),
2376
2377        name: organism.name.clone(),
2378
2379        description: format!(
2380            "Morphogenetically grown {:?} (gen={}, fitness={:.3})",
2381            organism.growth_pattern, organism.generation, organism.fitness_score
2382        ),
2383
2384        components,
2385
2386        connections,
2387
2388        version: organism.generation,
2389
2390        cohesion_score: organism.fitness_score,
2391    }
2392}
2393
2394// ─── Integráció: Vagus trigger ──────────────────────────────────────────────
2395
2396/// Vagus stressz szint alapján kompenzatórikus növekedés triggerelése
2397/// Ha a vagus tónus egy kritikus szint alá esik (magas stressz),
2398/// a morphogenesis automatikusan új struktúrákat növeszt,
2399/// hogy tehermentesítse a szűk keresztmetszeteket.
2400#[cfg(not(target_arch = "wasm32"))]
2401pub fn trigger_from_vagus(
2402    vagus_tone: &crate::vagus::VagusTone,
2403
2404    system_pulse: &crate::vagus::SystemPulse,
2405
2406    engine: &MorphogenesisEngine,
2407
2408    threshold: f64,
2409) -> Option<Organism> {
2410    // Ha a tónus a küszöb alatt van, stressz kompenzáció
2411
2412    if vagus_tone.current > threshold {
2413        return None; // Nincs szükség beavatkozásra
2414    }
2415
2416    // Stressz forrás azonosítása a pulzus alapján
2417
2418    let stress_source = if system_pulse.cpu_pressure > 0.8 {
2419        "cpu_bound"
2420    } else if system_pulse.memory_pressure > 0.8 {
2421        "memory_bound"
2422    } else if system_pulse.network_pressure > 0.8 {
2423        "network_bound"
2424    } else {
2425        "general"
2426    };
2427
2428    // Kompenzatórikus seed létrehozása
2429
2430    let seed = Seed {
2431        id: format!("compensate_{}", rand::random::<u32>()),
2432
2433        position: (0.0, 0.0, 0.0),
2434
2435        energy: vagus_tone.baseline * 100.0,
2436
2437        type_tag: stress_source.to_string(),
2438
2439        preferred_pattern: match stress_source {
2440            "network_bound" => Some(GrowthPattern::Mycelium), // több hálózati útvonal
2441
2442            "memory_bound" => Some(GrowthPattern::Capillary), // cache réteg növesztése
2443
2444            "cpu_bound" => Some(GrowthPattern::FractalLSystem), // új feldolgozó ágak
2445
2446            _ => Some(GrowthPattern::Hybrid),
2447        },
2448    };
2449
2450    let organism = engine.grow_from_seed(&seed, None);
2451
2452    if organism.fitness_score > 0.3 {
2453        Some(organism)
2454    } else {
2455        None
2456    }
2457}
2458
2459// ─── Integráció: Neuroplasticity térkép ─────────────────────────────────────
2460
2461/// Organizmus struktúra leképezése neuroplasztikus útvonalakra
2462/// Minden MorphConnection egy szinaptikus kapcsolattá alakul.
2463/// Az erős kapcsolatok magasabb súlyt kapnak.
2464pub fn map_to_neuroplasticity(organism: &Organism) -> Vec<(u32, u32, f32)> {
2465    organism
2466        .connections
2467        .iter()
2468        .filter(|c| c.is_active)
2469        .map(|c| {
2470            let weight = (c.weight * 0.5
2471                + c.bandwidth / 20000.0 * 0.3
2472                + (1.0 - c.latency_ms / 20.0).max(0.0) * 0.2) as f32;
2473
2474            (c.from_node as u32, c.to_node as u32, weight.clamp(0.0, 1.0))
2475        })
2476        .collect()
2477}
2478
2479// ─── Integráció: Federation fingerprint export ──────────────────────────────
2480
2481/// Fingerprint generálása federation rezonanciához
2482/// A fingerprint tartalmazza:
2483/// - Növekedési minta típusa
2484/// - Node-ok és kapcsolatok számának tömörített hash-e
2485/// - Fitness score
2486/// - Topológiai jellemzők (átlagos fokszám, sűrűség, fraktál dimenzió)
2487pub fn export_fingerprint(organism: &Organism) -> Vec<u8> {
2488    use std::hash::{Hash, Hasher};
2489
2490    use std::collections::hash_map::DefaultHasher;
2491
2492    let mut fingerprint = Vec::new();
2493
2494    // Növekedési minta
2495
2496    fingerprint.push(match organism.growth_pattern {
2497        GrowthPattern::Mycelium => 0x01,
2498
2499        GrowthPattern::Capillary => 0x02,
2500
2501        GrowthPattern::SlimeMold => 0x03,
2502
2503        GrowthPattern::FractalLSystem => 0x04,
2504
2505        GrowthPattern::Hybrid => 0xFF,
2506    });
2507
2508    // Strukturális hash
2509
2510    let mut hasher = DefaultHasher::new();
2511
2512    organism.nodes.len().hash(&mut hasher);
2513
2514    organism.connections.len().hash(&mut hasher);
2515
2516    ((organism.fitness_score * 1000.0) as u64).hash(&mut hasher);
2517
2518    let structural_hash = hasher.finish();
2519
2520    fingerprint.extend_from_slice(&structural_hash.to_le_bytes());
2521
2522    // Topológiai jellemzők (kvantált)
2523
2524    if let Some(ref metrics) = organism.metrics {
2525        let fractal_quant = (metrics.fractal_dimension * 100.0) as u16;
2526
2527        let redundancy_quant = (metrics.redundancy_score * 100.0) as u16;
2528
2529        let depth_quant = metrics.max_depth as u8;
2530
2531        fingerprint.extend_from_slice(&fractal_quant.to_le_bytes());
2532
2533        fingerprint.extend_from_slice(&redundancy_quant.to_le_bytes());
2534
2535        fingerprint.push(depth_quant);
2536    }
2537
2538    fingerprint
2539}
2540
2541// ─── Display implementációk ─────────────────────────────────────────────────
2542
2543use std::fmt;
2544
2545impl fmt::Display for NodeType {
2546    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2547        match self {
2548            NodeType::Root => write!(f, "Root"),
2549
2550            NodeType::Service => write!(f, "Service"),
2551
2552            NodeType::Database => write!(f, "Database"),
2553
2554            NodeType::Cache => write!(f, "Cache"),
2555
2556            NodeType::Gateway => write!(f, "Gateway"),
2557
2558            NodeType::LoadBalancer => write!(f, "LoadBalancer"),
2559
2560            NodeType::Queue => write!(f, "Queue"),
2561
2562            NodeType::Leaf => write!(f, "Leaf"),
2563
2564            NodeType::Custom(s) => write!(f, "Custom({})", s),
2565        }
2566    }
2567}
2568
2569impl fmt::Display for GrowthPattern {
2570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2571        match self {
2572            GrowthPattern::Mycelium => write!(f, "Mycelium"),
2573
2574            GrowthPattern::Capillary => write!(f, "Capillary"),
2575
2576            GrowthPattern::SlimeMold => write!(f, "SlimeMold"),
2577
2578            GrowthPattern::FractalLSystem => write!(f, "FractalLSystem"),
2579
2580            GrowthPattern::Hybrid => write!(f, "Hybrid"),
2581        }
2582    }
2583}
2584
2585impl fmt::Display for ConnectionType {
2586    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2587        match self {
2588            ConnectionType::DataFlow => write!(f, "DataFlow"),
2589
2590            ConnectionType::Control => write!(f, "Control"),
2591
2592            ConnectionType::Replication => write!(f, "Replication"),
2593
2594            ConnectionType::Backup => write!(f, "Backup"),
2595        }
2596    }
2597}
2598
2599impl fmt::Display for Organism {
2600    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2601        writeln!(
2602            f,
2603            "Organism: {} (gen={}, fitness={:.3})",
2604            self.name, self.generation, self.fitness_score
2605        )?;
2606
2607        writeln!(f, "  Pattern: {}", self.growth_pattern)?;
2608
2609        writeln!(
2610            f,
2611            "  Nodes: {}, Connections: {}",
2612            self.nodes.len(),
2613            self.connections.len()
2614        )?;
2615
2616        if let Some(ref m) = self.metrics {
2617            writeln!(
2618                f,
2619                "  Max depth: {}, Fractal dim: {:.3}",
2620                m.max_depth, m.fractal_dimension
2621            )?;
2622
2623            writeln!(
2624                f,
2625                "  Redundancy: {:.3}, Avg path: {:.3}",
2626                m.redundancy_score, m.avg_path_length
2627            )?;
2628        }
2629
2630        Ok(())
2631    }
2632}
2633
2634// ─── Segédfüggvények ─────────────────────────────────────────────────────────
2635
2636/// Több organizmus egyesítése egy nagyobb struktúrába
2637pub fn merge_organisms(organisms: &[Organism]) -> Option<Organism> {
2638    if organisms.is_empty() {
2639        return None;
2640    }
2641
2642    let mut merged = organisms[0].clone();
2643
2644    merged.id = format!("merged_{}", rand::random::<u32>());
2645
2646    merged.name = format!("Merged_{}", organisms.len());
2647
2648    let mut next_node_id = merged.nodes.len();
2649
2650    let mut next_conn_id = merged.connections.len();
2651
2652    for org in organisms.iter().skip(1) {
2653        for node in &org.nodes {
2654            let mut new_node = node.clone();
2655
2656            new_node.id = next_node_id;
2657
2658            merged.nodes.push(new_node);
2659
2660            next_node_id += 1;
2661        }
2662
2663        for conn in &org.connections {
2664            merged.connections.push(MorphConnection {
2665                id: next_conn_id,
2666
2667                from_node: conn.from_node,
2668
2669                to_node: conn.to_node,
2670
2671                ..conn.clone()
2672            });
2673
2674            next_conn_id += 1;
2675        }
2676    }
2677
2678    merged.calculate_metrics();
2679
2680    Some(merged)
2681}
2682
2683/// Organizmus struktúra egyszerűsítése (redundáns node-ok összevonása)
2684pub fn simplify_organism(organism: &mut Organism) -> usize {
2685    let _before = organism.nodes.len();
2686
2687    let mut removed = std::collections::HashSet::new();
2688
2689    // Azonos típusú, szomszédos és alacsony energiájú node-ok összevonása
2690
2691    let mut i = 0;
2692
2693    while i < organism.nodes.len() {
2694        if removed.contains(&i) {
2695            i += 1;
2696            continue;
2697        }
2698
2699        let node = &organism.nodes[i];
2700
2701        if node.node_type == NodeType::Leaf && node.energy < 10.0 {
2702            removed.insert(i);
2703        }
2704
2705        i += 1;
2706    }
2707
2708    // Node-ok eltávolítása (indexeket fenntartva)
2709
2710    let old_count = organism.nodes.len();
2711
2712    organism.nodes.retain(|n| !removed.contains(&n.id));
2713
2714    let removed_count = old_count - organism.nodes.len();
2715
2716    // Elszigetelt kapcsolatok tisztítása
2717
2718    let active_ids: std::collections::HashSet<usize> =
2719        organism.nodes.iter().map(|n| n.id).collect();
2720
2721    organism
2722        .connections
2723        .retain(|c| active_ids.contains(&c.from_node) && active_ids.contains(&c.to_node));
2724
2725    organism.calculate_metrics();
2726
2727    removed_count
2728}
2729
2730// ─── NodeType → string konverzió ────────────────────────────────────────────
2731
2732impl NodeType {
2733    #[allow(clippy::inherent_to_string_shadow_display)]
2734    pub fn to_string(&self) -> String {
2735        match self {
2736            NodeType::Root => "Root".to_string(),
2737
2738            NodeType::Service => "Service".to_string(),
2739
2740            NodeType::Database => "Database".to_string(),
2741
2742            NodeType::Cache => "Cache".to_string(),
2743
2744            NodeType::Gateway => "Gateway".to_string(),
2745
2746            NodeType::LoadBalancer => "LoadBalancer".to_string(),
2747
2748            NodeType::Queue => "Queue".to_string(),
2749
2750            NodeType::Leaf => "Leaf".to_string(),
2751
2752            NodeType::Custom(s) => s.clone(),
2753        }
2754    }
2755}
2756
2757// ─── Tesztek ─────────────────────────────────────────────────────────────────
2758
2759#[cfg(test)]
2760mod tests {
2761
2762    use super::*;
2763
2764    fn test_seed() -> Seed {
2765        Seed::new("test_seed", 0.0, 0.0, 0.0, "service")
2766    }
2767
2768    #[test]
2769
2770    fn test_seed_creation() {
2771        let seed = test_seed();
2772
2773        assert_eq!(seed.id, "test_seed");
2774
2775        assert_eq!(seed.energy, 100.0);
2776    }
2777
2778    #[test]
2779
2780    fn test_mycelium_growth() {
2781        let seed = test_seed();
2782
2783        let field = MorphogenField::new();
2784
2785        let config = GrowthConfig::mycelium_default();
2786
2787        let organism = mycelium_growth(&seed, &field, &config);
2788
2789        assert!(
2790            !organism.nodes.is_empty(),
2791            "Mycelium growth should produce nodes"
2792        );
2793
2794        assert!(
2795            organism.nodes.len() > 1,
2796            "Should have more than just the root node"
2797        );
2798
2799        assert!(organism.fitness_score >= 0.0);
2800    }
2801
2802    #[test]
2803
2804    fn test_capillary_growth() {
2805        let seed = test_seed();
2806
2807        let field = MorphogenField::new();
2808
2809        let config = GrowthConfig::capillary_default();
2810
2811        let organism = capillary_growth(&seed, &field, &config);
2812
2813        assert!(
2814            !organism.nodes.is_empty(),
2815            "Capillary growth should produce nodes"
2816        );
2817    }
2818
2819    #[test]
2820
2821    fn test_slime_mold_growth() {
2822        // Deterministic seed chosen so slime growth reliably produces nodes.
2823        let seed = Seed::new("slime2", 0.0, 0.0, 0.0, "service");
2824
2825        let field = MorphogenField::new();
2826
2827        let config = GrowthConfig::slime_mold_default();
2828
2829        let organism = slime_mold_growth(&seed, &field, &config);
2830
2831        assert!(
2832            !organism.nodes.is_empty(),
2833            "slime mold must produce nodes with the deterministic seed"
2834        );
2835    }
2836
2837    #[test]
2838
2839    fn test_fractal_growth() {
2840        let seed = test_seed();
2841
2842        let field = MorphogenField::new();
2843
2844        let config = GrowthConfig::fractal_lsystem_default();
2845
2846        let organism = fractal_growth(&seed, &field, &config);
2847
2848        assert!(
2849            !organism.nodes.is_empty(),
2850            "Fractal growth should produce nodes"
2851        );
2852    }
2853
2854    #[test]
2855
2856    fn test_engine_grow_from_seed() {
2857        let engine = MorphogenesisEngine::new();
2858
2859        let seed = test_seed();
2860
2861        let organism = engine.grow_from_seed(&seed, Some(GrowthPattern::Mycelium));
2862
2863        assert!(!organism.nodes.is_empty());
2864
2865        assert!(organism.metrics.is_some());
2866    }
2867
2868    #[test]
2869
2870    fn test_evolve_population() {
2871        let engine = MorphogenesisEngine::new();
2872
2873        let seeds = vec![test_seed()];
2874
2875        let results = engine.evolve_population(&seeds, 2, &FitnessObjective::Balanced, 10);
2876
2877        assert!(!results.is_empty(), "Evolution should produce results");
2878
2879        // First result should have highest fitness
2880
2881        if results.len() > 1 {
2882            assert!(results[0].fitness_score >= results[1].fitness_score);
2883        }
2884    }
2885
2886    #[test]
2887    fn evolution_is_deterministic_for_the_same_seeds() {
2888        let seeds = vec![
2889            test_seed(),
2890            Seed::new("b", 1.0, 2.0, 3.0, "service"),
2891            Seed::new("c", -1.0, 0.5, 2.0, "cache"),
2892        ];
2893
2894        let first = MorphogenesisEngine::new().evolve_population(
2895            &seeds,
2896            3,
2897            &FitnessObjective::Balanced,
2898            12,
2899        );
2900        let second = MorphogenesisEngine::new().evolve_population(
2901            &seeds,
2902            3,
2903            &FitnessObjective::Balanced,
2904            12,
2905        );
2906
2907        assert_eq!(first.len(), second.len());
2908        for (a, b) in first.iter().zip(second.iter()) {
2909            assert_eq!(a.seed.id, b.seed.id, "mutated seed identity must match");
2910            assert_eq!(
2911                export_fingerprint(a),
2912                export_fingerprint(b),
2913                "organisms must be byte-identical across runs"
2914            );
2915        }
2916    }
2917
2918    #[test]
2919
2920    fn test_evaluate_fitness() {
2921        let seed = test_seed();
2922
2923        let field = MorphogenField::new();
2924
2925        let config = GrowthConfig::default();
2926
2927        let organism = mycelium_growth(&seed, &field, &config);
2928
2929        let fitness = evaluate_fitness(&organism, &FitnessObjective::Balanced);
2930
2931        assert!(fitness.score >= 0.0 && fitness.score <= 1.0);
2932
2933        let latency_fitness = evaluate_fitness(&organism, &FitnessObjective::MinimizeLatency);
2934
2935        assert!(latency_fitness.score >= 0.0 && latency_fitness.score <= 1.0);
2936    }
2937
2938    #[test]
2939
2940    fn test_morphogen_field() {
2941        let mut field = MorphogenField::new();
2942
2943        field.add_attractor(5.0, 5.0, 5.0, 10.0);
2944
2945        let near_conc = field.concentration_at(5.0, 5.0, 5.0);
2946
2947        let far_conc = field.concentration_at(50.0, 50.0, 50.0);
2948
2949        assert!(
2950            near_conc > far_conc,
2951            "Concentration should be higher near attractor"
2952        );
2953    }
2954
2955    #[test]
2956
2957    fn test_organism_metrics() {
2958        let seed = test_seed();
2959
2960        let field = MorphogenField::new();
2961
2962        let config = GrowthConfig::default();
2963
2964        let mut organism = mycelium_growth(&seed, &field, &config);
2965
2966        organism.calculate_metrics();
2967
2968        assert!(organism.metrics.is_some());
2969
2970        let metrics = organism.metrics.unwrap();
2971
2972        assert_eq!(metrics.node_count, organism.nodes.len());
2973
2974        assert_eq!(metrics.connection_count, organism.connections.len());
2975    }
2976
2977    #[test]
2978
2979    fn test_prune_weak() {
2980        let engine = MorphogenesisEngine::new();
2981
2982        let seed = test_seed();
2983
2984        let field = MorphogenField::new();
2985
2986        let config = GrowthConfig::default();
2987
2988        let mut organism = mycelium_growth(&seed, &field, &config);
2989
2990        let before = organism.connections.len();
2991
2992        let pruned = engine.prune_weak(&mut organism, 0.5);
2993
2994        assert!(pruned <= before);
2995    }
2996
2997    #[test]
2998
2999    fn test_express_as_architecture() {
3000        let seed = test_seed();
3001
3002        let field = MorphogenField::new();
3003
3004        let config = GrowthConfig::default();
3005
3006        let organism = mycelium_growth(&seed, &field, &config);
3007
3008        let arch = express_as_architecture(&organism);
3009
3010        assert_eq!(arch.components.len(), organism.nodes.len());
3011    }
3012
3013    #[test]
3014
3015    fn test_trigger_from_vagus() {
3016        let engine = MorphogenesisEngine::new();
3017
3018        use crate::vagus;
3019
3020        let low_tone = vagus::VagusTone {
3021            current: 0.2,
3022
3023            baseline: 0.5,
3024
3025            trend: -0.1,
3026
3027            volatility: 0.3,
3028
3029            last_update: 0,
3030        };
3031
3032        let pulse = vagus::SystemPulse {
3033            timestamp: 0,
3034
3035            cpu_pressure: 0.9,
3036
3037            memory_pressure: 0.5,
3038
3039            io_pressure: 0.5,
3040
3041            network_pressure: 0.3,
3042
3043            request_rate: 100.0,
3044
3045            error_rate: 0.05,
3046
3047            hrv: 0.3,
3048        };
3049
3050        let result = trigger_from_vagus(&low_tone, &pulse, &engine, 0.5);
3051
3052        assert!(
3053            result.is_some(),
3054            "Should trigger growth when vagus tone is low"
3055        );
3056    }
3057
3058    #[test]
3059
3060    fn test_merge_organisms() {
3061        let seed = test_seed();
3062
3063        let field = MorphogenField::new();
3064
3065        let config = GrowthConfig::default();
3066
3067        let org1 = mycelium_growth(&seed, &field, &config);
3068
3069        let org2 = capillary_growth(&seed, &field, &config);
3070
3071        let merged = merge_organisms(&[org1, org2]);
3072
3073        assert!(merged.is_some());
3074
3075        assert!(!merged.unwrap().nodes.is_empty());
3076    }
3077
3078    #[test]
3079
3080    fn test_simplify_organism() {
3081        let seed = test_seed();
3082
3083        let field = MorphogenField::new();
3084
3085        let config = GrowthConfig::default();
3086
3087        let mut organism = mycelium_growth(&seed, &field, &config);
3088
3089        let removed = simplify_organism(&mut organism);
3090
3091        let _ = removed;
3092    }
3093
3094    #[test]
3095
3096    fn test_fingerprint_export() {
3097        let seed = test_seed();
3098
3099        let field = MorphogenField::new();
3100
3101        let config = GrowthConfig::default();
3102
3103        let organism = mycelium_growth(&seed, &field, &config);
3104
3105        let fp = export_fingerprint(&organism);
3106
3107        assert!(!fp.is_empty(), "Fingerprint should not be empty");
3108
3109        assert_eq!(fp[0], 0x01, "Mycelium pattern marker");
3110    }
3111
3112    #[test]
3113
3114    fn test_diffusion() {
3115        let mut field = MorphogenField::new();
3116
3117        field.add_attractor(0.0, 0.0, 0.0, 100.0);
3118
3119        field.diffuse();
3120
3121        let conc = field.concentration_at(0.0, 0.0, 0.0);
3122
3123        assert!(
3124            conc > 0.0,
3125            "After diffusion, concentration should remain > 0"
3126        );
3127    }
3128
3129    #[test]
3130
3131    fn test_evaporation() {
3132        let mut field = MorphogenField::new();
3133
3134        field.add_attractor(0.0, 0.0, 0.0, 1.0);
3135
3136        field.evaporate();
3137
3138        assert!(field.gradients.is_empty() || field.gradients.values().any(|v| *v < 1.0));
3139    }
3140
3141    #[test]
3142
3143    fn test_analyze_topology() {
3144        let seed = test_seed();
3145
3146        let field = MorphogenField::new();
3147
3148        let config = GrowthConfig::default();
3149
3150        let organism = mycelium_growth(&seed, &field, &config);
3151
3152        let analysis = MorphogenesisEngine::analyze_topology(&organism);
3153
3154        assert!(analysis.contains_key("avg_degree"));
3155
3156        assert!(analysis.contains_key("density"));
3157
3158        assert!(analysis.contains_key("avg_latency_ms"));
3159    }
3160
3161    #[test]
3162
3163    fn test_display_traits() {
3164        let seed = test_seed();
3165
3166        let field = MorphogenField::new();
3167
3168        let config = GrowthConfig::default();
3169
3170        let mut organism = mycelium_growth(&seed, &field, &config);
3171
3172        organism.fitness_score = 0.75;
3173
3174        let display_str = format!("{}", organism);
3175
3176        assert!(display_str.contains("Organism:"));
3177
3178        assert!(display_str.contains("fitness=0.75"));
3179    }
3180
3181    #[test]
3182
3183    fn test_growth_config_defaults() {
3184        let mycelium = GrowthConfig::mycelium_default();
3185
3186        assert_eq!(mycelium.pattern, GrowthPattern::Mycelium);
3187
3188        assert!(mycelium.branching_probability > 0.0);
3189
3190        let capillary = GrowthConfig::capillary_default();
3191
3192        assert_eq!(capillary.pattern, GrowthPattern::Capillary);
3193
3194        let slime = GrowthConfig::slime_mold_default();
3195
3196        assert_eq!(slime.pattern, GrowthPattern::SlimeMold);
3197
3198        let fractal = GrowthConfig::fractal_lsystem_default();
3199
3200        assert_eq!(fractal.pattern, GrowthPattern::FractalLSystem);
3201    }
3202
3203    #[test]
3204
3205    fn test_evolution_summary() {
3206        let engine = MorphogenesisEngine::new();
3207
3208        let seeds = vec![test_seed()];
3209
3210        engine.evolve_population(&seeds, 3, &FitnessObjective::Balanced, 8);
3211
3212        let summary = engine.evolution_summary();
3213
3214        assert!(!summary.is_empty());
3215
3216        assert_eq!(summary.len(), 3);
3217    }
3218
3219    #[test]
3220
3221    fn test_get_best_organism() {
3222        let engine = MorphogenesisEngine::new();
3223
3224        let seeds = vec![test_seed()];
3225
3226        engine.evolve_population(&seeds, 2, &FitnessObjective::Balanced, 6);
3227
3228        let best = engine.get_best_organism();
3229
3230        assert!(best.is_some());
3231    }
3232
3233    #[test]
3234
3235    fn test_node_type_conversion() {
3236        assert_eq!(NodeType::Root.to_string(), "Root");
3237
3238        assert_eq!(NodeType::Service.to_string(), "Service");
3239
3240        assert_eq!(NodeType::Cache.to_string(), "Cache");
3241
3242        assert_eq!(NodeType::Custom("test".to_string()).to_string(), "test");
3243    }
3244
3245    #[test]
3246
3247    fn test_different_growth_patterns_produce_different_structures() {
3248        let seed = test_seed();
3249
3250        let field = MorphogenField::new();
3251
3252        let config = GrowthConfig::default();
3253
3254        let org1 = mycelium_growth(&seed, &field, &config);
3255
3256        let org2 = fractal_growth(&seed, &field, &config);
3257
3258        // Both growth patterns should produce structures
3259
3260        assert!(org1.nodes.len() > 1);
3261
3262        assert!(org2.nodes.len() > 1);
3263    }
3264
3265    #[test]
3266
3267    fn test_organism_is_alive() {
3268        let seed = test_seed();
3269
3270        let field = MorphogenField::new();
3271
3272        let config = GrowthConfig::default();
3273
3274        let organism = mycelium_growth(&seed, &field, &config);
3275
3276        assert!(organism.is_alive());
3277    }
3278
3279    #[test]
3280
3281    fn test_map_to_neuroplasticity() {
3282        let seed = test_seed();
3283
3284        let field = MorphogenField::new();
3285
3286        let config = GrowthConfig::default();
3287
3288        let organism = mycelium_growth(&seed, &field, &config);
3289
3290        let pathways = map_to_neuroplasticity(&organism);
3291
3292        assert_eq!(
3293            pathways.len(),
3294            organism.connections.iter().filter(|c| c.is_active).count()
3295        );
3296    }
3297
3298    #[test]
3299
3300    fn test_hybrid_growth() {
3301        let engine = MorphogenesisEngine::new();
3302
3303        engine.set_config(GrowthConfig {
3304            pattern: GrowthPattern::Hybrid,
3305
3306            ..GrowthConfig::default()
3307        });
3308
3309        let seed = test_seed();
3310
3311        let organism = engine.grow_from_seed(&seed, None);
3312
3313        assert!(!organism.nodes.is_empty());
3314    }
3315
3316    #[test]
3317
3318    fn test_seed_with_energy() {
3319        let seed = Seed::new("high", 0.0, 0.0, 0.0, "db")
3320            .with_energy(500.0)
3321            .with_pattern(GrowthPattern::Capillary);
3322
3323        assert_eq!(seed.energy, 500.0);
3324
3325        assert_eq!(seed.preferred_pattern, Some(GrowthPattern::Capillary));
3326    }
3327
3328    #[test]
3329
3330    fn test_organism_age() {
3331        let seed = test_seed();
3332
3333        let field = MorphogenField::new();
3334
3335        let config = GrowthConfig::default();
3336
3337        let mut organism = mycelium_growth(&seed, &field, &config);
3338
3339        let initial_energy: f64 = organism.nodes.iter().map(|n| n.energy).sum();
3340
3341        organism.age_one_cycle();
3342
3343        let after_energy: f64 = organism.nodes.iter().map(|n| n.energy).sum();
3344
3345        assert!(after_energy < initial_energy, "Aging should reduce energy");
3346
3347        assert_eq!(organism.age_cycles, 1);
3348    }
3349
3350    #[test]
3351
3352    fn test_map_to_architecture_preserves_structure() {
3353        let seed = Seed::new("arch_test", 0.0, 0.0, 0.0, "gateway");
3354
3355        let field = MorphogenField::new();
3356
3357        let config = GrowthConfig::capillary_default();
3358
3359        let organism = capillary_growth(&seed, &field, &config);
3360
3361        let arch = express_as_architecture(&organism);
3362
3363        assert_eq!(arch.components.len(), organism.nodes.len());
3364    }
3365}