diff --git a/backend/src/optimizer.py b/backend/src/optimizer.py index 82d136a..aaf214b 100644 --- a/backend/src/optimizer.py +++ b/backend/src/optimizer.py @@ -40,9 +40,6 @@ def untangle2(resx: list) : return order - - - # Convert the result (edges from j to k like d_25 = edge between vertex 2 and vertex 5) into the list of indices corresponding to the landmarks def untangle(resx: list) : N = len(resx) # length of res @@ -102,7 +99,49 @@ def print_res(res: list, landmarks: list, P) : steps = path_length(P, abs(res.x)) print("\nSteps walked : " + str(steps)) -# Constraint to not have d14 and d41 simultaneously + +# Checks for cases of circular symmetry in the result +def has_circle(resx: list) : + 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. + n_edges = resx.sum() # number of edges + + + nonzeroind = np.nonzero(resx)[0] # the return is a little funny so I use the [0] + + nonzero_tup = np.unravel_index(nonzeroind, (L,L)) + + indx = nonzero_tup[0].tolist() + indy = nonzero_tup[1].tolist() + + + verts = [] + + for i, x in enumerate(indx) : + verts.append((x, indy[i])) + + + for vert in verts : + visited = [] + visited.append(vert) + + while len(visited) < n_edges + 1 : + + try : + ind = indx.index(vert[1]) + + vert = (indx[ind], indy[ind]) + + if vert in visited : + return visited + else : + visited.append(vert) + except : + break + + return [] + +# Constraint to not have d14 and d41 simultaneously. Does not prevent circular symmetry with more elements def break_sym(landmarks, A_ub, b_ub): L = len(landmarks) upper_ind = np.triu_indices(L,0,L) @@ -125,6 +164,26 @@ def break_sym(landmarks, A_ub, b_ub): return A_ub, b_ub + +def prevent_circle(landmarks, A_ub, b_ub, circle) : + N = len(landmarks) + l = [0]*N*N + + for index in circle : + x = index[0] + y = index[1] + l[x*N+y] = 1 + + A_ub = np.vstack((A_ub,l)) + b_ub.append(len(circle)-1) + + """print("\n\nPREVENT CIRCLE") + for i in range(7): + print(l[i*7:i*7+7]) + print("\n")""" + + return A_ub, b_ub + # Constraint to respect max number of travels def respect_number(landmarks, A_ub, b_ub): h = [] @@ -152,9 +211,9 @@ def respect_order(landmarks: list, A_eq, b_eq): A_eq = np.vstack((A_eq,l)) b_eq.append(0) - for i in range(7): + """for i in range(7): print(l[i*7:i*7+7]) - print("\n") + print("\n")""" return A_eq, b_eq @@ -268,7 +327,19 @@ A_eq, b_eq = respect_order(landmarks, A_eq, b_eq) # Respect order o x_bounds = [(0, 1)] * len(c) # Solve linear programming problem + 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) +circle = has_circle(res.x) + +while len(circle) != 0 : + print("The solution has a circular path. Not interpretable.") + print("Need to add constraints until no circle ") + + A_ub, b_ub = prevent_circle(landmarks, A_ub, b_ub, circle) + 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) + circle = has_circle(res.x) + + # Raise error if no solution is found if not res.success :