Exemplo n.º 1
0
    def UpdateTreeFromDiGraph(self, root, forest=False):

        try:
            self.DiGraph
        except:
            print('Run UpdateDiGraph!')
            return

        if forest == False:

            self.Tree = nx.maximum_spanning_arborescence(self.DiGraph.copy())

            # set tree root
            self.TreeRoot = root

            self.TransferAttributes(self.Tree, self.DiGraph)
            self.UpdateReducedTree()

        else:
            self.Tree = nx.maximum_branching(self.DiGraph.copy())

            # set tree root
            self.TreeRoot = None
            self.TransferAttributes(self.Tree, self.DiGraph)
            self.UpdateReducedTree()

        self.Tree.node[root]['root'] = '1'
Exemplo n.º 2
0
    def optimal_branching(self, model: 'ModelSuite') -> Branching:
        root_costs = model.roots_cost(self.lexicon)
        edge_costs = model.edges_cost(self.edge_set)
        graph = nx.DiGraph()
        for edge in self.edge_set:
            # weight is the negative cost, i.e. how much is "saved"
            # by including this edge (because we look for maximum branching)
            weight = root_costs[self.lexicon.get_id(edge.target)] -\
                     edge_costs[self.edge_set.get_id(edge)]
            if graph.has_edge(edge.source, edge.target):
                if weight > graph[edge.source][edge.target]['weight']:
                    graph[edge.source][edge.target]['weight'] = weight
            else:
                graph.add_edge(edge.source, edge.target, weight=weight)

        branching = nx.maximum_branching(graph)

        result = Branching()
        for source, target in branching.edges_iter():
            result.add_edge(\
                max(self.find_edges(source, target), \
                    key=lambda e: root_costs[self.lexicon.get_id(e.target)] -\
                                  edge_costs[self.edge_set.get_id(e)]))
        return result
Exemplo n.º 3
0
def branching_rest():
    graph, devices, vulns = generate_graph(5, 2, 3, chance=75)
    branching = maximum_branching(graph)
    arborescence = maximum_spanning_arborescence(graph)

    pass
Exemplo n.º 4
0
    def build_tree(self,
                   cprob: np.ndarray,
                   mode='connection_probability',
                   as_matrix=False,
                   recalculate_probs=False,
                   max_slaves=0,
                   max_depth=0):
        '''
        Get structure from conention probability mx
            `mode`:
                'connection_probability' -- method takes `connection_probability` on input and calculate connection_power itself
                'connection_power'       -- method takes `connection_power`on input; it suppose to correctness of cpower
                                            (actually it is needed to implement some features - you really should not use it)
            `as_matrix`:
                True                     -- returns adjacency matrix instead of networkx.DiGraph
                False                    -- returns networkx.DiGraph object
            `recalculate_probs`:         -- recalculate cpowers feature
            `max_slaves`                 -- max slaves feature. If it > 0 => for each node number of connections will be limited
            `max_depth`                  -- max depth feature. If it > 0 => tree_depth will be limited
        '''

        msize = len(cprob[0])
        # Mode checking
        if mode == 'connection_probability':
            cpower = self.connection_power(cprob)
        elif mode == 'connection_power':
            cpower = cprob

        # recalculating_probs feature (look on `DynamicHierarhy` function in Wolfram Notebook)
        if recalculate_probs:
            # Build base tree
            base_tree = self.build_tree(cprob,
                                        mode=mode,
                                        as_matrix=True,
                                        max_slaves=max_slaves,
                                        max_depth=max_depth)
            # Searching nodes to reweight
            nodes_to_reweight = []
            for i in range(msize):  # Row bypass
                connection_counter = 0  # counter of i node
                for j in range(msize):  # Column bypass
                    if base_tree[i][j] > 0:
                        connection_counter += 1
                if connection_counter > 1:  # add node to reweight list if more than 1 connection
                    nodes_to_reweight.append(i)
            # Reweighting nodes
            for i in nodes_to_reweight:
                div = 1  # divider of conn power
                for j in range(msize):
                    if base_tree[i][j] > 0:
                        #cpower[i][j] = cpower[i][j] / div
                        cprob[i][j] = cprob[i][j] / div
                        div *= 2
            cpower = self.connection_power(cprob)

        # max_slaves feature
        # bug:
        #   With standart nodesCoord matrix:
        #       I.
        #           1. Set max_slaves = 2, max_depth = 2
        #           2. Program prints: `No optimal tree found`
        #       II.
        #           1. Set max_slaves = 3 or 4, max_depth = 2
        #           2. Program build a tree with with no more, than 2 slaves
        # UPD: can not reproduce
        if max_slaves > 0:
            cpower_changed = True
            while cpower_changed:
                # Build base tree from existing cpower mx
                base_tree = self.build_tree(
                    cpower,
                    mode='connection_power',
                    as_matrix=True,
                    recalculate_probs=recalculate_probs,
                    max_depth=max_depth)
                # Searching first meeting of node with more than `max_slaves` connection
                cpower_changed = False
                for i in range(msize):
                    current_connections_index = []
                    current_connections_power = []
                    for j in range(msize):
                        # all exist connections are adding to list to get one with min cpower to drop it
                        if base_tree[i][j] > 0:
                            current_connections_index.append(
                                (i, j)
                            )  # need to write index of node and its power
                            current_connections_power.append(base_tree[i][j])
                    # If node with too many slaves is found, then we fix cpower -> cprob
                    # and rebuild tree (kind of recursive way)
                    if len(current_connections_power) > max_slaves:
                        # Setting flag
                        cpower_changed = True
                        # Search min connection
                        min_listindex = current_connections_power.index(
                            min(current_connections_power))
                        min_i = current_connections_index[min_listindex][0]
                        min_j = current_connections_index[min_listindex][1]
                        # and drop it
                        cpower[min_i][min_j] = 0

        # max_depth feature
        if max_depth > 0:
            cpower_changed = True
            while cpower_changed:
                # Build base tree from existing cpower mx
                base_tree = self.build_tree(
                    cpower,
                    mode='connection_power',
                    as_matrix=False,
                    recalculate_probs=recalculate_probs,
                    max_slaves=max_slaves)
                cpower_changed = False
                # If we have too far node, then we fix cpower -> cprob (cpower [-2][-1] := 0)
                # and rebuild tree (kind of recursive way)
                if Utils.tree_depth(base_tree) > max_depth:
                    # Setting flag
                    cpower_changed = True
                    longest_path = nx.dag_longest_path(base_tree)
                    # Farest node
                    far_i = longest_path[-2]
                    far_j = longest_path[-1]
                    # Drop it
                    cpower[far_i][far_j] = 0

        # Make structure
        # NOTE:
        # - maximum_spanning_arborescence -- if there is not possible to build with this set of nodes
        #     then it throws an exception - no arborescence can be built
        # - maximum_branching -- it builds an branching even if there is all zero weights
        G = nx.from_numpy_array(cpower, create_using=nx.DiGraph)
        try:
            #res = nx.maximum_spanning_arborescence(G, default=0)
            res = nx.maximum_branching(G, default=0)
            if as_matrix:
                res = nx.to_numpy_array(res)
        except nx.exception.NetworkXException:  # if no tree found
            raise  # handle this in interface part
            # We find out which node has no connection and drop it
        return res