def vne(datafile): # Input data. If no file is given on the command line then use a # default file name. The data read is # width - the width of the the roll, # size - the sie of each strip, # amount - the demand for each strip. SN, VNN, VNR = read_dat_file(datafile) SN_N = SN[1]; print (SN_N);
def __init__(self, filename): # read the data in filename self.arcCost = read_dat_file(filename)[0] self.numNodes = len(self.arcCost) # check data consistency for i in range(self.numNodes): if len(self.arcCost[i]) != self.numNodes: print("ERROR: Data file '%s' contains inconsistent data\n" % filename) raise Exception("data file error") self.arcCost[i][i] = 0.0
def __init__(self, filename): # read the data in filename self.arcCost = read_dat_file(filename)[0] self.numNodes = len(self.arcCost) # check data consistency for i in range(self.numNodes): if len(self.arcCost[i]) != self.numNodes: print "ERROR: Data file '%s' contains inconsistent data\n" % filename raise Exception("data file error") self.arcCost[i][i] = 0.0
def rates(datafile): # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # min -- a list/array of minimal power production of generators. # max -- a list/array of maximal power production of generators. # cost -- a list/array of cost for using a generator # demand -- the total power demand. # The arrays are all of equal length and each entry corresponds to # a generator. min, max, cost, demand = read_dat_file(datafile) generators = list(range(len(min))) # List of generators # Create a new (empty) model and populate it below. model = cplex.Cplex() # Create one variable for each generator. The variables model the amount # of power generated by the respective generator. They are of type # semi-continuous because a generator g produces at least min[g] if it # is switched on. model.variables.add(obj=cost, lb=min, ub=max) model.variables.set_types( zip(generators, len(generators) * [model.variables.type.semi_continuous])) # Require that the sum of the production of all generators # satisfies the demand. totalproduction = cplex.SparsePair(ind=generators, val=[1.0] * len(generators)) model.linear_constraints.add(lin_expr=[totalproduction], senses=["G"], rhs=[demand]) # Our objective is to minimize cost. Cost per unit of power generated # was already set when variables were created. model.objective.set_sense(model.objective.sense.minimize) # Eport the model to disk and solve. try: model.write("rates.lp") model.solve() except CplexSolverError as e: print("Exception raised during solve: " + e) else: # Solve succesful, dump solution. print("Solution status = ", model.solution.get_status()) for g in generators: print(" generator " + str(g) + ": " + str(model.solution.get_values(g))) print("Total cost = " + str(model.solution.get_objective_value()))
def rates(datafile): # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # min -- a list/array of minimal power production of generators. # max -- a list/array of maximal power production of generators. # cost -- a list/array of cost for using a generator # demand -- the total power demand. # The arrays are all of equal length and each entry corresponds to # a generator. min, max, cost, demand = read_dat_file(datafile) generators = list(range(len(min))) # List of generators # Create a new (empty) model and populate it below. model = cplex.Cplex() # Create one variable for each generator. The variables model the amount # of power generated by the respective generator. They are of type # semi-continuous because a generator g produces at least min[g] if it # is switched on. model.variables.add(obj=cost, lb=min, ub=max) model.variables.set_types(zip(generators, len(generators) * [model.variables.type.semi_continuous])) # Require that the sum of the production of all generators # satisfies the demand. totalproduction = cplex.SparsePair(ind=generators, val=[1.0] * len(generators)) model.linear_constraints.add(lin_expr=[totalproduction], senses=["G"], rhs=[demand]) # Our objective is to minimize cost. Cost per unit of power generated # was already set when variables were created. model.objective.set_sense(model.objective.sense.minimize) # Eport the model to disk and solve. try: model.write("rates.lp") model.solve() except CplexSolverError as e: print("Exception raised during solve: " + e) else: # Solve succesful, dump solution. print("Solution status = ", model.solution.get_status()) for g in generators: print(" generator " + str(g) + ": " + str(model.solution.get_values(g))) print("Total cost = " + str(model.solution.get_objective_value()))
def __init__(self, filename): # read the data in diet.dat (self.foodCost, self.foodMin, self.foodMax, self.nutrMin, self.nutrMax, self.nutrPer) = read_dat_file("../../data/diet.dat") # check data consistency if (len(self.foodCost) != len(self.foodMin) or len(self.foodCost) != len(self.foodMax) or len(self.nutrMin) != len(self.nutrMax) or len(self.nutrMin) != len(self.nutrPer)): print("ERROR: Data file '%s' contains inconsistent data\n" % filename) raise Exception("data file error") for np in self.nutrPer: if len(self.foodCost) != len(np): print("ERROR: Data file '%s' contains inconsistent data\n" % filename) raise Exception("data file error")
def __init__(self, filename): # read the data in diet.dat self.foodCost, self.foodMin, self.foodMax, self.nutrMin, \ self.nutrMax, self.nutrPer = \ read_dat_file("../../data/diet.dat") # check data consistency if len(self.foodCost) != len(self.foodMin) or \ len(self.foodCost) != len(self.foodMax) or \ len(self.nutrMin) != len(self.nutrMax) or \ len(self.nutrMin) != len(self.nutrPer): print "ERROR: Data file '%s' contains inconsistent data\n" % filename raise Exception("data file error") for np in self.nutrPer: if len(self.foodCost) != len(np): print "ERROR: Data file '%s' contains inconsistent data\n" % filename raise Exception("data file error")
if __name__ == "__main__": # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # min -- a list/array of minimal power production of generators. # max -- a list/array of maximal power production of generators. # cost -- a list/array of cost for using a generator # demand -- the total power demand. # The arrays are all of equal length and each entry corresponds to # a generator. datafile = "../../../examples/data/rates.dat" if len(sys.argv) < 2: print "Default data file : " + datafile else: datafile = sys.argv[1] min, max, cost, demand = read_dat_file(datafile) generators = range(len(min)) # List of generators # Create a new (empty) model and populate it below. model = cplex.Cplex() # Create one variable for each generator. The variables model the amount # of power generated by the respective generator. They are of type # semi-continuous because a generator g produces at least min[g] if it # is switched on. model.variables.add(obj = cost, lb = min, ub = max) model.variables.set_types(zip(generators, len(generators) * [model.variables.type.semi_continuous])) # Require that the sum of the production of all generators
def facility(): # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # capacity -- a list/array of facility capacity # fixedcost -- a list/array of facility fixed cost # cost -- a matrix for the costs to serve each client by each facility datafile = "../../../examples/data/facility.dat" if len(sys.argv) < 2: print("Default data file : " + datafile) else: datafile = sys.argv[1] capacity, fixedcost, cost = read_dat_file(datafile) num_facilities = len(fixedcost) num_clients = len(cost) # Create a new (empty) model and populate it below. model = cplex.Cplex() # Create one binary variable for each facility. The variables model # whether each facility is open or not model.variables.add(obj = fixedcost, lb = [0] * num_facilities, ub = [1] * num_facilities, types = ["B"] * num_facilities) # Create one binary variable for each facility/client pair. The variables # model whether a client is served by a facility. for c in range(num_clients): model.variables.add(obj = cost[c], lb = [0] * num_facilities, ub = [1] * num_facilities, types = ["B"] * num_facilities) # Create corresponding indices for later use supply = [] for c in range(num_clients): supply.append([]) for f in range(num_facilities): supply[c].append((c+1)*(num_facilities)+f) # Equivalently, supply can be defined by list comprehension # supply = [[(c + 1) * num_facilities + f # for f in range(num_facilities)] for c in range(num_clients)] # Each client must be assigned to exactly one location for c in range(num_clients): assignment_constraint = cplex.SparsePair(ind = [supply[c][f] for f in \ range(num_facilities)], val = [1.0] * num_facilities) model.linear_constraints.add(lin_expr = [assignment_constraint], senses = ["E"], rhs = [1]); # The number of clients assigned to a facility must be less than the # capacity of the facility, and clients must be assigned to an open facility for f in range(num_facilities): index = [f] value = [-capacity[f]] for c in range(num_clients): index.append(supply[c][f]) value.append(1.0) capacity_constraint = cplex.SparsePair(ind = index, val = value) model.linear_constraints.add(lin_expr = [capacity_constraint], senses = ["L"], rhs = [0]); # Our objective is to minimize cost. Fixed and variable costs # have been set when variables were created. model.objective.set_sense(model.objective.sense.minimize) # Solve try: model.solve() except CplexSolverError as e: print("Exception raised during solve: " + e) else: solution = model.solution # solution.get_status() returns an integer code print("Solution status = " , solution.get_status(), ":", end=' ') # the following line prints the corresponding string print(solution.status[solution.get_status()]) # Display solution. print("Total cost = " , solution.get_objective_value()) for f in range(num_facilities): if (solution.get_values(f) > model.parameters.mip.tolerances.integrality.get()): print("Facility %d is open and serves the following clients:" % f, end=' ') for c in range(num_clients): if (solution.get_values(supply[c][f]) > model.parameters.mip.tolerances.integrality.get()): print(c, end=' ') print()
def facility(datafile): # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # capacity -- a list/array of facility capacity # fixedcost -- a list/array of facility fixed cost # cost -- a matrix for the costs to serve each client by each # facility capacity, fixedcost, cost = read_dat_file(datafile) num_facilities = len(fixedcost) num_clients = len(cost) # Create a new (empty) model and populate it below. model = cplex.Cplex() # Create one binary variable for each facility. The variables model # whether each facility is open or not model.variables.add(obj=fixedcost, lb=[0] * num_facilities, ub=[1] * num_facilities, types=["B"] * num_facilities) # Create one binary variable for each facility/client pair. The variables # model whether a client is served by a facility. for c in range(num_clients): model.variables.add(obj=cost[c], lb=[0] * num_facilities, ub=[1] * num_facilities, types=["B"] * num_facilities) # Create corresponding indices for later use supply = [] for c in range(num_clients): supply.append([]) for f in range(num_facilities): supply[c].append((c + 1) * (num_facilities) + f) # Equivalently, supply can be defined by list comprehension # supply = [[(c + 1) * num_facilities + f # for f in range(num_facilities)] for c in range(num_clients)] # Each client must be assigned to exactly one location for c in range(num_clients): assignment_constraint = cplex.SparsePair( ind=[supply[c][f] for f in range(num_facilities)], val=[1.0] * num_facilities) model.linear_constraints.add(lin_expr=[assignment_constraint], senses=["E"], rhs=[1]) # The number of clients assigned to a facility must be less than the # capacity of the facility, and clients must be assigned to an open # facility for f in range(num_facilities): index = [f] value = [-capacity[f]] for c in range(num_clients): index.append(supply[c][f]) value.append(1.0) capacity_constraint = cplex.SparsePair(ind=index, val=value) model.linear_constraints.add(lin_expr=[capacity_constraint], senses=["L"], rhs=[0]) # Our objective is to minimize cost. Fixed and variable costs # have been set when variables were created. model.objective.set_sense(model.objective.sense.minimize) # Solve try: model.solve() except CplexSolverError as e: print("Exception raised during solve: " + e) else: solution = model.solution # solution.get_status() returns an integer code print("Solution status = ", solution.get_status(), ":", end=' ') # the following line prints the corresponding string print(solution.status[solution.get_status()]) # Display solution. print("Total cost = ", solution.get_objective_value()) for f in range(num_facilities): if (solution.get_values(f) > model.parameters.mip.tolerances.integrality.get()): print("Facility %d is open and serves the " "following clients:" % f, end=' ') for c in range(num_clients): if (solution.get_values(supply[c][f]) > model.parameters.mip.tolerances.integrality.get()): print(c, end=' ') print()
for v in range(cut.variables.get_num()): print " Cut" + str(v) + " = " + str(cut.solution.get_values(v)) if __name__ == "__main__": # Input data. If no file is given on the command line then use a # default file name. The data read is # width - the width of the the roll, # size - the sie of each strip, # amount - the demand for each strip. datafile = "data/cutstock.dat" if len(sys.argv) < 2: print "Default data file : " + datafile else: datafile = sys.argv[1] width, size, amount = read_dat_file(datafile) # Setup cutting optimization (master) problem. # This is the problem to which columns will be added in the loop # below. cut = cplex.Cplex() cutcons = range(len(amount)) # constraint indices cutvars = range(len(size)) # variable indices cut.variables.add(obj = [1] * len(cutvars)) # Add constraints. They have empty left-hand side initially. The # left-hand side is filled in the next loop. cut.linear_constraints.add(lin_expr = [SparsePair()] * len(cutcons), senses = ["G"] * len(cutcons), rhs = amount) for v in cutvars:
def cutstock(datafile): # Input data. If no file is given on the command line then use a # default file name. The data read is # width - the width of the the roll, # size - the sie of each strip, # amount - the demand for each strip. width, size, amount = read_dat_file(datafile) # Setup cutting optimization (master) problem. # This is the problem to which columns will be added in the loop # below. cut = cplex.Cplex() cutcons = list(range(len(amount))) # constraint indices cutvars = list(range(len(size))) # variable indices cut.variables.add(obj=[1] * len(cutvars)) # Add constraints. They have empty left-hand side initially. The # left-hand side is filled in the next loop. cut.linear_constraints.add(lin_expr=[SparsePair()] * len(cutcons), senses=["G"] * len(cutcons), rhs=amount) for v in cutvars: cut.linear_constraints.set_coefficients(v, v, int(width / size[v])) # Setup pattern generation (worker) problem. # The constraints and variables in this problem always stay the same # but the objective function will change during the column generation # loop. pat = cplex.Cplex() use = list(range(len(size))) # variable indices pat.variables.add(types=[pat.variables.type.integer] * len(use)) # Add a constant 1 to the objective. pat.variables.add(obj=[1], lb=[1], ub=[1]) # Single constraint: total size must not exceed the width. totalsize = SparsePair(ind=use, val=size) pat.linear_constraints.add(lin_expr=[totalsize], senses=["L"], rhs=[width]) pat.objective.set_sense(pat.objective.sense.minimize) # Column generation procedure while True: # Optimize over current patterns cut.solve() report1(cut) # Find and add new pattern. The objective function of the # worker problem is constructed from the dual values of the # constraints of the master problem. price = [-d for d in cut.solution.get_dual_values(cutcons)] pat.objective.set_linear(list(zip(use, price))) pat.solve() report2(pat, use) # If reduced cost (worker problem objective function value) is # non-negative we are optimal. Otherwise we found a new column # to be added. Coefficients of the new column are given by the # optimal solution vector to the worker problem. if pat.solution.get_objective_value() > -RC_EPS: break newpat = pat.solution.get_values(use) # The new pattern constitutes a new variable in the cutting # optimization problem. Create that variable and add it to all # constraints with the coefficients read from the optimal solution # of the pattern generation problem. idx = cut.variables.get_num() cut.variables.add(obj=[1.0]) cut.linear_constraints.set_coefficients( list(zip(cutcons, [idx] * len(use), newpat))) cutvars.append(idx) # Perform a final solve on the cutting optimization problem. # Turn all variables into integers before doing that. cut.variables.set_types( list(zip(cutvars, [cut.variables.type.integer] * len(cutvars)))) cut.solve() report3(cut) print("Solution status = ", cut.solution.get_status())
def cutstock(datafile): # Input data. If no file is given on the command line then use a # default file name. The data read is # width - the width of the the roll, # size - the sie of each strip, # amount - the demand for each strip. width, size, amount = read_dat_file(datafile) # Setup cutting optimization (master) problem. # This is the problem to which columns will be added in the loop # below. cut = cplex.Cplex() cutcons = list(range(len(amount))) # constraint indices cutvars = list(range(len(size))) # variable indices cut.variables.add(obj=[1] * len(cutvars)) # Add constraints. They have empty left-hand side initially. The # left-hand side is filled in the next loop. cut.linear_constraints.add(lin_expr=[SparsePair()] * len(cutcons), senses=["G"] * len(cutcons), rhs=amount) for v in cutvars: cut.linear_constraints.set_coefficients(v, v, int(width / size[v])) # Setup pattern generation (worker) problem. # The constraints and variables in this problem always stay the same # but the objective function will change during the column generation # loop. pat = cplex.Cplex() use = list(range(len(size))) # variable indices pat.variables.add(types=[pat.variables.type.integer] * len(use)) # Add a constant 1 to the objective. pat.variables.add(obj=[1], lb=[1], ub=[1]) # Single constraint: total size must not exceed the width. totalsize = SparsePair(ind=use, val=size) pat.linear_constraints.add(lin_expr=[totalsize], senses=["L"], rhs=[width]) pat.objective.set_sense(pat.objective.sense.minimize) # Column generation procedure while True: # Optimize over current patterns cut.solve() report1(cut) # Find and add new pattern. The objective function of the # worker problem is constructed from the dual values of the # constraints of the master problem. price = [-d for d in cut.solution.get_dual_values(cutcons)] pat.objective.set_linear(list(zip(use, price))) pat.solve() report2(pat, use) # If reduced cost (worker problem objective function value) is # non-negative we are optimal. Otherwise we found a new column # to be added. Coefficients of the new column are given by the # optimal solution vector to the worker problem. if pat.solution.get_objective_value() > -RC_EPS: break newpat = pat.solution.get_values(use) # The new pattern constitutes a new variable in the cutting # optimization problem. Create that variable and add it to all # constraints with the coefficients read from the optimal solution # of the pattern generation problem. idx = cut.variables.get_num() cut.variables.add(obj=[1.0]) cut.linear_constraints.set_coefficients(list(zip(cutcons, [idx] * len(use), newpat))) cutvars.append(idx) # Perform a final solve on the cutting optimization problem. # Turn all variables into integers before doing that. cut.variables.set_types( list(zip(cutvars, [cut.variables.type.integer] * len(cutvars)))) cut.solve() report3(cut) print("Solution status = ", cut.solution.get_status())
if __name__ == "__main__": # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # min -- a list/array of minimal power production of generators. # max -- a list/array of maximal power production of generators. # cost -- a list/array of cost for using a generator # demand -- the total power demand. # The arrays are all of equal length and each entry corresponds to # a generator. datafile = "../../../examples/data/rates.dat" if len(sys.argv) < 2: print("Default data file : " + datafile) else: datafile = sys.argv[1] min, max, cost, demand = read_dat_file(datafile) generators = list(range(len(min))) # List of generators # Create a new (empty) model and populate it below. model = cplex.Cplex() # Create one variable for each generator. The variables model the amount # of power generated by the respective generator. They are of type # semi-continuous because a generator g produces at least min[g] if it # is switched on. model.variables.add(obj=cost, lb=min, ub=max) model.variables.set_types( zip(generators, len(generators) * [model.variables.type.semi_continuous])) # Require that the sum of the production of all generators
def etsp(datafile): # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # activityOnAResource -- # An array of arrays represents the resources # required for each activity of a job # duration -- # An array of arrays represents the duration required # for each activity of a job # jobDueDate -- # contains the due date for each job # jobEarlinessCost -- # contains the penalty for being too early for each job # jobTardinessCost -- # contains the penalty for being too late for each job (activityOnAResource, duration, jobDueDate, jobEarlinessCost, jobTardinessCost) = read_dat_file(datafile) nbJob = len(jobDueDate) nbResource = len(activityOnAResource[1]) def starttime(job, res): return job * nbJob + res try: # Build model model = cplex.Cplex() model.objective.set_sense(model.objective.sense.minimize) # Add activity start time variables nbStart = nbJob * nbResource obj = [0.0] * nbStart lb = [0.0] * nbStart ub = [10000.0] * nbStart model.variables.add(obj, lb, ub) # State precedence constraints # starttime(i, j) - starttime(i, j-1) >= duration(i, j-1) for i in range(nbJob): for j in range(1, nbResource): ind = [starttime(i, j), starttime(i, j - 1)] val = [1.0, -1.0] row = [[ind, val]] model.linear_constraints.add(lin_expr=row, senses="G", rhs=[duration[i][j - 1]]) # Add indicator variables nIndicatorVars = nbResource * nbJob * (nbJob - 1) colname_ind = ["ind" + str(j + 1) for j in range(nIndicatorVars)] obj = [0.0] * nIndicatorVars lb = [0.0] * nIndicatorVars ub = [1.0] * nIndicatorVars types = ["B"] * nIndicatorVars model.variables.add(obj, lb, ub, types, colname_ind) # Add ind1 + ind2 >= 1 # ind3 + ind4 >= 1 # ind5 + ind6 >= 1 # ... # constraints j = nbStart for i in range(nIndicatorVars // 2): ind = [j, j + 1] val = [1.0, 1.0] row = [[ind, val]] model.linear_constraints.add(lin_expr=row, senses="G", rhs=[1]) j = j + 2 # Add indicator constraints # i1 = 1 <-> c1 # i2 = 1 <-> c2 index = 0 for i in range(nbResource): e = nbJob - 1 for j in range(e): activity1 = activityOnAResource[i][j] for k in range(j + 1, nbJob): activity2 = activityOnAResource[i][k] ic_dict = {} ic_dict["indvar"] = nbStart + index ic_dict["lin_expr"] = cplex.SparsePair( ind=[starttime(j, activity1), starttime(k, activity2)], val=[1.0, -1.0]) ic_dict["rhs"] = duration[k][activity2] / 1.0 ic_dict["sense"] = "G" ic_dict["complemented"] = 0 # ind(nbStart + index) = 1 -> ... # starttime(j, activity1) - starttime(k, activity2) >= # duration(k, activity2) model.indicator_constraints.add(**ic_dict) ic_dict["sense"] = "L" ic_dict["complemented"] = 1 # ind(nbStart + index) = 0 -> ... # starttime(j, activity1) - starttime(k, activity2) <= # duration(k, activity2) model.indicator_constraints.add(**ic_dict) ic_dict = {} ic_dict["indvar"] = nbStart + index + 1 ic_dict["lin_expr"] = cplex.SparsePair( ind=[starttime(k, activity2), starttime(j, activity1)], val=[1.0, -1.0]) ic_dict["rhs"] = duration[j][activity1] / 1.0 ic_dict["sense"] = "G" ic_dict["complemented"] = 0 # ind(nbStart + index) = 1 -> ... # starttime(k, activity2) - starttime(j, activity1) >= # duration(j, activity1) model.indicator_constraints.add(**ic_dict) ic_dict["sense"] = "L" ic_dict["complemented"] = 1 # ind(nbStart + index) = 0 -> ... # starttime(k, activity2) - starttime(j, activity1) <= # duration(j, activity1) model.indicator_constraints.add(**ic_dict) index = index + 2 # Add Objective function # each job has a cost which contains jobEarlinessCost and # jobTardinessCost, and get the index of Earliness variables, # Tardiness variables and Endness variables indexOfEarlinessVar = list( range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=jobEarlinessCost) indexOfTardinessVar = list( range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=jobTardinessCost) # Add finished time variables indexOfEndnessVar = list( range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=[0.0] * nbJob) # Add constraints for each Job # indexOfEndnessVar[i] - starttime(i, nbResource) = # duration[i][nbResource] for i in range(nbJob): ind = [indexOfEndnessVar[i], starttime(i, nbResource - 1)] val = [1.0, -1.0] row = [[ind, val]] model.linear_constraints.add(lin_expr=row, senses="E", rhs=[duration[i][nbResource - 1]]) # Add constraints for each Job # jobDueDate[i] = \ # indexOfEndnessVar[i] + indexOfEarlinessVar[i] - # indexOfTardinessVar[i] for i in range(nbJob): ind = [ indexOfEndnessVar[i], indexOfEarlinessVar[i], indexOfTardinessVar[i] ] val = [1.0, 1.0, -1.0] row = [[ind, val]] model.linear_constraints.add(lin_expr=row, senses="E", rhs=[jobDueDate[i]]) model.parameters.emphasis.mip = 4 model.solve() model.write('etsp.sav') except CplexError as exc: print(exc) return # Display solution print("Solution status = ", model.solution.get_status()) print("Optimal Value = ", model.solution.get_objective_value())
def facility(): # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # capacity -- a list/array of facility capacity # fixedcost -- a list/array of facility fixed cost # cost -- a matrix for the costs to serve each client by each facility datafile = "../../../examples/data/facility.dat" if len(sys.argv) < 2: print "Default data file : " + datafile else: datafile = sys.argv[1] capacity, fixedcost, cost = read_dat_file(datafile) num_facilities = len(fixedcost) num_clients = len(cost) # Create a new (empty) model and populate it below. model = cplex.Cplex() # Create one binary variable for each facility. The variables model # whether each facility is open or not model.variables.add(obj=fixedcost, lb=[0] * num_facilities, ub=[1] * num_facilities, types=["B"] * num_facilities) # Create one binary variable for each facility/client pair. The variables # model whether a client is served by a facility. for c in range(num_clients): model.variables.add(obj=cost[c], lb=[0] * num_facilities, ub=[1] * num_facilities, types=["B"] * num_facilities) # Create corresponding indices for later use supply = [] for c in range(num_clients): supply.append([]) for f in range(num_facilities): supply[c].append((c + 1) * (num_facilities) + f) # Equivalently, supply can be defined by list comprehension # supply = [[(c + 1) * num_facilities + f # for f in range(num_facilities)] for c in range(num_clients)] # Each client must be assigned to exactly one location for c in range(num_clients): assignment_constraint = cplex.SparsePair(ind = [supply[c][f] for f in \ range(num_facilities)], val = [1.0] * num_facilities) model.linear_constraints.add(lin_expr=[assignment_constraint], senses=["E"], rhs=[1]) # The number of clients assigned to a facility must be less than the # capacity of the facility, and clients must be assigned to an open facility for f in range(num_facilities): index = [f] value = [-capacity[f]] for c in range(num_clients): index.append(supply[c][f]) value.append(1.0) capacity_constraint = cplex.SparsePair(ind=index, val=value) model.linear_constraints.add(lin_expr=[capacity_constraint], senses=["L"], rhs=[0]) # Our objective is to minimize cost. Fixed and variable costs # have been set when variables were created. model.objective.set_sense(model.objective.sense.minimize) # Solve try: model.solve() except CplexSolverError, e: print "Exception raised during solve: " + e
datafile = defaultfile if len(sys.argv) < 2: print "Default data file : " + datafile else: datafile = sys.argv[1] else: prompt = """Enter the path to a data file: The path must be entered as a string; e.g. "../../../examples/data/etsp.dat". Enter "" to use the default file.\n""" user_file = input(prompt) print "hello" + user_file if user_file != "": datafile = user_file else: datafile = defaultfile activityOnAResource, duration, jobDueDate, jobEarlinessCost, jobTardinessCost = read_dat_file(datafile) nbJob = len(jobDueDate) nbResource = len(activityOnAResource[1]) def starttime(job, res): return job * nbJob + res etsp(datafile)
print "Default data file : " + datafile else: datafile = sys.argv[1] else: prompt = """Enter the path to a data file: The path must be entered as a string; e.g. "../../../examples/data/etsp.dat". Enter "" to use the default file.\n""" user_file = input(prompt) print "hello" + user_file if user_file != "": datafile = user_file else: datafile = defaultfile activityOnAResource, \ duration, \ jobDueDate, \ jobEarlinessCost, \ jobTardinessCost = \ read_dat_file(datafile) nbJob = len (jobDueDate) nbResource = len (activityOnAResource[1]) def starttime(job, res): return job * nbJob + res etsp(datafile)
def etsp(datafile): # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # activityOnAResource -- # An array of arrays represents the resources # required for each activity of a job # duration -- # An array of arrays represents the duration required # for each activity of a job # jobDueDate -- # contains the due date for each job # jobEarlinessCost -- # contains the penalty for being too early for each job # jobTardinessCost -- # contains the penalty for being too late for each job (activityOnAResource, duration, jobDueDate, jobEarlinessCost, jobTardinessCost) = read_dat_file(datafile) nbJob = len(jobDueDate) nbResource = len(activityOnAResource[1]) def starttime(job, res): return job * nbJob + res try: # Build model model = cplex.Cplex() model.objective.set_sense(model.objective.sense.minimize) # Add activity start time variables nbStart = nbJob * nbResource obj = [0.0] * nbStart lb = [0.0] * nbStart ub = [10000.0] * nbStart model.variables.add(obj, lb, ub) # State precedence constraints # starttime(i, j) - starttime(i, j-1) >= duration(i, j-1) for i in range(nbJob): for j in range(1, nbResource): ind = [starttime(i, j), starttime(i, j - 1)] val = [1.0, -1.0] row = [[ind, val]] model.linear_constraints.add( lin_expr=row, senses="G", rhs=[duration[i][j - 1]]) # Add indicator variables nIndicatorVars = nbResource * nbJob * (nbJob - 1) colname_ind = ["ind" + str(j + 1) for j in range(nIndicatorVars)] obj = [0.0] * nIndicatorVars lb = [0.0] * nIndicatorVars ub = [1.0] * nIndicatorVars types = ["B"] * nIndicatorVars model.variables.add(obj, lb, ub, types, colname_ind) # Add ind1 + ind2 >= 1 # ind3 + ind4 >= 1 # ind5 + ind6 >= 1 # ... # constraints j = nbStart for i in range(nIndicatorVars // 2): ind = [j, j + 1] val = [1.0, 1.0] row = [[ind, val]] model.linear_constraints.add(lin_expr=row, senses="G", rhs=[1]) j = j + 2 # Add indicator constraints # i1 = 1 <-> c1 # i2 = 1 <-> c2 index = 0 for i in range(nbResource): e = nbJob - 1 for j in range(e): activity1 = activityOnAResource[i][j] for k in range(j + 1, nbJob): activity2 = activityOnAResource[i][k] ic_dict = {} ic_dict["indvar"] = nbStart + index ic_dict["lin_expr"] = cplex.SparsePair( ind=[starttime(j, activity1), starttime(k, activity2)], val=[1.0, -1.0]) ic_dict["rhs"] = duration[k][activity2] / 1.0 ic_dict["sense"] = "G" ic_dict["complemented"] = 0 # ind(nbStart + index) = 1 -> ... # starttime(j, activity1) - starttime(k, activity2) >= # duration(k, activity2) model.indicator_constraints.add(**ic_dict) ic_dict["sense"] = "L" ic_dict["complemented"] = 1 # ind(nbStart + index) = 0 -> ... # starttime(j, activity1) - starttime(k, activity2) <= # duration(k, activity2) model.indicator_constraints.add(**ic_dict) ic_dict = {} ic_dict["indvar"] = nbStart + index + 1 ic_dict["lin_expr"] = cplex.SparsePair( ind=[starttime(k, activity2), starttime(j, activity1)], val=[1.0, -1.0]) ic_dict["rhs"] = duration[j][activity1] / 1.0 ic_dict["sense"] = "G" ic_dict["complemented"] = 0 # ind(nbStart + index) = 1 -> ... # starttime(k, activity2) - starttime(j, activity1) >= # duration(j, activity1) model.indicator_constraints.add(**ic_dict) ic_dict["sense"] = "L" ic_dict["complemented"] = 1 # ind(nbStart + index) = 0 -> ... # starttime(k, activity2) - starttime(j, activity1) <= # duration(j, activity1) model.indicator_constraints.add(**ic_dict) index = index + 2 # Add Objective function # each job has a cost which contains jobEarlinessCost and # jobTardinessCost, and get the index of Earliness variables, # Tardiness variables and Endness variables indexOfEarlinessVar = list(range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=jobEarlinessCost) indexOfTardinessVar = list(range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=jobTardinessCost) # Add finished time variables indexOfEndnessVar = list(range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=[0.0] * nbJob) # Add constraints for each Job # indexOfEndnessVar[i] - starttime(i, nbResource) = # duration[i][nbResource] for i in range(nbJob): ind = [indexOfEndnessVar[i], starttime(i, nbResource - 1)] val = [1.0, -1.0] row = [[ind, val]] model.linear_constraints.add( lin_expr=row, senses="E", rhs=[duration[i][nbResource - 1]]) # Add constraints for each Job # jobDueDate[i] = \ # indexOfEndnessVar[i] + indexOfEarlinessVar[i] - # indexOfTardinessVar[i] for i in range(nbJob): ind = [indexOfEndnessVar[i], indexOfEarlinessVar[i], indexOfTardinessVar[i]] val = [1.0, 1.0, -1.0] row = [[ind, val]] model.linear_constraints.add( lin_expr=row, senses="E", rhs=[jobDueDate[i]]) model.parameters.emphasis.mip = 4 model.solve() model.write('etsp.sav') except CplexError as exc: print(exc) return # Display solution print("Solution status = ", model.solution.get_status()) print("Optimal Value = ", model.solution.get_objective_value())
def etsp(datafile): """Read in data file and solve the model. If no file name is given on the command line we use a default file name. The data we read is: activityOnAResource -- An array of arrays represents the resources required for each activity of a job duration -- An array of arrays represents the duration required for each activity of a job jobDueDate -- contains the due date for each job jobEarlinessCost -- contains the penalty for being too early for each job jobTardinessCost -- contains the penalty for being too late for each job """ (activityOnAResource, duration, jobDueDate, jobEarlinessCost, jobTardinessCost) = read_dat_file(datafile) nbJob = len(jobDueDate) nbResource = len(activityOnAResource[1]) def starttime(job, res): """Calculates start variable indices.""" return job * nbJob + res # Build model model = cplex.Cplex() model.objective.set_sense(model.objective.sense.minimize) # Add activity start time variables nbStart = nbJob * nbResource obj = [0.0] * nbStart lb = [0.0] * nbStart ub = [10000.0] * nbStart model.variables.add(obj, lb, ub) # State precedence constraints # starttime(i, j) - starttime(i, j-1) >= duration(i, j-1) for i in range(nbJob): for j in range(1, nbResource): ind = [starttime(i, j), starttime(i, j - 1)] val = [1.0, -1.0] row = [[ind, val]] model.linear_constraints.add( lin_expr=row, senses="G", rhs=[duration[i][j - 1]]) # Add indicator variables nIndicatorVars = nbResource * nbJob * (nbJob - 1) colname_ind = ["ind" + str(j + 1) for j in range(nIndicatorVars)] obj = [0.0] * nIndicatorVars lb = [0.0] * nIndicatorVars ub = [1.0] * nIndicatorVars types = ["B"] * nIndicatorVars model.variables.add(obj, lb, ub, types, colname_ind) # Add ind1 + ind2 >= 1 # ind3 + ind4 >= 1 # ind5 + ind6 >= 1 # ... # constraints j = nbStart for i in range(nIndicatorVars // 2): ind = [j, j + 1] val = [1.0, 1.0] row = [[ind, val]] model.linear_constraints.add(lin_expr=row, senses="G", rhs=[1]) j = j + 2 # Add indicator constraints # i1 = 1 <-> c1 # i2 = 1 <-> c2 index = 0 for i in range(nbResource): e = nbJob - 1 for j in range(e): activity1 = activityOnAResource[i][j] for k in range(j + 1, nbJob): activity2 = activityOnAResource[i][k] ic_dict = {} ic_dict["indvar"] = nbStart + index ic_dict["lin_expr"] = cplex.SparsePair( ind=[starttime(j, activity1), starttime(k, activity2)], val=[1.0, -1.0]) ic_dict["rhs"] = duration[k][activity2] / 1.0 ic_dict["sense"] = "G" ic_dict["complemented"] = 0 # ind(nbStart + index) = 1 -> ... # starttime(j, activity1) - starttime(k, activity2) >= # duration(k, activity2) model.indicator_constraints.add(**ic_dict) ic_dict["sense"] = "L" ic_dict["complemented"] = 1 # ind(nbStart + index) = 0 -> ... # starttime(j, activity1) - starttime(k, activity2) <= # duration(k, activity2) model.indicator_constraints.add(**ic_dict) ic_dict = {} ic_dict["indvar"] = nbStart + index + 1 ic_dict["lin_expr"] = cplex.SparsePair( ind=[starttime(k, activity2), starttime(j, activity1)], val=[1.0, -1.0]) ic_dict["rhs"] = duration[j][activity1] / 1.0 ic_dict["sense"] = "G" ic_dict["complemented"] = 0 # ind(nbStart + index) = 1 -> ... # starttime(k, activity2) - starttime(j, activity1) >= # duration(j, activity1) model.indicator_constraints.add(**ic_dict) ic_dict["sense"] = "L" ic_dict["complemented"] = 1 # ind(nbStart + index) = 0 -> ... # starttime(k, activity2) - starttime(j, activity1) <= # duration(j, activity1) model.indicator_constraints.add(**ic_dict) index = index + 2 # Add Objective function # each job has a cost which contains jobEarlinessCost and # jobTardinessCost, and get the index of Earliness variables, # Tardiness variables and Endness variables indexOfEarlinessVar = list(range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=jobEarlinessCost) indexOfTardinessVar = list(range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=jobTardinessCost) # Add finished time variables indexOfEndnessVar = list(range(model.variables.get_num(), model.variables.get_num() + nbJob)) model.variables.add(obj=[0.0] * nbJob) # Add constraints for each Job # indexOfEndnessVar[i] - starttime(i, nbResource) = # duration[i][nbResource] for i in range(nbJob): ind = [indexOfEndnessVar[i], starttime(i, nbResource - 1)] val = [1.0, -1.0] row = [[ind, val]] model.linear_constraints.add( lin_expr=row, senses="E", rhs=[duration[i][nbResource - 1]]) # Add constraints for each Job # jobDueDate[i] = \ # indexOfEndnessVar[i] + indexOfEarlinessVar[i] - # indexOfTardinessVar[i] for i in range(nbJob): ind = [indexOfEndnessVar[i], indexOfEarlinessVar[i], indexOfTardinessVar[i]] val = [1.0, 1.0, -1.0] row = [[ind, val]] model.linear_constraints.add( lin_expr=row, senses="E", rhs=[jobDueDate[i]]) model.parameters.emphasis.mip.set( model.parameters.emphasis.mip.values.hidden_feasibility) try: model.solve() except CplexSolverError as cse: # For the Community Edition, this model exceeds problem size # limits. The following demonstrates how to handle a specific # error code. if cse.args[2] == error_codes.CPXERR_RESTRICTED_VERSION: print("The current problem is too large for your version of " "CPLEX. Reduce the size of the problem.") return else: raise model.write('etsp.sav') # Display solution print("Solution status = ", model.solution.get_status()) print("Optimal Value = ", model.solution.get_objective_value())
def facility(datafile, bendersopt): """Solve capacitated facility location problem.""" # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # fixedcost -- a list/array of facility fixed cost # cost -- a matrix for the costs to serve each client by each # facility # capacity -- a list/array of facility capacity fixedcost, cost, capacity = read_dat_file(datafile) num_locations = len(fixedcost) num_clients = len(cost) # Create the modeler/solver. cpx = cplex.Cplex() # Create variables. We have variables # open_[j] if location j is open. # supply[i][j]] how much client i is supplied from location j open_ = list( cpx.variables.add(obj=fixedcost, lb=[0] * num_locations, ub=[1] * num_locations, types=["B"] * num_locations)) supply = [None] * num_clients for i in range(num_clients): # Objective: Minimize the sum of fixed costs for using a location # and the costs for serving a client from a specific # location. supply[i] = list( cpx.variables.add(obj=cost[i], lb=[0.0] * num_locations, ub=[1.0] * num_locations)) # Constraint: Each client i must be assigned to exactly one location: # sum(j in nbLocations) supply[i][j] == 1 for each i in nbClients for i in range(num_clients): cpx.linear_constraints.add(lin_expr=[ cplex.SparsePair(ind=supply[i], val=[1.0] * num_locations) ], senses=["E"], rhs=[1.0]) # Constraint: For each location j, the capacity of the location must # be respected: # sum(i in nbClients) supply[i][j] <= capacity[j] * open_[j] for j in range(num_locations): ind = [supply[i][j] for i in range(num_clients)] + [open_[j]] val = [1.0] * num_clients + [-capacity[j]] cpx.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=ind, val=val)], senses=["L"], rhs=[0.0]) # Setup Benders decomposition if required. if bendersopt == ANNO_BENDERS: # We specify the structure for doing a Benders decomposition by # telling CPLEX which variables are in the master problem using # annotations. By default variables are assigned value # CPX_BENDERS_MASTERVALUE+1 and thus go into the workers. # Variables open_[j] should go into the master and therefore # we assign them value CPX_BENDERS_MASTER_VALUE. mastervalue = cpx.long_annotations.benders_mastervalue idx = cpx.long_annotations.add( name=cpx.long_annotations.benders_annotation, defval=mastervalue + 1) objtype = cpx.long_annotations.object_type.variable cpx.long_annotations.set_values(idx, objtype, [(open_[x], mastervalue) for x in range(num_locations)]) print("Solving with explicit Benders decomposition.") elif bendersopt == AUTO_BENDERS: # Let CPLEX automatically decompose the problem. In the case of # a capacitated facility location problem the variables of the # master problem should be the integer variables. By setting the # Benders strategy parameter to Full, CPLEX will put all integer # variables into the master, all continuous varibles into a # subproblem, and further decompose that subproblem, if possible. cpx.parameters.benders.strategy.set( cpx.parameters.benders.strategy.values.full) print("Solving with automatic Benders decomposition.") elif bendersopt == NO_BENDERS: print("Solving without Benders decomposition.") else: raise ValueError("invalid bendersopt argument") # Solve and display solution cpx.solve() print("Solution status =", cpx.solution.get_status_string()) print("Optimal value:", cpx.solution.get_objective_value()) tol = cpx.parameters.mip.tolerances.integrality.get() values = cpx.solution.get_values() for j in [ x for x in range(num_locations) if values[open_[x]] >= 1.0 - tol ]: print("Facility {0} is open, it serves clients {1}".format( j, " ".join([ str(x) for x in range(num_clients) if values[supply[x][j]] >= 1.0 - tol ])))
for v in range(cut.variables.get_num()): print(" Cut" + str(v) + " = " + str(cut.solution.get_values(v))) if __name__ == "__main__": # Input data. If no file is given on the command line then use a # default file name. The data read is # width - the width of the the roll, # size - the sie of each strip, # amount - the demand for each strip. datafile = "../../../examples/data/cutstock.dat" if len(sys.argv) < 2: print("Default data file : " + datafile) else: datafile = sys.argv[1] width, size, amount = read_dat_file(datafile) # Setup cutting optimization (master) problem. # This is the problem to which columns will be added in the loop # below. cut = cplex.Cplex() cutcons = list(range(len(amount))) # constraint indices cutvars = list(range(len(size))) # variable indices cut.variables.add(obj = [1] * len(cutvars)) # Add constraints. They have empty left-hand side initially. The # left-hand side is filled in the next loop. cut.linear_constraints.add(lin_expr = [SparsePair()] * len(cutcons), senses = ["G"] * len(cutcons), rhs = amount) for v in cutvars:
def admipex8(datadir, from_table, lazy, use_callback): """Solve a facility location problem with cut callbacks or lazy constraints. """ # Read in data file. The data we read is # fixedcost -- a list/array of facility fixed cost # cost -- a matrix for the costs to serve each client by each # facility # pylint: disable=unbalanced-tuple-unpacking fixedcost, cost, _ = read_dat_file(datadir + '/' + 'facility.dat') # Create the model locations = list(range(len(fixedcost))) clients = list(range(len(cost))) cpx = cplex.Cplex() # Create variables. # - used[j] If location j is used. # - supply[c][j] Amount shipped from location j to client c. This is a # number in [0,1] and specifies the percentage of c's # demand that is served from location i. # Note that we also create the objective function along with the variables # by specifying the objective coefficient for each variable in the 'obj' # argument. used = cpx.variables.add(obj=fixedcost, lb=[0] * len(locations), ub=[1] * len(locations), types=['B'] * len(locations), names=['used(%d)' % (j) for j in locations]) supply = [ cpx.variables.add(obj=[cost[c][j] for j in locations], lb=[0] * len(locations), ub=[1] * len(locations), types=['B'] * len(locations), names=['supply(%d)(%d)' % (c, j) for j in locations]) for c in clients ] # The supply for each client must sum to 1, i.e., the demand of each # client must be met. cpx.linear_constraints.add(lin_expr=[ cplex.SparsePair(supply[c], [1.0] * len(supply[c])) for c in clients ], senses=['E'] * len(clients), rhs=[1.0] * len(clients)) # Capacity constraint for each location. We just require that a single # location cannot serve all clients, that is, the capacity of each # location is nbClients-1. This makes the model a little harder to # solve and allows us to separate more cuts. if not lazy: cpx.linear_constraints.add(lin_expr=[ cplex.SparsePair([supply[c][j] for c in clients] + [used[j]], [1.0] * len(clients) + [-(len(clients) - 1.0)]) for j in locations ], senses=['L'] * len(locations), rhs=[0] * len(locations)) # Tweak some CPLEX parameters so that CPLEX has a harder time to # solve the model and our cut separators can actually kick in. cpx.parameters.mip.strategy.heuristicfreq.set(-1) cpx.parameters.mip.cuts.mircut.set(-1) cpx.parameters.mip.cuts.implied.set(-1) cpx.parameters.mip.cuts.gomory.set(-1) cpx.parameters.mip.cuts.flowcovers.set(-1) cpx.parameters.mip.cuts.pathcut.set(-1) cpx.parameters.mip.cuts.liftproj.set(-1) cpx.parameters.mip.cuts.zerohalfcut.set(-1) cpx.parameters.mip.cuts.cliques.set(-1) cpx.parameters.mip.cuts.covers.set(-1) # Setup the callback. # We instantiate the callback object and attach the necessary data # to it. # We also setup the contexmask parameter to indicate when the callback # should be called. facilitycb = FacilityCallback(clients, locations, used, supply) contextmask = 0 if use_callback: contextmask |= cplex.callbacks.Context.id.relaxation if from_table: # Generate all disaggregated constraints and put them into a # table that is scanned by the callback. facilitycb.cutlhs = [ cplex.SparsePair([supply[c][j], used[j]], [1.0, -1.0]) for j in locations for c in clients ] facilitycb.cutrhs = [0] * len(locations) * len(clients) if lazy: contextmask |= cplex.callbacks.Context.id.candidate # Callback is setup attach it to the model if contextmask: cpx.set_callback(facilitycb, contextmask) cpx.write('model.lp') cpx.solve() print('Solution status: %d' % cpx.solution.get_status()) print('Nodes processed: %d' % cpx.solution.progress.get_num_nodes_processed()) print('Active user cuts/lazy constraints: %d' % cpx.solution.MIP.get_num_cuts(cpx.solution.MIP.cut_type.user)) tol = cpx.parameters.mip.tolerances.integrality.get() print('Optimal value: %f' % cpx.solution.get_objective_value()) values = cpx.solution.get_values() for j in [x for x in locations if values[used[x]] >= 1 - tol]: print('Facility %d is used, it serves clients %s' % (j, ', '.join( [str(x) for x in clients if values[supply[x][j]] >= 1 - tol])))
datafile = sys.argv[1] else: prompt = """Enter the path to a data file: The path must be entered as a string; e.g. "../../../examples/data/etsp.dat". Enter "" to use the default file.\n""" user_file = input(prompt) print("hello" + user_file) if user_file != "": datafile = user_file else: datafile = defaultfile activityOnAResource, \ duration, \ jobDueDate, \ jobEarlinessCost, \ jobTardinessCost = \ read_dat_file(datafile) nbJob = len(jobDueDate) nbResource = len(activityOnAResource[1]) def starttime(job, res): return job * nbJob + res etsp(datafile)
def admipex5(args): # Set default arguments and parse command line datadir = '../../../examples/data' from_table = False lazy = False use_callback = True for arg in args[1:]: if arg.startswith('-data='): datadir = arg[6:] elif arg == '-table': from_table = True elif arg == '-lazy': lazy = True elif arg == '-no-cuts': use_callback = False else: print('Unknown argument %s' % arg) usage(args[0]) # Read in data file. If no file name is given on the command line # we use a default file name. The data we read is # fixedcost -- a list/array of facility fixed cost # cost -- a matrix for the costs to serve each client by each # facility fixedcost, cost, _ = read_dat_file(datadir + '/' + 'facility.dat') # Create the model locations = list(range(len(fixedcost))) clients = list(range(len(cost))) cpx = cplex.Cplex() # Create variables. # - used[j] If location j is used. # - supply[c][j] Amount shipped from location j to client c. This is a # number in [0,1] and specifies the percentage of c's # demand that is served from location i. # Note that we also create the objective function along with the variables # by specifying the objective coefficient for each variable in the 'obj' # argument. used = cpx.variables.add(obj=fixedcost, lb=[0] * len(locations), ub=[1] * len(locations), types=['B'] * len(locations), names=['used(%d)' % (j) for j in locations]) supply = [ cpx.variables.add(obj=[cost[c][j] for j in locations], lb=[0] * len(locations), ub=[1] * len(locations), types=['B'] * len(locations), names=['supply(%d)(%d)' % (c, j) for j in locations]) for c in clients ] # The supply for each client must sum to 1, i.e., the demand of each # client must be met. cpx.linear_constraints.add(lin_expr=[ cplex.SparsePair(supply[c], [1.0] * len(supply[c])) for c in clients ], senses=['E'] * len(clients), rhs=[1.0] * len(clients)) # Capacity constraint for each location. We just require that a single # location cannot serve all clients, that is, the capacity of each # location is nbClients-1. This makes the model a little harder to # solve and allows us to separate more cuts. if not lazy: cpx.linear_constraints.add(lin_expr=[ cplex.SparsePair([supply[c][j] for c in clients] + [used[j]], [1.0] * len(clients) + [-(len(clients) - 1.0)]) for j in locations ], senses=['L'] * len(locations), rhs=[0] * len(locations)) # Tweak some CPLEX parameters so that CPLEX has a harder time to # solve the model and our cut separators can actually kick in. cpx.parameters.threads.set(1) cpx.parameters.mip.strategy.heuristicfreq.set(-1) cpx.parameters.mip.cuts.mircut.set(-1) cpx.parameters.mip.cuts.implied.set(-1) cpx.parameters.mip.cuts.gomory.set(-1) cpx.parameters.mip.cuts.flowcovers.set(-1) cpx.parameters.mip.cuts.pathcut.set(-1) cpx.parameters.mip.cuts.liftproj.set(-1) cpx.parameters.mip.cuts.zerohalfcut.set(-1) cpx.parameters.mip.cuts.cliques.set(-1) cpx.parameters.mip.cuts.covers.set(-1) if use_callback: if from_table: # Generate all disaggregated constraints and put them into a # table that is scanned by the callback. usercb = cpx.register_callback(CutsFromTable) usercb.cutlhs = [ cplex.SparsePair([supply[c][j], used[j]], [1.0, -1.0]) for j in locations for c in clients ] usercb.cutrhs = [0] * len(locations) * len(clients) else: usercb = cpx.register_callback(Disaggregated) usercb.clients = clients usercb.locations = locations usercb.used = used usercb.supply = supply if lazy: lazycb = cpx.register_callback(LazyCallback) lazycb.clients = clients lazycb.locations = locations lazycb.used = used lazycb.supply = supply cpx.write('model.lp') cpx.solve() print('Solution status: %d' % cpx.solution.get_status()) print('Nodes processed: %d' % cpx.solution.progress.get_num_nodes_processed()) print('Active user cuts/lazy constraints: %d' % cpx.solution.MIP.get_num_cuts(cpx.solution.MIP.cut_type.user)) tol = cpx.parameters.mip.tolerances.integrality.get() print('Optimal value: %f' % cpx.solution.get_objective_value()) values = cpx.solution.get_values() for j in [x for x in locations if values[used[x]] >= 1 - tol]: print('Facility %d is used, it serves clients %s' % (j, ', '.join( [str(x) for x in clients if values[supply[x][j]] >= 1 - tol])))