working pulp

This commit is contained in:
Helldragon67 2025-01-15 17:11:29 +01:00
parent 3fe6056f3c
commit 814da4b5f6
2 changed files with 24 additions and 24 deletions

View File

@ -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

View File

@ -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