Compare commits
No commits in common. "bd4a88bb4e7eb4de7d42143090fae42fcc4e0bc3" and "aa4a3fdec99043ae104f0db4b58350b538260dea" have entirely different histories.
bd4a88bb4e
...
aa4a3fdec9
|
@ -2,6 +2,4 @@
|
|||
|
||||
with pkgs;
|
||||
|
||||
mkShell {
|
||||
buildInputs = [ python39 python39Packages.numpy python39Packages.pandas ];
|
||||
}
|
||||
mkShell { buildInputs = [ python39 python39Packages.pandas ]; }
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
from pandas import DataFrame, Series
|
||||
|
||||
|
||||
def get_first_solution(n, data):
|
||||
distance_sum = DataFrame(columns=["point", "distance"])
|
||||
for element in range(n):
|
||||
element_df = data.query(f"source == {element} or destination == {element}")
|
||||
distance = element_df["distance"].sum()
|
||||
distance_sum = distance_sum.append(
|
||||
{"point": element, "distance": distance}, ignore_index=True
|
||||
)
|
||||
furthest_index = distance_sum["distance"].astype(float).idxmax()
|
||||
furthest_row = distance_sum.iloc[furthest_index]
|
||||
furthest_row["distance"] = 0
|
||||
return furthest_row
|
||||
|
||||
|
||||
def get_different_element(original, row):
|
||||
if row.source == original:
|
||||
return row.destination
|
||||
return row.source
|
||||
|
||||
|
||||
def get_closest_element(element, data):
|
||||
element_df = data.query(f"source == {element} or destination == {element}")
|
||||
closest_index = element_df["distance"].astype(float).idxmin()
|
||||
closest_row = data.loc[closest_index]
|
||||
closest_point = get_different_element(original=element, row=closest_row)
|
||||
return Series(data={"point": closest_point, "distance": closest_row["distance"]})
|
||||
|
||||
|
||||
def explore_solutions(solutions, data):
|
||||
closest_elements = solutions["point"].apply(func=get_closest_element, data=data)
|
||||
furthest_index = closest_elements["distance"].astype(float).idxmax()
|
||||
return closest_elements.iloc[furthest_index]
|
||||
|
||||
|
||||
def remove_duplicates(current, previous, data):
|
||||
duplicate_free_df = data.query(
|
||||
f"(source != {current} or destination not in @previous) and (source not in @previous or destination != {current})"
|
||||
)
|
||||
return duplicate_free_df
|
||||
|
||||
|
||||
def greedy_algorithm(n, m, data):
|
||||
solutions = DataFrame(columns=["point", "distance"])
|
||||
first_solution = get_first_solution(n, data)
|
||||
solutions = solutions.append(first_solution, ignore_index=True)
|
||||
for _ in range(m):
|
||||
element = explore_solutions(solutions, data)
|
||||
solutions = solutions.append(element)
|
||||
data = remove_duplicates(
|
||||
current=element["point"], previous=solutions["point"], data=data
|
||||
)
|
||||
return solutions
|
|
@ -1,60 +0,0 @@
|
|||
from numpy.random import choice, seed
|
||||
|
||||
|
||||
def get_first_random_solution(m, data):
|
||||
seed(42)
|
||||
random_indexes = choice(len(data.index), size=m, replace=False)
|
||||
return data.loc[random_indexes]
|
||||
|
||||
|
||||
def replace_worst_element(previous, data):
|
||||
solution = previous.copy()
|
||||
worst_index = solution["distance"].astype(float).idxmin()
|
||||
random_element = data.sample().squeeze()
|
||||
while solution.isin(random_element.values.ravel()).any().any():
|
||||
random_element = data.sample().squeeze()
|
||||
solution.loc[worst_index] = random_element
|
||||
return solution, worst_index
|
||||
|
||||
|
||||
def choose_best_solution(previous, current, index):
|
||||
if previous.loc[index].distance >= current.loc[index].distance:
|
||||
return previous
|
||||
return current
|
||||
|
||||
|
||||
def get_random_solution(previous, data):
|
||||
candidates = []
|
||||
candidates.append(previous)
|
||||
solution, worst_index = replace_worst_element(previous, data)
|
||||
previous_worst_distance = previous["distance"].loc[worst_index]
|
||||
last_solution = candidates[-1]
|
||||
while last_solution.distance.loc[worst_index] <= previous_worst_distance:
|
||||
solution, _ = replace_worst_element(previous=solution, data=data)
|
||||
if solution.equals(last_solution):
|
||||
best_solution = choose_best_solution(
|
||||
previous=previous, current=solution, index=worst_index
|
||||
)
|
||||
return best_solution
|
||||
candidates.append(solution)
|
||||
last_solution = candidates[-1]
|
||||
return last_solution
|
||||
|
||||
|
||||
def explore_neighbourhood(element, data, max_iterations=100000):
|
||||
neighbourhood = []
|
||||
neighbourhood.append(element)
|
||||
for i in range(max_iterations):
|
||||
print(f"Iteration {i}")
|
||||
previous_solution = neighbourhood[-1]
|
||||
neighbour = get_random_solution(previous=previous_solution, data=data)
|
||||
if neighbour.equals(previous_solution):
|
||||
break
|
||||
neighbourhood.append(neighbour)
|
||||
return neighbour
|
||||
|
||||
|
||||
def local_search(m, data):
|
||||
first_solution = get_first_random_solution(m=m, data=data)
|
||||
best_solution = explore_neighbourhood(element=first_solution, data=data)
|
||||
return best_solution
|
47
src/main.py
47
src/main.py
|
@ -1,47 +0,0 @@
|
|||
from preprocessing import parse_file
|
||||
from greedy import greedy_algorithm
|
||||
from local_search import local_search
|
||||
from sys import argv
|
||||
from time import time
|
||||
|
||||
|
||||
def execute_algorithm(choice, n, m, data):
|
||||
if choice == "greedy":
|
||||
return greedy_algorithm(n, m, data)
|
||||
elif choice == "local":
|
||||
return local_search(m, data)
|
||||
else:
|
||||
print("The valid algorithm choices are 'greedy' and 'local'")
|
||||
exit(1)
|
||||
|
||||
|
||||
def show_results(solutions, time_delta):
|
||||
distance_sum = solutions["distance"].sum()
|
||||
duplicates = solutions.duplicated().any()
|
||||
print(solutions)
|
||||
print("Total distance: " + str(distance_sum))
|
||||
if not duplicates:
|
||||
print("No duplicates found")
|
||||
print("Execution time: " + str(time_delta))
|
||||
|
||||
|
||||
def usage(argv):
|
||||
print(f"Usage: python {argv[0]} <file> <algorithm choice>")
|
||||
print("algorithm choices:")
|
||||
print("greedy: greedy algorithm")
|
||||
print("local: local search algorithm")
|
||||
exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
if len(argv) != 3:
|
||||
usage(argv)
|
||||
n, m, data = parse_file(argv[1])
|
||||
start_time = time()
|
||||
solutions = execute_algorithm(choice=argv[2], n=n, m=m, data=data)
|
||||
end_time = time()
|
||||
show_results(solutions, time_delta=end_time - start_time)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,142 @@
|
|||
from preprocessing import parse_file
|
||||
from numpy.random import choice, randint, seed
|
||||
from pandas import DataFrame, Series
|
||||
from sys import argv
|
||||
from time import time
|
||||
|
||||
|
||||
def get_first_solution(n, data):
|
||||
distance_sum = DataFrame(columns=["point", "distance"])
|
||||
for element in range(n):
|
||||
element_df = data.query(f"source == {element} or destination == {element}")
|
||||
distance = element_df["distance"].sum()
|
||||
distance_sum = distance_sum.append(
|
||||
{"point": element, "distance": distance}, ignore_index=True
|
||||
)
|
||||
furthest_index = distance_sum["distance"].astype(float).idxmax()
|
||||
furthest_row = distance_sum.iloc[furthest_index]
|
||||
furthest_row["distance"] = 0
|
||||
return furthest_row
|
||||
|
||||
|
||||
def get_different_element(original, row):
|
||||
if row.source == original:
|
||||
return row.destination
|
||||
return row.source
|
||||
|
||||
|
||||
def get_closest_element(element, data):
|
||||
element_df = data.query(f"source == {element} or destination == {element}")
|
||||
closest_index = element_df["distance"].astype(float).idxmin()
|
||||
closest_row = data.loc[closest_index]
|
||||
closest_point = get_different_element(original=element, row=closest_row)
|
||||
return Series(data={"point": closest_point, "distance": closest_row["distance"]})
|
||||
|
||||
|
||||
def explore_solutions(solutions, data):
|
||||
closest_elements = solutions["point"].apply(func=get_closest_element, data=data)
|
||||
furthest_index = closest_elements["distance"].astype(float).idxmax()
|
||||
return closest_elements.iloc[furthest_index]
|
||||
|
||||
|
||||
def remove_duplicates(current, previous, data):
|
||||
data = data.query(
|
||||
f"(source != {current} or destination not in @previous) and (source not in @previous or destination != {current})"
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
def greedy_algorithm(n, m, data):
|
||||
solutions = DataFrame(columns=["point", "distance"])
|
||||
first_solution = get_first_solution(n, data)
|
||||
solutions = solutions.append(first_solution, ignore_index=True)
|
||||
for _ in range(m):
|
||||
element = explore_solutions(solutions, data)
|
||||
solutions = solutions.append(element)
|
||||
data = remove_duplicates(
|
||||
current=element["point"], previous=solutions["point"], data=data
|
||||
)
|
||||
return solutions
|
||||
|
||||
|
||||
def get_first_random_solution(m, data):
|
||||
seed(42)
|
||||
random_indexes = choice(len(data.index), size=m)
|
||||
return data.iloc[random_indexes]
|
||||
|
||||
|
||||
def replace_worst_element(previous, data):
|
||||
solution = previous.copy()
|
||||
worst_index = previous["distance"].astype(float).idxmin()
|
||||
random_candidate = data.loc[randint(low=0, high=len(data.index))]
|
||||
solution.loc[worst_index] = random_candidate
|
||||
return solution
|
||||
|
||||
|
||||
def get_random_solution(previous, data):
|
||||
solution = replace_worst_element(previous, data)
|
||||
while solution["distance"].sum() <= previous["distance"].sum():
|
||||
if solution.equals(previous):
|
||||
break
|
||||
solution = replace_worst_element(previous=solution, data=data)
|
||||
return solution
|
||||
|
||||
|
||||
def explore_neighbourhood(element, data, max_iterations=100000):
|
||||
neighbourhood = []
|
||||
neighbourhood.append(element)
|
||||
for _ in range(max_iterations):
|
||||
previous_solution = neighbourhood[-1]
|
||||
neighbour = get_random_solution(previous=previous_solution, data=data)
|
||||
if neighbour.equals(previous_solution):
|
||||
break
|
||||
neighbourhood.append(neighbour)
|
||||
return neighbour
|
||||
|
||||
|
||||
def local_search(m, data):
|
||||
first_solution = get_first_random_solution(m=m, data=data)
|
||||
best_solution = explore_neighbourhood(element=first_solution, data=data)
|
||||
return best_solution
|
||||
|
||||
|
||||
def execute_algorithm(choice, n, m, data):
|
||||
if choice == "greedy":
|
||||
return greedy_algorithm(n, m, data)
|
||||
elif choice == "local":
|
||||
return local_search(m, data)
|
||||
else:
|
||||
print("The valid algorithm choices are 'greedy' and 'local'")
|
||||
exit(1)
|
||||
|
||||
|
||||
def show_results(solutions, time_delta):
|
||||
distance_sum = solutions["distance"].sum()
|
||||
duplicates = solutions.duplicated().any()
|
||||
print(solutions)
|
||||
print("Total distance: " + str(distance_sum))
|
||||
if not duplicates:
|
||||
print("No duplicates found")
|
||||
print("Execution time: " + str(time_delta))
|
||||
|
||||
|
||||
def usage(argv):
|
||||
print(f"Usage: python {argv[0]} <file> <algorithm choice>")
|
||||
print("algorithm choices:")
|
||||
print("greedy: greedy algorithm")
|
||||
print("local: local search algorithm")
|
||||
exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
if len(argv) != 3:
|
||||
usage(argv)
|
||||
n, m, data = parse_file(argv[1])
|
||||
start_time = time()
|
||||
solutions = execute_algorithm(choice=argv[2], n=n, m=m, data=data)
|
||||
end_time = time()
|
||||
show_results(solutions, time_delta=end_time - start_time)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue