Beispiel #1
0
def kill_cycle(solver: GraphSolver, cycle: list, orig_cost: float):
    """
    Returns the first edge found in the cycle which, if removed from tree, leads to a decrease in cost (average pairwise
    distance).
    :param tree: tree (with 1 extra edge) to consider
    :param cycle: list of edges to consider (which form a cycle, removal of any restores tree)
    :param orig_cost: original cost
    :return:
    """
    tree = solver.T
    for edge in cycle:
        solver.remove_edge(edge)
        new_cost = average_pairwise_distance(tree)
        still_valid = is_valid_network(solver.G, solver.T)
        solver.add_edge(edge)
        if new_cost < orig_cost and still_valid:
            return edge, new_cost

    return None, orig_cost
Beispiel #2
0
def kill_cycle_all_paths(solver: GraphSolver, cycle: list, orig_cost: float):
    """
    Returns the first edge found in the cycle which, if removed from tree, leads to a decrease in cost (average pairwise
    distance).
    :param tree: tree (with 1 extra edge) to consider
    :param cycle: list of edges to consider (which form a cycle, removal of any restores tree)
    :param orig_cost: original cost
    :return:
    """
    tree = solver.T

    weights = [0] * len(cycle)

    # Count the number of times each edge in the cycle appears in the paths
    for n, (dist, path) in all_pairs_dijkstra(solver.G):
        for target in path.keys():
            for v in range(1, len(path[target])):
                path_edge = (path[target][v - 1], path[target][v])
                if path_edge in cycle:
                    weights[cycle.index(path_edge)] += 1

    # Multiply by the edge weight to get the contributing weight
    weights = [
        weights[i] * weight(solver.G, cycle[i]) for i in range(len(weights))
    ]

    edge = cycle[argmin(weights)]
    # print('weights for', cycle, 'are', weights)
    # cycle.sort(key= lambda x: weight(solver.T, x), reverse = True)
    # edge = cycle[0]
    solver.remove_edge(edge)
    new_cost = average_pairwise_distance(tree)
    solver.add_edge(edge)
    if new_cost < orig_cost:
        # print('nice')
        return edge, new_cost
    else:
        # print('removing', edge, 'from cycle', cycle, "didn't decrease cost because", new_cost, '>=', orig_cost)
        # print(weight(solver.T, edge), 'from', [weight(solver.T, e) for e in cycle])
        pass
    return None, orig_cost
Beispiel #3
0
def optimize_additions(solver: GraphSolver,
                       tree: Graph,
                       orig_cost: float = None):
    graph = solver.G
    if orig_cost is None:
        orig_cost = average_pairwise_distance(tree)

    # get all edges to consider
    edges = []
    for node in tree.nodes:
        for neighbor in graph.neighbors(node):
            if not edge_exists(tree.edges,
                               (node, neighbor)) and not edge_exists(
                                   edges, (node, neighbor)):
                edges.append((node, neighbor))

    # for each edge (consider order randomly)
    while edges:
        # random.seed(0)
        added_edge = random.choice(edges)
        edges.remove(added_edge)
        weight = graph[added_edge[0]][added_edge[1]]['weight']

        # if added edge creates a cycle
        if added_edge[1] in tree.nodes:
            solver.add_edge(added_edge)
            while (True):
                try:
                    cycle: list = find_cycle(tree, added_edge[0])
                except:  # No cycle
                    break

                try:
                    cycle.remove(added_edge)
                except ValueError:
                    cycle.remove(added_edge[::-1])

                replaced_edge, new_cost = kill_cycle(solver, cycle, orig_cost)
                # print("replaced_edge:", replaced_edge)
                # print("cost:", new_cost)

                if replaced_edge:
                    orig_cost = new_cost
                    solver.remove_edge(replaced_edge)
                else:
                    solver.remove_edge(added_edge)
        # if other vertex not in tree
        else:
            v = added_edge[1]
            solver.visit(v, added_edge)
            # add_edge(tree, added_edge, weight)

            new_cost = average_pairwise_distance(tree)

            if new_cost < orig_cost:
                orig_cost = new_cost
                add_neighbors(solver, edges, v)
            else:
                solver.unvisit(v)

        # remove considered edge
    return orig_cost