Skip to main content

optirs_core/neuromorphic/
mod.rs

1// Neuromorphic Computing Optimization
2//
3// This module implements optimization algorithms specifically designed for neuromorphic
4// computing platforms, including spike-based optimization, event-driven parameter updates,
5// and energy-efficient optimization strategies for neuromorphic chips.
6
7use scirs2_core::numeric::Float;
8use std::fmt::Debug;
9use std::time::Duration;
10
11pub mod energy_efficient;
12pub mod event_driven;
13pub mod spike_based;
14
15/// Convert an `f64` literal/derived value to a generic float type,
16/// falling back to `fallback` when the numeric type cannot represent it.
17/// Defensive only: always succeeds for the `f32`/`f64` types this crate
18/// targets. Shared by the neuromorphic submodules so none of them need a
19/// bare `.expect(...)` on a numeric-literal conversion.
20pub(crate) fn to_generic_or<F: Float>(value: f64, fallback: F) -> F {
21    F::from(value).unwrap_or(fallback)
22}
23
24// Re-export key types
25pub use energy_efficient::{EnergyBudget, EnergyEfficientOptimizer, EnergyOptimizationStrategy};
26pub use event_driven::{EventDrivenConfig, EventDrivenOptimizer, EventType};
27pub use spike_based::{SpikeTrainOptimizer, SpikingConfig, SpikingOptimizer};
28
29/// Neuromorphic computing platform types
30#[derive(Debug, Clone)]
31pub enum NeuromorphicPlatform {
32    /// Intel Loihi neuromorphic chip
33    IntelLoihi,
34
35    /// SpiNNaker platform
36    SpiNNaker,
37
38    /// IBM TrueNorth
39    IBMTrueNorth,
40
41    /// BrainChip Akida
42    BrainChipAkida,
43
44    /// University research platforms
45    Research,
46
47    /// Custom neuromorphic hardware
48    Custom(String),
49}
50
51/// Neuromorphic optimization configuration
52#[derive(Debug, Clone)]
53pub struct NeuromorphicConfig<T: Float + Debug + Send + Sync + 'static> {
54    /// Target neuromorphic platform
55    pub platform: NeuromorphicPlatform,
56
57    /// Spike-based optimization settings
58    pub spike_config: SpikingConfig<T>,
59
60    /// Event-driven optimization settings
61    pub event_config: EventDrivenConfig<T>,
62
63    /// Energy optimization settings
64    pub energy_config: EnergyOptimizationConfig<T>,
65
66    /// Enable temporal coding
67    pub temporal_coding: bool,
68
69    /// Enable rate coding
70    pub rate_coding: bool,
71
72    /// Spike timing dependent plasticity (STDP) parameters
73    pub stdp_config: STDPConfig<T>,
74
75    /// Membrane potential dynamics
76    pub membrane_dynamics: MembraneDynamicsConfig<T>,
77
78    /// Synaptic plasticity model
79    pub plasticity_model: PlasticityModel,
80
81    /// Enable homeostatic mechanisms
82    pub homeostatic_plasticity: bool,
83
84    /// Enable metaplasticity
85    pub metaplasticity: bool,
86
87    /// Population dynamics configuration
88    pub population_config: PopulationConfig,
89}
90
91/// Spike Timing Dependent Plasticity configuration
92#[derive(Debug, Clone)]
93pub struct STDPConfig<T: Float + Debug + Send + Sync + 'static> {
94    /// Learning rate for potentiation
95    pub learning_rate_pot: T,
96
97    /// Learning rate for depression
98    pub learning_rate_dep: T,
99
100    /// Time constant for potentiation (ms)
101    pub tau_pot: T,
102
103    /// Time constant for depression (ms)
104    pub tau_dep: T,
105
106    /// Maximum weight value
107    pub weight_max: T,
108
109    /// Minimum weight value
110    pub weight_min: T,
111
112    /// Enable triplet STDP
113    pub enable_triplet: bool,
114
115    /// Triplet learning rate
116    pub triplet_learning_rate: T,
117}
118
119/// Membrane potential dynamics configuration
120#[derive(Debug, Clone)]
121pub struct MembraneDynamicsConfig<T: Float + Debug + Send + Sync + 'static> {
122    /// Membrane time constant (ms)
123    pub tau_membrane: T,
124
125    /// Resting potential (mV)
126    pub resting_potential: T,
127
128    /// Threshold potential (mV)
129    pub threshold_potential: T,
130
131    /// Reset potential (mV)
132    pub reset_potential: T,
133
134    /// Refractory period (ms)
135    pub refractory_period: T,
136
137    /// Capacitance (pF)
138    pub capacitance: T,
139
140    /// Leak conductance (nS)
141    pub leak_conductance: T,
142
143    /// Enable adaptive threshold
144    pub adaptive_threshold: bool,
145
146    /// Threshold adaptation time constant
147    pub threshold_adaptation_tau: T,
148}
149
150/// Synaptic plasticity models
151#[derive(Debug, Clone, Copy)]
152pub enum PlasticityModel {
153    /// Hebbian plasticity
154    Hebbian,
155
156    /// Anti-Hebbian plasticity
157    AntiHebbian,
158
159    /// Spike Timing Dependent Plasticity
160    STDP,
161
162    /// Triplet STDP
163    TripletSTDP,
164
165    /// Voltage-dependent plasticity
166    VoltageDependentSTDP,
167
168    /// Calcium-based plasticity
169    CalciumBased,
170
171    /// BCM (Bienenstock-Cooper-Munro) rule
172    BCM,
173
174    /// Oja's rule
175    Oja,
176}
177
178/// Population-level configuration
179#[derive(Debug, Clone)]
180pub struct PopulationConfig {
181    /// Population size
182    pub population_size: usize,
183
184    /// Enable lateral inhibition
185    pub lateral_inhibition: bool,
186
187    /// Inhibition strength
188    pub inhibition_strength: f64,
189
190    /// Enable winner-take-all dynamics
191    pub winner_take_all: bool,
192
193    /// Population coding strategy
194    pub coding_strategy: PopulationCodingStrategy,
195
196    /// Enable population bursting
197    pub enable_bursting: bool,
198
199    /// Synchronization mechanisms
200    pub synchronization: SynchronizationMechanism,
201}
202
203/// Population coding strategies
204#[derive(Debug, Clone, Copy)]
205pub enum PopulationCodingStrategy {
206    /// Distributed coding
207    Distributed,
208
209    /// Sparse coding
210    Sparse,
211
212    /// Local coding
213    Local,
214
215    /// Vector coding
216    Vector,
217
218    /// Rank order coding
219    RankOrder,
220}
221
222/// Synchronization mechanisms
223#[derive(Debug, Clone, Copy)]
224pub enum SynchronizationMechanism {
225    /// No synchronization
226    None,
227
228    /// Global clock
229    GlobalClock,
230
231    /// Phase-locked loops
232    PhaseLocked,
233
234    /// Adaptive synchronization
235    Adaptive,
236
237    /// Network oscillations
238    NetworkOscillations,
239}
240
241/// Energy optimization configuration
242#[derive(Debug, Clone)]
243pub struct EnergyOptimizationConfig<T: Float + Debug + Send + Sync + 'static> {
244    /// Energy budget (nJ per operation)
245    pub energy_budget: T,
246
247    /// Energy optimization strategy
248    pub strategy: EnergyOptimizationStrategy,
249
250    /// Enable dynamic voltage scaling
251    pub dynamic_voltage_scaling: bool,
252
253    /// Enable clock gating
254    pub clock_gating: bool,
255
256    /// Enable power gating
257    pub power_gating: bool,
258
259    /// Sleep mode configuration
260    pub sleep_mode_config: SleepModeConfig<T>,
261
262    /// Energy monitoring frequency
263    pub monitoring_frequency: Duration,
264
265    /// Thermal management
266    pub thermal_management: ThermalManagementConfig<T>,
267}
268
269/// Sleep mode configuration for energy efficiency
270#[derive(Debug, Clone)]
271pub struct SleepModeConfig<T: Float + Debug + Send + Sync + 'static> {
272    /// Enable sleep mode
273    pub enable_sleep_mode: bool,
274
275    /// Sleep threshold (inactivity time)
276    pub sleep_threshold: Duration,
277
278    /// Wake-up time (ms)
279    pub wakeup_time: T,
280
281    /// Sleep energy consumption (nW)
282    pub sleep_power: T,
283
284    /// Wake-up energy cost (nJ)
285    pub wakeup_energy: T,
286}
287
288/// Thermal management configuration
289#[derive(Debug, Clone)]
290pub struct ThermalManagementConfig<T: Float + Debug + Send + Sync + 'static> {
291    /// Enable thermal management
292    pub enable_thermal_management: bool,
293
294    /// Target temperature (°C)
295    pub target_temperature: T,
296
297    /// Maximum temperature (°C)
298    pub max_temperature: T,
299
300    /// Thermal time constant (s)
301    pub thermal_time_constant: T,
302
303    /// Thermal throttling strategy
304    pub throttling_strategy: ThermalThrottlingStrategy,
305}
306
307/// Thermal throttling strategies
308#[derive(Debug, Clone, Copy)]
309pub enum ThermalThrottlingStrategy {
310    /// Frequency scaling
311    FrequencyScaling,
312
313    /// Voltage scaling
314    VoltageScaling,
315
316    /// Activity reduction
317    ActivityReduction,
318
319    /// Selective shutdown
320    SelectiveShutdown,
321
322    /// Dynamic load balancing
323    DynamicLoadBalancing,
324}
325
326/// Spike representation for neuromorphic optimization
327#[derive(Debug, Clone)]
328pub struct Spike<T: Float + Debug + Send + Sync + 'static> {
329    /// Neuron ID
330    pub neuron_id: usize,
331
332    /// Spike time (ms)
333    pub time: T,
334
335    /// Spike amplitude (mV)
336    pub amplitude: T,
337
338    /// Spike width (ms)
339    pub width: Option<T>,
340
341    /// Associated synapse weight
342    pub weight: T,
343
344    /// Presynaptic neuron ID
345    pub presynaptic_id: Option<usize>,
346
347    /// Postsynaptic neuron ID
348    pub postsynaptic_id: Option<usize>,
349}
350
351/// Spike train representation
352#[derive(Debug, Clone)]
353pub struct SpikeTrain<T: Float + Debug + Send + Sync + 'static> {
354    /// Neuron ID
355    pub neuron_id: usize,
356
357    /// Spike times
358    pub spike_times: Vec<T>,
359
360    /// Inter-spike intervals
361    pub inter_spike_intervals: Vec<T>,
362
363    /// Firing rate (Hz)
364    pub firing_rate: T,
365
366    /// Spike train duration (ms)
367    pub duration: T,
368
369    /// Spike count
370    pub spike_count: usize,
371}
372
373impl<T: Float + Debug + Send + Sync + 'static + std::iter::Sum> SpikeTrain<T> {
374    /// Create a new spike train from spike times
375    pub fn new(neuron_id: usize, spike_times: Vec<T>) -> Self {
376        let spike_count = spike_times.len();
377        let duration = if spike_count > 0 {
378            spike_times[spike_count - 1] - spike_times[0]
379        } else {
380            T::zero()
381        };
382
383        let firing_rate = if duration > T::zero() {
384            T::from(spike_count).unwrap_or_else(|| T::zero())
385                / (duration / T::from(1000.0).unwrap_or_else(|| T::zero()))
386        } else {
387            T::zero()
388        };
389
390        let inter_spike_intervals = if spike_count > 1 {
391            spike_times.windows(2).map(|w| w[1] - w[0]).collect()
392        } else {
393            Vec::new()
394        };
395
396        Self {
397            neuron_id,
398            spike_times,
399            inter_spike_intervals,
400            firing_rate,
401            duration,
402            spike_count,
403        }
404    }
405
406    /// Calculate coefficient of variation of inter-spike intervals
407    pub fn coefficient_of_variation(&self) -> T {
408        if self.inter_spike_intervals.len() < 2 {
409            return T::zero();
410        }
411
412        let count = to_generic_or(self.inter_spike_intervals.len() as f64, T::one());
413        let mean = self.inter_spike_intervals.iter().cloned().sum::<T>() / count;
414
415        let variance = self
416            .inter_spike_intervals
417            .iter()
418            .map(|&isi| (isi - mean) * (isi - mean))
419            .sum::<T>()
420            / count;
421
422        if mean == T::zero() {
423            return T::zero();
424        }
425        variance.sqrt() / mean
426    }
427
428    /// Calculate local variation measure
429    pub fn local_variation(&self) -> T {
430        if self.inter_spike_intervals.len() < 2 {
431            return T::zero();
432        }
433
434        let mut lv_sum = T::zero();
435        for window in self.inter_spike_intervals.windows(2) {
436            let isi1 = window[0];
437            let isi2 = window[1];
438            let diff = isi1 - isi2;
439            let sum = isi1 + isi2;
440
441            if sum > T::zero() {
442                lv_sum = lv_sum + (diff * diff) / (sum * sum);
443            }
444        }
445
446        let three = to_generic_or(3.0, T::one());
447        let denom = to_generic_or((self.inter_spike_intervals.len() - 1) as f64, T::one());
448        three * lv_sum / denom
449    }
450
451    /// Append a new spike at `time` and recompute `duration`, `firing_rate`
452    /// and `inter_spike_intervals` from the updated spike history (F51).
453    ///
454    /// Previously callers pushed directly onto `spike_times`/`spike_count`
455    /// without ever recomputing `firing_rate`, so homeostatic scaling (and
456    /// anything else reading `firing_rate`) always saw a permanently stale
457    /// value (0.0 for a train built from a single initial spike). This
458    /// mirrors [`Self::new`]'s math incrementally.
459    pub fn record_spike(&mut self, time: T) {
460        if let Some(&last) = self.spike_times.last() {
461            self.inter_spike_intervals.push(time - last);
462        }
463        self.spike_times.push(time);
464        self.spike_count += 1;
465
466        self.duration = if self.spike_count > 1 {
467            self.spike_times[self.spike_count - 1] - self.spike_times[0]
468        } else {
469            T::zero()
470        };
471
472        self.firing_rate = if self.duration > T::zero() {
473            to_generic_or(self.spike_count as f64, T::zero())
474                / (self.duration / to_generic_or(1000.0, T::one()))
475        } else {
476            T::zero()
477        };
478    }
479}
480
481/// Event-driven update representation
482#[derive(Debug, Clone)]
483pub struct NeuromorphicEvent<T: Float + Debug + Send + Sync + 'static> {
484    /// Event type
485    pub event_type: EventType,
486
487    /// Event timestamp
488    pub timestamp: T,
489
490    /// Source neuron
491    pub source_neuron: usize,
492
493    /// Target neuron
494    pub target_neuron: Option<usize>,
495
496    /// Event value/weight
497    pub value: T,
498
499    /// Energy cost of processing this event
500    pub energy_cost: T,
501
502    /// Priority level
503    pub priority: EventPriority,
504}
505
506/// Event priority levels for neuromorphic processing
507#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
508pub enum EventPriority {
509    Low,
510    Normal,
511    High,
512    Critical,
513    RealTime,
514}
515
516/// Neuromorphic optimization metrics
517#[derive(Debug, Clone)]
518pub struct NeuromorphicMetrics<T: Float + Debug + Send + Sync + 'static> {
519    /// Total spikes processed
520    pub total_spikes: usize,
521
522    /// Average firing rate (Hz)
523    pub average_firing_rate: T,
524
525    /// Energy consumption (nJ)
526    pub energy_consumption: T,
527
528    /// Power consumption (nW)
529    pub power_consumption: T,
530
531    /// Spike timing precision (ms)
532    pub timing_precision: T,
533
534    /// Synaptic operations per second
535    pub synaptic_ops_per_sec: T,
536
537    /// Plasticity events per second
538    pub plasticity_events_per_sec: T,
539
540    /// Memory bandwidth utilization
541    pub memory_bandwidth_utilization: T,
542
543    /// Thermal efficiency score
544    pub thermal_efficiency: T,
545
546    /// Network synchronization measure
547    pub network_synchronization: T,
548}
549
550impl<T: Float + Debug + Send + Sync + 'static> Default for NeuromorphicMetrics<T> {
551    fn default() -> Self {
552        Self {
553            total_spikes: 0,
554            average_firing_rate: T::zero(),
555            energy_consumption: T::zero(),
556            power_consumption: T::zero(),
557            timing_precision: T::from(0.1).unwrap_or_else(|| T::zero()), // 0.1ms default
558            synaptic_ops_per_sec: T::zero(),
559            plasticity_events_per_sec: T::zero(),
560            memory_bandwidth_utilization: T::zero(),
561            thermal_efficiency: T::one(),
562            network_synchronization: T::zero(),
563        }
564    }
565}
566
567impl<T: Float + Debug + Send + Sync + 'static> Default for NeuromorphicConfig<T> {
568    fn default() -> Self {
569        Self {
570            platform: NeuromorphicPlatform::IntelLoihi,
571            spike_config: SpikingConfig::default(),
572            event_config: EventDrivenConfig::default(),
573            energy_config: EnergyOptimizationConfig::default(),
574            temporal_coding: true,
575            rate_coding: false,
576            stdp_config: STDPConfig::default(),
577            membrane_dynamics: MembraneDynamicsConfig::default(),
578            plasticity_model: PlasticityModel::STDP,
579            homeostatic_plasticity: false,
580            metaplasticity: false,
581            population_config: PopulationConfig::default(),
582        }
583    }
584}
585
586impl<T: Float + Debug + Send + Sync + 'static> Default for STDPConfig<T> {
587    fn default() -> Self {
588        Self {
589            learning_rate_pot: T::from(0.01).unwrap_or_else(|| T::zero()),
590            learning_rate_dep: T::from(0.01).unwrap_or_else(|| T::zero()),
591            tau_pot: T::from(20.0).unwrap_or_else(|| T::zero()),
592            tau_dep: T::from(20.0).unwrap_or_else(|| T::zero()),
593            weight_max: T::one(),
594            weight_min: T::zero(),
595            enable_triplet: false,
596            triplet_learning_rate: T::from(0.001).unwrap_or_else(|| T::zero()),
597        }
598    }
599}
600
601impl<T: Float + Debug + Send + Sync + 'static> Default for MembraneDynamicsConfig<T> {
602    fn default() -> Self {
603        Self {
604            tau_membrane: T::from(20.0).unwrap_or_else(|| T::zero()),
605            resting_potential: T::from(-70.0).unwrap_or_else(|| T::zero()),
606            threshold_potential: T::from(-55.0).unwrap_or_else(|| T::zero()),
607            reset_potential: T::from(-80.0).unwrap_or_else(|| T::zero()),
608            refractory_period: T::from(2.0).unwrap_or_else(|| T::zero()),
609            capacitance: T::from(100.0).unwrap_or_else(|| T::zero()),
610            leak_conductance: T::from(10.0).unwrap_or_else(|| T::zero()),
611            adaptive_threshold: false,
612            threshold_adaptation_tau: T::from(100.0).unwrap_or_else(|| T::zero()),
613        }
614    }
615}
616
617impl Default for PopulationConfig {
618    fn default() -> Self {
619        Self {
620            population_size: 1000,
621            lateral_inhibition: false,
622            inhibition_strength: 0.1,
623            winner_take_all: false,
624            coding_strategy: PopulationCodingStrategy::Distributed,
625            enable_bursting: false,
626            synchronization: SynchronizationMechanism::None,
627        }
628    }
629}
630
631impl<T: Float + Debug + Send + Sync + 'static> Default for EnergyOptimizationConfig<T> {
632    fn default() -> Self {
633        Self {
634            energy_budget: T::from(10.0).unwrap_or_else(|| T::zero()), // 10 nJ per operation
635            strategy: EnergyOptimizationStrategy::DynamicVoltageScaling,
636            dynamic_voltage_scaling: true,
637            clock_gating: true,
638            power_gating: false,
639            sleep_mode_config: SleepModeConfig::default(),
640            monitoring_frequency: Duration::from_millis(100),
641            thermal_management: ThermalManagementConfig::default(),
642        }
643    }
644}
645
646impl<T: Float + Debug + Send + Sync + 'static> Default for SleepModeConfig<T> {
647    fn default() -> Self {
648        Self {
649            enable_sleep_mode: true,
650            sleep_threshold: Duration::from_millis(100),
651            wakeup_time: T::from(1.0).unwrap_or_else(|| T::zero()),
652            sleep_power: T::from(0.1).unwrap_or_else(|| T::zero()),
653            wakeup_energy: T::from(0.01).unwrap_or_else(|| T::zero()),
654        }
655    }
656}
657
658impl<T: Float + Debug + Send + Sync + 'static> Default for ThermalManagementConfig<T> {
659    fn default() -> Self {
660        Self {
661            enable_thermal_management: true,
662            target_temperature: T::from(65.0).unwrap_or_else(|| T::zero()),
663            max_temperature: T::from(85.0).unwrap_or_else(|| T::zero()),
664            thermal_time_constant: T::from(10.0).unwrap_or_else(|| T::zero()),
665            throttling_strategy: ThermalThrottlingStrategy::FrequencyScaling,
666        }
667    }
668}