Exemplo n.º 1
0
 def analyse_neuron(self, neuron):
     # type: (ASTNeuron) -> None
     """
     Analyse and transform a single neuron.
     :param neuron: a single neuron.
     """
     code, message = Messages.get_start_processing_neuron(neuron.get_name())
     Logger.log_message(neuron, code, message, neuron.get_source_position(), LoggingLevel.INFO)
     # make normalization
     # apply spikes to buffers
     # get rid of convolve, store them and apply then at the end
     equations_block = neuron.get_equations_block()
     shape_to_buffers = {}
     if neuron.get_equations_block() is not None:
         # extract function names and corresponding incoming buffers
         convolve_calls = OdeTransformer.get_sum_function_calls(equations_block)
         for convolve in convolve_calls:
             shape_to_buffers[str(convolve.get_args()[0])] = str(convolve.get_args()[1])
         OdeTransformer.refactor_convolve_call(neuron.get_equations_block())
         self.make_functions_self_contained(equations_block.get_ode_functions())
         self.replace_functions_through_defining_expressions(equations_block.get_ode_equations(),
                                                        equations_block.get_ode_functions())
         # transform everything into gsl processable (e.g. no functional shapes) or exact form.
         self.transform_shapes_and_odes(neuron, shape_to_buffers)
         self.apply_spikes_from_buffers(neuron, shape_to_buffers)
         # update the symbol table
         symbol_table_visitor = ASTSymbolTableVisitor()
         symbol_table_visitor.after_ast_rewrite_ = True		# ODE block might have been removed entirely: suppress warnings
         neuron.accept(symbol_table_visitor)
Exemplo n.º 2
0
 def analyse_neuron(self, neuron):
     # type: (ASTNeuron) -> None
     """
     Analyse and transform a single neuron.
     :param neuron: a single neuron.
     """
     code, message = Messages.get_start_processing_neuron(neuron.get_name())
     Logger.log_message(neuron, code, message, neuron.get_source_position(),
                        LoggingLevel.INFO)
     # make normalization
     # apply spikes to buffers
     # get rid of convolve, store them and apply then at the end
     equations_block = neuron.get_equations_block()
     shape_to_buffers = {}
     if neuron.get_equations_block() is not None:
         # extract function names and corresponding incoming buffers
         convolve_calls = OdeTransformer.get_sum_function_calls(
             equations_block)
         for convolve in convolve_calls:
             shape_to_buffers[str(convolve.get_args()[0])] = str(
                 convolve.get_args()[1])
         OdeTransformer.refactor_convolve_call(neuron.get_equations_block())
         self.make_functions_self_contained(
             equations_block.get_ode_functions())
         self.replace_functions_through_defining_expressions(
             equations_block.get_ode_equations(),
             equations_block.get_ode_functions())
         # transform everything into gsl processable (e.g. no functional shapes) or exact form.
         self.transform_shapes_and_odes(neuron, shape_to_buffers)
         self.apply_spikes_from_buffers(neuron, shape_to_buffers)
         # update the symbol table
         symbol_table_visitor = ASTSymbolTableVisitor()
         symbol_table_visitor.after_ast_rewrite_ = True  # ODE block might have been removed entirely: suppress warnings
         neuron.accept(symbol_table_visitor)
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
 def update_symbol_table(self, neuron, kernel_buffers):
     """
     Update symbol table and scope.
     """
     SymbolTable.delete_neuron_scope(neuron.get_name())
     symbol_table_visitor = ASTSymbolTableVisitor()
     symbol_table_visitor.after_ast_rewrite_ = True
     neuron.accept(symbol_table_visitor)
     SymbolTable.add_neuron_scope(neuron.get_name(), neuron.get_scope())
Exemplo n.º 5
0
    def make_inline_expressions_self_contained(
        self, inline_expressions: List[ASTInlineExpression]
    ) -> List[ASTInlineExpression]:
        """
        Make inline_expressions self contained, i.e. without any references to other inline_expressions.

        TODO: it should be a method inside of the ASTInlineExpression
        TODO: this should be done by means of a visitor

        :param inline_expressions: A sorted list with entries ASTInlineExpression.
        :return: A list with ASTInlineExpressions. Defining expressions don't depend on each other.
        """
        for source in inline_expressions:
            source_position = source.get_source_position()
            for target in inline_expressions:
                matcher = re.compile(
                    self._variable_matching_template.format(
                        source.get_variable_name()))
                target_definition = str(target.get_expression())
                target_definition = re.sub(
                    matcher, "(" + str(source.get_expression()) + ")",
                    target_definition)
                target.expression = ModelParser.parse_expression(
                    target_definition)
                target.expression.update_scope(source.get_scope())
                target.expression.accept(ASTSymbolTableVisitor())

                def log_set_source_position(node):
                    if node.get_source_position().is_added_source_position():
                        node.set_source_position(source_position)

                target.expression.accept(
                    ASTHigherOrderVisitor(visit_funcs=log_set_source_position))

        return inline_expressions
Exemplo n.º 6
0
    def replace_inline_expressions_through_defining_expressions(
            self, definitions, inline_expressions):
        # type: (list(ASTOdeEquation), list(ASTInlineExpression)) -> list(ASTInlineExpression)
        """
        Replaces symbols from `inline_expressions` in `definitions` with corresponding defining expressions from `inline_expressions`.

        :param definitions: A sorted list with entries {"symbol": "name", "definition": "expression"} that should be made free from.
        :param inline_expressions: A sorted list with entries {"symbol": "name", "definition": "expression"} with inline_expressions which must be replaced in `definitions`.
        :return: A list with definitions. Expressions in `definitions` don't depend on inline_expressions from `inline_expressions`.
        """
        for m in inline_expressions:
            source_position = m.get_source_position()
            for target in definitions:
                matcher = re.compile(
                    self._variable_matching_template.format(
                        m.get_variable_name()))
                target_definition = str(target.get_rhs())
                target_definition = re.sub(matcher,
                                           "(" + str(m.get_expression()) + ")",
                                           target_definition)
                target.rhs = ModelParser.parse_expression(target_definition)
                target.update_scope(m.get_scope())
                target.accept(ASTSymbolTableVisitor())

                def log_set_source_position(node):
                    if node.get_source_position().is_added_source_position():
                        node.set_source_position(source_position)

                target.accept(
                    ASTHigherOrderVisitor(visit_funcs=log_set_source_position))

        return definitions
Exemplo n.º 7
0
def add_declaration_to_state_block(neuron: ASTNeuron, variable: str,
                                   initial_value: str) -> ASTNeuron:
    """
    Adds a single declaration to the state block of the neuron. The declared variable is of type real.
    :param neuron: a neuron
    :param variable: state variable to add
    :param initial_value: corresponding initial value
    :return: a modified neuron
    """
    tmp = ModelParser.parse_expression(initial_value)
    vector_variable = ASTUtils.get_vectorized_variable(tmp, neuron.get_scope())
    declaration_string = variable + ' real' + (
        '[' + vector_variable.get_vector_parameter() + ']' if
        vector_variable is not None and vector_variable.has_vector_parameter()
        else '') + ' = ' + initial_value
    ast_declaration = ModelParser.parse_declaration(declaration_string)
    if vector_variable is not None:
        ast_declaration.set_size_parameter(
            vector_variable.get_vector_parameter())
    neuron.add_to_state_block(ast_declaration)
    ast_declaration.update_scope(neuron.get_state_blocks().get_scope())

    symtable_visitor = ASTSymbolTableVisitor()
    symtable_visitor.block_type_stack.push(BlockType.STATE)
    ast_declaration.accept(symtable_visitor)
    symtable_visitor.block_type_stack.pop()

    return neuron
Exemplo n.º 8
0
def analyse_and_generate_neuron(neuron):
    # type: (ASTNeuron) -> None
    """
    Analysis a single neuron, solves it and generates the corresponding code.
    :param neuron: a single neuron.
    """
    code, message = Messages.get_start_processing_neuron(neuron.get_name())
    Logger.log_message(neuron, code, message, neuron.get_source_position(), LoggingLevel.INFO)
    # make normalization
    # apply spikes to buffers
    # get rid of convolve, store them and apply then at the end
    equations_block = neuron.get_equations_block()
    shape_to_buffers = {}
    if neuron.get_equations_block() is not None:
        # extract function names and corresponding incoming buffers
        convolve_calls = OdeTransformer.get_sum_function_calls(equations_block)
        for convolve in convolve_calls:
            shape_to_buffers[str(convolve.get_args()[0])] = str(convolve.get_args()[1])
        OdeTransformer.refactor_convolve_call(neuron.get_equations_block())
        make_functions_self_contained(equations_block.get_ode_functions())
        replace_functions_through_defining_expressions(equations_block.get_ode_equations(),
                                                       equations_block.get_ode_functions())
        # transform everything into gsl processable (e.g. no functional shapes) or exact form.
        transform_shapes_and_odes(neuron, shape_to_buffers)
        # update the symbol table
        neuron.accept(ASTSymbolTableVisitor())
    generate_nest_code(neuron)
    # now store the transformed model
    store_transformed_model(neuron)
    # at that point all shapes are transformed into the ODE form and spikes can be applied
    code, message = Messages.get_code_generated(neuron.get_name(), FrontendConfiguration.get_target_path())
    Logger.log_message(neuron, code, message, neuron.get_source_position(), LoggingLevel.INFO)
Exemplo n.º 9
0
    def move_decls(cls, var_name, from_block, to_block, var_name_suffix, block_type: BlockType, mode="move", scope=None) -> List[ASTDeclaration]:
        from pynestml.codegeneration.ast_transformers import ASTTransformers
        from pynestml.visitors.ast_symbol_table_visitor import ASTSymbolTableVisitor
        assert mode in ["move", "copy"]

        if not from_block \
           or not to_block:
            return []

        decls = ASTTransformers.get_declarations_from_block(var_name, from_block)
        if var_name.endswith(var_name_suffix):
            decls.extend(ASTTransformers.get_declarations_from_block(var_name.removesuffix(var_name_suffix), from_block))

        if decls:
            Logger.log_message(None, -1, "Moving definition of " + var_name + " from synapse to neuron",
                               None, LoggingLevel.INFO)
            for decl in decls:
                if mode == "move":
                    from_block.declarations.remove(decl)
                if mode == "copy":
                    decl = decl.clone()
                assert len(decl.get_variables()) <= 1
                if not decl.get_variables()[0].name.endswith(var_name_suffix):
                    ASTUtils.add_suffix_to_decl_lhs(decl, suffix=var_name_suffix)
                to_block.get_declarations().append(decl)
                decl.update_scope(to_block.get_scope())

                ast_symbol_table_visitor = ASTSymbolTableVisitor()
                ast_symbol_table_visitor.block_type_stack.push(block_type)
                decl.accept(ast_symbol_table_visitor)
                ast_symbol_table_visitor.block_type_stack.pop()

        return decls
Exemplo n.º 10
0
    def replace_inline_expressions_through_defining_expressions(
        cls, definitions: Sequence[ASTOdeEquation],
        inline_expressions: Sequence[ASTInlineExpression]
    ) -> Sequence[ASTOdeEquation]:
        """
        Replaces symbols from `inline_expressions` in `definitions` with corresponding defining expressions from `inline_expressions`.

        :param definitions: A list of ODE definitions (**updated in-place**).
        :param inline_expressions: A list of inline expression definitions.
        :return: A list of updated ODE definitions (same as the ``definitions`` parameter).
        """
        for m in inline_expressions:
            source_position = m.get_source_position()
            for target in definitions:
                matcher = re.compile(
                    cls._variable_matching_template.format(
                        m.get_variable_name()))
                target_definition = str(target.get_rhs())
                target_definition = re.sub(matcher,
                                           "(" + str(m.get_expression()) + ")",
                                           target_definition)
                target.rhs = ModelParser.parse_expression(target_definition)
                target.update_scope(m.get_scope())
                target.accept(ASTSymbolTableVisitor())

                def log_set_source_position(node):
                    if node.get_source_position().is_added_source_position():
                        node.set_source_position(source_position)

                target.accept(
                    ASTHigherOrderVisitor(visit_funcs=log_set_source_position))

        return definitions
Exemplo n.º 11
0
 def test(self):
     for filename in os.listdir(
             os.path.realpath(
                 os.path.join(os.path.dirname(__file__),
                              os.path.join('..', 'models')))):
         if filename.endswith(".nestml"):
             input_file = FileStream(
                 os.path.join(
                     os.path.dirname(__file__),
                     os.path.join(os.path.join('..', 'models'), filename)))
             lexer = PyNestMLLexer(input_file)
             # create a token stream
             stream = CommonTokenStream(lexer)
             stream.fill()
             # parse the file
             parser = PyNestMLParser(stream)
             # process the comments
             compilation_unit = parser.nestMLCompilationUnit()
             # create a new visitor and return the new AST
             ast_builder_visitor = ASTBuilderVisitor(stream.tokens)
             ast = ast_builder_visitor.visit(compilation_unit)
             # update the corresponding symbol tables
             SymbolTable.initialize_symbol_table(ast.get_source_position())
             symbol_table_visitor = ASTSymbolTableVisitor()
             for neuron in ast.get_neuron_list():
                 neuron.accept(symbol_table_visitor)
                 SymbolTable.add_neuron_scope(name=neuron.get_name(),
                                              scope=neuron.get_scope())
             self.assertTrue(isinstance(ast, ASTNestMLCompilationUnit))
     return
Exemplo n.º 12
0
def add_declaration_to_internals(neuron: ASTNeuron, variable_name: str,
                                 init_expression: str) -> ASTNeuron:
    """
    Adds the variable as stored in the declaration tuple to the neuron. The declared variable is of type real.
    :param neuron: a single neuron instance
    :param variable_name: the name of the variable to add
    :param init_expression: initialization expression
    :return: the neuron extended by the variable
    """
    tmp = ModelParser.parse_expression(init_expression)
    vector_variable = ASTUtils.get_vectorized_variable(tmp, neuron.get_scope())

    declaration_string = variable_name + ' real' + (
        '[' + vector_variable.get_vector_parameter() + ']' if
        vector_variable is not None and vector_variable.has_vector_parameter()
        else '') + ' = ' + init_expression
    ast_declaration = ModelParser.parse_declaration(declaration_string)
    if vector_variable is not None:
        ast_declaration.set_size_parameter(
            vector_variable.get_vector_parameter())
    neuron.add_to_internal_block(ast_declaration)
    ast_declaration.update_scope(neuron.get_internals_blocks().get_scope())
    symtable_visitor = ASTSymbolTableVisitor()
    symtable_visitor.block_type_stack.push(BlockType.INTERNALS)
    ast_declaration.accept(symtable_visitor)
    symtable_visitor.block_type_stack.pop()
    return neuron
Exemplo n.º 13
0
 def deconstruct_assignment(cls,
                            lhs=None,
                            is_plus=False,
                            is_minus=False,
                            is_times=False,
                            is_divide=False,
                            _rhs=None):
     """
     From lhs and rhs it constructs a new rhs which corresponds to direct assignment.
     E.g.: a += b*c -> a = a + b*c
     :param lhs: a lhs rhs
     :type lhs: ast_expression or ast_simple_expression
     :param is_plus: is plus assignment
     :type is_plus: bool
     :param is_minus: is minus assignment
     :type is_minus: bool
     :param is_times: is times assignment
     :type is_times: bool
     :param is_divide: is divide assignment
     :type is_divide: bool
     :param _rhs: a rhs rhs
     :type _rhs: ASTExpression or ASTSimpleExpression
     :return: a new direct assignment rhs.
     :rtype: ASTExpression
     """
     from pynestml.visitors.ast_symbol_table_visitor import ASTSymbolTableVisitor
     from pynestml.meta_model.ast_node_factory import ASTNodeFactory
     assert ((is_plus + is_minus + is_times + is_divide) == 1), \
         '(PyNestML.CodeGeneration.Utils) Type of assignment not correctly specified!'
     if is_plus:
         op = ASTNodeFactory.create_ast_arithmetic_operator(
             is_plus_op=True, source_position=_rhs.get_source_position())
     elif is_minus:
         op = ASTNodeFactory.create_ast_arithmetic_operator(
             is_minus_op=True, source_position=_rhs.get_source_position())
     elif is_times:
         op = ASTNodeFactory.create_ast_arithmetic_operator(
             is_times_op=True, source_position=_rhs.get_source_position())
     else:
         op = ASTNodeFactory.create_ast_arithmetic_operator(
             is_div_op=True, source_position=_rhs.get_source_position())
     var_expr = ASTNodeFactory.create_ast_simple_expression(
         variable=lhs, source_position=lhs.get_source_position())
     var_expr.update_scope(lhs.get_scope())
     op.update_scope(lhs.get_scope())
     rhs_in_brackets = ASTNodeFactory.create_ast_expression(
         is_encapsulated=True,
         expression=_rhs,
         source_position=_rhs.get_source_position())
     rhs_in_brackets.update_scope(_rhs.get_scope())
     expr = ASTNodeFactory.create_ast_compound_expression(
         lhs=var_expr,
         binary_operator=op,
         rhs=rhs_in_brackets,
         source_position=_rhs.get_source_position())
     expr.update_scope(lhs.get_scope())
     # update the symbols
     expr.accept(ASTSymbolTableVisitor())
     return expr
Exemplo n.º 14
0
        def replace_var(_expr=None):
            if isinstance(_expr, ASTSimpleExpression) and _expr.is_variable():
                var = _expr.get_variable()
            elif isinstance(_expr, ASTVariable):
                var = _expr
            else:
                return

            if var.get_name() != var_name:
                return

            ast_ext_var = ASTExternalVariable(var.get_name() + suffix,
                                              differential_order=var.get_differential_order(),
                                              source_position=var.get_source_position())
            if alternate_name:
                ast_ext_var.set_alternate_name(alternate_name)

            ast_ext_var.update_alt_scope(new_scope)
            from pynestml.visitors.ast_symbol_table_visitor import ASTSymbolTableVisitor
            ast_ext_var.accept(ASTSymbolTableVisitor())

            if isinstance(_expr, ASTSimpleExpression) and _expr.is_variable():
                Logger.log_message(None, -1, "ASTSimpleExpression replacement made (var = " + str(
                    ast_ext_var.get_name()) + ") in expression: " + str(node.get_parent(_expr)), None, LoggingLevel.INFO)
                _expr.set_variable(ast_ext_var)
                return

            if isinstance(_expr, ASTVariable):
                if isinstance(node.get_parent(_expr), ASTAssignment):
                    node.get_parent(_expr).lhs = ast_ext_var
                    Logger.log_message(None, -1, "ASTVariable replacement made in expression: "
                                       + str(node.get_parent(_expr)), None, LoggingLevel.INFO)
                elif isinstance(node.get_parent(_expr), ASTSimpleExpression) and node.get_parent(_expr).is_variable():
                    node.get_parent(_expr).set_variable(ast_ext_var)
                elif isinstance(node.get_parent(_expr), ASTDeclaration):
                    # variable could occur on the left-hand side; ignore. Only replace if it occurs on the right-hand side.
                    pass
                else:
                    Logger.log_message(None, -1, "Error: unhandled use of variable "
                                       + var_name + " in expression " + str(_expr), None, LoggingLevel.INFO)
                    raise Exception()
                return

            p = node.get_parent(var)
            Logger.log_message(None, -1, "Error: unhandled use of variable "
                               + var_name + " in expression " + str(p), None, LoggingLevel.INFO)
            raise Exception()
Exemplo n.º 15
0
    def deconstruct_compound_assignment(self):
        """
        From lhs and rhs it constructs a new expression which corresponds to direct assignment.
        E.g.: a += b*c -> a = a + b*c
        :return: the rhs for an equivalent direct assignment.
        :rtype: ast_expression
        """
        from pynestml.visitors.ast_symbol_table_visitor import ASTSymbolTableVisitor
        # TODO: get rid of this through polymorphism?
        assert not self.is_direct_assignment, "Can only be invoked on a compound assignment."

        operator = self.extract_operator_from_compound_assignment()
        lhs_variable = self.get_lhs_variable_as_expression()
        rhs_in_brackets = self.get_bracketed_rhs_expression()
        result = self.construct_equivalent_direct_assignment_rhs(
            operator, lhs_variable, rhs_in_brackets)
        # create symbols for the new Expression:
        visitor = ASTSymbolTableVisitor()
        result.accept(visitor)
        return result
Exemplo n.º 16
0
 def add_to_internal_block(self, declaration, index=-1):
     """
     Adds the handed over declaration the internal block
     :param declaration: a single declaration
     :type declaration: ast_declaration
     """
     if self.get_internals_blocks() is None:
         ASTUtils.create_internal_block(self)
     n_declarations = len(self.get_internals_blocks().get_declarations())
     if n_declarations == 0:
         index = 0
     else:
         index = 1 + (index % len(self.get_internals_blocks().get_declarations()))
     self.get_internals_blocks().get_declarations().insert(index, declaration)
     declaration.update_scope(self.get_internals_blocks().get_scope())
     from pynestml.visitors.ast_symbol_table_visitor import ASTSymbolTableVisitor
     symtable_vistor = ASTSymbolTableVisitor()
     symtable_vistor.block_type_stack.push(BlockType.INTERNALS)
     declaration.accept(symtable_vistor)
     symtable_vistor.block_type_stack.pop()
Exemplo n.º 17
0
    def add_to_state_block(self, declaration):
        """
        Adds the handed over declaration to the state block.
        :param declaration: a single declaration.
        :type declaration: ast_declaration
        """
        from pynestml.utils.ast_utils import ASTUtils
        if self.get_state_blocks() is None:
            ASTUtils.create_state_block(self)
        self.get_state_blocks().get_declarations().append(declaration)
        declaration.update_scope(self.get_state_blocks().get_scope())
        from pynestml.visitors.ast_symbol_table_visitor import ASTSymbolTableVisitor

        symtable_vistor = ASTSymbolTableVisitor()
        symtable_vistor.block_type_stack.push(BlockType.STATE)
        declaration.accept(symtable_vistor)
        symtable_vistor.block_type_stack.pop()
        from pynestml.symbols.symbol import SymbolKind
        assert declaration.get_variables()[0].get_scope().resolve_to_symbol(
            declaration.get_variables()[0].get_name(), SymbolKind.VARIABLE) is not None
        assert declaration.get_scope().resolve_to_symbol(declaration.get_variables()[0].get_name(),
                                                         SymbolKind.VARIABLE) is not None
Exemplo n.º 18
0
    def parse_model(cls, file_path=None):
        """
        Parses a handed over model and returns the meta_model representation of it.
        :param file_path: the path to the file which shall be parsed.
        :type file_path: str
        :return: a new ASTNESTMLCompilationUnit object.
        :rtype: ASTNestMLCompilationUnit
        """
        try:
            input_file = FileStream(file_path)
        except IOError:
            code, message = Messages.get_input_path_not_found(path=file_path)
            Logger.log_message(node=None, code=None, message=message,
                               error_position=None, log_level=LoggingLevel.ERROR)
            return
        code, message = Messages.get_start_processing_file(file_path)
        Logger.log_message(node=None, code=code, message=message, error_position=None, log_level=LoggingLevel.INFO)

        # create a lexer and hand over the input
        lexer = PyNestMLLexer()
        lexer.removeErrorListeners()
        lexer.addErrorListener(ConsoleErrorListener())
        lexerErrorListener = NestMLErrorListener()
        lexer.addErrorListener(lexerErrorListener)
        # lexer._errHandler = BailErrorStrategy()  # N.B. uncomment this line and the next to halt immediately on lexer errors
        # lexer._errHandler.reset(lexer)
        lexer.inputStream = input_file
        # create a token stream
        stream = CommonTokenStream(lexer)
        stream.fill()
        if lexerErrorListener._error_occurred:
            code, message = Messages.get_lexer_error()
            Logger.log_message(node=None, code=None, message=message,
                               error_position=None, log_level=LoggingLevel.ERROR)
            return
        # parse the file
        parser = PyNestMLParser(None)
        parser.removeErrorListeners()
        parser.addErrorListener(ConsoleErrorListener())
        parserErrorListener = NestMLErrorListener()
        parser.addErrorListener(parserErrorListener)
        # parser._errHandler = BailErrorStrategy()	# N.B. uncomment this line and the next to halt immediately on parse errors
        # parser._errHandler.reset(parser)
        parser.setTokenStream(stream)
        compilation_unit = parser.nestMLCompilationUnit()
        if parserErrorListener._error_occurred:
            code, message = Messages.get_parser_error()
            Logger.log_message(node=None, code=None, message=message,
                               error_position=None, log_level=LoggingLevel.ERROR)
            return

        # create a new visitor and return the new AST
        ast_builder_visitor = ASTBuilderVisitor(stream.tokens)
        ast = ast_builder_visitor.visit(compilation_unit)

        # create and update the corresponding symbol tables
        SymbolTable.initialize_symbol_table(ast.get_source_position())
        for neuron in ast.get_neuron_list():
            neuron.accept(ASTSymbolTableVisitor())
            SymbolTable.add_neuron_scope(neuron.get_name(), neuron.get_scope())

        # store source paths
        for neuron in ast.get_neuron_list():
            neuron.file_path = file_path
        ast.file_path = file_path

        return ast
Exemplo n.º 19
0
    def parse_model(cls, file_path=None):
        """
        Parses a handed over model and returns the meta_model representation of it.
        :param file_path: the path to the file which shall be parsed.
        :type file_path: str
        :return: a new ASTNESTMLCompilationUnit object.
        :rtype: ASTNestMLCompilationUnit
        """
        try:
            input_file = FileStream(file_path)
        except IOError:
            code, message = Messages.get_input_path_not_found(path=file_path)
            Logger.log_message(neuron=None, code=None, message=message, error_position=None, log_level=LoggingLevel.ERROR)
            return
        code, message = Messages.get_start_processing_file(file_path)
        Logger.log_message(neuron=None, code=code, message=message, error_position=None, log_level=LoggingLevel.INFO)

        # create a lexer and hand over the input
        lexer = PyNestMLLexer()
        lexer.removeErrorListeners()
        lexer.addErrorListener(ConsoleErrorListener())
        lexerErrorListener = NestMLErrorListener()
        lexer.addErrorListener(lexerErrorListener)
        # lexer._errHandler = BailErrorStrategy()  # N.B. uncomment this line and the next to halt immediately on lexer errors
        # lexer._errHandler.reset(lexer)
        lexer.inputStream = input_file
        # create a token stream
        stream = CommonTokenStream(lexer)
        stream.fill()
        if lexerErrorListener._error_occurred:
            code, message = Messages.get_lexer_error()
            Logger.log_message(neuron=None, code=None, message=message, error_position=None, log_level=LoggingLevel.ERROR)
            return
        # parse the file
        parser = PyNestMLParser(None)
        parser.removeErrorListeners()
        parser.addErrorListener(ConsoleErrorListener())
        parserErrorListener = NestMLErrorListener()
        parser.addErrorListener(parserErrorListener)
        # parser._errHandler = BailErrorStrategy()	# N.B. uncomment this line and the next to halt immediately on parse errors
        # parser._errHandler.reset(parser)
        parser.setTokenStream(stream)
        compilation_unit = parser.nestMLCompilationUnit()
        if parserErrorListener._error_occurred:
            code, message = Messages.get_parser_error()
            Logger.log_message(neuron=None, code=None, message=message, error_position=None, log_level=LoggingLevel.ERROR)
            return

        # create a new visitor and return the new AST
        ast_builder_visitor = ASTBuilderVisitor(stream.tokens)
        ast = ast_builder_visitor.visit(compilation_unit)

        # create and update the corresponding symbol tables
        SymbolTable.initialize_symbol_table(ast.get_source_position())
        log_to_restore = copy.deepcopy(Logger.get_log())
        counter = Logger.curr_message

        # replace all derived variables through a computer processable names: e.g. g_in''' -> g_in__ddd
        restore_differential_order = []
        for ode in ASTUtils.get_all(ast, ASTOdeEquation):
            lhs_variable = ode.get_lhs()
            if lhs_variable.get_differential_order() > 0:
                lhs_variable.differential_order = lhs_variable.get_differential_order() - 1
                restore_differential_order.append(lhs_variable)

        for shape in ASTUtils.get_all(ast, ASTOdeShape):
            lhs_variable = shape.get_variable()
            if lhs_variable.get_differential_order() > 0:
                lhs_variable.differential_order = lhs_variable.get_differential_order() - 1
                restore_differential_order.append(lhs_variable)

        # than replace remaining variables
        for variable in ASTUtils.get_all(ast, ASTVariable):
            if variable.get_differential_order() > 0:
                variable.set_name(variable.get_name() + "__" + "d" * variable.get_differential_order())
                variable.differential_order = 0

        # now also equations have no ' at lhs. replace every occurrence of last d to ' to compensate
        for ode_variable in restore_differential_order:
            ode_variable.differential_order = 1
        Logger.set_log(log_to_restore, counter)
        for neuron in ast.get_neuron_list():
            neuron.accept(ASTSymbolTableVisitor())
            SymbolTable.add_neuron_scope(neuron.get_name(), neuron.get_scope())
        return ast
Exemplo n.º 20
0
    def setup_generation_helpers(self, neuron: ASTNeuron) -> Dict:
        """
        Returns a standard namespace with often required functionality.
        :param neuron: a single neuron instance
        :type neuron: ASTNeuron
        :return: a map from name to functionality.
        :rtype: dict
        """
        gsl_converter = GSLReferenceConverter()
        gsl_printer = UnitlessExpressionPrinter(gsl_converter)
        # helper classes and objects
        converter = NESTReferenceConverter(False)
        unitless_pretty_printer = UnitlessExpressionPrinter(converter)

        namespace = dict()

        namespace['neuronName'] = neuron.get_name()
        namespace['neuron'] = neuron
        namespace['moduleName'] = FrontendConfiguration.get_module_name()
        namespace['printer'] = NestPrinter(unitless_pretty_printer)
        namespace['assignments'] = NestAssignmentsHelper()
        namespace['names'] = NestNamesConverter()
        namespace['declarations'] = NestDeclarationsHelper()
        namespace['utils'] = ASTUtils()
        namespace['idemPrinter'] = UnitlessExpressionPrinter()
        namespace['outputEvent'] = namespace['printer'].print_output_event(
            neuron.get_body())
        namespace['is_spike_input'] = ASTUtils.is_spike_input(
            neuron.get_body())
        namespace['is_current_input'] = ASTUtils.is_current_input(
            neuron.get_body())
        namespace['odeTransformer'] = OdeTransformer()
        namespace['printerGSL'] = gsl_printer
        namespace['now'] = datetime.datetime.utcnow()
        namespace['tracing'] = FrontendConfiguration.is_dev

        namespace[
            'PredefinedUnits'] = pynestml.symbols.predefined_units.PredefinedUnits
        namespace[
            'UnitTypeSymbol'] = pynestml.symbols.unit_type_symbol.UnitTypeSymbol

        namespace['initial_values'] = {}
        namespace['uses_analytic_solver'] = neuron.get_name() in self.analytic_solver.keys() \
            and self.analytic_solver[neuron.get_name()] is not None
        if namespace['uses_analytic_solver']:
            namespace['analytic_state_variables'] = self.analytic_solver[
                neuron.get_name()]["state_variables"]
            namespace['analytic_variable_symbols'] = {
                sym:
                neuron.get_equations_block().get_scope().resolve_to_symbol(
                    sym, SymbolKind.VARIABLE)
                for sym in namespace['analytic_state_variables']
            }
            namespace['update_expressions'] = {}
            for sym, expr in self.analytic_solver[
                    neuron.get_name()]["initial_values"].items():
                namespace['initial_values'][sym] = expr
            for sym in namespace['analytic_state_variables']:
                expr_str = self.analytic_solver[
                    neuron.get_name()]["update_expressions"][sym]
                expr_ast = ModelParser.parse_expression(expr_str)
                # pretend that update expressions are in "equations" block, which should always be present, as differential equations must have been defined to get here
                expr_ast.update_scope(
                    neuron.get_equations_blocks().get_scope())
                expr_ast.accept(ASTSymbolTableVisitor())
                namespace['update_expressions'][sym] = expr_ast

            namespace['propagators'] = self.analytic_solver[
                neuron.get_name()]["propagators"]

        namespace['uses_numeric_solver'] = neuron.get_name() in self.analytic_solver.keys() \
            and self.numeric_solver[neuron.get_name()] is not None
        if namespace['uses_numeric_solver']:
            namespace['numeric_state_variables'] = self.numeric_solver[
                neuron.get_name()]["state_variables"]
            namespace['numeric_variable_symbols'] = {
                sym:
                neuron.get_equations_block().get_scope().resolve_to_symbol(
                    sym, SymbolKind.VARIABLE)
                for sym in namespace['numeric_state_variables']
            }
            assert not any([
                sym is None
                for sym in namespace['numeric_variable_symbols'].values()
            ])
            namespace['numeric_update_expressions'] = {}
            for sym, expr in self.numeric_solver[
                    neuron.get_name()]["initial_values"].items():
                namespace['initial_values'][sym] = expr
            for sym in namespace['numeric_state_variables']:
                expr_str = self.numeric_solver[
                    neuron.get_name()]["update_expressions"][sym]
                expr_ast = ModelParser.parse_expression(expr_str)
                # pretend that update expressions are in "equations" block, which should always be present, as differential equations must have been defined to get here
                expr_ast.update_scope(
                    neuron.get_equations_blocks().get_scope())
                expr_ast.accept(ASTSymbolTableVisitor())
                namespace['numeric_update_expressions'][sym] = expr_ast

            namespace['useGSL'] = namespace['uses_numeric_solver']
            namespace['names'] = GSLNamesConverter()
            converter = NESTReferenceConverter(True)
            unitless_pretty_printer = UnitlessExpressionPrinter(converter)
            namespace['printer'] = NestPrinter(unitless_pretty_printer)

        namespace["spike_updates"] = neuron.spike_updates

        rng_visitor = ASTRandomNumberGeneratorVisitor()
        neuron.accept(rng_visitor)
        namespace['norm_rng'] = rng_visitor._norm_rng_is_used

        return namespace