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 test_model(): # create solver instance s = Model() # add some variables x = s.addVar("x", vtype = 'C', obj = 1.0) y = s.addVar("y", vtype = 'C', obj = 2.0) assert x.getObj() == 1.0 assert y.getObj() == 2.0 s.setObjective(4.0 * y + 10.5, clear = False) assert x.getObj() == 1.0 assert y.getObj() == 4.0 assert s.getObjoffset() == 10.5 # add some constraint c = s.addCons(x + 2 * y >= 1.0) assert c.isLinear() s.chgLhs(c, 5.0) s.chgRhs(c, 6.0) assert s.getLhs(c) == 5.0 assert s.getRhs(c) == 6.0 # solve problem s.optimize() solution = s.getBestSol() # print solution assert (s.getVal(x) == s.getSolVal(solution, x)) assert (s.getVal(y) == s.getSolVal(solution, y)) assert round(s.getVal(x)) == 5.0 assert round(s.getVal(y)) == 0.0 assert s.getSlack(c, solution) == 0.0 assert s.getSlack(c, solution, 'lhs') == 0.0 assert s.getSlack(c, solution, 'rhs') == 1.0 assert s.getActivity(c, solution) == 5.0 s.writeProblem('model') s.writeProblem('model.lp') s.freeProb() s = Model() x = s.addVar("x", vtype = 'C', obj = 1.0) y = s.addVar("y", vtype = 'C', obj = 2.0) c = s.addCons(x + 2 * y <= 1.0) s.setMaximize() s.delCons(c) s.optimize() assert s.getStatus() == 'unbounded'
def mctransp(I,J,K,c,d,M): """mctransp -- model for solving the Multi-commodity Transportation Problem Parameters: - I: set of customers - J: set of facilities - K: set of commodities - c[i,j,k]: unit transportation cost on arc (i,j) for commodity k - d[i][k]: demand for commodity k at node i - M[j]: capacity Returns a model, ready to be solved. """ model = Model("multi-commodity transportation") # Create variables x = {} for (i,j,k) in c: x[i,j,k] = model.addVar(vtype="C", name="x(%s,%s,%s)" % (i,j,k), obj=c[i,j,k]) # todo arcs = tuplelist([(i,j,k) for (i,j,k) in x]) # Demand constraints for i in I: for k in K: model.addCons(sum(x[i,j,k] for (i,j,k) in arcs.select(i,"*",k)) == d[i,k], "Demand(%s,%s)" % (i,k)) # Capacity constraints for j in J: model.addConstr(sum(x[i,j,k] for (i,j,k) in arcs.select("*",j,"*")) <= M[j], "Capacity(%s)" % j) model.data = x return model
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 create_model(): # create solver instance s = Model() # add some variables x = s.addVar("x", obj = -1.0, vtype = "I", lb=-10) y = s.addVar("y", obj = 1.0, vtype = "I", lb=-1000) z = s.addVar("z", obj = 1.0, vtype = "I", lb=-1000) # add some constraint s.addCons(314*x + 867*y + 860*z == 363) s.addCons(87*x + 875*y - 695*z == 423) # create conshdlr and include it to SCIP conshdlr = MyConshdlr(shouldtrans=True, shouldcopy=False) s.includeConshdlr(conshdlr, "PyCons", "custom constraint handler implemented in python", sepapriority = 1, enfopriority = -1, chckpriority = 1, sepafreq = 10, propfreq = 50, eagerfreq = 1, maxprerounds = -1, delaysepa = False, delayprop = False, needscons = True, presoltiming = SCIP_PRESOLTIMING.FAST, proptiming = SCIP_PROPTIMING.BEFORELP) cons1 = s.createCons(conshdlr, "cons1name") ids.append(id(cons1)) cons2 = s.createCons(conshdlr, "cons2name") ids.append(id(cons2)) conshdlr.createData(cons1, 10, "cons1_anothername") conshdlr.createData(cons2, 12, "cons2_anothername") # add these constraints s.addPyCons(cons1) s.addPyCons(cons2) return s
def test_event(): # create solver instance s = Model() s.hideOutput() s.setPresolve(SCIP_PARAMSETTING.OFF) eventhdlr = MyEvent() s.includeEventhdlr(eventhdlr, "TestFirstLPevent", "python event handler to catch FIRSTLPEVENT") # add some variables x = s.addVar("x", obj=1.0) y = s.addVar("y", obj=2.0) # add some constraint s.addCons(x + 2*y >= 5) # solve problem s.optimize() # print solution assert round(s.getVal(x)) == 5.0 assert round(s.getVal(y)) == 0.0 del s assert 'eventinit' in calls assert 'eventexit' in calls assert 'eventexec' in calls assert len(calls) == 3
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 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 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 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 test_circle(): points =[ (2.802686, 1.398947), (4.719673, 4.792101), (1.407758, 7.769566), (2.253320, 2.373641), (8.583144, 9.769102), (3.022725, 5.470335), (5.791380, 1.214782), (8.304504, 8.196392), (9.812677, 5.284600), (9.445761, 9.541600)] m = Model() a = m.addVar('a', lb=None) b = m.addVar('b', ub=None) r = m.addVar('r') # minimize radius m.setObjective(r, 'minimize') for i,p in enumerate(points): # NOTE: SCIP will not identify this as SOC constraints! m.addCons( sqrt((a - p[0])**2 + (b - p[1])**2) <= r, name = 'point_%d'%i) m.optimize() bestsol = m.getBestSol() assert abs(m.getSolVal(bestsol, r) - 5.2543) < 1.0e-3 assert abs(m.getSolVal(bestsol, a) - 6.1242) < 1.0e-3 assert abs(m.getSolVal(bestsol, b) - 5.4702) < 1.0e-3
def sils(T,f,c,d,h): """sils -- LP lotsizing for the single item lot sizing problem Parameters: - T: number of periods - P: set of products - f[t]: set-up costs (on period t) - c[t]: variable costs - d[t]: demand values - h[t]: holding costs Returns a model, ready to be solved. """ model = Model("single item lotsizing") Ts = range(1,T+1) M = sum(d[t] for t in Ts) y,x,I = {},{},{} for t in Ts: y[t] = model.addVar(vtype="I", ub=1, name="y(%s)"%t) x[t] = model.addVar(vtype="C", ub=M, name="x(%s)"%t) I[t] = model.addVar(vtype="C", name="I(%s)"%t) I[0] = 0 for t in Ts: model.addCons(x[t] <= M*y[t], "ConstrUB(%s)"%t) model.addCons(I[t-1] + x[t] == I[t] + d[t], "FlowCons(%s)"%t) model.setObjective(\ quicksum(f[t]*y[t] + c[t]*x[t] + h[t]*I[t] for t in Ts),\ "minimize") model.data = y,x,I return model
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 mctransp(I,J,K,c,d,M): """mctransp -- model for solving the Multi-commodity Transportation Problem Parameters: - I: set of customers - J: set of facilities - K: set of commodities - c[i,j,k]: unit transportation cost on arc (i,j) for commodity k - d[i][k]: demand for commodity k at node i - M[j]: capacity Returns a model, ready to be solved. """ model = Model("multi-commodity transportation") # Create variables x = {} for (i,j,k) in c: x[i,j,k] = model.addVar(vtype="C", name="x(%s,%s,%s)" % (i,j,k)) # Demand constraints for i in I: for k in K: model.addCons(sum(x[i,j,k] for j in J if (i,j,k) in x) == d[i,k], "Demand(%s,%s)" % (i,k)) # Capacity constraints for j in J: model.addCons(sum(x[i,j,k] for (i,j2,k) in x if j2 == j) <= M[j], "Capacity(%s)" % j) # Objective model.setObjective(quicksum(c[i,j,k]*x[i,j,k] for (i,j,k) in x), "minimize") model.data = x return model
def test_lpi(): # create LP instance myLP = LP() myLP.addRow(entries = [(0,1),(1,2)] ,lhs = 5) lhs, rhs = myLP.getSides() assert lhs[0] == 5.0 assert rhs[0] == myLP.infinity() assert(myLP.ncols() == 2) myLP.chgObj(0, 1.0) myLP.chgObj(1, 2.0) solval = myLP.solve() # create solver instance s = Model() # add some variables x = s.addVar("x", obj=1.0) y = s.addVar("y", obj=2.0) # add some constraint s.addCons(x + 2*y >= 5) # solve problem s.optimize() # check solution assert round(s.getVal(x)) == 5.0 assert round(s.getVal(y)) == 0.0 assert round(s.getObjVal() == solval)
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 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 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 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 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 flp_nonlinear_sos(I,J,d,M,f,c,K): """flp_nonlinear_sos -- use model with SOS constraints 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 -- use model with SOS constraints") 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_sos(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] + z[j][k+1])\ # for k in range(len(a[j])-1)), # "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_knapsack(): # create solver instance s = Model("Knapsack") s.hideOutput() # setting the objective sense to maximise s.setMaximize() # item weights weights = [4, 2, 6, 3, 7, 5] # item costs costs = [7, 2, 5, 4, 3, 4] assert len(weights) == len(costs) # knapsack size knapsackSize = 15 # adding the knapsack variables knapsackVars = [] varNames = [] varBaseName = "Item" for i in range(len(weights)): varNames.append(varBaseName + "_" + str(i)) knapsackVars.append(s.addVar(varNames[i], vtype='I', obj=costs[i], ub=1.0)) # adding a linear constraint for the knapsack constraint coeffs = {knapsackVars[i]: weights[i] for i in range(len(weights))} s.addCons(coeffs, lhs=None, rhs=knapsackSize) # solve problem s.optimize() s.printStatistics() # retrieving the best solution solution = s.getBestSol() # print solution varSolutions = [] for i in range(len(weights)): solValue = round(s.getVal(knapsackVars[i], solution)) varSolutions.append(solValue) if solValue > 0: print (varNames[i], "Times Selected:", solValue) print ("\tIncluded Weight:", weights[i]*solValue, "\tItem Cost:", costs[i]*solValue) s.releaseVar(knapsackVars[i]) includedWeight = sum([weights[i]*varSolutions[i] for i in range(len(weights))]) assert includedWeight > 0 and includedWeight <= knapsackSize
def test_niceqcqp(): s = Model() x = s.addVar("x") y = s.addVar("y") s.addCons(x*x + y*y <= 2) s.setObjective(x + y, sense='maximize') s.optimize() assert round(s.getVal(x)) == 1.0 assert round(s.getVal(y)) == 1.0 s.free()
def test_largequadratic(): # inspired from performance issue on # http://stackoverflow.com/questions/38434300 m = Model("dense_quadratic") dim = 200 x = [m.addVar("x_%d" % i) for i in range(dim)] expr = quicksum((i+j+1)*x[i]*x[j] for i in range(dim) for j in range(dim)) cons = expr <= 1.0 # upper triangle, diagonal assert len(cons.expr.terms) == dim * (dim-1) / 2 + dim m.addCons(cons)
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 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 test_niceqp(): s = Model() x = s.addVar("x") y = s.addVar("y") s.addCons(x >= 2) s.addCons(x*x <= y) s.setObjective(y, sense='minimize') s.optimize() assert round(s.getVal(x)) == 2.0 assert round(s.getVal(y)) == 4.0 s.free()
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 staff(I,T,N,J,S,c,b): """ staff: staff scheduling Parameters: - I: set of members in the staff - T: number of periods in a cycle - N: number of working periods required for staff's elements in a cycle - J: set of shifts in each period (shift 0 == rest) - S: subset of shifts that must be kept at least consecutive days - c[i,t,j]: cost of a shift j of staff's element i on period t - b[t,j]: number of staff elements required in period t, shift j Returns a model, ready to be solved. """ Ts = range(1,T+1) model = Model("staff scheduling") x = {} for t in Ts: for j in J: for i in I: x[i,t,j] = model.addVar(vtype="B", name="x(%s,%s,%s)" % (i,t,j)) model.setObjective(quicksum(c[i,t,j]*x[i,t,j] for i in I for t in Ts for j in J if j != 0), "minimize") for t in Ts: for j in J: if j == 0: continue model.addCons(quicksum(x[i,t,j] for i in I) >= b[t,j], "Cover(%s,%s)" % (t,j)) for i in I: model.addCons(quicksum(x[i,t,j] for t in Ts for j in J if j != 0) == N, "Work(%s)"%i) for t in Ts: model.addCons(quicksum(x[i,t,j] for j in J) == 1, "Assign(%s,%s)" % (i,t)) for j in J: if j != 0: model.addCons(x[i,t,j] + quicksum(x[i,t,k] for k in J if k != j and k != 0) <= 1,\ "Require(%s,%s,%s)" % (i,t,j)) for t in range(2,T): for j in S: model.addCons(x[i,t-1,j] + x[i,t+1,j] >= x[i,t,j], "SameShift(%s,%s,%s)" % (i,t,j)) model.data = x return model
def solve_it(input_data): # Modify this code to run your optimization algorithm # parse the input lines = input_data.split('\n') nodeCount = int(lines[0]) points = [] for i in range(1, nodeCount + 1): line = lines[i] parts = line.split() points.append(Point(float(parts[0]), float(parts[1]))) cost_matrix = np.zeros((nodeCount, nodeCount), dtype="float32") for i in range(nodeCount): for j in range(i, nodeCount): cost_matrix[i, j] = length(points[i], points[j]) cost_matrix = pd.DataFrame(cost_matrix) cost_matrix = cost_matrix + cost_matrix.transpose() model = Model("tsp") model.hideOutput() xs = cost_matrix.applymap(lambda x: model.addVar(vtype="B")) us = pd.Series(range(nodeCount)).map(lambda x: model.addVar(vtype="I")) for index, row in xs.iterrows(): model.addCons(row.sum() == 1) for index, col in xs.iteritems(): model.addCons(col.sum() == 1) # (xs + xs.transpose()).applymap(lambda const: model.addCons(const <=1)) for i in range(nodeCount): for j in range(nodeCount): if i > j: model.addCons(xs[j][i] + xs[i][j] <= 1) if i == j: model.addCons(xs[i][j] == 0) if 0 < i and i != j: model.addCons( us[i] - us[j] + nodeCount * xs[i][j] <= nodeCount - 1) objective = (xs * cost_matrix).sum().sum() model.setObjective(objective) model.setMinimize() model.setRealParam("limits/time", 30) model.optimize() print({ "status": model.getStatus(), "obj": model.getObjVal(), "time": model.getTotalTime() }) result = xs.applymap(model.getVal) route = np.argmax(result.values, axis=1) start = 0 solution = [] for i in range(nodeCount): start = route[start] solution.append(start) # build a trivial solution # visit the nodes in the order they appear in the file # # calculate the length of the tour obj = total_length_by_order(points, solution) # prepare the solution in the specified output format output_data = '%.2f' % obj + ' ' + str(0) + '\n' output_data += ' '.join(map(str, solution)) return output_data
def mcf(n, c): """mcf: multi-commodity flow formulation for the (asymmetric) traveling salesman problem Parameters: - n: number of nodes - c[i,j]: cost for traversing arc (i,j) Returns a model, ready to be solved. """ model = Model("mcf") x, f = {}, {} 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)) if i != j and j != 1: for k in range(2, n + 1): if i != k: f[i, j, k] = model.addVar(ub=1, vtype="C", name="f(%s,%s,%s)" % (i, j, k)) 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 k in range(2, n + 1): model.addCons( quicksum(f[1, i, k] for i in range(2, n + 1) if (1, i, k) in f) == 1, "FlowOut(%s)" % k) model.addCons( quicksum(f[i, k, k] for i in range(1, n + 1) if (i, k, k) in f) == 1, "FlowIn(%s)" % k) for i in range(2, n + 1): if i != k: model.addCons(quicksum(f[j,i,k] for j in range(1,n+1) if (j,i,k) in f) == \ quicksum(f[i,j,k] for j in range(1,n+1) if (i,j,k) in f), "FlowCons(%s,%s)"%(i,k)) for (i, j, k) in f: model.addCons(f[i, j, k] <= x[i, j], "FlowUB(%s,%s,%s)" % (i, j, k)) model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize") model.data = x, f return model
def mils_fl(T,P,f,g,c,d,h,M): """ mils_fl: facility location formulation for the multi-item lot-sizing problem Requires more variables, but gives a better solution because LB is better than the standard formulation. It can be used as a heuristic method that is sometimes better than relax-and-fix. Parameters: - T: number of periods - P: set of products - 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 - M[t]: resource upper bound on period t Returns a model, ready to be solved. """ Ts = range(1,T+1) model = Model("multi-item lotsizing -- facility location formulation") y,X = {},{} for p in P: for t in Ts: y[t,p] = model.addVar(vtype="B", name="y(%s,%s)"%(t,p)) for s in range(1,t+1): X[s,t,p] = model.addVar(name="X(%s,%s,%s)"%(s,t,p)) for t in Ts: # capacity constraints model.addCons(quicksum(X[t,s,p] for s in range(t,T+1) for p in P) + \ quicksum(g[t,p]*y[t,p] for p in P) <= M[t], "Capacity(%s)"%(t)) for p in P: # demand satisfaction constraints model.addCons(quicksum(X[s,t,p] for s in range(1,t+1)) == d[t,p], "Demand(%s,%s)"%(t,p)) # connection constraints for s in range(1,t+1): model.addCons(X[s,t,p] <= d[t,p] * y[s,p], "Connect(%s,%s,%s)"%(s,t,p)) C = {} # variable costs plus holding costs for p in P: for s in Ts: sumC = 0 for t in range(s,T+1): C[s,t,p] = (c[s,p] + sumC) sumC += h[t,p] model.setObjective(quicksum(f[t,p]*y[t,p] for t in Ts for p in P) + \ quicksum(C[s,t,p]*X[s,t,p] for t in Ts for p in P for s in range(1,t+1)), "minimize") model.data = y,X model.write("tmp.lp") return model
class MipModel: """Models the connected subgraph problem via mixed integer programming.""" def __init__(self, prob_input: Input, hide_output: bool = True, *, binary_variables: bool = False) -> None: self.model = Model() if hide_output: self.model.hideOutput() self._prob_input = prob_input self._edge_vars = dict() self._node_vars = dict() self.__add_non_terminal_vars(binary_variables) self.__add_edge_vars(binary_variables) @property def graph_edges(self): return self._prob_input.edges @property def terminals(self): return self._prob_input.terminals @property def non_terminals(self): return self._prob_input.non_terminals @property def node_costs(self): return self._prob_input.costs @property def node_profits(self): return self._prob_input.profits @property def budget(self): return self._prob_input.budget @property def edge_vars(self): return self._edge_vars @property def non_terminal_vars(self): return self._node_vars @property def positive_non_terminal_vars(self): return { v: self.model.getVal(var) for v, var in self.non_terminal_vars.items() if self.model.getVal(var) > 0. } @property def positive_edge_vars(self): return { v: self.model.getVal(var) for v, var in self.edge_vars.items() if self.model.getVal(var) > 0. } def __add_edge_vars(self, binary: bool) -> None: """Creates variables for graph edges and adds them to the solver model.""" for edge in self.graph_edges: name = f'x_{edge}' self.edge_vars[edge] = self.model.addVar( vtype='B' if binary else 'C', lb=0, ub=1, name=name) module_logger.debug(f'Added {len(self.graph_edges)} edge variables.') def __add_non_terminal_vars(self, binary: bool) -> None: """Creates variables for non-terminal nodes and adds them to the solver model.""" for node in self.non_terminals: name = f'y_{node}' self.non_terminal_vars[node] = self.model.addVar( vtype='B' if binary else 'C', lb=0, ub=1, name=name) module_logger.debug( f'Added {len(self.non_terminal_vars)} node variables.') def add_cardinality_constraint(self) -> None: """Creates an equality constraint where the rhs corresponds to the sum over all edge variables and the lhs corresponds to the sum over all non-terminal node variables plus the number of terminals minus 1. In other words, x(E) = y(N) + |T| - 1. """ rhs_vars = (self.non_terminal_vars.get(n) for n in self.non_terminals) self.model.addCons(quicksum( self.edge_vars.values()) == quicksum(rhs_vars) + len(self.terminals) - 1, name='card_cons') if logging.root.level >= logging.DEBUG: lhs_str = " + ".join(str(e) for e in self.edge_vars.values()) rhs_str = " + ".join( str(i) for i in rhs_vars) + str(len(self.terminals) - 1) module_logger.debug( f'Added cardinality constraint: {lhs_str} == {rhs_str}') def add_budget_constraint(self) -> None: """Ensures that the weight taken over all selected nodes is less or equal than the budget. """ lhs = [(self.node_costs[v], var) for v, var in self.non_terminal_vars.items()] rhs = self.budget - quicksum(self.node_costs[t] for t in self.terminals) self.model.addCons(quicksum(weight * var for weight, var in lhs) <= rhs, name='weight_cons') if logging.root.level >= logging.DEBUG: lhs_str = " + ".join(str(weight) + str(var) for weight, var in lhs) module_logger.debug(f'Added budged constraint: {lhs_str} <= {rhs}') 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 test_model(): # create solver instance s = Model() # add some variables x = s.addVar("x", vtype = 'C', obj = 1.0) y = s.addVar("y", vtype = 'C', obj = 2.0) assert x.getObj() == 1.0 assert y.getObj() == 2.0 s.setObjective(4.0 * y + 10.5, clear = False) assert x.getObj() == 1.0 assert y.getObj() == 4.0 assert s.getObjoffset() == 10.5 # add some constraint c = s.addCons(x + 2 * y >= 1.0) assert c.isLinear() s.chgLhs(c, 5.0) s.chgRhs(c, 6.0) assert s.getLhs(c) == 5.0 assert s.getRhs(c) == 6.0 badsolution = s.createSol() s.setSolVal(badsolution, x, 2.0) s.setSolVal(badsolution, y, 2.0) assert s.getSlack(c, badsolution) == 0.0 assert s.getSlack(c, badsolution, 'lhs') == 1.0 assert s.getSlack(c, badsolution, 'rhs') == 0.0 assert s.getActivity(c, badsolution) == 6.0 s.freeSol(badsolution) # solve problem s.optimize() solution = s.getBestSol() # print solution assert (s.getVal(x) == s.getSolVal(solution, x)) assert (s.getVal(y) == s.getSolVal(solution, y)) assert round(s.getVal(x)) == 5.0 assert round(s.getVal(y)) == 0.0 assert s.getSlack(c, solution) == 0.0 assert s.getSlack(c, solution, 'lhs') == 0.0 assert s.getSlack(c, solution, 'rhs') == 1.0 assert s.getActivity(c, solution) == 5.0 s.freeProb() s = Model() x = s.addVar("x", vtype = 'C', obj = 1.0) y = s.addVar("y", vtype = 'C', obj = 2.0) c = s.addCons(x + 2 * y <= 1.0) s.setMaximize() s.delCons(c) s.optimize() assert s.getStatus() == 'unbounded'
from pyscipopt import Model model = Model("Animal quiz") x = model.addVar(vtype="I", name="octopus") y = model.addVar(vtype="I", name="turtel") z = model.addVar(vtype="I", name="bird") model.addCons(x + y + z == 32, name="Heads") model.addCons(8 * x + 4 * y + 2 * z == 80, name="Legs") model.setObjective(x + y, "minimize") model.hideOutput() model.optimize() print("Optimal value:", model.getObjVal()) print((x.name, y.name, z.name), " = ", (model.getVal(x), model.getVal(y), model.getVal(z)))
def calc_damage(self): data = self.data # 各サブステ x とダメージ倍率 f(x) の関係式を2次関数で近似。パラメータa,b,cは要調整。 # 係数: # f(x) = ax^2 + bx + c # scipを使う関係上、連続な関数を使用せざるを得ない。下記参照リンクの計算式の床関数もガン無視。なので多少誤差が出る(コンマ%くらい?)。 # reference: http://allaganstudies.akhmorning.com/guide/damage/ self.lmd_fdh = lambda x: 4.1667e-5 * x + 1 self.lmd_fch = lambda x: (3.6732e-9 * x + 2.7271e-5) * x + 0.02 + 1 self.lmd_fdt = lambda x: 3.9394e-05 * x + 1 self.lmd_fss_gdc = lambda x: (2.13073e-9 * x + 3.81069e-5) * x + 1 self.lmd_fss_dot_aa = lambda x: 3.9394e-05 * x + 1 self.lmd_fss = lambda x: self.rate_ss * self.lmd_fss_gdc(x) \ + (self.rate_aa+self.rate_dot) * self.lmd_fss_dot_aa(x) \ + (1-(self.rate_ss+self.rate_aa+self.rate_dot)) * 1 self.lmd_ftn = lambda x: 3.0303e-5 * x + 1 self.lmd_fpi = lambda x: 1 # 信仰値はダメージ倍率に影響なし self.expr_min = lambda x, y: (x + y) / 2 - abs( x - y) / 2 # min関数をscipが読める形に置き換える。 # サブステの装備内での上限値を考慮するために必要。 model = Model("calc_damage_multiplier") objvar = model.addVar("objvar", lb=1.0, ub=None, vtype="C") model.setObjective(objvar, "maximize") #### def variables for SCIP #### _is_chosen = {} # ex_m = {} ex_m_dh = {} ex_m_ch = {} ex_m_dt = {} ex_m_ss = {} ex_m_tn = {} ex_m_pi = {} # mg_m = {} mg_m_dh = {} mg_m_ch = {} mg_m_dt = {} mg_m_ss = {} mg_m_tn = {} mg_m_pi = {} # subst = {} dh = {} ch = {} dt = {} ss = {} tn = {} pi = {} for eq in data: # 各装備に対するエクス装着数 ex_m_dh[eq] = model.addVar(name="ex_m_dh_" + eq, vtype="I", lb=0) ex_m_ch[eq] = model.addVar(name="ex_m_ch_" + eq, vtype="I", lb=0) ex_m_dt[eq] = model.addVar(name="ex_m_dt_" + eq, vtype="I", lb=0) ex_m_ss[eq] = model.addVar(name="ex_m_ss_" + eq, vtype="I", lb=0) ex_m_tn[eq] = model.addVar(name="ex_m_tn_" + eq, vtype="I", lb=0) ex_m_pi[eq] = model.addVar(name="ex_m_pi_" + eq, vtype="I", lb=0) # 制約条件:1装備当たりのエクス装着数が、装着可能な個数の上限を超えない model.addCons( ex_m_dh[eq] + ex_m_ch[eq] + ex_m_dt[eq] + ex_m_ss[eq] + ex_m_tn[eq] + ex_m_pi[eq] <= data[eq]["ex_m"]) # 各装備に対するメガ装着数 mg_m_dh[eq] = model.addVar(name="mg_m_dh_" + eq, vtype="I", lb=0) mg_m_ch[eq] = model.addVar(name="mg_m_ch_" + eq, vtype="I", lb=0) mg_m_dt[eq] = model.addVar(name="mg_m_dt_" + eq, vtype="I", lb=0) mg_m_ss[eq] = model.addVar(name="mg_m_ss_" + eq, vtype="I", lb=0) mg_m_tn[eq] = model.addVar(name="mg_m_tn_" + eq, vtype="I", lb=0) mg_m_pi[eq] = model.addVar(name="mg_m_pi_" + eq, vtype="I", lb=0) # 制約条件:1装備当たりのメガ装着数が、装着可能な個数の上限を超えない model.addCons( mg_m_dh[eq] + mg_m_ch[eq] + mg_m_dt[eq] + mg_m_ss[eq] + mg_m_tn[eq] + mg_m_pi[eq] <= data[eq]["mg_m"]) ######## どちらの装備を選択したほうがよいかを変数にして解いてみる。 _is_chosen[eq] = [] if len(data[eq]["dh"]) == 1: _is_chosen[eq].append( model.addVar(name=eq + "_0", vtype="B", lb=0, ub=1)) model.addCons(_is_chosen[eq][0] <= 1) else: _is_chosen[eq].append( model.addVar(name=eq + "_0", vtype="B", lb=0, ub=1)) # 要修正。3以上の時。 _is_chosen[eq].append( model.addVar(name=eq + "_1", vtype="B", lb=0, ub=1)) model.addCons(_is_chosen[eq][0] + _is_chosen[eq][1] <= 1) # model.addCons(quicksum(_is_chosen[eq][i] for i in range(len(_is_chosen[eq]))) <= 1) ######## # tmp_dh = 60*ex_m_dh[eq] + 20*mg_m_dh[eq] + data[eq]["dh"][0] # tmp_ch = 60*ex_m_ch[eq] + 20*mg_m_ch[eq] + data[eq]["ch"][0] # tmp_dt = 60*ex_m_dt[eq] + 20*mg_m_dt[eq] + data[eq]["dt"][0] # tmp_ss = 60*ex_m_ss[eq] + 20*mg_m_ss[eq] + data[eq]["ss"][0] ######## tmp_dh = 60*ex_m_dh[eq] + 20*mg_m_dh[eq] \ + quicksum( data[eq]["dh"][i][0]*_is_chosen[eq][i] for i in range(len(_is_chosen[eq])) ) tmp_ch = 60*ex_m_ch[eq] + 20*mg_m_ch[eq] \ + quicksum( data[eq]["ch"][i][0]*_is_chosen[eq][i] for i in range(len(_is_chosen[eq])) ) tmp_dt = 60*ex_m_dt[eq] + 20*mg_m_dt[eq] \ + quicksum( data[eq]["dt"][i][0]*_is_chosen[eq][i] for i in range(len(_is_chosen[eq])) ) tmp_ss = 60*ex_m_ss[eq] + 20*mg_m_ss[eq] \ + quicksum( data[eq]["ss"][i][0]*_is_chosen[eq][i] for i in range(len(_is_chosen[eq])) ) tmp_tn = 60*ex_m_tn[eq] + 20*mg_m_tn[eq] \ + quicksum( data[eq]["tn"][i][0]*_is_chosen[eq][i] for i in range(len(_is_chosen[eq])) ) tmp_pi = 60*ex_m_pi[eq] + 20*mg_m_pi[eq] \ + quicksum( data[eq]["pi"][i][0]*_is_chosen[eq][i] for i in range(len(_is_chosen[eq])) ) # マテリアにより上昇するサブステが、サブステ上限値を超えないようにする dh[eq] = self.expr_min(tmp_dh, data[eq]["dh"][0][1]) ch[eq] = self.expr_min(tmp_ch, data[eq]["ch"][0][1]) dt[eq] = self.expr_min(tmp_dt, data[eq]["dt"][0][1]) ss[eq] = self.expr_min(tmp_ss, data[eq]["ss"][0][1]) tn[eq] = self.expr_min(tmp_tn, data[eq]["tn"][0][1]) pi[eq] = self.expr_min(tmp_pi, data[eq]["pi"][0][1]) dh_sum = quicksum(dh[eq] for eq in data) ch_sum = quicksum(ch[eq] for eq in data) dt_sum = quicksum(dt[eq] for eq in data) ss_sum = quicksum(ss[eq] for eq in data) tn_sum = quicksum(tn[eq] for eq in data) pi_sum = quicksum(pi[eq] for eq in data) #### damage efficiency in each substatuses #### fdh = self.lmd_fdh(dh_sum) fch = self.lmd_fch(ch_sum) fdt = self.lmd_fdt(dt_sum) fss = self.lmd_fss(ss_sum) ftn = self.lmd_ftn(tn_sum) fpi = self.lmd_fpi(pi_sum) model.addCons(objvar <= fdh * fch * fdt * fss * ftn * fpi) # 制約条件(目的関数):ダメージ効率を最大化する #### SS調整 #### model.addCons(ss_sum >= self.ss_lower) # 制約条件: SSが少なくとも X 以上 ## 信仰調整 ## model.addCons(pi_sum >= self.pi_lower) # 制約条件: 信仰が少なくとも X 以上 #### optimize #### model.optimize() sol = model.getBestSol() #### show result #### ## 注意: addVar()で vtype="I" や "B" として宣言した変数(整数変数、バイナリ変数)は、 ## 解を取得するために getVal() を呼ぶと、値が float 型で返ってくるので気を付けること。 num_eq = {} result = {} for eq in data: ######## print(_is_chosen[eq]) num_eq[eq] = [round(model.getVal(v)) for v in _is_chosen[eq]].index(1) ######## result[eq] = {} result[eq]["dh"] = ( min( 60 * round(model.getVal(ex_m_dh[eq])) + 20 * round(model.getVal(mg_m_dh[eq])) + data[eq]["dh"][num_eq[eq]][0], data[eq]["dh"][num_eq[eq]][1]), data[eq]["dh"][num_eq[eq]][1], ) result[eq]["ch"] = ( min( 60 * round(model.getVal(ex_m_ch[eq])) + 20 * round(model.getVal(mg_m_ch[eq])) + data[eq]["ch"][num_eq[eq]][0], data[eq]["ch"][num_eq[eq]][1]), data[eq]["ch"][num_eq[eq]][1], ) result[eq]["dt"] = ( min( 60 * round(model.getVal(ex_m_dt[eq])) + 20 * round(model.getVal(mg_m_dt[eq])) + data[eq]["dt"][num_eq[eq]][0], data[eq]["dt"][num_eq[eq]][1]), data[eq]["dt"][num_eq[eq]][1], ) result[eq]["ss"] = ( min( 60 * round(model.getVal(ex_m_ss[eq])) + 20 * round(model.getVal(mg_m_ss[eq])) + data[eq]["ss"][num_eq[eq]][0], data[eq]["ss"][num_eq[eq]][1]), data[eq]["ss"][num_eq[eq]][1], ) result[eq]["tn"] = ( min( 60 * round(model.getVal(ex_m_tn[eq])) + 20 * round(model.getVal(mg_m_tn[eq])) + data[eq]["tn"][num_eq[eq]][0], data[eq]["tn"][num_eq[eq]][1]), data[eq]["tn"][num_eq[eq]][1], ) result[eq]["pi"] = ( min( 60 * round(model.getVal(ex_m_pi[eq])) + 20 * round(model.getVal(mg_m_pi[eq])) + data[eq]["pi"][num_eq[eq]][0], data[eq]["pi"][num_eq[eq]][1]), data[eq]["pi"][num_eq[eq]][1], ) # 装備品のみのサブステ equip_dh = sum([data[eq]["dh"][num_eq[eq]][0] for eq in data]) equip_ch = sum([data[eq]["ch"][num_eq[eq]][0] for eq in data]) equip_dt = sum([data[eq]["dt"][num_eq[eq]][0] for eq in data]) equip_ss = sum([data[eq]["ss"][num_eq[eq]][0] for eq in data]) equip_tn = sum([data[eq]["tn"][num_eq[eq]][0] for eq in data]) equip_pi = sum([data[eq]["pi"][num_eq[eq]][0] for eq in data]) subst_init = equip_dh + equip_ch + equip_dt + equip_ss + equip_tn + equip_pi # マテリアのみのサブステ subst_materia_dh = sum([result[eq]["dh"][0] for eq in result]) - equip_dh subst_materia_ch = sum([result[eq]["ch"][0] for eq in result]) - equip_ch subst_materia_dt = sum([result[eq]["dt"][0] for eq in result]) - equip_dt subst_materia_ss = sum([result[eq]["ss"][0] for eq in result]) - equip_ss subst_materia_tn = sum([result[eq]["tn"][0] for eq in result]) - equip_tn subst_materia_pi = sum([result[eq]["pi"][0] for eq in result]) - equip_pi subst_materia = subst_materia_dh + subst_materia_ch + subst_materia_dt + subst_materia_ss + subst_materia_tn + subst_materia_pi fdh_sol = self.lmd_fdh(equip_dh + subst_materia_dh) fch_sol = self.lmd_fch(equip_ch + subst_materia_ch) fdt_sol = self.lmd_fdt(equip_dt + subst_materia_dt) fss_sol = self.lmd_fss(equip_ss + subst_materia_ss) fss_dot_aa_sol = self.lmd_fss_dot_aa(equip_ss + subst_materia_ss) fss_gdc_sol = self.lmd_fss_gdc(equip_ss + subst_materia_ss) ftn_sol = self.lmd_ftn(equip_tn + subst_materia_tn) fpi_sol = self.lmd_fpi(equip_pi + subst_materia_pi) print(sol) print("Optimal value:", model.getObjVal()) print("") print("") print(" エクス |メガ | サブステ") print( " dh ch dt ss tn pi|dh ch dt ss tn pi| dh ch dt ss tn pi" ) for eq in data: ex_m_dh_num = round(model.getVal(ex_m_dh[eq])) ex_m_ch_num = round(model.getVal(ex_m_ch[eq])) ex_m_dt_num = round(model.getVal(ex_m_dt[eq])) ex_m_ss_num = round(model.getVal(ex_m_ss[eq])) ex_m_tn_num = round(model.getVal(ex_m_tn[eq])) ex_m_pi_num = round(model.getVal(ex_m_pi[eq])) mg_m_dh_num = round(model.getVal(mg_m_dh[eq])) mg_m_ch_num = round(model.getVal(mg_m_ch[eq])) mg_m_dt_num = round(model.getVal(mg_m_dt[eq])) mg_m_ss_num = round(model.getVal(mg_m_ss[eq])) mg_m_tn_num = round(model.getVal(mg_m_tn[eq])) mg_m_pi_num = round(model.getVal(mg_m_pi[eq])) tmp_form = lambda x: str(x) if x > 0 else "-" string = "{0:10s}: {1} {2} {3} {4} {5} {6} |{7} {8} {9} {10} {11} {12} |{13:4d} +{14:3d} {15:4d} +{16:3d} {17:4d} +{18:3d} {19:4d} +{20:3d} {21:4d} +{22:3d} {23:4d} +{24:3d}" print( string.format( eq, tmp_form(ex_m_dh_num), tmp_form(ex_m_ch_num), tmp_form(ex_m_dt_num), tmp_form(ex_m_ss_num), tmp_form(ex_m_tn_num), tmp_form(ex_m_pi_num), tmp_form(mg_m_dh_num), tmp_form(mg_m_ch_num), tmp_form(mg_m_dt_num), tmp_form(mg_m_ss_num), tmp_form(mg_m_tn_num), tmp_form(mg_m_pi_num), data[eq]["dh"][num_eq[eq]][0], round(result[eq]["dh"][0]) - data[eq]["dh"][num_eq[eq]][0], data[eq]["ch"][num_eq[eq]][0], round(result[eq]["ch"][0]) - data[eq]["ch"][num_eq[eq]][0], data[eq]["dt"][num_eq[eq]][0], round(result[eq]["dt"][0]) - data[eq]["dt"][num_eq[eq]][0], data[eq]["ss"][num_eq[eq]][0], round(result[eq]["ss"][0]) - data[eq]["ss"][num_eq[eq]][0], data[eq]["tn"][num_eq[eq]][0], round(result[eq]["tn"][0]) - data[eq]["tn"][num_eq[eq]][0], data[eq]["pi"][num_eq[eq]][0], round(result[eq]["pi"][0]) - data[eq]["pi"][num_eq[eq]][0], )) print("") print(num_eq) print("") print("サブステ 装備 : {0:4.0f}".format(subst_init)) print("サブステ マテリア : {0:4.0f}".format(subst_materia)) print("サブステ 総数 : {0:4.0f}".format(subst_init + subst_materia)) print("") print(" Equip Materia") print("dh(ダイレクトヒット) : {0:4.0f} ({1:4.0f} + {2:4.0f})".format( equip_dh + subst_materia_dh, equip_dh, subst_materia_dh)) print("ch(クリティカルヒット) : {0:4.0f} ({1:4.0f} + {2:4.0f})".format( equip_ch + subst_materia_ch, equip_ch, subst_materia_ch)) print("dt(意思力) : {0:4.0f} ({1:4.0f} + {2:4.0f})".format( equip_dt + subst_materia_dt, equip_dt, subst_materia_dt)) print("ss(スキルスピード) : {0:4.0f} ({1:4.0f} + {2:4.0f})".format( equip_ss + subst_materia_ss, equip_ss, subst_materia_ss)) print("tn(不屈) : {0:4.0f} ({1:4.0f} + {2:4.0f})".format( equip_tn + subst_materia_tn, equip_tn, subst_materia_tn)) print("pi(信仰) : {0:4.0f} ({1:4.0f} + {2:4.0f})".format( equip_pi + subst_materia_pi, equip_pi, subst_materia_pi)) print("") self.show_eff(fdh_sol, fch_sol, fdt_sol, fss_sol, fss_gdc_sol, fss_dot_aa_sol, ftn_sol, fpi_sol) # memo # 解に対する変数の値が知りたい場合 # print(sol[dh]) # print(model.getSolVal(sol, dh)) # print(model.getVal(dh)) # 解に対する式の値が知りたい場合 # print(model.getSolVal(sol, fdh)) # print(model.getVal(fdh)) print("******** 厳密解 ********") rtn = self.calc_exact_dmg_multiplier(equip_dh + subst_materia_dh, equip_ch + subst_materia_ch, equip_dt + subst_materia_dt, equip_ss + subst_materia_ss, equip_tn + subst_materia_tn, equip_pi + subst_materia_pi) self.show_eff(*rtn)
def updateCopyNum(B, F, S, CRefer, cells, alpha=0.1, root=0, vType='C', Cap=False): tumors = B.shape[0] cellsTotal = cells + CRefer.shape[0] copyNum = B.shape[1] m = Model('phylo') C = {} for i in range(cells): for j in range(copyNum): C[i, j] = m.addVar(vtype=vType, name='C(%s,%s)' % (i, j)) bDelta = {} for i in range(tumors): for j in range(copyNum): bDelta[i, j] = m.addVar(vtype='C', name='bDelta(%s,%s)' % (i, j)) for p in range(tumors): for s in range(copyNum): expr = B[p, s] for k in range(cells): expr += -(F[p, k] * C[k, s]) m.addCons(bDelta[p, s] - (expr) >= 0, name='resu(%s,%s)' % (p, s)) m.addCons(bDelta[p, s] + (expr) >= 0, name='resl(%s,%s)' % (p, s)) for k in range(cells): for s in range(copyNum): m.addCons(C[k, s] >= 0, name='pos(%s,%s)' % (k, s)) if (Cap == True): for k in range(cells): for s in range(copyNum): m.addCons(C[k, s] <= 10, name='cap(%s,%s)' % (k, s)) wDelta = {} for i in range(cellsTotal): for j in range(cellsTotal): for k in range(copyNum): wDelta[i, j, k] = m.addVar(vtype='C', name='wDelta(%s,%s,%s)' % (i, j, k)) for u in range(cellsTotal): for v in range(cellsTotal): for i in range(copyNum): if (u < cells): Cui = C[u, i] else: Cui = CRefer[u - cells, i] if (v < cells): Cvi = C[v, i] else: Cvi = CRefer[v - cells, i] m.addCons(wDelta[u, v, i] - Cui + Cvi >= 0, name='delu(%s,%s,%s)' % (u, v, i)) m.addCons(wDelta[u, v, i] - Cvi + Cui >= 0, name='dell(%s,%s,%s)' % (u, v, i)) objExpr = quicksum(bDelta[i, j] for i in range(tumors) for j in range(copyNum)) for u in range(cellsTotal): for v in range(cellsTotal): objExpr += alpha * quicksum(wDelta[u, v, i] for i in range(copyNum)) * S[u, v] m.setObjective(objExpr, 'minimize') m.optimize() #print('Total Obj:', m.getObjVal()) # 2 is OPTIMAL Cresult = np.zeros([cells, copyNum], dtype=np.float) for k in range(cells): for s in range(copyNum): Cresult[k, s] = m.getVal(C[k, s]) objVal = m.getObjVal() return [Cresult, objVal]
def optimize_schedule(prefs, LP_input, grades, teacher, GAP, requirements=None, prox=None, save_location=None): """ Runs the optimizer in SCIP Parameters ---------- prefs - a Pandas DataFrame containing the student preferences LP_Input- a Pandas DataFrame coming from a clean_data function, that serves as the main input to the LP, it must have columns: Course Name Double Period Max Min Required Grades Number of Instances Room Type grades - a Pandas DataFrame that has all the students and their grade prox - a Padnas DataFrame that serves as the proximity matrix for courses teacher_info - a Padnas DataFrame that list all courses and the teacher that will be teaching it Gap - the number from the GUI slider we will use to determine what MIPGap to run the solver with Requirements - List of requirement objects that were solicited from the user these are then iterated over, parsed, and coded NOTE: most of the commented out stuff is from a previous iteration where the data was being pulled from various .csv files, I have included it as a helper if we need to go back and de-bug and see how it once worked when the data was coming from somewhere else NOTE 2: The commented out variables, constraints, and other optimization code is for Gurobi, the non-commented is for SCIP """ # prefs.to_csv("OptTestFiles/prefs.csv") # LP_input.to_csv("OptTestFiles/LP_input.csv") # teacher.to_csv("OptTestFiles/teacher.csv") start_time = timeit.default_timer() # -------------------------------------------------------- # Read Data # -------------------------------------------------------- # prefs = pd.read_csv("Resources/FlatChoicesBinary.csv") # courses = pd.read_csv("Resources/FlatCourseSize.csv") #prox = pd.read_csv("Resources/Proximity.csv") prox = pd.read_csv("../Resources/Proximity.csv") #prox.to_csv("OptTestFiles/prox.csv") #teacher = pd.read_csv("../Resources/Teacher_Info.csv", header=None) # course_rooms = pd.read_csv("Resources/CourseRoomReqs.csv") grades = pd.read_csv("../Resources/grades.csv", header=None) #grades.to_csv("OptTestFiles/grades.csv") # clean it up prefs.rename(columns={"Unnamed: 0": "Student"}, inplace=True) # courses.rename(columns={"0":"Class"}, inplace=True) # courses.drop("Unnamed: 0", axis=1, inplace=True) # NEW DATA #df = pd.read_csv("Resources/LP_Input.csv") df = LP_input # -------------------------------------------------------- # Pull out sets # -------------------------------------------------------- # Extract sets S = prefs["Student"].tolist( ) # list of all students (once we get ID make dictionary) # Cd = {} # Course dictionary # for i in courses.index: # Cd[i] = courses["Class"].iloc[i] Cd = {} for i in df.index: Cd[i] = df["Course Name"].iloc[i] for i in Cd: print(i, Cd[i]) C = range(len(Cd)) # Gather "Other Indicies" other_indicies = [] for j in Cd: if "Other" in Cd[j]: other_indicies.append(j) T = [1, 2, 3, 4, 7, 8] # Periods ## Instructors and corerspondence I = list(set(teacher[0])) DW_courses = list(set(teacher[1])) # Grades for each student Grades = grades[1] # Extract Preferences P = prefs.drop("Student", axis=1).as_matrix() # Double periods # Db = courses["Double"].fillna(0).astype(int) Db = df["Double Period"].fillna(0).astype(int) Db = Db.values # Course Sizes (min and max) # MIN = courses["Min"] # MAX = courses["Max"] MIN = df["Min"] MIN = MIN.values MAX = df["Max"] MAX = MAX.values # To check feasibility: # MIN = [3]*len(C) # MAX = [40]*len(C) # Proximity Matrix D = prox.drop("0", axis=1).as_matrix() # Create Proximity dictionary {subject:proximity vector} prox_dict = {} Subjects = list(prox.columns)[1:] for subj in list(prox.columns)[1:]: prox_dict[subj] = prox[subj] # Required Courses # grade_requirements = {} # for grade in [5,6,7,8,9,10,11,12]: # grade_requirements[grade] = df.index[df['Required Grades'] == grade].tolist() # # remove empties # for g in grade_requirements.keys(): # if grade_requirements[g] == []: # del grade_requirements[g] # -------------------------------------------------------- # Multi-Instance Course list # -------------------------------------------------------- # Look through input to determine which courses are multi-input # Create a list of these courses (only the first half of the double # if it is a double course) multi = df["Number of Instances"].fillna(0).astype(int) # print("\n\n\nMulti is:\n\n") # print(multi) # print("\n\n\nMulti of a single index\n\n") # print("Multi is of type", type(multi)) # print("At a single index", multi[2]) # print("At a single index with get", multi.get(2)) # print("type when trying to convert", type(multi[0])) multi = multi.values # print("\n\n\nMulti (values) is:\n\n") # print(multi) # print("\n\n\nMulti of a single index\n\n") # print("Multi is of type", type(multi)) # print("At a single index", multi[2]) # #print("At a single index with get", multi.get(2)) # print("type when trying to convert", type(multi[0])) multi_nested_list = [] j = 0 while j < len(Cd): # if it is part of multi-instance cluster if multi[j] == 2: #print("testing multi[j] ==2 with j=", j, "multi[j]=",multi[j]) #if int(multi.get(j)) == 2: # if it is a double period if Db[j] == 1: new = [j, j + 2] j += 4 # pass over cluster else: # not a double period new = [j, j + 1] j += 2 multi_nested_list.append(new) # if not a multi-instance elif multi[j] == 3: # these can't be double periods so just drop in all 3 multi_nested_list.append([j, j + 1, j + 2]) j += 3 else: j += 1 # ignore OTHER in multi-instance (these have 6 next to them) # -------------------------------------------------------- # Map Teachers to Courses # -------------------------------------------------------- # Need matrix with instructors as rows, all courses as columns, and 1 if teaching that course I_C_dict = {} for i in I: I_C_dict[i] = [] for index in range(teacher.shape[0]): if teacher.iloc[index][0] == i: l = I_C_dict[i] l.append(teacher.iloc[index][1]) I_C_dict[i] = l # Teacher_Course_Matrix courses_list = list(Cd.values()) Teacher_Course_Matrix = np.zeros(len(courses_list)) for i in I: t = np.zeros(len(courses_list)) for j in Cd: if Cd[j] in I_C_dict[i]: # print(i, "is teaching:", (40-len(i)-12)*".", Cd[j]) t[j] = 1 Teacher_Course_Matrix = np.vstack( [Teacher_Course_Matrix, np.matrix(t)]) Ta = np.array(Teacher_Course_Matrix[1:] ) # matrix tying teachers to courses they teach # -------------------------------------------------------- # Set up Room Data # -------------------------------------------------------- # Set of rooms R = [ "U1", "Steve", "U2", "U3", "U4/5", "U6", "U7", "L2", "L3", "Library", "Art", "L4", "L6", "Sci A", "Sci B", "Sci C", "Music Room", "Gym", "Gym2" ] # Department Courses Science_Rooms = ["Sci A", "Sci B", "Sci C"] Art_Rooms = ["Art"] Gym_Rooms = ["Gym", "Gym2"] Music_Rooms = ["Music Room"] Free_Rooms = list( set(R) - set(Science_Rooms + Art_Rooms + Gym_Rooms + Music_Rooms)) # Science_Courses = course_rooms["Science"] # Art_Courses = course_rooms["Art"] # Gym_Courses = course_rooms["Gym"] # Music_Courses = course_rooms["Music"] # Free_Courses = course_rooms["Free"] #Resource_Courses = course_rooms["Resource"] # Get courses for each room type (Art, Science, Gym, Music, Resource) Art_Courses = df.index[df['Room Type'] == "Art"].tolist() Science_Courses = df.index[df['Room Type'] == "Science"].tolist() Gym_Courses = df.index[df['Room Type'] == "Gym"].tolist() Music_Courses = df.index[df['Room Type'] == "Music"].tolist() Resource_Courses = df.index[df['Room Type'] == "Resource"].tolist() room_constrained_subjects = ["Science", "Art", "Music", "Gym"] constrained_rooms = { "Science": Science_Rooms, "Art": Art_Rooms, "Music": Music_Rooms, "Gym": Gym_Rooms } constrained_courses = { "Science": Science_Courses, "Art": Art_Courses, "Music": Music_Courses, "Gym": Gym_Courses } #------------------------------------------------------------ #------------------------------------------------------------ #------------------------------------------------------------ #------------------------------------------------------------ # Start Model Setup #------------------------------------------------------------ #------------------------------------------------------------ # Create Model instance m = Model("Schedule") # Trackers--to verify what SCIP/GB says num_vars = 0 num_cons = 0 #------------------------------------------------------------ # Create Variables #------------------------------------------------------------ print("Adding variables") # Add Student Variables (X) X = {} for i in S: for j in range(len(C)): name = "Student " + str(i) + " in course " + str(j) # X[i,j] = m.addVar(vtype=GRB.BINARY, name=name) X[i, j] = m.addVar(vtype="B", name=name) num_vars += 1 print("\tStudent/Course variable added") # Add Course Variable Course = {} # Variable dictionary for j in range(len(C)): for t in T: name = "Course " + str(j) + " in period " + str(t) # Course[j,t] = m.addVar(vtype=GRB.BINARY, name=name) Course[j, t] = m.addVar(vtype="B", name=name) num_vars += 1 print("\tCourse/Period variable added") # Create the u variable U = {} for i in S: for j in range(len(C)): for t in T: name = "min " + str(i) + ", " + str(j) + ", " + str(t) # U[i,j,t] = m.addVar(vtype=GRB.BINARY, name=name) U[i, j, t] = m.addVar(vtype="B", name=name) num_vars += 1 print("\tU(Student/Course/Period) variable added") # Define r room variable (over course j in room r durring period t) Rv = {} for j in range(len(C)): if "Other" not in Cd[j] and "Empty" not in Cd[j]: for s in R: for t in T: name = "Course " + str(j) + " in room " + str(s) + \ " durring period " + str(t) # Rv[j,s,t] = m.addVar(vtype=GRB.BINARY, name=name) Rv[j, s, t] = m.addVar(vtype="B", name=name) num_vars += 1 print("\tRoom/Period Variables added") #------------------------------------------------------------ #------------------------------------------------------------ # Add Constraints #------------------------------------------------------------ #------------------------------------------------------------ print("Adding constraints") # Force student in one course per period for i in S: for t in T: # m.addConstr(quicksum(U[i,j,t] for j in C) == 1) # one course per period m.addCons(quicksum(U[i, j, t] for j in C) == 1) # one course per period num_cons += 1 print("\tOne course per period") # "AND" Constraint--no more than one course per period for a student for i in S: for j in C: # m.addConstr(X[i,j] == quicksum(U[i,j,t] for t in T)) m.addCons(X[i, j] == quicksum(U[i, j, t] for t in T)) num_cons += 1 for t in T: # m.addConstr(Course[j,t] >= U[i,j,t]) m.addCons(Course[j, t] >= U[i, j, t]) num_cons += 1 print("\tU set-up constraints (`and`) added") # must have preffed the course (minus the requirements) # 8th graders must be in Researchers (j=88) # 9th Graders in 1 of African Studies (8), or Latrin American Studies (61) # 6th Graders in People and Lit (78,80), or Inquiry and Tools (52,54) for i in S: for j in Cd: if Grades[i] == 8 and j == 88: pass elif Grades[i] == 9 and (j in [8, 9, 61, 62]): pass elif Grades[i] == 6 and (j in [78, 79, 80, 81, 52, 53, 54, 55]): # so many as these are alternates and doubles pass else: # m.addConstr(X[i,j] <= P[i][j]) m.addCons(X[i, j] <= P[i][j]) num_cons += 1 print("\tStudents in courses they prefer") # g = 0 # for i in S: # if Grades[i] == 9: # if P[i][8] == 1: # g += 1 # Add capacity and minimum constraint print("Are we having the same problem with MAX?:", MAX[0]) for j in range(len(C)): # m.addConstr(quicksum(X[i,j] for i in S) <= MAX[j]) m.addCons(quicksum(X[i, j] for i in S) <= MAX[j]) #m.addConstr(quicksum(X[i,j] for i in S) <= 100) #m.addConstr(quicksum(X[i,j] for i in S) >= MIN[j]) m.addCons(quicksum(X[i, j] for i in S) >= MIN[j]) num_cons += 2 print("\tCourse capacity") #------------------------------------------------------------ # Proximity Constraints #------------------------------------------------------------ # Setup proximity min and max dicts (temp untill we generate more granular data) min_sub_dict = {} max_sub_dict = {} for subject in Subjects: min_sub_dict[subject] = np.ones(len(S)) * 0 max_sub_dict[subject] = np.ones(len(S)) * 3 # it works when max is 6 --> I think the constraints are written correctly? # infeasible when 5, very suspicious # # proximity by subject #for subject in Subjects: # print("min_sub_dict:", min_sub_dict) # print("max_sub_dict:", max_sub_dict) # print("Prox_dict", prox_dict.keys()) # print("Prox_dict['Other']", prox_dict["Other"]) # print("Prox_dict['K']", prox_dict["K"]) # print(prox_dict["Other"][0]) # print("\n\nRun over all j for Other") # print("Cd is", Cd ) # for j in Cd: # print("j:", j) # if j == 89: # print("j is 89 so should get a 1?") # print(prox_dict["Other"][j]) # for subject in ["K", "F", "D", "M", "IIC", "VI", "C", "IV", "IIA", "E", "I", # "H", "V", "VII", "Other", "G", "J", "IIB", "L", "IB"]: # test with limited set of subjects, trying to find issue # print("subject:", subject) # for i in S: # #print("i:", i) # if min_sub_dict[subject][i] > 0: # # m.addConstr(quicksum(prox_dict[subject][j]*X[i,j] for j in range(len(C))) >= min_sub_dict[subject][i])\ # print("We have hit the interior") # m.addCons(quicksum(prox_dict[subject][j]*X[i,j] for j in range(len(C))) >= min_sub_dict[subject][i]) # # do we always need a max? # # m.addConstr(quicksum(prox_dict[subject][j]*X[i,j] for j in range(len(C))) <= max_sub_dict[subject][i]) # m.addCons(quicksum(prox_dict[subject][j]*X[i,j] for j in range(len(C))) <= max_sub_dict[subject][i]) # print("\tProximity constraint added") print( "\n\nProximity constraints NOT ADDED as I don't think the files match\n\n" ) #------------------------------------------------------------ # Teacher Constraitns #------------------------------------------------------------ # Teacher teaching at most one course per period print("\n\nTa is:", Ta) print("\n\nTa Shape:", Ta.shape) print("\n\nCd is:", Cd) print("I is:", I) print("teacher is:", teacher) for j in Cd: print(Cd[j]) for k in range(len(I)): for t in T: print("k:", k, "t:", t) # m.addConstr(quicksum(Course[j,t]*Ta[k][j] for j in C) <= 1) m.addCons(quicksum(Course[j, t] * Ta[k][j] for j in C) <= 1) num_cons += 1 print("\tTeacher teaches as most once per period") #------------------------------------------------------------ # Course Constraints #------------------------------------------------------------ # Course Taught only once Constraint for j in range(len(C)): # m.addConstr(quicksum(Course[j,t] for t in T) == 1) m.addCons(quicksum(Course[j, t] for t in T) == 1) num_cons += 1 print("\tCourse taught only once") # Double period--consecutive constraints for j in range(len(C)): if Db[j] == 1: # if double period for t in T: if t != 4 and t != 8: # m.addConstr(Course[j,t] == Course[j+1, t+1]) # change to == from >= m.addCons(Course[j, t] == Course[j + 1, t + 1]) # change to == from >= num_cons += 1 print("\tDouble periods must be consecutive") # # Double Period--not 4th or 8th for j in range(len(C)): if Db[j] == 1: # m.addConstr(Course[j,4] == 0) m.addCons(Course[j, 4] == 0) # m.addConstr(Course[j,8] == 0) m.addCons(Course[j, 8] == 0) num_cons += 2 print("\tDouble periods not in 4th or 8th") # # Double Period--Student in both for i in S: for j in range(len(C)): if Db[j] == 1: # m.addConstr(X[i,j+1] == X[i,j]) # this was >= but == is better? m.addCons(X[i, j + 1] == X[i, j]) # this was >= but == is better? num_cons += 1 print("\tStudents in both parts of double") # Multi-Instance courses (students only in one instance--at most) for i in S: for course_set in multi_nested_list: # in at most one course of the list # m.addConstr(quicksum(X[i,j] for j in course_set) <= 1) m.addCons(quicksum(X[i, j] for j in course_set) <= 1) print("\t Students in at most of instance of multi-instance Course ") #------------------------------------------------------------ # Required Courses #------------------------------------------------------------ # 8th graders must be in Researchers (j=88) # 9th Graders in 1 of African Studies (8), or Latrin American Studies (61) # 6th Graders in People and Lit (78,80), or Inquiry and Tools (52,54) # MUST RE-IMPLEMENT THIS BASED ON THE REAUIREMENT SOLICIATIONS # for i in S: # if Grades[i] == 8: # m.addConstr(X[i,88] == 1) # if Grades[i] == 9: # m.addConstr(X[i,8] + X[i,61] == 1) # if Grades[i] == 6: # m.addConstr(X[i,78] + X[i,80] + X[i,52] + X[i,54] == 1) # print "\tGrade level course requirements" print("\n\n\n FIGURE OUT HOW TO CODE IN THE REQUIREMENTS \n\n\n\n") # for i in S: # # For each grade that has some requirement # for grade in grade_requirements.keys(): # # Determine if this student a restricted grade # if Grades[i] == grade: # for i in range(len(grade_requirements[grade])): # j = grade_requirements[grade][i] # pull course index # # Determine if multi-instance # if multi[j] != 0: # # If also double # if Db[j] == 1: ## INCOMPLETE: # I am thinking about how to handle this with 6th grades who have OR conditions #------------------------------------------------------------ # Room Constraints #------------------------------------------------------------ # If course taught, gets one room for j in range(len(C)): if "Other" not in Cd[j] and "Empty" not in Cd[j]: for t in T: # m.addConstr(quicksum(Rv[j,s,t] for s in R) == Course[j,t]) m.addCons(quicksum(Rv[j, s, t] for s in R) == Course[j, t]) print("\tCourses get one room") # make set of course indicies without Other and Empty c_mini = [] for j in Cd: if "Other" not in Cd[j] and "Empty" not in Cd[j]: c_mini.append(j) # Room gets at most one course per period for s in R: for t in T: # m.addConstr(quicksum(Rv[j,s,t] for j in c_mini) <= 1) m.addCons(quicksum(Rv[j, s, t] for j in c_mini) <= 1) print("\tRooms get at most one course per period") # Double periods in the same room for j in Cd: if Db[j] == 1: for t in T: if t != 4 and t != 8: for s in R: # m.addConstr(Rv[j,s,t] == Rv[j+1, s, t+1]) m.addCons(Rv[j, s, t] == Rv[j + 1, s, t + 1]) num_cons += 1 print("\tDouble Periods in same room") # force subject constrained courses into appropriate rooms # for subject in room_constrained_subjects: # sub_courses = constrained_courses[subject] # coruses in this subject # sub_rooms = constrained_rooms[subject] # appropriate rooms # for j in Cd: # if "Other" not in Cd[j] and "Empty" not in Cd[j]: # if sub_courses[j] == 1: # if course is in subject # for t in T: # m.addConstr(quicksum(Rv[j,s,t] for s in sub_rooms) == Course[j,t]) # print "\tCourses with subject specific room needs accomodated" for subject in room_constrained_subjects: sub_courses = constrained_courses[subject] # coruses in this subject sub_rooms = constrained_rooms[subject] # appropriate rooms for j in sub_courses: for t in T: # m.addConstr(quicksum(Rv[j,s,t] for s in sub_rooms) == Course[j,t]) m.addCons( quicksum(Rv[j, s, t] for s in sub_rooms) == Course[j, t]) print("\tCourses with subject specific room needs accomodated") #------------------------------------------------------------- # Period Constraints #------------------------------------------------------------- # Force "Other" courses in specific periods for i in range(len(T)): # m.addConstr(Course[other_indicies[i], T[i]] == 1) m.addCons(Course[other_indicies[i], T[i]] == 1) print("\t`Other` courses in each period") # Required Courses in periods 1-4 # Must be in begning of day # for j in [88, 8, 9, 61, 62, 78, 79, 80, 81, 52, 53, 54, 55]: # #for j in [88, 8, 9, 61, 62]: # # m.addConstr(quicksum(Course[j, t] for t in [1,2,3,4]) == 1) # m.addCons(quicksum(Course[j, t] for t in [1,2,3,4]) == 1) # print "\tRequired courses in periods 1 -> 4" # # Concurrance (People and lit (78,80)) and (Inquire and tools (52, 54)) # for t in T: # #m.addConstr(Course[78,t] == Course[80,t]) # ISSUE! <----------------------------- # m.addConstr(Course[52,t] == Course[54,t]) # print "Concurrance of Multi-instance courses" print("TODO: MAKE SURE THE REAUIRED DOUBLE PERIOD COURSES IN MORNING?") print("All constraints added") #------------------------------------------------------------- #------------------------------------------------------------- # Set Objective #------------------------------------------------------------- #------------------------------------------------------------- # Null objective # m.setObjective(X[1,1]*0, GRB.MAXIMIZE) # just find a feasible solution # Set Gap # m.Params.MIPGap=.3 # 30% <-- I know this is appropriate as have run quite a bit # m.Params.MIPGap=1 m.setRealParam('limits/gap', GAP) print("GAP set") # Preference objective #m.setObjective(quicksum(X[i,j]*P[i][j] for i in S for j in C), GRB.MAXIMIZE) # Minimize other objective # m.setObjective(-1*quicksum(X[i,j] for i in S for j in other_indicies), GRB.MAXIMIZE) # Minimize other, and Maximize Prefs m.setObjective( -1 * quicksum(X[i, j] for i in S for j in other_indicies) + quicksum(X[i, j] * P[i][j] for i in S for j in C), "maximize") print("Objective Set") # print(str(num_vars), "Variables") # print(str(num_cons), "Constraints") elapsed = timeit.default_timer() - start_time print("Model setup in " + str(round(elapsed, 3)) + " seconds") #------------------------------------------------------------- # Solve #------------------------------------------------------------- # Solve model print("-" * 30 + "Optimization Starting" + "-" * 30) m.optimize() # NOTE: solver info printed to terminal # What am I going to do with the solution? # Maybe make a solution object, that saves the variable values, along # with the courses, teacher names, etc. this can easily be pickled, # and parsed to get the schedules? # Save all variable values XV = {} CourseV = {} for i in S: for j in range(len(C)): # get student variable XV[i, j] = get_value(X[i, j]) for t in T: CourseV[j, t] = get_value(Course[j, t]) # get rooms RoomV = {} # for j in range(len(C)): for j in c_mini: for s in R: for t in T: RoomV[j, s, t] = get_value(Rv[j, s, t]) #RoomV[j,s,t] = Rv[j,s,t].X UV = {} for i in S: for j in Cd: for t in T: UV[i, j, t] = get_value(U[i, j, t]) # Create Solution object to faving solution = Solution(Cd, R, Ta, S, XV, CourseV, RoomV, UV) # Save the solution file = save_location + ".pkl" with open(file, "rb") as output: pickle.dump(solution, output, pickle.HIGHEST_PROTOCOL) # Return to solution object as well return solution
from pyscipopt import Model import time tic = time.time() # create model object model = Model('exercise1') # create variables x = model.addVar('x', ub=3) y = model.addVar('y', lb=0) # objective function definition model.setObjective(-4 * x - 2 * y, sense='minimize') # create constrains model.addCons(x + y <= 8) model.addCons(8 * x + 3 * y >= -24) model.addCons(-6 * x + 8 * y <= 48) model.addCons(3 * x + 5 * y <= 15) # launch optimization model.optimize() # get results sol = model.getBestSol() # display results print('\nBest solution:') print('x=', sol[x]) print('y=', sol[y])
def updateTree(B, Ctotal, cells=None, alpha=0.1, root=0): tumors = B.shape[0] cellsTotal = Ctotal.shape[0] copyNum = Ctotal.shape[1] if (cells == None): cells = cellsTotal m = Model('phylo') g, S = {}, {} for i in range(cellsTotal): for j in range(cellsTotal): S[i, j] = m.addVar(vtype='B', name='S(%s,%s)' % (i, j)) for k in range(cellsTotal): g[i, j, k] = m.addVar(vtype='B', name='g(%s,%s,%s)' % (i, j, k)) for t in range(cellsTotal): for u in range(cellsTotal): if u != t and u != root: expr = 0 for v in range(cellsTotal): expr += (g[u, v, t] - g[v, u, t]) m.addCons(expr == 0, name='conserv(%s,%s)' % (u, t)) for t in range(cellsTotal): if t != root: m.addCons(quicksum(g[i, t, t] for i in range(cellsTotal)) == 1, name='sink(%s)' % (t, )) m.addCons(quicksum(g[t, i, t] for i in range(cellsTotal)) == 0, name='leaf(%s)' % (t, )) m.addCons(quicksum(g[i, root, j] for i in range(cellsTotal) for j in range(cellsTotal)) == 0, name='root') for t in range(cellsTotal): if t != root: m.addCons(quicksum(g[root, i, t] for i in range(cellsTotal)) == 1, name='source(%s)' % (t, )) for t in range(cellsTotal): for u in range(cellsTotal): for v in range(cellsTotal): m.addCons(S[u, v] - g[u, v, t] >= 0, name='present(%s,%s,%s)' % (u, v, t)) wDelta = getDistanceMatrix(Ctotal) objExpr = quicksum(S[i, j] for i in range(cellsTotal) for j in range(cellsTotal)) for u in range(cellsTotal): for v in range(cellsTotal): objExpr += wDelta[u, v] * S[u, v] m.setObjective(alpha * objExpr, "minimize") m.optimize() #print('Total Obj:', m.getObjVal()) Sresult = np.zeros([cellsTotal, cellsTotal], dtype=np.int8) for u in range(cellsTotal): for v in range(cellsTotal): Sresult[u, v] = m.getVal(S[u, v]) objVal = m.getObjVal() return [Sresult, objVal]
def test_string(): 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') m.addCons(coil / wire - const1 == 0, name='defconst1') m.addCons((4.0*const1 - 1.0) / (4.0*const1 - 4.0) + 0.615 / const1 - const2 == 0, name='defconst2') m.addCons(8.0*MAXWORKLOAD/PI*const1*const2 - MAXSHEARSTRESS*wire**2 <= 0.0, name='shear') m.addCons(8.0/SHEARMOD*ncoils*const1**3 / wire - defl == 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-6
def test_gastrans(): GASTEMP = 281.15 RUGOSITY = 0.05 DENSITY = 0.616 COMPRESSIBILITY = 0.8 nodes = [ # name supplylo supplyup pressurelo pressureup cost ("Anderlues", 0.0, 1.2, 0.0, 66.2, 0.0 ), # 0 ("Antwerpen", None, -4.034, 30.0, 80.0, 0.0 ), # 1 ("Arlon", None, -0.222, 0.0, 66.2, 0.0 ), # 2 ("Berneau", 0.0, 0.0, 0.0, 66.2, 0.0 ), # 3 ("Blaregnies", None, -15.616, 50.0, 66.2, 0.0 ), # 4 ("Brugge", None, -3.918, 30.0, 80.0, 0.0 ), # 5 ("Dudzele", 0.0, 8.4, 0.0, 77.0, 2.28 ), # 6 ("Gent", None, -5.256, 30.0, 80.0, 0.0 ), # 7 ("Liege", None, -6.385, 30.0, 66.2, 0.0 ), # 8 ("Loenhout", 0.0, 4.8, 0.0, 77.0, 2.28 ), # 9 ("Mons", None, -6.848, 0.0, 66.2, 0.0 ), # 10 ("Namur", None, -2.120, 0.0, 66.2, 0.0 ), # 11 ("Petange", None, -1.919, 25.0, 66.2, 0.0 ), # 12 ("Peronnes", 0.0, 0.96, 0.0, 66.2, 1.68 ), # 13 ("Sinsin", 0.0, 0.0, 0.0, 63.0, 0.0 ), # 14 ("Voeren", 20.344, 22.012, 50.0, 66.2, 1.68 ), # 15 ("Wanze", 0.0, 0.0, 0.0, 66.2, 0.0 ), # 16 ("Warnand", 0.0, 0.0, 0.0, 66.2, 0.0 ), # 17 ("Zeebrugge", 8.87, 11.594, 0.0, 77.0, 2.28 ), # 18 ("Zomergem", 0.0, 0.0, 0.0, 80.0, 0.0 ) # 19 ] arcs = [ # node1 node2 diameter length active */ ( 18, 6, 890.0, 4.0, False ), ( 18, 6, 890.0, 4.0, False ), ( 6, 5, 890.0, 6.0, False ), ( 6, 5, 890.0, 6.0, False ), ( 5, 19, 890.0, 26.0, False ), ( 9, 1, 590.1, 43.0, False ), ( 1, 7, 590.1, 29.0, False ), ( 7, 19, 590.1, 19.0, False ), ( 19, 13, 890.0, 55.0, False ), ( 15, 3, 890.0, 5.0, True ), ( 15, 3, 395.0, 5.0, True ), ( 3, 8, 890.0, 20.0, False ), ( 3, 8, 395.0, 20.0, False ), ( 8, 17, 890.0, 25.0, False ), ( 8, 17, 395.0, 25.0, False ), ( 17, 11, 890.0, 42.0, False ), ( 11, 0, 890.0, 40.0, False ), ( 0, 13, 890.0, 5.0, False ), ( 13, 10, 890.0, 10.0, False ), ( 10, 4, 890.0, 25.0, False ), ( 17, 16, 395.5, 10.5, False ), ( 16, 14, 315.5, 26.0, True ), ( 14, 2, 315.5, 98.0, False ), ( 2, 12, 315.5, 6.0, False ) ] scip = Model() # create flow variables flow = {} for arc in arcs: flow[arc] = scip.addVar("flow_%s_%s"%(nodes[arc[0]][0],nodes[arc[1]][0]), # names of nodes in arc lb = 0.0 if arc[4] else None) # no lower bound if not active # pressure difference variables pressurediff = {} for arc in arcs: pressurediff[arc] = scip.addVar("pressurediff_%s_%s"%(nodes[arc[0]][0],nodes[arc[1]][0]), # names of nodes in arc lb = None) # supply variables supply = {} for node in nodes: supply[node] = scip.addVar("supply_%s"%(node[0]), lb = node[1], ub = node[2], obj = node[5]) # square pressure variables pressure = {} for node in nodes: pressure[node] = scip.addVar("pressure_%s"%(node[0]), lb = node[3]**2, ub = node[4]**2) # node balance constrains, for each node i: outflows - inflows = supply for nid, node in enumerate(nodes): # find arcs that go or end at this node flowbalance = 0 for arc in arcs: if arc[0] == nid: # arc is outgoing flowbalance += flow[arc] elif arc[1] == nid: # arc is incoming flowbalance -= flow[arc] else: continue scip.addCons(flowbalance == supply[node], name="flowbalance%s"%node[0]) # pressure difference constraints: pressurediff[node1 to node2] = pressure[node1] - pressure[node2] for arc in arcs: scip.addCons(pressurediff[arc] == pressure[nodes[arc[0]]] - pressure[nodes[arc[1]]], "pressurediffcons_%s_%s"%(nodes[arc[0]][0],nodes[arc[1]][0])) # pressure loss constraints: # active arc: flow[arc]^2 + coef * pressurediff[arc] <= 0.0 # regular pipes: flow[arc] * abs(flow[arc]) - coef * pressurediff[arc] == 0.0 # coef = 96.074830e-15*diameter(i)^5/(lambda*compressibility*temperatur*length(i)*density) # lambda = (2*log10(3.7*diameter(i)/rugosity))^(-2) from math import log10 for arc in arcs: coef = 96.074830e-15 * arc[2]**5 * (2.0*log10(3.7*arc[2]/RUGOSITY))**2 / COMPRESSIBILITY / GASTEMP / arc[3] / DENSITY if arc[4]: # active scip.addCons(flow[arc]**2 + coef * pressurediff[arc] <= 0.0, "pressureloss_%s_%s"%(nodes[arc[0]][0],nodes[arc[1]][0])) else: scip.addCons(flow[arc]*abs(flow[arc]) - coef * pressurediff[arc] == 0.0, "pressureloss_%s_%s"%(nodes[arc[0]][0],nodes[arc[1]][0])) scip.setRealParam('limits/time', 5) scip.optimize() if scip.getStatus() == 'timelimit': pytest.skip() assert abs(scip.getPrimalbound() - 89.08584) < 1.0e-9
def pricerredcost(self): # Retreiving the dual solutions dualSolutions = [] for i, c in enumerate(self.data['cons']): dualSolutions.append(self.model.getDualsolLinear(c)) # Building a MIP to solve the subproblem subMIP = Model("CuttingStock-Sub") # Turning off presolve subMIP.setPresolve(SCIP_PARAMSETTING.OFF) # Setting the verbosity level to 0 subMIP.hideOutput() cutWidthVars = [] varNames = [] varBaseName = "CutWidth" # Variables for the subMIP for i in range(len(dualSolutions)): varNames.append(varBaseName + "_" + str(i)) cutWidthVars.append( subMIP.addVar(varNames[i], vtype="I", obj=-1.0 * dualSolutions[i])) # Adding the knapsack constraint knapsackCons = subMIP.addCons( quicksum(w * v for (w, v) in zip( self.data['widths'], cutWidthVars)) <= self.data['rollLength']) # Solving the subMIP to generate the most negative reduced cost pattern subMIP.optimize() objval = 1 + subMIP.getObjVal() # Adding the column to the master problem if objval < -1e-08: currentNumVar = len(self.data['var']) # Creating new var; must set pricedVar to True newVar = self.model.addVar("NewPattern_" + str(currentNumVar), vtype="C", obj=1.0, pricedVar=True) # Adding the new variable to the constraints of the master problem newPattern = [] for i, c in enumerate(self.data['cons']): coeff = round(subMIP.getVal(cutWidthVars[i])) self.model.addConsCoeff(c, newVar, coeff) newPattern.append(coeff) # Storing the new variable in the pricer data. self.data['patterns'].append(newPattern) self.data['var'].append(newVar) return {'result': SCIP_RESULT.SUCCESS}
def tsp_solver(c, customers, vehicle_tours): def addcut(cut_edges): G = networkx.Graph() G.add_edges_from(cut_edges) Components = list(networkx.connected_components(G)) if len(Components) == 1: return False model.freeTransform() for S in Components: model.addCons( quicksum(x[i, j] for i in S for j in S) <= len(S) - 1) return True # Add the depot on each vehicle vehicle_tours = {k: vehicle_tours[k] + [0] for k in vehicle_tours.keys()} final_obj = 0 final_tours = [] for key, value in vehicle_tours.items(): v_customers = value model = Model("vrp_tsp") x = {} for i in v_customers: for j in v_customers: # vehicle moves from customer i to customer j x[i, j] = model.addVar(vtype="B", name="x(%s,%s)" % (i, j)) for i in v_customers: # Constraint: every customer can only be visited once # (or, every node must be connected and connect to another node) model.addCons(quicksum(x[i, j] for j in v_customers) == 1) model.addCons(quicksum(x[j, i] for j in v_customers) == 1) for j in v_customers: if i == j: # Constraint: a node cannot conect to itself model.addCons(x[i, j] == 0) # Objective function: minimize total distance of the tour model.setObjective( quicksum(x[i, j] * c[(i, j)] for i in v_customers for j in v_customers), "minimize") EPS = 1.e-6 isMIP = False while True: model.optimize() edges = [] for (i, j) in x: if model.getVal(x[i, j]) > EPS: edges.append((i, j)) if addcut(edges) == False: if isMIP: # integer variables, components connected: solution found break model.freeTransform() for ( i, j ) in x: # all components connected, switch to integer model model.chgVarType(x[i, j], "B") isMIP = True # model.optimize() best_sol = model.getBestSol() sub_tour = [] # Build the graph path # Retrieve the last node of the graph, i.e., the last one connecting to the depot last_node = [n for n in edges if n[1] == 0][0][0] G = networkx.Graph() G.add_edges_from(edges) path = list(networkx.all_simple_paths(G, source=0, target=last_node)) path.sort(reverse=True, key=lambda u: len(u)) if len(path) > 0: path = path[0][1:] else: path = path[1:] obj = model.getSolObjVal(best_sol) final_obj += obj final_tours.append([customers[i] for i in path]) return final_obj, final_tours
for b in range(1, M + 1): for c in range(1, G + 1): name = "T1_fmg_" + str(a) + ',' + str(b) + ',' + str(c) T1_fmg[a, b, c] = m.addVar(name, vtype='I', lb=-0.1, ub=1.1) # 定义临时变量,降级到l级的牛奶的总量 D_fml2g = {} for a in range(1, F + 1): for b in range(1, M + 1): for d in range(1, L + 1): for e in range(1, G + 1): name = "D_fml2g_" + str(a) + ',' + str(b) + ',' + str( d) + ',' + str(e) D_fml2g[a, b, d, e] = m.addVar(name, vtype='I', lb=0) m.addCons(D_fml2g[a, b, d, e] == quicksum(D_fml1l2g[a, b, c, d, e] for c in range(1, L + 1))) # 临时变量,从l级降级到其他级别的牛奶总量 D_fml1g = {} for a in range(1, F + 1): for b in range(1, M + 1): for d in range(1, L + 1): for e in range(1, G + 1): name = "D_fml1g_" + str(a) + ',' + str(b) + ',' + str( d) + ',' + str(e) D_fml1g[a, b, d, e] = m.addVar(name, vtype='I', lb=0) m.addCons(D_fml1g[a, b, d, e] == quicksum(D_fml1l2g[a, b, d, c, e] for c in range(1, L + 1)))
def vehicle_assignment_solver(K, a, b, c, customer_count, predefined_vehicle_index=None, predefined_vehicle_nodes=None): v_range = range(0, K) c_range = range(1, customer_count) samples = [] a_ord = sorted(a.items(), key=lambda k: k[1]) a_ord.reverse() samples.append(a_ord[0]) del a_ord[0] while True: a_ord = sorted(a_ord, key=lambda el: dist_between_nodes(el, samples, c), reverse=True) samples.append(a_ord[0]) del a_ord[0] if len(samples) == K: break w = {} for i in v_range: w[i] = samples[i][0] # Resolve MIP problem to find the best possible vehicle-customers combinations model = Model("vrp_vehicles") #model.hideOutput() if customer_count >= 200: model.setRealParam("limits/gap", 0.005) y = {} for v in v_range: for i in c_range: # customer i is visited by vehicle v y[i, v] = model.addVar(vtype="B", name="y(%s,%s)" % (i, v)) for v in v_range: # Constraint: the demand of customers assigned to vehicle V cannot exceed its capacity model.addCons(quicksum(a[i] * y[i, v] for i in c_range) <= b) # Constraint: for this model, we enforce every vehicle to visit a customer # model.addCons(quicksum(y[i, v] for i in c_range) >= 1) # Constraint: we enforce the customers on 'w' to be visited by the defined vehicle #model.addCons(y[w[v], v] == 1) #if predefined_vehicle_nodes and v == predefined_vehicle_index: # for p in predefined_vehicle_nodes: # model.addCons(y[p, predefined_vehicle_index] == 1) for i in c_range: # if i > 0: # Constraint: each customer has to be visited by exactly one vehicle model.addCons(quicksum(y[i, v] for v in v_range) == 1) model.setObjective( quicksum( quicksum( cost_of_new_customer_in_vehicle(c, i, w[v]) * y[i, v] for i in c_range) for v in v_range), "maximize") model.optimize() # best_sol = model.getBestSol() vehicle_tours = {} for v in v_range: vehicle_tours[v] = [] for i in c_range: # val = model.getSolVal(best_sol, y[i, v]) val = model.getVal(y[i, v]) if val > 0.5: vehicle_tours[v].append(i) obj = model.getObjVal() return obj, vehicle_tours
(5, 2): 8, (5, 3): 4, } 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(sum(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(sum(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() print("Optimal value:", model.getObjVal()) EPS = 1.e-6
P_In_S[t] = model.addVar(vtype="C", name="x(%s)"%j) P_RO[t] = model.addVar(vtype="C", name="x(%s)"%j, lb=0, ub=2500) st[t] = model.addVar(vtype="C", name="x(%s)"%j, ub = 1) Fp[t] = model.addVar(vtype="C", name="x(%s)"%j, lb=0, ub = 4) Yopt[t] = model.addVar(vtype="C", name="x(%s)"%j, lb=.6, ub=1) P_Sys[t]= model.addVar(vtype="C", name="x(%s)"%j) Vf[t] = model.addVar(vtype="C", name="x(%s)"%j) hdot[t]= model.addVar(vtype="C", name="x(%s)"%j) h[t] = model.addVar(vtype="C", name="x(%s)"%j, lb=0, ub=hmax) Theta_VFD[t] = model.addVar(vtype="C", name="x(%s)"%j, lb=0, ub=Theta_Max) Vr[t] = model.addVar(vtype="C", name="x(%s)"%j, lb=0, ub=2) # Create Constraints for t in time: model.addCons(quickSum()) for j in Blends: x[j] = model.addVar(vtype="C", name="x(%s)"%j) # Create constraints c = {} for i in Grapes: c[i] = model.addCons(quicksum(Use[i,j]*x[j] for j in Blends) <= Inventory[i], name="Use(%s)"%i) # Objective model.setObjective(quicksum(Profit[j]*x[j] for j in Blends), "maximize") model.optimize() if model.getStatus() == "optimal":
def create_model(self): model = Model() x, b = {}, {} _A = [(i, t) for i in self.tasks for t in self.periods] for (i, t) in _A: x[i, t] = model.addVar(vtype="B", name="x(%s,%s)" % (i, t)) # create decision variables b[i, t] = model.addVar(vtype="B", name="b(%s,%s)" % (i, t)) # create decision variables # create constraints for t in self.periods: model.addCons( quicksum(self.p[i, t] * (1 - x[i, t]) for i in self.tasks) - self.d[t] >= 0) # 1 model.addCons(quicksum(x[i, t] for i in self.tasks) <= self.LT[t]) # 6 model.addCons( quicksum((self.MV[i] + self.MH[i] + self.ML[i]) * x[i, t] for i in self.tasks) <= self.AM[t]) # 11 model.addCons( quicksum(self.V[i] * x[i, t] for i in self.tasks) <= self.AV[t]) # 12 model.addCons( quicksum(self.H[i] * x[i, t] for i in self.tasks) <= self.AH[t]) # 13 for i in self.tasks: model.addCons(quicksum(b[i, t] for t in self.periods) == 1) # 2 model.addCons( quicksum(x[i, t] for t in self.periods) == self.LP[i]) # 5 model.addCons( quicksum(b[i, t] for t in self.periods[:self.L[i] - self.LP[i] + 2]) == 1) # 9 for t in self.periods: model.addCons(x[i, t] >= b[i, t]) # 3 for t in self.periods[1:]: model.addCons(x[i, t] - x[i, t - 1] <= b[i, t]) # 3, t >= 2 model.addCons( x[i, t] + x[i, t - 1] + b[i, t] <= 1 + self.LP[i]) # 4 for j in self.tasks: if j != i: model.addCons(x[i, t] + x[j, t] <= 1) # 8 for t in self.periods: model.addCons( quicksum(b[i, k] for k in self.periods) - b[j, t] >= 0) # 7 for t in self.U: model.addCons(x[i, t] == 0) # 10 # create costs C_M, C_T = {}, {} for i in self.tasks: for t in self.periods: C_M[i,t] = self.C_MV[t] * self.MV[i] + self.C_MH[t] * self.MH[i] + \ self.C_ML[t] * self.ML[i] C_T[i,t] = (self.C_FV * self.V[i] + self.C_FH * self.H[i])/self.LP[i] + \ self.C_SV[i,t] * self.V[i] + self.C_SH[i,t] * self.H[i] # create ojective function model.setObjective(quicksum((C_M[i,t] + self.C_EQ[i,t] + self.C_I[i,t] + \ C_T[i,t]) * x[i,t] for t in self.periods for i in self.tasks), "minimize") model.hideOutput() # silent mode model.optimize() if model.getStatus() != 'optimal': print('Model is not feasible!') else: c_total = model.getObjVal() print("Total cost is: ", c_total) for (i, t) in _A: if model.getVal(x[i, t]) == 1.0: print(x[i, t], " = 1") if model.getVal(b[i, t]) == 1.0: print(b[i, t], " = 1") return
print("* Sense: %s" % m.getObjectiveSense()) for v in m.getVars(): if v.name != "n": print("%s: %d" % (v, round(m.getVal(v)))) print("\n") # AND # model = Model() model.hideOutput() x = model.addVar("x", "B") y = model.addVar("y", "B") z = model.addVar("z", "B") r = model.addVar("r", "B") model.addConsAnd([x, y, z], r) model.addCons(x == 1) model.setObjective(r, sense="minimize") model.optimize() printFunc("AND", model) # OR # model = Model() model.hideOutput() x = model.addVar("x", "B") y = model.addVar("y", "B") z = model.addVar("z", "B") r = model.addVar("r", "B") model.addConsOr([x, y, z], r) model.addCons(x == 0) model.setObjective(r, sense="maximize") model.optimize()
subject to 2x + y + z <= 60 x + 2y + z <= 60 z <= 30 x,y,z >= 0 Copyright (c) by Joao Pedro PEDROSO and Mikio KUBO, 2015 """ from pyscipopt import Model model = Model("Simple linear optimization") x1 = model.addVar(vtype="C", name="x1") x2 = model.addVar(vtype="C", name="x2") x3 = model.addVar(vtype="C", name="x3") model.addCons(2 * x1 + x2 + x3 <= 60) model.addCons(x1 + 2 * x2 + x3 <= 60) model.addCons(x3 <= 30) model.setObjective(15 * x1 + 18 * x2 + 30 * x3, "maximize") model.optimize() if model.getStatus() == "optimal": print("Optimal value:", model.getObjVal()) print("Solution:") print(" x1 = ", model.getVal(x1)) print(" x2 = ", model.getVal(x2)) print(" x3 = ", model.getVal(x3)) else: print("Problem could not be solved to optimality")
def lewis_caroll_zebra(positions, carac): """ Parameters: - n: Integer, number of queen and size of the grid Returns a model, ready to be solved. """ m = Model() # create a binary variable for every field and value x = {} for i in range(5): for j in range(5): for k in range(5): name = str(i)+','+str(j)+','+str(k) x[i, j, k] = m.addVar(name, vtype='B') # only one value per carac in every field for i in range(5): for j in range(5): m.addCons(quicksum(x[i, j, k] for k in range(5)) == 1) # only "one coffee" constraint for j in range(5): for k in range(5): m.addCons(quicksum(x[i, j, k] for i in range(5)) == 1) m.addCons(x[0, 1, 0] == 1) # Le norvégien habite la première maison, m.addCons(x[1, 0, 0] == 1) # La maison à coté de celle du norvégien est bleue, m.addCons(x[2, 2, 0] == 1) # L’habitant de la troisième maison boit du lait, for i in range(5): m.addCons(x[i, 1, 1] == x[i, 0, 1]) # L’anglais habite la maison rouge, m.addCons(x[i, 2, 2] == x[i, 0, 3]) # L’habitant de la maison verte boit du café m.addCons(x[i, 0, 2] == x[i, 3, 0]) # L’habitant de la maison jaune fume des Kools, m.addCons(x[i, 1, 2] == x[i, 4, 1]) # L’espagnol a un chien, m.addCons(x[i, 1, 4] == x[i, 2, 3]) # L'ukrainien boit du thé m.addCons(x[i, 1, 3] == x[i, 3, 1]) # Le japonais fume des cravens m.addCons(x[i, 3, 2] == x[i, 4, 3]) # Le fumeur de old golds a un escargot m.addCons(x[i, 3, 3] == x[i, 2, 1]) # Le fumeur de gitanes boit du vin, m.addCons(x[0, 0, 4] == 0) for i in range(4): m.addCons(x[i, 0, 3] == x[i+1, 0, 4]) # La maison blanche se trouve juste après la verte, m.addCons(x[0, 3, 4]==x[1, 4, 2]) m.addCons(x[0, 3, 0]==x[1, 4, 4]) for i in range(1, 4): m.addCons(x[i, 3, 4] <= x[i+1, 4, 2] + x[i-1, 4, 2]) # Un voisin du fumeur de Chesterfields a un renard, m.addCons(x[i, 3, 0] <= x[i+1, 4, 4] + x[i-1, 4, 4]) # Un voisin du fumeur de Kools a un cheval. m.addCons(x[4, 3, 4]==x[3, 4, 2]) m.addCons(x[4, 3, 0]==x[3, 4, 4]) return m, x
def test_model(): # create solver instance s = Model() # test parameter methods pric = s.getParam('lp/pricing') s.setParam('lp/pricing', 'q') assert 'q' == s.getParam('lp/pricing') s.setParam('lp/pricing', pric) s.setParam('visual/vbcfilename', 'vbcfile') assert 'vbcfile' == s.getParam('visual/vbcfilename') assert 'lp/pricing' in s.getParams() s.setParams({'visual/vbcfilename': '-'}) assert '-' == s.getParam('visual/vbcfilename') # add some variables x = s.addVar("x", vtype = 'C', obj = 1.0) y = s.addVar("y", vtype = 'C', obj = 2.0) assert x.getObj() == 1.0 assert y.getObj() == 2.0 s.setObjective(4.0 * y + 10.5, clear = False) assert x.getObj() == 1.0 assert y.getObj() == 4.0 assert s.getObjoffset() == 10.5 # add some constraint c = s.addCons(x + 2 * y >= 1.0) assert c.isLinear() s.chgLhs(c, 5.0) s.chgRhs(c, 6.0) assert s.getLhs(c) == 5.0 assert s.getRhs(c) == 6.0 # solve problem s.optimize() solution = s.getBestSol() # print solution assert (s.getVal(x) == s.getSolVal(solution, x)) assert (s.getVal(y) == s.getSolVal(solution, y)) assert round(s.getVal(x)) == 5.0 assert round(s.getVal(y)) == 0.0 assert s.getSlack(c, solution) == 0.0 assert s.getSlack(c, solution, 'lhs') == 0.0 assert s.getSlack(c, solution, 'rhs') == 1.0 assert s.getActivity(c, solution) == 5.0 # check expression evaluations expr = x*x + 2*x*y + y*y expr2 = x + 1 assert s.getVal(expr) == s.getSolVal(solution, expr) assert s.getVal(expr2) == s.getSolVal(solution, expr2) assert round(s.getVal(expr)) == 25.0 assert round(s.getVal(expr2)) == 6.0 s.writeProblem('model') s.writeProblem('model.lp') s.freeProb() s = Model() x = s.addVar("x", vtype = 'C', obj = 1.0) y = s.addVar("y", vtype = 'C', obj = 2.0) c = s.addCons(x + 2 * y <= 1.0) s.setMaximize() s.delCons(c) s.optimize() assert s.getStatus() == 'unbounded'
def scf(n, c): """scf: single-commodity flow formulation for the (asymmetric) traveling salesman problem Parameters: - n: number of nodes - c[i,j]: cost for traversing arc (i,j) Returns a model, ready to be solved. """ model = Model("atsp - scf") x, f = {}, {} 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)) if i == 1: f[i, j] = model.addVar(lb=0, ub=n - 1, vtype="C", name="f(%s,%s)" % (i, j)) else: f[i, j] = model.addVar(lb=0, ub=n - 2, vtype="C", name="f(%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.addCons( quicksum(f[1, j] for j in range(2, n + 1)) == n - 1, "FlowOut") for i in range(2, n + 1): model.addCons(quicksum(f[j,i] for j in range(1,n+1) if j != i) - \ quicksum(f[i,j] for j in range(1,n+1) if j != i) == 1, "FlowCons(%s)"%i) for j in range(2, n + 1): model.addCons(f[1, j] <= (n - 1) * x[1, j], "FlowUB(%s,%s)" % (1, j)) for i in range(2, n + 1): if i != j: model.addCons(f[i, j] <= (n - 2) * x[i, j], "FlowUB(%s,%s)" % (i, j)) model.setObjective(quicksum(c[i, j] * x[i, j] for (i, j) in x), "minimize") model.data = x, f return model
def mintreeMFP(n, e, d): """ mintreeMFP: min Cost Tree based on Flow Conservation Parameters: - n: number of nodes - e[i,j]['cap','cost']: edges of graph, 'cap': capacity of edge, 'cost': cost for traversing edge (i,j) - d[i,j]: demande(data) from node i to j Returns a model, ready to be solved. """ print("\n========min Cost Tree based on Flow Conservation======") model = Model("mintreeMFP") x, f, z = {}, {}, {} # flow variable """ In our model, f[i,j] is the sum of flow on edge, if f[i,j]>0 then z[i,j]=1 else z[i,j]=0, such that get minTree In order to express the logical constraint, define a Big M, and z is Binary, z[i,j]>=f[i,j]/M (gurantee f/M <1) and z[i,j]<=f[i,j]*M (gurantee f[i,j]*M >1) """ M = 100000000 for (i, j) in e.keys(): f[i, j] = model.addVar(ub=1000000, lb=0, vtype="C", name="f[%s,%s]" % (i, j)) z[i, j] = model.addVar(ub=1, lb=0, vtype="B", name="z[%s,%s]" % (i, j)) for (s, t) in d.keys(): x[i, j, s, t] = model.addVar(ub=1000000, lb=0, vtype="C", name="x[%s,%s,%s,%s]" % (i, j, s, t)) # node flow conservation for (s, t) in d.keys(): for j in n.keys(): # for destination node if j == t: model.addCons( quicksum(x[i, j, s, t] for i in n.keys() if (i, j) in e.keys()) - quicksum(x[j, i, s, t] for i in n.keys() if (j, i) in e.keys()) == d[s, t], "DesNode(%s)" % j) # for source node elif j == s: model.addCons( quicksum(x[i, j, s, t] for i in n.keys() if (i, j) in e.keys()) - quicksum(x[j, i, s, t] for i in n.keys() if (j, i) in e.keys()) == -d[s, t], "SourceNode(%s)" % j) else: model.addCons( quicksum(x[i, j, s, t] for i in n.keys() if (i, j) in e.keys()) - quicksum(x[j, i, s, t] for i in n.keys() if (j, i) in e.keys()) == 0, "SourceNode(%s)" % j) # constrains for edge capacity, take into consideration of tree optimization, using variable f for (i, j) in e.keys(): f[i, j] = quicksum(x[i, j, s, t] for (s, t) in d.keys()) model.addCons(f[i, j] <= e[i, j]['cap'], 'edge(%s,%s)' % (i, j)) # logical constraint model.addCons(M * z[i, j] >= f[i, j]) model.addCons(z[i, j] <= f[i, j] * M) model.data = x, f #model.setObjective(quicksum(f[i,j]*e[i,j]['cost'] for (i,j) in e.keys()), "minimize") model.setObjective(quicksum(z[i, j] for (i, j) in e.keys()), "minimize") return model
] weights = [ 7, 86, 5, 76, 7, 56, 76, 76, 7, 67, 6, 76, 75, 6, 567, 56, 578, 58, 6, 465 ] x = {} n = len(values) capacity = 500 model = Model('knapsack') # define variables as binaries for i in range(n): x[i] = model.addVar(name=f'x_{i}', vtype='B') # add constraint so that the sum of weights is less than or equal to capacity model.addCons(quicksum(x[i] * weights[i] for i in range(n)) <= capacity) # set the objective to the negative of sum of values to maximize value model.setObjective(quicksum(-x[i] * values[i] for i in range(n))) # optimize model.optimize() sol = model.getBestSol() # print results for i in range(n): print(sol[x[i]])
def scip_solver_2(customers, customer_count, vehicle_count, vehicle_capacity): model = Model("vrp") c_range = range(0, customer_count) cd_range = range(1, customer_count) x, d, w, v = {}, {}, {}, {} for i in c_range: for j in c_range: d[i, j] = length(customers[i], customers[j]) w[i, j] = customers[i].demand + customers[j].demand if j > i and i == 0: # depot x[i, j] = model.addVar(ub=2, vtype="I", name="x(%s,%s)" % (i, j)) elif j > i: x[i, j] = model.addVar(ub=1, vtype="I", name="x(%s,%s)" % (i, j)) model.addCons( quicksum(x[0, j] for j in cd_range) <= 2 * vehicle_count, "DegreeDepot") for i in cd_range: model.addCons( quicksum(x[j, i] for j in c_range if j < i) + quicksum(x[i, j] for j in c_range if j > i) == 2, "Degree(%s)" % i) model.setObjective( quicksum(d[i, j] * x[i, j] for i in c_range for j in c_range if j > i), "minimize") mip_gaps = [0.0] runs = 0 start = datetime.now() for gap in mip_gaps: model.freeTransform() model.setRealParam("limits/gap", gap) model.setRealParam("limits/time", 60 * 20) # Time limit in seconds edges, final_edges, runs = optimize(customer_count, customers, model, vehicle_capacity, vehicle_count, x) run_time = datetime.now() - start print(edges) print(final_edges) output = [[]] * vehicle_count for i in range(vehicle_count): output[i] = [] current_item = None if len(final_edges) > 0: for e in final_edges: if e[0] == 0: current_item = e break if current_item: a = current_item[0] current_node = current_item[1] output[i].append(customers[current_node]) final_edges.remove(current_item) searching_connections = True while searching_connections and len(final_edges) > 0: for edge in final_edges: found_connection = False a_edge = edge[0] b_edge = edge[1] if b_edge == current_node and a_edge == 0: final_edges.remove(edge) break if a_edge == current_node: output[i].append(customers[b_edge]) current_node = b_edge found_connection = True elif b_edge == current_node: output[i].append(customers[a_edge]) current_node = a_edge found_connection = True if found_connection: final_edges.remove(edge) break if not found_connection: searching_connections = False print(output) sol = model.getBestSol() obj = model.getSolObjVal(sol) print("RUN TIME: %s" % str(run_time)) print("NUMBER OF OPTIMIZATION RUNS: %s" % runs) return obj, output
#!/usr/bin/env python from pyscipopt import Model model = Model("test") x = model.addVar() y = model.addVar() z = model.addVar() model.addCons(x + y + z == 32) # Set objective function model.setObjective(x + y, "minimize") # model.hideOutput() model.writeLP('./Lp.lp')
def test_cuttingstock(): # create solver instance s = Model("CuttingStock") s.setPresolve(0) # creating a pricer pricer = CutPricer() s.includePricer(pricer, "CuttingStockPricer", "Pricer to identify new cutting stock patterns") # item widths widths = [14, 31, 36, 45] # width demand demand = [211, 395, 610, 97] # roll length rollLength = 100 assert len(widths) == len(demand) # adding the initial variables cutPatternVars = [] varNames = [] varBaseName = "Pattern" patterns = [] initialCoeffs = [] for i in range(len(widths)): varNames.append(varBaseName + "_" + str(i)) cutPatternVars.append(s.addVar(varNames[i], obj=1.0)) # adding a linear constraint for the knapsack constraint demandCons = [] for i in range(len(widths)): numWidthsPerRoll = float(int(rollLength / widths[i])) demandCons.append( s.addCons(numWidthsPerRoll * cutPatternVars[i] >= demand[i], separate=False, modifiable=True)) newPattern = [0] * len(widths) newPattern[i] = numWidthsPerRoll patterns.append(newPattern) # Setting the pricer_data for use in the init and redcost functions pricer.data = {} pricer.data['var'] = cutPatternVars pricer.data['cons'] = demandCons pricer.data['widths'] = widths pricer.data['demand'] = demand pricer.data['rollLength'] = rollLength pricer.data['patterns'] = patterns # solve problem s.optimize() # print original data printWidths = '\t'.join(str(e) for e in widths) print('\nInput Data') print('==========') print('Roll Length:', rollLength) print('Widths:\t', printWidths) print('Demand:\t', '\t'.join(str(e) for e in demand)) # print solution widthOutput = [0] * len(widths) print('\nResult') print('======') print('\t\tSol Value', '\tWidths\t', printWidths) for i in range(len(pricer.data['var'])): rollUsage = 0 solValue = round(s.getVal(pricer.data['var'][i])) if solValue > 0: outline = 'Pattern_' + str(i) + ':\t' + str( solValue) + '\t\tCuts:\t' for j in range(len(widths)): rollUsage += pricer.data['patterns'][i][j] * widths[j] widthOutput[j] += pricer.data['patterns'][i][j] * solValue outline += str(pricer.data['patterns'][i][j]) + '\t' outline += 'Usage:' + str(rollUsage) print(outline) print('\t\t\tTotal Output:', '\t'.join(str(e) for e in widthOutput))