def diet(F,N,a,b,c,d): """diet -- model for the modern diet problem Parameters: F - set of foods N - set of nutrients a[i] - minimum intake of nutrient i b[i] - maximum intake of nutrient i c[j] - cost of food j d[j][i] - amount of nutrient i in food j Returns a model, ready to be solved. """ model = Model("modern diet") # Create variables x,y,z = {},{},{} for j in F: x[j] = model.addVar(vtype="I", name="x(%s)" % j) for i in N: z[i] = model.addVar(lb=a[i], ub=b[i], vtype="C", name="z(%s)" % i) # Constraints: for i in N: model.addCons(quicksum(d[j][i]*x[j] for j in F) == z[i], name="Nutr(%s)" % i) model.setObjective(quicksum(c[j]*x[j] for j in F), "minimize") model.data = x,y,z return model
def vrp(V, c, m, q, Q): """solve_vrp -- solve the vehicle routing problem. - start with assignment model (depot has a special status) - add cuts until all components of the graph are connected Parameters: - V: set/list of nodes in the graph - c[i,j]: cost for traversing edge (i,j) - m: number of vehicles available - q[i]: demand for customer i - Q: vehicle capacity Returns the optimum objective value and the list of edges used. """ model = Model("vrp") vrp_conshdlr = VRPconshdlr() x = {} for i in V: for j in V: if j > i and i == V[0]: # depot x[i,j] = model.addVar(ub=2, vtype="I", name="x(%s,%s)"%(i,j)) elif j > i: x[i,j] = model.addVar(ub=1, vtype="I", name="x(%s,%s)"%(i,j)) model.addCons(quicksum(x[V[0],j] for j in V[1:]) == 2*m, "DegreeDepot") for i in V[1:]: model.addCons(quicksum(x[j,i] for j in V if j < i) + quicksum(x[i,j] for j in V if j > i) == 2, "Degree(%s)"%i) model.setObjective(quicksum(c[i,j]*x[i,j] for i in V for j in V if j>i), "minimize") model.data = x return model, vrp_conshdlr
def kmedian(I,J,c,k): """kmedian -- minimize total cost of servicing customers from k facilities Parameters: - I: set of customers - J: set of potential facilities - c[i,j]: cost of servicing customer i from facility j - k: number of facilities to be used Returns a model, ready to be solved. """ model = Model("k-median") x,y = {},{} for j in J: y[j] = model.addVar(vtype="B", name="y(%s)"%j) for i in I: x[i,j] = model.addVar(vtype="B", name="x(%s,%s)"%(i,j)) for i in I: model.addCons(quicksum(x[i,j] for j in J) == 1, "Assign(%s)"%i) for j in J: model.addCons(x[i,j] <= y[j], "Strong(%s,%s)"%(i,j)) model.addCons(quicksum(y[j] for j in J) == k, "Facilities") model.setObjective(quicksum(c[i,j]*x[i,j] for i in I for j in J), "minimize") model.data = x,y return model
def p_portfolio(I,sigma,r,alpha,beta): """p_portfolio -- modified markowitz model for portfolio optimization. Parameters: - I: set of items - sigma[i]: standard deviation of item i - r[i]: revenue of item i - alpha: acceptance threshold - beta: desired confidence level Returns a model, ready to be solved. """ model = Model("p_portfolio") x = {} for i in I: x[i] = model.addVar(vtype="C", name="x(%s)"%i) # quantity of i to buy rho = model.addVar(vtype="C", name="rho") rhoaux = model.addVar(vtype="C", name="rhoaux") model.addCons(rho == quicksum(r[i]*x[i] for i in I)) model.addCons(quicksum(x[i] for i in I) == 1) model.addCons(rhoaux == (alpha - rho)*(1/phi_inv(beta))) #todo model.addCons(quicksum(sigma[i]**2 * x[i] * x[i] for i in I) <= rhoaux * rhoaux) model.setObjective(rho, "maximize") model.data = x return model
def mult_selection(model,a,b): """mult_selection -- add piecewise relation with multiple selection formulation Parameters: - model: a model where to include the piecewise linear relation - a[k]: x-coordinate of the k-th point in the piecewise linear relation - b[k]: y-coordinate of the k-th point in the piecewise linear relation Returns the model with the piecewise linear relation on added variables X, Y, and z. """ K = len(a)-1 w,z = {},{} for k in range(K): w[k] = model.addVar(lb=-model.infinity()) # do not name variables for avoiding clash z[k] = model.addVar(vtype="B") X = model.addVar(lb=a[0], ub=a[K], vtype="C") Y = model.addVar(lb=-model.infinity()) for k in range(K): model.addCons(w[k] >= a[k]*z[k]) model.addCons(w[k] <= a[k+1]*z[k]) model.addCons(quicksum(z[k] for k in range(K)) == 1) model.addCons(X == quicksum(w[k] for k in range(K))) c = [float(b[k+1]-b[k])/(a[k+1]-a[k]) for k in range(K)] d = [b[k]-c[k]*a[k] for k in range(K)] model.addCons(Y == quicksum(d[k]*z[k] + c[k]*w[k] for k in range(K))) return X,Y,z
def transp(I,J,c,d,M): """transp -- model for solving the transportation problem Parameters: I - set of customers J - set of facilities c[i,j] - unit transportation cost on arc (i,j) d[i] - demand at node i M[j] - capacity Returns a model, ready to be solved. """ model = Model("transportation") # Create variables x = {} for i in I: for j in J: x[i,j] = model.addVar(vtype="C", name="x(%s,%s)" % (i, j)) # Demand constraints for i in I: model.addCons(quicksum(x[i,j] for j in J if (i,j) in x) == d[i], name="Demand(%s)" % i) # Capacity constraints for j in J: model.addCons(quicksum(x[i,j] for i in I if (i,j) in x) <= M[j], name="Capacity(%s)" % j) # Objective model.setObjective(quicksum(c[i,j]*x[i,j] for (i,j) in x), "minimize") model.optimize() model.data = x return model
def prodmix(I,K,a,p,epsilon,LB): """prodmix: robust production planning using soco Parameters: I - set of materials K - set of components a[i][k] - coef. matrix p[i] - price of material i LB[k] - amount needed for k Returns a model, ready to be solved. """ model = Model("robust product mix") x,rhs = {},{} for i in I: x[i] = model.addVar(vtype="C", name="x(%s)"%i) for k in K: rhs[k] = model.addVar(vtype="C", name="rhs(%s)"%k) model.addCons(quicksum(x[i] for i in I) == 1) for k in K: model.addCons(rhs[k] == -LB[k]+ quicksum(a[i,k]*x[i] for i in I) ) model.addCons(quicksum(epsilon*epsilon*x[i]*x[i] for i in I) <= rhs[k]*rhs[k]) model.setObjective(quicksum(p[i]*x[i] for i in I), "minimize") model.data = x,rhs return model
def markowitz(I,sigma,r,alpha): """markowitz -- simple markowitz model for portfolio optimization. Parameters: - I: set of items - sigma[i]: standard deviation of item i - r[i]: revenue of item i - alpha: acceptance threshold Returns a model, ready to be solved. """ model = Model("markowitz") x = {} for i in I: x[i] = model.addVar(vtype="C", name="x(%s)"%i) # quantity of i to buy model.addCons(quicksum(r[i]*x[i] for i in I) >= alpha) model.addCons(quicksum(x[i] for i in I) == 1) # set nonlinear objective: SCIP only allow for linear objectives hence the following obj = model.addVar(vtype="C", name="objective", lb = None, ub = None) # auxiliary variable to represent objective model.addCons(quicksum(sigma[i]**2 * x[i] * x[i] for i in I) <= obj) model.setObjective(obj, "minimize") model.data = x return model
def maxflow(V,M,source,sink): """maxflow: maximize flow from source to sink, taking into account arc capacities M Parameters: - V: set of vertices - M[i,j]: dictionary or capacity for arcs (i,j) - source: flow origin - sink: flow target Returns a model, ready to be solved. """ # create max-flow underlying model, on which to find cuts model = Model("maxflow") f = {} # flow variable for (i,j) in M: f[i,j] = model.addVar(lb=-M[i,j], ub=M[i,j], name="flow(%s,%s)"%(i,j)) cons = {} for i in V: if i != source and i != sink: cons[i] = model.addCons( quicksum(f[i,j] for j in V if i<j and (i,j) in M) - \ quicksum(f[j,i] for j in V if i>j and (j,i) in M) == 0, "FlowCons(%s)"%i) model.setObjective(quicksum(f[i,j] for (i,j) in M if i==source), "maximize") # model.write("tmp.lp") model.data = f,cons return model
def scheduling_time_index(J,p,r,w): """ scheduling_time_index: model for the one machine total weighted tardiness problem Model for the one machine total weighted tardiness problem using the time index formulation Parameters: - J: set of jobs - p[j]: processing time of job j - r[j]: earliest start time of job j - w[j]: weighted of job j; the objective is the sum of the weighted completion time Returns a model, ready to be solved. """ model = Model("scheduling: time index") T = max(r.values()) + sum(p.values()) X = {} # X[j,t]=1 if job j starts processing at time t, 0 otherwise for j in J: for t in range(r[j], T-p[j]+2): X[j,t] = model.addVar(vtype="B", name="x(%s,%s)"%(j,t)) for j in J: model.addCons(quicksum(X[j,t] for t in range(1,T+1) if (j,t) in X) == 1, "JobExecution(%s)"%(j)) for t in range(1,T+1): ind = [(j,t2) for j in J for t2 in range(t-p[j]+1,t+1) if (j,t2) in X] if ind != []: model.addCons(quicksum(X[j,t2] for (j,t2) in ind) <= 1, "MachineUB(%s)"%t) model.setObjective(quicksum((w[j] * (t - 1 + p[j])) * X[j,t] for (j,t) in X), "minimize") model.data = X return model
def convex_comb_agg(model,a,b): """convex_comb_agg -- add piecewise relation convex combination formulation -- non-disaggregated. Parameters: - model: a model where to include the piecewise linear relation - a[k]: x-coordinate of the k-th point in the piecewise linear relation - b[k]: y-coordinate of the k-th point in the piecewise linear relation Returns the model with the piecewise linear relation on added variables X, Y, and z. """ K = len(a)-1 w,z = {},{} for k in range(K+1): w[k] = model.addVar(lb=0, ub=1, vtype="C") for k in range(K): z[k] = model.addVar(vtype="B") X = model.addVar(lb=a[0], ub=a[K], vtype="C") Y = model.addVar(lb=-model.infinity(), vtype="C") model.addCons(X == quicksum(a[k]*w[k] for k in range(K+1))) model.addCons(Y == quicksum(b[k]*w[k] for k in range(K+1))) model.addCons(w[0] <= z[0]) model.addCons(w[K] <= z[K-1]) for k in range(1,K): model.addCons(w[k] <= z[k-1]+z[k]) model.addCons(quicksum(w[k] for k in range(K+1)) == 1) model.addCons(quicksum(z[k] for k in range(K)) == 1) return X,Y,z
def tsp(V,c): """tsp -- model for solving the traveling salesman problem with callbacks - start with assignment model - add cuts until there are no sub-cycles Parameters: - V: set/list of nodes in the graph - c[i,j]: cost for traversing edge (i,j) Returns the optimum objective value and the list of edges used. """ model = Model("TSP_lazy") conshdlr = TSPconshdlr() x = {} for i in V: for j in V: if j > i: x[i,j] = model.addVar(vtype = "B",name = "x(%s,%s)" % (i,j)) for i in V: model.addCons(quicksum(x[j, i] for j in V if j < i) + quicksum(x[i, j] for j in V if j > i) == 2, "Degree(%s)" % i) model.setObjective(quicksum(c[i, j] * x[i, j] for i in V for j in V if j > i), "minimize") model.data = x return model, conshdlr
def gcp_fixed_k(V,E,K): """gcp_fixed_k -- model for minimizing number of bad edges in coloring a graph Parameters: - V: set/list of nodes in the graph - E: set/list of edges in the graph - K: number of colors to be used Returns a model, ready to be solved. """ model = Model("gcp - fixed k") x,z = {},{} for i in V: for k in range(K): x[i,k] = model.addVar(vtype="B", name="x(%s,%s)"%(i,k)) for (i,j) in E: z[i,j] = model.addVar(vtype="B", name="z(%s,%s)"%(i,j)) for i in V: model.addCons(quicksum(x[i,k] for k in range(K)) == 1, "AssignColor(%s)" % i) for (i,j) in E: for k in range(K): model.addCons(x[i,k] + x[j,k] <= 1 + z[i,j], "BadEdge(%s,%s,%s)"%(i,j,k)) model.setObjective(quicksum(z[i,j] for (i,j) in E), "minimize") model.data = x,z return model
def eoq_soco(I,F,h,d,w,W): """eoq_soco -- multi-item capacitated economic ordering quantity model using soco Parameters: - I: set of items - F[i]: ordering cost for item i - h[i]: holding cost for item i - d[i]: demand for item i - w[i]: unit weight for item i - W: capacity (limit on order quantity) Returns a model, ready to be solved. """ model = Model("EOQ model using SOCO") T,c = {},{} for i in I: T[i] = model.addVar(vtype="C", name="T(%s)"%i) # cycle time for item i c[i] = model.addVar(vtype="C", name="c(%s)"%i) # total cost for item i for i in I: model.addCons(F[i] <= c[i]*T[i]) model.addCons(quicksum(w[i]*d[i]*T[i] for i in I) <= W) model.setObjective(quicksum(c[i] + h[i]*d[i]*T[i]*0.5 for i in I), "minimize") model.data = T,c return model
def eld_another(U,p_min,p_max,d,brk): """eld -- economic load dispatching in electricity generation Parameters: - U: set of generators (units) - p_min[u]: minimum operating power for unit u - p_max[u]: maximum operating power for unit u - d: demand - brk[u][k]: (x,y) coordinates of breakpoint k, k=0,...,K for unit u Returns a model, ready to be solved. """ model = Model("Economic load dispatching") # set objective based on piecewise linear approximation p,F,z = {},{},{} for u in U: abrk = [X for (X,Y) in brk[u]] bbrk = [Y for (X,Y) in brk[u]] p[u],F[u],z[u] = convex_comb_sos(model,abrk,bbrk) p[u].lb = p_min[u] p[u].ub = p_max[u] # demand satisfaction model.addCons(quicksum(p[u] for u in U) == d, "demand") # objective model.setObjective(quicksum(F[u] for u in U), "minimize") model.data = p return model
def gpp(V,E): """gpp -- model for the graph partitioning problem Parameters: - V: set/list of nodes in the graph - E: set/list of edges in the graph Returns a model, ready to be solved. """ model = Model("gpp") x = {} y = {} for i in V: x[i] = model.addVar(vtype="B", name="x(%s)"%i) for (i,j) in E: y[i,j] = model.addVar(vtype="B", name="y(%s,%s)"%(i,j)) model.addCons(quicksum(x[i] for i in V) == len(V)/2, "Partition") for (i,j) in E: model.addCons(x[i] - x[j] <= y[i,j], "Edge(%s,%s)"%(i,j)) model.addCons(x[j] - x[i] <= y[i,j], "Edge(%s,%s)"%(j,i)) model.setObjective(quicksum(y[i,j] for (i,j) in E), "minimize") model.data = x return model
def convex_comb_dis(model,a,b): """convex_comb_dis -- add piecewise relation with convex combination formulation Parameters: - model: a model where to include the piecewise linear relation - a[k]: x-coordinate of the k-th point in the piecewise linear relation - b[k]: y-coordinate of the k-th point in the piecewise linear relation Returns the model with the piecewise linear relation on added variables X, Y, and z. """ K = len(a)-1 wL,wR,z = {},{},{} for k in range(K): wL[k] = model.addVar(lb=0, ub=1, vtype="C") wR[k] = model.addVar(lb=0, ub=1, vtype="C") z[k] = model.addVar(vtype="B") X = model.addVar(lb=a[0], ub=a[K], vtype="C") Y = model.addVar(lb=-model.infinity(), vtype="C") model.addCons(X == quicksum(a[k]*wL[k] + a[k+1]*wR[k] for k in range(K))) model.addCons(Y == quicksum(b[k]*wL[k] + b[k+1]*wR[k] for k in range(K))) for k in range(K): model.addCons(wL[k] + wR[k] == z[k]) model.addCons(quicksum(z[k] for k in range(K)) == 1) return X,Y,z
def kcenter(I,J,c,k): """kcenter -- minimize the maximum travel cost from customers to k facilities. Parameters: - I: set of customers - J: set of potential facilities - c[i,j]: cost of servicing customer i from facility j - k: number of facilities to be used Returns a model, ready to be solved. """ model = Model("k-center") z = model.addVar(vtype="C", name="z") x,y = {},{} for j in J: y[j] = model.addVar(vtype="B", name="y(%s)"%j) for i in I: x[i,j] = model.addVar(vtype="B", name="x(%s,%s)"%(i,j)) for i in I: model.addCons(quicksum(x[i,j] for j in J) == 1, "Assign(%s)"%i) for j in J: model.addCons(x[i,j] <= y[j], "Strong(%s,%s)"%(i,j)) model.addCons(c[i,j]*x[i,j] <= z, "Max_x(%s,%s)"%(i,j)) model.addCons(quicksum(y[j] for j in J) == k, "Facilities") model.setObjective(z, "minimize") model.data = x,y return model
def mils_echelon(T,K,P,f,g,c,d,h,a,M,UB,phi): """ mils_echelon: echelon formulation for the multi-item, multi-stage lot-sizing problem Parameters: - T: number of periods - K: set of resources - P: set of items - f[t,p]: set-up costs (on period t, for product p) - g[t,p]: set-up times - c[t,p]: variable costs - d[t,p]: demand values - h[t,p]: holding costs - a[t,k,p]: amount of resource k for producing p in period t - M[t,k]: resource k upper bound on period t - UB[t,p]: upper bound of production time of product p in period t - phi[(i,j)]: units of i required to produce a unit of j (j parent of i) """ rho = calc_rho(phi) # rho[(i,j)]: units of i required to produce a unit of j (j ancestor of i) model = Model("multi-stage lotsizing -- echelon formulation") y,x,E,H = {},{},{},{} Ts = range(1,T+1) for p in P: for t in Ts: y[t,p] = model.addVar(vtype="B", name="y(%s,%s)"%(t,p)) x[t,p] = model.addVar(vtype="C", name="x(%s,%s)"%(t,p)) H[t,p] = h[t,p] - sum([h[t,q]*phi[q,p] for (q,p2) in phi if p2 == p]) E[t,p] = model.addVar(vtype="C", name="E(%s,%s)"%(t,p)) # echelon inventory E[0,p] = model.addVar(vtype="C", name="E(%s,%s)"%(0,p)) # echelon inventory for t in Ts: for p in P: # flow conservation constraints dsum = d[t,p] + sum([rho[p,q]*d[t,q] for (p2,q) in rho if p2 == p]) model.addCons(E[t-1,p] + x[t,p] == E[t,p] + dsum, "FlowCons(%s,%s)"%(t,p)) # capacity connection constraints model.addCons(x[t,p] <= UB[t,p]*y[t,p], "ConstrUB(%s,%s)"%(t,p)) # time capacity constraints for k in K: model.addCons(quicksum(a[t,k,p]*x[t,p] + g[t,p]*y[t,p] for p in P) <= M[t,k], "TimeUB(%s,%s)"%(t,k)) # calculate echelon quantities for p in P: model.addCons(E[0,p] == 0, "EchelonInit(%s)"%(p)) for t in Ts: model.addCons(E[t,p] >= quicksum(phi[p,q]*E[t,q] for (p2,q) in phi if p2 == p), "EchelonLB(%s,%s)"%(t,p)) model.setObjective(\ quicksum(f[t,p]*y[t,p] + c[t,p]*x[t,p] + H[t,p]*E[t,p] for t in Ts for p in P), \ "minimize") model.data = y,x,E return model
def mtz_strong(n,c): """mtz_strong: Miller-Tucker-Zemlin's model for the (asymmetric) traveling salesman problem (potential formulation, adding stronger constraints) Parameters: n - number of nodes c[i,j] - cost for traversing arc (i,j) Returns a model, ready to be solved. """ model = Model("atsp - mtz-strong") x,u = {},{} for i in range(1,n+1): u[i] = model.addVar(lb=0, ub=n-1, vtype="C", name="u(%s)"%i) for j in range(1,n+1): if i != j: x[i,j] = model.addVar(vtype="B", name="x(%s,%s)"%(i,j)) for i in range(1,n+1): model.addCons(quicksum(x[i,j] for j in range(1,n+1) if j != i) == 1, "Out(%s)"%i) model.addCons(quicksum(x[j,i] for j in range(1,n+1) if j != i) == 1, "In(%s)"%i) for i in range(1,n+1): for j in range(2,n+1): if i != j: model.addCons(u[i] - u[j] + (n-1)*x[i,j] + (n-3)*x[j,i] <= n-2, "LiftedMTZ(%s,%s)"%(i,j)) for i in range(2,n+1): model.addCons(-x[1,i] - u[i] + (n-3)*x[i,1] <= -2, name="LiftedLB(%s)"%i) model.addCons(-x[i,1] + u[i] + (n-3)*x[1,i] <= n-2, name="LiftedUB(%s)"%i) model.setObjective(quicksum(c[i,j]*x[i,j] for (i,j) in x), "minimize") model.data = x,u return model
def addcut(self, checkonly, sol): D,Ts = self.data y,x,I = self.model.data cutsadded = False for ell in Ts: lhs = 0 S,L = [],[] for t in range(1,ell+1): yt = self.model.getSolVal(sol, y[t]) xt = self.model.getSolVal(sol, x[t]) if D[t,ell]*yt < xt: S.append(t) lhs += D[t,ell]*yt else: L.append(t) lhs += xt if lhs < D[1,ell]: if checkonly: return True else: # add cutting plane constraint self.model.addCons(quicksum([x[t] for t in L]) + \ quicksum(D[t, ell] * y[t] for t in S) >= D[1, ell], removable = True) cutsadded = True return cutsadded
def gcp(V,E,K): """gcp -- model for minimizing the number of colors in a graph Parameters: - V: set/list of nodes in the graph - E: set/list of edges in the graph - K: upper bound on the number of colors Returns a model, ready to be solved. """ model = Model("gcp") x,y = {},{} for k in range(K): y[k] = model.addVar(vtype="B", name="y(%s)"%k) for i in V: x[i,k] = model.addVar(vtype="B", name="x(%s,%s)"%(i,k)) for i in V: model.addCons(quicksum(x[i,k] for k in range(K)) == 1, "AssignColor(%s)"%i) for (i,j) in E: for k in range(K): model.addCons(x[i,k] + x[j,k] <= y[k], "NotSameColor(%s,%s,%s)"%(i,j,k)) model.setObjective(quicksum(y[k] for k in range(K)), "minimize") model.data = x return model
def solve(self, integer=False): ''' By default we solve a linear version of the column generation. If integer is True than we solve the problem of finding the best routes to be used without column generation. ''' self.integer = integer if self.patterns is None: self.genInitialPatterns() # Creating master Model: master = Model("Master problem") # Creating pricer: if not integer: master.setPresolve(SCIP_PARAMSETTING.OFF) # Populating master model. # Binary variables z_r indicating whether # pattern r is used in the solution: z = {} for i, _ in enumerate(self.patterns): z[i] = master.addVar(vtype="B" if integer else "C", lb=0.0, ub=1.0, name="z_%d" % i) # Set objective: master.setObjective(quicksum(self.patCost(p)*z[i] for i, p in enumerate(self.patterns)), "minimize") clientCons = [None]*len(self.clientNodes) for i, c in enumerate(self.clientNodes): cons = master.addCons( quicksum(self.isClientVisited(c, p)*z[i] for i, p in enumerate(self.patterns)) == 1, "Consumer_%d" % c, separate=False, modifiable=True) clientCons[i] = cons if not integer: pricer = VRPpricer(z, clientCons, self.data, self.patterns, self.data.costs, self.isClientVisited, self.patCost, self.maxPatterns) master.includePricer(pricer, "VRP pricer", "Identifying new routes") self.pricer = pricer if integer: print("Finding the best patterns among:") for p in self.patterns: print(p) self.master = master # Save master model. master.optimize()
def mils_standard(T,K,P,f,g,c,d,h,a,M,UB,phi): """ mils_standard: standard formulation for the multi-item, multi-stage lot-sizing problem Parameters: - T: number of periods - K: set of resources - P: set of items - f[t,p]: set-up costs (on period t, for product p) - g[t,p]: set-up times - c[t,p]: variable costs - d[t,p]: demand values - h[t,p]: holding costs - a[t,k,p]: amount of resource k for producing p in period t - M[t,k]: resource k upper bound on period t - UB[t,p]: upper bound of production time of product p in period t - phi[(i,j)]: units of i required to produce a unit of j (j parent of i) """ model = Model("multi-stage lotsizing -- standard formulation") y,x,I = {},{},{} Ts = range(1,T+1) for p in P: for t in Ts: y[t,p] = model.addVar(vtype="B", name="y(%s,%s)"%(t,p)) x[t,p] = model.addVar(vtype="C",name="x(%s,%s)"%(t,p)) I[t,p] = model.addVar(vtype="C",name="I(%s,%s)"%(t,p)) I[0,p] = model.addVar(name="I(%s,%s)"%(0,p)) for t in Ts: for p in P: # flow conservation constraints model.addCons(I[t-1,p] + x[t,p] == \ quicksum(phi[p,q]*x[t,q] for (p2,q) in phi if p2 == p) \ + I[t,p] + d[t,p], "FlowCons(%s,%s)"%(t,p)) # capacity connection constraints model.addCons(x[t,p] <= UB[t,p]*y[t,p], "ConstrUB(%s,%s)"%(t,p)) # time capacity constraints for k in K: model.addCons(quicksum(a[t,k,p]*x[t,p] + g[t,p]*y[t,p] for p in P) <= M[t,k], "TimeUB(%s,%s)"%(t,k)) # initial inventory quantities for p in P: model.addCons(I[0,p] == 0, "InventInit(%s)"%(p)) model.setObjective(\ quicksum(f[t,p]*y[t,p] + c[t,p]*x[t,p] + h[t,p]*I[t,p] for t in Ts for p in P), \ "minimize") model.data = y,x,I return model
def flp_nonlinear_cc_dis_strong(I,J,d,M,f,c,K): """flp_nonlinear_bin -- use convex combination model, with binary variables Parameters: - I: set of customers - J: set of facilities - d[i]: demand for customer i - M[j]: capacity of facility j - f[j]: fixed cost for using a facility in point j - c[i,j]: unit cost of servicing demand point i from facility j - K: number of linear pieces for approximation of non-linear cost function Returns a model, ready to be solved. """ a,b = {},{} for j in J: U = M[j] L = 0 width = U/float(K) a[j] = [k*width for k in range(K+1)] b[j] = [f[j]*math.sqrt(value) for value in a[j]] model = Model("nonlinear flp -- piecewise linear version with convex combination") x = {} for j in J: for i in I: x[i,j] = model.addVar(vtype="C", name="x(%s,%s)"%(i,j)) # i's demand satisfied from j # total volume transported from plant j, corresponding (linearized) cost, selection variable: X,F,z = {},{},{} for j in J: # add constraints for linking piecewise linear part: X[j],F[j],z[j] = convex_comb_dis(model,a[j],b[j]) X[j].ub = M[j] for i in I: model.addCons( x[i,j] <= \ quicksum(min(d[i],a[j][k+1]) * z[j][k] for k in range(K)),\ "Strong(%s,%s)"%(i,j)) # constraints for customer's demand satisfaction for i in I: model.addCons(quicksum(x[i,j] for j in J) == d[i], "Demand(%s)"%i) for j in J: model.addCons(quicksum(x[i,j] for i in I) == X[j], "Capacity(%s)"%j) model.setObjective(quicksum(F[j] for j in J) +\ quicksum(c[i,j]*x[i,j] for j in J for i in I),\ "minimize") model.data = x,X,F return model
def test_string_poly(): PI = 3.141592653589793238462643 NWIRES = 11 DIAMETERS = [0.207, 0.225, 0.244, 0.263, 0.283, 0.307, 0.331, 0.362, 0.394, 0.4375, 0.500] PRELOAD = 300.0 MAXWORKLOAD = 1000.0 MAXDEFLECT = 6.0 DEFLECTPRELOAD = 1.25 MAXFREELEN = 14.0 MAXCOILDIAM = 3.0 MAXSHEARSTRESS = 189000.0 SHEARMOD = 11500000.0 m = Model() coil = m.addVar('coildiam') wire = m.addVar('wirediam') defl = m.addVar('deflection', lb=DEFLECTPRELOAD / (MAXWORKLOAD - PRELOAD), ub=MAXDEFLECT / PRELOAD) ncoils = m.addVar('ncoils', vtype='I') const1 = m.addVar('const1') const2 = m.addVar('const2') volume = m.addVar('volume') y = [m.addVar('wire%d' % i, vtype='B') for i in range(NWIRES)] obj = 1.0 * volume m.setObjective(obj, 'minimize') m.addCons(PI/2*(ncoils + 2)*coil*wire**2 - volume == 0, name='voldef') # defconst1: coil / wire - const1 == 0.0 m.addCons(coil - const1*wire == 0, name='defconst1') # defconst2: (4.0*const1 - 1.0) / (4.0*const1 - 4.0) + 0.615 / const1 - const2 == 0.0 d1 = (4.0*const1 - 4.0) d2 = const1 m.addCons((4.0*const1 - 1.0)*d2 + 0.615*d1 - const2*d1*d2 == 0, name='defconst2') m.addCons(8.0*MAXWORKLOAD/PI*const1*const2 - MAXSHEARSTRESS*wire**2 <= 0.0, name='shear') # defdefl: 8.0/shearmod * ncoils * const1^3 / wire - defl == 0.0 m.addCons(8.0/SHEARMOD*ncoils*const1**3 - defl*wire == 0.0, name="defdefl") m.addCons(MAXWORKLOAD*defl + 1.05*ncoils*wire + 2.1*wire <= MAXFREELEN, name='freel') m.addCons(coil + wire <= MAXCOILDIAM, name='coilwidth') m.addCons(quicksum(c*v for (c,v) in zip(DIAMETERS, y)) - wire == 0, name='defwire') m.addCons(quicksum(y) == 1, name='selectwire') m.optimize() assert abs(m.getPrimalbound() - 1.6924910128) < 1.0e-5
def addcut2(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = networkx.connected_components(G) if len(Components) == 1: return False for S in Components: T = set(V) - set(S) print("S:",S) print("T:",T) model.addCons(quicksum(x[i,j] for i in S for j in T if j>i) + quicksum(x[i,j] for i in T for j in S if j>i) >= 2) print("cut: %s <--> %s >= 2" % (S,T), [(i,j) for i in S for j in T if j>i]) return True
def weber(I,x,y,w): """weber: model for solving the single source weber problem using soco. Parameters: - I: set of customers - x[i]: x position of customer i - y[i]: y position of customer i - w[i]: weight of customer i Returns a model, ready to be solved. """ model = Model("weber") X,Y,z,xaux,yaux = {},{},{},{},{} X = model.addVar(lb=-model.infinity(), vtype="C", name="X") Y = model.addVar(lb=-model.infinity(), vtype="C", name="Y") for i in I: z[i] = model.addVar(vtype="C", name="z(%s)"%(i)) xaux[i] = model.addVar(lb=-model.infinity(), vtype="C", name="xaux(%s)"%(i)) yaux[i] = model.addVar(lb=-model.infinity(), vtype="C", name="yaux(%s)"%(i)) for i in I: model.addCons(xaux[i]*xaux[i] + yaux[i]*yaux[i] <= z[i]*z[i], "MinDist(%s)"%(i)) model.addCons(xaux[i] == (x[i]-X), "xAux(%s)"%(i)) model.addCons(yaux[i] == (y[i]-Y), "yAux(%s)"%(i)) model.setObjective(quicksum(w[i]*z[i] for i in I), "minimize") model.data = X,Y,z return model
def addCuts(self, checkonly): """add cuts if necessary and return whether model is feasible""" cutsadded = False edges = [] x = self.model.data for (i, j) in x: if self.model.getVal(x[i, j]) > .5: if i != V[0] and j != V[0]: edges.append((i, j)) G = networkx.Graph() G.add_edges_from(edges) Components = list(networkx.connected_components(G)) for S in Components: S_card = len(S) q_sum = sum(q[i] for i in S) NS = int(math.ceil(float(q_sum) / Q)) S_edges = [(i, j) for i in S for j in S if i < j and (i, j) in edges] if S_card >= 3 and (len(S_edges) >= S_card or NS > 1): cutsadded = True if checkonly: break else: self.model.addCons(quicksum(x[i, j] for i in S for j in S if j > i) <= S_card - NS) print("adding cut for", S_edges) return cutsadded
def addcut2(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = list(networkx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: T = set(V) - set(S) print("S:",S) print("T:",T) model.addCons(quicksum(x[i,j] for i in S for j in T if j>i) + quicksum(x[i,j] for i in T for j in S if j>i) >= 2) print("cut: %s >= 2" % "+".join([("x[%s,%s]" % (i,j)) for i in S for j in T if j>i])) return True
def flp(I,J,d,M,f,c): """flp -- model for the capacitated facility location problem Parameters: - I: set of customers - J: set of facilities - d[i]: demand for customer i - M[j]: capacity of facility j - f[j]: fixed cost for using a facility in point j - c[i,j]: unit cost of servicing demand point i from facility j Returns a model, ready to be solved. """ master = Model("flp-master") subprob = Model("flp-subprob") # creating the problem y = {} for j in J: y[j] = master.addVar(vtype="B", name="y(%s)"%j) master.setObjective( quicksum(f[j]*y[j] for j in J), "minimize") master.data = y # creating the subproblem x,y = {},{} for j in J: y[j] = subprob.addVar(vtype="B", name="y(%s)"%j) for i in I: x[i,j] = subprob.addVar(vtype="C", name="x(%s,%s)"%(i,j)) for i in I: subprob.addCons(quicksum(x[i,j] for j in J) == d[i], "Demand(%s)"%i) for j in M: subprob.addCons(quicksum(x[i,j] for i in I) <= M[j]*y[j], "Capacity(%s)"%i) for (i,j) in x: subprob.addCons(x[i,j] <= d[i]*y[j], "Strong(%s,%s)"%(i,j)) subprob.setObjective( quicksum(c[i,j]*x[i,j] for i in I for j in J), "minimize") subprob.data = x,y return master, subprob
def containsOutlier(mergedCluster, samples): dimension = mergedCluster.getDimension() ###################### modelo ############################################ model = Model() model.hideOutput() delta = model.addVar(vtype="CONTINUOUS", name="delta", lb=None) pVars = {} for (spl, f) in itertools.product(samples.getSamples(), range(dimension)): pVars[(spl, f)] = model.addVar(vtype="CONTINUOUS", name="p" + str(spl) + "%s" % (f), lb=None) qVars = {} for spl in samples.getSamples(): qVars[spl] = model.addVar(vtype="CONTINUOUS", name="q" + str(spl), lb=None) for spl in samples.getSamples(): model.addCons( (qVars[spl] + quicksum(pVars[(spl, j)] * spl.getFeature(j) for j in range(dimension))) <= -delta, "r%s" % (spl)) for spl in samples.getSamples(): for clstr_spl in mergedCluster.getSamples(): model.addCons((qVars[spl] + quicksum(pVars[(spl, j)] * clstr_spl.getFeature(j) for j in range(dimension))) >= delta, "r%s%s" % (spl, clstr_spl)) model.setObjective(delta, sense="maximize") ########################################################################## model.optimize() """print("valor objetivo: " + str(model.getObjVal())) for s in samples.getSamples(): print(str(qVars[spl]) + ": " + str(model.getVal(qVars[s]))) for (spl,f) in itertools.product(samples.getSamples(),range(dimension)): print(str(pVars[spl,f]) + ": " + str(model.getVal(pVars[spl,f])))""" return model.getObjVal() == 0
def add_constraints(self, _lambda, x1, x2, fx1_x2_list): triangle_active = {} # 1 self.model.addCons(quicksum(_lambda[i] for i in _lambda) == 1) simplices = self.mesh_2d.get_simplices_list() for i in range(len(simplices)): triangle_active[i] = self.model.addVar(name="y[%d]" % i, vtype="B") # 2 self.model.addCons( quicksum(triangle_active[i] for i in triangle_active) == 1) # 3 for j, triangle_point in enumerate(simplices): self.model.addCons( quicksum(k for k in triangle_point) >= triangle_active[j]) # 4 self.model.addCons( quicksum(_lambda[i] * x1[i] for i in range(len(x1))) <= self.x1_max) self.model.addCons( quicksum(_lambda[i] * x1[i] for i in range(len(x1))) >= self.x1_min) # 5 self.model.addCons( quicksum(_lambda[i] * x2[i] for i in range(len(x2))) <= self.x2_max) self.model.addCons( quicksum(_lambda[i] * x2[i] for i in range(len(x2))) >= self.x2_min)
def set_objective(self, weight_list, grade_dict=None): """Takes in a list of weights "weight_list" that is the weights on which schedule a student is assigned, e.g. [3,2,1] would award 3 points when a student gets their first choice schedule. grade_dict is an optional input, if given, it must have an entry for each different grade, i.e. 5 to 12 which maps to a weight. This weight puts a reward on giving an individual in that grade their first choice schedule (and weight-1 for their second choice) Sets the objective associated with self.m""" first = weight_list[0] second = weight_list[1] third = weight_list[2] # Deal with grades ## I will make another dictionary that maps seniors and 8th graders ## to 2 pts, while everyone else to 1 points if grade_dict == None: # make own dictionary basic weights ## I will make another dictionary that maps seniors and 8th graders ## to 2 pts, while everyone else to 1 points grade_dict = {} for s in self.GRADES: if self.GRADES[s] == 8 or self.GRADES[s] == 12: grade_dict[s] = 2 elif self.GRADES[s] == 7 or self.GRADES[s] == 11: grade_dict[s] = 1 else: grade_dict[s] = 0 else: # a dictionary is provided, verify that it has enough entries if len(grade_dict) == 8: for g in [-1, 5, 6, 7, 8, 9, 10, 11, 12]: if g not in grade_dict: raise ValueError( "Dictionary does not have correct values") print("User specified grade weight dictionary is valid") # Add objective to model self.m.setObjective( quicksum(first * self.X[s, 1] + second * self.X[s, 2] + third * self.X[s, 3] for s in self.STUDENTS) + quicksum(grade_dict[s] * self.X[s, 1] for s in self.STUDENTS), "maximize") print("Objective Set")
def lawlers_linearization(A, B): setup_start = time.time() n = A.shape[0] m = Model("Lawlers Linearization") x = {} y = {} rowsum_A = A.sum(axis=1) rowsum_B = B.sum(axis=1) a = rowsum_A.reshape(-1, 1) @ rowsum_B.reshape(1, -1) for i in range(n): for j in range(n): x[i, j] = m.addVar(f"x[{i},{j}]", "I", lb=0, ub=1) for i in range(n): for j in range(n): for k in range(n): for l in range(n): y[i, j, k, l] = m.addVar(f"y[{i}{j}{k}{l}]", "I", 0, 1) m.addCons(x[i, j] + x[k, l] >= 2 * y[i, j, k, l]) m.addCons( quicksum(y[i, j, k, l] for i in range(n) for j in range(n) for k in range(n) for l in range(n)) == (n * n)) for l in range(n): m.addCons(quicksum(x[k, l] for k in range(n)) == 1) m.addCons(quicksum(x[l, k] for k in range(n)) == 1) m.setObjective( quicksum(A[i, k] * B[j, l] * y[i, j, k, l] for i in range(n) for j in range(n) for k in range(n) for l in range(n))) setup_end = time.time() opt_start = time.time() m.optimize() opt_end = time.time() m.printSol() print("Objective val: {:.2f}".format(m.getObjVal())) print(f"Setup time | {setup_end - setup_start:.2f}s") print(f"Opt time | {opt_end - opt_start:.2f}s") pp_vars(m, y) if m.getStatus() == "optimal": print("Solved! Optimal value:", m.getObjVal())
def max_profits(self) -> None: """Maximises the profit taken over all non-terminal nodes.""" obj = [(self.node_profits[v], var) for v, var in self.non_terminal_vars.items()] self.model.setObjective(quicksum(profit * var for profit, var in obj), "maximize") if logging.root.level >= logging.DEBUG: obj_str = " + ".join(str(profit) + str(var) for profit, var in obj) module_logger.debug(f'Added objective: {obj_str}')
def addcut2(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = list(networkx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: T = set(V) - set(S) print("S:", S) print("T:", T) model.addCons( quicksum(x[i, j] for i in S for j in T if j > i) + quicksum(x[i, j] for i in T for j in S if j > i) >= 2) print("cut: %s >= 2" % "+".join([("x[%s,%s]" % (i, j)) for i in S for j in T if j > i])) return True
def add_proximity_constraints(self): """ Adds the proximity constraints """ # Setup proximity min and max dicts (temp untill we generate more granular data) # min_sub_dict = {} # max_sub_dict = {} # for subject in self.prox_dict.keys(): # min_sub_dict[subject] = np.ones(len(self.S))*0 # max_sub_dict[subject] = np.ones(len(self.S))*3 # for subject in self.prox_dict.keys(): # if subject != "Other": # for i in self.S: # # Only add the minimum constraint if meaningful # if min_sub_dict[subject][i] > 0: # self.m.addCons(quicksum(self.prox_dict[subject][j]*self.X[i,j] # for j in range(len(self.C))) >= min_sub_dict[subject][i]) # # Always add the max constraint # self.m.addCons(quicksum(self.prox_dict[subject][j]*self.X[i,j] # for j in self.C) <= max_sub_dict[subject][i]) for subject in self.num_courses.keys(): #if (subject not in ["Other", "J"] and (subject in self.num_courses.keys()) ): if subject in self.num_courses.keys(): print("\t\t", subject) #d = self.num_courses[subject] # easy reference to list for i in self.S: # Only add the minimum constraint if meaningful #if d[i] > 0: # make sure they don't request too many #pm = np.sum(self.prox_dict[subject]) # number possible # courses that satisfy req #lim = np.min([pm, d[i]]) # min(# they want, # possible) #if subject == "IB": #print("\t\t\tlimit:", lim) #self.m.addCons(quicksum(self.prox_dict[subject][j]*self.X[i,j] # for j in self.C) >= lim) # was == but >= might be faster #------------------------------------------------------ # Come Back to This #------------------------------------------------------ # This is pissy as prox not updated for new RR courses # I will comment this out and try somethign else as a TEMP fix try: self.m.addCons(quicksum(self.prox_dict[subject][j]*self.X[i,j] for j in self.C) <= 2) # was == but >= might be faster self.num_cons += 1 except: pass # mini = range(len(self.Cd)-3) # as there are 3 RR's # self.m.addCons(quicksum(self.prox_dict[subject][j]*self.X[i,j] # for j in mini) <= 2) # was == but >= might be faster print("\tProximity constraint added")
def weber_MS(I, J, x, y, w): """weber -- model for solving the weber problem using soco (multiple source version). Parameters: - I: set of customers - J: set of potential facilities - x[i]: x position of customer i - y[i]: y position of customer i - w[i]: weight of customer i Returns a model, ready to be solved. """ M = max([((x[i] - x[j])**2 + (y[i] - y[j])**2) for i in I for j in I]) model = Model("weber - multiple source") X, Y, v, u = {}, {}, {}, {} xaux, yaux, uaux = {}, {}, {} for j in J: X[j] = model.addVar(lb=-model.infinity(), vtype="C", name="X(%s)" % j) Y[j] = model.addVar(lb=-model.infinity(), vtype="C", name="Y(%s)" % j) for i in I: v[i, j] = model.addVar(vtype="C", name="v(%s,%s)" % (i, j)) u[i, j] = model.addVar(vtype="B", name="u(%s,%s)" % (i, j)) xaux[i, j] = model.addVar(lb=-model.infinity(), vtype="C", name="xaux(%s,%s)" % (i, j)) yaux[i, j] = model.addVar(lb=-model.infinity(), vtype="C", name="yaux(%s,%s)" % (i, j)) uaux[i, j] = model.addVar(vtype="C", name="uaux(%s,%s)" % (i, j)) for i in I: model.addCons(quicksum(u[i, j] for j in J) == 1, "Assign(%s)" % i) for j in J: model.addCons( xaux[i, j] * xaux[i, j] + yaux[i, j] * yaux[i, j] <= v[i, j] * v[i, j], "MinDist(%s,%s)" % (i, j)) model.addCons(xaux[i, j] == (x[i] - X[j]), "xAux(%s,%s)" % (i, j)) model.addCons(yaux[i, j] == (y[i] - Y[j]), "yAux(%s,%s)" % (i, j)) model.addCons(uaux[i, j] >= v[i, j] - M * (1 - u[i, j]), "uAux(%s,%s)" % (i, j)) model.setObjective(quicksum(w[i] * uaux[i, j] for i in I for j in J), "minimize") model.data = X, Y, v, u return model
def tsptw2(n, c, e, l): """tsptw2: model for the traveling salesman problem with time windows (based on Miller-Tucker-Zemlin's formulation, two-index potential) Parameters: - n: number of nodes - c[i,j]: cost for traversing arc (i,j) - e[i]: earliest date for visiting node i - l[i]: latest date for visiting node i Returns a model, ready to be solved. """ model = Model("tsptw2") x, u = {}, {} for i in range(1, n + 1): for j in range(1, n + 1): if i != j: x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j)) u[i, j] = model.addVar(vtype="C", name="u(%s,%s)" % (i, j)) for i in range(1, n + 1): model.addCons( quicksum(x[i, j] for j in range(1, n + 1) if j != i) == 1, "Out(%s)" % i) model.addCons( quicksum(x[j, i] for j in range(1, n + 1) if j != i) == 1, "In(%s)" % i) for j in range(2, n + 1): model.addCons( quicksum(u[i, j] + c[i, j] * x[i, j] for i in range(1, n + 1) if i != j) - quicksum(u[j, k] for k in range(1, n + 1) if k != j) <= 0, "Relate(%s)" % j) for i in range(1, n + 1): for j in range(1, n + 1): if i != j: model.addCons(e[i] * x[i, j] <= u[i, j], "LB(%s,%s)" % (i, j)) model.addCons(u[i, j] <= l[i] * x[i, j], "UB(%s,%s)" % (i, j)) model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize") model.data = x, u return model
def xin_yuan_linearization(A, B): setup_start = time.time() n = A.shape[0] L = _gen_glb_lmatrix(A, B) m = Model("Xin-Yuan Linearization") x = {} z = {} ceq = {} cleq = {} rowsum_A = A.sum(axis=1) rowsum_B = B.sum(axis=1) a = rowsum_A.reshape(-1, 1) @ rowsum_B.reshape(1, -1) for i in range(n): for j in range(n): x[i, j] = m.addVar(f"x[{i},{j}]", "I", lb=0, ub=1) z[i, j] = m.addVar(f"z[{i},{j}]", "C", lb=0) m.addCons(x[i, j] * x[i, j] - x[i, j] == 0) for l in range(n): m.addCons(quicksum(x[k, l] for k in range(n)) == 1) m.addCons(quicksum(x[l, k] for k in range(n)) == 1) for i in range(n): for j in range(n): ceq[i, j] = m.addCons(z[i, j] == x[i, j] * quicksum(A[i, k] * B[j, l] * x[k, l] for k in range(n) for l in range(n))) cleq[i, j] = m.addCons( z[i, j] >= quicksum(A[i, k] * B[j, l] * x[k, l] - a[i, j] * (1 - x[i, j]) for k in range(n) for l in range(n))) m.setObjective(quicksum(z[i, j] for i in range(n) for j in range(n))) setup_end = time.time() opt_start = time.time() m.optimize() opt_end = time.time() m.printSol() print("Objective val: {:.2f}".format(m.getObjVal())) print(f"Setup time | {setup_end - setup_start:.2f}s") print(f"Opt time | {opt_end - opt_start:.2f}s")
def eoq(I,F,h,d,w,W,a0,aK,K): """eoq -- multi-item capacitated economic ordering quantity model Parameters: - I: set of items - F[i]: ordering cost for item i - h[i]: holding cost for item i - d[i]: demand for item i - w[i]: unit weight for item i - W: capacity (limit on order quantity) - a0: lower bound on the cycle time (x axis) - aK: upper bound on the cycle time (x axis) - K: number of linear pieces to use in the approximation Returns a model, ready to be solved. """ # construct points for piecewise-linear relation, store in a,b a,b = {},{} delta = float(aK-a0)/K for i in I: for k in range(K): T = a0 + delta*k a[i,k] = T # abscissa: cycle time b[i,k] = F[i]/T + h[i]*d[i]*T/2. # ordinate: (convex) cost for this cycle time model = Model("multi-item, capacitated EOQ") x,c,w_ = {},{},{} for i in I: x[i] = model.addVar(vtype="C", name="x(%s)"%i) # cycle time for item i c[i] = model.addVar(vtype="C", name="c(%s)"%i) # total cost for item i for k in range(K): w_[i,k] = model.addVar(ub=1, vtype="C", name="w(%s,%s)"%(i,k)) #todo ?? for i in I: model.addCons(quicksum(w_[i,k] for k in range(K)) == 1) model.addCons(quicksum(a[i,k]*w_[i,k] for k in range(K)) == x[i]) model.addCons(quicksum(b[i,k]*w_[i,k] for k in range(K)) == c[i]) model.addCons(quicksum(w[i]*d[i]*x[i] for i in I) <= W) model.setObjective(quicksum(c[i] for i in I), "minimize") model.data = x,w return model
def eld_complete(U, p_min, p_max, d, brk): """eld -- economic load dispatching in electricity generation Parameters: - U: set of generators (units) - p_min[u]: minimum operating power for unit u - p_max[u]: maximum operating power for unit u - d: demand - brk[k]: (x,y) coordinates of breakpoint k, k=0,...,K Returns a model, ready to be solved. """ model = Model("Economic load dispatching") p, F = {}, {} for u in U: p[u] = model.addVar(lb=p_min[u], ub=p_max[u], name="p(%s)" % u) # capacity F[u] = model.addVar(lb=0, name="fuel(%s)" % u) # set fuel costs based on piecewise linear approximation for u in U: abrk = [X for (X, Y) in brk[u]] bbrk = [Y for (X, Y) in brk[u]] # convex combination part: K = len(brk[u]) - 1 z = {} for k in range(K + 1): z[k] = model.addVar( ub=1) # do not name variables for avoiding clash model.addCons(p[u] == quicksum(abrk[k] * z[k] for k in range(K + 1))) model.addCons(F[u] == quicksum(bbrk[k] * z[k] for k in range(K + 1))) model.addCons(quicksum(z[k] for k in range(K + 1)) == 1) model.addConsSOS2([z[k] for k in range(K + 1)]) # demand satisfaction model.addCons(quicksum(p[u] for u in U) == d, "demand") # objective model.setObjective(quicksum(F[u] for u in U), "minimize") model.data = p return model
def mctransp(I, J, K, c, d, M): model = Model("multi-commodity transportation") # inicjacja modelu x = {} for i, j, k in c: x[i, j, k] = model.addVar(vtype="C", name="x[%s,%s,%s]" % (i, j, k)) # dodawanie zmiennych for i in I: for k in K: model.addCons( quicksum(x[i, j, k] for j in J if (i, j, k) in x) == d[i, k], "Popyt[%s,%s]" % (i, k)) # ograniczenia na zapotrzebowanie for j in J: model.addCons( quicksum(x[i, j, k] for (i, j2, k) in x if j2 == j) <= M[j], "Pojemnosc[%s]" % j) # ograniczenia na pojemnosc model.setObjective(quicksum(c[i, j, k] * x[i, j, k] for i, j, k in x), sense='minimize') # funkcja celu model.data = x return model
def bpp(s,B): """bpp: Martello and Toth's model to solve the bin packing problem. Parameters: - s: list with item widths - B: bin capacity Returns a model, ready to be solved. """ n = len(s) U = len(FFD(s,B)) # upper bound of the number of bins model = Model("bpp") # setParam("MIPFocus",1) x,y = {},{} for i in range(n): for j in range(U): x[i,j] = model.addVar(vtype="B", name="x(%s,%s)"%(i,j)) for j in range(U): y[j] = model.addVar(vtype="B", name="y(%s)"%j) # assignment constraints for i in range(n): model.addCons(quicksum(x[i,j] for j in range(U)) == 1, "Assign(%s)"%i) # bin capacity constraints for j in range(U): model.addCons(quicksum(s[i]*x[i,j] for i in range(n)) <= B*y[j], "Capac(%s)"%j) # tighten assignment constraints for j in range(U): for i in range(n): model.addCons(x[i,j] <= y[j], "Strong(%s,%s)"%(i,j)) # tie breaking constraints for j in range(U-1): model.addCons(y[j] >= y[j+1],"TieBrk(%s)"%j) # SOS constraints for i in range(n): model.addConsSOS1([x[i,j] for j in range(U)]) model.setObjective(quicksum(y[j] for j in range(U)), "minimize") model.data = x,y return model
def convex_comb_dis_log(model, a, b): """convex_comb_dis_log -- add piecewise relation with a logarithmic number of binary variables using the convex combination formulation. Parameters: - model: a model where to include the piecewise linear relation - a[k]: x-coordinate of the k-th point in the piecewise linear relation - b[k]: y-coordinate of the k-th point in the piecewise linear relation Returns the model with the piecewise linear relation on added variables X, Y, and z. """ K = len(a) - 1 G = int(math.ceil((math.log(K) / math.log(2)))) # number of required bits N = 1 << G # number of required variables # print("K,G,N:",K,G,N wL, wR, z = {}, {}, {} for k in range(N): wL[k] = model.addVar(lb=0, ub=1, vtype="C") wR[k] = model.addVar(lb=0, ub=1, vtype="C") X = model.addVar(lb=a[0], ub=a[K], vtype="C") Y = model.addVar(lb=-model.infinity(), vtype="C") g = {} for j in range(G): g[j] = model.addVar(vtype="B") model.addCons(X == quicksum(a[k] * wL[k] + a[k + 1] * wR[k] for k in range(K))) model.addCons(Y == quicksum(b[k] * wL[k] + b[k + 1] * wR[k] for k in range(K))) model.addCons(quicksum(wL[k] + wR[k] for k in range(K)) == 1) # binary variables setup for j in range(G): ones = [] zeros = [] for k in range(K): if k & (1 << j): ones.append(k) else: zeros.append(k) model.addCons(quicksum(wL[k] + wR[k] for k in ones) <= g[j]) model.addCons(quicksum(wL[k] + wR[k] for k in zeros) <= 1 - g[j]) return X, Y, wL, wR
def rcs(J,P,R,T,p,c,a,RUB): """rcs -- model for the resource constrained scheduling problem Parameters: - J: set of jobs - P: set of precedence constraints between jobs - R: set of resources - T: number of periods - p[j]: processing time of job j - c[j,t]: cost incurred when job j starts processing on period t. - a[j,r,t]: resource r usage for job j on period t (after job starts) - RUB[r,t]: upper bound for resource r on period t Returns a model, ready to be solved. """ model = Model("resource constrained scheduling") s,x = {},{} # s - start time variable; x=1 if job j starts on period t for j in J: s[j] = model.addVar(vtype="C", name="s(%s)"%j) for t in range(1,T-p[j]+2): x[j,t] = model.addVar(vtype="B", name="x(%s,%s)"%(j,t)) for j in J: # job execution constraints model.addCons(quicksum(x[j,t] for t in range(1,T-p[j]+2)) == 1, "ConstrJob(%s,%s)"%(j,t)) # start time constraints model.addCons(quicksum((t-1)*x[j,t] for t in range(2,T-p[j]+2)) == s[j], "ConstrJob(%s,%s)"%(j,t)) # resource upper bound constraints for t in range(1,T-p[j]+2): for r in R: model.addCons( quicksum(a[j,r,t-t_]*x[j,t_] for j in J for t_ in range(max(t-p[j]+1,1),min(t+1,T-p[j]+2))) \ <= RUB[r,t], "ResourceUB(%s)"%t) # time (precedence) constraints, i.e., s[k]-s[j] >= p[j] for (j,k) in P: model.addCons(s[k] - s[j] >= p[j], "Precedence(%s,%s)"%(j,k)) model.setObjective(quicksum(c[j,t]*x[j,t] for (j,t) in x), "minimize") model.data = x,s return model
def isRedundant(self, region): dimension = self.getDimension() ############ model ############################## model = Model() model.hideOutput() xVars = {} for i in range(dimension): xVars[i] = model.addVar(vtype="CONTINUOUS", name="x[%s]" %(i),lb=None) for hiperplane in region.getHyperplanes().difference(set([self])): model.addCons(quicksum(hiperplane.getCoefficient(f)*xVars[f] for f in range(dimension)) <= hiperplane.getIntercept(),"r1%s" % (hiperplane)) model.addCons(quicksum(self.getCoefficient(f)*xVars[f] for f in range(dimension)) <= self.getIntercept() + 1.0,"prevent_unbound") model.setObjective(quicksum(self.getCoefficient(f)*xVars[f] for f in range(dimension)), sense="maximize") model.optimize() return model.getObjVal() <= self.getIntercept()
def linear_assignment(A): n, _ = A.shape x = {} m = Model("lap") model = m # create the variables for i in range(n): for j in range(n): x[i, j] = m.addVar(f"x[{i},{j}]", vtype="I", lb=0, ub=1) # create constraint: pairs of elements in a row or col mult == 0 for j in range(n): for k in range(j): model.addCons(x[i, j] * x[i, k] == 0, f"x[{i},:]") model.addCons(x[j, i] * x[k, i] == 0, f"x[:,{i}]") # x_ij^2 - x_ij == 0 for i in range(n): for j in range(n): model.addCons(x[i, j] * x[i, j] - x[i, j] == 0, f"x[{i},{j}]^2") # \sum_i x_ij^2 - 1 == 0 for j in range(n): model.addCons( quicksum(x[i, j] * x[i, j] for i in range(n)) - 1 == 0, f"col[{j}]") for i in range(n): model.addCons( quicksum(x[i, j] * x[i, j] for j in range(n)) - 1 == 0, f"row[{i}]") m.setObjective( quicksum(x[i, j] * A[i, j] for i in range(n) for j in range(n))) m.optimize() m.printSol() print("===========================") rows, cols = linear_sum_assignment(A) pmat = make_perm(rows, cols) sol = (A * pmat).sum() print(f"Linear sum assignment sol: {sol:.2f}")
def xorc_constraint(v=0, sense="maximize"): """ XOR (r as variable) custom constraint""" assert v in [0, 1], "v must be 0 or 1 instead of %s" % v.__repr__() model, x, y, z = _init() r = model.addVar("r", "B") n = model.addVar("n", "I") # auxiliary model.addCons(r + quicksum([x, y, z]) == 2 * n) model.addCons(x == v) model.setObjective(r, sense=sense) _optimize("Custom XOR (as variable)", model)
def max_stable_set(V, E): model = Model("mss model") x = {} for i in V: # vertex in stable set or not x[i] = model.addVar(vtype="B", name="x(%s)" % i) for (i, j) in E: model.addCons(x[i] + x[j] <= 1, "Edge(%s,%s)" % (i, j)) model.setObjective(quicksum(x[i] for i in V), "maximize") model.data = x return model
def basic(n, c): model = Model("atsp - mtz") x, u = {}, {} for i in range(1, n + 1): u[i] = model.addVar(lb=0, ub=n - 1, vtype="C", name="u(%s)" % i) # visit order for j in range(1, n + 1): if i != j: x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j)) for i in range(1, n + 1): model.addCons( quicksum(x[i, j] for j in range(1, n + 1) if j != i) == 1, "Out(%s)" % i) model.addCons( quicksum(x[j, i] for j in range(1, n + 1) if j != i) == 1, "In(%s)" % i) model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize") model.data = x, u return model
def mtz_strong(n, c): """mtz_strong: Miller-Tucker-Zemlin's model for the (asymmetric) traveling salesman problem (potential formulation, adding stronger constraints) Parameters: n - number of nodes c[i,j] - cost for traversing arc (i,j) Returns a model, ready to be solved. """ model = Model("atsp - mtz-strong") x, u = {}, {} for i in range(1, n + 1): u[i] = model.addVar(lb=0, ub=n - 1, vtype="C", name="u(%s)" % i) for j in range(1, n + 1): if i != j: x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j)) for i in range(1, n + 1): model.addCons( quicksum(x[i, j] for j in range(1, n + 1) if j != i) == 1, "Out(%s)" % i) model.addCons( quicksum(x[j, i] for j in range(1, n + 1) if j != i) == 1, "In(%s)" % i) for i in range(1, n + 1): for j in range(2, n + 1): if i != j: model.addCons( u[i] - u[j] + (n - 1) * x[i, j] + (n - 3) * x[j, i] <= n - 2, "LiftedMTZ(%s,%s)" % (i, j)) for i in range(2, n + 1): model.addCons(-x[1, i] - u[i] + (n - 3) * x[i, 1] <= -2, name="LiftedLB(%s)" % i) model.addCons(-x[i, 1] + u[i] + (n - 3) * x[1, i] <= n - 2, name="LiftedUB(%s)" % i) model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize") model.data = x, u return model
def solve(self, time_limit): ex_model = Model("extensive model") eventhdlr = IP_Eventhdlr() eventhdlr.IPSol = self.best_sol_list x = {} y = {} values = self._instance.get_values() for i in range(len(values)): x[i] = ex_model.addVar(vtype="B", name="x(%s)" % i) for s in range(self._n_w): for i in range(len(values)): y[i, s] = ex_model.addVar(vtype="B", name="y{},{}".format(i, s)) ex_model.addCons(x[i] >= y[i, s], "x,y{},sc:{}".format(i, s)) for s in range(self._n_w): w = self._instance.sample_scenarios() ex_model.addCons( quicksum(w[i] * (x[i] - y[i, s]) for i in range(len(values))) <= self._instance.get_C(), "respect capacity for scenario {}".format(s)) ex_model.setObjective( quicksum(x[i] * values[i] for i in range(len(values))) - (1 / self._n_w) * quicksum( quicksum(y[i, s] * (self._instance.get_penalty() + values[i]) for i in range(len(values))) for s in range(self._n_w)), "maximize") ex_model.data = x, y ex_model.hideOutput() ex_model.includeEventhdlr(eventhdlr, "IPBest_Sol", "retrieve best bound after each LP event") ex_model.setRealParam('limits/time', time_limit) ex_model.optimize() self.gap = ex_model.getGap() status = ex_model.getStatus() if status == "unbounded" or status == "infeasible": return status x, y = ex_model.data self.solution = np.zeros(len(values)) for i in range(len(values)): self.solution[i] = ex_model.getVal(x[i]) self.opt_obj = ex_model.getObjVal()
def addcut(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = networkx.connected_components(G) if len(Components) == 1: return False for S in Components: model.addCons( quicksum(x[i, j] for i in S for j in S if j > i) <= len(S) - 1) print("cut: len(%s) <= %s" % (S, len(S) - 1)) return True
def test_quicksum(): m = Model("quicksum") x = m.addVar("x") y = m.addVar("y") z = m.addVar("z") c = 2.3 q = quicksum([x, y, z, c]) s = sum([x, y, z, c]) assert (q.terms == s.terms)
def addcut(cut_edges): G = nx.Graph() G.add_edges_from(cut_edges) Components = list(nx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: model.addCons( quicksum(x[i, j] for i in S for j in S if j > i) <= len(S) - 1) return True
def model_definition(self, pipe: Connection): x1, x2, fx1_x2, _lambda = self.mesh_2d.get_credential_list() for i in range(len(_lambda)): _lambda[i] = self.model.addVar(lb=0, ub=1, name="L[%d]" % i) self.add_constraints(_lambda, x1, x2, fx1_x2) if self.incoming: self.model.addCons( quicksum(_lambda[i] * x1[i] for i in range(len(x1))) == pipe.p_e) self.model.addCons( quicksum(_lambda[i] * x2[i] for i in range(len(x2))) == pipe.q_e) else: self.model.addCons( quicksum(_lambda[i] * x1[i] for i in range(len(x1))) == pipe.p_b) self.model.addCons( quicksum(_lambda[i] * x1[i] for i in range(len(x1))) == pipe.q_b)
def flp(I, J, d, M, f, c): model = Model("flp") x, y = {}, {} for j in J: y[j] = model.addVar(vtype="B", name="y(%s)" % j) for i in I: x[i, j] = model.addVar(vtype="C", name="x(%s,%s)" % (i, j)) for i in I: model.addCons(quicksum(x[i, j] for j in J) == d[i], "Demand(%s)" % i) for j in M: model.addCons( quicksum(x[i, j] for i in I) <= M[j] * y[j], "Capacity(%s)" % i) for (i, j) in x: model.addCons(x[i, j] <= d[i] * y[j], "Strong(%s,%s)" % (i, j)) model.setObjective( quicksum(f[j] * y[j] for j in J) + quicksum(c[i, j] * x[i, j] for i in I for j in J), "minimize") model.data = x, y return model
def add_max_cons(MAX, m, X, STUDENTS, COURSES, schedule1, schedule2, schedule3): """Adds the max class size constraint an dreturns the model""" for c in range(len(COURSES)): m.addCons( quicksum(X[s, 1] * schedule1[s, c] + X[s, 2] * schedule2[s, c] + X[s, 3] * schedule3[s, c] for s in range(len(STUDENTS))) <= MAX[c]) return m