Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
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')
Esempio n. 5
0
    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:
Esempio n. 6
0
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