Exemple #1
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 #2
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])
Exemple #3
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 #4
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 #5
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 #6
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 #7
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)))