use super::Interface;
use ternary_signal::Polarity;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Nuclei {
pub soma_size: u8,
pub axon_affinity: u8,
pub myelin_affinity: u8,
pub metabolic_rate: u8,
pub leak: u8,
pub refractory: u32,
pub oscillation_period: u32,
pub interface: Interface,
pub polarity: Polarity,
}
impl Nuclei {
#[inline]
pub const fn new(
soma_size: u8,
axon_affinity: u8,
myelin_affinity: u8,
metabolic_rate: u8,
leak: u8,
refractory: u32,
oscillation_period: u32,
interface: Interface,
polarity: Polarity,
) -> Self {
Self {
soma_size,
axon_affinity,
myelin_affinity,
metabolic_rate,
leak,
refractory,
oscillation_period,
interface,
polarity,
}
}
pub const fn pyramidal() -> Self {
Self {
soma_size: 200,
axon_affinity: 200,
myelin_affinity: 180,
metabolic_rate: 100,
leak: 80,
refractory: 2000,
oscillation_period: 0,
interface: Interface::none(),
polarity: Polarity::Positive,
}
}
pub const fn interneuron() -> Self {
Self {
soma_size: 80,
axon_affinity: 40,
myelin_affinity: 20,
metabolic_rate: 60,
leak: 200, refractory: 500, oscillation_period: 0,
interface: Interface::none(),
polarity: Polarity::Negative,
}
}
pub const fn memory(bank_id: u16) -> Self {
Self {
soma_size: 120,
axon_affinity: 100,
myelin_affinity: 100,
metabolic_rate: 80,
leak: 100,
refractory: 1500,
oscillation_period: 0,
interface: Interface::memory(bank_id),
polarity: Polarity::Positive,
}
}
pub const fn sensory(channel: u16, modality: u8) -> Self {
Self {
soma_size: 100,
axon_affinity: 150,
myelin_affinity: 120,
metabolic_rate: 90,
leak: 120,
refractory: 1000,
oscillation_period: 0,
interface: Interface::sensory(channel, modality),
polarity: Polarity::Positive,
}
}
pub const fn auditory(channel: u16) -> Self {
Self::sensory(channel, Interface::MODALITY_AUDITORY)
}
pub const fn visual(channel: u16) -> Self {
Self::sensory(channel, Interface::MODALITY_VISUAL)
}
pub const fn motor(channel: u16, modality: u8) -> Self {
Self {
soma_size: 180,
axon_affinity: 220,
myelin_affinity: 200,
metabolic_rate: 110,
leak: 70,
refractory: 2000,
oscillation_period: 0,
interface: Interface::motor(channel, modality),
polarity: Polarity::Positive,
}
}
pub const fn oscillator(period_us: u32) -> Self {
Self {
soma_size: 100,
axon_affinity: 150,
myelin_affinity: 150,
metabolic_rate: 120, leak: 60,
refractory: 1000,
oscillation_period: period_us,
interface: Interface::none(),
polarity: Polarity::Positive,
}
}
pub const fn modulator(chemical_id: u8) -> Self {
Self {
soma_size: 90,
axon_affinity: 80,
myelin_affinity: 40,
metabolic_rate: 70,
leak: 100,
refractory: 3000,
oscillation_period: 0,
interface: Interface::chemical(chemical_id),
polarity: Polarity::Zero, }
}
pub const fn relay() -> Self {
Self {
soma_size: 140,
axon_affinity: 180,
myelin_affinity: 220, metabolic_rate: 50, leak: 150,
refractory: 800,
oscillation_period: 0,
interface: Interface::none(),
polarity: Polarity::Positive,
}
}
pub const fn gate() -> Self {
Self {
soma_size: 100,
axon_affinity: 100,
myelin_affinity: 100,
metabolic_rate: 80,
leak: 220, refractory: 1200,
oscillation_period: 0,
interface: Interface::none(),
polarity: Polarity::Positive,
}
}
#[inline]
pub const fn is_oscillator(&self) -> bool {
self.oscillation_period > 0
}
#[inline]
pub const fn is_sensory(&self) -> bool {
self.interface.is_sensory()
}
#[inline]
pub const fn is_motor(&self) -> bool {
self.interface.is_motor()
}
#[inline]
pub const fn is_memory(&self) -> bool {
self.interface.is_memory()
}
#[inline]
pub const fn is_internal(&self) -> bool {
!self.interface.is_external()
}
#[inline]
pub const fn is_excitatory(&self) -> bool {
matches!(self.polarity, Polarity::Positive)
}
#[inline]
pub const fn is_inhibitory(&self) -> bool {
matches!(self.polarity, Polarity::Negative)
}
#[inline]
pub const fn max_dendrite_connections(&self) -> u16 {
10 + (self.soma_size as u16 * 2)
}
#[inline]
pub fn max_axon_length(&self) -> f32 {
let affinity_factor = self.axon_affinity as f32 / 255.0;
let metabolic_factor = 1.0 - (self.metabolic_rate as f32 / 510.0); affinity_factor * metabolic_factor * 20.0 }
#[inline]
pub fn conduction_velocity(&self) -> f32 {
0.2 + (self.myelin_affinity as f32 / 255.0) * 0.8
}
#[inline]
pub const fn leak_tau_us(&self) -> u32 {
100_000 - (self.leak as u32 * 390)
}
}
impl Default for Nuclei {
fn default() -> Self {
Self::pyramidal()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_factory_presets() {
let pyr = Nuclei::pyramidal();
assert!(pyr.is_excitatory());
assert!(pyr.is_internal());
let inter = Nuclei::interneuron();
assert!(inter.is_inhibitory());
let osc = Nuclei::oscillator(1000);
assert!(osc.is_oscillator());
let mem = Nuclei::memory(0);
assert!(mem.is_memory());
let sens = Nuclei::auditory(0);
assert!(sens.is_sensory());
let mot = Nuclei::motor(0, 1);
assert!(mot.is_motor());
}
#[test]
fn test_derived_properties() {
let pyr = Nuclei::pyramidal();
assert!(pyr.max_dendrite_connections() > 100);
assert!(pyr.max_axon_length() > 5.0);
assert!(pyr.conduction_velocity() > 0.5);
}
#[test]
fn test_leak_tau() {
let fast_leak = Nuclei::interneuron();
let slow_leak = Nuclei::pyramidal();
assert!(fast_leak.leak_tau_us() < slow_leak.leak_tau_us());
}
}