more balanced scores
All checks were successful
Build and push docker image / Build (pull_request) Successful in 1m41s

This commit is contained in:
2024-08-12 15:58:30 +02:00
parent bea3a65fec
commit da921171e9
7 changed files with 97 additions and 54 deletions

View File

@@ -23,8 +23,8 @@ class LandmarkManager:
radius_close_to: int # radius in meters
church_coeff: float # coeff to adjsut score of churches
park_coeff: float # coeff to adjust score of parks
tag_coeff: float # coeff to adjust weight of tags
nature_coeff: float # coeff to adjust score of parks
overall_coeff: float # coeff to adjust weight of tags
N_important: int # number of important landmarks to consider
@@ -38,8 +38,13 @@ class LandmarkManager:
self.max_bbox_side = parameters['city_bbox_side']
self.radius_close_to = parameters['radius_close_to']
self.church_coeff = parameters['church_coeff']
self.park_coeff = parameters['park_coeff']
self.tag_coeff = parameters['tag_coeff']
self.nature_coeff = parameters['nature_coeff']
self.overall_coeff = parameters['overall_coeff']
self.tag_exponent = parameters['tag_exponent']
self.image_bonus = parameters['image_bonus']
self.wikipedia_bonus = parameters['wikipedia_bonus']
self.viewpoint_bonus = parameters['viewpoint_bonus']
self.pay_bonus = parameters['pay_bonus']
self.N_important = parameters['N_important']
with constants.OPTIMIZER_PARAMETERS_PATH.open('r') as f:
@@ -76,25 +81,25 @@ class LandmarkManager:
bbox = self.create_bbox(center_coordinates, reachable_bbox_side)
# list for sightseeing
if preferences.sightseeing.score != 0:
score_function = lambda loc, n_tags: int((((n_tags**1.2)*self.tag_coeff) )*self.church_coeff) # self.count_elements_close_to(loc) +
score_function = lambda score: int(score*10)*preferences.sightseeing.score/5 # self.count_elements_close_to(loc) +
L1 = self.fetch_landmarks(bbox, self.amenity_selectors['sightseeing'], preferences.sightseeing.type, score_function)
L += L1
# list for nature
if preferences.nature.score != 0:
score_function = lambda loc, n_tags: int((((n_tags**1.2)*self.tag_coeff) )*self.park_coeff) # self.count_elements_close_to(loc) +
score_function = lambda score: int(score*10*self.nature_coeff)*preferences.nature.score/5 # self.count_elements_close_to(loc) +
L2 = self.fetch_landmarks(bbox, self.amenity_selectors['nature'], preferences.nature.type, score_function)
L += L2
# list for shopping
if preferences.shopping.score != 0:
score_function = lambda loc, n_tags: int(((n_tags**1.2)*self.tag_coeff)) # self.count_elements_close_to(loc) +
score_function = lambda score: int(score*10)*preferences.shopping.score/5 # self.count_elements_close_to(loc) +
L3 = self.fetch_landmarks(bbox, self.amenity_selectors['shopping'], preferences.shopping.type, score_function)
L += L3
L = self.remove_duplicates(L)
self.correct_score(L, preferences)
# self.correct_score(L, preferences)
L_constrained = take_most_important(L, self.N_important)
self.logger.info(f'Generated {len(L)} landmarks around {center_coordinates}, and constrained to {len(L_constrained)} most important ones.')
@@ -273,8 +278,8 @@ class LandmarkManager:
continue
# skip if unused
if 'disused:leisure' in elem.tags().keys():
continue
# if 'disused:leisure' in elem.tags().keys():
# continue
# skip if part of another building
if 'building:part' in elem.tags().keys() and elem.tag('building:part') == 'yes':
@@ -284,19 +289,20 @@ class LandmarkManager:
osm_id = elem.id() # Add OSM id
elem_type = landmarktype # Add the landmark type as 'sightseeing,
n_tags = len(elem.tags().keys()) # Add number of tags
score = n_tags**self.tag_exponent # Add score
# remove specific tags
skip = False
for tag in elem.tags().keys():
if "pay" in tag:
n_tags -= 1 # discard payment options for tags
score += self.pay_bonus # discard payment options for tags
if "disused" in tag:
skip = True # skip disused amenities
break
if "wikipedia" in tag:
n_tags += 1 # wikipedia entries count more
if "wiki" in tag:
score += self.wikipedia_bonus # wikipedia entries count more
# if tag == "wikidata":
# Q = elem.tag('wikidata')
@@ -305,15 +311,16 @@ class LandmarkManager:
# item.get()
# n_languages = len(item.labels)
# n_tags += n_languages/10
if "viewpoint" in tag:
n_tags += 10
score += self.viewpoint_bonus
if "image" in tag:
score += self.image_bonus
if elem_type != "nature":
if "leisure" in tag and elem.tag('leisure') == "park":
elem_type = "nature"
if elem_type == "nature":
n_tags += 1
if landmarktype != "shopping":
if "shop" in tag:
@@ -326,20 +333,22 @@ class LandmarkManager:
if skip:
continue
score = score_function(location, n_tags)
if score != 0:
# Generate the landmark and append it to the list
landmark = Landmark(
name=name,
type=elem_type,
location=location,
osm_type=osm_type,
osm_id=osm_id,
attractiveness=score,
must_do=False,
n_tags=int(n_tags)
)
return_list.append(landmark)
score = score_function(score)
if "place_of_worship" in elem.tags().values() :
score = int(score*self.church_coeff)
# Generate the landmark and append it to the list
landmark = Landmark(
name=name,
type=elem_type,
location=location,
osm_type=osm_type,
osm_id=osm_id,
attractiveness=score,
must_do=False,
n_tags=int(n_tags)
)
return_list.append(landmark)
self.logger.debug(f"Fetched {len(return_list)} landmarks of type {landmarktype} in {bbox}")

View File

@@ -203,7 +203,7 @@ class Optimizer:
return c, A_ub, [max_steps]
def respect_number(self, L: int):
def respect_number(self, L, max_landmarks: int):
"""
Generate constraints to ensure each landmark is visited only once and cap the total number of visited landmarks.
@@ -224,7 +224,7 @@ class Optimizer:
b.append(1)
A = np.vstack((A, ones*L))
b.append(self.max_landmarks+1)
b.append(max_landmarks+1)
return A, b
@@ -433,6 +433,7 @@ class Optimizer:
self,
max_time: int,
landmarks: list[Landmark],
max_landmarks: int = None
) -> list[Landmark]:
"""
Main optimization pipeline to solve the landmark visiting problem.
@@ -443,15 +444,18 @@ class Optimizer:
Args:
max_time (int): Maximum time allowed for the tour in minutes.
landmarks (list[Landmark]): List of landmarks to visit.
max_landmarks (int): Maximum number of landmarks visited
Returns:
list[Landmark]: The optimized tour of landmarks with updated travel times, or None if no valid solution is found.
"""
if max_landmarks is None :
max_landmarks = self.max_landmarks
L = len(landmarks)
# SET CONSTRAINTS FOR INEQUALITY
c, A_ub, b_ub = self.init_ub_dist(landmarks, max_time) # Add the distances from each landmark to the other
A, b = self.respect_number(L) # Respect max number of visits (no more possible stops than landmarks).
A, b = self.respect_number(L, max_landmarks) # Respect max number of visits (no more possible stops than landmarks).
A_ub = np.vstack((A_ub, A), dtype=np.int16)
b_ub += b
A, b = self.break_sym(L) # break the 'zig-zag' symmetry

View File

@@ -17,7 +17,7 @@ class Refiner :
detour_factor: float # detour factor of straight line vs real distance in cities
detour_corridor_width: float # width of the corridor around the path
average_walking_speed: float # average walking speed of adult
max_landmarks: int # max number of landmarks to visit
max_landmarks_refiner: int # max number of landmarks to visit
optimizer: Optimizer # optimizer object
def __init__(self, optimizer: Optimizer) :
@@ -29,7 +29,7 @@ class Refiner :
self.detour_factor = parameters['detour_factor']
self.detour_corridor_width = parameters['detour_corridor_width']
self.average_walking_speed = parameters['average_walking_speed']
self.max_landmarks = parameters['max_landmarks'] + 4
self.max_landmarks_refiner = parameters['max_landmarks_refiner']
def create_corridor(self, landmarks: list[Landmark], width: float) :
@@ -308,8 +308,8 @@ class Refiner :
"""
# No need to refine if no detour is taken
if detour == 0:
return base_tour
# if detour == 0:
# return base_tour
minor_landmarks = self.get_minor_landmarks(all_landmarks, base_tour, self.detour_corridor_width)
@@ -322,7 +322,8 @@ class Refiner :
# get a new tour
new_tour = self.optimizer.solve_optimization(
max_time = max_time + detour,
landmarks = full_set
landmarks = full_set,
max_landmarks = self.max_landmarks_refiner
)
if new_tour is None: