fixed optimizer and added a member to Landmark class
All checks were successful
Build and push docker image / Build (pull_request) Successful in 2m16s
Build and release APK / Build APK (pull_request) Successful in 5m28s
Build web / Build Web (pull_request) Successful in 1m23s

This commit is contained in:
Kilian Scheidecker 2024-06-11 10:46:09 +02:00
parent 53a5a9e873
commit af4d68f36f
4 changed files with 4991 additions and 5309 deletions

View File

@ -9,12 +9,12 @@ from typing import Tuple
BBOX_SIDE = 10 # size of bbox in *km* for general area, 10km
RADIUS_CLOSE_TO = 25 # size of area in *m* for close features, 25m radius
RADIUS_CLOSE_TO = 27.5 # size of area in *m* for close features, 30m radius
MIN_SCORE = 30 # DEPRECIATED. discard elements with score < 30
MIN_TAGS = 5 # DEPRECIATED. discard elements withs less than 5 tags
CHURCH_PENALTY = 0.1 # penalty to reduce score of curches
PARK_COEFF = 10 # multiplier for parks
N_IMPORTANT = 30 # take the 30 most important landmarks
CHURCH_PENALTY = 0.6 # penalty to reduce score of curches
PARK_COEFF = 1.4 # multiplier for parks
N_IMPORTANT = 40 # take the 30 most important landmarks
SIGHTSEEING = LandmarkType(landmark_type='sightseeing')
NATURE = LandmarkType(landmark_type='nature')
@ -74,7 +74,7 @@ def generate_landmarks(preferences: Preferences, city_country: str = None, coord
L += L3
return L, take_most_important(L)
return remove_duplicates(L), take_most_important(L)
#return L, cleanup_list(L)
# Determines if two locations are close to each other
@ -86,7 +86,7 @@ def is_close_to(loc1: Tuple[float, float], loc2: Tuple[float, float])->bool :
else :
return False
# Take the most important landmarks from the list
def take_most_important(L: List[Landmark])->List[Landmark] :
L_copy = []
L_clean = []
@ -110,9 +110,7 @@ def take_most_important(L: List[Landmark])->List[Landmark] :
for old in L_copy :
if old.name == elem.name :
old.attractiveness = L[t].attractiveness
continue
scores = [0]*len(L_copy)
for i, elem in enumerate(L_copy) :
scores[i] = elem.attractiveness
@ -124,23 +122,14 @@ def take_most_important(L: List[Landmark])->List[Landmark] :
return L_clean
# Remove duplicate elements and elements with low score
def cleanup_list(L: List[Landmark])->List[Landmark] :
def remove_duplicates(L: List[Landmark])->List[Landmark] :
L_clean = []
names = []
for landmark in L :
if landmark.name in names : # Remove duplicates
continue
elif landmark.attractiveness < MIN_SCORE : # Remove uninteresting
continue
elif landmark.n_tags < MIN_TAGS : # Remove uninteresting 2.0
continue
else :
names.append(landmark.name)
L_clean.append(landmark)
@ -157,7 +146,6 @@ def correct_score(L: List[Landmark], preference: Preference) :
raise TypeError(f"LandmarkType {preference.type} does not match the type of Landmark {L[0].name}")
for elem in L :
elem.attractiveness = int(elem.attractiveness) + elem.n_tags*100 # arbitrary correction of the balance score vs number of tags
elem.attractiveness = int(elem.attractiveness*preference.score/500) # arbitrary computation
# Correct the score of a list of landmarks by taking into account preferences and the number of tags
@ -264,14 +252,11 @@ def get_landmarks_coords(coordinates: Tuple[float, float], l: List[Landmark], la
# Add score of given landmark based on the number of surrounding elements. Penalty for churches as there are A LOT
if amenity == "'amenity'='place_of_worship'" :
score = int(count_elements_within_radius(location)*CHURCH_PENALTY)
score = int((count_elements_within_radius(location) + n_tags*100 )*CHURCH_PENALTY)
elif amenity == "'leisure'='park'" :
score = int(count_elements_within_radius(location)*PARK_COEFF)
score = int((count_elements_within_radius(location) + n_tags*100 )*PARK_COEFF)
else :
score = count_elements_within_radius(location)
if name == "Jardin du Luxembourg" :
continue
score = count_elements_within_radius(location) + n_tags*100
if score is not None :
# Generate the landmark and append it to the list

View File

@ -69,9 +69,7 @@ def untangle(resx: list) -> list:
# Just to print the result
def print_res(res, order, landmarks: List[Landmark], P) -> list:
things = []
def print_res(L: List[Landmark], landmarks: List[Landmark], P) -> list:
"""N = int(np.sqrt(len(X)))
for i in range(N):
@ -81,20 +79,24 @@ def print_res(res, order, landmarks: List[Landmark], P) -> list:
for i,x in enumerate(X) : X[i] = round(x,0)
print(order)"""
if len(order) == len(landmarks):
if len(L) == len(landmarks):
print('\nAll landmarks can be visited within max_steps, the following order is suggested : ')
else :
print('Could not visit all the landmarks, the following order is suggested : ')
for idx in order :
print('- ' + landmarks[idx].name)
things.append(landmarks[idx].name)
dist = 0
for elem in L :
if elem.name != 'start' :
print('- ' + elem.name + ', time to reach = ' + str(elem.time_to_reach))
dist += elem.time_to_reach
else :
print('- ' + elem.name)
steps = path_length(P, abs(res.x))
print("\nMinutes walked : " + str(steps))
print(f"\nVisited {len(order)} out of {len(landmarks)} landmarks")
#steps = path_length(P, abs(res.x))
print("\nMinutes walked : " + str(dist))
print(f"\nVisited {len(L)} out of {len(landmarks)} landmarks")
return things
return
@ -366,21 +368,26 @@ def init_eq_not_stay(N: int):
return [l], [0]
# Constraint to ensure start at start and finish at goal
def respect_start_finish(N, A_eq: list, b_eq: list):
ls = [1]*N + [0]*N*(N-1) # sets only horizontal ones for start (go from)
ljump = [0]*N*N
ljump[N-1] = 1 # Prevent start finish jump
lg = [0]*N*N
for k in range(N-1) : # sets only vertical ones for goal (go to)
def respect_start_finish(L: int, A_eq: list, b_eq: list):
ls = [1]*L + [0]*L*(L-1) # sets only horizontal ones for start (go from)
ljump = [0]*L*L
ljump[L-1] = 1 # Prevent start finish jump
lg = [0]*L*L
ll = [0]*L*(L-1) + [1]*L
for k in range(L-1) : # sets only vertical ones for goal (go to)
ll[k*L] = 1
if k != 0 : # Prevent the shortcut start -> finish
lg[k*N+N-1] = 1
lg[k*L+L-1] = 1
A_eq = np.vstack((A_eq,ls))
A_eq = np.vstack((A_eq,ljump))
A_eq = np.vstack((A_eq,lg))
A_eq = np.vstack((A_eq,ll))
b_eq.append(1)
b_eq.append(0)
b_eq.append(1)
b_eq.append(0)
return A_eq, b_eq
@ -390,19 +397,19 @@ def init_ub_dist(landmarks: List[Landmark], max_steps: int):
# Objective function coefficients. a*x1 + b*x2 + c*x3 + ...
c = []
# Coefficients of inequality constraints (left-hand side)
A = []
A_ub = []
for i, spot1 in enumerate(landmarks) :
dist_table = [0]*len(landmarks)
c.append(-spot1.attractiveness)
for j, spot2 in enumerate(landmarks) :
d, t = get_distance(spot1.location, spot2.location)
dist_table[j] = t
A.append(dist_table)
A_ub += dist_table
c = c*len(landmarks)
A_ub = []
"""A_ub = []
for line in A :
#print(line)
A_ub += line
A_ub += line"""
return c, A_ub, [max_steps]
# Go through the landmarks and force the optimizer to use landmarks where attractiveness is set to -1
@ -438,7 +445,7 @@ def path_length(P: list, resx: list) :
return np.dot(P, resx)
# Main optimization pipeline
def solve_optimization (landmarks, max_steps, printing_details) :
def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_details: bool) :
N = len(landmarks)
@ -500,13 +507,30 @@ def solve_optimization (landmarks, max_steps, printing_details) :
t, order, [] = is_connected(res.x, landmarks)
prev = landmarks[order[0]]
i = 0
L = []
#prev = landmarks[order[i]]
while(len(L) != len(order)) :
elem = landmarks[order[i]]
if elem != prev :
d, t = get_distance(elem.location, prev.location)
elem.time_to_reach = t
L.append(elem)
prev = elem
i += 1
if printing_details is True :
if i != 0 :
print(f"Neded to recompute paths {i} times because of unconnected loops...")
print_res(res, order, landmarks, P)
print_res(L, landmarks, P)
return order
print(np.dot(P, res.x))
return L

View File

@ -79,16 +79,16 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]:
test = landmarks_short
test.append(finish)
test.insert(0, start)
test.insert(0, start)
test.append(finish)
max_walking_time = 4 # hours
visiting_order = solve_optimization(test, max_walking_time*60, True)
visiting_list = solve_optimization(test, max_walking_time*60, True)
return len(visiting_order)
return visiting_list
test4(tuple((48.834378, 2.322113)))
test4(tuple((48.8795156, 2.3660204)))

File diff suppressed because it is too large Load Diff