vincentiusyoshuac commited on
Commit
e4ae25f
·
verified ·
1 Parent(s): 37485e4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -35
app.py CHANGED
@@ -8,24 +8,17 @@ import time
8
  from functools import lru_cache
9
  from concurrent.futures import ThreadPoolExecutor
10
 
11
- def held_karp_tsp(dist_matrix: np.ndarray, return_to_start: bool = True, start_idx: int = 0, end_idx: int = None) -> tuple:
 
 
 
 
12
  if len(dist_matrix) < 2:
13
  return 0, []
14
 
15
  n = len(dist_matrix)
16
  inf = float('inf')
17
 
18
- if start_idx != 0:
19
- new_matrix = dist_matrix.copy()
20
- new_matrix[[0, start_idx]] = new_matrix[[start_idx, 0]]
21
- new_matrix[:, [0, start_idx]] = new_matrix[:, [start_idx, 0]]
22
- dist_matrix = new_matrix
23
-
24
- if end_idx == 0:
25
- end_idx = start_idx
26
- elif end_idx == start_idx:
27
- end_idx = 0
28
-
29
  dp = np.full((1 << n, n), inf)
30
  parent = np.full((1 << n, n), -1, dtype=int)
31
 
@@ -52,12 +45,8 @@ def held_karp_tsp(dist_matrix: np.ndarray, return_to_start: bool = True, start_i
52
  curr = min(range(n), key=lambda x: dp[mask][x] + dist_matrix[x][0])
53
  final_cost = dp[mask][curr] + dist_matrix[curr][0]
54
  else:
55
- if end_idx is not None:
56
- curr = end_idx if end_idx < start_idx else (end_idx - 1)
57
- final_cost = dp[mask][curr]
58
- else:
59
- curr = min(range(n), key=lambda x: dp[mask][x])
60
- final_cost = dp[mask][curr]
61
 
62
  path = []
63
  while curr != -1:
@@ -70,13 +59,14 @@ def held_karp_tsp(dist_matrix: np.ndarray, return_to_start: bool = True, start_i
70
  path.append(0)
71
  path.reverse()
72
 
73
- if start_idx != 0:
74
- path = [(i if i != 0 else start_idx) if i != start_idx else 0 for i in path]
75
-
76
  return final_cost, path
77
 
78
  @st.cache_data
79
  def get_route_osrm(start_coords: tuple, end_coords: tuple) -> tuple:
 
 
 
 
80
  try:
81
  coords = f"{start_coords[1]},{start_coords[0]};{end_coords[1]},{end_coords[0]}"
82
  url = f"http://router.project-osrm.org/route/v1/driving/{coords}"
@@ -108,6 +98,7 @@ def get_route_osrm(start_coords: tuple, end_coords: tuple) -> tuple:
108
 
109
  @st.cache_data
110
  def cached_geocoding(city_name: str) -> tuple:
 
111
  try:
112
  geolocator = Nominatim(user_agent="tsp_app")
113
  location = geolocator.geocode(city_name, timeout=10)
@@ -119,6 +110,9 @@ def cached_geocoding(city_name: str) -> tuple:
119
  return None
120
 
121
  def create_distance_matrix_with_routes(coordinates: list) -> tuple:
 
 
 
122
  valid_coordinates = [c for c in coordinates if c is not None]
123
  n = len(valid_coordinates)
124
 
@@ -155,6 +149,9 @@ def create_distance_matrix_with_routes(coordinates: list) -> tuple:
155
 
156
  def plot_route_with_roads(map_obj: folium.Map, coordinates: list, route: list,
157
  city_names: list, routes_dict: dict, return_to_start: bool) -> folium.Map:
 
 
 
158
  route_group = folium.FeatureGroup(name="Route")
159
 
160
  for i in range(len(route)-1):
@@ -216,7 +213,7 @@ def main():
216
 
217
  trip_type = st.radio(
218
  "Tipe Perjalanan",
219
- ["Single Trip (Titik awal ke titik akhir)", "Closed Loop (Kembali ke titik awal)"],
220
  help="Pilih apakah Anda ingin kembali ke lokasi awal atau tidak"
221
  )
222
  return_to_start = trip_type.startswith("Closed Loop")
@@ -234,9 +231,8 @@ def main():
234
  city_coords = []
235
 
236
  for i in range(city_count):
237
- label = "Kota Asal" if i == 0 else "Kota Tujuan" if i == city_count-1 else f"Kota {i+1}"
238
  city_name = st.text_input(
239
- label,
240
  value=st.session_state.city_inputs[i],
241
  key=f"city_{i}"
242
  )
@@ -252,7 +248,7 @@ def main():
252
 
253
  with col2:
254
  if not city_coords:
255
- map_center = [-2.548926, 118.014863]
256
  zoom_start = 5
257
  else:
258
  map_center = city_coords[0]
@@ -268,16 +264,7 @@ def main():
268
  start_time = time.time()
269
 
270
  dist_matrix, valid_coordinates, routes_dict = create_distance_matrix_with_routes(city_coords)
271
-
272
- start_idx = 0
273
- end_idx = len(valid_coordinates) - 1 if not return_to_start else None
274
-
275
- min_cost, optimal_route = held_karp_tsp(
276
- dist_matrix,
277
- return_to_start=return_to_start,
278
- start_idx=start_idx,
279
- end_idx=end_idx
280
- )
281
 
282
  end_time = time.time()
283
 
 
8
  from functools import lru_cache
9
  from concurrent.futures import ThreadPoolExecutor
10
 
11
+ def held_karp_tsp(dist_matrix: np.ndarray, return_to_start: bool = True) -> tuple:
12
+ """
13
+ Modified Held-Karp algorithm for solving TSP
14
+ Returns: (minimum cost, optimal route)
15
+ """
16
  if len(dist_matrix) < 2:
17
  return 0, []
18
 
19
  n = len(dist_matrix)
20
  inf = float('inf')
21
 
 
 
 
 
 
 
 
 
 
 
 
22
  dp = np.full((1 << n, n), inf)
23
  parent = np.full((1 << n, n), -1, dtype=int)
24
 
 
45
  curr = min(range(n), key=lambda x: dp[mask][x] + dist_matrix[x][0])
46
  final_cost = dp[mask][curr] + dist_matrix[curr][0]
47
  else:
48
+ curr = min(range(n), key=lambda x: dp[mask][x])
49
+ final_cost = dp[mask][curr]
 
 
 
 
50
 
51
  path = []
52
  while curr != -1:
 
59
  path.append(0)
60
  path.reverse()
61
 
 
 
 
62
  return final_cost, path
63
 
64
  @st.cache_data
65
  def get_route_osrm(start_coords: tuple, end_coords: tuple) -> tuple:
66
+ """
67
+ Get route using OSRM public API
68
+ Returns: (distance in km, encoded polyline of the route)
69
+ """
70
  try:
71
  coords = f"{start_coords[1]},{start_coords[0]};{end_coords[1]},{end_coords[0]}"
72
  url = f"http://router.project-osrm.org/route/v1/driving/{coords}"
 
98
 
99
  @st.cache_data
100
  def cached_geocoding(city_name: str) -> tuple:
101
+ """Cache geocoding results"""
102
  try:
103
  geolocator = Nominatim(user_agent="tsp_app")
104
  location = geolocator.geocode(city_name, timeout=10)
 
110
  return None
111
 
112
  def create_distance_matrix_with_routes(coordinates: list) -> tuple:
113
+ """
114
+ Create distance matrix and store routes between all points using OSRM
115
+ """
116
  valid_coordinates = [c for c in coordinates if c is not None]
117
  n = len(valid_coordinates)
118
 
 
149
 
150
  def plot_route_with_roads(map_obj: folium.Map, coordinates: list, route: list,
151
  city_names: list, routes_dict: dict, return_to_start: bool) -> folium.Map:
152
+ """
153
+ Plot route using actual road paths from OSRM
154
+ """
155
  route_group = folium.FeatureGroup(name="Route")
156
 
157
  for i in range(len(route)-1):
 
213
 
214
  trip_type = st.radio(
215
  "Tipe Perjalanan",
216
+ ["Closed Loop (Kembali ke titik awal)", "Single Trip (Tidak kembali ke titik awal)"],
217
  help="Pilih apakah Anda ingin kembali ke lokasi awal atau tidak"
218
  )
219
  return_to_start = trip_type.startswith("Closed Loop")
 
231
  city_coords = []
232
 
233
  for i in range(city_count):
 
234
  city_name = st.text_input(
235
+ f"Kota {i+1}",
236
  value=st.session_state.city_inputs[i],
237
  key=f"city_{i}"
238
  )
 
248
 
249
  with col2:
250
  if not city_coords:
251
+ map_center = [-2.548926, 118.014863] # Center of Indonesia
252
  zoom_start = 5
253
  else:
254
  map_center = city_coords[0]
 
264
  start_time = time.time()
265
 
266
  dist_matrix, valid_coordinates, routes_dict = create_distance_matrix_with_routes(city_coords)
267
+ min_cost, optimal_route = held_karp_tsp(dist_matrix, return_to_start)
 
 
 
 
 
 
 
 
 
268
 
269
  end_time = time.time()
270