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
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
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
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
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)
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
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
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
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
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
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
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
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
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
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
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)
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
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))
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
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
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)