working pulp
This commit is contained in:
parent
3fe6056f3c
commit
814da4b5f6
@ -81,6 +81,7 @@ def test_bellecour(client, request) : # pylint: disable=redefined-outer-name
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
result = response.json()
|
result = response.json()
|
||||||
|
print(result)
|
||||||
landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])
|
landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])
|
||||||
|
|
||||||
# Get computation time
|
# Get computation time
|
||||||
|
@ -2,6 +2,7 @@ import yaml, logging
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pulp as pl
|
import pulp as pl
|
||||||
from scipy.optimize import linprog
|
from scipy.optimize import linprog
|
||||||
|
from scipy.sparse import lil_matrix, csr_matrix
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
|
|
||||||
from ..structs.landmark import Landmark
|
from ..structs.landmark import Landmark
|
||||||
@ -255,7 +256,7 @@ class Optimizer:
|
|||||||
incr += 1
|
incr += 1
|
||||||
|
|
||||||
|
|
||||||
# Prevent the use of a particular solution
|
# Prevent the use of a particular solution. TODO probably can be done faster just using resx
|
||||||
def prevent_config(self, resx):
|
def prevent_config(self, resx):
|
||||||
"""
|
"""
|
||||||
Prevent the use of a particular solution by adding constraints to the optimization.
|
Prevent the use of a particular solution by adding constraints to the optimization.
|
||||||
@ -331,8 +332,6 @@ class Optimizer:
|
|||||||
"""
|
"""
|
||||||
resx = np.round(resx).astype(np.int8) # round all elements and cast them to int
|
resx = np.round(resx).astype(np.int8) # round all elements and cast them to int
|
||||||
|
|
||||||
print(f"resx = ")
|
|
||||||
# for r in resx : print(r)
|
|
||||||
N = len(resx) # length of res
|
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.
|
L = int(np.sqrt(N)) # number of landmarks. CAST INTO INT but should not be a problem because N = L**2 by def.
|
||||||
|
|
||||||
@ -509,14 +508,21 @@ class Optimizer:
|
|||||||
|
|
||||||
# SET CONSTRAINTS FOR INEQUALITY
|
# SET CONSTRAINTS FOR INEQUALITY
|
||||||
c, A_ub, b_ub = self.init_ub_time(landmarks, max_time) # Adds the distances from each landmark to the other.
|
c, A_ub, b_ub = self.init_ub_time(landmarks, max_time) # Adds the distances from each landmark to the other.
|
||||||
|
print("ok1")
|
||||||
self.respect_number(A_ub, b_ub, L, max_landmarks) # Respects max number of visits (no more possible stops than landmarks).
|
self.respect_number(A_ub, b_ub, L, max_landmarks) # Respects max number of visits (no more possible stops than landmarks).
|
||||||
|
print("ok2")
|
||||||
self.break_sym(A_ub, b_ub, L) # Breaks the 'zig-zag' symmetry. Avoids d12 and d21 but not larger cirlces.
|
self.break_sym(A_ub, b_ub, L) # Breaks the 'zig-zag' symmetry. Avoids d12 and d21 but not larger cirlces.
|
||||||
|
|
||||||
# SET CONSTRAINTS FOR EQUALITY
|
# SET CONSTRAINTS FOR EQUALITY
|
||||||
|
print("ok3")
|
||||||
A_eq, b_eq = self.init_eq_not_stay(landmarks) # Force solution not to stay in same place
|
A_eq, b_eq = self.init_eq_not_stay(landmarks) # Force solution not to stay in same place
|
||||||
|
print("ok4")
|
||||||
self.respect_start_finish(A_eq, b_eq, L) # Force start and finish positions
|
self.respect_start_finish(A_eq, b_eq, L) # Force start and finish positions
|
||||||
|
print("ok5")
|
||||||
self.respect_order(A_eq, b_eq, L) # Respect order of visit (only works when max_time is limiting factor)
|
self.respect_order(A_eq, b_eq, L) # Respect order of visit (only works when max_time is limiting factor)
|
||||||
|
print("ok6")
|
||||||
self.respect_user_must(A_eq, b_eq, landmarks) # Force to do/avoid landmarks set by user.
|
self.respect_user_must(A_eq, b_eq, landmarks) # Force to do/avoid landmarks set by user.
|
||||||
|
print("ok7")
|
||||||
|
|
||||||
self.logger.debug(f"Optimizing with {A_ub.shape[0]} + {A_eq.shape[0]} = {A_ub.shape[0] + A_eq.shape[0]} constraints.")
|
self.logger.debug(f"Optimizing with {A_ub.shape[0]} + {A_eq.shape[0]} = {A_ub.shape[0] + A_eq.shape[0]} constraints.")
|
||||||
|
|
||||||
@ -539,7 +545,7 @@ class Optimizer:
|
|||||||
prob += (pl.lpSum([A_eq[i][j] * x[j] for j in range(L*L)]) == b_eq[i])
|
prob += (pl.lpSum([A_eq[i][j] * x[j] for j in range(L*L)]) == b_eq[i])
|
||||||
|
|
||||||
# 6. Solve the problem
|
# 6. Solve the problem
|
||||||
prob.solve(pl.PULP_CBC_CMD(msg=True))
|
prob.solve(pl.PULP_CBC_CMD(msg=False))
|
||||||
|
|
||||||
# 7. Extract Results
|
# 7. Extract Results
|
||||||
status = pl.LpStatus[prob.status]
|
status = pl.LpStatus[prob.status]
|
||||||
@ -559,32 +565,25 @@ class Optimizer:
|
|||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
timeout = 80
|
timeout = 80
|
||||||
while circles is not None and i < timeout:
|
while circles is not None :
|
||||||
i += 1
|
i += 1
|
||||||
# print(f"Iteration {i} of fixing circles")
|
# print(f"Iteration {i} of fixing circles")
|
||||||
print("ok1")
|
# l, b = self.prevent_config(solution)
|
||||||
A, b = self.prevent_config(solution)
|
# prob += (pl.lpSum([l[j] * x[j] for j in range(L*L)]) == b)
|
||||||
print("ok2")
|
|
||||||
print(f"A: {A}")
|
|
||||||
print(f"b: {b}")
|
|
||||||
try :
|
|
||||||
prob += pl.lpSum([A[j] * x[j // L][j % L] for j in range(L * L)]) == b
|
|
||||||
except Exception as exc :
|
|
||||||
self.logger.error(f'Unexpected error occured', details=exc)
|
|
||||||
raise Exception from exc
|
|
||||||
|
|
||||||
print("ok3")
|
|
||||||
for circle in circles :
|
for circle in circles :
|
||||||
A, b = self.prevent_circle(circle, L)
|
A, b = self.prevent_circle(circle, L)
|
||||||
prob += (pl.lpSum([A[0][j] * x[j // L][j % L] for j in range(L*L)]) == b[0])
|
prob += (pl.lpSum([A[0][j] * x[j] for j in range(L*L)]) == b[0])
|
||||||
prob += (pl.lpSum([A[1][j] * x[j // L][j % L] for j in range(L*L)]) == b[1])
|
prob += (pl.lpSum([A[1][j] * x[j] for j in range(L*L)]) == b[1])
|
||||||
print("ok4")
|
prob.solve(pl.PULP_CBC_CMD(msg=False))
|
||||||
prob.solve(pl.PULP_CBC_CMD(msg=True))
|
|
||||||
|
|
||||||
status = pl.LpStatus[prob.status]
|
status = pl.LpStatus[prob.status]
|
||||||
solution = [pl.value(var) for var in x] # The values of the decision variables (will be 0 or 1)
|
solution = [pl.value(var) for var in x] # The values of the decision variables (will be 0 or 1)
|
||||||
|
|
||||||
if status != 'Optimal' :
|
if status != 'Optimal' :
|
||||||
|
self.logger.error("The problem is overconstrained, no solution after {i} cycles.")
|
||||||
|
raise ArithmeticError("No solution could be found. Please try again with more time or different preferences.")
|
||||||
|
if i == timeout :
|
||||||
self.logger.error(f'Unexpected error after {timeout} iterations of fixing circles.')
|
self.logger.error(f'Unexpected error after {timeout} iterations of fixing circles.')
|
||||||
raise ArithmeticError("Solving failed because of overconstrained problem")
|
raise ArithmeticError("Solving failed because of overconstrained problem")
|
||||||
|
|
||||||
@ -600,5 +599,5 @@ class Optimizer:
|
|||||||
order = self.get_order(solution)
|
order = self.get_order(solution)
|
||||||
tour = [landmarks[i] for i in order]
|
tour = [landmarks[i] for i in order]
|
||||||
|
|
||||||
self.logger.debug(f"Re-optimized {i} times, score: {int(pl.value(prob.objective))}")
|
self.logger.debug(f"Re-optimized {i} times, objective value : {int(pl.value(prob.objective))}")
|
||||||
return tour
|
return tour
|
||||||
|
Loading…
x
Reference in New Issue
Block a user