示例#1
0
 def __init__(self, name):
     self.name = name
     self._imported_modules: List[Module] = []
     self._io: List[ModuleIO] = []
     self.FIG = FluidInteractionGraph()
     self.fluids = dict()
     self.mappings: List[ExplicitMapping] = []
示例#2
0
 def __init__(self, name):
     self.name = name
     self._imported_modules: List[Module] = []
     self._io: List[ModuleIO] = []
     self.FIG = FluidInteractionGraph()
     self.fluids = dict()
     self._mappings: List[NodeMappingTemplate] = []
示例#3
0
    def generate_and_annotations(self, fig: FluidInteractionGraph) -> None:
        m = self._connectivity_matrix
        shape = m.shape
        n_cols = shape[1]

        # Find all the different columns which are equal
        all_candidates = []
        skip_list = []
        for i in range(n_cols):
            candidate = []
            candidate.append(self.get_fig(i))
            found_flag = False
            if i in skip_list:
                continue
            for j in range(i + 1, n_cols):
                if j in skip_list:
                    continue

                col_i = m[:, i]
                col_j = m[:, j]
                if np.array_equal(col_i, col_j):
                    skip_list.append(i)
                    skip_list.append(j)
                    candidate.append(self.get_edge(j))
                    found_flag = True

            if found_flag is True:
                all_candidates.append(candidate)

        print(all_candidates)
        # Generate all the different AND annotations necessary
        for candidate in all_candidates:
            for edge in candidate:
                # TODO - Figure out if the edge needs any additional markup here
                source_node = fig.get_fignode(edge[0])
                target_node = fig.get_fignode(edge[1])
                if source_node is None:
                    raise Exception(
                        "Could not find the corresponding nodes {}".format(
                            source_node))
                if target_node is None:
                    raise Exception(
                        "could not find the corresponding nodes {}".format(
                            target_node))
                fig.connect_fignodes(source_node, target_node)

            origin_nodes = [fig.get_fignode(edge[0]) for edge in candidate]
            print("Added AND annotation on FIG: {}".format(str(origin_nodes)))
            assert (origin_nodes is not None)
            annotation = fig.add_and_annotation(origin_nodes)
            self._and_annotations.append(annotation)
示例#4
0
 def generate_not_annotations(self, fig: FluidInteractionGraph) -> None:
     m = self._connectivity_matrix
     shape = m.shape
     n_cols = shape[1]
     annotated_edges = self._annotated_connectivity_edges
     # Pick whatever single connectivity descriptions are left in this design
     for i in range(n_cols):
         edge = self.get_connectivity_edge(i)
         if edge not in annotated_edges:
             source_node = fig.get_fignode(edge[0])
             target_node = fig.get_fignode(edge[1])
             print("Found new NOT-DISTRIBUTE Candidate : {} -> {}".format(
                 edge[0], edge[1]))
             fig.connect_fignodes(source_node, target_node)
             annotation = fig.add_not_annotation([source_node, target_node])
             self._not_annotations.append(annotation)
示例#5
0
    def split_cn(
        self,
        cn_to_split: ConstructionNode,
        split_groups: List[Set[str]],
        fig: FluidInteractionGraph,
    ) -> None:
        """This method splits the construction node into multiple pieces.
        This is driven by the lists of strings holding the FIG node id's.
        It put each list of ID's in the split_groups variable into individual
        construction nodes.

        WARNING ! - Generates CN edges only between the new CN's

        In addition to splitting up the node, the method also creates edges
        between all the nodes based on how the FIG subgraph is connected

        Args:
            cn_to_split (ConstructionNode): Construction node that needs to be split into multiple nodes
            split_groups (List[List[str]]): A list of lists where each list should contain the FIG node IDs that neet to be in differnt nodes
        """
        name = cn_to_split.id
        fig_nodes = []
        for nodes in split_groups:
            fig_nodes.extend(nodes)
        full_subgraph = fig.subgraph(fig_nodes)
        for group_index in range(len(split_groups)):
            split_group = split_groups[group_index]
            fig_subgraph = fig.subgraph(split_group)
            cn = ConstructionNode("{}_split_{}".format(name, group_index))
            # Copy all the mapping options but have a differet fig_subgraph
            for mapping_option in cn_to_split.mapping_options:
                # TODO = Figure out what kind of a network mapping I need to get for this
                mapping_copy = copy(mapping_option)
                mapping_copy.fig_subgraph = fig_subgraph
                cn.add_mapping_option(mapping_option)

            self.add_construction_node(cn)

        # Delete the node now
        self.delete_node(cn_to_split.id)

        # TODO - create connections between the cns based on the figs
        self.generate_edges(full_subgraph)

        raise NotImplementedError()
示例#6
0
    def generate_or_annotations(self, fig: FluidInteractionGraph) -> None:

        m = self._connectivity_matrix
        shape = m.shape
        n_rows = shape[0]
        # n_cols = shape[1]

        all_candidates = []
        skip_list = []
        for i in range(n_rows):
            candidate_row_index = [i]
            accumulate_vector = m[i, :]
            ones_count = self.__ones_count(accumulate_vector)
            found_flag = False
            if i in skip_list:
                continue
            for j in range(i + 1, n_rows):
                if j in skip_list:
                    continue
                # Compute XOR and see if the hamming distance is
                # row_i = m[i, :]
                row_j = m[j, :]

                # distance = self.__hamming_distance(row_i, row_c)
                # if distance != 2:
                #     continue

                # TODO - Go through the rows, see if the row-i and row-j
                # compute the XOR of the current vector with the accumulate
                xord_vector = np.logical_xor(accumulate_vector, row_j)
                distance = self.__hamming_distance(xord_vector,
                                                   accumulate_vector)
                count = self.__ones_count(xord_vector)

                if distance == 1 and count == ones_count + 1:
                    candidate_row_index.append(j)
                    accumulate_vector = xord_vector
                    ones_count = count
                    skip_list.append(j)
                    found_flag = True

            if found_flag:
                all_candidates.append(candidate_row_index)

        print(all_candidates)
        # Generate all the different OR annotations necessary

        # Figure out how to process the candidates:
        # We should be able to go through each row,
        # figure out if the row's->positive's->source are in any of the AND annotations
        # if they are pick up the AND annotation node as one of the targets
        # else (is not present in AND annotation) pick up the positive's corresponding
        # flow node as one of the targets for the or annotation
        for candidate in all_candidates:
            args_for_annotation = []
            for row_index in candidate:
                row = m[row_index, :]
                for i in range(len(row)):
                    if row[i] == 1:
                        # Find the corresponding collumn edge:
                        edge = self.get_edge(i)
                        # First make a connection so that this is taken care or
                        source_node = fig.get_fignode(edge[0])
                        target_node = fig.get_fignode(edge[1])
                        fig.connect_fignodes(source_node, target_node)

                        # Add the connection target in inot the annotion targets we want
                        # this representated for the entire converage
                        target = edge[1]
                        args_for_annotation.append(fig.get_fignode(target))
                        # Check if the source is in any of the AND annotations
                        source = edge[0]
                        found_flag = False
                        annotation_to_use = None
                        for annotation in self._and_annotations:
                            if source in fig.neighbors(annotation.id):
                                found_flag = True
                                annotation_to_use = fig.get_fignode(
                                    annotation.id)
                                break
                        if found_flag is True:
                            if annotation_to_use not in args_for_annotation:
                                args_for_annotation.append(annotation_to_use)
                        else:
                            if source not in args_for_annotation:
                                args_for_annotation.append(
                                    fig.get_fignode(source))

            self._or_annotations.append(
                fig.add_or_annotation(args_for_annotation))
示例#7
0
def override_network_mappings(
    mappings: List[NodeMappingTemplate],
    mapping_library: MappingLibrary,
    fig: FluidInteractionGraph,
    construction_graph: ConstructionGraph,
) -> None:
    # Go through the entire set of mappings in the FIG and generate / append the mapping options
    # Step 1 - Loop through each of the mappingtemplates
    # Step 2 - Loop through each of the instances in teh mappingtemplate
    # Step 3 - Find the cn associated with each of the fig nodes and override the explicit mapping if mappingtemplate has an associated technology string
    assign_node_index = 0
    for mapping in mappings:
        for instance in mapping.instances:

            primitive_to_use = None
            if mapping.technology_string is not None:
                # Create a mapping option from the library with the corresponding info
                try:
                    primitive_to_use = mapping_library.get_primitive(
                        mapping.technology_string)
                except Exception:
                    print(
                        "Could not find primitive with technology: {}".format(
                            mapping.technology_string))
                    exit(-100)

            node_ids = []
            cn = None  # Get the right construction node for doing the stuff
            cn_mapping_options = []

            if isinstance(instance, NetworkMapping):
                print("Applying Network Mapping: \n Input - {} \n Output - {}".
                      format(
                          ",".join([n.id for n in instance.input_nodes]),
                          ",".join([n.id for n in instance.output_nodes]),
                      ))

                node_ids.extend(n.id for n in instance.input_nodes)
                node_ids.extend(n.id for n in instance.output_nodes)
                subgraph = fig.subgraph(node_ids)
                # try:
                #     # TODO - Incase this is a flow-flow candidate, we need to get the
                #     # cn corresponding to this mapping.
                #     # TODO - do we need to have a new flow node constructed

                #     cn = construction_graph.get_subgraph_cn(subgraph)
                # except Exception as e:
                #     # Incase we cannot find a corresponding construction node,
                #     # we need to create a new construction node
                #     print(e)
                #     cn = ConstructionNode("assign_{}".format(assign_node_index))
                #     # Increment the index of the assign construction node
                #     assign_node_index += 1

                #     # Find the cn's associated with the input nodes
                #     input_cns = []
                #     output_cns = []
                #     for fig_node in instance.input_nodes:
                #         cn_temp = construction_graph.get_fignode_cn(fig_node)
                #         if cn_temp not in input_cns:
                #             input_cns.append(cn_temp)
                #     for fig_node in instance.output_nodes:
                #         cn_temp = construction_graph.get_fignode_cn(fig_node)
                #         if cn_temp not in output_cns:
                #             output_cns.append(cn_temp)

                #     # split_groups = []
                #     # # TODO - If we need to split the we first are gonna make a copy
                #     # # of the subgraph and then delete any edges between the inputs
                #     # # and the outputs
                #     # subgraph_copy = deepcopy(subgraph)
                #     # # Delete any edges between inputs and outputs
                #     # for input_node in instance.input_nodes:
                #     #     for output_node in instance.output_nodes:
                #     #         if subgraph_copy.has_edge(input_node.id, output_node.id):
                #     #             subgraph_copy.remove_edge(input_node.id, output_node.id)

                #     # components = subgraph_copy.connected_components()
                #     # for component in components:
                #     #     split_groups.append(list(component.nodes))

                #     # TODO - If inputcns and output cns are the same, we split them
                #     for input_cn in input_cns:
                #         if input_cn in output_cns:
                #             split_groups = generate_split_groups(
                #                 input_cn.mapping_options[0].fig_subgraph, instance
                #             )
                #             construction_graph.split_cn(input_cn, split_groups, fig)
                #     # Now insert the node
                #     construction_graph.insert_cn(cn, input_cns, output_cns)

                # # Check to see if this works or not
                # cn = construction_graph.get_subgraph_cn(subgraph)

                # Find the cn's associated with the input nodes
                input_cns = []
                output_cns = []
                for fig_node in instance.input_nodes:
                    cn_temp = construction_graph.get_fignode_cn(fig_node)
                    if cn_temp not in input_cns:
                        input_cns.append(cn_temp)
                for fig_node in instance.output_nodes:
                    cn_temp = construction_graph.get_fignode_cn(fig_node)
                    if cn_temp not in output_cns:
                        output_cns.append(cn_temp)

                cn = ConstructionNode("assign_{}".format(assign_node_index))
                assign_node_index += 1
                mapping_option = NetworkMappingOption(
                    network_primitive=primitive_to_use,
                    mapping_type=NetworkMappingOptionType.
                    COMPONENT_REPLACEMENT,
                    subgraph_view=subgraph,
                )
                cn.use_explicit_mapping(mapping_option)
                construction_graph.insert_cn(cn, input_cns, output_cns, fig)
            else:
                continue
            # Now that we know what the mapping options are (either explicit
            # loaded from the library, we can add the performance constraints)
            for mapping_option in cn_mapping_options:
                # Add all the constraints to the mapping_option
                cn.constraints.extend(mapping.constraints)
示例#8
0
def override_mappings(
    mappings: List[NodeMappingTemplate],
    mapping_library: MappingLibrary,
    fig: FluidInteractionGraph,
    construction_graph: ConstructionGraph,
) -> None:
    # Go through the entire set of mappings in the FIG and generate / append the mapping options
    # Step 1 - Loop through each of the mappingtemplates
    # Step 2 - Loop through each of the instances in teh mappingtemplate
    # Step 3 - Find the cn associated with each of the fig nodes and override the explicit mapping if mappingtemplate has an associated technology string
    assign_node_index = 0
    for mapping in mappings:
        for instance in mapping.instances:

            primitive_to_use = None
            if mapping.technology_string is not None:
                # Create a mapping option from the library with the corresponding info
                primitive_to_use = mapping_library.get_primitive(
                    mapping.technology_string)

            node_ids = []
            cn = None  # Get the right construction node for doing the stuff
            cn_mapping_options = []

            if isinstance(instance, NetworkMapping):
                print("Skipping Network Mapping: \n Input - {} \n Output - {}".
                      format(
                          ",".join([n.id for n in instance.input_nodes]),
                          ",".join([n.id for n in instance.output_nodes]),
                      ))
                continue
            else:
                print("Applying Network Mapping: \n Nodes - {}".format(
                    instance.node))

                # Find the construction node assicated with the
                # FIG node and then do the followinging:
                # Step 1 - If the mappingtemplate has no technology string assiciated
                # with the mapping, just apply the constraints to the associated mapping
                # options

                # Step 2 - In there is a string assiciated with the mappingtemplate, we
                # eliminate all mapping options that dont have a matching string / generate
                # a mapping option with the corresponding

                # In the case of an Fluid Value interaction put all valuenodes in the subgraph
                node_ids.extend([
                    fig.get_fignode(edge[0]).id
                    for edge in fig.in_edges(instance.node.id)
                    if isinstance(fig.get_fignode(edge[0]), ValueNode)
                ])
                node_ids.append(instance.node.id)
                subgraph = fig.subgraph(node_ids)

                # Get the Construction node that has the corresponding subgraph,
                # and then replace the mapping option
                cn = construction_graph.get_subgraph_cn(subgraph)
                if primitive_to_use is not None:
                    mapping_option = MappingOption(primitive_to_use, subgraph)
                    cn.use_explicit_mapping(mapping_option)
                    cn_mapping_options.append(mapping_option)
                else:
                    # Add the constraints to all the mapping options
                    # This is an example where since no explicit mapping
                    # was specified, we only add the performance/material
                    # constraints. This can be ulitized for whittling down
                    # options later if necessary.
                    cn_mapping_options.extend(cn.mapping_options)

            # Now that we know what the mapping options are (either explicit
            # loaded from the library, we can add the performance constraints)
            for mapping_option in cn_mapping_options:
                # Add all the constraints to the mapping_option
                cn.constraints.extend(mapping.constraints)
示例#9
0
def map_technologies(graph: FluidInteractionGraph):
    print("Running the direct technology mapper:")
    print(graph.G.edges())
    # Iterate through all the custom mapping interactions
    # Step 1-
    #   Clump all the graph nodes by common outputs, this way we try to combine the interactions
    #   based on the common outputs. so if its a dictionary <output, [interactions]> then we just
    #   need to merge the arrays of interactions in the first pass. Need to keep in mind that we
    #   need keep reconstructing the dictionary after every merge because we might have merged
    #   interactions in the algorithm
    #
    # print(graph.fluids)
    # print(graph.fluidinteractions)
    # Create all the indexes in STEP 1
    breakflag = True
    while breakflag:
        repeat = False
        PASS1_DICT = dict()
        for interaction in list(graph.fluidinteractions):
            print(interaction)
            neighbors = list(graph.G.neighbors(interaction))
            for output in neighbors:
                if output in PASS1_DICT.keys():
                    print("Added entry :", interaction)
                    PASS1_DICT[output].append(interaction)
                else:
                    print("Created entry for pass1 :", output)
                    print("Added entry :", interaction)
                    PASS1_DICT[output] = [interaction]

        for interaction in PASS1_DICT.keys():
            nodes = PASS1_DICT[interaction]

            if len(nodes) > 1:
                graph.merge_interactions(nodes)
                repeat = True
                break

        if repeat:
            continue

        breakflag = False

    print("Finished the STEP 1 of operator merging")
    print("PASS1 Reduced Graph:", graph.G.edges())
    # print(graph.fluidinteractions)

    # Step 2-
    #   The second pass we construct dictionary <interactions, set(inputs)> and then we
    #   basically merge all the interactions with duplicating inputs
    #
    print("Starting the STEP 2 of operator merging")

    for interaction in list(graph.fluidinteractions):
        # print("Interaction:", interaction)

        # This comprehension generates the list inputs
        neighbors = [i[0] for i in list(graph.G.in_edges(interaction))]
        # print("neighbours:", neighbors)
        for neighbor in neighbors:
            if interaction in PASS2_DICT.keys():
                # Since interaction already exists in the dictionary, we just add it to it and the
                # set datastructure will ensure that its unique
                PASS2_DICT[interaction].add(neighbor)
            else:
                # Since interaction does not exist in dictionary, we create a new entry to it
                foo = set()
                foo.add(neighbor)
                PASS2_DICT[interaction] = foo

    print("PASS 2 DICTIONARY: ", PASS2_DICT)

    #   Now that the dictionary has been built, the fluidic interactions with the
    #   same sets of inputs need to merged. To do that that, create anoter dictionary
    #   that will have the sets as keys

    MERGE_DICT = dict()

    for interaction in PASS2_DICT.keys():
        inputset = frozenset(PASS2_DICT[interaction])
        if inputset in MERGE_DICT.keys():
            MERGE_DICT[inputset].append(interaction)
        else:
            foo = []
            foo.append(interaction)
            MERGE_DICT[inputset] = foo

    # print("MERGE_DICT: ", MERGE_DICT)

    # Now to merge each of these list of fluid interactions

    for key in MERGE_DICT.keys():
        interactions = MERGE_DICT[key]
        if len(interactions) > 1:
            graph.merge_interactions(interactions)

    print("PASS2 Reduced Graph:", graph.G.edges())
示例#10
0
    def generate_and_annotations(self, fig: FluidInteractionGraph) -> None:
        m = self._connectivity_matrix
        shape = m.shape
        n_cols = shape[1]

        # Find all the different columns which are equal
        all_candidates = []
        skip_list = []
        for i in range(n_cols):
            candidate = []
            candidate.append(self.get_connectivity_edge(i))
            found_flag = False
            if i in skip_list:
                continue
            for j in range(i + 1, n_cols):
                if j in skip_list:
                    continue

                col_i = m[:, i]
                col_j = m[:, j]
                if np.array_equal(col_i, col_j):
                    skip_list.append(i)
                    skip_list.append(j)
                    candidate.append(self.get_connectivity_edge(j))
                    found_flag = True

            if found_flag is True:
                all_candidates.append(candidate)

        print("DISTRIBUTE-AND CANDIDATES:")
        print(all_candidates)

        # Populating this skip list is important to make sure
        # that all the nodes with the AND annotation are zero'ed
        # This will simplify how the or-compuation can be done
        for candidate in all_candidates:
            # Skip the first one and add the rest of
            # the edges into the skip list
            for i in range(1, len(candidate)):
                self.add_to_column_skip_list(candidate[i])

        # Add all the annotated edges to the list that keeps
        # track of used edges, this way we can ensrue that all
        # used edges are accounted for when we need to use the
        # NOTAnnotation

        for candidate in all_candidates:
            self._annotated_connectivity_edges.extend(candidate)

        # Generate all the different AND annotations necessary
        for candidate in all_candidates:
            for edge in candidate:
                # TODO - Figure out if the edge needs any additional markup here
                source_node = fig.get_fignode(edge[0])
                target_node = fig.get_fignode(edge[1])
                if source_node is None:
                    raise Exception(
                        "Could not find the corresponding nodes {}".format(
                            source_node))
                if target_node is None:
                    raise Exception(
                        "could not find the corresponding nodes {}".format(
                            target_node))
                fig.connect_fignodes(source_node, target_node)

            origin_nodes = [fig.get_fignode(edge[0]) for edge in candidate]
            print("Added AND annotation on FIG: {}".format(str(origin_nodes)))
            assert origin_nodes is not None
            annotation = fig.add_and_annotation(origin_nodes)
            self._and_annotations.append(annotation)
示例#11
0
class Module(object):
    def __init__(self, name):
        self.name = name
        self._imported_modules: List[Module] = []
        self._io: List[ModuleIO] = []
        self.FIG = FluidInteractionGraph()
        self.fluids = dict()
        self.mappings: List[ExplicitMapping] = []

    @property
    def io(self) -> List[ModuleIO]:
        return self._io

    @property
    def imported_modules(self) -> List[Module]:
        return self._imported_modules

    def add_new_import(self, module: Module) -> None:
        self._imported_modules.append(module)

    def get_explicit_mappings(self) -> List[ExplicitMapping]:
        return self.mappings

    def add_io(self, io: ModuleIO):
        self._io.append(io)
        for i in range(len(io.vector_ref)):
            self.FIG.add_fignode(io.vector_ref[i])

    def get_io(self, name: str) -> ModuleIO:
        for module_io in self._io:
            if name == module_io.id:
                return module_io

        raise Exception("ModuleIO:{0} not found !".format(name))

    def get_all_io(self) -> List[ModuleIO]:
        return self._io

    def add_fluid(self, fluid: Flow):
        self.fluids[fluid.id] = fluid
        self.FIG.add_fignode(fluid)

    def get_fluid(self, name: str) -> Optional[FIGNode]:
        return self.FIG.get_fignode(name)

    def add_fluid_connection(self, item1id: str, item2id: str) -> None:
        source = self.FIG.get_fignode(item1id)
        target = self.FIG.get_fignode(item2id)
        self.FIG.connect_fignodes(source, target)

    def add_fluid_custom_interaction(
            self, item: Flow, operator: str,
            interaction_type: InteractionType) -> Interaction:
        # Check if the item exists
        finteraction = FluidProcessInteraction(item, operator)
        self.FIG.add_interaction(finteraction)
        return finteraction

    def add_finteraction_custom_interaction(
            self, item: Interaction, operator: str,
            interaction_type: InteractionType) -> Interaction:
        # Check if the item exists
        # TODO: create finteraction factory method and FluidInteraction
        # finteraction = FluidInteraction(fluid1=item, interactiontype=interaction_type, custominteraction= operator)
        finteraction = FluidProcessInteraction(item, operator)
        self.FIG.add_interaction(finteraction)
        return finteraction

    def add_fluid_custominteraction(self, fluid1: Flow, fluid2: Flow,
                                    interaction: str) -> Interaction:
        finteraction = FluidFluidCustomInteraction(fluid1, fluid2, interaction)
        self.FIG.add_interaction(finteraction)
        return finteraction

    def add_fluid_fluid_interaction(
            self, fluid1: Flow, fluid2: Flow,
            interaction_type: InteractionType) -> Interaction:

        fluid_interaction = FluidFluidInteraction(fluid1, fluid2,
                                                  interaction_type)
        self.FIG.add_interaction(fluid_interaction)

        return fluid_interaction

    def add_fluid_finteraction_interaction(self, fluid1: Flow,
                                           finteraction: Interaction,
                                           interaction_type: InteractionType):
        # TODO: Create new factory method for creating this kind of fluid interaction
        new_fluid_interaction = FluidFluidInteraction(fluid1, finteraction,
                                                      interaction_type)

        # self.FIG.add_fluid_finteraction_interaction(fluid1, finteraction, new_fluid_interaction)
        self.FIG.add_interaction(new_fluid_interaction)

        return new_fluid_interaction

    def add_finteraction_finteraction_interaction(
            self, f_interaction1: Interaction, f_interaction2: Interaction,
            interaction_type: InteractionType) -> Interaction:
        # TODO - Revisit this to fix the fluid data mappings

        new_fluid_interaction = FluidFluidInteraction(f_interaction1,
                                                      f_interaction2,
                                                      interaction_type)

        self.FIG.add_interaction(new_fluid_interaction)

        return new_fluid_interaction

    def add_interaction_output(self, output: Flow, interaction: Interaction):
        self.FIG.connect_fignodes(output, interaction)

    def add_fluid_numeric_interaction(
            self, fluid1: Flow, number: Optional[int, float],
            interaction_type: InteractionType) -> Interaction:
        # finteraction = FluidInteraction(fluid1=fluid1, interactiontype=interaction)
        finteraction = None

        if interaction_type is InteractionType.METER:
            finteraction = FluidNumberInteraction(fluid1, number,
                                                  interaction_type)
        elif interaction_type is InteractionType.DILUTE:
            finteraction = FluidNumberInteraction(fluid1, number,
                                                  interaction_type)
        elif interaction_type is InteractionType.DIVIDE:
            finteraction = FluidIntegerInteraction(fluid1, number,
                                                   interaction_type)
        else:
            raise Exception("Unsupported Numeric Operator")

        self.FIG.add_interaction(finteraction)

        return finteraction

    def add_mapping(self, mapping: ExplicitMapping):
        self.mappings.append(mapping)

    def __str__(self):
        ret = "Name : " + self.name + "\n"
        for module_io in self._io:
            ret += module_io.__str__()
            ret += "\n"
        return ret

    def instantiate_module(self, type_id: str, var_name: str,
                           io_mapping: Dict[str, str]) -> None:
        # Step 1 - Find the corresponding module from the imports
        module_to_import = None
        for module_check in self.imported_modules:
            if module_check.name == type_id:
                module_to_import = module_check

        # Step 2 - Create a copy of the fig
        fig_copy = copy.deepcopy(module_to_import.FIG)

        # Step 3 - Convert all the flow IO nodes where mappings exist
        # to flow nodes
        for there_node_key in io_mapping.keys():
            fignode = fig_copy.get_fignode(there_node_key)
            # Skip if its a control type one
            if fignode.type is IOType.CONTROL:
                continue
            # Convert this node into a flow node
            # Sanity check to see if its flow input/output
            assert (fignode.type is IOType.FLOW_INPUT
                    or fignode.type is IOType.FLOW_OUTPUT)
            # Replace
            new_fignode = Flow(fignode.id)
            fig_copy.switch_fignode(fignode, new_fignode)

        # Step 4 - Relabel all the nodes with the prefix defined by
        # var_name
        rename_map = dict()
        for node in list(fig_copy.nodes):
            rename_map[node] = self.__generate_instance_node_name(
                node, var_name)

        fig_copy.rename_nodes(rename_map)

        # Step 5 - Stitch together tall the io newly formed io nodes into
        # current fig
        self.FIG.add_fig(fig_copy)

        # Step 6 - connect all the io nodes
        for there_id, here_id in io_mapping.items():
            # target_fig = self.FIG.get_fignode(rename_map[value])
            # source_fig = self.FIG.get_fignode(key)
            there_check_node = module_to_import.FIG.get_fignode(there_id)
            there_node = self.FIG.get_fignode(rename_map[there_id])
            here_node = self.FIG.get_fignode(here_id)
            if there_check_node.type is IOType.FLOW_INPUT:
                source_node = here_node
                target_node = there_node
            elif there_check_node.type is IOType.FLOW_OUTPUT:
                source_node = there_node
                target_node = here_node
            else:
                source_node = here_node
                target_node = there_node
            assert (source_node is not None)
            assert (target_node is not None)
            self.FIG.connect_fignodes(source_node, target_node)
        pass

    def __generate_instance_node_name(self, node: str, var_name: str) -> str:
        return "{0}_{1}".format(var_name, node)
示例#12
0
class Module:
    def __init__(self, name):
        self.name = name
        self._imported_modules: List[Module] = []
        self._io: List[ModuleIO] = []
        self.FIG = FluidInteractionGraph()
        self.fluids = dict()
        self._mappings: List[NodeMappingTemplate] = []

    @property
    def mappings(self) -> List[NodeMappingTemplate]:
        return self._mappings

    @property
    def io(self) -> List[ModuleIO]:
        return self._io

    @property
    def imported_modules(self) -> List[Module]:
        return self._imported_modules

    def add_new_import(self, module: Module) -> None:
        self._imported_modules.append(module)

    def get_explicit_mappings(self) -> List[NodeMappingTemplate]:
        return self.mappings

    def add_io(self, io: ModuleIO):
        self._io.append(io)
        for i in range(len(io.vector_ref)):
            self.FIG.add_fignode(io.vector_ref[i])

    def get_io(self, name: str) -> ModuleIO:
        for module_io in self._io:
            if name == module_io.id:
                return module_io

        raise Exception("ModuleIO:{0} not found !".format(name))

    def get_all_io(self) -> List[ModuleIO]:
        return self._io

    def add_fluid(self, fluid: Flow):
        self.fluids[fluid.id] = fluid
        self.FIG.add_fignode(fluid)

    def get_fluid(self, name: str) -> Optional[FIGNode]:
        return self.FIG.get_fignode(name)

    def add_fluid_connection(self, item1id: str, item2id: str) -> None:
        source = self.FIG.get_fignode(item1id)
        target = self.FIG.get_fignode(item2id)
        self.FIG.connect_fignodes(source, target)

    def add_fluid_custom_interaction(
        self, item: Flow, operator: str, interaction_type: InteractionType
    ) -> Interaction:
        # Check if the item exists
        finteraction = FluidProcessInteraction(item, operator)
        self.FIG.add_interaction(finteraction)
        return finteraction

    def add_finteraction_custom_interaction(
        self, item: Interaction, operator: str, interaction_type: InteractionType
    ) -> Interaction:
        # Check if the item exists
        # TODO: create finteraction factory method and FluidInteraction
        # finteraction = FluidInteraction(fluid1=item, interactiontype=interaction_type, custominteraction= operator)
        finteraction = FluidProcessInteraction(item, operator)
        self.FIG.add_interaction(finteraction)
        return finteraction

    # def add_fluid_custominteraction(
    #     self, fluid1: Flow, fluid2: Flow, interaction: str
    # ) -> Interaction:
    #     finteraction = FluidFluidCustomInteraction(fluid1, fluid2, interaction)
    #     self.FIG.add_interaction(finteraction)
    #     return finteraction

    def add_fluid_fluid_interaction(
        self, fluid1: Flow, fluid2: Flow, interaction_type: InteractionType
    ) -> Interaction:

        fluid_interaction = FluidFluidInteraction(fluid1, fluid2, interaction_type)
        self.FIG.add_interaction(fluid_interaction)

        return fluid_interaction

    def add_fluid_finteraction_interaction(
        self, fluid1: Flow, finteraction: Interaction, interaction_type: InteractionType
    ) -> Interaction:
        # TODO: Create new factory method for creating this kind of fluid interaction
        new_fluid_interaction = FluidFluidInteraction(
            fluid1, finteraction, interaction_type
        )

        # self.FIG.add_fluid_finteraction_interaction(fluid1, finteraction, new_fluid_interaction)
        self.FIG.add_interaction(new_fluid_interaction)

        return new_fluid_interaction

    def add_finteraction_finteraction_interaction(
        self,
        f_interaction1: Interaction,
        f_interaction2: Interaction,
        interaction_type: InteractionType,
    ) -> Interaction:
        # TODO - Revisit this to fix the fluid data mappings

        new_fluid_interaction = FluidFluidInteraction(
            f_interaction1, f_interaction2, interaction_type
        )

        self.FIG.add_interaction(new_fluid_interaction)

        return new_fluid_interaction

    def add_interaction_output(self, output: Flow, interaction: Interaction):
        self.FIG.connect_fignodes(output, interaction)

    def add_fluid_numeric_interaction(
        self,
        fluid1: Flow,
        number: float,
        interaction_type: InteractionType,
    ) -> Interaction:
        # finteraction = FluidInteraction(fluid1=fluid1, interactiontype=interaction)
        finteraction = None

        if interaction_type is InteractionType.METER:
            finteraction = FluidNumberInteraction(fluid1, number, interaction_type)
        elif interaction_type is InteractionType.DILUTE:
            finteraction = FluidNumberInteraction(fluid1, number, interaction_type)
        elif interaction_type is InteractionType.DIVIDE:
            finteraction = FluidIntegerInteraction(fluid1, number, interaction_type)
        else:
            raise Exception("Unsupported Numeric Operator")

        self.FIG.add_interaction(finteraction)

        return finteraction

    def __str__(self):
        ret = "Name : " + self.name + "\n"
        for module_io in self._io:
            ret += module_io.__str__()
            ret += "\n"
        return ret

    def instantiate_module(
        self, type_id: str, var_name: str, io_mapping: Dict[str, str]
    ) -> None:
        # Step 1 - Find the corresponding module from the imports
        module_to_import = None
        for module_check in self.imported_modules:
            if module_check.name == type_id:
                module_to_import = module_check

        # Step 2 - Create a copy of the fig
        fig_copy = copy.deepcopy(module_to_import.FIG)

        # Step 3 - Convert all the flow IO nodes where mappings exist
        # to flow nodes
        for there_node_key in io_mapping.keys():
            fignode = fig_copy.get_fignode(there_node_key)
            # Skip if its a control type one
            if fignode.type is IOType.CONTROL:
                continue
            # Convert this node into a flow node
            # Sanity check to see if its flow input/output
            assert (
                fignode.type is IOType.FLOW_INPUT or fignode.type is IOType.FLOW_OUTPUT
            )
            # Replace
            new_fignode = Flow(fignode.id)
            fig_copy.switch_fignode(fignode, new_fignode)

        # Step 4 - Relabel all the nodes with the prefix defined by
        # var_name
        rename_map = dict()
        for node in list(fig_copy.nodes):
            rename_map[node] = self.__generate_instance_node_name(node, var_name)

        fig_copy.rename_nodes(rename_map)

        # Step 5 - Stitch together tall the io newly formed io nodes into
        # current fig
        self.FIG.add_fig(fig_copy)

        # Step 6 - connect all the io nodes
        for there_id, here_id in io_mapping.items():
            # target_fig = self.FIG.get_fignode(rename_map[value])
            # source_fig = self.FIG.get_fignode(key)
            there_check_node = module_to_import.FIG.get_fignode(there_id)
            there_node = self.FIG.get_fignode(rename_map[there_id])
            here_node = self.FIG.get_fignode(here_id)
            if there_check_node.type is IOType.FLOW_INPUT:
                source_node = here_node
                target_node = there_node
            elif there_check_node.type is IOType.FLOW_OUTPUT:
                source_node = there_node
                target_node = here_node
            else:
                source_node = here_node
                target_node = there_node
            assert source_node is not None
            assert target_node is not None
            self.FIG.connect_fignodes(source_node, target_node)

        # TODO - Step 7 - Make copies of all the mappingtemplates for the final FIG.
        # Since we only utilize mappings based on the assicated fig node it should be
        # possible to find the corresponding fignodes by ID's
        for mappingtemplate in module_to_import.mappings:
            # TODO - Switch this to shallow copy implementation if the scheme needs to
            # follow python specs correctly
            mappingtemplate_copy = copy.deepcopy(mappingtemplate)
            # TODO - Switch out each of the instances here
            for mapping_instance in mappingtemplate_copy.instances:
                if isinstance(
                    mapping_instance,
                    (FluidicOperatorMapping, StorageMapping, PumpMapping),
                ):
                    # Swap the basic node from original to the instance
                    there_node_id = mapping_instance.node.id
                    here_node = self.FIG.get_fignode(rename_map[there_node_id])
                    mapping_instance.node = here_node
                elif isinstance(mapping_instance, NetworkMapping):
                    # TODO - Swap the nodes in the inputs and the outputs
                    # Swap the inputs
                    nodes_to_switch = mapping_instance.input_nodes
                    mapping_instance.input_nodes = self.__switch_fignodes_list(
                        rename_map, nodes_to_switch
                    )

                    nodes_to_switch = mapping_instance.output_nodes
                    mapping_instance.output_nodes = self.__switch_fignodes_list(
                        rename_map, nodes_to_switch
                    )

            self.mappings.append(mappingtemplate_copy)

    def __switch_fignodes_list(self, rename_map, nodes_to_switch):
        there_node_ids = [n.id for n in nodes_to_switch]
        here_nodes = [
            self.FIG.get_fignode(rename_map[there_node_id])
            for there_node_id in there_node_ids
        ]
        return here_nodes

    def __generate_instance_node_name(self, node: str, var_name: str) -> str:
        return "{0}_{1}".format(var_name, node)