def get_spike_update_expressions(self, neuron: ASTNeuron, kernel_buffers, solver_dicts, delta_factors) -> List[ASTAssignment]: """ Generate the equations that update the dynamical variables when incoming spikes arrive. To be invoked after ode-toolbox. For example, a resulting `assignment_str` could be "I_kernel_in += (in_spikes/nS) * 1". The values are taken from the initial values for each corresponding dynamical variable, either from ode-toolbox or directly from user specification in the model. Note that for kernels, `initial_values` actually contains the increment upon spike arrival, rather than the initial value of the corresponding ODE dimension. """ spike_updates = [] initial_values = neuron.get_initial_values_blocks() for kernel, spike_input_port in kernel_buffers: if neuron.get_scope().resolve_to_symbol(str(spike_input_port), SymbolKind.VARIABLE) is None: continue buffer_type = neuron.get_scope().resolve_to_symbol(str(spike_input_port), SymbolKind.VARIABLE).get_type_symbol() if is_delta_kernel(kernel): continue for kernel_var in kernel.get_variables(): for var_order in range(get_kernel_var_order_from_ode_toolbox_result(kernel_var.get_name(), solver_dicts)): kernel_spike_buf_name = construct_kernel_X_spike_buf_name( kernel_var.get_name(), spike_input_port, var_order) expr = get_initial_value_from_ode_toolbox_result(kernel_spike_buf_name, solver_dicts) assert expr is not None, "Initial value not found for kernel " + kernel_var expr = str(expr) if expr in ["0", "0.", "0.0"]: continue # skip adding the statement if we're only adding zero assignment_str = kernel_spike_buf_name + " += " assignment_str += "(" + str(spike_input_port) + ")" if not expr in ["1.", "1.0", "1"]: assignment_str += " * (" + \ self._printer.print_expression(ModelParser.parse_expression(expr)) + ")" if not buffer_type.print_nestml_type() in ["1.", "1.0", "1"]: assignment_str += " / (" + buffer_type.print_nestml_type() + ")" ast_assignment = ModelParser.parse_assignment(assignment_str) ast_assignment.update_scope(neuron.get_scope()) ast_assignment.accept(ASTSymbolTableVisitor()) spike_updates.append(ast_assignment) for k, factor in delta_factors.items(): var = k[0] inport = k[1] assignment_str = var.get_name() + "'" * (var.get_differential_order() - 1) + " += " if not factor in ["1.", "1.0", "1"]: assignment_str += "(" + self._printer.print_expression(ModelParser.parse_expression(factor)) + ") * " assignment_str += str(inport) ast_assignment = ModelParser.parse_assignment(assignment_str) ast_assignment.update_scope(neuron.get_scope()) ast_assignment.accept(ASTSymbolTableVisitor()) spike_updates.append(ast_assignment) return spike_updates
def apply_incoming_spikes(neuron): """ Adds a set of update instructions to the handed over neuron. :param neuron: a single neuron instance :type neuron: ASTNeuron :return: the modified neuron :rtype: ASTNeuron """ assert (neuron is not None and isinstance(neuron, ASTNeuron)), \ '(PyNestML.Solver.BaseTransformer) No or wrong type of neuron provided (%s)!' % type(neuron) conv_calls = OdeTransformer.get_sum_function_calls(neuron) printer = ExpressionsPrettyPrinter() spikes_updates = list() for convCall in conv_calls: shape = convCall.get_args()[0].get_variable().get_complete_name() buffer = convCall.get_args()[1].get_variable().get_complete_name() initial_values = ( neuron.get_initial_values_blocks().get_declarations() if neuron.get_initial_values_blocks() is not None else list()) for astDeclaration in initial_values: for variable in astDeclaration.get_variables(): if re.match(shape + "[\']*", variable.get_complete_name()) or re.match( shape + '__[\\d]+$', variable.get_complete_name()): spikes_updates.append( ModelParser.parse_assignment( variable.get_complete_name() + " += " + buffer + " * " + printer.print_expression( astDeclaration.get_expression()))) for update in spikes_updates: add_assignment_to_update_block(update, neuron) return neuron
def apply_spikes_from_buffers(self, neuron, shape_to_buffers): """generate the equations that update the dynamical variables when incoming spikes arrive. For example, a resulting `assignment_string` could be "I_shape_in += (in_spikes/nS) * 1". The definition of the spike kernel shape is then set to 0. """ spike_updates = [] initial_values = neuron.get_initial_values_blocks() for declaration in initial_values.get_declarations(): variable = declaration.get_variables()[0] for shape in shape_to_buffers: matcher_computed_shape_odes = re.compile(shape + r"(__\d+)?") if re.match(matcher_computed_shape_odes, str(variable)): buffer_type = neuron.get_scope(). \ resolve_to_symbol(shape_to_buffers[shape], SymbolKind.VARIABLE).get_type_symbol() assignment_string = variable.get_complete_name() + " += (" + shape_to_buffers[ shape] + '/' + buffer_type.print_nestml_type() + ") * " + \ self._printer.print_expression(declaration.get_expression()) spike_updates.append( ModelParser.parse_assignment(assignment_string)) # the IV is applied. can be reset declaration.set_expression( ModelParser.parse_expression("0")) for assignment in spike_updates: add_assignment_to_update_block(assignment, neuron)
def apply_incoming_spikes(neuron): """ Adds a set of update instructions to the handed over neuron. :param neuron: a single neuron instance :type neuron: ASTNeuron :return: the modified neuron :rtype: ASTNeuron """ assert (neuron is not None and isinstance(neuron, ASTNeuron)), \ '(PyNestML.Solver.BaseTransformer) No or wrong type of neuron provided (%s)!' % type(neuron) conv_calls = OdeTransformer.get_sum_function_calls(neuron) printer = ExpressionsPrettyPrinter() spikes_updates = list() for convCall in conv_calls: shape = convCall.get_args()[0].get_variable().get_complete_name() buffer = convCall.get_args()[1].get_variable().get_complete_name() initial_values = ( neuron.get_initial_values_blocks().get_declarations() if neuron.get_initial_values_blocks() is not None else list()) for astDeclaration in initial_values: for variable in astDeclaration.get_variables(): if re.match(shape + "[\']*", variable.get_complete_name()) or re.match(shape + '__[\\d]+$', variable.get_complete_name()): spikes_updates.append(ModelParser.parse_assignment( variable.get_complete_name() + " += " + buffer + " * " + printer.print_expression( astDeclaration.get_expression()))) for update in spikes_updates: add_assignment_to_update_block(update, neuron) return neuron
def test_assignment_with_comments(self): assignment = '\n' \ '/* pre */\n' \ 'a = b # in\n' \ '/* post */\n' \ '\n' model = ModelParser.parse_assignment(assignment) model_printer = ASTNestMLPrinter() self.assertEqual(assignment, model_printer.print_node(model))
def test_assignment_with_comments(self): assignment = '\n' \ '/* pre */\n' \ 'a = b # in\n' \ '/* post */\n' \ '\n' model = ModelParser.parse_assignment(assignment) model_printer = ASTNestMLPrinter() self.assertEqual(assignment, model_printer.print_node(model))
def add_state_updates(neuron: ASTNeuron, update_expressions: Mapping[str, str]) -> ASTNeuron: """ Adds all update instructions as contained in the solver output to the update block of the neuron. :param neuron: a single neuron :param update_expressions: map of variables to corresponding updates during the update step. :return: a modified version of the neuron """ for variable, update_expression in update_expressions.items(): declaration_statement = variable + '__tmp real = ' + update_expression add_declaration_to_update_block(ModelParser.parse_declaration(declaration_statement), neuron) for variable, update_expression in update_expressions.items(): add_assignment_to_update_block(ModelParser.parse_assignment(variable + ' = ' + variable + '__tmp'), neuron) return neuron
def add_state_updates(state_shape_variables_updates, neuron): # type: (map[str, str], ASTNeuron) -> ASTNeuron """ Adds all update instructions as contained in the solver output to the update block of the neuron. :param state_shape_variables_updates: map of variables to corresponding updates during the update step. :param neuron: a single neuron :return: a modified version of the neuron """ for variable in state_shape_variables_updates: declaration_statement = variable + '__tmp real = ' + state_shape_variables_updates[variable] add_declaration_to_update_block(ModelParser.parse_declaration(declaration_statement), neuron) for variable in state_shape_variables_updates: add_assignment_to_update_block(ModelParser.parse_assignment(variable + ' = ' + variable + '__tmp'), neuron) return neuron
def add_state_updates(state_shape_variables_updates, neuron): # type: (map[str, str], ASTNeuron) -> ASTNeuron """ Adds all update instructions as contained in the solver output to the update block of the neuron. :param state_shape_variables_updates: map of variables to corresponding updates during the update step. :param neuron: a single neuron :return: a modified version of the neuron """ for variable in state_shape_variables_updates: declaration_statement = variable + '__tmp real = ' + state_shape_variables_updates[ variable] add_declaration_to_update_block( ModelParser.parse_declaration(declaration_statement), neuron) for variable in state_shape_variables_updates: add_assignment_to_update_block( ModelParser.parse_assignment(variable + ' = ' + variable + '__tmp'), neuron) return neuron
def apply_spikes_from_buffers(neuron, shape_to_buffers): spike_updates = [] initial_values = neuron.get_initial_values_blocks() for declaration in initial_values.get_declarations(): variable = declaration.get_variables()[0] for shape in shape_to_buffers: matcher_computed_shape_odes = re.compile(shape + r"(__\d+)?") buffer_type = neuron.get_scope(). \ resolve_to_symbol(shape_to_buffers[shape], SymbolKind.VARIABLE).get_type_symbol() if re.match(matcher_computed_shape_odes, str(variable)): assignment_string = variable.get_complete_name() + " += (" + shape_to_buffers[ shape] + '/' + buffer_type.print_nestml_type() + ") * " + \ _printer.print_expression(declaration.get_expression()) spike_updates.append(ModelParser.parse_assignment(assignment_string)) # the IV is applied. can be reset declaration.set_expression(ModelParser.parse_expression("0")) for assignment in spike_updates: add_assignment_to_update_block(assignment, neuron)
def apply_spikes_from_buffers(self, neuron, shape_to_buffers): """generate the equations that update the dynamical variables when incoming spikes arrive. For example, a resulting `assignment_string` could be "I_shape_in += (in_spikes/nS) * 1". The definition of the spike kernel shape is then set to 0. """ spike_updates = [] initial_values = neuron.get_initial_values_blocks() for declaration in initial_values.get_declarations(): variable = declaration.get_variables()[0] for shape in shape_to_buffers: matcher_computed_shape_odes = re.compile(shape + r"(__\d+)?") if re.match(matcher_computed_shape_odes, str(variable)): buffer_type = neuron.get_scope(). \ resolve_to_symbol(shape_to_buffers[shape], SymbolKind.VARIABLE).get_type_symbol() assignment_string = variable.get_complete_name() + " += (" + shape_to_buffers[ shape] + '/' + buffer_type.print_nestml_type() + ") * " + \ self._printer.print_expression(declaration.get_expression()) spike_updates.append(ModelParser.parse_assignment(assignment_string)) # the IV is applied. can be reset declaration.set_expression(ModelParser.parse_expression("0")) for assignment in spike_updates: add_assignment_to_update_block(assignment, neuron)
def test_assignment_without_comments(self): assignment = 'a = b\n' model = ModelParser.parse_assignment(assignment) model_printer = ASTNestMLPrinter() self.assertEqual(assignment, model_printer.print_node(model))
def test_assignment_without_comments(self): assignment = 'a = b\n' model = ModelParser.parse_assignment(assignment) model_printer = ASTNestMLPrinter() self.assertEqual(assignment, model_printer.print_node(model))