PySCIPOpt  4.3.0
Python Interface for the SCIP Optimization Suite
lotsizing_lazy.py
Go to the documentation of this file.
1 
3 """
4 Approaches:
5  - sils: solve the problem using the standard formulation
6  - sils_cut: solve the problem using cutting planes
7 
8 Copyright (c) by Joao Pedro PEDROSO and Mikio KUBO, 2012
9 """
10 from pyscipopt import Model, Conshdlr, quicksum, multidict, SCIP_RESULT, SCIP_PRESOLTIMING, SCIP_PROPTIMING
11 
12 class Conshdlr_sils(Conshdlr):
13 
14  def addcut(self, checkonly, sol):
15  D,Ts = self.data
16  y,x,I = self.model.data
17  cutsadded = False
18 
19  for ell in Ts:
20  lhs = 0
21  S,L = [],[]
22  for t in range(1,ell+1):
23  yt = self.model.getSolVal(sol, y[t])
24  xt = self.model.getSolVal(sol, x[t])
25  if D[t,ell]*yt < xt:
26  S.append(t)
27  lhs += D[t,ell]*yt
28  else:
29  L.append(t)
30  lhs += xt
31  if lhs < D[1,ell]:
32  if checkonly:
33  return True
34  else:
35  # add cutting plane constraint
36  self.model.addCons(quicksum([x[t] for t in L]) + \
37  quicksum(D[t, ell] * y[t] for t in S)
38  >= D[1, ell], removable = True)
39  cutsadded = True
40  return cutsadded
41 
42  def conscheck(self, constraints, solution, checkintegrality, checklprows, printreason, completely):
43  if not self.addcut(checkonly = True, sol = solution):
44  return {"result": SCIP_RESULT.INFEASIBLE}
45  else:
46  return {"result": SCIP_RESULT.FEASIBLE}
47 
48  def consenfolp(self, constraints, nusefulconss, solinfeasible):
49  if self.addcut(checkonly = False):
50  return {"result": SCIP_RESULT.CONSADDED}
51  else:
52  return {"result": SCIP_RESULT.FEASIBLE}
53 
54  def conslock(self, constraint, locktype, nlockspos, nlocksneg):
55  pass
56 
57 def sils(T,f,c,d,h):
58  """sils -- LP lotsizing for the single item lot sizing problem
59  Parameters:
60  - T: number of periods
61  - P: set of products
62  - f[t]: set-up costs (on period t)
63  - c[t]: variable costs
64  - d[t]: demand values
65  - h[t]: holding costs
66  Returns a model, ready to be solved.
67  """
68  model = Model("single item lotsizing")
69  Ts = range(1,T+1)
70  M = sum(d[t] for t in Ts)
71  y,x,I = {},{},{}
72  for t in Ts:
73  y[t] = model.addVar(vtype="I", ub=1, name="y(%s)"%t)
74  x[t] = model.addVar(vtype="C", ub=M, name="x(%s)"%t)
75  I[t] = model.addVar(vtype="C", name="I(%s)"%t)
76  I[0] = 0
77 
78  for t in Ts:
79  model.addCons(x[t] <= M*y[t], "ConstrUB(%s)"%t)
80  model.addCons(I[t-1] + x[t] == I[t] + d[t], "FlowCons(%s)"%t)
81 
82  model.setObjective(\
83  quicksum(f[t]*y[t] + c[t]*x[t] + h[t]*I[t] for t in Ts),\
84  "minimize")
85 
86  model.data = y,x,I
87  return model
88 
89 def sils_cut(T,f,c,d,h, conshdlr):
90  """solve_sils -- solve the lot sizing problem with cutting planes
91  - start with a relaxed model
92  - used lazy constraints to elimitate fractional setup variables with cutting planes
93  Parameters:
94  - T: number of periods
95  - P: set of products
96  - f[t]: set-up costs (on period t)
97  - c[t]: variable costs
98  - d[t]: demand values
99  - h[t]: holding costs
100  Returns the final model solved, with all necessary cuts added.
101  """
102  Ts = range(1,T+1)
103 
104  model = sils(T,f,c,d,h)
105  y,x,I = model.data
106 
107  # relax integer variables
108  for t in Ts:
109  model.chgVarType(y[t], "C")
110  model.addVar(vtype="B", name="fake") # for making the problem MIP
111 
112  # compute D[i,j] = sum_{t=i}^j d[t]
113  D = {}
114  for t in Ts:
115  s = 0
116  for j in range(t,T+1):
117  s += d[j]
118  D[t,j] = s
119 
120  #include the lot sizing constraint handler
121  model.includeConshdlr(conshdlr, "SILS", "Constraint handler for single item lot sizing",
122  sepapriority = 0, enfopriority = -1, chckpriority = -1, sepafreq = -1, propfreq = -1,
123  eagerfreq = -1, maxprerounds = 0, delaysepa = False, delayprop = False, needscons = False,
124  presoltiming = SCIP_PRESOLTIMING.FAST, proptiming = SCIP_PROPTIMING.BEFORELP)
125  conshdlr.data = D,Ts
126 
127  model.data = y,x,I
128  return model
129 
131  """mk_example: book example for the single item lot sizing"""
132  T = 5
133  _,f,c,d,h = multidict({
134  1 : [3,1,5,1],
135  2 : [3,1,7,1],
136  3 : [3,3,3,1],
137  4 : [3,3,6,1],
138  5 : [3,3,4,1],
139  })
140 
141  return T,f,c,d,h
142 
143 if __name__ == "__main__":
144  T,f,c,d,h = mk_example()
145 
146  model = sils(T,f,c,d,h)
147  y,x,I = model.data
148  model.optimize()
149  print("\nOptimal value [standard]:",model.getObjVal())
150  print("%8s%8s%8s%8s%8s%8s%12s%12s" % ("t","fix","var","h","dem","y","x","I"))
151  for t in range(1,T+1):
152  print("%8d%8d%8d%8d%8d%8.1f%12.1f%12.1f" % (t,f[t],c[t],h[t],d[t],model.getVal(y[t]),model.getVal(x[t]),model.getVal(I[t])))
153 
154  conshdlr = Conshdlr_sils()
155  model = sils_cut(T,f,c,d,h, conshdlr)
156  model.setBoolParam("misc/allowstrongdualreds", 0)
157  model.optimize()
158  y,x,I = model.data
159  print("\nOptimal value [cutting planes]:",model.getObjVal())
160  print("%8s%8s%8s%8s%8s%8s%12s%12s" % ("t","fix","var","h","dem","y","x","I"))
161  for t in range(1,T+1):
162  print("%8d%8d%8d%8d%8d%8.1f%12.1f%12.1f" % (t,f[t],c[t],h[t],d[t],model.getVal(y[t]),model.getVal(x[t]),model.getVal(I[t])))
pyscipopt.expr.quicksum
def quicksum(termlist)
Definition: expr.pxi:357
lotsizing_lazy.sils
def sils(T, f, c, d, h)
Definition: lotsizing_lazy.py:57
pyscipopt.conshdlr.conslock
def conslock(self, constraint, locktype, nlockspos, nlocksneg)
Definition: conshdlr.pxi:90
pyscipopt.conshdlr.conscheck
def conscheck(self, constraints, solution, checkintegrality, checklprows, printreason, completely)
Definition: conshdlr.pxi:71
pyscipopt.conshdlr.consenfolp
def consenfolp(self, constraints, nusefulconss, solinfeasible)
Definition: conshdlr.pxi:56
lotsizing_lazy.mk_example
def mk_example()
Definition: lotsizing_lazy.py:130
pyscipopt.Multidict.multidict
def multidict(D)
Definition: Multidict.py:3
lotsizing_lazy.sils_cut
def sils_cut(T, f, c, d, h, conshdlr)
Definition: lotsizing_lazy.py:89