scirs2_spatial/neuromorphic/
mod.rs

1//! Neuromorphic Computing for Spatial Data Processing
2//!
3//! This module implements brain-inspired computing paradigms for spatial algorithms,
4//! leveraging spiking neural networks, memristive computing, and neuroplasticity
5//! for energy-efficient adaptive spatial processing. These algorithms mimic biological
6//! neural computation to achieve extreme energy efficiency and real-time adaptation.
7//!
8//! # Features
9//!
10//! - **Spiking Neural Networks (SNNs)** for spatial pattern recognition
11//! - **Memristive crossbar arrays** for in-memory spatial computations
12//! - **Spike-timing dependent plasticity (STDP)** for adaptive learning
13//! - **Event-driven spatial processing** for real-time applications
14//! - **Neuromorphic clustering** using competitive learning
15//! - **Temporal coding** for multi-dimensional spatial data
16//! - **Bio-inspired optimization** using neural adaptation mechanisms
17//! - **Homeostatic plasticity** for stable learning
18//! - **Neuromodulation** for context-dependent adaptation
19//!
20//! # Module Organization
21//!
22//! ## Core Components
23//! - [`core::events`] - Spike event structures and utilities
24//! - [`core::neurons`] - Spiking neuron models with various dynamics
25//! - [`core::synapses`] - Synaptic models with STDP and metaplasticity
26//!
27//! ## Algorithm Implementations
28//! - [`algorithms::spiking_clustering`] - SNN-based clustering
29//! - [`algorithms::competitive_learning`] - Winner-take-all and homeostatic clustering
30//! - [`algorithms::memristive_learning`] - Advanced memristive learning systems
31//! - [`algorithms::processing`] - General neuromorphic processing pipeline
32//!
33//! # Examples
34//!
35//! ## Basic Spiking Neural Network Clustering
36//! ```rust,ignore
37//! use scirs2_core::ndarray::Array2;
38//! use scirs2_spatial::neuromorphic::SpikingNeuralClusterer;
39//!
40//! let points = Array2::from_shape_vec((4, 2), vec![
41//!     0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0
42//! ]).unwrap();
43//!
44//! let mut clusterer = SpikingNeuralClusterer::new(2)
45//!     .with_spike_threshold(0.8)
46//!     .with_stdp_learning(true)
47//!     .with_lateral_inhibition(true);
48//!
49//! let (assignments, spike_events) = clusterer.fit(&points.view()).unwrap();
50//! println!("Cluster assignments: {:?}", assignments);
51//! println!("Recorded {} spike events", spike_events.len());
52//! ```
53//!
54//! ## Competitive Learning with Homeostasis
55//! ```rust,ignore
56//! use scirs2_core::ndarray::Array2;
57//! use scirs2_spatial::neuromorphic::HomeostaticNeuralClusterer;
58//!
59//! let points = Array2::from_shape_vec((4, 2), vec![
60//!     0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0
61//! ]).unwrap();
62//!
63//! let mut clusterer = HomeostaticNeuralClusterer::new(2, 2)
64//!     .with_homeostatic_params(0.1, 1000.0);
65//!
66//! let assignments = clusterer.fit(&points.view(), 50).unwrap();
67//! println!("Homeostatic clustering results: {:?}", assignments);
68//! ```
69//!
70//! ## Advanced Memristive Learning
71//! ```rust,ignore
72//! use scirs2_core::ndarray::{Array1, Array2};
73//! use scirs2_spatial::neuromorphic::{AdvancedMemristiveLearning, MemristiveDeviceType};
74//!
75//! let mut learning_system = AdvancedMemristiveLearning::new(
76//!     4, 2, MemristiveDeviceType::TitaniumDioxide
77//! ).with_forgetting_protection(true);
78//!
79//! let spatial_data = Array2::from_shape_vec((4, 4), vec![
80//!     0.0, 0.0, 1.0, 1.0,
81//!     1.0, 0.0, 0.0, 1.0,
82//!     0.0, 1.0, 1.0, 0.0,
83//!     1.0, 1.0, 0.0, 0.0
84//! ]).unwrap();
85//! let targets = Array1::from_vec(vec![0.0, 1.0, 1.0, 0.0]);
86//!
87//! # tokio_test::block_on(async {
88//! let result = learning_system.train_spatial_data(
89//!     &spatial_data.view(), &targets.view(), 50
90//! ).await.unwrap();
91//! println!("Training completed with final accuracy: {:.2}",
92//!          result.training_metrics.last().unwrap().accuracy);
93//! # });
94//! ```
95//!
96//! ## Event-driven Neuromorphic Processing
97//! ```rust,ignore
98//! use scirs2_core::ndarray::Array2;
99//! use scirs2_spatial::neuromorphic::NeuromorphicProcessor;
100//!
101//! let points = Array2::from_shape_vec((3, 2), vec![
102//!     0.0, 0.0, 1.0, 1.0, 2.0, 2.0
103//! ]).unwrap();
104//!
105//! let mut processor = NeuromorphicProcessor::new()
106//!     .with_memristive_crossbar(true)
107//!     .with_temporal_coding(true)
108//!     .with_crossbar_size(64, 64);
109//!
110//! // Encode spatial data as neuromorphic events
111//! let events = processor.encode_spatial_events(&points.view()).unwrap();
112//!
113//! // Process events through neuromorphic pipeline
114//! let processed_events = processor.process_events(&events).unwrap();
115//! println!("Processed {} events", processed_events.len());
116//! ```
117//!
118//! # Performance Considerations
119//!
120//! Neuromorphic algorithms are designed for:
121//! - **Energy efficiency**: Event-driven processing reduces computation
122//! - **Real-time adaptation**: Online learning without full retraining
123//! - **Noise tolerance**: Biological inspiration provides robustness
124//! - **Scalability**: Distributed processing capabilities
125//!
126//! # Biological Inspiration
127//!
128//! These algorithms draw inspiration from:
129//! - **Synaptic plasticity**: Adaptive connection strengths
130//! - **Homeostatic regulation**: Maintaining stable activity levels
131//! - **Neuromodulation**: Context-dependent learning control
132//! - **Memory consolidation**: Strengthening important patterns
133//! - **Competitive dynamics**: Winner-take-all neural competition
134
135pub mod algorithms;
136pub mod core;
137
138// Re-export core components for easier access
139pub use core::events::{SpikeEvent, SpikeSequence};
140pub use core::neurons::{AdaptiveSpikingNeuron, SpikingNeuron};
141pub use core::synapses::{HomeostaticSynapse, MetaplasticSynapse, Synapse};
142
143// Re-export main algorithm implementations
144pub use algorithms::competitive_learning::{
145    AdaptationScale, CompetitiveNeuralClusterer, HomeostaticNeuralClusterer, HomeostaticNeuron,
146    LearningRateAdaptation, MetaplasticityController, MultiTimescaleAdaptation,
147};
148pub use algorithms::memristive_learning::{
149    AdvancedMemristiveLearning, ConsolidationEvent, ConsolidationRules, ConsolidationType,
150    ForgettingProtectionRules, HomeostaticMechanism, HomeostaticSystem, LearningHistory,
151    LearningRateAdaptation as MemristiveLearningRateAdaptation, MemristiveCrossbar,
152    MemristiveDeviceType, MetaplasticityRules, NeuromodulationEffects, NeuromodulationSystem,
153    NeuromodulatorReleasePatterns, PerformanceMetrics, PlasticityEvent, PlasticityEventType,
154    PlasticityLearningRates, PlasticityMechanism, PlasticityThresholds, PlasticityTimeConstants,
155    PlasticityType, ThresholdAdaptation, TrainingResult,
156};
157pub use algorithms::processing::NeuromorphicProcessor;
158pub use algorithms::spiking_clustering::{NetworkStats, SpikingNeuralClusterer};
159
160/// Neuromorphic algorithm trait for unified interface
161///
162/// This trait provides a common interface for all neuromorphic algorithms,
163/// enabling interchangeable use and consistent API across different approaches.
164pub trait NeuromorphicAlgorithm<T> {
165    /// Input data type
166    type Input;
167    /// Output data type  
168    type Output;
169    /// Error type
170    type Error;
171
172    /// Fit the algorithm to spatial data
173    fn fit(&mut self, data: &Self::Input) -> Result<Self::Output, Self::Error>;
174
175    /// Predict using the trained algorithm
176    fn predict(&self, data: &Self::Input) -> Result<Self::Output, Self::Error>;
177
178    /// Get algorithm parameters
179    fn parameters(&self) -> T;
180
181    /// Reset algorithm to initial state
182    fn reset(&mut self);
183}
184
185/// Neuromorphic processing capabilities
186///
187/// Enumeration of different neuromorphic processing modes and capabilities
188/// available in the system.
189#[derive(Debug, Clone, PartialEq, Eq)]
190pub enum NeuromorphicCapability {
191    /// Spike-timing dependent plasticity
192    SpikePlasticity,
193    /// Homeostatic regulation
194    HomeostaticRegulation,
195    /// Competitive learning dynamics
196    CompetitiveDynamics,
197    /// Memristive crossbar arrays
198    MemristiveComputing,
199    /// Event-driven processing
200    EventDrivenProcessing,
201    /// Temporal coding schemes
202    TemporalCoding,
203    /// Neuromodulation effects
204    Neuromodulation,
205    /// Memory consolidation
206    MemoryConsolidation,
207    /// Online learning
208    OnlineLearning,
209    /// Catastrophic forgetting protection
210    ForgettingProtection,
211}
212
213/// Neuromorphic system configuration
214///
215/// Configuration structure for setting up neuromorphic systems with
216/// specific capabilities and parameters.
217#[derive(Debug, Clone)]
218pub struct NeuromorphicConfig {
219    /// Enabled capabilities
220    pub capabilities: Vec<NeuromorphicCapability>,
221    /// Number of neurons/clusters
222    pub num_neurons: usize,
223    /// Input dimensions
224    pub input_dims: usize,
225    /// Learning rate
226    pub learning_rate: f64,
227    /// Spike threshold
228    pub spike_threshold: f64,
229    /// Time step for simulation
230    pub time_step: f64,
231    /// Maximum simulation time
232    pub max_time: f64,
233    /// Enable debugging output
234    pub debug_mode: bool,
235}
236
237impl Default for NeuromorphicConfig {
238    fn default() -> Self {
239        Self {
240            capabilities: vec![
241                NeuromorphicCapability::SpikePlasticity,
242                NeuromorphicCapability::EventDrivenProcessing,
243            ],
244            num_neurons: 10,
245            input_dims: 2,
246            learning_rate: 0.01,
247            spike_threshold: 1.0,
248            time_step: 0.1,
249            max_time: 100.0,
250            debug_mode: false,
251        }
252    }
253}
254
255impl NeuromorphicConfig {
256    /// Create new configuration
257    pub fn new() -> Self {
258        Self::default()
259    }
260
261    /// Set number of neurons
262    pub fn with_neurons(mut self, num_neurons: usize) -> Self {
263        self.num_neurons = num_neurons;
264        self
265    }
266
267    /// Set input dimensions
268    pub fn with_input_dims(mut self, input_dims: usize) -> Self {
269        self.input_dims = input_dims;
270        self
271    }
272
273    /// Set learning rate
274    pub fn with_learning_rate(mut self, learning_rate: f64) -> Self {
275        self.learning_rate = learning_rate;
276        self
277    }
278
279    /// Add capability
280    pub fn with_capability(mut self, capability: NeuromorphicCapability) -> Self {
281        if !self.capabilities.contains(&capability) {
282            self.capabilities.push(capability);
283        }
284        self
285    }
286
287    /// Remove capability
288    pub fn without_capability(mut self, capability: &NeuromorphicCapability) -> Self {
289        self.capabilities.retain(|c| c != capability);
290        self
291    }
292
293    /// Enable debug mode
294    pub fn with_debug(mut self, debug: bool) -> Self {
295        self.debug_mode = debug;
296        self
297    }
298
299    /// Check if capability is enabled
300    pub fn has_capability(&self, capability: &NeuromorphicCapability) -> bool {
301        self.capabilities.contains(capability)
302    }
303}
304
305/// Neuromorphic system factory
306///
307/// Factory for creating different types of neuromorphic systems based
308/// on configuration and requirements.
309pub struct NeuromorphicFactory;
310
311impl NeuromorphicFactory {
312    /// Create spiking neural network clusterer
313    pub fn create_spiking_clusterer(config: &NeuromorphicConfig) -> SpikingNeuralClusterer {
314        let mut clusterer = SpikingNeuralClusterer::new(config.num_neurons)
315            .with_spike_threshold(config.spike_threshold)
316            .with_time_step(config.time_step);
317
318        if config.has_capability(&NeuromorphicCapability::SpikePlasticity) {
319            clusterer = clusterer.with_stdp_learning(true);
320        }
321
322        if config.has_capability(&NeuromorphicCapability::CompetitiveDynamics) {
323            clusterer = clusterer.with_lateral_inhibition(true);
324        }
325
326        clusterer
327    }
328
329    /// Create competitive neural clusterer
330    pub fn create_competitive_clusterer(config: &NeuromorphicConfig) -> CompetitiveNeuralClusterer {
331        CompetitiveNeuralClusterer::new(config.num_neurons, config.input_dims)
332    }
333
334    /// Create homeostatic neural clusterer
335    pub fn create_homeostatic_clusterer(config: &NeuromorphicConfig) -> HomeostaticNeuralClusterer {
336        let mut clusterer = HomeostaticNeuralClusterer::new(config.num_neurons, config.input_dims);
337
338        if config.has_capability(&NeuromorphicCapability::HomeostaticRegulation) {
339            clusterer = clusterer.with_homeostatic_params(0.1, 1000.0);
340        }
341
342        clusterer
343    }
344
345    /// Create advanced memristive learning system
346    pub fn create_memristive_system(
347        config: &NeuromorphicConfig,
348        device_type: MemristiveDeviceType,
349    ) -> AdvancedMemristiveLearning {
350        let mut system =
351            AdvancedMemristiveLearning::new(config.input_dims, config.num_neurons, device_type);
352
353        if config.has_capability(&NeuromorphicCapability::ForgettingProtection) {
354            system = system.with_forgetting_protection(true);
355        }
356
357        if config.has_capability(&NeuromorphicCapability::HomeostaticRegulation) {
358            let target_rates = scirs2_core::ndarray::Array1::from_elem(config.num_neurons, 0.1);
359            system = system.with_homeostatic_regulation(target_rates);
360        }
361
362        system
363    }
364
365    /// Create neuromorphic processor
366    pub fn create_processor(config: &NeuromorphicConfig) -> NeuromorphicProcessor {
367        let mut processor = NeuromorphicProcessor::new();
368
369        if config.has_capability(&NeuromorphicCapability::MemristiveComputing) {
370            processor = processor.with_memristive_crossbar(true);
371        }
372
373        if config.has_capability(&NeuromorphicCapability::TemporalCoding) {
374            processor = processor.with_temporal_coding(true);
375        }
376
377        processor
378    }
379}
380
381/// Neuromorphic utilities
382///
383/// Utility functions for working with neuromorphic algorithms and data.
384pub mod utils {
385    use super::*;
386    use crate::error::SpatialResult;
387    use scirs2_core::ndarray::ArrayView2;
388
389    /// Convert spatial data to spike events
390    ///
391    /// Converts regular spatial data into spike events using rate coding,
392    /// where higher values correspond to higher spike rates.
393    pub fn spatial_to_spikes(
394        data: &ArrayView2<f64>,
395        time_window: f64,
396        max_rate: f64,
397    ) -> SpatialResult<Vec<SpikeEvent>> {
398        let (n_points, n_dims) = data.dim();
399        let mut events = Vec::new();
400
401        for (point_idx, point) in data.outer_iter().enumerate() {
402            for (dim, &value) in point.iter().enumerate() {
403                // Normalize value to [0, 1] and scale to spike rate
404                let normalized = (value + 10.0) / 20.0; // Assume data in [-10, 10]
405                let spike_rate = normalized.clamp(0.0, 1.0) * max_rate;
406
407                // Generate Poisson spike train
408                let num_spikes = (spike_rate * time_window) as usize;
409                for spike_idx in 0..num_spikes {
410                    let timestamp = (spike_idx as f64) * (time_window / num_spikes as f64);
411                    let event =
412                        SpikeEvent::new(point_idx * n_dims + dim, timestamp, 1.0, point.to_vec());
413                    events.push(event);
414                }
415            }
416        }
417
418        // Sort events by timestamp
419        events.sort_by(|a, b| a.timestamp().partial_cmp(&b.timestamp()).unwrap());
420        Ok(events)
421    }
422
423    /// Analyze spike patterns
424    ///
425    /// Analyzes spike timing patterns to extract information about
426    /// spatial structure and temporal dynamics.
427    pub fn analyze_spike_patterns(events: &[SpikeEvent]) -> SpikePatternAnalysis {
428        if events.is_empty() {
429            return SpikePatternAnalysis::default();
430        }
431
432        let total_events = events.len();
433        let time_span = events.last().unwrap().timestamp() - events.first().unwrap().timestamp();
434        let avg_rate = if time_span > 0.0 {
435            total_events as f64 / time_span
436        } else {
437            0.0
438        };
439
440        // Calculate inter-spike intervals
441        let mut intervals = Vec::new();
442        for i in 1..events.len() {
443            intervals.push(events[i].timestamp() - events[i - 1].timestamp());
444        }
445
446        let avg_interval = if !intervals.is_empty() {
447            intervals.iter().sum::<f64>() / intervals.len() as f64
448        } else {
449            0.0
450        };
451
452        // Calculate coefficient of variation for regularity
453        let interval_var = if intervals.len() > 1 {
454            let mean = avg_interval;
455            let variance =
456                intervals.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / intervals.len() as f64;
457            variance.sqrt() / mean.max(1e-10)
458        } else {
459            0.0
460        };
461
462        SpikePatternAnalysis {
463            total_spikes: total_events,
464            time_span,
465            average_rate: avg_rate,
466            average_interval: avg_interval,
467            regularity: 1.0 / (1.0 + interval_var), // Higher = more regular
468            unique_neurons: events
469                .iter()
470                .map(|e| e.neuron_id())
471                .collect::<std::collections::HashSet<_>>()
472                .len(),
473        }
474    }
475
476    /// Spike pattern analysis results
477    #[derive(Debug, Clone)]
478    pub struct SpikePatternAnalysis {
479        /// Total number of spikes
480        pub total_spikes: usize,
481        /// Total time span
482        pub time_span: f64,
483        /// Average firing rate
484        pub average_rate: f64,
485        /// Average inter-spike interval
486        pub average_interval: f64,
487        /// Regularity measure (0-1, higher = more regular)
488        pub regularity: f64,
489        /// Number of unique neurons
490        pub unique_neurons: usize,
491    }
492
493    impl Default for SpikePatternAnalysis {
494        fn default() -> Self {
495            Self {
496                total_spikes: 0,
497                time_span: 0.0,
498                average_rate: 0.0,
499                average_interval: 0.0,
500                regularity: 0.0,
501                unique_neurons: 0,
502            }
503        }
504    }
505}
506
507#[cfg(test)]
508mod tests {
509    use super::*;
510    use scirs2_core::ndarray::Array2;
511
512    #[test]
513    fn test_neuromorphic_config() {
514        let config = NeuromorphicConfig::new()
515            .with_neurons(5)
516            .with_input_dims(3)
517            .with_capability(NeuromorphicCapability::HomeostaticRegulation)
518            .without_capability(&NeuromorphicCapability::SpikePlasticity);
519
520        assert_eq!(config.num_neurons, 5);
521        assert_eq!(config.input_dims, 3);
522        assert!(config.has_capability(&NeuromorphicCapability::HomeostaticRegulation));
523        assert!(!config.has_capability(&NeuromorphicCapability::SpikePlasticity));
524    }
525
526    #[test]
527    fn test_neuromorphic_factory() {
528        let config = NeuromorphicConfig::new()
529            .with_neurons(3)
530            .with_input_dims(2)
531            .with_capability(NeuromorphicCapability::CompetitiveDynamics);
532
533        let spiking_clusterer = NeuromorphicFactory::create_spiking_clusterer(&config);
534        assert_eq!(spiking_clusterer.num_clusters(), 3);
535        assert!(spiking_clusterer.is_lateral_inhibition_enabled());
536
537        let competitive_clusterer = NeuromorphicFactory::create_competitive_clusterer(&config);
538        assert_eq!(competitive_clusterer.num_clusters(), 3);
539
540        let processor = NeuromorphicFactory::create_processor(&config);
541        assert!(!processor.is_memristive_enabled()); // Not in capabilities
542    }
543
544    #[test]
545    fn test_utils_spatial_to_spikes() {
546        let data = Array2::from_shape_vec((2, 2), vec![0.0, 1.0, -1.0, 0.5]).unwrap();
547        let events = utils::spatial_to_spikes(&data.view(), 1.0, 10.0).unwrap();
548
549        // Should generate events for non-zero values
550        assert!(!events.is_empty());
551
552        // Events should be sorted by timestamp
553        for i in 1..events.len() {
554            assert!(events[i - 1].timestamp() <= events[i].timestamp());
555        }
556    }
557
558    #[test]
559    fn test_utils_spike_pattern_analysis() {
560        let events = vec![
561            SpikeEvent::new(0, 0.0, 1.0, vec![0.0, 0.0]),
562            SpikeEvent::new(1, 1.0, 1.0, vec![1.0, 0.0]),
563            SpikeEvent::new(0, 2.0, 1.0, vec![0.0, 1.0]),
564            SpikeEvent::new(2, 3.0, 1.0, vec![1.0, 1.0]),
565        ];
566
567        let analysis = utils::analyze_spike_patterns(&events);
568        assert_eq!(analysis.total_spikes, 4);
569        assert_eq!(analysis.time_span, 3.0);
570        assert!(analysis.average_rate > 0.0);
571        assert_eq!(analysis.unique_neurons, 3);
572    }
573
574    #[test]
575    fn test_empty_spike_analysis() {
576        let events = Vec::new();
577        let analysis = utils::analyze_spike_patterns(&events);
578        assert_eq!(analysis.total_spikes, 0);
579        assert_eq!(analysis.time_span, 0.0);
580        assert_eq!(analysis.average_rate, 0.0);
581    }
582}