def solve(data, recompute, display, load, callback, time, **args): R, C, slices, areas, overlap = preprocess(data, recompute, display) with localsolver.LocalSolver() as ls: model = ls.model # Variables x = [model.bool() for i in range(len(slices))] # Constraints for i in range(R): if display and i % 50 == 0: print(str(i) + '/' + str(R)) for j in range(C): model.constraint(model.sum(x[s] for s in overlap[i][j]) <= 1) # Objective model.maximize(model.sum(s * area for s, area in zip(x, areas))) model.close() if callback: set_callback(ls, slices, x) if load: load_initial_position(load, slices, x) ls.create_phase().time_limit = int(time) ls.solve() solution = retrieve_solution(slices, x) return solution
def __init__(self, graph, options): self.graph = graph self.ls = localsolver.LocalSolver() self.model = self.ls.get_model() self.options = options # Constraints + starting point self.coarsening = [] # Decisions self.node_placement = None # Debug self.edge_counters = [] self.edge_degrees = [] self.edge_costs = []
def solve(filename): with localsolver.LocalSolver() as ls: # # Reads instance data # file_it = iter(read_integers(filename)) # Number of vertices n = next(file_it) # Number of edges m = next(file_it) # Origin of each edge origin = [None] * m # Destination of each edge dest = [None] * m # Weight of each edge w = [None] * m for e in range(m): origin[e] = next(file_it) dest[e] = next(file_it) w[e] = next(file_it) model = ls.model # Decision variables x[i] # Is true if vertex x[i] is on the right side of the cut and false if it is on the left side of the cut x = [model.bool() for i in range(n)] # incut[e] is true if its endpoints are in different class of the partition incut = [None] * m for e in range(m): incut[e] = model.neq(x[origin[e] - 1], x[dest[e] - 1]) # Size of the cut cut_weight = model.sum(w[e] * incut[e] for e in range(m)) model.maximize(cut_weight) model.close() # # Param # if len(sys.argv) >= 4: ls.param.time_limit = int(sys.argv[3]) else: ls.param.time_limit = 10 ls.solve() return ls
def solve(self, instance, time_limit=5): instance = np.array(instance) if self.maximize: np.fill_diagonal(instance, 0) instance = instance.max( ) - instance # transformation function (similarity -> distance) instance = np.pad( instance, ((0, 1), (0, 1)), mode='constant', constant_values=0 # dummy node ) np.fill_diagonal(instance, 1e7) #instance.max()) # self loops num_cities = instance.shape[0] with localsolver.LocalSolver() as ls: # model model = ls.model cities = model.list(num_cities) model.constraint(model.count(cities) == num_cities) distance_array = model.array(instance.tolist()) # minimize the total distance dist_selector = model.function( lambda i: model.at(distance_array, cities[i - 1], cities[i])) obj = (model.sum(model.range(1, num_cities), dist_selector) + model.at(distance_array, cities[num_cities - 1], cities[0])) model.minimize(obj) model.close() # time limit ls.create_phase().time_limit = time_limit ls.solve() solution = [c for c in cities.value] dummy_idx = solution.index(num_cities - 1) self.solution = solution[dummy_idx + 1:] + solution[:dummy_idx] return self
########## knapsack.py ########## import localsolver import sys if len(sys.argv) < 2: print("Usage: python knapsack.py inputFile [outputFile] [timeLimit]") sys.exit(1) def read_integers(filename): with open(filename) as f: return [int(elem) for elem in f.read().split()] with localsolver.LocalSolver() as ls: # # Reads instance data # file_it = iter(read_integers(sys.argv[1])) # Number of items nb_items = next(file_it) # Items properties weights = [next(file_it) for i in range(nb_items)] values = [next(file_it) for i in range(nb_items)] # Knapsack bound
def solve(data, load, callback, time, **args): # data = preprocess(data) R, C, F, N, B, T, demand = data with localsolver.LocalSolver() as ls: model = ls.model # Data times = model.array(build_times([((0, 0), (0, 0), 0, 0)] + demand)) max_lates = model.array([e - s for _, _, s, e in demand]) # Variables cars = [model.list(N) for i in range(F)] # Expressions def make_lambda(k): return lambda i, prev: model.max( 0, prev + model.iif( i == 0, model.at(times, 0, cars[k][0] + 1), model.at(times, cars[k][i - 1] + 1, cars[k][i] + 1))) lates = [ model.array(model.range(0, N), model.function(make_lambda(k))) for k in range(F) ] # Constraints model.constraint(model.disjoint(*cars)) for late, car in zip(lates, cars): for i in range(N): model.constraint( model.count(car) <= model.create_constant(i) or late[i] <= model.at(max_lates, car[i])) # Objective model.maximize(model.sum([model.count(car) for car in cars])) model.close() l = cars[0].get_value() l.clear() l.add(0) a = cars[1].get_value() a.clear() a.add(1) a.add(2) if callback: set_callback(ls) if load: load_initial_position(load) ls.create_phase().time_limit = int(time) ls.solve() for car in cars: print(car.value) for late in lates: print(late.value) print(max_lates.value) print(build_times([((0, 0), (0, 0), 0, 0)] + demand)) # solution = retrieve_solution(cars, lates, N) print(ls.compute_inconsistency()) return []
def main(instance_file, str_time_limit, sol_file, str_nb_trucks, truck_capacity, demands_for_day): nb_trucks = int(str_nb_trucks) mapIndex = {} # # Reads instance data # (nb_customers, truck_capacity, distance_matrix, distance_warehouses, dist_warehouses, demands, mapIndex, timePV, time_wh_to_pv, pv_for_time) = read_excel(instance_file, mapIndex, int(truck_capacity), demands_for_day) if nb_trucks == 0: nb_trucks = get_nb_trucks(instance_file) with localsolver.LocalSolver() as ls: # # Declares the optimization model # model = ls.model # Sequence of customers visited by each truck. customers_sequences = [ model.list(nb_customers) for k in range(nb_trucks) ] # All customers must be visited by the trucks model.constraint(model.partition(customers_sequences)) # Create demands as an array to be able to access it with an "at" operator demands_array = model.array(demands) # Create distance as an array to be able to acces it with an "at" operator distance_array = model.array() for n in range(nb_customers): distance_array.add_operand(model.array(distance_matrix[n])) distance_warehouse_array = model.array(distance_warehouses) route_distances = [None for n in range(nb_trucks)] # # A truck is used if it visits at least one customer trucks_used = [(model.count(customers_sequences[k]) > 0) for k in range(nb_trucks)] nb_trucks_used = model.sum(trucks_used) #for k in range(nb_trucks): for k in range(nb_trucks): sequence = customers_sequences[k] c = model.count(sequence) # Quantity in each truck demand_selector = model.function( lambda i: model.at(demands_array, sequence[i])) route_quantity = model.sum(model.range(0, c), demand_selector) model.constraint(route_quantity <= truck_capacity) # Distance traveled by each truck dist_selector = model.function(lambda i: model.at( distance_array, sequence[i - 1], sequence[i])) route_distances[k] = model.sum(model.range(1,c), dist_selector) + \ model.iif(c > 0, model.at(distance_warehouse_array, sequence[0]) + model.at(distance_warehouse_array, sequence[c-1]),0) # Total distance travelled total_distance = model.sum(route_distances) #print(route_distances.get_value()) # Objective: minimize the number of trucks used, then minimize the distance travelled model.minimize(nb_trucks_used) model.minimize(total_distance) model.close() # # Parameterizes the solver # ls.param.time_limit = int(str_time_limit) ls.solve() # # Writes the solution in a file with the following format: # - number of routes and total distance # - for each routes the nodes visited (omitting the start/end at the depot) # if len(sys.argv) >= 3: with open("../results/" + sol_file, 'w') as f: f.write("%d %d\n" % (nb_trucks_used.value, total_distance.value)) for k in range(nb_trucks): if (trucks_used[k].value != 1): continue # Values in sequence are in [0..nbCustomers-1]. +2 is to put it back in [2..nbCustomers+1] # as in the data files (1 being the depot) for customer in customers_sequences[k].value: f.write("%d " % (customer + 2)) f.write("\n") add_time = [] add_time_temp = [] sum_time = 0 sum_time_route = [] sum_dist = 0 sum_dist_route = [] sumQTA = 0 sum_QTA_route = [] with open("../results/" + sol_file, "r") as fd: for line in fd: add_time.append(line) fd.close() for n, el in enumerate(add_time): if (n != 0): add_time_temp = el.split(" ") for k, elem in enumerate(add_time_temp): if (elem != "\n"): if (k > 0): #print(add_time_temp[k-1]) #print(elem) #print(distance_matrix[ int(add_time_temp[k-1]) -2][int(elem) -2]) sum_time += timePV[int(add_time_temp[k - 1]) - 2][int(elem) - 2] sum_dist += distance_matrix[int(add_time_temp[k - 1]) - 2][int(elem) - 2] sumQTA += demands[int(add_time_temp[k]) - 2] sum_time_route.append(sum_time) sum_dist_route.append(sum_dist) sum_QTA_route.append(sumQTA) sum_time = 0 sum_dist = 0 sumQTA = 0 # Write solution as pv id. write_results(mapIndex, "../results/" + sol_file) file_sol = [] with open("../results/" + sol_file, "r") as fd: for line in fd: file_sol.append(line) fd.close() tempList = [] for n, el in enumerate(file_sol): if (n != 0): tempList = el.split(" ") initNode = tempList[0] endNode = tempList[-2] # Time sum_time_route[n - 1] += time_wh_to_pv[pv_for_time.index( int(initNode))] sum_time_route[n - 1] += time_wh_to_pv[pv_for_time.index( int(endNode))] # Distance from/to depot #print(pv_for_time.index(int(initNode))) #print(dist_warehouses[pv_for_time.index(int(initNode))]) sum_dist_route[n - 1] += dist_warehouses[pv_for_time.index( int(initNode))] sum_dist_route[n - 1] += dist_warehouses[pv_for_time.index( int(endNode))] # Draw graph of track's route draw_graph("../results/" + sol_file, sum_time_route, sum_dist_route, sum_QTA_route, truck_capacity, warehouse="434")
def main(instance_file, str_time_limit, sol_file, str_nb_trucks): nb_trucks = int(str_nb_trucks) # # Reads instance data # (nb_customers, truck_capacity, distance_matrix, distance_warehouses, demands) = read_input_cvrp(instance_file) # The number of trucks is usually given in the name of the file # nb_trucks can also be given in command line if nb_trucks == 0: nb_trucks = get_nb_trucks(instance_file) with localsolver.LocalSolver() as ls: # # Declares the optimization model # model = ls.model # Sequence of customers visited by each truck. customers_sequences = [ model.list(nb_customers) for k in range(nb_trucks) ] # All customers must be visited by the trucks model.constraint(model.partition(customers_sequences)) # Create demands as an array to be able to access it with an "at" operator demands_array = model.array(demands) # Create distance as an array to be able to acces it with an "at" operator distance_array = model.array() for n in range(nb_customers): distance_array.add_operand(model.array(distance_matrix[n])) distance_warehouse_array = model.array(distance_warehouses) route_distances = [None] * nb_trucks # A truck is used if it visits at least one customer trucks_used = [(model.count(customers_sequences[k]) > 0) for k in range(nb_trucks)] nb_trucks_used = model.sum(trucks_used) for k in range(nb_trucks): sequence = customers_sequences[k] c = model.count(sequence) # Quantity in each truck demand_selector = model.lambda_function( lambda i: demands_array[sequence[i]]) route_quantity = model.sum(model.range(0, c), demand_selector) model.constraint(route_quantity <= truck_capacity) # Distance traveled by each truck dist_selector = model.lambda_function(lambda i: model.at( distance_array, sequence[i - 1], sequence[i])) route_distances[k] = model.sum(model.range(1, c), dist_selector) + \ model.iif(c > 0, distance_warehouse_array[sequence[0]] + distance_warehouse_array[sequence[c-1]], 0) # Total distance traveled total_distance = model.sum(route_distances) # Objective: minimize the number of trucks used, then minimize the distance traveled model.minimize(nb_trucks_used) model.minimize(total_distance) model.close() # # Parameterizes the solver # ls.param.time_limit = int(str_time_limit) ls.solve() # # Writes the solution in a file with the following format: # - number of trucks used and total distance # - for each truck the nodes visited (omitting the start/end at the depot) # if len(sys.argv) >= 3: with open(sol_file, 'w') as f: f.write("%d %d\n" % (nb_trucks_used.value, total_distance.value)) for k in range(nb_trucks): if trucks_used[k].value != 1: continue # Values in sequence are in [0..nbCustomers-1]. +2 is to put it back in [2..nbCustomers+1] # as in the data files (1 being the depot) for customer in customers_sequences[k].value: f.write("%d " % (customer + 2)) f.write("\n")
def solve(self): """ Solves the instance. :return: """ ''' #calculate a new equivalent non directed exchanges, # (in order to remove the cases where we have the double arrow source -> target and target -> source exchanges2 = {} for source in self.instance.get_all_sources(): exchanges_s = self.instance.exchanges[source] for target,v in exchanges_s.items(): s = source t = target if source > target: s,t = t,s if s not in exchanges2: exchanges2[s] = {} exchanges2_s = exchanges2[s] if t not in exchanges2_s: exchanges2_s[t] = v else: exchanges2_s[t] += v ''' exchanges2 = self.instance.exchanges # Maximum number of clusters, to be set to number of OBEs nb_max_cluster = len(self.instance.get_all_nodes()) with localsolver.LocalSolver() as ls: # Declares the optimization model self.model = ls.model # Set decisions: cluster_list[k] represents the OBEs in cluster k clusters_list = [ self.model.set(self.nb_nodes) for k in range(self.nb_clusters) ] # Each OBE must be in one cluster and one cluster only self.model.constraint(self.model.partition(clusters_list)) # translation int to OBE name: obeToInt = {} intToObe = [] for count, val in enumerate(self.instance.get_all_nodes()): obeToInt[val] = count intToObe.append(val) #x[n][k]: is n in cluster #k x = {} for n in self.instance.get_all_nodes(): x[n] = [] for k in clusters_list: x[n].append(self.model.contains(k, obeToInt[n])) #y[k][s][t]: (cluster, source name, target name): is the arrow s->t inner to the cluster k #z[s][t] (not used): indexed by OBE names (source and target): is the arrow s->t inner to the same cluster y = {} z = {} for source in exchanges2: z[source] = {} z_s = z[source] for target in exchanges2[source]: z_s_t_k = [] for k in range(0, self.nb_clusters): if k not in y: y[k] = {} y_k = y[k] if source not in y_k: y_k[source] = {} y_k_s = y_k[source] a = self.model.and_(x[source][k], x[target][k]) y_k_s[target] = a z_s_t_k.append(a) z_s[target] = self.model.or_(z_s_t_k) ''' #internal traffic: definition using z (not used) internal_traffic = [] for source in exchanges2: for target,exchange in exchanges2[source].items(): internal_traffic.append( self.model.iif(z[source][target], exchange, 0)) total_traffic = self.model.sum(internal_traffic) ''' #cluster sizes: cluster_sizes = [] for k in clusters_list: cluster_sizes.append(self.model.count(k)) #internal traffic per cluster: total_traffic_k = [] for k in range(0, len(clusters_list)): weights_in_cluster = [] for source in exchanges2: for target, exchange in exchanges2[source].items(): weights_in_cluster.append( self.model.iif(y[k][source][target], exchange, 0)) total_traffic_k.append(self.model.sum(weights_in_cluster)) #internal traffic total_traffic = self.model.sum(total_traffic_k) #nb elmt in cluster cluster_count = [self.model.count(k) for k in clusters_list] #min_cluster_size (if cluster is not empty) min_cluster_size = self.min_cluster_size if self.min_cluster_size is None and self.force_nb_clusters: min_cluster_size = 1 if min_cluster_size is not None and min_cluster_size > 0: for k_idx, k in enumerate(clusters_list): if self.force_nb_clusters: self.model.add_constraint( cluster_count[k_idx] >= min_cluster_size) else: self.model.add_constraint( self.model.or_( cluster_count[k_idx] >= min_cluster_size, cluster_count[k_idx] == 0)) #max_cluster_size if self.max_cluster_size is not None: for k in clusters_list: self.model.add_constraint( self.model.count(k) <= self.max_cluster_size) #min_cluster_weight (if cluster is not empty) if self.min_cluster_weight is not None and self.min_cluster_weight > 0: for k_idx, k in enumerate(total_traffic_k): if self.force_nb_clusters: self.model.add_constraint(k >= self.min_cluster_weight) else: self.model.add_constraint( self.model.or_(k >= self.min_cluster_weight, cluster_count[k_idx] == 0)) for count, node in enumerate(self.separated_nodes): self.model.add_constraint( self.model.contains(clusters_list[count], obeToInt[node])) self.model.maximize(total_traffic) # heuristic: we add an equilibrium score in order to have clusters with similar weights # let's try to optimize the sum -ln(traffic_proportion_in_cluster)*cluster_traffic ''' equilibrum_score = 1-4*self.model.sum([k*self.model.log((k+0.000000001)/total_traffic) for k in total_traffic_k])/(total_traffic*math.log(self.nb_clusters)) heuristic_total_traffics = total_traffic*equilibrum_score self.model.maximize(heuristic_total_traffics) ''' if self.time_limit is not None: phase = ls.create_phase() phase.set_optimized_objective(0) phase.set_time_limit(self.time_limit) # close the model self.model.close() # Parameterizes the solver # solve model start = time.time() ls.solve() end = time.time() self.running_time = end - start logging.info("Running time (sec.) = {}".format(self.running_time)) status = ls.solution.get_status() if status in (localsolver.LSSolutionStatus.FEASIBLE, localsolver.LSSolutionStatus.OPTIMAL): logging.info("sum internal traffic = {}".format( total_traffic.value)) #logging.info("equilibrium score " + str(equilibrum_score.value)) for node in self.instance.get_all_nodes(): for k in range(self.nb_clusters): if x[node][k].value == 1: self.solution[node] = k break self.instance.set_solution(self.solution) # Writes the solution in a file with open('./LS_solution.txt', 'w') as f: f.write("%d\n" % total_traffic.value) for cluster in range(self.nb_clusters): for obe in self.instance.get_all_nodes(): f.write("%s " % x[obe][cluster].value) f.write("\n") else: self.infeasible = True logging.warning("Problem has no solution")
def ls_problem(self, liste_tic=False, liste_job=False, instance=0, no_pen=False, affectation={}, dual=-1, time_limit=10): ############################################################################### ################### initialisation variables ############################# ############################################################################### res = ls_prob() if (liste_tic == False): TICS = copy.deepcopy(constantes.TICS) ##restriction du problème à un sous ensemble de tic else: TICS = copy.deepcopy(constantes.TICS) TICS = [t for t in TICS if t.id in liste_tic] if (liste_job == False): JOBS = copy.deepcopy(constantes.JOBS) ##restriction du problème à un sous ensemble de tic et de job else: JOBS = copy.deepcopy(constantes.JOBS) JOBS = [j for j in JOBS if j.id in liste_job] res.JOBS = JOBS res.TICS = TICS ind_jobs = [j.id for j in JOBS] ind_jobs.insert(0, 0) ind_tics = [t.id for t in TICS] ind_tics_2 = [t.id for t in TICS] ind_tics_2.insert(0, 0) ####creation des données initiales pourlocalsolver nb_job = len(res.JOBS) nb_tic = len(res.TICS) t_min = [j.t_min for j in res.JOBS] t_max = [j.t_max for j in res.JOBS] t_start = [t.t_start for t in res.TICS] t_end = [t.t_end for t in res.TICS] dur = [j.dur for j in res.JOBS] ############################################################################### ######################## localsolver ##################################### ############################################################################### with localsolver.LocalSolver() as ls: # # Declares the optimization model # model = ls.model # Sequence of customers visited by each truck. jobs_sequences = [model.list(nb_job) for k in range(nb_tic)] ##ajout des contraintes de compétences #localsolver.LSOperator.INDEXOF(jobs_sequences[1],1)==-1 # All customers must be visited by the trucks ##TODO creer technicien fictif for k in range(nb_tic): cmp_list = TICS[k].cmp_list #cmp_list=[t for t in TICS if t.id==k+1][0].cmp_list for j in range(nb_job): comp = JOBS[j].cmp #comp=[jj for jj in JOBS if jj.id==j+1][0].cmp if comp not in cmp_list: model.constraint( model.index(jobs_sequences[k], j) == -1) model.constraint(model.partition(jobs_sequences)) # Create demands, earliest, latest and service as arrays to be able to access it with an "at" operator t_min_array = model.array(t_min) t_max_array = model.array(t_max) t_start_array = model.array(t_start) t_end_array = model.array(t_end) dur_array = model.array(dur) # Create distance as an array to be able to acces it with an "at" operator distance_array = model.array() temps_array = model.array() for j1 in res.JOBS: distance_matrix = [] temps_matrix = [] for j2 in res.JOBS: distance_matrix.append(job.distance(j1, j2)) temps_matrix.append(job.temps(j1, j2)) distance_array.add_operand(model.array(distance_matrix)) temps_array.add_operand(model.array(temps_matrix)) distance_warehouse_array = model.array() temps_warehouse_array = model.array() for t in res.TICS: distance_warehouse_matrix = [] temps_warehouse_matrix = [] for j1 in res.JOBS: distance_warehouse_matrix.append(job.distance(t, j1)) temps_warehouse_matrix.append(job.temps(t, j1)) distance_warehouse_array.add_operand( model.array(distance_warehouse_matrix)) temps_warehouse_array.add_operand( model.array(temps_warehouse_matrix)) route_distances = [None for n in res.TICS] end_time = [None for n in res.TICS] test_temp = [None for n in res.TICS] home_lateness = [None for n in res.TICS] lateness = [None for n in res.TICS] # A truck is used if it visits at least one customer trucks_used = [(model.count(jobs_sequences[k]) > 0) for k in range(nb_tic)] #nb_trucks_used = model.sum(trucks_used) for k in range(nb_tic): sequence = jobs_sequences[k] c = model.count(sequence) # Distance traveled by each truck dist_selector = model.function(lambda i: model.at( distance_array, sequence[i - 1], sequence[i])) route_distances[k] = model.sum(model.range(1,c), dist_selector) + \ model.iif(c > 0, model.at(distance_warehouse_array,k,sequence[0]) + model.at(distance_warehouse_array,k, sequence[c-1]),0) # End of each visit ##TODO a modifier pourauthoriser un temps d'attente? end_selector = model.function(lambda i, prev: model.max(t_min_array[sequence[i]], model.iif(i == 0,model.at(t_start_array,k)+model.at(temps_warehouse_array,k,sequence[0]), \ prev + model.at(temps_array,sequence[i-1],sequence[i]))) + \ model.at(dur_array, sequence[i])) end_time[k] = model.array(model.range(0, c), end_selector) #test_temp[k] = end_time[k][0] # Arriving home after max_horizon home_lateness[k] = model.iif(trucks_used[k], \ model.max(0,model.at(end_time[k],c-1) + model.at(temps_warehouse_array,k,sequence[c-1])-t_end[k]), \ 0) # completing visit after latest_end ##TODO retirer dur du job late_selector = model.function(lambda i: model.max( 0, model.at(end_time[k], i) - model.at( dur_array, sequence[i]) - model.at( t_max_array, sequence[i]))) lateness[k] = home_lateness[k] + model.sum( model.range(0, c), late_selector) # Total lateness total_lateness = model.sum(lateness) # Total distance travelled total_distance = model.sum(route_distances) # Objective: minimize the number of trucks used, then minimize the distance travelled model.minimize(total_lateness) model.minimize(total_distance) model.close() # # Parameterizes the solver # ls.create_phase().time_limit = time_limit ls.solve() # # Writes the solution in a file with the following format : # - number of trucks used and total distance # - for each truck the nodes visited (omitting the start/end at the depot) # #print("%d %d\n" % (total_lateness.value,total_distance.value)) print(constantes.INSTANCE) print(total_distance.value) return total_distance.value + 100000 * total_lateness.value