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()
|
||||
print(result)
|
||||
landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])
|
||||
|
||||
# Get computation time
|
||||
|
@ -2,6 +2,7 @@ import yaml, logging
|
||||
import numpy as np
|
||||
import pulp as pl
|
||||
from scipy.optimize import linprog
|
||||
from scipy.sparse import lil_matrix, csr_matrix
|
||||
from collections import defaultdict, deque
|
||||
|
||||
from ..structs.landmark import Landmark
|
||||
@ -69,7 +70,7 @@ class Optimizer:
|
||||
for j in range(i+1, L) :
|
||||
if i !=j :
|
||||
t = get_time(spot1.location, landmarks[j].location)
|
||||
A_ub[0, i*L + j] = t + spot1.duration
|
||||
A_ub[0, i*L + j] = t + spot1.duration
|
||||
A_ub[0, j*L + i] = t + landmarks[j].duration
|
||||
|
||||
# Expand 'c' to L*L for every decision variable
|
||||
@ -255,7 +256,7 @@ class Optimizer:
|
||||
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):
|
||||
"""
|
||||
Prevent the use of a particular solution by adding constraints to the optimization.
|
||||
@ -330,9 +331,7 @@ class Optimizer:
|
||||
tuple[list[int], Optional[list[list[int]]]]: A tuple containing the visit order and a list of any detected circles.
|
||||
"""
|
||||
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
|
||||
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
|
||||
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).
|
||||
print("ok2")
|
||||
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
|
||||
print("ok3")
|
||||
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
|
||||
print("ok5")
|
||||
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.
|
||||
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.")
|
||||
|
||||
@ -539,7 +545,7 @@ class Optimizer:
|
||||
prob += (pl.lpSum([A_eq[i][j] * x[j] for j in range(L*L)]) == b_eq[i])
|
||||
|
||||
# 6. Solve the problem
|
||||
prob.solve(pl.PULP_CBC_CMD(msg=True))
|
||||
prob.solve(pl.PULP_CBC_CMD(msg=False))
|
||||
|
||||
# 7. Extract Results
|
||||
status = pl.LpStatus[prob.status]
|
||||
@ -559,32 +565,25 @@ class Optimizer:
|
||||
|
||||
i = 0
|
||||
timeout = 80
|
||||
while circles is not None and i < timeout:
|
||||
while circles is not None :
|
||||
i += 1
|
||||
# print(f"Iteration {i} of fixing circles")
|
||||
print("ok1")
|
||||
A, b = self.prevent_config(solution)
|
||||
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")
|
||||
# l, b = self.prevent_config(solution)
|
||||
# prob += (pl.lpSum([l[j] * x[j] for j in range(L*L)]) == b)
|
||||
|
||||
for circle in circles :
|
||||
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[1][j] * x[j // L][j % L] for j in range(L*L)]) == b[1])
|
||||
print("ok4")
|
||||
prob.solve(pl.PULP_CBC_CMD(msg=True))
|
||||
prob += (pl.lpSum([A[0][j] * x[j] for j in range(L*L)]) == b[0])
|
||||
prob += (pl.lpSum([A[1][j] * x[j] for j in range(L*L)]) == b[1])
|
||||
prob.solve(pl.PULP_CBC_CMD(msg=False))
|
||||
|
||||
status = pl.LpStatus[prob.status]
|
||||
solution = [pl.value(var) for var in x] # The values of the decision variables (will be 0 or 1)
|
||||
|
||||
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.')
|
||||
raise ArithmeticError("Solving failed because of overconstrained problem")
|
||||
|
||||
@ -600,5 +599,5 @@ class Optimizer:
|
||||
order = self.get_order(solution)
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user