Merge branch 'feature/adding-timed-visits'
This commit is contained in:
		@@ -2,5 +2,5 @@ detour_factor: 1.4
 | 
			
		||||
detour_corridor_width: 300
 | 
			
		||||
average_walking_speed: 4.8
 | 
			
		||||
max_landmarks: 10
 | 
			
		||||
max_landmarks_refiner: 20
 | 
			
		||||
overshoot: 1.3
 | 
			
		||||
max_landmarks_refiner: 30
 | 
			
		||||
overshoot: 1.8
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,11 @@ class Landmark(BaseModel) :
 | 
			
		||||
    attractiveness : int
 | 
			
		||||
    n_tags : int
 | 
			
		||||
    image_url : Optional[str] = None                            # TODO future
 | 
			
		||||
    website_url : Optional[str] = None
 | 
			
		||||
    wikipedia_url : Optional[str] = None
 | 
			
		||||
    description : Optional[str] = None                          # TODO future
 | 
			
		||||
    duration : Optional[int] = 0                                # TODO future
 | 
			
		||||
    name_en : Optional[str] = None
 | 
			
		||||
 | 
			
		||||
    # Unique ID of a given landmark
 | 
			
		||||
    uuid: str = Field(default_factory=uuid4)                    # TODO implement this ASAP
 | 
			
		||||
@@ -33,7 +36,9 @@ class Landmark(BaseModel) :
 | 
			
		||||
        return self.uuid.int
 | 
			
		||||
    
 | 
			
		||||
    def __str__(self) -> str:
 | 
			
		||||
        time_to_next_str = f"time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else ""
 | 
			
		||||
        # return f'Landmark({self.type}): [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}]'
 | 
			
		||||
        return f'({self.type[:4]}),  score={self.attractiveness}\tmain:{not self.is_secondary}\tduration={self.duration}\t{time_to_next_str}\t{self.name}'
 | 
			
		||||
        time_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else ""
 | 
			
		||||
        is_secondary_str = f", secondary" if self.is_secondary else ""
 | 
			
		||||
        type_str = '(' + self.type + ')'
 | 
			
		||||
        if self.type in ["start", "finish", "nature", "shopping"] : type_str += '\t '
 | 
			
		||||
        return f'Landmark{type_str}: [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}{is_secondary_str}]'
 | 
			
		||||
    
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ class LinkedLandmarks:
 | 
			
		||||
        
 | 
			
		||||
        # Update 'is_secondary' for landmarks with attractiveness below the threshold score
 | 
			
		||||
        for landmark in self._landmarks:
 | 
			
		||||
            if landmark.attractiveness < threshold_score:
 | 
			
		||||
            if landmark.attractiveness < threshold_score and landmark.type not in ["start", "finish"]:
 | 
			
		||||
                landmark.is_secondary = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,9 +23,8 @@ def test(start_coords: tuple[float, float], finish_coords: tuple[float, float] =
 | 
			
		||||
        sightseeing=Preference(type='sightseeing', score = 5),
 | 
			
		||||
        nature=Preference(type='nature', score = 5),
 | 
			
		||||
        shopping=Preference(type='shopping', score = 5),
 | 
			
		||||
 | 
			
		||||
        max_time_minute=300,
 | 
			
		||||
        detour_tolerance_minute=15
 | 
			
		||||
        max_time_minute=100,
 | 
			
		||||
        detour_tolerance_minute=0
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Create start and finish 
 | 
			
		||||
@@ -64,10 +63,7 @@ def test(start_coords: tuple[float, float], finish_coords: tuple[float, float] =
 | 
			
		||||
    logger.info("Optimized route : ")
 | 
			
		||||
    for l in linked_tour :
 | 
			
		||||
        logger.info(f"{l}")
 | 
			
		||||
        total_time += l.duration
 | 
			
		||||
        total_time += l.time_to_reach_next
 | 
			
		||||
 | 
			
		||||
    logger.info(f"Total time: {total_time}")
 | 
			
		||||
    logger.info(f"Estimated length of tour : {linked_tour.total_time} mintutes and visiting {len(linked_tour._landmarks)} landmarks.")
 | 
			
		||||
 | 
			
		||||
    # with open('linked_tour.yaml', 'w') as f:
 | 
			
		||||
    #     yaml.dump(linked_tour.asdict(), f)
 | 
			
		||||
@@ -78,6 +74,6 @@ def test(start_coords: tuple[float, float], finish_coords: tuple[float, float] =
 | 
			
		||||
# test(tuple((48.8344400, 2.3220540)))       # Café Chez César 
 | 
			
		||||
# test(tuple((48.8375946, 2.2949904)))       # Point random
 | 
			
		||||
# test(tuple((47.377859, 8.540585)))         # Zurich HB
 | 
			
		||||
test(tuple((45.7576485, 4.8330241)))      # Lyon Bellecour
 | 
			
		||||
# test(tuple((48.5848435, 7.7332974)))      # Strasbourg Gare
 | 
			
		||||
# test(tuple((45.758217, 4.831814)))      # Lyon Bellecour
 | 
			
		||||
test(tuple((48.5848435, 7.7332974)))      # Strasbourg Gare
 | 
			
		||||
# test(tuple((48.2067858, 16.3692340)))      # Vienne
 | 
			
		||||
 
 | 
			
		||||
@@ -81,19 +81,19 @@ class LandmarkManager:
 | 
			
		||||
        bbox = self.create_bbox(center_coordinates, reachable_bbox_side)
 | 
			
		||||
        # list for sightseeing
 | 
			
		||||
        if preferences.sightseeing.score != 0:
 | 
			
		||||
            score_function = lambda score: int(score*10)*preferences.sightseeing.score/5   # 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 score: int(score*10*self.nature_coeff)*preferences.nature.score/5   # 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 score: int(score*10)*preferences.shopping.score/5 # 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
 | 
			
		||||
 | 
			
		||||
@@ -290,7 +290,10 @@ class LandmarkManager:
 | 
			
		||||
                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
 | 
			
		||||
 | 
			
		||||
                website_url = None
 | 
			
		||||
                wikpedia_url = None
 | 
			
		||||
                image_url = None
 | 
			
		||||
                name_en = None
 | 
			
		||||
 | 
			
		||||
                # remove specific tags
 | 
			
		||||
                skip = False
 | 
			
		||||
@@ -304,7 +307,7 @@ class LandmarkManager:
 | 
			
		||||
 | 
			
		||||
                    if "wiki" in tag:
 | 
			
		||||
                        score += self.wikipedia_bonus             # wikipedia entries count more
 | 
			
		||||
 | 
			
		||||
                        
 | 
			
		||||
                    # if tag == "wikidata":
 | 
			
		||||
                    #     Q = elem.tag('wikidata')
 | 
			
		||||
                    #     site = Site("wikidata", "wikidata")
 | 
			
		||||
@@ -315,6 +318,7 @@ class LandmarkManager:
 | 
			
		||||
 | 
			
		||||
                    if "viewpoint" in tag:
 | 
			
		||||
                        score += self.viewpoint_bonus
 | 
			
		||||
                        duration = 10
 | 
			
		||||
 | 
			
		||||
                    if "image" in tag:
 | 
			
		||||
                        score += self.image_bonus
 | 
			
		||||
@@ -331,26 +335,31 @@ class LandmarkManager:
 | 
			
		||||
                        if tag == "building" and elem.tag('building') in ['retail', 'supermarket', 'parking']:
 | 
			
		||||
                            skip = True
 | 
			
		||||
                            break
 | 
			
		||||
                    
 | 
			
		||||
                    # Get additional information
 | 
			
		||||
                    # if tag == 'wikipedia' :
 | 
			
		||||
                    #     wikpedia_url = elem.tag('wikipedia')
 | 
			
		||||
                    if tag in ['website', 'contact:website'] :
 | 
			
		||||
                        website_url = elem.tag(tag)
 | 
			
		||||
                    if tag == 'image' :
 | 
			
		||||
                        image_url = elem.tag('image')
 | 
			
		||||
                    if tag =='name:en' :
 | 
			
		||||
                        name_en = elem.tag('name:en')
 | 
			
		||||
 | 
			
		||||
                if skip:
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
                score = score_function(score)
 | 
			
		||||
                if "place_of_worship" in elem.tags().values() :
 | 
			
		||||
                    score = int(score*self.church_coeff)
 | 
			
		||||
                    duration = 20
 | 
			
		||||
                    duration = 15
 | 
			
		||||
                
 | 
			
		||||
                elif "museum" in elem.tags().values() :
 | 
			
		||||
                    score = int(score*self.church_coeff)
 | 
			
		||||
                    duration = 60
 | 
			
		||||
                
 | 
			
		||||
                elif "fountain" in elem.tags().values() :
 | 
			
		||||
                    duration = 5
 | 
			
		||||
                
 | 
			
		||||
                elif "park" in elem.tags().values() :
 | 
			
		||||
                    duration = 30
 | 
			
		||||
                
 | 
			
		||||
                else : 
 | 
			
		||||
                    duration = 15
 | 
			
		||||
                    duration = 5
 | 
			
		||||
 | 
			
		||||
                # Generate the landmark and append it to the list
 | 
			
		||||
                landmark = Landmark(
 | 
			
		||||
@@ -362,7 +371,11 @@ class LandmarkManager:
 | 
			
		||||
                    attractiveness=score,
 | 
			
		||||
                    must_do=False,
 | 
			
		||||
                    n_tags=int(n_tags),
 | 
			
		||||
                    duration = duration
 | 
			
		||||
                    duration = duration, 
 | 
			
		||||
                    name_en=name_en,
 | 
			
		||||
                    image_url=image_url,
 | 
			
		||||
                    # wikipedia_url=wikpedia_url,
 | 
			
		||||
                    website_url=website_url
 | 
			
		||||
                )
 | 
			
		||||
                return_list.append(landmark)
 | 
			
		||||
        
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ class Optimizer:
 | 
			
		||||
    detour_factor: float            # detour factor of straight line vs real distance in cities
 | 
			
		||||
    average_walking_speed: float    # average walking speed of adult
 | 
			
		||||
    max_landmarks: int              # max number of landmarks to visit
 | 
			
		||||
    overshoot: float                # experimentally determined overshoot possibility to return long enough tours
 | 
			
		||||
    overshoot: float                # overshoot to allow maxtime to overflow. Optimizer is a bit restrictive
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __init__(self) :
 | 
			
		||||
@@ -178,7 +178,7 @@ class Optimizer:
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            landmarks (list[Landmark]): List of landmarks.
 | 
			
		||||
            max_time (int): Maximum time allowed for tour.
 | 
			
		||||
            max_time (int): Maximum time of visit allowed.
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            Tuple[list[float], list[float], list[int]]: Objective function coefficients, inequality constraint coefficients, and the right-hand side of the inequality constraint.
 | 
			
		||||
@@ -195,7 +195,7 @@ class Optimizer:
 | 
			
		||||
            for j, spot2 in enumerate(landmarks) :
 | 
			
		||||
                t = get_time(spot1.location, spot2.location) + spot1.duration
 | 
			
		||||
                dist_table[j] = t
 | 
			
		||||
            closest = sorted(dist_table)[:22]
 | 
			
		||||
            closest = sorted(dist_table)[:25]
 | 
			
		||||
            for i, dist in enumerate(dist_table) :
 | 
			
		||||
                if dist not in closest :
 | 
			
		||||
                    dist_table[i] = 32700
 | 
			
		||||
@@ -476,7 +476,7 @@ class Optimizer:
 | 
			
		||||
        A, b = self.respect_start_finish(L)                  # Force start and finish positions
 | 
			
		||||
        A_eq = np.vstack((A_eq, A), dtype=np.int8)
 | 
			
		||||
        b_eq += b
 | 
			
		||||
        A, b = self.respect_order(L)                         # Respect order of visit (only works when max_steps is limiting factor)
 | 
			
		||||
        A, b = self.respect_order(L)                         # Respect order of visit (only works when max_time is limiting factor)
 | 
			
		||||
        A_eq = np.vstack((A_eq, A), dtype=np.int8)
 | 
			
		||||
        b_eq += b
 | 
			
		||||
        
 | 
			
		||||
 
 | 
			
		||||
@@ -214,7 +214,7 @@ class Refiner :
 | 
			
		||||
            if self.is_in_area(area, landmark.location) and landmark.name not in visited_names:
 | 
			
		||||
                second_order_landmarks.append(landmark)
 | 
			
		||||
 | 
			
		||||
        return take_most_important.take_most_important(second_order_landmarks, len(visited_landmarks))
 | 
			
		||||
        return take_most_important.take_most_important(second_order_landmarks, int(self.max_landmarks_refiner*0.75))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # Try fix the shortest path using shapely
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user