Add local search module
This commit is contained in:
parent
20aa6b2d1e
commit
7cbb25c546
|
@ -0,0 +1,75 @@
|
|||
from numpy.random import choice, seed, randint
|
||||
from pandas import DataFrame
|
||||
|
||||
|
||||
def get_row_distance(source, destination, data):
|
||||
row = data.query(
|
||||
"""(source == @source and destination == @destination) or \
|
||||
(source == @destination and destination == @source)"""
|
||||
)
|
||||
return row["distance"].values[0]
|
||||
|
||||
|
||||
def compute_distance(element, solution, data):
|
||||
accumulator = 0
|
||||
distinct_elements = solution.query(f"point != {element}")
|
||||
for _, item in distinct_elements.iterrows():
|
||||
accumulator += get_row_distance(
|
||||
source=element,
|
||||
destination=item.point,
|
||||
data=data,
|
||||
)
|
||||
return accumulator
|
||||
|
||||
|
||||
def get_first_random_solution(n, m, data):
|
||||
solution = DataFrame(columns=["point", "distance"])
|
||||
seed(42)
|
||||
solution["point"] = choice(n, size=m, replace=False)
|
||||
solution["distance"] = solution["point"].apply(
|
||||
func=compute_distance, solution=solution, data=data
|
||||
)
|
||||
return solution
|
||||
|
||||
|
||||
def element_in_dataframe(solution, element):
|
||||
duplicates = solution.query(f"point == {element}")
|
||||
return not duplicates.empty
|
||||
|
||||
|
||||
def replace_worst_element(previous, n, data):
|
||||
solution = previous.copy()
|
||||
worst_index = solution["distance"].astype(float).idxmin()
|
||||
random_element = randint(n)
|
||||
while element_in_dataframe(solution=solution, element=random_element):
|
||||
random_element = randint(n)
|
||||
solution["point"].loc[worst_index] = random_element
|
||||
solution["distance"].loc[worst_index] = compute_distance(
|
||||
element=solution["point"].loc[worst_index], solution=solution, data=data
|
||||
)
|
||||
return solution
|
||||
|
||||
|
||||
def get_random_solution(previous, n, data):
|
||||
solution = replace_worst_element(previous, n, data)
|
||||
while solution["distance"].sum() <= previous["distance"].sum():
|
||||
solution = replace_worst_element(previous=solution, n=n, data=data)
|
||||
return solution
|
||||
|
||||
|
||||
def explore_neighbourhood(element, n, data, max_iterations=100000):
|
||||
neighbourhood = []
|
||||
neighbourhood.append(element)
|
||||
for _ in range(max_iterations):
|
||||
previous_solution = neighbourhood[-1]
|
||||
neighbour = get_random_solution(previous=previous_solution, n=n, data=data)
|
||||
neighbourhood.append(neighbour)
|
||||
return neighbour
|
||||
|
||||
|
||||
def local_search(n, m, data):
|
||||
first_solution = get_first_random_solution(n, m, data)
|
||||
best_solution = explore_neighbourhood(
|
||||
element=first_solution, n=n, data=data, max_iterations=100
|
||||
)
|
||||
return best_solution
|
Loading…
Reference in New Issue