90、一维装箱

数据集

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)


你可能感兴趣的:(python,开发语言)