Skip to content

4.1 ChannelRouter and RouterConfig

Raul Cardenas Montoya edited this page Sep 19, 2026 · 1 revision

ChannelRouter and RouterConfig

Relevant source files

The following files were used as context for generating this wiki page:

Purpose and Scope

This section covers the optional, domain-agnostic sparse routing subsystem implemented in src/router.rs. The channel router integrates signal pulses across a bank of neuromodulatory neurons to produce a sparse routing mask. It supports adaptive neuromodulatory routing where channels strengthen with use via dopamine-gated mechanisms and weaken when idle using use-it-or-lose-it plasticity.

The core components detailed herein include RouterConfig parameter validation, the NeuromodNeuron integration primitive, the ChannelRouter struct, and the execution pipelines for route and route_modulated operations, including fatigue and plasticity tracking.

Sources: [src/router.rs:1-178]()


1. Configuration Validation and Limits (RouterConfig)

The RouterConfig struct governs the initialization parameters for a ChannelRouter. Direct struct instantiation can yield out-of-range values, so validation is strictly enforced via RouterConfig::validate and construction methods like ChannelRouter::try_with_config.

Validation Bounds and Hard Limits

  • MAX_ROUTER_CHANNELS: Set to 1024. It caps the dense N × N weight matrix and baseline copy sizes.
  • MAX_ROUTING_TIMESTEPS: Set to 4096. It restricts the time complexity of the routing loop (O(timesteps × channel_count)).
  • channel_count: Must fall within 1..=MAX_ROUTER_CHANNELS.
  • Weights (self_weight, cross_weight, threshold): Must be finite; signed weights are explicitly permitted (e.g., negative cross_weight for lateral inhibition).
  • Rates and factors (leak, min_fire_rate, plasticity_decay, plasticity_speed, fatigue_accumulation, fatigue_recovery): Must be finite and bounded within 0.0..=1.0.
  • plasticity_potentiate: Must be finite and >= 0.0.
graph TD
    UserConfig["RouterConfig Struct Literal"] --> ValidateFn["RouterConfig::validate()"]
    ValidateFn --> CheckChannels["Check channel_count <= MAX_ROUTER_CHANNELS"]
    ValidateFn --> CheckSteps["Check routing_timesteps <= MAX_ROUTING_TIMESTEPS"]
    ValidateFn --> CheckFinite["Check finite ranges for weights and rates"]
    CheckChannels --> Valid["Valid Router Configuration"]
    CheckSteps --> Valid
    CheckFinite --> Valid
    CheckChannels -- "Exceeds 1024" --> Error["MeshError::InvalidConfig"]
    CheckSteps -- "Exceeds 4096" --> Error
    CheckFinite -- "NaN / Inf / Out-of-Bounds" --> Error
Loading

Sources: [src/router.rs:27-39](), [src/router.rs:121-178]()


2. Neuromodulatory Integration Primitive (NeuromodNeuron)

NeuromodNeuron is a router-internal integration primitive rather than a general-purpose canonical neuron model (such as LIF or Izhikevich, which reside in external crates). It updates membrane potentials according to a discrete-time leaky integration equation scaled by a neuromodulatory gain factor.

Membrane Potential Dynamics

The membrane potential $V$ evolves per timestep according to:

$$V_{t+1} = V_t + (G \cdot I_{syn}) - \lambda(V_t - V_{rest})$$

Where:

  • $G$ is the neuromodulatory gain (NeuromodNeuron::gain).
  • $I_{syn}$ is the incoming stimulus.
  • $\lambda$ is the passive leak rate (NeuromodNeuron::leak).
  • $V_{rest}$ is the resting potential (NeuromodNeuron::v_rest).
graph TD
    InputStimulus["Input Stimulus (I_syn)"] --> IntegrateMethod["NeuromodNeuron::integrate()"]
    GainScale["NeuromodNeuron::gain"] --> IntegrateMethod
    MembranePot["NeuromodNeuron::v"] --> IntegrateMethod
    LeakRate["NeuromodNeuron::leak"] --> IntegrateMethod
    RestPot["NeuromodNeuron::v_rest"] --> IntegrateMethod
    IntegrateMethod --> UpdateV["V_t+1 = V_t + (G * I_syn) - leak * (V_t - V_rest)"]
    UpdateV --> CheckFireMethod["NeuromodNeuron::check_fire()"]
    CheckFireMethod --> ThresholdTest{"V >= threshold?"}
    ThresholdTest -- "Yes" --> Fire["Spike Fired: Reset V to v_reset, set last_spike = true"]
    ThresholdTest -- "No" --> NoFire["No Spike: set last_spike = false"]
Loading

Sources: [src/router.rs:40-119]()


3. Routing Pipeline and Plasticity (route / route_modulated)

The ChannelRouter executes multi-timestep routing sweeps using route and route_modulated. The pipeline converts incoming pulse vectors into activation masks over several integration timesteps, evaluating firing rates against MIN_FIRE_RATE and updating synaptic weights via use-it-or-lose-it decay and dopamine-gated potentiation.

Pipeline Execution Steps

  1. Input Injection: Incoming channel pulses are mapped into the internal NeuromodNeuron bank.
  2. Timestep Integration: For routing_timesteps (defaulting to ROUTING_TIMESTEPS = 16), neurons integrate lateral and self-weights.
  3. Firing Rate Evaluation: Spikes are counted per channel and checked against MIN_FIRE_RATE (0.1875).
  4. Plasticity Adaptation: Weights are updated via decay towards baseline for idle channels and potentiation for active channels.
  5. Fatigue Updates: Fatigue variables (fatigue_accumulation and fatigue_recovery) modify subsequent excitability to prevent channel saturation.
graph TD
    InputData["Input Pulses / Signals"] --> RouteFn["ChannelRouter::route() or route_modulated()"]
    RouteFn --> LoopTimesteps["Iterate routing_timesteps (O(T * N))"]
    LoopTimesteps --> NeuronIntegrate["NeuromodNeuron::integrate()"]
    NeuronIntegrate --> NeuronCheck["NeuromodNeuron::check_fire()"]
    NeuronCheck --> CountSpikes["Accumulate Spikes per Channel"]
    CountSpikes --> RateCheck{"Firing Rate >= MIN_FIRE_RATE?"}
    RateCheck -- "Active" --> Potentiate["Plasticity Potentiate (Dopamine-gated)"]
    RateCheck -- "Idle" --> Decay["Plasticity Decay (Use-it-or-lose-it)"]
    Potentiate --> ApplyFatigue["Update Fatigue Accumulation/Recovery"]
    Decay --> ApplyFatigue
    ApplyFatigue --> OutputMask["Return Sparse Routing Mask / Vec<bool>"]
Loading

Sources: [src/router.rs:21-39](), [src/router.rs:121-178]()

Clone this wiki locally