<commit_before>use {Delay, Network, NeuronId, Num, SynapseId, Timestep};

// XXX: Make configurable
const STDP_FIRE_RESET: Num = 0.1;
const STDP_DECAY: Num = 0.95;

pub struct Simulator {
    current_time_step: Timestep,

    // We use a cyclic buffer with (time_step % max_delay) as index into the futures_spike array
    future_spikes: Vec<Vec<SynapseId>>,
}

// NOTE: This must be a power of two
const MAX_DELAY: usize = 64;

#[inline(always)]
fn timeslot(at: Timestep) -> usize {
    (at & (MAX_DELAY - 1)) as usize
}

#[inline(always)]
fn timeslot_in_future(at: Timestep, delay: Delay) -> usize {
    timeslot(at + delay as usize)
}

impl Simulator {
    pub fn new(max_delay: usize) -> Simulator {
        assert!(max_delay < MAX_DELAY);
        Simulator {
            current_time_step: 0,
            future_spikes: (0..MAX_DELAY).map(|_| Vec::new()).collect(),
        }
    }

    pub fn current_time_step(&self) -> Timestep {
        self.current_time_step
    }

    /// External input currents have to be set manually by calling `set_external_input`.

    pub fn step<F>(&mut self, network: &mut Network, fired_callback: &mut F)
    where
        F: FnMut(NeuronId, Timestep),
    {
        let time_step = self.current_time_step;

        // Clear all input currents
        network.reset_all_input_currents();

        // get all synapse input
        {
            let spikes = &mut self.future_spikes[timeslot(time_step)];
            network.process_firing_synapses(spikes);
            spikes.clear();
        }

        network.update_state(
            STDP_FIRE_RESET,
            STDP_DECAY,
            &mut |syn_id, delay| {
                self.future_spikes[timeslot_in_future(time_step, delay)].push(syn_id);
            },
            &mut |neuron_id| {
                fired_callback(neuron_id, time_step);
            },
        );

        self.current_time_step += 1;
    }
}<commit_msg>Get rid of constant MAX_DELAY. This is now being determined at Simulator startup time.<commit_after>use {Delay, Network, NeuronId, Num, SynapseId, Timestep};

// XXX: Make configurable
const STDP_FIRE_RESET: Num = 0.1;
const STDP_DECAY: Num = 0.95;

pub struct Simulator {
    current_time_step: Timestep,

    // We use a cyclic buffer with (time_step % max_delay) as index into the futures_spike array
    future_spikes: Vec<Vec<SynapseId>>,

    /// The next power of two of `max_delay` - 1. This is used as
    /// bit-wise AND mask, to avoid using the expensive modulo (%)
    /// operator.
    max_delay_bitwise_and_mask: usize,
}

impl Simulator {
    pub fn new(max_delay: usize) -> Simulator {
        assert!(max_delay > 1);
        let next_power_of_two = max_delay.checked_next_power_of_two().unwrap();
        assert!(next_power_of_two >= max_delay);
        let max_delay_bitwise_and_mask = next_power_of_two - 1;

        Simulator {
            current_time_step: 0,
            future_spikes: (0..next_power_of_two).map(|_| Vec::new()).collect(),
            max_delay_bitwise_and_mask,
        }
    }

    #[inline(always)]
    fn timeslot(&self, at: Timestep) -> usize {
        (at as usize) & self.max_delay_bitwise_and_mask
    }

    #[inline(always)]
    fn timeslot_in_future(&self, at: Timestep, delay: Delay) -> usize {
        self.timeslot(at + delay as usize)
    }

    pub fn current_time_step(&self) -> Timestep {
        self.current_time_step
    }

    /// External input currents have to be set manually by calling `set_external_input`.

    pub fn step<F>(&mut self, network: &mut Network, fired_callback: &mut F)
    where
        F: FnMut(NeuronId, Timestep),
    {
        let time_step = self.current_time_step;

        // Clear all input currents
        network.reset_all_input_currents();

        // get all synapse input
        {
            let idx = self.timeslot(time_step);
            let spikes = &mut self.future_spikes[idx];
            network.process_firing_synapses(spikes);
            spikes.clear();
        }

        network.update_state(
            STDP_FIRE_RESET,
            STDP_DECAY,
            &mut |syn_id, delay| {
                let idx = self.timeslot_in_future(time_step, delay);
                self.future_spikes[idx].push(syn_id);
            },
            &mut |neuron_id| {
                fired_callback(neuron_id, time_step);
            },
        );

        self.current_time_step += 1;
    }
}
{'fraction_non_alphanumeric': 0.10617059891107078, 'fraction_numerical': 0.004990925589836661, 'mean_word_length': 2.3175319789315276, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2799702', 'n_tokens_mistral': 1475, 'n_tokens_neox': 1429, 'n_words': 340}