示例#1
0
 def initialize_gpu(self):
         # Select integration scheme according to method
         if self.method == 'Euler': scheme = euler_scheme
         elif self.method == 'RK': scheme = rk2_scheme
         elif self.method == 'exponential_Euler': scheme = exp_euler_scheme
         else: raise Exception("The numerical integration method is not valid")
         
         self.mf = GPUModelFitting(self.group, self.model, self.criterion_object,
                                   self.input_var, self.neurons/self.groups,
                                   self.onset, 
                                   statemonitor_var = self.statemonitor_var,
                                   spikemonitor = self.spikemonitor,
                                   nbr_spikes = self.nbr_spikes,
                                   duration = self.sliced_duration,
                                   precision=self.precision, scheme=scheme)
示例#2
0
class Simulator(object):
    def __init__(
            self,
            model,
            reset,
            threshold,
            inputs,
            input_var='I',
            dt=defaultclock.dt,
            refractory=0 * ms,
            max_refractory=None,
            spikes=None,
            traces=None,
            groups=1,
            slices=1,
            overlap=0 * second,
            onset=0 * second,
            neurons=1000,  # = nodesize = number of neurons on this node = total number of neurons/slices
            initial_values=None,
            unit_type='CPU',
            stepsize=100 * ms,
            precision='double',
            criterion=None,
            statemonitor_var=None,
            method='Euler'):
        self.model = model
        self.reset = reset
        self.threshold = threshold
        self.inputs = inputs
        self.input_var = input_var
        self.dt = dt
        self.refractory = refractory
        self.max_refractory = max_refractory
        self.spikes = spikes
        self.traces = traces
        self.initial_values = initial_values
        self.groups = groups
        self.slices = slices
        self.overlap = overlap
        self.onset = onset
        self.neurons = neurons
        self.unit_type = unit_type
        self.statemonitor_var = statemonitor_var
        self.stepsize = stepsize
        self.precision = precision
        self.criterion = criterion
        self.method = method
        self.use_gpu = self.unit_type == 'GPU'

        if self.statemonitor_var is not None:
            self.statemonitor_values = zeros(self.neurons)

        self.initialize_neurongroup()
        self.transform_data()
        self.inject_input()
        self.initialize_criterion(delays=zeros(self.neurons))

        if self.use_gpu:
            self.initialize_gpu()

    def initialize_neurongroup(self):
        # Add 'refractory' parameter on the CPU only
        if not self.use_gpu:
            if self.max_refractory is not None:
                refractory = 'refractory'
                self.model.add_param('refractory', second)
            else:
                refractory = self.refractory
        else:
            if self.max_refractory is not None:
                refractory = 0 * ms
            else:
                refractory = self.refractory

        # Must recompile the Equations : the functions are not transfered after pickling/unpickling
        self.model.compile_functions()

        self.group = NeuronGroup(self.neurons,
                                 model=self.model,
                                 reset=self.reset,
                                 threshold=self.threshold,
                                 refractory=refractory,
                                 max_refractory=self.max_refractory,
                                 method=self.method,
                                 clock=Clock(dt=self.dt))

        if self.initial_values is not None:
            for param, value in self.initial_values.iteritems():
                self.group.state(param)[:] = value

    def initialize_gpu(self):
        # Select integration scheme according to method
        if self.method == 'Euler': scheme = euler_scheme
        elif self.method == 'RK': scheme = rk2_scheme
        elif self.method == 'exponential_Euler': scheme = exp_euler_scheme
        else: raise Exception("The numerical integration method is not valid")

        self.mf = GPUModelFitting(self.group,
                                  self.model,
                                  self.criterion_object,
                                  self.input_var,
                                  self.onset,
                                  statemonitor_var=self.statemonitor_var,
                                  duration=self.sliced_duration,
                                  precision=self.precision,
                                  scheme=scheme)

    def transform_data(self):
        self.transformer = DataTransformer(self.neurons,
                                           self.inputs,
                                           spikes=self.spikes,
                                           traces=self.traces,
                                           dt=self.dt,
                                           slices=self.slices,
                                           overlap=self.overlap,
                                           groups=self.groups)
        self.total_steps = self.transformer.total_steps
        self.sliced_duration = self.transformer.sliced_duration

        self.sliced_inputs = self.transformer.slice_traces(self.inputs)
        self.inputs_inline, self.inputs_offset = self.transformer.transform_traces(
            self.sliced_inputs)

        if self.traces is not None:
            self.sliced_traces = self.transformer.slice_traces(self.traces)
            self.traces_inline, self.traces_offset = self.transformer.transform_traces(
                self.sliced_traces)
        else:
            self.sliced_traces, self.traces_inline, self.traces_offset = None, None, None

        if self.spikes is not None:
            self.sliced_spikes = self.transformer.slice_spikes(self.spikes)
            self.spikes_inline, self.spikes_offset = self.transformer.transform_spikes(
                self.sliced_spikes)
        else:
            self.sliced_spikes, self.spikes_inline, self.spikes_offset = None, None, None

    def inject_input(self):
        # Injects current in consecutive subgroups, where I_offset have the same value
        # on successive intervals
        I_offset = self.inputs_offset
        k = -1
        for i in hstack((nonzero(diff(I_offset))[0], len(I_offset) - 1)):
            I_offset_subgroup_value = I_offset[i]
            I_offset_subgroup_length = i - k
            sliced_subgroup = self.group.subgroup(I_offset_subgroup_length)
            input_sliced_values = self.inputs_inline[
                I_offset_subgroup_value:I_offset_subgroup_value +
                self.total_steps]
            sliced_subgroup.set_var_by_array(
                self.input_var,
                TimedArray(input_sliced_values, clock=self.group.clock))
            k = i

    def initialize_criterion(self, **criterion_params):
        # general criterion parameters
        params = dict(group=self.group,
                      traces=self.sliced_traces,
                      spikes=self.sliced_spikes,
                      targets_count=self.groups * self.slices,
                      duration=self.sliced_duration,
                      onset=self.onset,
                      spikes_inline=self.spikes_inline,
                      spikes_offset=self.spikes_offset,
                      traces_inline=self.traces_inline,
                      traces_offset=self.traces_offset)
        for key, val in criterion_params.iteritems():
            params[key] = val
        criterion_name = self.criterion.__class__.__name__

        # criterion-specific parameters
        if criterion_name == 'GammaFactor':
            params['delta'] = self.criterion.delta
            params[
                'coincidence_count_algorithm'] = self.criterion.coincidence_count_algorithm
            self.criterion_object = GammaFactorCriterion(**params)

        if criterion_name == 'LpError':
            params['p'] = self.criterion.p
            params['varname'] = self.criterion.varname
            self.criterion_object = LpErrorCriterion(**params)

    def update_neurongroup(self, **param_values):
        """
        Inject fitting parameters into the NeuronGroup
        """
        # Sets the parameter values in the NeuronGroup object
        self.group.reinit()
        for param, value in param_values.iteritems():
            self.group.state(param)[:] = kron(value, ones(
                self.slices))  # kron param_values if slicing

        # Reinitializes the model variables
        if self.initial_values is not None:
            for param, value in self.initial_values.iteritems():
                self.group.state(param)[:] = value

    def combine_sliced_values(self, values):
        if type(values) is tuple:
            combined_values = tuple(
                [sum(reshape(v, (self.slices, -1)), axis=0) for v in values])
        else:
            combined_values = sum(reshape(values, (self.slices, -1)), axis=0)
        return combined_values

    def run(self, **param_values):
        delays = param_values.pop('delays', zeros(self.neurons))
        refractory = param_values.pop('refractory', zeros(self.neurons))

        self.update_neurongroup(**param_values)

        # repeat spike delays and refractory to take slices into account
        delays = kron(delays, ones(self.slices))
        refractory = kron(refractory, ones(self.slices))

        # TODO: add here parameters to criterion_params if a criterion must use some parameters
        criterion_params = dict(delays=delays)

        self.update_neurongroup(**param_values)
        self.initialize_criterion(**criterion_params)

        if self.use_gpu:
            # Reinitializes the simulation object
            self.mf.reinit_vars(self.criterion_object, self.inputs_inline,
                                self.inputs_offset, self.spikes_inline,
                                self.spikes_offset, self.traces_inline,
                                self.traces_offset, delays, refractory)
            # LAUNCHES the simulation on the GPU
            self.mf.launch(self.sliced_duration, self.stepsize)
            # Synchronize the GPU values with a call to gpuarray.get()
            self.criterion_object.update_gpu_values()
        else:
            # set the refractory period
            if self.max_refractory is not None:
                self.group.refractory = refractory
            # Launch the simulation on the CPU
            self.group.clock.reinit()
            net = Network(self.group, self.criterion_object)
            if self.statemonitor_var is not None:
                self.statemonitor = StateMonitor(self.group,
                                                 self.statemonitor_var,
                                                 record=True)
                net.add(self.statemonitor)
            net.run(self.sliced_duration)

        sliced_values = self.criterion_object.get_values()
        combined_values = self.combine_sliced_values(sliced_values)
        values = self.criterion_object.normalize(combined_values)
        return values

    def get_statemonitor_values(self):
        if not self.use_gpu:
            return self.statemonitor.values
        else:
            return self.mf.get_statemonitor_values()
示例#3
0
class Simulator(object):
    def __init__(self, model, reset, threshold, 
                 inputs, input_var = 'I', dt = defaultclock.dt,
                 refractory = 0*ms, max_refractory = None,
                 spikes = None, traces = None,
                 groups = 1,
                 slices = 1, overlap = 0*second,
                 onset = 0*second,
                 neurons = 1000, # = nodesize = number of neurons on this node = (total number of neurons on this node)/(number of slices)
                 initial_values = None,
                 unit_type = 'CPU',
                 stepsize = 128*ms,
                 precision = 'double',
                 criterion = None,
                 statemonitor_var=None,
                 spikemonitor = False,
                 nbr_spikes = 200,
                 ntrials=1,
                 method = 'Euler',
#                 stand_alone=False,
#                 neuron_group=None,
#                 given_neuron_group=False
                 ):
#        print refractory, max_refractory
#        self.neuron_group = neuron_group
#        self.given_neuron_group = False
#        self.stand_alone = given_neuron_group
        self.model = model
        self.reset = reset
        self.threshold = threshold
        self.inputs = inputs
        self.input_var = input_var
        self.dt = dt
        self.refractory = refractory
        self.max_refractory = max_refractory
        self.spikes = spikes
        self.traces = traces
        self.initial_values = initial_values 
        self.groups = groups
        self.slices = slices
        self.overlap = overlap
        self.ntrials=ntrials
        self.onset = onset
        self.neurons = neurons
        self.unit_type = unit_type
        if type(statemonitor_var) is not list and statemonitor_var is not None:
            statemonitor_var = [statemonitor_var]
        self.statemonitor_var = statemonitor_var
        self.spikemonitor=spikemonitor
        self.nbr_spikes = nbr_spikes
        self.stepsize = stepsize
        self.precision = precision
        self.criterion = criterion
        self.method = method
        self.use_gpu = self.unit_type=='GPU'
        
        if self.statemonitor_var is not None:
            self.statemonitor_values = [zeros(self.neurons)]*len(statemonitor_var)
        
        self.initialize_neurongroup()
        self.transform_data()
        self.inject_input()
        if self.criterion.__class__.__name__ == 'Brette':
            self.initialize_criterion(delays=zeros(self.neurons),tau_metric=zeros(self.neurons))
        else:
            self.initialize_criterion(delays=zeros(self.neurons))
        if self.use_gpu:
            self.initialize_gpu()
            
    def initialize_neurongroup(self):
        # Add 'refractory' parameter on the CPU only
        if not self.use_gpu:
            if self.max_refractory is not None:
                refractory = 'refractory'
                self.model.add_param('refractory', second)
            else:
                refractory = self.refractory
        else:
            if self.max_refractory is not None:
                refractory = 0*ms
            else:
                refractory = self.refractory
        
        # Must recompile the Equations : the functions are not transfered after pickling/unpickling
        self.model.compile_functions()
#        print refractory, self.max_refractory
        if  type(refractory) is double:
            refractory=refractory*second
#        if self.give_neuron_group == False:
        self.group = NeuronGroup(self.neurons, # TODO: * slices?
                                 model=self.model,
                                 reset=self.reset,
                                 threshold=self.threshold,
                                 refractory=refractory,
                                 max_refractory = self.max_refractory,
                                 method = self.method,
                                 clock=Clock(dt=self.dt))
        
        if self.initial_values is not None:
            for param, value in self.initial_values.iteritems():
                self.group.state(param)[:] = value

#        else: 
#            self.group = self.neuron_group
    
    def initialize_gpu(self):
            # Select integration scheme according to method
            if self.method == 'Euler': scheme = euler_scheme
            elif self.method == 'RK': scheme = rk2_scheme
            elif self.method == 'exponential_Euler': scheme = exp_euler_scheme
            else: raise Exception("The numerical integration method is not valid")
            
            self.mf = GPUModelFitting(self.group, self.model, self.criterion_object,
                                      self.input_var, self.neurons/self.groups,
                                      self.onset, 
                                      statemonitor_var = self.statemonitor_var,
                                      spikemonitor = self.spikemonitor,
                                      nbr_spikes = self.nbr_spikes,
                                      duration = self.sliced_duration,
                                      precision=self.precision, scheme=scheme)
    
    def transform_data(self):
        self.transformer = DataTransformer(self.neurons,
                                           self.inputs,
                                           spikes = self.spikes, 
                                           traces = self.traces,
                                           dt = self.dt,
                                           slices = self.slices,
                                           overlap = self.overlap, 
                                           groups = self.groups,ntrials=self.ntrials)
        self.total_steps = self.transformer.total_steps
        self.sliced_duration = self.transformer.sliced_duration
        if self.ntrials>1:
            self.inputs_inline = self.inputs.flatten()
            self.sliced_inputs = self.inputs
            self.inputs_offset  = zeros(self.neurons)
        else:
            self.sliced_inputs = self.transformer.slice_traces(self.inputs)
            self.inputs_inline, self.inputs_offset = self.transformer.transform_traces(self.sliced_inputs)

        if self.traces is not None:
            self.sliced_traces = self.transformer.slice_traces(self.traces)
            self.traces_inline, self.traces_offset = self.transformer.transform_traces(self.sliced_traces)
        else:
            self.sliced_traces, self.traces_inline, self.traces_offset = None, None, None
        
        if self.spikes is not None:
            if self.ntrials>1:
                self.sliced_spikes = self.transformer.slice_spikes(self.spikes)
                self.spikes_inline, self.trials_offset = self.transformer.transform_trials(self.spikes)
                self.spikes_offset = zeros((self.neurons),dtype=int)
            else:
                self.sliced_spikes = self.transformer.slice_spikes(self.spikes)
                self.spikes_inline, self.spikes_offset = self.transformer.transform_spikes(self.sliced_spikes)
                self.trials_offset=[0]
        else:
            self.sliced_spikes, self.spikes_inline, self.spikes_offset,self.trials_offset = None, None, None, None
        
        
    def inject_input(self):
        # Injects current in consecutive subgroups, where I_offset have the same value
        # on successive intervals
        I_offset = self.inputs_offset
        k = -1
        for i in hstack((nonzero(diff(I_offset))[0], len(I_offset) - 1)):
            I_offset_subgroup_value = I_offset[i]
            I_offset_subgroup_length = i - k
            sliced_subgroup = self.group.subgroup(I_offset_subgroup_length)
            input_sliced_values = self.inputs_inline[I_offset_subgroup_value:I_offset_subgroup_value + self.total_steps]
            sliced_subgroup.set_var_by_array(self.input_var, TimedArray(input_sliced_values, clock=self.group.clock))
            k = i
    
    def initialize_criterion(self, **criterion_params):
        # general criterion parameters
        params = dict(group=self.group, traces=self.sliced_traces, spikes=self.sliced_spikes, 
                      targets_count=self.groups*self.slices, duration=self.sliced_duration, onset=self.onset, 
                      spikes_inline=self.spikes_inline, spikes_offset=self.spikes_offset,
                      traces_inline=self.traces_inline, traces_offset=self.traces_offset,trials_offset=self.trials_offset)
        for key,val in criterion_params.iteritems():
            params[key] = val
        criterion_name = self.criterion.__class__.__name__
        
        # criterion-specific parameters
        if criterion_name == 'GammaFactor':
            params['delta'] = self.criterion.delta
            params['coincidence_count_algorithm'] = self.criterion.coincidence_count_algorithm
            params['fr_weight'] = self.criterion.fr_weight
            self.criterion_object = GammaFactorCriterion(**params)
            
        if criterion_name == 'GammaFactor2':
            params['delta'] = self.criterion.delta
            params['coincidence_count_algorithm'] = self.criterion.coincidence_count_algorithm
            params['fr_weight'] = self.criterion.fr_weight
            params['nlevels'] = self.criterion.nlevels
            params['level_duration'] = self.criterion.level_duration
            self.criterion_object = GammaFactorCriterion2(**params)

        if criterion_name == 'LpError':
            params['p'] = self.criterion.p
            params['varname'] = self.criterion.varname
            params['method'] = self.criterion.method
            params['insets'] = self.criterion.insets
            params['outsets'] = self.criterion.outsets
            params['points'] = self.criterion.points
            self.criterion_object = LpErrorCriterion(**params)
            
        if criterion_name == 'VanRossum':
            params['tau'] = self.criterion.tau
            self.criterion_object = VanRossumCriterion(**params)
        
        if criterion_name == 'Brette':
            self.criterion_object = BretteCriterion(**params)
    
    def update_neurongroup(self, **param_values):
        """
        Inject fitting parameters into the NeuronGroup
        """
        # Sets the parameter values in the NeuronGroup object
        self.group.reinit()
        for param, value in param_values.iteritems():
            self.group.state(param)[:] = kron(value, ones(self.slices)) # kron param_values if slicing
        
        # Reinitializes the model variables
        if self.initial_values is not None:
            for param, value in self.initial_values.iteritems():
                self.group.state(param)[:] = value
    
    def combine_sliced_values(self, values):
        if type(values) is tuple:
            combined_values = tuple([sum(reshape(v, (self.slices, -1)), axis=0) for v in values])
        else:
            combined_values = sum(reshape(values, (self.slices, -1)), axis=0)
        return combined_values
    
    def run(self, **param_values):
        delays = param_values.pop('delays', zeros(self.neurons))
        
#        print self.refractory,self.max_refractory
        if self.max_refractory is not None:
            refractory = param_values.pop('refractory', zeros(self.neurons))
        else:
            refractory = self.refractory*ones(self.neurons)
            
        tau_metric = param_values.pop('tau_metric', zeros(self.neurons))
        self.update_neurongroup(**param_values)

        # repeat spike delays and refractory to take slices into account
        delays = kron(delays, ones(self.slices))
        refractory = kron(refractory, ones(self.slices))
        tau_metric = kron(tau_metric, ones(self.slices))
        # TODO: add here parameters to criterion_params if a criterion must use some parameters
        criterion_params = dict(delays=delays)

        if self.criterion.__class__.__name__ == 'Brette':
            criterion_params['tau_metric'] = tau_metric
    
        
        self.update_neurongroup(**param_values)
        self.initialize_criterion(**criterion_params)
        
        if self.use_gpu:
            # Reinitializes the simulation object
            self.mf.reinit_vars(self.criterion_object,
                                self.inputs_inline, self.inputs_offset,
                                self.spikes_inline, self.spikes_offset,
                                self.traces_inline, self.traces_offset,
                                delays, refractory
                                )
            # LAUNCHES the simulation on the GPU
            self.mf.launch(self.sliced_duration, self.stepsize)
            # Synchronize the GPU values with a call to gpuarray.get()
            self.criterion_object.update_gpu_values()
        else:
            # set the refractory period
            if self.max_refractory is not None:
                self.group.refractory = refractory
            # Launch the simulation on the CPU
            self.group.clock.reinit()
            net = Network(self.group, self.criterion_object)
            if self.statemonitor_var is not None:
                self.statemonitors = []
                for state in self.statemonitor_var:
                    monitor = StateMonitor(self.group, state, record=True)
                    self.statemonitors.append(monitor)
                    net.add(monitor)
            net.run(self.sliced_duration)
        
        sliced_values = self.criterion_object.get_values()
        combined_values = self.combine_sliced_values(sliced_values)
        values = self.criterion_object.normalize(combined_values)
        return values

    def get_statemonitor_values(self):
        if not self.use_gpu:
            return [monitor.values for monitor in self.statemonitors]
        else:
            return self.mf.get_statemonitor_values()
        
    def get_spikemonitor_values(self):
        if not self.use_gpu:
            return [monitor.values for monitor in self.statemonitors]
        else:
            return self.mf.get_spikemonitor_values()
示例#4
0
class Simulator(object):
    def __init__(
        self,
        model,
        reset,
        threshold,
        inputs,
        input_var="I",
        dt=defaultclock.dt,
        refractory=0 * ms,
        max_refractory=None,
        spikes=None,
        traces=None,
        groups=1,
        slices=1,
        overlap=0 * second,
        onset=0 * second,
        neurons=1000,  # = nodesize = number of neurons on this node = total number of neurons/slices
        initial_values=None,
        unit_type="CPU",
        stepsize=100 * ms,
        precision="double",
        criterion=None,
        statemonitor_var=None,
        method="Euler",
    ):
        self.model = model
        self.reset = reset
        self.threshold = threshold
        self.inputs = inputs
        self.input_var = input_var
        self.dt = dt
        self.refractory = refractory
        self.max_refractory = max_refractory
        self.spikes = spikes
        self.traces = traces
        self.initial_values = initial_values
        self.groups = groups
        self.slices = slices
        self.overlap = overlap
        self.onset = onset
        self.neurons = neurons
        self.unit_type = unit_type
        self.statemonitor_var = statemonitor_var
        self.stepsize = stepsize
        self.precision = precision
        self.criterion = criterion
        self.method = method
        self.use_gpu = self.unit_type == "GPU"

        if self.statemonitor_var is not None:
            self.statemonitor_values = zeros(self.neurons)

        self.initialize_neurongroup()
        self.transform_data()
        self.inject_input()
        self.initialize_criterion(delays=zeros(self.neurons))

        if self.use_gpu:
            self.initialize_gpu()

    def initialize_neurongroup(self):
        # Add 'refractory' parameter on the CPU only
        if not self.use_gpu:
            if self.max_refractory is not None:
                refractory = "refractory"
                self.model.add_param("refractory", second)
            else:
                refractory = self.refractory
        else:
            if self.max_refractory is not None:
                refractory = 0 * ms
            else:
                refractory = self.refractory

        # Must recompile the Equations : the functions are not transfered after pickling/unpickling
        self.model.compile_functions()

        self.group = NeuronGroup(
            self.neurons,
            model=self.model,
            reset=self.reset,
            threshold=self.threshold,
            refractory=refractory,
            max_refractory=self.max_refractory,
            method=self.method,
            clock=Clock(dt=self.dt),
        )

        if self.initial_values is not None:
            for param, value in self.initial_values.iteritems():
                self.group.state(param)[:] = value

    def initialize_gpu(self):
        # Select integration scheme according to method
        if self.method == "Euler":
            scheme = euler_scheme
        elif self.method == "RK":
            scheme = rk2_scheme
        elif self.method == "exponential_Euler":
            scheme = exp_euler_scheme
        else:
            raise Exception("The numerical integration method is not valid")

        self.mf = GPUModelFitting(
            self.group,
            self.model,
            self.criterion_object,
            self.input_var,
            self.onset,
            statemonitor_var=self.statemonitor_var,
            duration=self.sliced_duration,
            precision=self.precision,
            scheme=scheme,
        )

    def transform_data(self):
        self.transformer = DataTransformer(
            self.neurons,
            self.inputs,
            spikes=self.spikes,
            traces=self.traces,
            dt=self.dt,
            slices=self.slices,
            overlap=self.overlap,
            groups=self.groups,
        )
        self.total_steps = self.transformer.total_steps
        self.sliced_duration = self.transformer.sliced_duration

        self.sliced_inputs = self.transformer.slice_traces(self.inputs)
        self.inputs_inline, self.inputs_offset = self.transformer.transform_traces(self.sliced_inputs)

        if self.traces is not None:
            self.sliced_traces = self.transformer.slice_traces(self.traces)
            self.traces_inline, self.traces_offset = self.transformer.transform_traces(self.sliced_traces)
        else:
            self.sliced_traces, self.traces_inline, self.traces_offset = None, None, None

        if self.spikes is not None:
            self.sliced_spikes = self.transformer.slice_spikes(self.spikes)
            self.spikes_inline, self.spikes_offset = self.transformer.transform_spikes(self.sliced_spikes)
        else:
            self.sliced_spikes, self.spikes_inline, self.spikes_offset = None, None, None

    def inject_input(self):
        # Injects current in consecutive subgroups, where I_offset have the same value
        # on successive intervals
        I_offset = self.inputs_offset
        k = -1
        for i in hstack((nonzero(diff(I_offset))[0], len(I_offset) - 1)):
            I_offset_subgroup_value = I_offset[i]
            I_offset_subgroup_length = i - k
            sliced_subgroup = self.group.subgroup(I_offset_subgroup_length)
            input_sliced_values = self.inputs_inline[
                I_offset_subgroup_value : I_offset_subgroup_value + self.total_steps
            ]
            sliced_subgroup.set_var_by_array(self.input_var, TimedArray(input_sliced_values, clock=self.group.clock))
            k = i

    def initialize_criterion(self, **criterion_params):
        # general criterion parameters
        params = dict(
            group=self.group,
            traces=self.sliced_traces,
            spikes=self.sliced_spikes,
            targets_count=self.groups * self.slices,
            duration=self.sliced_duration,
            onset=self.onset,
            spikes_inline=self.spikes_inline,
            spikes_offset=self.spikes_offset,
            traces_inline=self.traces_inline,
            traces_offset=self.traces_offset,
        )
        for key, val in criterion_params.iteritems():
            params[key] = val
        criterion_name = self.criterion.__class__.__name__

        # criterion-specific parameters
        if criterion_name == "GammaFactor":
            params["delta"] = self.criterion.delta
            params["coincidence_count_algorithm"] = self.criterion.coincidence_count_algorithm
            self.criterion_object = GammaFactorCriterion(**params)

        if criterion_name == "LpError":
            params["p"] = self.criterion.p
            params["varname"] = self.criterion.varname
            self.criterion_object = LpErrorCriterion(**params)

    def update_neurongroup(self, **param_values):
        """
        Inject fitting parameters into the NeuronGroup
        """
        # Sets the parameter values in the NeuronGroup object
        self.group.reinit()
        for param, value in param_values.iteritems():
            self.group.state(param)[:] = kron(value, ones(self.slices))  # kron param_values if slicing

        # Reinitializes the model variables
        if self.initial_values is not None:
            for param, value in self.initial_values.iteritems():
                self.group.state(param)[:] = value

    def combine_sliced_values(self, values):
        if type(values) is tuple:
            combined_values = tuple([sum(reshape(v, (self.slices, -1)), axis=0) for v in values])
        else:
            combined_values = sum(reshape(values, (self.slices, -1)), axis=0)
        return combined_values

    def run(self, **param_values):
        delays = param_values.pop("delays", zeros(self.neurons))
        refractory = param_values.pop("refractory", zeros(self.neurons))

        self.update_neurongroup(**param_values)

        # repeat spike delays and refractory to take slices into account
        delays = kron(delays, ones(self.slices))
        refractory = kron(refractory, ones(self.slices))

        # TODO: add here parameters to criterion_params if a criterion must use some parameters
        criterion_params = dict(delays=delays)

        self.update_neurongroup(**param_values)
        self.initialize_criterion(**criterion_params)

        if self.use_gpu:
            # Reinitializes the simulation object
            self.mf.reinit_vars(
                self.criterion_object,
                self.inputs_inline,
                self.inputs_offset,
                self.spikes_inline,
                self.spikes_offset,
                self.traces_inline,
                self.traces_offset,
                delays,
                refractory,
            )
            # LAUNCHES the simulation on the GPU
            self.mf.launch(self.sliced_duration, self.stepsize)
            # Synchronize the GPU values with a call to gpuarray.get()
            self.criterion_object.update_gpu_values()
        else:
            # set the refractory period
            if self.max_refractory is not None:
                self.group.refractory = refractory
            # Launch the simulation on the CPU
            self.group.clock.reinit()
            net = Network(self.group, self.criterion_object)
            if self.statemonitor_var is not None:
                self.statemonitor = StateMonitor(self.group, self.statemonitor_var, record=True)
                net.add(self.statemonitor)
            net.run(self.sliced_duration)

        sliced_values = self.criterion_object.get_values()
        combined_values = self.combine_sliced_values(sliced_values)
        values = self.criterion_object.normalize(combined_values)
        return values

    def get_statemonitor_values(self):
        if not self.use_gpu:
            return self.statemonitor.values
        else:
            return self.mf.get_statemonitor_values()