cleaned up
This commit is contained in:
parent
30ed2bb9ed
commit
4896e95617
@ -55,6 +55,7 @@ def prevent_config(resx):
|
|||||||
return h, [len(vertices_visited)-1]
|
return h, [len(vertices_visited)-1]
|
||||||
|
|
||||||
|
|
||||||
|
# Prevents the creation of the same circle (both directions)
|
||||||
def prevent_circle(circle_vertices: list, L: int) :
|
def prevent_circle(circle_vertices: list, L: int) :
|
||||||
|
|
||||||
l1 = [0]*L*L
|
l1 = [0]*L*L
|
||||||
@ -73,138 +74,9 @@ def prevent_circle(circle_vertices: list, L: int) :
|
|||||||
|
|
||||||
return np.vstack((l1, l2)), [0, 0]
|
return np.vstack((l1, l2)), [0, 0]
|
||||||
|
|
||||||
# Prevent the possibility of a given solution bit
|
|
||||||
def break_circle(circle_vertices: list, L: int, A_ub: list, b_ub: list):
|
|
||||||
|
|
||||||
if L-1 in circle_vertices :
|
# Returns the order of visit as well as any circles if there are some
|
||||||
circle_vertices.remove(L-1)
|
def is_connected(resx) :
|
||||||
|
|
||||||
h = [0]*L*L
|
|
||||||
for i in range(L) :
|
|
||||||
if i in circle_vertices :
|
|
||||||
h[i*L:i*L+L] = [1]*L
|
|
||||||
|
|
||||||
A_ub = np.vstack((A_ub, h))
|
|
||||||
b_ub.append(len(circle_vertices)-1)
|
|
||||||
|
|
||||||
return A_ub, b_ub
|
|
||||||
|
|
||||||
"""
|
|
||||||
def break_circles(circle_edges_list: list, L: int, A_ub: list, b_ub: list):
|
|
||||||
|
|
||||||
for circle_edges in circle_edges_list :
|
|
||||||
if L-1 in circle_vertices :
|
|
||||||
circle_vertices.remove(L-1)
|
|
||||||
|
|
||||||
h = [0]*L*L
|
|
||||||
for i in range(L) :
|
|
||||||
if i in circle_vertices :
|
|
||||||
h[i*L:i*L+L] = [1]*L
|
|
||||||
|
|
||||||
A_ub = np.vstack((A_ub, h))
|
|
||||||
b_ub.append(len(circle_vertices)-1)
|
|
||||||
|
|
||||||
return A_ub, b_ub
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Checks if the path is connected, returns a circle if it finds one and the RESULT
|
|
||||||
def is_connected(resx):
|
|
||||||
|
|
||||||
# first round the results to have only 0-1 values
|
|
||||||
for i, elem in enumerate(resx):
|
|
||||||
resx[i] = round(elem)
|
|
||||||
|
|
||||||
N = len(resx) # length of res
|
|
||||||
L = int(np.sqrt(N)) # number of landmarks. CAST INTO INT but should not be a problem because N = L**2 by def.
|
|
||||||
n_edges = resx.sum() # number of edges
|
|
||||||
|
|
||||||
nonzeroind = np.nonzero(resx)[0] # the return is a little funny so I use the [0]
|
|
||||||
|
|
||||||
nonzero_tup = np.unravel_index(nonzeroind, (L,L))
|
|
||||||
|
|
||||||
ind_a = nonzero_tup[0].tolist()
|
|
||||||
ind_b = nonzero_tup[1].tolist()
|
|
||||||
|
|
||||||
edges = []
|
|
||||||
edges_visited = []
|
|
||||||
vertices_visited = []
|
|
||||||
|
|
||||||
for i, a in enumerate(ind_a) :
|
|
||||||
edges.append((a, ind_b[i])) # Create the list of edges
|
|
||||||
|
|
||||||
edge1 = (ind_a[0], ind_b[0])
|
|
||||||
del ind_a[0]
|
|
||||||
|
|
||||||
edges_visited.append(edge1)
|
|
||||||
vertices_visited.append(edge1[0])
|
|
||||||
|
|
||||||
remaining = edges
|
|
||||||
remaining.remove(edge1)
|
|
||||||
|
|
||||||
break_flag = False
|
|
||||||
while len(remaining) > 0 and not break_flag:
|
|
||||||
for edge2 in remaining :
|
|
||||||
if edge2[0] == edge1[1] :
|
|
||||||
"""if edge1[1] in vertices_visited :
|
|
||||||
ind_b.remove(edge2[1])
|
|
||||||
#edges_visited.append(edge2)
|
|
||||||
break_flag = True
|
|
||||||
break
|
|
||||||
else : """
|
|
||||||
vertices_visited.append(edge1[1])
|
|
||||||
ind_a.remove(edge2[0])
|
|
||||||
ind_b.remove(edge2[0])
|
|
||||||
#edges_visited.append(edge2)
|
|
||||||
remaining.remove(edge2)
|
|
||||||
edge1 = edge2
|
|
||||||
|
|
||||||
elif edge1[1] == L-1 or edge1[1] in vertices_visited:
|
|
||||||
ind_b.remove(edge1[1])
|
|
||||||
break_flag = True
|
|
||||||
break
|
|
||||||
|
|
||||||
vertices_visited.append(edge1[1])
|
|
||||||
|
|
||||||
# Return order of visit if all good
|
|
||||||
if len(vertices_visited) == n_edges +1 :
|
|
||||||
return vertices_visited, []
|
|
||||||
|
|
||||||
"""edge1 = (ind_a[0], ind_b[0])
|
|
||||||
|
|
||||||
vertices_visited.clear()
|
|
||||||
edges_visited.clear()
|
|
||||||
|
|
||||||
edges_visited.append(edge1)
|
|
||||||
vertices_visited.append(edge1[0])
|
|
||||||
|
|
||||||
remaining = edges
|
|
||||||
remaining.remove(edge1)
|
|
||||||
|
|
||||||
break_flag = False
|
|
||||||
while len(remaining) > 0 and not break_flag:
|
|
||||||
for edge2 in remaining :
|
|
||||||
if edge2[0] == edge1[1] :
|
|
||||||
# if edge1[1] in vertices_visited :
|
|
||||||
# edges_visited.append(edge2)
|
|
||||||
# break_flag = True
|
|
||||||
# break
|
|
||||||
# else :
|
|
||||||
vertices_visited.append(edge1[1])
|
|
||||||
edges_visited.append(edge2)
|
|
||||||
remaining.remove(edge2)
|
|
||||||
edge1 = edge2
|
|
||||||
|
|
||||||
elif edge1[1] == L-1 or edge1[1] in vertices_visited:
|
|
||||||
break_flag = True
|
|
||||||
break
|
|
||||||
|
|
||||||
vertices_visited.append(edge1[1])
|
|
||||||
"""
|
|
||||||
|
|
||||||
return vertices_visited, edges_visited
|
|
||||||
|
|
||||||
|
|
||||||
def is_connected2(resx) :
|
|
||||||
|
|
||||||
# first round the results to have only 0-1 values
|
# first round the results to have only 0-1 values
|
||||||
for i, elem in enumerate(resx):
|
for i, elem in enumerate(resx):
|
||||||
@ -221,9 +93,6 @@ def is_connected2(resx) :
|
|||||||
ind_a = nonzero_tup[0].tolist()
|
ind_a = nonzero_tup[0].tolist()
|
||||||
ind_b = nonzero_tup[1].tolist()
|
ind_b = nonzero_tup[1].tolist()
|
||||||
|
|
||||||
# print(f"ind_a = {ind_a}")
|
|
||||||
# print(f"ind_b = {ind_b}")
|
|
||||||
|
|
||||||
# Step 1: Create a graph representation
|
# Step 1: Create a graph representation
|
||||||
graph = defaultdict(list)
|
graph = defaultdict(list)
|
||||||
for a, b in zip(ind_a, ind_b):
|
for a, b in zip(ind_a, ind_b):
|
||||||
@ -232,7 +101,6 @@ def is_connected2(resx) :
|
|||||||
# Step 2: Function to perform BFS/DFS to extract journeys
|
# Step 2: Function to perform BFS/DFS to extract journeys
|
||||||
def get_journey(start):
|
def get_journey(start):
|
||||||
journey_nodes = []
|
journey_nodes = []
|
||||||
#journey_edges = []
|
|
||||||
visited = set()
|
visited = set()
|
||||||
stack = deque([start])
|
stack = deque([start])
|
||||||
|
|
||||||
@ -242,26 +110,21 @@ def is_connected2(resx) :
|
|||||||
visited.add(node)
|
visited.add(node)
|
||||||
journey_nodes.append(node)
|
journey_nodes.append(node)
|
||||||
for neighbor in graph[node]:
|
for neighbor in graph[node]:
|
||||||
#journey_edges.append((node, neighbor))
|
|
||||||
if neighbor not in visited:
|
if neighbor not in visited:
|
||||||
stack.append(neighbor)
|
stack.append(neighbor)
|
||||||
|
|
||||||
return journey_nodes#, journey_edges
|
return journey_nodes
|
||||||
|
|
||||||
# Step 3: Extract all journeys
|
# Step 3: Extract all journeys
|
||||||
all_journeys_nodes = []
|
all_journeys_nodes = []
|
||||||
#all_journeys_edges = []
|
|
||||||
visited_nodes = set()
|
visited_nodes = set()
|
||||||
|
|
||||||
for node in ind_a:
|
for node in ind_a:
|
||||||
if node not in visited_nodes:
|
if node not in visited_nodes:
|
||||||
journey_nodes = get_journey(node)
|
journey_nodes = get_journey(node)
|
||||||
all_journeys_nodes.append(journey_nodes)
|
all_journeys_nodes.append(journey_nodes)
|
||||||
#all_journeys_edges.append(journey_edges)
|
|
||||||
visited_nodes.update(journey_nodes)
|
visited_nodes.update(journey_nodes)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for l in all_journeys_nodes :
|
for l in all_journeys_nodes :
|
||||||
if 0 in l :
|
if 0 in l :
|
||||||
order = l
|
order = l
|
||||||
@ -274,16 +137,13 @@ def is_connected2(resx) :
|
|||||||
return order, all_journeys_nodes
|
return order, all_journeys_nodes
|
||||||
|
|
||||||
|
|
||||||
|
# Function that returns the time in minutes from one location to another
|
||||||
|
|
||||||
# Function that returns the distance in meters from one location to another
|
|
||||||
def get_time(p1: Tuple[float, float], p2: Tuple[float, float], detour: float, speed: float) :
|
def get_time(p1: Tuple[float, float], p2: Tuple[float, float], detour: float, speed: float) :
|
||||||
|
|
||||||
# Compute the straight-line distance in km
|
# Compute the straight-line distance in km
|
||||||
if p1 == p2 :
|
if p1 == p2 :
|
||||||
return 0
|
return 0
|
||||||
else:
|
else:
|
||||||
#dist = 6371.01 * acos(sin(radians(p1[0]))*sin(radians(p2[0])) + cos(radians(p1[0]))*cos(radians(p2[0]))*cos(radians(p1[1]) - radians(p2[1])))
|
|
||||||
dist = geodesic(p1, p2).kilometers
|
dist = geodesic(p1, p2).kilometers
|
||||||
|
|
||||||
# Consider the detour factor for average cityto deterline walking distance (in km)
|
# Consider the detour factor for average cityto deterline walking distance (in km)
|
||||||
@ -292,12 +152,6 @@ def get_time(p1: Tuple[float, float], p2: Tuple[float, float], detour: float, sp
|
|||||||
# Time to walk this distance (in minutes)
|
# Time to walk this distance (in minutes)
|
||||||
walk_time = walk_dist/speed*60
|
walk_time = walk_dist/speed*60
|
||||||
|
|
||||||
"""if walk_time > 15 :
|
|
||||||
walk_time = 5*round(walk_time/5)
|
|
||||||
else :
|
|
||||||
walk_time = round(walk_time)"""
|
|
||||||
|
|
||||||
|
|
||||||
return round(walk_time)
|
return round(walk_time)
|
||||||
|
|
||||||
|
|
||||||
@ -394,8 +248,8 @@ def init_eq_not_stay(L: int):
|
|||||||
return [l], [0]
|
return [l], [0]
|
||||||
|
|
||||||
|
|
||||||
# Go through the landmarks and force the optimizer to use landmarks where attractiveness is set to -1
|
# Go through the landmarks and force the optimizer to use landmarks marked as must_do
|
||||||
def respect_user_mustsee(landmarks: List[Landmark]) :
|
def respect_user_must_do(landmarks: List[Landmark]) :
|
||||||
L = len(landmarks)
|
L = len(landmarks)
|
||||||
|
|
||||||
A = [0]*L*L
|
A = [0]*L*L
|
||||||
@ -482,6 +336,7 @@ def link_list(order: List[int], landmarks: List[Landmark])->List[Landmark] :
|
|||||||
return L, total_dist
|
return L, total_dist
|
||||||
|
|
||||||
|
|
||||||
|
# Same as link_list but does it on a already ordered list
|
||||||
def link_list_simple(ordered_visit: List[Landmark])-> List[Landmark] :
|
def link_list_simple(ordered_visit: List[Landmark])-> List[Landmark] :
|
||||||
|
|
||||||
# Read the parameters from the file
|
# Read the parameters from the file
|
||||||
@ -528,7 +383,7 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
|
|||||||
|
|
||||||
# SET CONSTRAINTS FOR EQUALITY
|
# SET CONSTRAINTS FOR EQUALITY
|
||||||
A_eq, b_eq = init_eq_not_stay(L) # Force solution not to stay in same place
|
A_eq, b_eq = init_eq_not_stay(L) # Force solution not to stay in same place
|
||||||
A, b = respect_user_mustsee(landmarks) # Check if there are user_defined must_see. Also takes care of start/goal
|
A, b = respect_user_must_do(landmarks) # Check if there are user_defined must_see. Also takes care of start/goal
|
||||||
A_eq = np.vstack((A_eq, A))
|
A_eq = np.vstack((A_eq, A))
|
||||||
b_eq += b
|
b_eq += b
|
||||||
A, b = respect_start_finish(L) # Force start and finish positions
|
A, b = respect_start_finish(L) # Force start and finish positions
|
||||||
@ -550,8 +405,8 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
|
|||||||
|
|
||||||
# If there is a solution, we're good to go, just check for connectiveness
|
# If there is a solution, we're good to go, just check for connectiveness
|
||||||
else :
|
else :
|
||||||
order, circles = is_connected2(res.x)
|
order, circles = is_connected(res.x)
|
||||||
#nodes, edges = is_connected2(res.x)
|
#nodes, edges = is_connected(res.x)
|
||||||
i = 0
|
i = 0
|
||||||
timeout = 80
|
timeout = 80
|
||||||
while circles is not None and i < timeout:
|
while circles is not None and i < timeout:
|
||||||
@ -564,8 +419,8 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
|
|||||||
A_eq = np.vstack((A_eq, A))
|
A_eq = np.vstack((A_eq, A))
|
||||||
b_eq += b
|
b_eq += b
|
||||||
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq = b_eq, bounds=x_bounds, method='highs', integrality=3)
|
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq = b_eq, bounds=x_bounds, method='highs', integrality=3)
|
||||||
order, circles = is_connected2(res.x)
|
order, circles = is_connected(res.x)
|
||||||
#nodes, edges = is_connected2(res.x)
|
#nodes, edges = is_connected(res.x)
|
||||||
if circles is None :
|
if circles is None :
|
||||||
break
|
break
|
||||||
print(i)
|
print(i)
|
||||||
@ -575,7 +430,7 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
|
|||||||
raise TimeoutError(f"Optimization took too long. No solution found after {timeout} iterations.")
|
raise TimeoutError(f"Optimization took too long. No solution found after {timeout} iterations.")
|
||||||
|
|
||||||
# Add the times to reach and stop optimizing
|
# Add the times to reach and stop optimizing
|
||||||
L, total_dist = link_list(order, landmarks)
|
L, _ = link_list(order, landmarks)
|
||||||
|
|
||||||
if printing_details is True :
|
if printing_details is True :
|
||||||
if i != 0 :
|
if i != 0 :
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import os
|
|
||||||
import json
|
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from landmarks_manager import generate_landmarks
|
from landmarks_manager import generate_landmarks
|
||||||
@ -25,45 +23,6 @@ def write_data(L: List[Landmark], file_name: str):
|
|||||||
|
|
||||||
data.to_json(file_name, indent = 2, force_ascii=False)
|
data.to_json(file_name, indent = 2, force_ascii=False)
|
||||||
|
|
||||||
def test3(city_country: str) -> List[Landmark]:
|
|
||||||
|
|
||||||
|
|
||||||
preferences = Preferences(
|
|
||||||
sightseeing=Preference(
|
|
||||||
name='sightseeing',
|
|
||||||
type=LandmarkType(landmark_type='sightseeing'),
|
|
||||||
score = 5),
|
|
||||||
nature=Preference(
|
|
||||||
name='nature',
|
|
||||||
type=LandmarkType(landmark_type='nature'),
|
|
||||||
score = 0),
|
|
||||||
shopping=Preference(
|
|
||||||
name='shopping',
|
|
||||||
type=LandmarkType(landmark_type='shopping'),
|
|
||||||
score = 5))
|
|
||||||
|
|
||||||
coordinates = None
|
|
||||||
|
|
||||||
landmarks, landmarks_short = generate_landmarks(preferences=preferences, city_country=city_country, coordinates=coordinates)
|
|
||||||
|
|
||||||
#write_data(landmarks)
|
|
||||||
|
|
||||||
start = Landmark(name='start', type=LandmarkType(landmark_type='start'), location=(48.2044576, 16.3870242), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
|
||||||
finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(48.2044576, 16.3870242), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
|
||||||
|
|
||||||
|
|
||||||
test = landmarks_short
|
|
||||||
|
|
||||||
test.insert(0, start)
|
|
||||||
test.append(finish)
|
|
||||||
|
|
||||||
max_walking_time = 2 # hours
|
|
||||||
|
|
||||||
visiting_list = solve_optimization(test, max_walking_time*60, True)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test4(coordinates: tuple[float, float]) -> List[Landmark]:
|
def test4(coordinates: tuple[float, float]) -> List[Landmark]:
|
||||||
|
|
||||||
@ -116,5 +75,4 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]:
|
|||||||
test4(tuple((48.8344400, 2.3220540))) # Café Chez César
|
test4(tuple((48.8344400, 2.3220540))) # Café Chez César
|
||||||
#test4(tuple((48.8375946, 2.2949904))) # Point random
|
#test4(tuple((48.8375946, 2.2949904))) # Point random
|
||||||
#test4(tuple((47.377859, 8.540585))) # Zurich HB
|
#test4(tuple((47.377859, 8.540585))) # Zurich HB
|
||||||
#test4(tuple((45.7576485, 4.8330241))) # Lyon Bellecour
|
#test4(tuple((45.7576485, 4.8330241))) # Lyon Bellecour
|
||||||
#test3('Vienna, Austria')
|
|
Loading…
x
Reference in New Issue
Block a user