Exemple #1
0
def max_cycle_ratio(g, estimate=None):
    maxratio, arg_cycle = None, None
    for scc in nx.strongly_connected_component_subgraphs(g):
        root = next(iter(scc.nodes()))
        scc_mcr, cycle = compute_mcr_component(scc, root, estimate)
        if scc_mcr is None:
            continue

        if maxratio is None or scc_mcr > maxratio:
            maxratio = scc_mcr
            arg_cycle = cycle

    forest = Forest()
    for scc in nx.strongly_connected_component_subgraphs(g, False):
        if scc.number_of_edges() == 0:
            continue

        for (v, w, scc_data) in scc.edges(data=True):
            data = g.get_edge_data(v, w)

            # negate weight so that we can construct a longest paths tree for the current solution
            scc_data['w'] = data.get('weight',
                                     0) - data.get('tokens', 0) * maxratio

        root = w
        parents, _ = longest_distances(scc, root, 'w')
        for child in parents:
            in_edge = parents.get(child)
            if in_edge is not None:
                forest.add_edge(*in_edge)

    return maxratio, arg_cycle, forest
Exemple #2
0
    def test_multi_children(self):
        tree = Forest()
        tree.add_edge(1, 2)
        tree.add_edge(1, 3)

        self.assertEqual(tree.parent(2), (1, 2))
        self.assertEqual(tree.parent(3), (1, 3))

        self.assertListEqual(list(tree.pre_order(1)), [1, 2, 3])

        tree.add_edge(1, 4)
        self.assertEqual(tree.parent(4), (1, 4))
        self.assertListEqual(list(tree.pre_order(1)), [1, 2, 3, 4])
Exemple #3
0
def compute_mcr_component(g, root, estimate=None):
    ''' Computes the maximum cycle ratio of g.
    NOTES:
        - The weight on each edge must be non-negative
        - The number of tokens on each edge must be non-negative.
        - The graph is assumed to be strongly connected.
    '''

    # initialize:
    distances = {}
    queue = PriorityQueue()

    if estimate is None:
        # determine lower bound for mcr
        estimate = 1
        for (v, w, data) in g.edges(data=True):
            tokens = data.get('tokens', 0)
            weight = data.get('weight', 0)
            estimate = estimate + max(0, weight)

    initial_graph = nx.MultiDiGraph()

    # construct graph with non-parametric path weights
    for v in g:
        initial_graph.add_node(v)

    for v, w, key, data in nx.MultiDiGraph(g).edges(keys=True, data=True):
        tokens = data.get('tokens', 0)
        weight = data.get('weight', 0)
        initial_graph.add_edge(v,
                               w,
                               key,
                               weight=weight - tokens * estimate,
                               dist=pdistance(weight, tokens))

    try:
        parents, _ = longest_distances(initial_graph, root)
        # build tree from parents
        tree = Forest()
        for child in parents:
            in_edge = parents.get(child)
            if in_edge is not None:
                tree.add_edge(*in_edge)

        distances[root] = pdistance(0, 0)
        if root in tree:
            for v, w, key in tree.pre_order_edges(root):
                dv = distances[v]
                data = initial_graph.get_edge_data(v, w, key)
                distances[w] = dv + data.get('dist')

    except PositiveCycle as ex:
        raise InfeasibleException(ex.cycle)

    # fill priority queue:
    # go over all nodes and compute their key
    # print("Distances from root {}: {}".format(root, distances))
    for v in distances:
        update_node_key(initial_graph, v, distances, queue)

    # pivot until cycle is found
    while len(queue) > 0:
        (node, (ratio, (v, w, vw_key))) = queue.pop()
        delta = distances[v] + initial_graph.get_edge_data(
            v, w, vw_key)['dist'] - distances[w]

        for j in tree.pre_order(w):
            # update parametric distance to j
            distances[j] += delta

            if v == j:
                # j is reachable from v -> there's a cycle!
                is_multi = g.is_multigraph()
                path = deque([(v, w, vw_key) if is_multi else (v, w)])
                p = v
                while p != w:
                    k, _, key = tree.parent(p)
                    path.appendleft((k, p, key) if is_multi else (k, p))
                    p = k
                return -ratio, list(path)

            # update successors of j; the node key of a successor k can only increase!
            for _, k, jk_key, data in initial_graph.out_edges(j,
                                                              keys=True,
                                                              data=True):
                # update priority of (j, k)
                ratio_k = None
                if k in queue:
                    ratio_k, _ = queue[k]

                delta_k = distances[j] + data['dist'] - distances[k]
                if delta_k[1] > 0:
                    r = -Fraction(delta_k[0], delta_k[1])
                    if ratio_k is None or r < ratio_k:
                        queue[k] = (r, (j, k, jk_key))

            # recompute vertex key of j
            update_node_key(initial_graph, j, distances, queue)

        tree.add_edge(v, w, vw_key)
    else:
        # no cycle found, any period is admissible
        # Note that this implies that the graph is acyclic
        return None, None
Exemple #4
0
    def test_two_trees_merged(self):
        forest = Forest()
        forest.add_edge(1, 2)
        forest.add_edge(2, 3)
        forest.add_edge(2, 4)
        forest.add_edge(1, 5)
        forest.add_edge(5, 6)
        forest.add_edge(5, 7)
        forest.add_edge(7, 8)
        forest.add_edge(7, 9)
        forest.add_edge(10, 11)
        forest.add_edge(10, 12)
        forest.add_edge(12, 13)

        # merge the two trees together into a single tree
        forest.add_edge(9, 10)
        self.assertSetEqual(set(forest.roots()), {1})
        self.assertListEqual(list(forest.pre_order()),
                             [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
Exemple #5
0
    def test_two_trees(self):
        forest = Forest()
        forest.add_edge(1, 2)
        forest.add_edge(2, 3)
        forest.add_edge(2, 4)
        forest.add_edge(1, 5)
        forest.add_edge(5, 6)
        forest.add_edge(5, 7)
        forest.add_edge(7, 8)
        forest.add_edge(7, 9)
        self.assertListEqual(list(forest.pre_order(1)),
                             [1, 2, 3, 4, 5, 6, 7, 8, 9])

        forest.add_edge(10, 11)
        forest.add_edge(10, 12)
        forest.add_edge(12, 13)
        self.assertListEqual(list(forest.pre_order(10)), [10, 11, 12, 13])

        self.assertSetEqual(set(forest.roots()), {1, 10})
        po = sum([list(forest.pre_order(r)) for r in forest.roots()], [])

        self.assertListEqual(list(forest.pre_order()), po)
Exemple #6
0
    def test_single_edge(self):
        tree = Forest()
        tree.add_edge(1, 2, 3, dict(a=1))

        self.assertListEqual(list(tree.pre_order(1)), [1, 2])
        self.assertEqual(tree.parent(2), (1, 2, 3, dict(a=1)))
Exemple #7
0
    def test_swap_subtree(self):
        tree = Forest()
        tree.add_edge(1, 2)
        tree.add_edge(2, 3)
        tree.add_edge(2, 4)
        tree.add_edge(1, 5)
        tree.add_edge(5, 6)
        tree.add_edge(5, 7)
        tree.add_edge(7, 8)
        tree.add_edge(7, 9)
        self.assertListEqual(list(tree.pre_order(1)),
                             [1, 2, 3, 4, 5, 6, 7, 8, 9])

        tree.add_edge(2, 7)
        self.assertEqual(tree.parent(7), (2, 7))
        self.assertListEqual(list(tree.pre_order(1)),
                             [1, 2, 3, 4, 7, 8, 9, 5, 6])
Exemple #8
0
    def test_swap_edge(self):
        tree = Forest()
        tree.add_edge(1, 2)
        tree.add_edge(2, 3)
        tree.add_edge(2, 4)
        tree.add_edge(1, 5)
        tree.add_edge(5, 6)
        tree.add_edge(5, 7)

        self.assertListEqual(list(tree.pre_order(1)), [1, 2, 3, 4, 5, 6, 7])

        tree.add_edge(6, 4)
        self.assertEqual(tree.parent(4), (6, 4))
        self.assertListEqual(list(tree.pre_order(2)), [2, 3])
        self.assertListEqual(list(tree.pre_order(5)), [5, 6, 4, 7])
        self.assertListEqual(list(tree.pre_order(1)), [1, 2, 3, 5, 6, 4, 7])