forked from seanys/Transportation-and-Optimization-Notes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcolumn_generation.py
167 lines (129 loc) · 5.07 KB
/
column_generation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
'''
来源: https://gist.github.com/Bart6114/8414730
原理:选择随机变量作为Restricted Master Problem,通过Pricing过程,求解
SubProblem,如果符合条件,则添加新的Pattern,再重新进行Pricing,达到标准
后实验停止。
'''
from pulp import * # 该Column Generation基于Pulp
import random # 生成随机数
class MasterProblem:
'''主问题
随机选择部分变量作为主问题的初始Pattern,基础求解出来后,开始
求解Subproblem,如果有新的Pattern则加入,没有的话则采用整数
规划方式进行求解
'''
def __init__(self, maxValue, itemLengths, itemDemands, initialPatterns, problemname):
self.maxValue=maxValue
self.itemLengths=itemLengths
self.itemDemands=itemDemands
self.initialPatterns=initialPatterns
self.prob = LpProblem(problemname,LpMinimize) # 建立初始问题
self.obj = LpConstraintVar("obj") # 建立目标函数的约束变量
self.prob.setObjective(self.obj)
self.PatternVars = []
self.constraintList = [] # 约束函数部分
for i,x in enumerate(itemDemands): # 建立主问题的全部约束
var = LpConstraintVar("C"+str(i),LpConstraintGE,x)
self.constraintList.append(var)
self.prob += var
for i,x in enumerate(self.initialPatterns): # 建立初始的解
temp = []
for j,y in enumerate(x):
if y > 0:
temp.append(j)
var = LpVariable("Pat"+str(i) , 0, None, LpContinuous, lpSum(self.obj+[self.constraintList[v] for v in temp])) # create decision variable: will determine how often pattern x should be produced
self.PatternVars.append(var)
def solve(self):
self.prob.writeLP('res/prob.lp')
self.prob.solve()
return [self.prob.constraints[i].pi for i in self.prob.constraints]
def addPattern(self,pattern):
'''增加新的Pattern'''
self.initialPatterns.append(pattern)
temp = []
for j,y in enumerate(pattern):
if y>0:
temp.append(j)
var = LpVariable("Pat"+str(len(self.initialPatterns)) , 0, None, LpContinuous, lpSum(self.obj+[pattern[v]*self.constraintList[v] for v in temp]))
self.PatternVars.append(var)
def startSub(self,duals):
'''解SubProblem求解新的Pattern'''
newSubProb = SubProblem(duals,self.itemLengths,self.maxValue)
pattern = newSubProb.returnPattern()
return pattern
def setRelaxed(self,relaxed):
'''如果没有找到新的Patterns,那么按照整数规划求解'''
if relaxed == False:
for var in self.prob.variables():
var.cat = LpInteger
def getObjective(self):
return value(self.prob.objective)
def getUsedPatterns(self):
usedPatternList=[]
for i,x in enumerate(self.PatternVars):
if value(x)>0:
usedPatternList.append((value(x),self.initialPatterns[i]))
return usedPatternList
class SubProblem(object):
'''子问题建立
思路:通过对偶问题求目标参数,以及约束,解出后如果目标函数符合
条件,则在Pattern中增加新的变量,然后进入下一轮求解
'''
def __init__(self,duals, itemLengths,maxValue):
self.subprob = LpProblem("Sub problem solver",LpMinimize)
self.varList = [LpVariable('S'+str(i),0,None,LpInteger) for i,x in enumerate(duals)]
self.subprob += -lpSum([duals[i]*x for i,x in enumerate(self.varList)]) # 建立对偶问题
self.subprob += lpSum([itemLengths[i]*x for i,x in enumerate(self.varList)]) <= maxValue
self.subprob.writeLP('res/subprob.lp')
self.subprob.solve()
self.subprob.roundSolution()
def returnPattern(self):
'''判断是否可以解'''
pattern = False
if value(self.subprob.objective) < -1.00001:
pattern = []
for v in self.varList:
pattern.append(value(v))
return pattern
random.seed(2012)
nrItems = 12
lengthSheets=20
itemLengths=[]
itemDemands=[]
# 生成整个的约束变量
while len(itemLengths) != nrItems:
length = random.randint(5, lengthSheets-2)
demand = random.randint(5, 100)
if length not in itemLengths:
itemLengths.append(length)
itemDemands.append(demand)
print("Item lengts : %s" % itemLengths)
print("Item demands : %s\n\n" % itemDemands)
# 随机生成问题
patterns = []
print("Generating start patterns:")
for x in range(nrItems):
temp = [0.0 for y in range(x)]
temp.append(1.0)
temp += [0.0 for y in range(nrItems-x-1)]
patterns.append(temp)
print(temp)
# 解Master Problem
print("\n\nTrying to solve problem")
CGprob = MasterProblem(lengthSheets,itemLengths,itemDemands,patterns,'1D cutting stock')
# 进行持续性松弛,解SubProblem,直到没有更优解
relaxed = True
while relaxed == True:
duals = CGprob.solve()
newPattern = CGprob.startSub(duals)
print('New pattern: %s' % newPattern)
if newPattern:
CGprob.addPattern(newPattern) # 找到新的Pattern就开始求解
else:
CGprob.setRelaxed(False) # 没有找到新的Pattern,就按照整数规划方式求解
CGprob.solve()
relaxed=False
print("\n\nSolution: %s sheets required" % CGprob.getObjective())
t=CGprob.getUsedPatterns()
for i,x in enumerate(t):
print("Pattern %s: selected %s times %s" % (i,x[0],x[1]))