Skip to main content

exo_exotic/
morphogenesis.rs

1//! # Morphogenetic Cognition
2//!
3//! Self-organizing pattern formation inspired by biological development.
4//! Uses reaction-diffusion systems (Turing patterns) to generate
5//! emergent cognitive structures.
6//!
7//! ## Key Concepts
8//!
9//! - **Turing Patterns**: Emergent patterns from reaction-diffusion
10//! - **Morphogens**: Signaling molecules that create concentration gradients
11//! - **Self-Organization**: Structure emerges from local rules
12//! - **Cognitive Embryogenesis**: Growing cognitive structures
13//!
14//! ## Mathematical Foundation
15//!
16//! Based on Turing's 1952 paper "The Chemical Basis of Morphogenesis":
17//! ∂u/∂t = Du∇²u + f(u,v)
18//! ∂v/∂t = Dv∇²v + g(u,v)
19
20use serde::{Deserialize, Serialize};
21use std::collections::HashMap;
22use uuid::Uuid;
23
24/// A field where morphogenetic patterns emerge
25#[derive(Debug)]
26pub struct MorphogeneticField {
27    /// Width of the field
28    width: usize,
29    /// Height of the field
30    height: usize,
31    /// Activator concentration
32    activator: Vec<Vec<f64>>,
33    /// Inhibitor concentration
34    inhibitor: Vec<Vec<f64>>,
35    /// Diffusion rate for activator
36    da: f64,
37    /// Diffusion rate for inhibitor
38    db: f64,
39    /// Reaction parameters
40    params: ReactionParams,
41    /// Pattern history for analysis
42    pattern_history: Vec<PatternSnapshot>,
43    /// Time step
44    dt: f64,
45}
46
47/// Parameters for reaction kinetics
48#[derive(Debug, Clone)]
49pub struct ReactionParams {
50    /// Feed rate
51    pub f: f64,
52    /// Kill rate
53    pub k: f64,
54    /// Activator production rate
55    pub alpha: f64,
56    /// Inhibitor production rate
57    pub beta: f64,
58}
59
60/// A snapshot of the pattern state
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct PatternSnapshot {
63    pub timestamp: u64,
64    pub complexity: f64,
65    pub dominant_wavelength: f64,
66    pub symmetry_score: f64,
67}
68
69/// Turing pattern generator
70#[derive(Debug)]
71pub struct TuringPattern {
72    /// Pattern type
73    pub pattern_type: PatternType,
74    /// Characteristic wavelength
75    pub wavelength: f64,
76    /// Amplitude of pattern
77    pub amplitude: f64,
78    /// Pattern data
79    pub data: Vec<Vec<f64>>,
80}
81
82/// Types of Turing patterns
83#[derive(Debug, Clone, PartialEq)]
84pub enum PatternType {
85    /// Spots pattern
86    Spots,
87    /// Stripes pattern
88    Stripes,
89    /// Labyrinth pattern
90    Labyrinth,
91    /// Hexagonal pattern
92    Hexagonal,
93    /// Mixed/transitional
94    Mixed,
95}
96
97/// Cognitive embryogenesis - growing cognitive structures
98#[derive(Debug)]
99pub struct CognitiveEmbryogenesis {
100    /// Current developmental stage
101    stage: DevelopmentStage,
102    /// Growing cognitive structures
103    structures: Vec<CognitiveStructure>,
104    /// Morphogen gradients
105    gradients: HashMap<String, Vec<f64>>,
106    /// Development history
107    history: Vec<DevelopmentEvent>,
108}
109
110#[derive(Debug, Clone, PartialEq)]
111pub enum DevelopmentStage {
112    /// Initial undifferentiated state
113    Zygote,
114    /// Early division
115    Cleavage,
116    /// Pattern formation
117    Gastrulation,
118    /// Structure differentiation
119    Organogenesis,
120    /// Mature structure
121    Mature,
122}
123
124#[derive(Debug, Clone)]
125pub struct CognitiveStructure {
126    pub id: Uuid,
127    pub structure_type: StructureType,
128    pub position: (f64, f64, f64),
129    pub size: f64,
130    pub connectivity: Vec<Uuid>,
131    pub specialization: f64,
132}
133
134#[derive(Debug, Clone, PartialEq)]
135pub enum StructureType {
136    SensoryRegion,
137    ProcessingNode,
138    MemoryStore,
139    IntegrationHub,
140    OutputRegion,
141}
142
143#[derive(Debug, Clone)]
144pub struct DevelopmentEvent {
145    pub stage: DevelopmentStage,
146    pub event_type: String,
147    pub timestamp: u64,
148}
149
150impl MorphogeneticField {
151    /// Create a new morphogenetic field
152    pub fn new(width: usize, height: usize) -> Self {
153        let mut field = Self {
154            width,
155            height,
156            activator: vec![vec![1.0; width]; height],
157            inhibitor: vec![vec![0.0; width]; height],
158            da: 1.0,
159            db: 0.5,
160            params: ReactionParams {
161                f: 0.055,
162                k: 0.062,
163                alpha: 1.0,
164                beta: 1.0,
165            },
166            pattern_history: Vec::new(),
167            dt: 1.0,
168        };
169
170        // Add initial perturbation
171        field.add_random_perturbation(0.05);
172        field
173    }
174
175    /// Create with specific parameters
176    pub fn with_params(
177        width: usize,
178        height: usize,
179        da: f64,
180        db: f64,
181        params: ReactionParams,
182    ) -> Self {
183        let mut field = Self::new(width, height);
184        field.da = da;
185        field.db = db;
186        field.params = params;
187        field
188    }
189
190    /// Add random perturbation to break symmetry
191    pub fn add_random_perturbation(&mut self, magnitude: f64) {
192        use std::time::{SystemTime, UNIX_EPOCH};
193        let seed = SystemTime::now()
194            .duration_since(UNIX_EPOCH)
195            .map(|d| d.as_nanos())
196            .unwrap_or(12345) as u64;
197
198        let mut state = seed;
199
200        for y in 0..self.height {
201            for x in 0..self.width {
202                // Simple LCG random
203                state = state
204                    .wrapping_mul(6364136223846793005)
205                    .wrapping_add(1442695040888963407);
206                let r = (state as f64) / (u64::MAX as f64);
207                self.inhibitor[y][x] += (r - 0.5) * magnitude;
208            }
209        }
210    }
211
212    /// Measure pattern complexity
213    pub fn measure_complexity(&self) -> f64 {
214        // Complexity based on spatial entropy and gradient magnitude
215        let mut gradient_sum = 0.0;
216        let mut count = 0;
217
218        for y in 1..self.height - 1 {
219            for x in 1..self.width - 1 {
220                let dx = self.activator[y][x + 1] - self.activator[y][x - 1];
221                let dy = self.activator[y + 1][x] - self.activator[y - 1][x];
222                gradient_sum += (dx * dx + dy * dy).sqrt();
223                count += 1;
224            }
225        }
226
227        if count > 0 {
228            (gradient_sum / count as f64).min(1.0)
229        } else {
230            0.0
231        }
232    }
233
234    /// Run one simulation step using Gray-Scott model
235    pub fn step(&mut self) {
236        let mut new_a = self.activator.clone();
237        let mut new_b = self.inhibitor.clone();
238
239        for y in 1..self.height - 1 {
240            for x in 1..self.width - 1 {
241                let a = self.activator[y][x];
242                let b = self.inhibitor[y][x];
243
244                // Laplacian (diffusion)
245                let lap_a = self.activator[y - 1][x]
246                    + self.activator[y + 1][x]
247                    + self.activator[y][x - 1]
248                    + self.activator[y][x + 1]
249                    - 4.0 * a;
250
251                let lap_b = self.inhibitor[y - 1][x]
252                    + self.inhibitor[y + 1][x]
253                    + self.inhibitor[y][x - 1]
254                    + self.inhibitor[y][x + 1]
255                    - 4.0 * b;
256
257                // Gray-Scott reaction
258                let reaction = a * b * b;
259
260                new_a[y][x] =
261                    a + self.dt * (self.da * lap_a - reaction + self.params.f * (1.0 - a));
262
263                new_b[y][x] = b + self.dt
264                    * (self.db * lap_b + reaction - (self.params.f + self.params.k) * b);
265
266                // Clamp values
267                new_a[y][x] = new_a[y][x].clamp(0.0, 1.0);
268                new_b[y][x] = new_b[y][x].clamp(0.0, 1.0);
269            }
270        }
271
272        self.activator = new_a;
273        self.inhibitor = new_b;
274    }
275
276    /// Run simulation for n steps
277    pub fn simulate(&mut self, steps: usize) {
278        for _ in 0..steps {
279            self.step();
280        }
281
282        // Record snapshot
283        self.pattern_history.push(PatternSnapshot {
284            timestamp: self.pattern_history.len() as u64,
285            complexity: self.measure_complexity(),
286            dominant_wavelength: self.estimate_wavelength(),
287            symmetry_score: self.measure_symmetry(),
288        });
289    }
290
291    /// Estimate dominant wavelength using autocorrelation
292    fn estimate_wavelength(&self) -> f64 {
293        let center_y = self.height / 2;
294        let slice: Vec<f64> = (0..self.width)
295            .map(|x| self.activator[center_y][x])
296            .collect();
297
298        // Find first minimum in autocorrelation
299        let mut best_lag = 1;
300        let mut min_corr = f64::MAX;
301
302        for lag in 1..self.width / 4 {
303            let mut corr = 0.0;
304            let mut count = 0;
305
306            for i in 0..self.width - lag {
307                corr += slice[i] * slice[i + lag];
308                count += 1;
309            }
310
311            if count > 0 {
312                corr /= count as f64;
313                if corr < min_corr {
314                    min_corr = corr;
315                    best_lag = lag;
316                }
317            }
318        }
319
320        (best_lag * 2) as f64 // Wavelength is twice the first minimum lag
321    }
322
323    /// Measure pattern symmetry
324    fn measure_symmetry(&self) -> f64 {
325        let mut diff_sum = 0.0;
326        let mut count = 0;
327
328        // Check left-right symmetry
329        for y in 0..self.height {
330            for x in 0..self.width / 2 {
331                let mirror_x = self.width - 1 - x;
332                let diff = (self.activator[y][x] - self.activator[y][mirror_x]).abs();
333                diff_sum += diff;
334                count += 1;
335            }
336        }
337
338        if count > 0 {
339            1.0 - (diff_sum / count as f64).min(1.0)
340        } else {
341            0.0
342        }
343    }
344
345    /// Detect pattern type
346    pub fn detect_pattern_type(&self) -> PatternType {
347        let complexity = self.measure_complexity();
348        let symmetry = self.measure_symmetry();
349        let wavelength = self.estimate_wavelength();
350
351        if complexity < 0.1 {
352            PatternType::Mixed // Uniform
353        } else if symmetry > 0.7 && wavelength > self.width as f64 / 4.0 {
354            PatternType::Stripes
355        } else if symmetry > 0.5 && wavelength < self.width as f64 / 8.0 {
356            PatternType::Spots
357        } else if complexity > 0.5 {
358            PatternType::Labyrinth
359        } else {
360            PatternType::Mixed
361        }
362    }
363
364    /// Get the activator field
365    pub fn activator_field(&self) -> &Vec<Vec<f64>> {
366        &self.activator
367    }
368
369    /// Get the inhibitor field
370    pub fn inhibitor_field(&self) -> &Vec<Vec<f64>> {
371        &self.inhibitor
372    }
373
374    /// Get pattern at specific location
375    pub fn sample(&self, x: usize, y: usize) -> Option<(f64, f64)> {
376        if x < self.width && y < self.height {
377            Some((self.activator[y][x], self.inhibitor[y][x]))
378        } else {
379            None
380        }
381    }
382}
383
384impl CognitiveEmbryogenesis {
385    /// Create a new embryogenesis process
386    pub fn new() -> Self {
387        Self {
388            stage: DevelopmentStage::Zygote,
389            structures: Vec::new(),
390            gradients: HashMap::new(),
391            history: Vec::new(),
392        }
393    }
394
395    /// Advance development by one stage
396    pub fn develop(&mut self) -> DevelopmentStage {
397        let new_stage = match self.stage {
398            DevelopmentStage::Zygote => {
399                self.initialize_gradients();
400                DevelopmentStage::Cleavage
401            }
402            DevelopmentStage::Cleavage => {
403                self.divide_structures();
404                DevelopmentStage::Gastrulation
405            }
406            DevelopmentStage::Gastrulation => {
407                self.form_patterns();
408                DevelopmentStage::Organogenesis
409            }
410            DevelopmentStage::Organogenesis => {
411                self.differentiate();
412                DevelopmentStage::Mature
413            }
414            DevelopmentStage::Mature => DevelopmentStage::Mature,
415        };
416
417        self.history.push(DevelopmentEvent {
418            stage: new_stage.clone(),
419            event_type: format!("Transition to {:?}", new_stage),
420            timestamp: self.history.len() as u64,
421        });
422
423        self.stage = new_stage.clone();
424        new_stage
425    }
426
427    fn initialize_gradients(&mut self) {
428        // Create morphogen gradients
429        let gradient_length = 100;
430
431        // Anterior-posterior gradient
432        let ap_gradient: Vec<f64> = (0..gradient_length)
433            .map(|i| i as f64 / gradient_length as f64)
434            .collect();
435        self.gradients
436            .insert("anterior_posterior".to_string(), ap_gradient);
437
438        // Dorsal-ventral gradient
439        let dv_gradient: Vec<f64> = (0..gradient_length)
440            .map(|i| {
441                let x = i as f64 / gradient_length as f64;
442                (x * std::f64::consts::PI).sin()
443            })
444            .collect();
445        self.gradients
446            .insert("dorsal_ventral".to_string(), dv_gradient);
447    }
448
449    fn divide_structures(&mut self) {
450        // Create initial structures through division
451        let initial = CognitiveStructure {
452            id: Uuid::new_v4(),
453            structure_type: StructureType::ProcessingNode,
454            position: (0.5, 0.5, 0.5),
455            size: 1.0,
456            connectivity: Vec::new(),
457            specialization: 0.0,
458        };
459
460        // Divide into multiple structures
461        for i in 0..4 {
462            let angle = i as f64 * std::f64::consts::PI / 2.0;
463            self.structures.push(CognitiveStructure {
464                id: Uuid::new_v4(),
465                structure_type: StructureType::ProcessingNode,
466                position: (0.5 + 0.3 * angle.cos(), 0.5 + 0.3 * angle.sin(), 0.5),
467                size: initial.size / 4.0,
468                connectivity: Vec::new(),
469                specialization: 0.0,
470            });
471        }
472    }
473
474    fn form_patterns(&mut self) {
475        // Establish connectivity patterns based on gradients
476        let structure_ids: Vec<Uuid> = self.structures.iter().map(|s| s.id).collect();
477
478        for i in 0..self.structures.len() {
479            for j in i + 1..self.structures.len() {
480                let dist = self.distance(i, j);
481                if dist < 0.5 {
482                    self.structures[i].connectivity.push(structure_ids[j]);
483                    self.structures[j].connectivity.push(structure_ids[i]);
484                }
485            }
486        }
487    }
488
489    fn distance(&self, i: usize, j: usize) -> f64 {
490        let (x1, y1, z1) = self.structures[i].position;
491        let (x2, y2, z2) = self.structures[j].position;
492        ((x2 - x1).powi(2) + (y2 - y1).powi(2) + (z2 - z1).powi(2)).sqrt()
493    }
494
495    fn differentiate(&mut self) {
496        // Differentiate structures based on position in gradients
497        for structure in &mut self.structures {
498            let (x, y, _) = structure.position;
499
500            // Determine type based on position
501            structure.structure_type = if x < 0.3 {
502                StructureType::SensoryRegion
503            } else if x > 0.7 {
504                StructureType::OutputRegion
505            } else if y < 0.3 {
506                StructureType::MemoryStore
507            } else if y > 0.7 {
508                StructureType::IntegrationHub
509            } else {
510                StructureType::ProcessingNode
511            };
512
513            structure.specialization = 1.0;
514        }
515    }
516
517    /// Get current stage
518    pub fn current_stage(&self) -> &DevelopmentStage {
519        &self.stage
520    }
521
522    /// Get structures
523    pub fn structures(&self) -> &[CognitiveStructure] {
524        &self.structures
525    }
526
527    /// Check if development is complete
528    pub fn is_mature(&self) -> bool {
529        self.stage == DevelopmentStage::Mature
530    }
531
532    /// Run full development
533    pub fn full_development(&mut self) {
534        while self.stage != DevelopmentStage::Mature {
535            self.develop();
536        }
537    }
538}
539
540impl Default for CognitiveEmbryogenesis {
541    fn default() -> Self {
542        Self::new()
543    }
544}
545
546#[cfg(test)]
547mod tests {
548    use super::*;
549
550    #[test]
551    fn test_morphogenetic_field_creation() {
552        let field = MorphogeneticField::new(32, 32);
553        assert_eq!(field.width, 32);
554        assert_eq!(field.height, 32);
555    }
556
557    #[test]
558    fn test_simulation_step() {
559        let mut field = MorphogeneticField::new(32, 32);
560        field.step();
561
562        // Field should still be valid
563        assert!(field.activator[16][16] >= 0.0);
564        assert!(field.activator[16][16] <= 1.0);
565    }
566
567    #[test]
568    fn test_pattern_complexity() {
569        let mut field = MorphogeneticField::new(32, 32);
570
571        // Initial complexity should be low
572        let initial_complexity = field.measure_complexity();
573
574        // After simulation, patterns should form
575        field.simulate(100);
576        let final_complexity = field.measure_complexity();
577
578        // Complexity should generally increase (patterns form)
579        assert!(final_complexity >= 0.0);
580    }
581
582    #[test]
583    fn test_pattern_detection() {
584        let mut field = MorphogeneticField::new(32, 32);
585        field.simulate(50);
586
587        let pattern_type = field.detect_pattern_type();
588        // Should detect some pattern type
589        assert!(matches!(
590            pattern_type,
591            PatternType::Spots
592                | PatternType::Stripes
593                | PatternType::Labyrinth
594                | PatternType::Hexagonal
595                | PatternType::Mixed
596        ));
597    }
598
599    #[test]
600    fn test_cognitive_embryogenesis() {
601        let mut embryo = CognitiveEmbryogenesis::new();
602        assert_eq!(*embryo.current_stage(), DevelopmentStage::Zygote);
603
604        embryo.full_development();
605
606        assert!(embryo.is_mature());
607        assert!(!embryo.structures().is_empty());
608    }
609
610    #[test]
611    fn test_structure_differentiation() {
612        let mut embryo = CognitiveEmbryogenesis::new();
613        embryo.full_development();
614
615        // Should have different structure types
616        let types: Vec<_> = embryo
617            .structures()
618            .iter()
619            .map(|s| &s.structure_type)
620            .collect();
621
622        assert!(embryo.structures().iter().all(|s| s.specialization > 0.0));
623    }
624
625    #[test]
626    fn test_gradient_initialization() {
627        let mut embryo = CognitiveEmbryogenesis::new();
628        embryo.develop(); // Zygote -> Cleavage, initializes gradients
629
630        assert!(embryo.gradients.contains_key("anterior_posterior"));
631        assert!(embryo.gradients.contains_key("dorsal_ventral"));
632    }
633}