Beispiel #1
0
def solveFile(fileName: str, log = False) -> bool:
    """
    Solve a graph saved in ./inputs/{fileName}.in and output it in output folder. 
    Return if solve file succeed. 
    """

    try:
        G = read_input_file("./inputs/%s.in" % fileName)
        T = solver.ABC(G, N_EMPLOYED, N_ONLOOKER, N_ITERATIONS, FIRE_LIMIT, TERMINATION_LIMIT, log = log)
        assert(is_valid_network(G, T))

        if os.path.exists("./outputs/%s.out" % fileName):
            oldT = read_output_file("./outputs/%s.out" % fileName, G)
            if len(T) == 1 and len(oldT) != 1:
                write_output_file(T, "./outputs/%s.out" % fileName)
                return True
            if len(oldT) == 1 or average_pairwise_distance(oldT) <= average_pairwise_distance(T):
                # do nothing
                print("File %s is skipped because old tree is better. " % fileName)
                return True

        write_output_file(T, "./outputs/%s.out" % fileName)
        return True

    except KeyboardInterrupt:
        raise KeyboardInterrupt
    except:
        # stdout
        print("ERROR: An error occured when processing on %s: %s" % (fileName, sys.exc_info()[0]))
        return False
Beispiel #2
0
    def helper2(G):
        T = nx.minimum_spanning_tree(G)
        curr_lowest = average_pairwise_distance(T)
        curr_lowest_tree = T

        S = min_weighted_dominating_set(T)

        newG = nx.subgraph(T, S)

        ncc = nx.number_connected_components(newG)
        ccs = list(connected_components(newG))

        for i in range(len(ccs) - 1):
            curr_node = ccs[i].pop()
            ccs[i].add(curr_node)
            next_node = ccs[i + 1].pop()
            ccs[i + 1].add(next_node)
            path = nx.dijkstra_path(G, curr_node, next_node)

            for n in path:
                if (n not in list(newG.nodes)):
                    S.add(n)

            newG = nx.subgraph(G, S)
            newT = nx.minimum_spanning_tree(newG)
            if (is_valid_network(G, newT)):
                apd = average_pairwise_distance(newT)
                if (apd < curr_lowest):
                    curr_lowest = apd
                    curr_lowest_tree = newT

        return curr_lowest_tree
def solve(G):
    T = findSpanningTreeDFS(G)
    # T = nx.minimum_spanning_tree(G)

    while True:
        node_degree = T.degree(list(T.nodes()))
        leaves = []
        for node in node_degree:
            if node[1] == 1:
                edge = list(G.edges(node[0]))[0]
                leaves.append((node[0], G.get_edge_data(edge[0],
                                                        edge[1])['weight']))

        # leaves = Sort_Tuple(leaves, 1)
        random.shuffle(leaves)
        score = average_pairwise_distance(T)
        all_worse = True
        while len(leaves) > 0:
            leaf = leaves.pop()[0]
            if T.degree(leaf) == 1:
                newT = T.copy()
                newT.remove_node(leaf)
                newScore = average_pairwise_distance(newT)
                if newScore < score and nx.is_dominating_set(G, newT.nodes()):
                    all_worse = False
                    score = newScore
                    T = newT
        if all_worse:
            break
    return T
Beispiel #4
0
def random_prune(G, tree):
    min_tree = tree
    for k in range(1000):
        T = tree.copy()
        """list = range(25)
        random_range = random.choice(list)
        for j in range(70): #ramdom select leaves. if delete and valid, delete it
            temp = T.copy()
            leaves = [x for x in T.nodes() if T.degree(x) == 1 or T.degree(x) == 2]
            if len(leaves) == 0:
                break
            select = random.choice(leaves)
            temp.remove_node(select)
            if is_valid_network(G, temp):
                T = temp"""

        for j in range(30):
            temp = T.copy()
            for i in range(5):
                leaves = [x for x in T.nodes() if T.degree(x) == 1 or T.degree(x) == 2]
                if len(leaves) == 0:
                    break
                select = random.choice(leaves)
                temp = T.copy()
                temp.remove_node(select)
                if is_valid_network(G, temp):
                    T = temp
            if is_valid_network(G, temp) and average_pairwise_distance(temp) < average_pairwise_distance(T):
                T = temp

        if average_pairwise_distance(T) < average_pairwise_distance(min_tree):
            min_tree = T
            print(average_pairwise_distance(min_tree))
    return min_tree
def solve(G):
    """
    Args:
        G: networkx.Graph

    Returns:
        T: networkx.Graph
    """

    g = GraphSolver(G)
    start = g.find_leaf_path()
    T = g.dijkstra_solve_graph(start, calculate_heuristic, first_heuristic)
    optimize_sorted(g, T)
    rebuilder = Rebuilder(g)
    min_T = T.copy()
    min_cost = average_pairwise_distance(T)
    # print('*', min_cost)
    for _ in range(50):
        if rebuilder.rebuild():
            g = GraphSolver(G)
            for v in min_T.nodes:
                g.visit(v)
            for e in min_T.edges:
                g.add_edge(e)
            # print('reset')
        g.dijkstra_solve_graph(start, calculate_heuristic, first_heuristic)
        optimize_sorted(g, g.T)

        cost = average_pairwise_distance(g.T)
        # print(cost)
        if cost < min_cost:
            min_cost = cost
            min_T = g.T.copy()
    return min_T
def endgame_optimization(G, T):
    """Given the original graph and a proposed solution T, searches neighboring edges to add that could potentially
    lower the overall cost of the solution tree. Returns final solution tree."""
    current_average = average_pairwise_distance(T)

    T_vertices = list(T.nodes)
    G_vertices = list(G.nodes)
    corona = [gv for gv in G_vertices if gv not in T_vertices]

    for cv in corona:
        # Look at all edges leading out of the coronavertex and pick the cheapest one to consider adding.
        T_vertices = list(T.nodes)
        cv_neighbors = [n for n in list(G.adj[cv]) if n in T_vertices]
        cv_edges = [(cn, G.get_edge_data(cv, cn)['weight'])
                    for cn in cv_neighbors]
        cheapest_edge = min(cv_edges, key=lambda t: t[
            1])  # can only make one connection from cv into the tree
        connection_point = cheapest_edge[
            0]  # identify connection point within tree
        connection_weight = cheapest_edge[1]
        if connection_weight < current_average:
            T.add_node(cv)
            T.add_edge(cv, connection_point, weight=connection_weight)
            new_average = average_pairwise_distance(T)
            if new_average >= current_average:  # uh oh, got heavier
                T.remove_node(cv)
            else:
                current_average = new_average
    return T
Beispiel #7
0
def solve_min_MST_cut_sometimes(G):
    G2 = copy.deepcopy(G)
    path_lengths = dict(
        nx.algorithms.shortest_paths.unweighted.all_pairs_shortest_path_length(
            G2))
    for e in G2.edges():
        n1 = e[0]
        n2 = e[1]
        G2[n1][n2]['weight'] += min(sum(path_lengths[n1].values()),
                                    sum(path_lengths[n2].values()))
    T = nx.minimum_spanning_tree(G2)
    T = nx.Graph(G.edge_subgraph(T.edges()))
    remove = [node for node, degree in dict(T.degree()).items() if degree == 1]
    # print(remove)
    for i in remove:
        T_temporary = copy.deepcopy(T)
        T_temporary.remove_node(i)
        if average_pairwise_distance(T_temporary) <= average_pairwise_distance(
                T):
            T.remove_node(i)
    remove = [node for node, degree in dict(T.degree()).items() if degree == 1]
    # print(remove)
    q = PriorityQueue()
    for i in remove:
        n2 = list(T.edges(i))[0][1]
        q.put((-T[i][n2]['weight'], i))
    while q.qsize() > 0:
        nodeToRemove = q.get()[1]
        # print("removing node: " + str(nodeToRemove))
        G2 = copy.deepcopy(G)
        G2.remove_node(nodeToRemove)
        nodesInGraphNotTree = [
            node for node in G2.nodes if not node in T.nodes
        ]
        canRemove = True
        for n in nodesInGraphNotTree:
            if len(set(G2.neighbors(n)) & set(T.nodes)) == 0:
                canRemove = False
                break
        if canRemove:
            # print("can remove node!")
            if len(T.nodes) == 1:
                break
            T_temp = copy.deepcopy(T)
            T_temp.remove_node(nodeToRemove)
            if average_pairwise_distance(T_temp) <= average_pairwise_distance(
                    T):
                T.remove_node(nodeToRemove)
                removeMore = [
                    node for node, degree in dict(T.degree()).items()
                    if degree == 1
                ]
                setDiff = list(
                    set(removeMore).difference(set([x[1] for x in q.queue])))
                # print("new 1-edge nodes: " + str(setDiff))
                for i in setDiff:
                    node2 = list(T.edges(i))[0][1]
                    q.put((-T[i][node2]['weight'], i))
    return T
Beispiel #8
0
def remove_bad_leaves(G):
    for v in G.nodes:
        T = G.copy()
        T.remove_node(v)
        if G.in_degree(v) == 1 and G.out_degree(v) == 1:
            curr = average_pairwise_distance(G)
            if average_pairwise_distance(T) < curr:
                G.remove_node(v)
    return G
def mstPruned(G):
    networkNodes = []
    leaf_nodes = []
    validNetworkNodes = dict(
    )  #containing key = Node, Value = how many edges in MST
    for edge in G.edges():
        #edge should be in (u,v) format edge[0] = u node. edge[1] = v
        u = edge[0]
        v = edge[1]
        if u in validNetworkNodes:
            validNetworkNodes[u] = validNetworkNodes.get(u) + 1
        else:
            validNetworkNodes[u] = 1

        if v in validNetworkNodes:
            validNetworkNodes[v] = validNetworkNodes.get(v) + 1
        else:
            validNetworkNodes[v] = 1

    for x in validNetworkNodes:
        if validNetworkNodes.get(x) >= 2:
            networkNodes.append(x)
        else:
            leaf_nodes.append(x)

    #creating our output T Graph
    T = nx.Graph()
    T.add_nodes_from(networkNodes)  #adding network nodes into output T Graph

    for edge in G.edges():
        u = edge[0]
        v = edge[1]
        if u in networkNodes and v in networkNodes:
            T.add_edge(u, v, weight=G[u][v]['weight'])
    solDict = dict([(T, average_pairwise_distance(T))])
    # Graph T should now contain all the nodes in initial network and all the edges connections

    #optimizes by checking if adding leaf nodes one by one creats lower average distance
    for i in leaf_nodes:
        copyT = nx.Graph()
        networkNodes.append(i)
        copyT.add_nodes_from(networkNodes)
        for edge in G.edges():
            u = edge[0]
            v = edge[1]
            if u in networkNodes and v in networkNodes:
                copyT.add_edge(u, v, weight=G[u][v]['weight'])

        if average_pairwise_distance(copyT) < average_pairwise_distance(T):
            solDict[copyT] = average_pairwise_distance(copyT)

    return min(solDict, key=solDict.get)
Beispiel #10
0
def solve(G):
    G.remove_edges_from(nx.selfloop_edges(G))
    node = the_node(G)
    if node != G:
        print(node)
        return node
    spt = spt_solution(G)
    mst = mst_solution(G)
    if average_pairwise_distance(spt) < average_pairwise_distance(mst):
        print("spt")
        return spt
    else:
        print("mst")
        return mst
Beispiel #11
0
def simulated_annealing(G, T, steps=10000):
    """Takes in a possible solution tree T, original graph G, and executes a simulated_annealing procedure.
    At the conclusion returns the final T. """
    temp = [steps - i for i in range(steps)]
    calculate_prob = lambda iteration, delta: np.exp(-1 * delta / temp[
        iteration])
    for i in range(steps):
        T_prime = generate_new_solution(G, T)
        delta = average_pairwise_distance(T_prime) - average_pairwise_distance(
            T)
        if delta < 0:
            T = T_prime
        elif np.random.random() < calculate_prob(i, delta):
            T = T_prime
    return T
Beispiel #12
0
def pruneLeavesRando(l, currentAvg, res):
	#randomize the order and see if we get different solutions?
	leaves = sortEdges(l)
	print(leaves)
	removedLeaves = []
	temp = res.copy()
	bestAvg = currentAvg
	bestLeaves = []
	#start with the largest edge weight of leaves first
	for i in range(0, 15):
		leaves = random.shuffle(leaves)
		for elem in leaves:
			temp.remove(elem)
			print(temp)
			#create new graph to recalculate avg pairwise distance w/o elem
			Tr = nx.Graph()
			Tr.add_weighted_edges_from(temp)
			new_avg = average_pairwise_distance(Tr)
			#if better avg obtained w/o elem: remove it and update avg
			#else, add it back and move on to next leaf
			if new_avg <= currentAvg:
				removedLeaves.append(elem)
				currentAvg = new_avg
				print("removed:"+ str(new_avg))
			else:
				temp.add(elem)
				print("kept:"+ str(new_avg))
		if new_avg <= bestAvg:
			bestLeaves = removedLeaves.copy()
			bestAvg = new_avg
			print(new_avg + "    " + "iteration " +  i)
		removedLeaves = []


	return bestLeaves
Beispiel #13
0
def test_edge(T, G, u, v):
    if (u, v) not in G.edges:
        return float("inf")
    T.add_weighted_edges_from([(u, v, G[u][v]['weight'])])
    d = average_pairwise_distance(T)
    T.remove_edge(u, v)
    return d
Beispiel #14
0
def solve_vertex_combinations(G):
    """
    Args:
        G: networkx.Graph
    Returns:
        T: networkx.Graph
    """

    # TODO: your code here!
    dominating_trees = []
    for n in range(1, G.number_of_nodes() + 1):
        for SG in (G.subgraph(nodes)
                   for nodes in itertools.combinations(G, n)):
            if nx.algorithms.components.connected.is_connected(
                    SG) and nx.algorithms.dominating.is_dominating_set(
                        G, SG.nodes):
                dominating_tree = nx.minimum_spanning_tree(SG)
                if dominating_tree.number_of_nodes() == 1:
                    return dominating_tree
                dominating_trees.append(
                    (dominating_tree,
                     average_pairwise_distance(dominating_tree)))
                # print("adding dominating tree")
                # print(dominating_tree.nodes)

    min_dominating_tree = min(dominating_trees, key=operator.itemgetter(1))[0]

    return min_dominating_tree
Beispiel #15
0
def solve(G):
    """
    Args:
        G: networkx.Graph

    Returns:
        T: networkx.Graph
    """

    g = GraphSolver(G)
    start = g.find_leaf_path()
    if start is None:
        start = first_heuristic(g)
    graph_choices = []
    for v in g.neighbors(start):
        newG = G.copy()
        new_g = GraphSolver(newG)
        new_g.visit(start)
        new_g.visit(v, (start, v))
        graph_choices.append(new_g)
    minT = G
    minCost = float('inf')
    for g_option in graph_choices:
        g_option.dijkstra_solve_graph(start, calculate_heuristic,
                                      first_heuristic)
        optimize_sorted(g_option, g_option.T, cycle_killer_fn=kill_cycle)
        cost = average_pairwise_distance(g_option.T)
        if cost < minCost:
            minCost = cost
            minT = g_option.T
    return minT
Beispiel #16
0
def spt_solution(G):
    # resultDict = {}
    smallest = [float('inf'), None]
    for starting in G.nodes():
        T = getSPT(G, starting)
        aveDis = average_pairwise_distance(T)
        if smallest[0] > aveDis:
            smallest = [aveDis, T]
    before_pruning = smallest[1]
    no_ramdom = prune_leaf(G, before_pruning)
    random = random_prune(G, before_pruning)
    if average_pairwise_distance(no_ramdom) < average_pairwise_distance(random):
        print("No random spt")
        return no_ramdom
    else:
        print("random spt")
        return random
Beispiel #17
0
def mst_solution(G):
    # check complete graph
    # Minimum Spanning Tree T, our output
    T = nx.Graph()
    T.add_nodes_from(G.nodes(data = True))
    T.add_edges_from(nx.minimum_spanning_edges(G))
    T2 = T.copy()
    # deleting leaves from T
    T = prune_leaf(G, T)
    T2 = random_prune(G, T2)
    # return the min of T and T2
    if average_pairwise_distance(T) < average_pairwise_distance(T2):
        print("no random mst")
        return T
    else:
        print("random mst")
        return T2
Beispiel #18
0
def solve(G):
    """
    Args:
        G: networkx.Graph

    Returns:
        T: networkx.Graph
    """

    best_tree = minimum_spanning_tree(G)
    best_avg = average_pairwise_distance(best_tree)
    for i in range(1000):
        tree = minimum_spanning_tree(G)
        new_g = remove_bad_leaves(tree)
        if average_pairwise_distance(new_g) < best_avg:
            best_tree = tree
            best_avg = average_pairwise_distance(new_g)
    return best_tree
Beispiel #19
0
def optimize(G, T, L, NodeLevel, l_max):
    """
    Args:
        G: networkx.Graph
        T: networkx.Graph - MRCT for G
        L: dictionary mapping levels to a list of the nodes in them
        NodeLevel: dictionary mapping nodes in G to their level
        l_max: the level of the core node(s)

    Returns:
        T: networkx.Graph - modified version of input T optimized for reduced average
        pairwise distance
    """
    core = [k for k in T.nodes if NodeLevel[k] == l_max]
    min_cost = average_pairwise_distance(T)
    for l in range(l_max - 1, 1, -1):
        for k in L[l]:
            if k not in T.nodes:
                continue
            chain = list(nx.all_simple_paths(T, k, core[0]))
            assert len(chain) == 1
            chain = chain[0]
            edges = [(chain[i - 1], chain[i])
                     for i in range(2,
                                    len(chain) - 1)]
            for e in edges:
                T.remove_edge(e[0], e[1])
                T1, T2 = [T.subgraph(c) for c in nx.connected_components(T)]
                if core[0] in T1.nodes:
                    T1, T2 = T2, T1
                best_edge = (e[0], e[1], G[e[0]][e[1]]['weight'])
                for t in G.edges(k):
                    if t[1] in T2.nodes:
                        T.add_weighted_edges_from([(k, t[1],
                                                    G[k][t[1]]['weight'])])
                        d = average_pairwise_distance(T)
                        if d < min_cost:
                            min_cost = d
                            best_edge = (k, t[1], G[k][t[1]]['weight'])
                        T.remove_edge(k, t[1])
                T.add_weighted_edges_from([best_edge])
    return T
Beispiel #20
0
def getAvePairwiseDistance(tree):
    vertices = tree.nodes()
    edges = tree.edges()
    tree_cp = nx.Graph()
    tree_cp.add_nodes_from(vertices)
    tree_cp.add_edges_from(edges)

    for vertex in vertices:
        if tree.degree(vertex) == 0:
            tree_cp.remove_node(vertex)
    return average_pairwise_distance(tree_cp)
Beispiel #21
0
def process_edges(G, e):
    dominating_trees = []
    for SG in (G.edge_subgraph(edges)
               for edges in itertools.combinations(G.edges(), e)):
        if nx.algorithms.tree.recognition.is_tree(
                SG) and nx.algorithms.dominating.is_dominating_set(
                    G, SG.nodes):
            dominating_trees.append((SG, average_pairwise_distance(SG)))
            print("adding dominating tree")
            print(SG.nodes)
    return dominating_trees
Beispiel #22
0
def prune_leaf(G, T):
    for _ in range(25):
        leaves = [x for x in T.nodes() if T.degree(x) == 1]
        for i in leaves:
            temp = T.copy()
            temp.remove_node(i)
            try:
                if is_valid_network(G, temp) and average_pairwise_distance(temp) < average_pairwise_distance(T):
                    T = temp
            except:
                continue
    deg_two = [x for x in T.nodes() if T.degree(x) == 2]
    for i in deg_two:
        temp = T.copy()
        temp.remove_node(i)
        try:
            if is_valid_network(G, temp) and average_pairwise_distance(temp) < average_pairwise_distance(T):
                T = temp
        except:
            continue
    return T
def solve(G):
    """
    Pure simulated annealing. Start with an arbitrary MST though.
    Args:
        G: networkx.Graph

    Returns:
        T: networkx.Graph
    """
    mst = nx.minimum_spanning_tree(G, weight='weight')
    print("starting measure: " + str(average_pairwise_distance(mst)))
    return simulated_annealing(G, mst, 1000)
def solve(G):
    """
    Args:
        G: networkx.Graph

    Returns:
        solution tree
    """

    T1 = solver.solve(G)
    T2 = solver1.solve(G)
    T3 = solver2.solve(G)

    if is_valid_network(G, T1) != True:
        return min([T2, T3], key=lambda x: average_pairwise_distance(x))
    elif is_valid_network(G, T2) != True:
        return min([T1, T3], key=lambda x: average_pairwise_distance(x))
    elif is_valid_network(G, T3) != True:
        return min([T1, T2], key=lambda x: average_pairwise_distance(x))
    else:
        return min([T1, T2, T3], key=lambda x: average_pairwise_distance(x))
Beispiel #25
0
def algo8(G):
    """
    if cycle, we remove two nodes that has largest edges
    """
    cur = float('inf')
    for i in nx.find_cycle(G):
        copy = G.copy()
        copy.remove_nodes_from(i)
        temp = average_pairwise_distance(copy)
        if temp < cur:
            cur = temp
            returnG = copy
    return returnG
Beispiel #26
0
def process_vertices(G, n):
    dominating_trees = []
    for SG in (G.subgraph(nodes) for nodes in itertools.combinations(G, n)):
        if nx.algorithms.components.connected.is_connected(
                SG) and nx.algorithms.dominating.is_dominating_set(
                    G, SG.nodes):
            dominating_tree = nx.minimum_spanning_tree(SG)
            connected_subgraphs.append(
                (dominating_tree, average_pairwise_distance(dominating_tree)))
            # print("adding dominating tree")
            # print(dominating_tree.nodes)

    return dominating_trees
def combine_outputs():
    output_dir = "outputs"
    output_Avik = "outputsAvik"
    output_Raghav = "outputsRaghav"
    input_dir = "inputs"
    for input_path in os.listdir(input_dir):
        graph_name = input_path.split(".")[0]
        G = read_input_file(f"{input_dir}/{input_path}")
        Avik_T = read_output_file(f"{output_Avik}/{graph_name}.out", G)
        Raghav_T = read_output_file(f"{output_Raghav}/{graph_name}.out", G)
        T = min([Avik_T,Raghav_T], key = lambda x: average_pairwise_distance(x))
        write_output_file(T, f"{output_dir}/{graph_name}.out")
        print("%s Written"%(graph_name))
def solve(G):
    """
    Args:
        G: networkx.Graph

    Returns:
        T: networkx.Graph
    """

    g = GraphSolver(G)
    T = g.dijkstra_solve_graph(None, calculate_heuristic, first_heuristic)
    if average_pairwise_distance(T) == 0:
        return T
    optimize_sorted(g, T, cycle_killer_fn=kill_cycle)
    return T
def solve(G):
    """
    Args:
        G: networkx.Graph

    Returns:
        T: networkx.Graph
    """

    g = GraphSolver(G)
    start = g.find_leaf_path()
    T = g.dijkstra_solve_graph(start, calculate_heuristic, first_heuristic)
    if average_pairwise_distance(T) == 0:
        return T
    optimize(g, T)
    return T
Beispiel #30
0
def solve_graph(config):
    input_filenames, cacher = config
    for input_filename in input_filenames:
        global all_costs
        global all_times
        costs_iter = iter(all_costs)
        times_iter = iter(all_times)
        # print("File name:", input_filename)
        # for each solver
        for solver_filename in solvers:
            costs = []
            times = []
            # get the solver from module name
            mod = import_module(solver_filename)
            solve = getattr(mod, 'solve')

            # pass these to the combined solver
            mod.cacher = cacher
            mod.OUTPUT_DIRECTORY = OUTPUT_DIRECTORY
            mod.input_filename = input_filename 

            if input_filename == 'small-206.in':
                print('stop!')  # breakpoint for debugging

            input_path = os.path.join(INPUT_DIRECTORY, input_filename)
            graph = read_input_file(input_path, MAX_SIZE)
            start = time()
            tree = solve(graph)
            end = time()
            times.append(end - start)

            if not is_valid_network(graph, tree):
                print(solver_filename, 'is invalid!')
                nx.draw(graph)
                return

            # print(solver_filename, 'Nodes: ', tree.nodes)
            # for e in tree.edges:
            #     print("edge:", e, "; weight:", weight(graph, e))
            cost = average_pairwise_distance(tree)
            print(solver_filename, 'running', input_filename, '\n Average cost: ', cost, '\n Average time:', sum(times) / len(times), '\n')
            costs.append(cost)

            out_file = os.path.join(OUTPUT_DIRECTORY, input_filename[:-3], solver_filename + '.out')
            os.makedirs(os.path.dirname(out_file), exist_ok=True)
            write_output_file(tree, out_file)