def _parse_variables(self):
     for ix, (sv_id, sv) in enumerate(self.scope_variables.items()):
         full_tag = d_u(sv.id)
         self.values_order[full_tag] = ix
         self._parse_variable(full_tag, sv, sv_id)
     for ix, (sv_id, sv) in enumerate(self.temporary_variables.items()):
         full_tag = d_u(sv.id)
         self._parse_variable(full_tag, sv, sv_id)
Beispiel #2
0
    def create_assignments(self, variables):
        from tqdm import tqdm
        temp_variables = {}
        for ii, n in tqdm(
                enumerate(
                    self.get_where_node_attr('node_type',
                                             NodeTypes.EQUATION))):
            for i, e in self.get_edges_for_node(start_node=n):
                va = e[1].copy()
                if va in self.vars_assignments and len(
                        self.vars_assignments[va]) > 1:
                    # Make new temp var
                    sv = self.get(e[1], 'scope_var')
                    tmp_key = sv.tag + str(self.key_map[va]) + '_tmp'
                    tmp_label = sv.tag + variables[str(
                        self.key_map[va])].path.primary_path + '_tmp'
                    # Create fake scope variables for tmp setvar
                    fake_sv = {}
                    svf = None
                    if isinstance(sv, SetOfVariables):
                        tmp_var_counter = 0
                        tsv = TemporarySetVar(tmp_key, sv)
                        for svi in sv.variables.values():
                            tmp_var_counter += 1
                            svf = TemporaryVar(
                                'tmp_var_' + str(tmp_var_counter), svi,
                                svi.tag + '_' + str(sv.id), svi.set_var,
                                svi.set_var_ix)
                            tsv.tmp_vars.append(svf)
                        fake_sv[tsv.id] = tsv
                    else:
                        svf = TemporaryVar(d_u(tmp_key), sv, tmp_key, None,
                                           None)
                        fake_sv[d_u(svf.get_path_dot())] = svf

                    temp_variables.update(fake_sv)

                    tmp = self.add_node(Node(key=tmp_key,
                                             node_type=NodeTypes.TMP,
                                             name=tmp_key,
                                             file='sum',
                                             label=tmp_label,
                                             ln=0,
                                             scope_var=svf),
                                        ignore_existing=False)
                    # Add temp var to Equation target

                    self.add_edge(
                        Edge(n,
                             tmp,
                             e_type=EdgeType.TARGET,
                             arg_local=self.edges_c[i[0]].arg_local))
                    # Add temp var in var assignments

                    self.vars_assignments_mappings[va][(
                        nix := self.vars_assignments[va].index(n))] = ':'
                    self.vars_assignments[va][nix] = tmp
        return temp_variables
    def __init__(self,
                 filename,
                 equation_graph,
                 scope_variables,
                 equations,
                 scoped_equations,
                 temporary_variables,
                 system_tag="",
                 use_llvm=True,
                 imports=None):
        self.filename = filename
        self.imports = imports
        self.system_tag = system_tag
        self.scope_variables = scope_variables
        self.set_variables = {}
        self.states = []
        self.deriv = []

        for ix, (sv_id, sv) in enumerate(self.scope_variables.items()):
            full_tag = d_u(sv.id)
            if sv.type == VariableType.STATE:
                self.states.append(full_tag)
            elif sv.type == VariableType.DERIVATIVE:
                self.deriv.append(full_tag)

        for k, var in temporary_variables.items():
            if var.type == VariableType.TMP_PARAMETER_SET:
                self.set_variables.update({k: var})
                new_sv = {}
                tail = {}
                for k, v in self.scope_variables.items():
                    if k in var.set_var.variables:
                        tail.update({k: v})
                        new_sv.update({
                            var.tmp_vars[v.set_var_ix].id:
                            var.tmp_vars[v.set_var_ix]
                        })
                    else:
                        new_sv.update({k: v})
                self.scope_variables = dict(new_sv, **tail)
            if var.type == VariableType.TMP_PARAMETER:
                new_sv = {}
                tail = {}
                for k, v in self.scope_variables.items():
                    if k == var.scope_var_id:
                        tail.update({k: v})
                        new_sv.update({var.id: var})
                    else:
                        new_sv.update({k: v})
                self.scope_variables = dict(new_sv, **tail)

        self.scoped_equations = scoped_equations
        self.temporary_variables = temporary_variables

        self.values_order = {}

        self.scope_var_node = {}
        self.scalar_variables = {}

        self._parse_variables()

        # Sort the graph topologically to start generating code
        self.topo_sorted_nodes = equation_graph.topological_nodes()
        self.equation_graph = equation_graph.clean()

        self.number_of_states = len(self.states)
        self.number_of_derivatives = len(self.deriv)

        # Initialize llvm builder - will be a list of intermediate llvm instructions to be lowered in generate
        self.llvm = use_llvm
        if self.llvm:
            self.generated_program = LLVMBuilder(np.ascontiguousarray(
                [x.value for x in self.scope_variables.values()],
                dtype=np.float64),
                                                 self.values_order,
                                                 self.states,
                                                 self.deriv,
                                                 system_tag=self.system_tag)
        else:
            self.generated_program = ASTBuilder(np.ascontiguousarray(
                [x.value for x in self.scope_variables.values()],
                dtype=np.float64),
                                                self.values_order,
                                                self.states,
                                                self.deriv,
                                                system_tag=self.system_tag)

        self.mod_body = []
        # Create a kernel of assignments and calls

        self.eq_vardefs = {}
        # Loop over equation functions and generate code for each equation.
        self._parse_equations(equations)

        self.all_targeted = []
        self.all_read = []
        self.all_targeted_set_vars = []
        self.all_read_set_vars = []
class EquationGenerator:
    def __init__(self,
                 filename,
                 equation_graph,
                 scope_variables,
                 equations,
                 scoped_equations,
                 temporary_variables,
                 system_tag="",
                 use_llvm=True,
                 imports=None):
        self.filename = filename
        self.imports = imports
        self.system_tag = system_tag
        self.scope_variables = scope_variables
        self.set_variables = {}
        self.states = []
        self.deriv = []

        for ix, (sv_id, sv) in enumerate(self.scope_variables.items()):
            full_tag = d_u(sv.id)
            if sv.type == VariableType.STATE:
                self.states.append(full_tag)
            elif sv.type == VariableType.DERIVATIVE:
                self.deriv.append(full_tag)

        for k, var in temporary_variables.items():
            if var.type == VariableType.TMP_PARAMETER_SET:
                self.set_variables.update({k: var})
                new_sv = {}
                tail = {}
                for k, v in self.scope_variables.items():
                    if k in var.set_var.variables:
                        tail.update({k: v})
                        new_sv.update({
                            var.tmp_vars[v.set_var_ix].id:
                            var.tmp_vars[v.set_var_ix]
                        })
                    else:
                        new_sv.update({k: v})
                self.scope_variables = dict(new_sv, **tail)
            if var.type == VariableType.TMP_PARAMETER:
                new_sv = {}
                tail = {}
                for k, v in self.scope_variables.items():
                    if k == var.scope_var_id:
                        tail.update({k: v})
                        new_sv.update({var.id: var})
                    else:
                        new_sv.update({k: v})
                self.scope_variables = dict(new_sv, **tail)

        self.scoped_equations = scoped_equations
        self.temporary_variables = temporary_variables

        self.values_order = {}

        self.scope_var_node = {}
        self.scalar_variables = {}

        self._parse_variables()

        # Sort the graph topologically to start generating code
        self.topo_sorted_nodes = equation_graph.topological_nodes()
        self.equation_graph = equation_graph.clean()

        self.number_of_states = len(self.states)
        self.number_of_derivatives = len(self.deriv)

        # Initialize llvm builder - will be a list of intermediate llvm instructions to be lowered in generate
        self.llvm = use_llvm
        if self.llvm:
            self.generated_program = LLVMBuilder(np.ascontiguousarray(
                [x.value for x in self.scope_variables.values()],
                dtype=np.float64),
                                                 self.values_order,
                                                 self.states,
                                                 self.deriv,
                                                 system_tag=self.system_tag)
        else:
            self.generated_program = ASTBuilder(np.ascontiguousarray(
                [x.value for x in self.scope_variables.values()],
                dtype=np.float64),
                                                self.values_order,
                                                self.states,
                                                self.deriv,
                                                system_tag=self.system_tag)

        self.mod_body = []
        # Create a kernel of assignments and calls

        self.eq_vardefs = {}
        # Loop over equation functions and generate code for each equation.
        self._parse_equations(equations)

        self.all_targeted = []
        self.all_read = []
        self.all_targeted_set_vars = []
        self.all_read_set_vars = []

    def _parse_variable(self, full_tag, sv, sv_id):

        if full_tag not in self.scope_var_node:
            self.scope_var_node[full_tag] = sv

        # If a scope_variable is part of a set it should be referenced alone
        if sv.set_var:
            if not sv.set_var.id in self.set_variables:
                self.set_variables[sv.set_var.id] = sv.set_var
        else:
            self.scalar_variables[full_tag] = sv

    def _parse_variables(self):
        for ix, (sv_id, sv) in enumerate(self.scope_variables.items()):
            full_tag = d_u(sv.id)
            self.values_order[full_tag] = ix
            self._parse_variable(full_tag, sv, sv_id)
        for ix, (sv_id, sv) in enumerate(self.temporary_variables.items()):
            full_tag = d_u(sv.id)
            self._parse_variable(full_tag, sv, sv_id)

    def get_external_function_name(self, ext_func):
        if self.llvm:
            return self._llvm_func_name(ext_func)
        return ext_func

    def _llvm_func_name(self, ext_func):
        return ext_func + '_llvm1.<locals>.' + ext_func + '_llvm'

    def _parse_equations(self, equations):
        logging.info('make equations for compilation')
        for eq_key, eq in equations.items():
            vardef = Vardef(llvm=self.llvm)

            eq[2].lower_graph = None
            if self.llvm:
                func_llvm, signature, args, target_ids = compiled_function_from_graph_generic_llvm(
                    eq[2],
                    imports=self.imports,
                    var_def_=Vardef(llvm=self.llvm),
                    compiled_function=True)
                self.generated_program.add_external_function(
                    func_llvm, signature, len(args), target_ids)
            else:
                func, args, target_ids = function_from_graph_generic(
                    eq[2], var_def_=vardef, arg_metadata=eq[2].arg_metadata)
                self.generated_program.add_external_function(
                    func, None, len(args), target_ids)

            vardef.llvm_target_ids = target_ids
            vardef.args_order = args
            self.eq_vardefs[eq_key] = vardef

    def search_in_item_scope(self, var_id, item_id):
        for var in self.scope_variables.values():
            ##TODO add namespacecheck
            if var.item.id == item_id and var.tag == self.scope_variables[
                    var_id].tag:
                return var.id
        raise ValueError("No variable found for id {}", var_id)

    def _process_equation_node(self, n):

        eq_key = self.scoped_equations[self.equation_graph.key_map[n]]

        # Define the function to call for this eq
        ext_func = recurse_Attribute(self.equation_graph.get(n, 'func'))
        item_id = self.equation_graph.get(n, 'item_id')

        vardef = self.eq_vardefs[eq_key]

        # Find the arguments by looking for edges of arg type
        a_indcs, a_edges = list(
            self.equation_graph.get_edges_for_node_filter(
                end_node=n, attr='e_type', val=EdgeType.ARGUMENT))
        # Determine the local arguments names
        args_local = [
            self.equation_graph.key_map[ae[0]]
            for i, ae in zip(a_indcs, a_edges)
            if not self.equation_graph.edges_c[i].arg_local == 'local'
        ]

        # Determine the local arguments names
        args_scope_var = [
            self.equation_graph.edges_c[i].arg_local
            for i, ae in zip(a_indcs, a_edges)
            if not self.equation_graph.edges_c[i].arg_local == 'local'
        ]

        # Find the targets by looking for target edges
        t_indcs, t_edges = list(
            self.equation_graph.get_edges_for_node_filter(start_node=n,
                                                          attr='e_type',
                                                          val=EdgeType.TARGET))
        targets_local = [
            self.equation_graph.key_map[te[1]]
            for i, te in zip(t_indcs, t_edges)
            if not self.equation_graph.edges_c[i].arg_local == 'local'
        ]
        targets_scope_var = [
            self.equation_graph.edges_c[i].arg_local
            for i, ae in zip(t_indcs, t_edges)
            if not self.equation_graph.edges_c[i].arg_local == 'local'
        ]
        set_size = 0
        # Record targeted and read variables
        if self.equation_graph.get(n, 'vectorized'):

            # Map of scope.?? vars and set variable names
            scope_vars = {
                'scope.' + self.set_variables[k].tag: v
                for k, v in zip(args_scope_var +
                                targets_scope_var, args_local + targets_local)
            }

            # Put the information of args and targets in the scope_var attr of the graph node for those equation
            self.equation_graph.nodes[n].scope_var = {
                'args': [scope_vars[a] for a in vardef.args],
                'targets': [scope_vars[a] for a in vardef.targets]
            }
            # Record all targeted variables
            for t in vardef.targets:
                self.all_targeted_set_vars.append(scope_vars[t])
                ##TODO check that they all the same size
                set_size = self.set_variables[scope_vars[t]].get_size()
            # Record all read variables
            for a in vardef.args:
                self.all_read_set_vars.append(scope_vars[a])
        else:
            # Map of scope.?? vars and global-scope variable names
            scope_vars = {
                'scope.' + self.scope_variables[k].tag: v
                for k, v in zip(args_scope_var +
                                targets_scope_var, args_local + targets_local)
            }

            # Put the information of args and targets in the scope_var attr of the graph node for those equation
            self.equation_graph.nodes[n].scope_var = {
                'args': [scope_vars[a] for a in vardef.args],
                'targets': [scope_vars[a] for a in vardef.targets]
            }
            for a in vardef.args:
                if (sva := scope_vars[a]) in self.set_variables:
                    self.all_read_set_vars.append(sva)
                else:
                    self.all_read.append(sva)

            self.all_targeted += [scope_vars[t] for t in vardef.targets]

        # Generate ast for this equation callcompiled_function_from_graph_generic_llvm
        if self.equation_graph.get(n, 'vectorized'):

            llvm_args = []
            for t in vardef.args_order:
                llvm_args_ = []
                set_var = self.set_variables[scope_vars[t]]
                for i in range(set_var.get_size()):
                    llvm_args_.append(set_var.get_var_by_idx(i).id)
                llvm_args.append(llvm_args_)
            ##reshape to correct format
            llvm_args = [list(x) for x in zip(*llvm_args)]
            self.generated_program.add_set_call(
                self.get_external_function_name(ext_func), llvm_args,
                vardef.llvm_target_ids)
        else:
            # Generate llvm arguments
            args = []

            for a in vardef.args_order:
                if a in scope_vars:
                    args.append(d_u(scope_vars[a]))
                else:
                    args.append(self.search_in_item_scope(a, item_id))

            # Add this eq to the llvm_program
            self.generated_program.add_call(
                self.get_external_function_name(ext_func), args,
                vardef.llvm_target_ids)
                                    self.equation_graph.key_map[t]])):
                            target_indcs_map[mi].append((v[0], mi))
                    else:
                        target_indcs_map[0].append((v[0], None))
                else:
                    for mi in maps:
                        target_indcs_map[mi[1] if mi[1] else 0].append(
                            (v[0], mi[0]))

            target_var = self.equation_graph.key_map[t]

            # Generate llvm/ast
            mapping_dict = {}
            for values in target_indcs_map:
                for v in values:
                    var_name = d_u(self.equation_graph.key_map[v[0]])
                    if var_name in self.scope_variables:
                        if target_var in mapping_dict:
                            mapping_dict[target_var].append(var_name)
                        else:
                            mapping_dict[target_var] = [var_name]
                    else:
                        if var_name in self.set_variables:
                            if var_name in mapping_dict:
                                mapping_dict[target_var].append(
                                    self.set_variables[var_name].
                                    get_var_by_idx(v[1]).id)
                            else:
                                mapping_dict[target_var] = [
                                    self.set_variables[var_name].
                                    get_var_by_idx(v[1]).id