def __init__(self, model: mip.Model): if model.status == mip.OptimizationStatus.LOADED: logger.debug("model not runned yet, checking if feasible or not") model.emphasis = 1 # feasibility model.preprocess = 1 # -1 automatic, 0 off, 1 on. model.optimize() assert (model.status == mip.OptimizationStatus.INFEASIBLE ), "model is not linear infeasible" self.model = model
def __init__(self, model: mip.Model): if model.status == mip.OptimizationStatus.LOADED: print("model not runned yet, checking if feasible or not") model.emphasis = 1 # feasibility model.preprocess = 1 # -1 automatic, 0 off, 1 on. model.optimize() assert ( model.status == mip.OptimizationStatus.INFEASIBLE ), "model is not linear infeasible" self.model = model self.iis_num_iterations = 0 self.iis_iterations = [] self.relax_slack_iterations = []
def build_infeasible_cont_model(num_constraints: int = 10, num_infeasible_sets: int = 20) -> Model: # build an infeasible model, based on many redundant constraints mdl = Model(name='infeasible_model_continuous') var = mdl.add_var(name='var', var_type=CONTINUOUS, lb=-1000, ub=1000) for idx, rand_constraint in enumerate(np.linspace(1, 1000, num_constraints)): crt = mdl.add_constr(var >= rand_constraint, name='lower_bound_{}'.format(idx)) logger.debug('added {} to the model'.format(crt)) num_constraint_inf = int(num_infeasible_sets / num_constraints) for idx, rand_constraint in enumerate( np.linspace(-1000, -1, num_constraint_inf)): crt = mdl.add_constr(var <= rand_constraint, name='upper_bound_{}'.format(idx)) logger.debug('added {} to the model'.format(crt)) mdl.emphasis = 1 # feasibility mdl.preprocess = 1 # -1 automatic, 0 off, 1 on. # mdl.pump_passes TODO configure to feasibility emphasis return mdl
def tsp_mip_solver(input_data): # parse the input lines = input_data.split('\n') nodeCount = int(lines[0]) points = [] for i in range(1, nodeCount + 1): line = lines[i] parts = line.split() points.append(Point(float(parts[0]), float(parts[1]))) print('Points parsed!') # calculate distance matrix d_m = [[length(q, p) for q in points] for p in points] print('Distance matrix ready!') # declare MIP model m = Model(solver_name='GRB') print('-Model instatiated!', datetime.datetime.now()) # states search emphasis # - '0' (default) balanced approach # - '1' (feasibility) aggressively searches for feasible solutions # - '2' (optimality) explores search space to tighten dual gap m.emphasis = 0 # whenever the distance of the lower and upper bounds is less or # equal max_gap*100%, the search can be finished m.max_gap = 0.05 # specifies number of used threads # 0 uses solver default configuration, # -1 uses the number of available processing cores # ≥1 uses the specified number of threads. # An increased number of threads may improve the solution time but also increases # the memory consumption. Each thread needs to store a different model instance! m.threads = 0 # controls the generation of cutting planes # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger # -1 means automatic # 0 disables completely # 1 (default) generates cutting planes in a moderate way # 2 generates cutting planes aggressively # 3 generates even more cutting planes m.cuts = -1 m.preprocess = 1 m.pump_passes = 20 m.sol_pool_size = 1 nodes = set(range(nodeCount)) # instantiate "entering and leaving" variables x = [[m.add_var(name="x{}_{}".format(p, q), var_type='B') for q in nodes] for p in nodes] # instantiate subtour elimination variables y = [m.add_var(name="y{}".format(i)) for i in nodes] print('-Variables instantiated', datetime.datetime.now()) # declare objective function m.objective = minimize( xsum(d_m[i][j] * x[i][j] for i in nodes for j in nodes)) print('-Objective declared!', datetime.datetime.now()) # declare constraints # leave each city only once for i in tqdm(nodes): m.add_constr(xsum(x[i][j] for j in nodes - {i}) == 1) # enter each city only once for i in tqdm(nodes): m.add_constr(xsum(x[j][i] for j in nodes - {i}) == 1) # subtour elimination constraints for (i, j) in tqdm(product(nodes - {0}, nodes - {0})): if i != j: m.add_constr(y[i] - (nodeCount + 1) * x[i][j] >= y[j] - nodeCount) print('-Constraints declared!', datetime.datetime.now()) #Maximum time in seconds that the search can go on if a feasible solution #is available and it is not being improved mssi = 1000 #default = inf # specifies maximum number of nodes to be explored in the search tree (default = inf) mn = 1000000 #default = 1073741824 # optimize model m within a processing time limit of 'ms' seconds ms = 3000 #default = inf # executes the optimization print('-Optimizer start.', datetime.datetime.now()) #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn) status = m.optimize(max_seconds=ms, max_seconds_same_incumbent=mssi) print('Opt. Status:', status) print('MIP Sol. Obj.:', m.objective_value) print('Dual Bound:', m.objective_bound) print('Dual gap:', m.gap) sol = [0] c_node = 0 for j in range(nodeCount - 1): for i in range(nodeCount): if round(m.var_by_name("x{}_{}".format(c_node, i)).x) != 0: sol.append(i) c_node = i break obj = m.objective_value # prepare the solution in the specified output format if status == OptimizationStatus.OPTIMAL: output_data = '%.2f' % obj + ' ' + str(1) + '\n' output_data += ' '.join(map(str, sol)) elif status == OptimizationStatus.FEASIBLE: output_data = '%.2f' % obj + ' ' + str(0) + '\n' output_data += ' '.join(map(str, sol)) return output_data
def fl_mip_solver(input_data): # Modify this code to run your optimization algorithm # parse the input lines = input_data.split('\n') parts = lines[0].split() facility_count = int(parts[0]) customer_count = int(parts[1]) facilities = [] for i in range(1, facility_count+1): parts = lines[i].split() facilities.append(Facility(i-1, float(parts[0]), int(parts[1]), Point(float(parts[2]), float(parts[3])) )) customers = [] for i in range(facility_count+1, facility_count+1+customer_count): parts = lines[i].split() customers.append(Customer(i-1-facility_count, int(parts[0]), Point(float(parts[1]), float(parts[2])))) print('F count:',facility_count) print('C count:',customer_count) # instantiates setup cost vector set_cost = [f.setup_cost for f in facilities] # instantiates proportional capacity matrix such that Cap[i,j] represents the demand of # customer 'j' as a fraction of the total capacity of facility 'i' Cap = [[c.demand/f.capacity for c in customers] for f in facilities] # instantiates distance matrix in such a way that "sum_{j \in M} D[i,j]*at[i,j]" is the total # distance cost for facility 'i' D = [[length(c.location, f.location) for c in customers] for f in facilities] # declares MIP model #m = Model(solver_name=CBC) m = Model(solver_name='GRB') print('-Model instatiated!',datetime.datetime.now()) # states search emphasis # - '0' (default) balanced approach # - '1' (feasibility) aggressively searches for feasible solutions # - '2' (optimality) explores search space to tighten dual gap m.emphasis = 2 # whenever the distance of the lower and upper bounds is less or # equal max_gap*100%, the search can be finished m.max_gap = 0.05 # specifies number of used threads # 0 uses solver default configuration, # -1 uses the number of available processing cores # ≥1 uses the specified number of threads. # An increased number of threads may improve the solution time but also increases # the memory consumption. Each thread needs to store a different model instance! m.threads = -1 # controls the generation of cutting planes # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger # -1 means automatic # 0 disables completely # 1 (default) generates cutting planes in a moderate way # 2 generates cutting planes aggressively # 3 generates even more cutting planes m.cuts=-1 m.preprocess=1 m.pump_passes=10 m.sol_pool_size=1 # instantiates open facilities variables op = [m.add_var(name="op{}".format(i),var_type='B') for i in range(facility_count)] # instantiates matrix of atribution variables # (line 'i' is an atribution vector for facility 'i') # e.g.: At[3][4] returns whether customer 4 is assigned to facility 3 At = [[m.add_var(name="At{},{}".format(i,j) ,var_type='B') for j in range(customer_count)] for i in range(facility_count)] print('-Variables declared!',datetime.datetime.now()) # instantiates objective function # m.objective = minimize("setup costs" + "distance costs") # Form example: # m.objective = minimize( # xsum(dist[i, j] * x[i, j] for (i, j) in product(F, C)) + xsum(y[i] for i in F) ) m.objective = minimize( xsum(set_cost[i]*op[i] for i in range(facility_count)) + xsum(sum(D[i][j]*At[i][j] for j in range(customer_count)) for i in range(facility_count)) ) print('-Objective declared!',datetime.datetime.now()) # instatiates capacity constraints # -can be expressed as "sum_{j \in M} Cap[i,j]*At[i,j] <= op[i]" for all facilities 'i' # -if a facility is closed (op[i]=0), its effective capacity is 0 for i in range(facility_count): m.add_lazy_constr( xsum(Cap[i][j]*At[i][j] for j in range(customer_count)) <= op[i] ) # instantiates assignment constraints (maximum of 1 facility per customer) # -can be expressed as: "sum of elements over of each column of 'At' == 1" for i in range(customer_count): m += xsum(At[j][i] for j in range(facility_count)) == 1 print('-Contraints processed!',datetime.datetime.now()) #Maximum time in seconds that the search can go on if a feasible solution #is available and it is not being improved mssi = 1000 #default = inf # specifies maximum number of nodes to be explored in the search tree (default = inf) mn = 40000 #default = 1073741824 # optimize model m within a processing time limit of 'ms' seconds ms = 3000 #default = inf print('-Optimizer start.',datetime.datetime.now()) # executes the optimization #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn) status = m.optimize(max_seconds = ms , max_seconds_same_incumbent = mssi) final_obj = m.objective_value print('Opt. Status:',status) print('MIP Sol. Obj.:',final_obj) print('Dual Bound:',m.objective_bound) print('Dual gap:',m.gap) used=[i for i in range(facility_count) if m.vars[i].x==1] solution=[None] * customer_count for i in range(facility_count): for j in range(customer_count): if round(m.vars[i*customer_count + j + facility_count].x) == 1: solution[j]=i # parse output varibles and convert to conventional solution output format # calculate the cost of the solution obj = sum([facilities[f].setup_cost for f in used]) for customer in customers: obj += length(customer.location, facilities[solution[customer.index]].location) if status == OptimizationStatus.OPTIMAL: # prepare the solution in the specified output format output_data = '%.2f' % obj + ' ' + str(1) + '\n' output_data += ' '.join(map(str, solution)) elif status == OptimizationStatus.FEASIBLE: output_data = '%.2f' % obj + ' ' + str(0) + '\n' output_data += ' '.join(map(str, solution)) return output_data
def mip_solver(input_data): # Modify this code to run your optimization algorithm # parse the input lines = input_data.split('\n') firstLine = lines[0].split() item_count = int(firstLine[0]) capacity = int(firstLine[1]) items = [] for i in range(1, item_count+1): line = lines[i] parts = line.split() items.append(Item(i-1, int(parts[0]), int(parts[1]))) # a trivial algorithm for filling the knapsack # it takes items in-order until the knapsack is full value = 0 weight = 0 taken = [0]*len(items) # declare value vector val_vec = [item.value for item in items] # declare weight vector scaled by capacity wgt_vec = [item.weight/capacity for item in items] # start MIP solver m = Model(solver_name='GRB') print('-Model instatiated!',datetime.datetime.now()) # states search emphasis # - '0' (default) balanced approach # - '1' (feasibility) aggressively searches for feasible solutions # - '2' (optimality) explores search space to tighten dual gap m.emphasis = 2 # whenever the distance of the lower and upper bounds is less or # equal max_gap*100%, the search can be finished m.max_gap = 0.05 # specifies number of used threads # 0 uses solver default configuration, # -1 uses the number of available processing cores # ≥1 uses the specified number of threads. # An increased number of threads may improve the solution time but also increases # the memory consumption. Each thread needs to store a different model instance! m.threads = -1 # controls the generation of cutting planes # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger # -1 means automatic # 0 disables completely # 1 (default) generates cutting planes in a moderate way # 2 generates cutting planes aggressively # 3 generates even more cutting planes m.cuts=-1 m.preprocess=1 m.pump_passes=10 m.sol_pool_size=1 # instantiates taken items variable vector taken = [m.add_var(name="it{}".format(i),var_type='B') for i in range(item_count)] print('-Variables declared!',datetime.datetime.now()) # instantiates objective function m.objective = maximize( xsum( val_vec[i]*taken[i] for i in range(item_count) ) ) print('-Objective declared!',datetime.datetime.now()) m.add_constr( xsum( wgt_vec[i]*taken[i] for i in range(item_count)) <=1 ) print('-Contraints processed!',datetime.datetime.now()) #Maximum time in seconds that the search can go on if a feasible solution #is available and it is not being improved mssi = 1000 #default = inf # specifies maximum number of nodes to be explored in the search tree (default = inf) mn = 40000 #default = 1073741824 # optimize model m within a processing time limit of 'ms' seconds ms = 3000 #default = inf print('-Optimizer start.',datetime.datetime.now()) # executes the optimization #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn) status = m.optimize(max_seconds = ms , max_seconds_same_incumbent = mssi) final_obj = m.objective_value print('Opt. Status:',status) print('MIP Sol. Obj.:',final_obj) print('Dual Bound:',m.objective_bound) print('Dual gap:',m.gap) sol = [round(it.x) for it in taken] value = int(final_obj) taken = sol # prepare the solution in the specified output format if status == OptimizationStatus.OPTIMAL: output_data = str(value) + ' ' + str(1) + '\n' output_data += ' '.join(map(str, taken)) elif status == OptimizationStatus.FEASIBLE: output_data = str(value) + ' ' + str(0) + '\n' output_data += ' '.join(map(str, taken)) if item_count == 10000: output_data=greedy(input_data) return output_data
# denominator of the expected value m += xsum(w[i]*(d - (y[1][i] - z[1][i])) for i in range(M)) == 1, "denominator" # if not antidisabling, turn each antidisable off if not ANTIDISABLE: for i in range(len(z[0])): m += z[0][i] == 0, f"{zi.name}0" m += z[1][i] == 0, f"{zi.name}1" ### objective: maximize expected value of the remaining characters # numerator of the expected value, denominator has been accounted for m.objective = xsum(t[i]*(d - (y[1][i] - z[1][i])) for i in range(M)) if __name__ == "__main__": m.emphasis = 2 # emphasize optimality m.preprocess = 1 # don't preprocess if it introduces error status = m.optimize() disable_list = [bundle_list[i] for i in range(N) if x[i].x >= 0.99] + \ [series_list[i - N] for i in range(N, N + A) if x[i].x >= 0.99] antidisable_list = [series_list[i] for i in range(M) if z[0][i].x >= 0.99] total = get_size(disable_list) count, count_anti = get_wa(disable_list), get_wa(antidisable_list) X, p = random_variable(character_values(disable_list, antidisable_list)) print(f"expected value: {E(p, X):.3f}") print(f"disablelist ({len(disable_list)}/{NUM_DISABLE})") print(f"{server_disabled + total} disabled ({server_wa + count} $wa)") print(f"Overlap limit: {total} / {OVERLAP} characters") print(f"{count} $wa characters disabled by $disable")