数据集
Bin packing - one-dimensional
整数规划建模
import pyscipopt
import re
import time
import math
#记录每个函数执行的时间
loop = 1
def timeLog(f):
def wrapper(*args, **kw):
global loop
now = time.perf_counter()
res = f(*args, **kw)
print("%s-%s:"%(loop, f.__name__), time.perf_counter()-now)
loop += 1
return res
return wrapper
class Case:
def __init__(self, name, box, goods, boxUsedMin):
self.name = name
self.box = box
self.goods = goods
self.boxUsedMin = boxUsedMin
def __repr__(self):
return str([self.name, self.box, self.goods, self.boxUsedMin])
def dataRead():
data_paths = [r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack1.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack2.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack3.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack4.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack5.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack6.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack7.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack8.txt"]
cases = []
for path in data_paths:
f = open(path)
#一个文件中的case个数
num = int(f.readline())
for _ in range(num):
name = f.readline().replace('\n', '').strip()
row = f.readline().replace('\n', '').strip()
row = [float(w) for w in re.split(" ", row)]
box, numGoods, boxUsedMin = row[0], int(row[1]), int(row[2])
goods = []
for _ in range(numGoods):
goods.append(float(f.readline()))
cases.append(Case(name, box, goods, boxUsedMin))
return cases
def caseStandardization(cases):
for case in cases:
#确认需要乘多少
n = 1
while case.box * n != int(case.box * n):
n *= 10
for good in case.goods:
while good * n != int(good * n):
n *= 10
#都乘以这个数,化为整数
case.box = int(case.box * n)
for i in range(len(case.goods)):
case.goods[i] = int(case.goods[i] * n)
#启发式方法得到箱子数上界
def NF(case):
L_goods = [[]]
box = case.box
boxLeft = box
for good in case.goods:
if good <= boxLeft:
boxLeft -= good
L_goods[-1].append(good)
else:
boxLeft = box - good
L_goods.append([good])
return len(L_goods)
def IPBPP1D(case, time_limit = 1000, printLog = False):
m = NF(case)
n = len(case.goods)
W = case.goods
V = case.box
mMin = math.ceil(sum(case.goods)/case.box)
model = pyscipopt.Model("IPBPP1D")
Y = [model.addVar(vtype="B", name="Y[%s]" % i) for i in range(m)]
X = [[model.addVar(vtype="B", name="X[%s,%s]" % (i, j)) for j in range(n)] for i in range(m)]
model.setObjective(pyscipopt.quicksum(Y[i] for i in range(m)), "minimize")
#每个箱子启用后才能进行装载
for i in range(m):
model.addCons(pyscipopt.quicksum(W[j]*X[i][j] for j in range(n)) <= V*Y[i])
#每个good都被装下
for j in range(n):
model.addCons(pyscipopt.quicksum(X[i][j] for i in range(m)) == 1)
#体积约束
model.addCons(pyscipopt.quicksum(Y[i] for i in range(m)) >= mMin)
# 设置求解时间
model.setRealParam("limits/time", time_limit)
if not printLog:
model.hideOutput()
model.optimize()
print("\ngap:", model.getGap())
# 拿结果
Y1 = [round(model.getVal(Y[i])) for i in range(m)]
X1 = [[round(model.getVal(X[i][j])) for j in range(n)] for i in range(m)]
return Y1, X1
if __name__ == '__main__':
cases = dataRead()
caseStandardization(cases)
case = cases[0]
Y, X = IPBPP1D(case, printLog=True)
启发式算法
import re
import time
from BPP.meta_heuristic.Two_opt import two_opt
#记录每个函数执行的时间
loop = 1
def timeLog(f):
def wrapper(*args, **kw):
global loop
now = time.perf_counter()
res = f(*args, **kw)
print("%s-%s:"%(loop, f.__name__), time.perf_counter()-now)
loop += 1
return res
return wrapper
class Case:
def __init__(self, name, box, goods, boxUsedMin):
self.name = name
self.box = box
self.goods = goods
self.boxUsedMin = boxUsedMin
def __repr__(self):
return str([self.name, self.box, self.goods, self.boxUsedMin])
def dataRead():
data_paths = [r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack1.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack2.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack3.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack4.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack5.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack6.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack7.txt",
r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/BPP1D/data/binpack8.txt"]
cases = []
for path in data_paths:
f = open(path)
#一个文件中的case个数
num = int(f.readline())
for _ in range(num):
name = f.readline().replace('\n', '').strip()
row = f.readline().replace('\n', '').strip()
row = [float(w) for w in re.split(" ", row)]
box, numGoods, boxUsedMin = row[0], int(row[1]), int(row[2])
goods = []
for _ in range(numGoods):
goods.append(float(f.readline()))
cases.append(Case(name, box, goods, boxUsedMin))
return cases
def caseStandardization(cases):
for case in cases:
#确认需要乘多少
n = 1
while case.box * n != int(case.box * n):
n *= 10
for good in case.goods:
while good * n != int(good * n):
n *= 10
#都乘以这个数,化为整数
case.box = int(case.box * n)
for i in range(len(case.goods)):
case.goods[i] = int(case.goods[i] * n)
#next fit,一个个的打开箱子,将物品装进去,如果装不下就开一个新的箱子
def NF(box, goods):
L_goods = [[]]
boxLeft = box
for good in goods:
if good <= boxLeft:
boxLeft -= good
L_goods[-1].append(good)
else:
boxLeft = box - good
L_goods.append([good])
return len(L_goods)
#first fit,检查所有非空箱子,找第一个非空箱子放进去
def FF(box, goods):
L_goods = [[]]
L_boxLeft = [box]
for good in goods:
flag = False
for i in range(len(L_boxLeft)):
if good <= L_boxLeft[i]:
L_boxLeft[i] -= good
L_goods[i].append(good)
flag = True
break
if not flag:
L_boxLeft.append(box - good)
L_goods.append([good])
return len(L_goods)
#first fit Decreasing,先降序排序,再FF
def FFD(box, goods):
goods1 = sorted(goods, reverse=True)
return FF(box, goods1)
#best fit,检查所有非空箱子,找剩余空间最小的放进去
def BF(box, goods):
L_goods = [[]]
L_boxLeft = [box]
for good in goods:
idx, leftMin = None, None
for i in range(len(L_boxLeft)):
if good <= L_boxLeft[i]:
if leftMin is None or leftMin > L_boxLeft[i]:
idx = i
leftMin = L_boxLeft[i]
if idx is not None:
L_boxLeft[idx] -= good
L_goods[idx].append(good)
else:
L_boxLeft.append(box - good)
L_goods.append([good])
return len(L_goods)
#best fit Decreasing,先降序排序,再BF
def BFD(box, goods):
goods1 = sorted(goods, reverse=True)
return BF(box, goods1)
#打散顺序,然后采用FF和BF尝试
def twoOpt(box, goods):
goods1 = sorted(goods, reverse=True)
X = goods1
def f(X, **kwargs):
return FF(kwargs['box'], X)
def f2(X, **kwargs):
return BF(kwargs['box'], X)
def c(X):
return True
def e(x,y):
if x == y:
return True
return False
X1 = two_opt(X, f, c, e, False, 100, box=box)
X2 = two_opt(X, f2, c, e, False, 100, box=box)
return min(FF(box, X1),BF(box, X2))
def runOne(case):
box, goods = case.box, case.goods
#NF
boxUsedNF = NF(box, goods)
#FF
boxUsedFF = FF(box, goods)
boxUsedFFD = FFD(box, goods)
#BF
boxUsedBF = BF(box, goods)
boxUsedBFD = BFD(box, goods)
#twoOpt
boxUsedTwoOpt = twoOpt(box, goods)
print("\nname: ", case.name)
print("opt: ", case.boxUsedMin)
print("boxUsedNF: ", boxUsedNF)
print("boxUsedFF: ", boxUsedFF)
print("boxUsedFFD: ", boxUsedFFD)
print("boxUsedBF: ", boxUsedBF)
print("boxUsedBFD: ", boxUsedBFD)
print("boxUsedTwoOpt: ", boxUsedTwoOpt)
return case.boxUsedMin, boxUsedNF, boxUsedFF, boxUsedFFD, boxUsedBF, boxUsedBFD, boxUsedTwoOpt
def gapCount(L_opt, L):
L_gap = [(L[i]-L_opt[i])/L_opt[i] for i in range(len(L_opt))]
return sum(L_gap)/len(L_gap)
def runAll(cases):
L_opt = []
L_NF = []
L_FF = []
L_FFD = []
L_BF = []
L_BFD = []
L_twoOpt = []
for case in cases:
boxUsedMin, boxUsedNF, boxUsedFF, boxUsedFFD, boxUsedBF, boxUsedBFD, boxUsedTwoOpt = runOne(case)
L_opt.append(boxUsedMin)
L_NF.append(boxUsedNF)
L_FF.append(boxUsedFF)
L_FFD.append(boxUsedFFD)
L_BF.append(boxUsedBF)
L_BFD.append(boxUsedBFD)
L_twoOpt.append(boxUsedTwoOpt)
#统计gap
gapNF = gapCount(L_opt, L_NF)
gapFF = gapCount(L_opt, L_FF)
gapFFD = gapCount(L_opt, L_FFD)
gapBF = gapCount(L_opt, L_BF)
gapBFD = gapCount(L_opt, L_BFD)
gaptwoOpt = gapCount(L_opt, L_twoOpt)
print("\ngapNF: ", gapNF)
print("gapFF: ", gapFF)
print("gapFFD: ", gapFFD)
print("gapBF: ", gapBF)
print("gapBFD: ", gapBFD)
print("gaptwoOpt: ", gaptwoOpt)
if __name__ == '__main__':
cases = dataRead()
caseStandardization(cases)
runAll(cases)