def findtour(inputfile): data = read_file(inputfile) numl, numh, listl, listh, start, matrix = data_parser(data) G, message = adjacency_matrix_to_graph(matrix) nodes = G.__iter__() nodedict = {} numdict = {} for i in range(numl): nextnode = next(nodes) nodedict[listl[i]] = nextnode numdict[nextnode] = listl[i] paths = [] graphs = [] distances = [] disttonode = {} nodetodist = {} list_home_nodes = [] for home in listh: homenode = nodedict.get(home) distance, shortestpath = nx.single_source_dijkstra( G, homenode, nodedict.get(start)) paths += [shortestpath] shortestgraph = nx.path_graph(shortestpath) graphs += [shortestgraph] distances.append(distance) if not distance in disttonode: disttonode[distance] = [homenode] else: disttonode[distance].append(homenode) nodetodist[homenode] = distance list_home_nodes += [homenode] distances.sort(reverse=False) mst = nx.compose_all(graphs) leaves = [x for x in mst.nodes() if mst.degree(x) == 1] visited = [] drive = [] adjlist = mst._adj startnode = nodedict.get(start) dropdict = {} tour, dropdict = traverse(startnode, visited, leaves, drive, distances, adjlist, nodedict, disttonode, nodetodist, G, startnode, mst, list_home_nodes, dropdict) tour = [ tour[i] for i in range(len(tour)) if (i == 0) or tour[i] != tour[i - 1] ] return tour, dropdict, numdict
def findtour(inputfile): data = read_file(inputfile) # need this to create output file name = inputfile.name numl, numh, listl, listh, start, matrix = data_parser(data) G, message = adjacency_matrix_to_graph(matrix) nodes = G.__iter__() nodedict = {} for i in range(numl): nodedict[listl[i]] = next(nodes) paths = [] graphs = [] distances = [] disttonode = {} nodetodist = {} for home in listh: homenode = nodedict.get(home) distance, shortestpath = nx.single_source_dijkstra( G, homenode, nodedict.get(start)) paths += [shortestpath] shortestgraph = nx.path_graph(shortestpath) graphs += [shortestgraph] distances.append(distance) # fix duplicate keys if not distance in disttonode: disttonode[distance] = [homenode] else: disttonode[distance].append(homenode) nodetodist[homenode] = distance distances.sort(reverse=True) mst = nx.compose_all(graphs) leaves = [x for x in mst.nodes() if mst.degree(x) == 1] visited = [] drive = [] adjlist = mst._adj startnode = nodedict.get(start) tour = traverse(startnode, visited, leaves, drive, distances, adjlist, nodedict, disttonode, nodetodist, G, startnode, mst, [], listh) return tour
def readInput(filename): """ Read from an input file Parameters ---------- filename: relative path to the input file Return ------ node_names: list of the names of all nodes house_names: list of the names of houses start_node: starting node adj_mat: adjacency matrix """ ''' f = open(filename, 'r') num_nodes = int(f.readline().strip()) num_houses = int(f.readline().strip()) node_names = f.readline().strip().split(' ') house_names = f.readline().strip().split(' ') start_node = f.readline().strip() adj_mat = [] for _ in range(num_nodes): adj_mat.append(f.readline().strip().split(' ')) f.close() return node_names, house_names, start_node, adj_mat ''' _, _, node_names, house_names, start, adj_mat = student_utils.data_parser( read_file(filename)) return node_names, house_names, start, adj_mat
def run(input_file="", random=False, size=50, draw=False, output_path="", output_log_path="", solver_mode="GRB",time_limit=None): """ Runs the solver using eithe random input or given the input file. Parameters ---------- input_file: str An optional input file to run the program with random: bool Uses a random input to generate the file size: int The size of the random input to use draw: bool A boolean to decide whether to draw the file output_path: str The output path to write the input to. If None, ignores it output_log_path: str Logges the optimal value and the bound. This is to see if time limit was hit and un optimal bound was found. If None, doesn't write a file solver_mode: str "GRB" for gurobi if the license exists and "CBC" for open source CBC time_limit: int The number of seconds to timeout the optimzer. If none is passed, no timelimit. """ if random: num_of_locations, num_houses, list_locations, list_houses, starting_car_location, adjacency_matrix = create_valid_random_test_input( size) else: input_data = utils.read_file(input_file) num_of_locations, num_houses, list_locations, list_houses, starting_car_location, adjacency_matrix = data_parser( input_data) G, list_locations, list_houses, starting_car_location = build_graph_given(num_of_locations, num_houses, list_locations, list_houses, starting_car_location, adjacency_matrix) objective_value, objective_bound, x, T = solve(G, list_locations, list_houses, starting_car_location, solver_mode=solver_mode,time_limit=time_limit) path_taken, dropped_off = get_path_car_taken_from_vars(G, x, T, list_locations, list_houses, starting_car_location, draw=draw) if random: input_file_loc = save_input_to_file(size, num_of_locations, num_houses, list_locations, list_houses, starting_car_location, adjacency_matrix, provided_input=True) print('Input file written to: ' + input_file_loc) write_path = save_output_file(num_of_locations, path_taken, dropped_off, output_path=output_path) run_hierholzer(write_path, full_path=True) if output_log_path: make_dir_if_not_exists(output_log_path) with open(output_log_path, 'w') as f: f.write('objective value: ' + str(objective_value) + '\n') f.write('objective bound: ' + str(objective_bound) + '\n')
return output if __name__ == '__main__': parser = argparse.ArgumentParser(description='Parsing arguments') parser.add_argument('locations', type=int) parser.add_argument('tas', type=int) args = parser.parse_args() while True: write_to_file( str(args.locations) + ".in", generate_input(args.locations, args.tas)) input_file = str(args.locations) + ".in" input_data = utils.read_file(input_file) num_of_locations, num_houses, list_locations, list_houses, starting_car_location, adjacency_matrix = data_parser( input_data) G, adj_message = adjacency_matrix_to_graph(adjacency_matrix) if not is_metric(G): print("not metric!") continue car_path, drop_offs = solve(list_locations, list_houses, starting_car_location, adjacency_matrix, params=[]) seen = [] duplicate_found = False for nxt in car_path[1:-1]: if nxt in seen:
def complete_home_graph_generator_from_file(input_file, params=[]): input_data = utils.read_file(input_file) old_num_of_locations, old_num_houses, old_list_locations, old_list_houses, old_starting_car_location, old_adjacency_matrix = su.data_parser( input_data) # make a old graph from file old_graph, old_adj_message = su.adjacency_matrix_to_graph(old_adjacency_matrix) new_num_of_locations = -1 new_list_locations = [] new_num_houses = old_num_houses new_list_houses = old_list_houses new_starting_car_location = old_starting_car_location new_adjacency_matrix = None # Flag shortest_paths_between_homes = None message = '' error = False old_starting_point_index = old_list_locations.index(old_starting_car_location) # Make complete_home_graph is_sp_home = None if old_starting_car_location in new_list_houses: is_sp_home = True if is_sp_home: print(" Sp is home, Complete Graph size = num_houses") complete_home_graph = nx.complete_graph(new_num_houses) new_num_of_locations = old_num_houses new_list_locations = old_list_houses else: # + 1 for the starting point print(" Sp is not home, Complete Graph size = num_houses + 1") complete_home_graph = nx.complete_graph(new_num_houses + 1) new_num_of_locations = old_num_houses + 1 new_list_locations = old_list_houses.copy() new_list_locations.insert(0, old_starting_car_location) # For debugging # nx.draw(complete_home_graph) # plt.show() give_nodes_names(is_sp_home, complete_home_graph, new_num_houses, new_list_houses, new_starting_car_location) shortest_paths_between_homes = give_edges_weights(complete_home_graph, old_graph, old_list_locations) new_adjacency_matrix = nx.to_numpy_array(complete_home_graph) # tests if not all(name.isalnum() and len(name) <= MAX_NAME_LENGTH for name in new_list_locations): message += f'One or more of the names of your locations are either not alphanumeric or are above the max length of {MAX_NAME_LENGTH}.\n' error = True # check counts if len(new_list_locations) != new_num_of_locations: message += f'The number of locations you listed ({len(new_list_locations)}) differs from the number you gave on the first line ({new_num_of_locations}).\n' error = True if len(new_list_houses) != new_num_houses: message += f'The number of homes you listed ({len(new_list_houses)}) differs from the number you gave on the first line ({new_num_houses}).\n' error = True # # no more needed because in the new complete_home_graph, the number of houses = the number of locatinos # if num_of_locations < num_houses: # message += f'The number of houses must be less than or equal to the number of locations.\n' # error = True # check containment if any(house not in new_list_locations for house in new_list_houses): message += f'You listed at least one house that is not an actual location. Ahh!\n' error = True if new_starting_car_location not in new_list_locations: message += f'You listed a starting car location that is not an actual location.\n' error = True # check distinct if not len(set(new_list_locations)) == len(new_list_locations): message += 'The names of your locations are not distinct.\n' error = True if not len(set(new_list_houses)) == len(new_list_houses): message += 'The names of your houses are not distinct.\n' error = True # check adjacency matrix if not len(new_adjacency_matrix) == len(new_adjacency_matrix[0]) == new_num_of_locations: message += f'The dimensions of your adjacency matrix do not match the number of locations you provided.\n' error = True if not all( entry == 'x' or (type(entry) is float and entry > 0 and entry <= 2e9 and su.decimal_digits_check(entry)) for row in new_adjacency_matrix for entry in row): message += f'Your adjacency matrix may only contain the character "x", or strictly positive integers less than 2e+9, or strictly positive floats with less than 5 decimal digits.\n' error = True # if not square, terminate if len(set(map(len, new_adjacency_matrix))) != 1 or len(new_adjacency_matrix[0]) != len(new_adjacency_matrix): message += f'Your adjacency matrix must be square.\n' error = True return message, error new_adjacency_matrix_numpy = np.matrix(new_adjacency_matrix) # check requirements on square matrix if not np.all(new_adjacency_matrix_numpy.T == new_adjacency_matrix_numpy): message += f'Your adjacency matrix is not symmetric.\n' error = True if not nx.is_connected(complete_home_graph): message += 'Your new complete_home_graph is not connected.\n' error = True if not su.is_metric(complete_home_graph): message += 'Your new complete_home_graph is not metric.\n' error = True if not message: message = "If you've received no other error messages, then your complete_home_graph is valid!\n\n\n" # print for debugging print("\n old_num_of_locations : " + str(old_num_of_locations)) print(" old_num_houses : " + str(old_num_houses)) print(" old_list_locations names: " + str(old_list_locations)) print(" old_list_houses names : " + str(old_list_houses)) print(" Old Starting Point name(Str) : " + old_starting_car_location) print(" Old Starting Point index : " + str(old_starting_point_index)) print("\n New Complete Graph Generated") print(" new_num_of_locations names: " + str(new_num_of_locations)) print(" new_num_houses names: " + str(new_num_houses)) print(" new_list_locations names: " + str(new_list_locations)) print(" new_list_houses: " + str(new_list_locations)) new_starting_point_index = 0 print(" New Starting Point name(Str) : " + old_starting_car_location) print(" ** New Starting Point index: " + str(new_starting_point_index)) # print(" new_adjacency_matrix:") # print(new_adjacency_matrix) # print(" shortest_paths_between_homes: \n" + str(shortest_paths_between_homes)) print("\n") # for edge in shortest_paths_between_homes: # print(edge, ':', shortest_paths_between_homes[edge]) # print("\n") return message, error, new_num_of_locations, new_num_houses, old_list_locations, new_list_locations, new_list_houses, \ new_starting_car_location, new_adjacency_matrix, shortest_paths_between_homes, complete_home_graph, old_graph, new_starting_point_index