2021-05-17 20:42:17 +02:00
|
|
|
from numpy import put, sum, append, where, zeros
|
2021-04-29 12:33:46 +02:00
|
|
|
from numpy.random import choice, seed
|
|
|
|
|
|
|
|
|
2021-05-17 21:49:20 +02:00
|
|
|
def generate_first_solution(n, m):
|
2021-04-29 12:33:46 +02:00
|
|
|
seed(42)
|
2021-05-10 19:25:06 +02:00
|
|
|
solution = zeros(shape=n, dtype=bool)
|
|
|
|
random_indices = choice(n, size=m, replace=False)
|
|
|
|
put(solution, ind=random_indices, v=True)
|
|
|
|
return solution
|
|
|
|
|
|
|
|
|
2021-05-17 20:50:26 +02:00
|
|
|
def get_genotype(element):
|
|
|
|
genotype = where(element == True)
|
|
|
|
return genotype[0]
|
|
|
|
|
|
|
|
|
2021-05-17 20:42:17 +02:00
|
|
|
def evaluate_element(element, data):
|
|
|
|
fitness = []
|
2021-05-17 20:50:26 +02:00
|
|
|
genotype = get_genotype(element)
|
|
|
|
distances = data.query(f"source in @genotype and destination in @genotype")
|
|
|
|
for item in genotype[:-1]:
|
2021-05-17 20:42:17 +02:00
|
|
|
element_df = distances.query(f"source == {item} or destination == {item}")
|
|
|
|
max_distance = element_df["distance"].astype(float).max()
|
|
|
|
fitness = append(arr=fitness, values=max_distance)
|
|
|
|
distances = distances.query(f"source != {item} and destination != {item}")
|
|
|
|
return sum(fitness)
|
2021-04-29 12:33:46 +02:00
|
|
|
|
|
|
|
|
|
|
|
def element_in_dataframe(solution, element):
|
|
|
|
duplicates = solution.query(
|
|
|
|
f"(source == {element.source} and destination == {element.destination}) or (source == {element.destination} and destination == {element.source})"
|
|
|
|
)
|
|
|
|
return not duplicates.empty
|
|
|
|
|
|
|
|
|
|
|
|
def replace_worst_element(previous, data):
|
|
|
|
solution = previous.copy()
|
|
|
|
worst_index = solution["distance"].astype(float).idxmin()
|
|
|
|
random_element = data.sample().squeeze()
|
|
|
|
while element_in_dataframe(solution=solution, element=random_element):
|
|
|
|
random_element = data.sample().squeeze()
|
|
|
|
solution.loc[worst_index] = random_element
|
|
|
|
return solution, worst_index
|
|
|
|
|
|
|
|
|
|
|
|
def get_random_solution(previous, data):
|
|
|
|
solution, worst_index = replace_worst_element(previous, data)
|
|
|
|
previous_worst_distance = previous["distance"].loc[worst_index]
|
|
|
|
while solution.distance.loc[worst_index] <= previous_worst_distance:
|
|
|
|
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)
|
|
|
|
neighbourhood.append(neighbour)
|
|
|
|
return neighbour
|
|
|
|
|
|
|
|
|
2021-05-10 19:25:06 +02:00
|
|
|
def genetic_algorithm(n, m, data):
|
2021-05-17 21:49:20 +02:00
|
|
|
first_solution = generate_first_solution(n=n, m=m)
|
2021-04-29 12:33:46 +02:00
|
|
|
best_solution = explore_neighbourhood(
|
|
|
|
element=first_solution, data=data, max_iterations=100
|
|
|
|
)
|
|
|
|
return best_solution
|