permafixed the optimizer ???
This commit is contained in:
parent
568e7bfbc4
commit
30ed2bb9ed
@ -8,5 +8,5 @@ geological
|
|||||||
'tourism'='alpine_hut'
|
'tourism'='alpine_hut'
|
||||||
'tourism'='viewpoint'
|
'tourism'='viewpoint'
|
||||||
'tourism'='zoo'
|
'tourism'='zoo'
|
||||||
#'tourism'='artwork'
|
'tourism'='artwork'
|
||||||
'waterway'='waterfall'
|
'waterway'='waterfall'
|
@ -31,7 +31,7 @@ def print_res(L: List[Landmark], L_tot):
|
|||||||
|
|
||||||
|
|
||||||
# Prevent the use of a particular solution
|
# Prevent the use of a particular solution
|
||||||
def prevent_config(resx, A_ub, b_ub):
|
def prevent_config(resx):
|
||||||
|
|
||||||
for i, elem in enumerate(resx):
|
for i, elem in enumerate(resx):
|
||||||
resx[i] = round(elem)
|
resx[i] = round(elem)
|
||||||
@ -52,13 +52,10 @@ def prevent_config(resx, A_ub, b_ub):
|
|||||||
if i in vertices_visited :
|
if i in vertices_visited :
|
||||||
h[i*L:i*L+L] = ones
|
h[i*L:i*L+L] = ones
|
||||||
|
|
||||||
A_ub = np.vstack((A_ub, h))
|
return h, [len(vertices_visited)-1]
|
||||||
b_ub.append(len(vertices_visited)-1)
|
|
||||||
|
|
||||||
return A_ub, b_ub
|
|
||||||
|
|
||||||
|
|
||||||
def prevent_circle(circle_vertices: list, L: int, A_eq: list, b_eq: list) :
|
def prevent_circle(circle_vertices: list, L: int) :
|
||||||
|
|
||||||
l1 = [0]*L*L
|
l1 = [0]*L*L
|
||||||
l2 = [0]*L*L
|
l2 = [0]*L*L
|
||||||
@ -74,12 +71,7 @@ def prevent_circle(circle_vertices: list, L: int, A_eq: list, b_eq: list) :
|
|||||||
l1[g*L + s] = 1
|
l1[g*L + s] = 1
|
||||||
l2[s*L + g] = 1
|
l2[s*L + g] = 1
|
||||||
|
|
||||||
A_eq = np.vstack((A_eq, l1))
|
return np.vstack((l1, l2)), [0, 0]
|
||||||
b_eq.append(0)
|
|
||||||
A_eq = np.vstack((A_eq, l2))
|
|
||||||
b_eq.append(0)
|
|
||||||
|
|
||||||
return A_eq, b_eq
|
|
||||||
|
|
||||||
# Prevent the possibility of a given solution bit
|
# Prevent the possibility of a given solution bit
|
||||||
def break_circle(circle_vertices: list, L: int, A_ub: list, b_ub: list):
|
def break_circle(circle_vertices: list, L: int, A_ub: list, b_ub: list):
|
||||||
@ -340,14 +332,16 @@ def init_ub_dist(landmarks: List[Landmark], max_steps: int):
|
|||||||
|
|
||||||
|
|
||||||
# Constraint to respect only one travel per landmark. Also caps the total number of visited landmarks
|
# Constraint to respect only one travel per landmark. Also caps the total number of visited landmarks
|
||||||
def respect_number(L: int, A_ub, b_ub, max_landmarks):
|
def respect_number(L: int, max_landmarks: int):
|
||||||
|
|
||||||
ones = [1]*L
|
ones = [1]*L
|
||||||
zeros = [0]*L
|
zeros = [0]*L
|
||||||
for i in range(L) :
|
A = ones + zeros*(L-1)
|
||||||
h = zeros*i + ones + zeros*(L-1-i)
|
b = [1]
|
||||||
A_ub = np.vstack((A_ub, h))
|
for i in range(L-1) :
|
||||||
b_ub.append(1)
|
h_new = zeros*i + ones + zeros*(L-1-i)
|
||||||
|
A = np.vstack((A, h_new))
|
||||||
|
b.append(1)
|
||||||
|
|
||||||
if max_landmarks is None :
|
if max_landmarks is None :
|
||||||
# Read the parameters from the file
|
# Read the parameters from the file
|
||||||
@ -355,29 +349,35 @@ def respect_number(L: int, A_ub, b_ub, max_landmarks):
|
|||||||
parameters = json.loads(f.read())
|
parameters = json.loads(f.read())
|
||||||
max_landmarks = parameters['max landmarks']
|
max_landmarks = parameters['max landmarks']
|
||||||
|
|
||||||
A_ub = np.vstack((A_ub, ones*L))
|
A = np.vstack((A, ones*L))
|
||||||
b_ub.append(max_landmarks+1)
|
b.append(max_landmarks+1)
|
||||||
|
|
||||||
return A_ub, b_ub
|
return A, b
|
||||||
|
|
||||||
|
|
||||||
# Constraint to not have d14 and d41 simultaneously. Does not prevent circular symmetry with more elements
|
# Constraint to not have d14 and d41 simultaneously. Does not prevent cyclic paths with more elements
|
||||||
def break_sym(L, A_ub, b_ub):
|
def break_sym(L):
|
||||||
|
|
||||||
upper_ind = np.triu_indices(L,0,L)
|
upper_ind = np.triu_indices(L,0,L)
|
||||||
|
|
||||||
up_ind_x = upper_ind[0]
|
up_ind_x = upper_ind[0]
|
||||||
up_ind_y = upper_ind[1]
|
up_ind_y = upper_ind[1]
|
||||||
|
|
||||||
for i, _ in enumerate(up_ind_x) :
|
A = [0]*L*L # useless row to prevent overhead ? better solution welcomed
|
||||||
|
# A[up_ind_x[0]*L + up_ind_y[0]] = 1
|
||||||
|
# A[up_ind_y[0]*L + up_ind_x[0]] = 1
|
||||||
|
b = [1]
|
||||||
|
|
||||||
|
for i, _ in enumerate(up_ind_x[1:]) :
|
||||||
l = [0]*L*L
|
l = [0]*L*L
|
||||||
if up_ind_x[i] != up_ind_y[i] :
|
if up_ind_x[i] != up_ind_y[i] :
|
||||||
l[up_ind_x[i]*L + up_ind_y[i]] = 1
|
l[up_ind_x[i]*L + up_ind_y[i]] = 1
|
||||||
l[up_ind_y[i]*L + up_ind_x[i]] = 1
|
l[up_ind_y[i]*L + up_ind_x[i]] = 1
|
||||||
|
|
||||||
A_ub = np.vstack((A_ub,l))
|
A = np.vstack((A,l))
|
||||||
b_ub.append(1)
|
b.append(1)
|
||||||
|
|
||||||
return A_ub, b_ub
|
return A, b
|
||||||
|
|
||||||
|
|
||||||
# Constraint to not stay in position. Removes d11, d22, d33, etc.
|
# Constraint to not stay in position. Removes d11, d22, d33, etc.
|
||||||
@ -395,22 +395,24 @@ def init_eq_not_stay(L: int):
|
|||||||
|
|
||||||
|
|
||||||
# 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 where attractiveness is set to -1
|
||||||
def respect_user_mustsee(landmarks: List[Landmark], A_eq: list, b_eq: list) :
|
def respect_user_mustsee(landmarks: List[Landmark]) :
|
||||||
L = len(landmarks)
|
L = len(landmarks)
|
||||||
|
|
||||||
for i, elem in enumerate(landmarks) :
|
A = [0]*L*L
|
||||||
|
b = [0]
|
||||||
|
for i, elem in enumerate(landmarks[1:]) :
|
||||||
if elem.must_do is True and elem.name not in ['finish', 'start']:
|
if elem.must_do is True and elem.name not in ['finish', 'start']:
|
||||||
l = [0]*L*L
|
l = [0]*L*L
|
||||||
l[i*L:i*L+L] = [1]*L # set mandatory departures from landmarks tagged as 'must_do'
|
l[i*L:i*L+L] = [1]*L # set mandatory departures from landmarks tagged as 'must_do'
|
||||||
|
|
||||||
A_eq = np.vstack((A_eq,l))
|
A = np.vstack((A,l))
|
||||||
b_eq.append(1)
|
b.append(1)
|
||||||
|
|
||||||
return A_eq, b_eq
|
return A, b
|
||||||
|
|
||||||
|
|
||||||
# Constraint to ensure start at start and finish at goal
|
# Constraint to ensure start at start and finish at goal
|
||||||
def respect_start_finish(L: int, A_eq: list, b_eq: list):
|
def respect_start_finish(L: int):
|
||||||
l_start = [1]*L + [0]*L*(L-1) # sets departures only for start (horizontal ones)
|
l_start = [1]*L + [0]*L*(L-1) # sets departures only for start (horizontal ones)
|
||||||
l_start[L-1] = 0 # prevents the jump from start to finish
|
l_start[L-1] = 0 # prevents the jump from start to finish
|
||||||
l_goal = [0]*L*L # sets arrivals only for finish (vertical ones)
|
l_goal = [0]*L*L # sets arrivals only for finish (vertical ones)
|
||||||
@ -421,32 +423,33 @@ def respect_start_finish(L: int, A_eq: list, b_eq: list):
|
|||||||
l_goal[k*L+L-1] = 1
|
l_goal[k*L+L-1] = 1
|
||||||
|
|
||||||
|
|
||||||
A_eq = np.vstack((A_eq,l_start))
|
A = np.vstack((l_start, l_goal))
|
||||||
A_eq = np.vstack((A_eq,l_goal))
|
b = [1, 1]
|
||||||
A_eq = np.vstack((A_eq,l_L))
|
A = np.vstack((A,l_L))
|
||||||
b_eq.append(1)
|
b.append(0)
|
||||||
b_eq.append(1)
|
|
||||||
b_eq.append(0)
|
|
||||||
|
|
||||||
return A_eq, b_eq
|
return A, b
|
||||||
|
|
||||||
|
|
||||||
# Constraint to tie the problem together. Necessary but not sufficient to avoid circles
|
# Constraint to tie the problem together. Necessary but not sufficient to avoid circles
|
||||||
def respect_order(N: int, A_eq, b_eq):
|
def respect_order(L: int):
|
||||||
for i in range(N-1) : # Prevent stacked ones
|
|
||||||
if i == 0 or i == N-1: # Don't touch start or finish
|
A = [0]*L*L # useless row to reduce overhead ? better solution is welcome
|
||||||
|
b = [0]
|
||||||
|
for i in range(L-1) : # Prevent stacked ones
|
||||||
|
if i == 0 or i == L-1: # Don't touch start or finish
|
||||||
continue
|
continue
|
||||||
else :
|
else :
|
||||||
l = [0]*N
|
l = [0]*L
|
||||||
l[i] = -1
|
l[i] = -1
|
||||||
l = l*N
|
l = l*L
|
||||||
for j in range(N) :
|
for j in range(L) :
|
||||||
l[i*N + j] = 1
|
l[i*L + j] = 1
|
||||||
|
|
||||||
A_eq = np.vstack((A_eq,l))
|
A = np.vstack((A,l))
|
||||||
b_eq.append(0)
|
b.append(0)
|
||||||
|
|
||||||
return A_eq, b_eq
|
return A, b
|
||||||
|
|
||||||
|
|
||||||
# Computes the time to reach from each landmark to the next
|
# Computes the time to reach from each landmark to the next
|
||||||
@ -515,14 +518,25 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
|
|||||||
|
|
||||||
# SET CONSTRAINTS FOR INEQUALITY
|
# SET CONSTRAINTS FOR INEQUALITY
|
||||||
c, A_ub, b_ub = init_ub_dist(landmarks, max_steps) # Add the distances from each landmark to the other
|
c, A_ub, b_ub = init_ub_dist(landmarks, max_steps) # Add the distances from each landmark to the other
|
||||||
A_ub, b_ub = respect_number(L, A_ub, b_ub, max_landmarks) # Respect max number of visits (no more possible stops than landmarks).
|
A, b = respect_number(L, max_landmarks) # Respect max number of visits (no more possible stops than landmarks).
|
||||||
A_ub, b_ub = break_sym(L, A_ub, b_ub) # break the 'zig-zag' symmetry
|
A_ub = np.vstack((A_ub, A))
|
||||||
|
b_ub += b
|
||||||
|
A, b = break_sym(L) # break the 'zig-zag' symmetry
|
||||||
|
A_ub = np.vstack((A_ub, A))
|
||||||
|
b_ub += b
|
||||||
|
|
||||||
|
|
||||||
# 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_eq, b_eq = respect_user_mustsee(landmarks, A_eq, b_eq) # Check if there are user_defined must_see. Also takes care of start/goal
|
A, b = respect_user_mustsee(landmarks) # Check if there are user_defined must_see. Also takes care of start/goal
|
||||||
A_eq, b_eq = respect_start_finish(L, A_eq, b_eq) # Force start and finish positions
|
A_eq = np.vstack((A_eq, A))
|
||||||
A_eq, b_eq = respect_order(L, A_eq, b_eq) # Respect order of visit (only works when max_steps is limiting factor)
|
b_eq += b
|
||||||
|
A, b = respect_start_finish(L) # Force start and finish positions
|
||||||
|
A_eq = np.vstack((A_eq, A))
|
||||||
|
b_eq += b
|
||||||
|
A, b = respect_order(L) # Respect order of visit (only works when max_steps is limiting factor)
|
||||||
|
A_eq = np.vstack((A_eq, A))
|
||||||
|
b_eq += b
|
||||||
|
|
||||||
# SET BOUNDS FOR DECISION VARIABLE (x can only be 0 or 1)
|
# SET BOUNDS FOR DECISION VARIABLE (x can only be 0 or 1)
|
||||||
x_bounds = [(0, 1)]*L*L
|
x_bounds = [(0, 1)]*L*L
|
||||||
@ -541,10 +555,14 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
|
|||||||
i = 0
|
i = 0
|
||||||
timeout = 80
|
timeout = 80
|
||||||
while circles is not None and i < timeout:
|
while circles is not None and i < timeout:
|
||||||
A_ub, b_ub = prevent_config(res.x, A_ub, b_ub)
|
A, b = prevent_config(res.x)
|
||||||
|
A_ub = np.vstack((A_ub, A))
|
||||||
|
b_ub += b
|
||||||
#A_ub, b_ub = prevent_circle(order, len(landmarks), A_ub, b_ub)
|
#A_ub, b_ub = prevent_circle(order, len(landmarks), A_ub, b_ub)
|
||||||
for circle in circles :
|
for circle in circles :
|
||||||
A_ub, b_ub = prevent_circle(circle, len(landmarks), A_ub, b_ub)
|
A, b = prevent_circle(circle, len(landmarks))
|
||||||
|
A_eq = np.vstack((A_eq, A))
|
||||||
|
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_connected2(res.x)
|
||||||
#nodes, edges = is_connected2(res.x)
|
#nodes, edges = is_connected2(res.x)
|
||||||
|
@ -99,8 +99,8 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]:
|
|||||||
landmarks_short.insert(0, start)
|
landmarks_short.insert(0, start)
|
||||||
landmarks_short.append(finish)
|
landmarks_short.append(finish)
|
||||||
|
|
||||||
max_walking_time = 120 # minutes
|
max_walking_time = 50 # minutes
|
||||||
detour = 30 # minutes
|
detour = 0 # minutes
|
||||||
|
|
||||||
# First stage optimization
|
# First stage optimization
|
||||||
base_tour = solve_optimization(landmarks_short, max_walking_time, True)
|
base_tour = solve_optimization(landmarks_short, max_walking_time, True)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user