def solve_tsp(V,c): """solve_tsp -- solve the traveling salesman problem - start with assignment model - add cuts until there are no sub-cycles Parameters: - V: set/list of nodes in the graph - c[i,j]: cost for traversing edge (i,j) Returns the optimum objective value and the list of edges used. """ def addcut(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = list(networkx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: model.addCons(quicksum(x[i,j] for i in S for j in S if j>i) <= len(S)-1) print("cut: len(%s) <= %s" % (S,len(S)-1)) return True def addcut2(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = list(networkx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: T = set(V) - set(S) print("S:",S) print("T:",T) model.addCons(quicksum(x[i,j] for i in S for j in T if j>i) + quicksum(x[i,j] for i in T for j in S if j>i) >= 2) print("cut: %s >= 2" % "+".join([("x[%s,%s]" % (i,j)) for i in S for j in T if j>i])) return True # main part of the solution process: model = Model("tsp") model.hideOutput() # silent/verbose mode x = {} for i in V: for j in V: if j > i: x[i,j] = model.addVar(ub=1, name="x(%s,%s)"%(i,j)) for i in V: model.addCons(quicksum(x[j,i] for j in V if j < i) + \ quicksum(x[i,j] for j in V if j > i) == 2, "Degree(%s)"%i) model.setObjective(quicksum(c[i,j]*x[i,j] for i in V for j in V if j > i), "minimize") EPS = 1.e-6 isMIP = False while True: model.optimize() edges = [] for (i,j) in x: if model.getVal(x[i,j]) > EPS: edges.append( (i,j) ) if addcut(edges) == False: if isMIP: # integer variables, components connected: solution found break model.freeTransform() for (i,j) in x: # all components connected, switch to integer model model.chgVarType(x[i,j], "B") isMIP = True return model.getObjVal(),edges
def encode_scipplan(domain, instance, horizon, epsilon, gap): bigM = 1000.0 model = Model(domain + "_" + instance + "_" + str(horizon)) initials = readConstraintFiles("./translation/initial_" + domain + "_" + instance+".txt") instantaneous_constraints = readConstraintFiles("./translation/instantaneous_constraints_" + domain + "_" + instance+".txt") temporal_constraints = readConstraintFiles("./translation/temporal_constraints_" + domain + "_" + instance+".txt") goals = readConstraintFiles("./translation/goal_" + domain + "_" + instance+".txt") transitions = readTransitions("./translation/transitions_" + domain + "_" + instance+".txt") reward = readReward("./translation/reward_" + domain + "_" + instance+".txt") A, S, Aux, A_type, S_type, Aux_type = readVariables("./translation/pvariables_"+domain+"_"+instance+".txt") model, x, y, v, d = initialize_original_variables(model, A, S, Aux, A_type, S_type, Aux_type, horizon) model = encode_initial_constraints(model, S, y, initials) model, d, v, Aux = encode_global_instantaneous_constraints(model, A, S, Aux, x, y, v, d, instantaneous_constraints, horizon, bigM) model, d, v, Aux = encode_global_temporal_constraints(model, A, S, Aux, x, y, v, d, temporal_constraints, horizon, bigM) model, d = encode_transitions(model, A, S, Aux, x, y, v, d, transitions, horizon) model, d = encode_goal_constraints(model, S, Aux, y, v, d, goals, horizon) model = encode_reward(model, A, S, Aux, x, y, v, d, reward, horizon) for t in range(horizon): model.addCons(x[("dt",t)] <= bigM) model.setRealParam("limits/gap", gap) while True: model.optimize() if len(model.getSols()) == 0: print("Problem is infeasible for the given horizon.") return False violated_t, interval, violated_c_index = checkTemporalConstraintViolation(model, A, S, Aux, x, y, v, d, temporal_constraints, horizon, epsilon) #print(violated_t, interval, violated_c_index) if violated_t == -1: break zero_crossing_coef = ((interval[1] + interval[0]) / 2.0) / model.getVal(x[("dt",violated_t)]) model.freeTransform() model = encode_violated_global_temporal_constraint(model, A, S, Aux, x, y, v, d, temporal_constraints, horizon, violated_t, zero_crossing_coef, violated_c_index) print("Plan:") for t in range(horizon): for index, a in enumerate(A): print(a + " at time " + str(t) + " by value " + str(model.getVal(x[(a,t)]))) return True
def test_solution_getbest(): m = Model() x = m.addVar("x", lb=0, ub=2, obj=-1) y = m.addVar("y", lb=0, ub=4, obj=0) m.addCons(x * x <= y) m.optimize() sol = m.getBestSol() assert round(sol[x]) == 2.0 assert round(sol[y]) == 4.0 print(sol) # prints the solution in the transformed space m.freeTransform() sol = m.getBestSol() assert round(sol[x]) == 2.0 assert round(sol[y]) == 4.0 print(sol) # prints the solution in the original space
def scip_solver(graph, weight='weight'): try: from pyscipopt import Model, quicksum except ImportError: raise ImportError( 'SCIP Optimization Suit with Python support not found') nodes = graph.nodes() num_nodes = graph.number_of_nodes() c = nx.adjacency_matrix(graph, weight=weight) # Define the optimization problem model = Model('tsp') model.hideOutput() # silent/verbose mode # Create the variables x = {} for i in xrange(num_nodes): for j in xrange(i + 1, num_nodes): x[i, j] = model.addVar(ub=1, name='x(%s,%s)' % (i, j)) # Add the constraints for i in xrange(num_nodes): model.addCons( quicksum([x[j, i] for j in xrange(i)]) + quicksum([x[i, j] for j in xrange(i + 1, num_nodes)]) == 2, 'Degree(%s)' % i) # Set minimization objective model.setObjective( quicksum(c[i, j] * x[i, j] for i in xrange(num_nodes) for j in xrange(i + 1, num_nodes)), 'minimize') # Limit the number of edges in a connected component S to |S|-1 def addcut(cut_edges): G = nx.Graph() G.add_edges_from(cut_edges) Components = list(nx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: model.addCons( quicksum(x[i, j] for i in S for j in S if j > i) <= len(S) - 1) return True # Solve EPS = 1.e-6 isMIP = False while True: model.optimize() edges = [] for (i, j) in x: if model.getVal(x[i, j]) > EPS: edges.append((i, j)) if addcut(edges) == False: if isMIP: # integer variables, components connected: solution found break model.freeTransform() for (i, j) in x: # all components connected, switch to integer model model.chgVarType(x[i, j], 'B') isMIP = True # Extract the tour from the edges G = nx.Graph() for e in edges: G.add_edge(nodes[e[0]], nodes[e[1]]) tour_edges = nx.eulerian_circuit(G, source=graph.nodes_iter().next()) tour = [e[0] for e in tour_edges] return tour
def tsp_solver(c, customers, vehicle_tours): def addcut(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = list(networkx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: model.addCons( quicksum(x[i, j] for i in S for j in S) <= len(S) - 1) return True # Add the depot on each vehicle vehicle_tours = {k: vehicle_tours[k] + [0] for k in vehicle_tours.keys()} final_obj = 0 final_tours = [] for key, value in vehicle_tours.iteritems(): v_customers = value model = Model("vrp_tsp") #model.hideOutput() x = {} for i in v_customers: for j in v_customers: # vehicle moves from customer i to customer j x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j)) for i in v_customers: # Constraint: every customer can only be visited once # (or, every node must be connected and connect to another node) model.addCons(quicksum(x[i, j] for j in v_customers) == 1) model.addCons(quicksum(x[j, i] for j in v_customers) == 1) for j in v_customers: if i == j: # Constraint: a node cannot conect to itself model.addCons(x[i, j] == 0) # Objective function: minimize total distance of the tour model.setObjective( quicksum(x[i, j] * c[(i, j)] for i in v_customers for j in v_customers), "minimize") EPS = 1.e-6 isMIP = False while True: model.optimize() edges = [] for (i, j) in x: if model.getVal(x[i, j]) > EPS: edges.append((i, j)) if addcut(edges) == False: if isMIP: # integer variables, components connected: solution found break model.freeTransform() for ( i, j ) in x: # all components connected, switch to integer model model.chgVarType(x[i, j], "B") isMIP = True # model.optimize() best_sol = model.getBestSol() sub_tour = [] # Build the graph path # Retrieve the last node of the graph, i.e., the last one connecting to the depot last_node = [n for n in edges if n[1] == 0][0][0] G = networkx.Graph() G.add_edges_from(edges) path = list(networkx.all_simple_paths(G, source=0, target=last_node)) path.sort(reverse=True, key=lambda u: len(u)) if len(path) > 0: path = path[0][1:] else: path = path[1:] obj = model.getSolObjVal(best_sol) final_obj += obj final_tours.append([customers[i] for i in path]) # print("Customers visited by vehicle %s: %s" % (key, value)) # print("Objective cost for vehicle %s: %s" % (key, obj)) # print("Edges visited by vehicle %s: %s" % (key, edges)) # print("Path visited by vehicle %s: %s" % (key, path)) return final_obj, final_tours
def scip_solver_2(customers, customer_count, vehicle_count, vehicle_capacity): model = Model("vrp") c_range = range(0, customer_count) cd_range = range(1, customer_count) x, d, w, v = {}, {}, {}, {} for i in c_range: for j in c_range: d[i, j] = length(customers[i], customers[j]) w[i, j] = customers[i].demand + customers[j].demand if j > i and i == 0: # depot x[i, j] = model.addVar(ub=2, vtype="I", name="x(%s,%s)" % (i, j)) elif j > i: x[i, j] = model.addVar(ub=1, vtype="I", name="x(%s,%s)" % (i, j)) model.addCons( quicksum(x[0, j] for j in cd_range) <= 2 * vehicle_count, "DegreeDepot") for i in cd_range: model.addCons( quicksum(x[j, i] for j in c_range if j < i) + quicksum(x[i, j] for j in c_range if j > i) == 2, "Degree(%s)" % i) # model.addCons(quicksum(x[j, i] * w[j, i] for j in c_range if j < i) + # quicksum(x[i, j] * w[i, j] for j in c_range if j > i) <= 2*vehicle_capacity) # for j in cd_range: # for z in cd_range: # if j > i and z > j: # x[i, j] + x[j, z] + x[i, z] <= 2 # for j in c_range: # if j > i: # model.addCons(x[i, j] * w[i, j] <= vehicle_capacity) model.setObjective( quicksum(d[i, j] * x[i, j] for i in c_range for j in c_range if j > i), "minimize") # model.hideOutput() # mip_gaps = [0.9, 0.5, 0.2, 0.03] mip_gaps = [0.0] runs = 0 start = datetime.now() for gap in mip_gaps: model.freeTransform() model.setRealParam("limits/gap", gap) # model.setRealParam("limits/absgap", 0.3) model.setRealParam("limits/time", 60 * 20) # Time limit in seconds # model.setIntParam('limits/bestsol', 1) edges, final_edges, runs = optimize(customer_count, customers, model, vehicle_capacity, vehicle_count, x) # model.setIntParam('limits/bestsol', -1) # model.freeTransform() # model.setRealParam("limits/gap", 0) # edges, final_edges = optimize(customer_count, customers, model, vehicle_capacity, vehicle_count, x) run_time = datetime.now() - start print edges print final_edges output = [[]] * vehicle_count for i in range(vehicle_count): output[i] = [] current_item = None if len(final_edges) > 0: # Get the first edge starting with 0 for e in final_edges: if e[0] == 0: current_item = e break if current_item: a = current_item[0] current_node = current_item[1] output[i].append(customers[current_node]) final_edges.remove(current_item) searching_connections = True while searching_connections and len(final_edges) > 0: for edge in final_edges: found_connection = False a_edge = edge[0] b_edge = edge[1] # If we find the node connecting with a 0 # it means the cycle has been closed if b_edge == current_node and a_edge == 0: final_edges.remove(edge) break if a_edge == current_node: output[i].append(customers[b_edge]) current_node = b_edge found_connection = True elif b_edge == current_node: output[i].append(customers[a_edge]) current_node = a_edge found_connection = True if found_connection: final_edges.remove(edge) break if not found_connection: searching_connections = False print output sol = model.getBestSol() obj = model.getSolObjVal(sol) print("RUN TIME: %s" % str(run_time)) print("NUMBER OF OPTIMIZATION RUNS: %s" % runs) return obj, output
def tsp2lp(V, c, filename): def addcut(cut_edges): # Initialize graph G = nx.Graph() G.add_edges_from(cut_edges) if nx.number_connected_components(G) == 1: return False model.freeTransform() for S in nx.connected_components(G): model.addCons( quicksum(x[i, j] for i in S for j in S if j > i) <= len(S) - 1) # print("cut: len(%s) <= %s" % (S, len(S) - 1)) return True def addcut2(cut_edges): # Initialize graph G = nx.Graph() G.add_edges_from(cut_edges) if nx.number_connected_components(G) == 1: return False model.freeTransform() for S in nx.connected_components(G): T = set(V) - set(S) model.addCons( quicksum(x[i, j] for i in S for j in T if j > i) + quicksum(x[i, j] for i in T for j in S if j > i) >= 2) return True model = Model() model.hideOutput() # silent/verbose mode x = {} for i in V: for j in V: if j > i: x[i, j] = model.addVar(ub=1, name="x(%s,%s)" % (i, j)) for i in V: model.addCons( quicksum(x[j, i] for j in V if j < i) + quicksum(x[i, j] for j in V if j > i) == 2, "Degree(%s)" % i, ) model.setObjective( quicksum(c[i, j] * x[i, j] for i in V for j in V if j > i), "minimize") EPS = 1.e-6 isMIP = False while True: model.optimize() edges = [] for (i, j) in x: if model.getVal(x[i, j]) > EPS: edges.append((i, j)) if addcut(edges) == False: if isMIP: # integer variables, components connected: solution found break model.freeTransform() for (i, j) in x: # all components connected, switch to integer model model.chgVarType(x[i, j], "B") isMIP = True model.writeProblem(filename) return model
def solve_tsp(V, c): """solve_tsp -- solve the traveling salesman problem - start with assignment model - add cuts until there are no sub-cycles Parameters: - V: set/list of nodes in the graph - c[i,j]: cost for traversing edge (i,j) Returns the optimum objective value and the list of edges used. """ def addcut(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = networkx.connected_components(G) if len(Components) == 1: return False for S in Components: model.addCons( quicksum(x[i, j] for i in S for j in S if j > i) <= len(S) - 1) print("cut: len(%s) <= %s" % (S, len(S) - 1)) return True def addcut2(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = networkx.connected_components(G) if len(Components) == 1: return False for S in Components: T = set(V) - set(S) print("S:", S) print("T:", T) model.addCons( quicksum(x[i, j] for i in S for j in T if j > i) + quicksum(x[i, j] for i in T for j in S if j > i) >= 2) print("cut: %s <--> %s >= 2" % (S, T), [(i, j) for i in S for j in T if j > i]) return True def isMIP(x): for var in x: if var.vtype == "CONTINUOUS": return False return True # main part of the solution process: model = Model("tsp") # model.Params.OutputFlag = 0 # silent/verbose mode x = {} for i in V: for j in V: if j > i: x[i, j] = model.addVar(ub=1, name="x(%s,%s)" % (i, j)) for i in V: model.addCons(quicksum(x[j,i] for j in V if j < i) + \ quicksum(x[i,j] for j in V if j > i) == 2, "Degree(%s)"%i) model.setObjective( quicksum(c[i, j] * x[i, j] for i in V for j in V if j > i), "minimize") EPS = 1.e-6 while True: model.optimize() edges = [] for (i, j) in x: if model.getVal(x[i, j]) > EPS: edges.append((i, j)) model.freeTransform() if addcut(edges) == False: if isMIP( ): # integer variables, components connected: solution found break for (i, j) in x: # all components connected, switch to integer model model.chgVarType(x[i, j], "B") return model.getObjVal(), edges
def solve_tsp(V, c): """solve_tsp -- solve the traveling salesman problem - start with assignment model - add cuts until there are no sub-cycles Parameters: - V: set/list of nodes in the graph - c[i,j]: cost for traversing edge (i,j) Returns the optimum objective value and the list of edges used. """ def addcut(cut_edges, fn_constrain): G = networkx.Graph() G.add_edges_from(cut_edges) Components = list(networkx.connected_components(G)) print('len(components): %s' % len(Components)) if len(Components) == 1: return False model.freeTransform() fn_constrain(Components) return True def subtour_elim(Components): for S in Components: model.addCons( quicksum(x[i, j] for i in S for j in S if j > i) <= len(S) - 1) # print("cut: len(%s) <= %s" % (S, len(S) - 1)) def cutset(Components): for S in Components: T = set(V) - set(S) # print("S:", S) # print("T:", T) model.addCons( quicksum(x[i, j] for i in S for j in T if j > i) + quicksum(x[i, j] for i in T for j in S if j > i) >= 2) # print("cut: %s >= 2" % "+".join( # [("x[%s,%s]" % (i, j)) for i in S for j in T if j > i])) # main part of the solution process: model = Model("tsp") model.hideOutput() # silent/verbose mode x = {} for i in V: for j in V: if j > i: # for symmetric graph, only consider direction: j > i x[i, j] = model.addVar(ub=1, name="x(%s,%s)" % (i, j)) for i in V: model.addCons( quicksum(x[j, i] for j in V if j < i) + quicksum(x[i, j] for j in V if j > i) == 2, "Degree(%s)" % i) model.setObjective( quicksum(c[i, j] * x[i, j] for i in V for j in V if j > i), "minimize") EPS = 1.e-6 isMIP = False while True: model.optimize() edges = [] for (i, j) in x: if model.getVal(x[i, j]) > EPS: edges.append((i, j)) if not addcut(edges, subtour_elim): if isMIP: # integer variables, components connected: solution found break model.freeTransform() print('chgVarType to Integer') for (i, j) in x: # all components connected, switch to integer model model.chgVarType(x[i, j], "B") isMIP = True return model.getObjVal(), edges
def scip_solver_2(customers, customer_count, vehicle_count, vehicle_capacity): model = Model("vrp") c_range = range(0, customer_count) cd_range = range(1, customer_count) x, d, w, v = {}, {}, {}, {} for i in c_range: for j in c_range: d[i, j] = length(customers[i], customers[j]) w[i, j] = customers[i].demand + customers[j].demand if j > i and i == 0: # depot x[i, j] = model.addVar(ub=2, vtype="I", name="x(%s,%s)" % (i, j)) elif j > i: x[i, j] = model.addVar(ub=1, vtype="I", name="x(%s,%s)" % (i, j)) model.addCons( quicksum(x[0, j] for j in cd_range) <= 2 * vehicle_count, "DegreeDepot") for i in cd_range: model.addCons( quicksum(x[j, i] for j in c_range if j < i) + quicksum(x[i, j] for j in c_range if j > i) == 2, "Degree(%s)" % i) model.setObjective( quicksum(d[i, j] * x[i, j] for i in c_range for j in c_range if j > i), "minimize") mip_gaps = [0.0] runs = 0 start = datetime.now() for gap in mip_gaps: model.freeTransform() model.setRealParam("limits/gap", gap) model.setRealParam("limits/time", 60 * 20) # Time limit in seconds edges, final_edges, runs = optimize(customer_count, customers, model, vehicle_capacity, vehicle_count, x) run_time = datetime.now() - start print(edges) print(final_edges) output = [[]] * vehicle_count for i in range(vehicle_count): output[i] = [] current_item = None if len(final_edges) > 0: for e in final_edges: if e[0] == 0: current_item = e break if current_item: a = current_item[0] current_node = current_item[1] output[i].append(customers[current_node]) final_edges.remove(current_item) searching_connections = True while searching_connections and len(final_edges) > 0: for edge in final_edges: found_connection = False a_edge = edge[0] b_edge = edge[1] if b_edge == current_node and a_edge == 0: final_edges.remove(edge) break if a_edge == current_node: output[i].append(customers[b_edge]) current_node = b_edge found_connection = True elif b_edge == current_node: output[i].append(customers[a_edge]) current_node = a_edge found_connection = True if found_connection: final_edges.remove(edge) break if not found_connection: searching_connections = False print(output) sol = model.getBestSol() obj = model.getSolObjVal(sol) print("RUN TIME: %s" % str(run_time)) print("NUMBER OF OPTIMIZATION RUNS: %s" % runs) return obj, output
def solve(event): global n, trucks, solver, li, ax, warehouses, loc_x, loc_y, lines_x, lines_y, obj_value, exec_value global distances, distances2 print("solving...") ax.clear() ax.set_xlim(0,1000) ax.set_ylim(0,1000) plot_data(ax, loc_x, loc_y, warehouses) ax.text(400, 1075, "solving...", family="serif", horizontalalignment='left', verticalalignment='top') plt.draw() fig.canvas.draw() start_time = time.time() # Calculate constraint for Li total_l = 0 total_c = 0.0 paths = 0 slack = False while total_c < n or paths < trucks: c1 = min(c,n) total_c += c1 total_l += c1*(c1+1)/2 paths += 1 if total_c > n: slack = True if solver=="cbc" or solver=="glpk" or solver=="gurobi": # Objective function z = pulp.LpProblem('Test', pulp.LpMinimize) # Generate decision variables x = {} y = {} variables = [] l = {} s = {} for i in range(n+warehouses): for j in range(n+warehouses): if i==j: continue x[i,j] = pulp.LpVariable('x_' + str(i) + '_' + str(j), 0, 1, pulp.LpInteger) if i >= warehouses: l[i] = pulp.LpVariable('l_' + str(i), 1, min(n,c), pulp.LpInteger) # Objective function z += pulp.lpSum([distances[i][j] * x[i,j] for i in range(n+warehouses) for j in list(range(i)) + list(range(i+1,n+warehouses))]) # Constraints constraintSeq = [] constraintTrucks = [] for i in range(n+warehouses): if i>=warehouses: constraintSeq.append(l[i]) constraintFrom = [] constraintTo = [] for j in range(n+warehouses): if i==j: continue if i>=warehouses and j>=warehouses: z += pulp.lpSum([l[i], -1*l[j], n*x[i,j], -n+1]) <= 0 if i>=warehouses: constraintFrom.append(x[i,j]) constraintTo.append(x[j,i]) if i<warehouses: constraintTrucks.append(x[j,i]) if i>=warehouses: z += pulp.lpSum(constraintFrom) == 1 # paths from location z += pulp.lpSum(constraintTo) == 1 # paths to location if i==warehouses and (paths > 1 or warehouses>1): z += pulp.lpSum(constraintTrucks) == paths # paths to warehouse if not slack: z += pulp.lpSum(constraintSeq) == total_l else: z += pulp.lpSum(constraintSeq) <= total_l # Solve if solver=="cbc": status = z.solve() if solver=="glpk": status = z.solve(pulp.GLPK()) if solver=="gurobi": status = z.solve(pulp.GUROBI_CMD()) # should be 'Optimal' if pulp.LpStatus[status]!="Optimal": print("RESULT: ".pulp.LpStatus[status]) print("Objective function value: "+str(z.objective.value())) # Print variables & save path lines_x = [] lines_y = [] li = [0] * n for i in range(n+warehouses): if i>=warehouses: li[i-warehouses] = pulp.value(l[i]) for j in range(n+warehouses): if i==j: continue if pulp.value(x[i,j]) == 1: lines_x.append(loc_x[i]) lines_x.append(loc_x[j]) lines_y.append(loc_y[i]) lines_y.append(loc_y[j]) lines_x.append(np.nan) lines_y.append(np.nan) obj_value = "c=" + str(round(z.objective.value(),2)) elif solver=="cut plane": model = Model("tsp") model.hideOutput() x = {} l = {} for i in range(n+warehouses): for j in range(n+warehouses): if i != j: x[i,j] = model.addVar(ub=1, name="x(%s,%s)"%(i,j)) if (paths > 1 or warehouses > 1) and i >= warehouses: l[i] = model.addVar(ub=min(c,n),lb=1, name="l(%s)"%(i)) if paths == 1 and warehouses == 1: # SYMMETRIC DISTANCE MATRIX ONLY #for i in range(n+warehouses): #model.addCons(quicksum(x[j,i] for j in range(n+warehouses) if j != i) + \ # quicksum(x[i,j] for j in range(n+warehouses) if j != i) == 2,"Degree(%s)"%i) # ASYMMETRIC DISTANCE MATRIX for i in range(n+warehouses): model.addCons(quicksum(x[j,i] for j in range(n+warehouses) if j != i) == 1,"In(%s)"%i) model.addCons(quicksum(x[i,j] for j in range(n+warehouses) if j != i) == 1,"Out(%s)"%i) else: for i in range(warehouses, n+warehouses): model.addCons(quicksum(x[j,i] for j in range(n+warehouses) if j != i) == 1,"In(%s)"%i) model.addCons(quicksum(x[i,j] for j in range(n+warehouses) if j != i) == 1,"Out(%s)"%i) for i in range(warehouses, n+warehouses): for j in range(warehouses, n+warehouses): if i!=j: model.addCons(l[i] -l[j] +n*x[i,j] <= n-1, "Li(%s,%s)"%(i,j)) model.addCons(quicksum(x[j,i] for i in range(warehouses) for j in range(n+warehouses) if i!=j) == paths, "Paths(%s)"%paths) if not slack: model.addCons(quicksum(l[i] for i in range(warehouses,n+warehouses)) == total_l,"TotalL") else: model.addCons(quicksum(l[i] for i in range(warehouses,n+warehouses)) <= total_l, "TotalL") model.setObjective(quicksum(distances2[i,j]*x[i,j] for (i,j) in x), "minimize") EPS = 1.e-6 isMIP = False model.setPresolve(SCIP_PARAMSETTING.OFF) while True: model.optimize() #edges = [] lines_x = [] lines_y = [] edges = [] li = [0] * n for (i,j) in x: # i=j already skipped if model.getVal(x[i,j]) > EPS: #edges.append( (i,j) ) lines_x.append(loc_x[i]) lines_x.append(loc_x[j]) lines_y.append(loc_y[i]) lines_y.append(loc_y[j]) lines_x.append(np.nan) lines_y.append(np.nan) edges.append( (i,j) ) if paths>1 or warehouses>1: for i in range(warehouses, n+warehouses): li[i-warehouses] = int(model.getVal(l[i])) obj_value = "c=" + str(round(model.getObjVal(),2)) ax.clear() ax.set_xlim(0,1000) ax.set_ylim(0,1000) plot_data_lines(lines_x,lines_y) plot_data(ax, loc_x, loc_y, warehouses) ax.text(400, 1075, "solving...", family="serif", horizontalalignment='left', verticalalignment='top') fig.canvas.draw() if addcut(edges,model,x,warehouses) == False: if isMIP: # integer variables, components connected: solution found break model.freeTransform() for (i,j) in x: # all components connected, switch to integer model model.chgVarType(x[i,j], "B") if paths > 1 or warehouses > 1: for i in range(warehouses,n+warehouses): model.chgVarType(l[i], "I") isMIP = True sol_li = [0] * (n+warehouses) sol_xij = {} print('solved.') elif solver == 'held-karp': li = [0] * n opt, path = held_karp(distances) print(path) obj_value = "c=" + str(round(opt,2)) x = [[0 for x in range(n+warehouses)] for y in range(n+warehouses)] for idx, val in enumerate(path): if idx < (len(path)-1): x[val][path[idx+1]] = 1; elif idx == (len(path)-1): x[val][path[0]] = 1; for i in range(n+warehouses): for j in range(n+warehouses): if x[i][j] == 1: #edges.append( (i,j) ) lines_x.append(loc_x[i]) lines_x.append(loc_x[j]) lines_y.append(loc_y[i]) lines_y.append(loc_y[j]) lines_x.append(np.nan) lines_y.append(np.nan) #edges.append( (i,j) ) # Print computation time time2 = time.time() - start_time exec_value = time2 units = 'secs' if time2 > 60: time2 /= 60 units = 'mins' if time2 > 60: time2 /= 60 units = 'hours' time2 = round(time2,2) exec_value = "exec=" + str(time2) + " " + units print("--- " + str(time2) + " " + units + " ---") # Redraw points ax.clear() ax.set_xlim(0,1000) ax.set_ylim(0,1000) plot_data_lines(lines_x,lines_y) plot_data(ax, loc_x, loc_y, warehouses) ax.text(350, 1075, obj_value, family="serif", horizontalalignment='right', verticalalignment='top') ax.text(450, 1075, exec_value, family="serif", horizontalalignment='left', verticalalignment='top') fig.canvas.draw()