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//! ]).expect("Operation failed");
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()).expect("Operation failed");
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//! ]).expect("Operation failed");
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).expect("Operation failed");
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//! ]).expect("Operation failed");
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().expect("Operation failed").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//! ]).expect("Operation failed");
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()).expect("Operation failed");
112//!
113//! // Process events through neuromorphic pipeline
114//! let processed_events = processor.process_events(&events).expect("Operation failed");
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| {
420            a.timestamp()
421                .partial_cmp(&b.timestamp())
422                .expect("Operation failed")
423        });
424        Ok(events)
425    }
426
427    /// Analyze spike patterns
428    ///
429    /// Analyzes spike timing patterns to extract information about
430    /// spatial structure and temporal dynamics.
431    pub fn analyze_spike_patterns(events: &[SpikeEvent]) -> SpikePatternAnalysis {
432        if events.is_empty() {
433            return SpikePatternAnalysis::default();
434        }
435
436        let total_events = events.len();
437        let time_span = events.last().expect("Operation failed").timestamp()
438            - events.first().expect("Operation failed").timestamp();
439        let avg_rate = if time_span > 0.0 {
440            total_events as f64 / time_span
441        } else {
442            0.0
443        };
444
445        // Calculate inter-spike intervals
446        let mut intervals = Vec::new();
447        for i in 1..events.len() {
448            intervals.push(events[i].timestamp() - events[i - 1].timestamp());
449        }
450
451        let avg_interval = if !intervals.is_empty() {
452            intervals.iter().sum::<f64>() / intervals.len() as f64
453        } else {
454            0.0
455        };
456
457        // Calculate coefficient of variation for regularity
458        let interval_var = if intervals.len() > 1 {
459            let mean = avg_interval;
460            let variance =
461                intervals.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / intervals.len() as f64;
462            variance.sqrt() / mean.max(1e-10)
463        } else {
464            0.0
465        };
466
467        SpikePatternAnalysis {
468            total_spikes: total_events,
469            time_span,
470            average_rate: avg_rate,
471            average_interval: avg_interval,
472            regularity: 1.0 / (1.0 + interval_var), // Higher = more regular
473            unique_neurons: events
474                .iter()
475                .map(|e| e.neuron_id())
476                .collect::<std::collections::HashSet<_>>()
477                .len(),
478        }
479    }
480
481    /// Spike pattern analysis results
482    #[derive(Debug, Clone)]
483    pub struct SpikePatternAnalysis {
484        /// Total number of spikes
485        pub total_spikes: usize,
486        /// Total time span
487        pub time_span: f64,
488        /// Average firing rate
489        pub average_rate: f64,
490        /// Average inter-spike interval
491        pub average_interval: f64,
492        /// Regularity measure (0-1, higher = more regular)
493        pub regularity: f64,
494        /// Number of unique neurons
495        pub unique_neurons: usize,
496    }
497
498    impl Default for SpikePatternAnalysis {
499        fn default() -> Self {
500            Self {
501                total_spikes: 0,
502                time_span: 0.0,
503                average_rate: 0.0,
504                average_interval: 0.0,
505                regularity: 0.0,
506                unique_neurons: 0,
507            }
508        }
509    }
510}
511
512#[cfg(test)]
513mod tests {
514    use super::*;
515    use scirs2_core::ndarray::Array2;
516
517    #[test]
518    fn test_neuromorphic_config() {
519        let config = NeuromorphicConfig::new()
520            .with_neurons(5)
521            .with_input_dims(3)
522            .with_capability(NeuromorphicCapability::HomeostaticRegulation)
523            .without_capability(&NeuromorphicCapability::SpikePlasticity);
524
525        assert_eq!(config.num_neurons, 5);
526        assert_eq!(config.input_dims, 3);
527        assert!(config.has_capability(&NeuromorphicCapability::HomeostaticRegulation));
528        assert!(!config.has_capability(&NeuromorphicCapability::SpikePlasticity));
529    }
530
531    #[test]
532    fn test_neuromorphic_factory() {
533        let config = NeuromorphicConfig::new()
534            .with_neurons(3)
535            .with_input_dims(2)
536            .with_capability(NeuromorphicCapability::CompetitiveDynamics);
537
538        let spiking_clusterer = NeuromorphicFactory::create_spiking_clusterer(&config);
539        assert_eq!(spiking_clusterer.num_clusters(), 3);
540        assert!(spiking_clusterer.is_lateral_inhibition_enabled());
541
542        let competitive_clusterer = NeuromorphicFactory::create_competitive_clusterer(&config);
543        assert_eq!(competitive_clusterer.num_clusters(), 3);
544
545        let processor = NeuromorphicFactory::create_processor(&config);
546        assert!(!processor.is_memristive_enabled()); // Not in capabilities
547    }
548
549    #[test]
550    fn test_utils_spatial_to_spikes() {
551        let data =
552            Array2::from_shape_vec((2, 2), vec![0.0, 1.0, -1.0, 0.5]).expect("Operation failed");
553        let events = utils::spatial_to_spikes(&data.view(), 1.0, 10.0).expect("Operation failed");
554
555        // Should generate events for non-zero values
556        assert!(!events.is_empty());
557
558        // Events should be sorted by timestamp
559        for i in 1..events.len() {
560            assert!(events[i - 1].timestamp() <= events[i].timestamp());
561        }
562    }
563
564    #[test]
565    fn test_utils_spike_pattern_analysis() {
566        let events = vec![
567            SpikeEvent::new(0, 0.0, 1.0, vec![0.0, 0.0]),
568            SpikeEvent::new(1, 1.0, 1.0, vec![1.0, 0.0]),
569            SpikeEvent::new(0, 2.0, 1.0, vec![0.0, 1.0]),
570            SpikeEvent::new(2, 3.0, 1.0, vec![1.0, 1.0]),
571        ];
572
573        let analysis = utils::analyze_spike_patterns(&events);
574        assert_eq!(analysis.total_spikes, 4);
575        assert_eq!(analysis.time_span, 3.0);
576        assert!(analysis.average_rate > 0.0);
577        assert_eq!(analysis.unique_neurons, 3);
578    }
579
580    #[test]
581    fn test_empty_spike_analysis() {
582        let events = Vec::new();
583        let analysis = utils::analyze_spike_patterns(&events);
584        assert_eq!(analysis.total_spikes, 0);
585        assert_eq!(analysis.time_span, 0.0);
586        assert_eq!(analysis.average_rate, 0.0);
587    }
588}