用gurobi进行仓网建模伪代码

背景

现状:由dg和cq两个仓往全国31个省会城市利用空运和陆运发送货物。

规划
在不影响时效的情况下,希望以成本最少为原则在候选wh个城市中最多选择两个中转仓中转货物

约束条件

  1. 当有两个中转仓时,则dg和cq仓发往同一个地点的货物不能分别走不同的中转仓进行中转
  2. 当中转仓时效超过上限时,则该条线路不能选择该中转仓进行中转
  3. 若直发的成本较优时,则可以不选择该中转仓进行中转
  4. dg和cq到中转仓选择干线运输,到下游城市选择支线运输

模型构建

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

仓网模型伪代码

import os
import json
from dataprocessor import *
from config import Config
from gurobipy import *
import pandas as pd

class WarehouseSelection(object):
    def __init__(self, data, config):
        self.data = data
        self.config = config
        self.model = None

    def run(self):
        print('..')
        l_wh = self.data.l_wh
        l_cus = self.data.l_cus
        d_line = self.data.d_line
        d_cus = self.data.d_cus
        M = 100000

        '''#### model declare ####'''
        model = Model('warehouse_location')

        '''#### define decision variables ####'''
        var_wh = model.addVars(l_wh, vtype=GRB.BINARY, name='wh')
        var_dg_wh_cus = model.addVars(l_wh, l_cus, vtype=GRB.BINARY, name='dg_wh_cus')
        var_cq_wh_cus = model.addVars(l_wh, l_cus, vtype=GRB.BINARY, name='cq_wh_cus')
        var_dg_cus = model.addVars(l_cus, vtype=GRB.BINARY, name='dg_cus')
        var_cq_cus = model.addVars(l_cus, vtype=GRB.BINARY, name='cq_cus')


        '''#### define objective function ####'''
        print('objective function')
        wh_transit_cost = self.compute_wh_transit_cost(var_dg_wh_cus, var_cq_wh_cus)
        src_transit_cost = self.compute_src_transit_cost(var_dg_cus, var_cq_cus)
        wh_cost = self.compute_wh_cost(var_wh, var_dg_wh_cus, var_cq_wh_cus)
        cost = wh_cost + wh_transit_cost + src_transit_cost

        model.setObjective(cost, GRB.MINIMIZE)

        '''#### define model constraints ####'''
        # 1. time constraints
        for wh in l_wh:
            for cus in l_cus:
                model.addConstr(var_dg_wh_cus[wh, cus] * d_line[wh, cus]['slv_50%'] <= d_cus[cus]['dg_wh_slv'])
                model.addConstr(var_cq_wh_cus[wh, cus] * d_line[wh, cus]['slv_50%'] <= d_cus[cus]['cq_wh_slv'])

        # 2.当选中一个中转仓往下游客户cus发货,那么不可能有另一个中转仓也往下游cus发货
        for cus in l_cus:
            for wh in l_wh:
                model.addConstr(var_dg_wh_cus[wh, cus] + quicksum(var_cq_wh_cus[w, cus] for w in l_wh if w != wh) <= 1)
                model.addConstr(var_cq_wh_cus[wh, cus] + quicksum(var_dg_wh_cus[w, cus] for w in l_wh if w != wh) <= 1)

        # 3. dg和cq的货物发到下游每个城市只存在东莞直发或者是某个中转仓转发
        for cus in l_cus:
            model.addConstr(var_dg_cus[cus] + quicksum(var_dg_wh_cus[wh, cus] for wh in l_wh) == 1)
            model.addConstr(var_cq_cus[cus] + quicksum(var_cq_wh_cus[wh, cus] for wh in l_wh) == 1)

        # 4.若存在某个中转仓发货到下游某城市,则该中转仓必须被选中
        for wh in l_wh:
            model.addConstr(quicksum(var_dg_wh_cus[wh, cus] for cus in l_cus) + quicksum(var_cq_wh_cus[wh, cus] for cus in l_cus) <= M * var_wh[wh])

        # 5.最多只有两个中转仓被选中
        model.addConstr(quicksum(var_wh[wh] for wh in l_wh) <= 2)

        # model.addConstr(quicksum(var_wh[wh] for wh in l_wh) >= 1)

        '''#### solve model ####'''
        model.optimize()

        """######## check the result ######### """
        if model.Status == GRB.OPTIMAL:
            print('the warehouse selection optimized successfully !')
            print('the objective of the model is {}'.format(model.objVal))
            self.model = model
            print('dump model to file:\n')
            model.write('warehouse selection.lp')
            # get the variables
            self.wh = model.getAttr('x', var_wh)
            print("选中的中转仓是: " )
            print(self.wh)
            self.dg_cus = model.getAttr('x', var_dg_cus)
            print("由dg直发到下游的城市是: ")
            print(self.dg_cus)
            self.cq_cus = model.getAttr('x', var_cq_cus)
            print("由cq直发到下游的城市是: ")
            print(self.cq_cus)
            self.dg_wh_cus = model.getAttr('x', var_dg_wh_cus)
            print("由dg转中转仓到下游的城市是: ")
            print(self.dg_wh_cus)
            self.cq_wh_cus = model.getAttr('x', var_cq_wh_cus)
            print("由cq转中转仓到下游的城市是: ")
            print(self.cq_wh_cus)

            r_wh_transit_cost = self.compute_wh_transit_cost(self.dg_wh_cus, self.cq_wh_cus)
            print("中转仓运输成本:" + str(r_wh_transit_cost))
            r_src_transit_cost = self.compute_src_transit_cost(self.dg_cus, self.cq_cus)
            print("dg和cq干线成本:" + str(r_src_transit_cost))
            r_wh_cost = self.compute_wh_cost(self.wh, self.dg_wh_cus, self.cq_wh_cus)
            print("仓储成本:" + str(r_wh_cost))

        """######## output the detail ######### """
        self.compute_detail_cost()


        return

    def compute_detail_cost(self):
        abs_filepath = os.path.abspath(os.path.join(os.getcwd(), ".."))
        dg_wh_cus = self.dg_wh_cus
        cq_wh_cus = self.cq_wh_cus
        dg_cus = self.dg_cus
        cq_cus = self.cq_cus
        wh = self.wh

        dg_cus_df = pd.DataFrame(dg_cus, index=['dg_city']).T
        cq_cus_df = pd.DataFrame(cq_cus, index=['cq_city']).T
        dg_wh_cus_df = pd.DataFrame(dg_wh_cus, index=['dg_wh_city']).T
        cq_wh_cus_df = pd.DataFrame(cq_wh_cus, index=['dg_wh_city']).T

        dg_cus_df.to_excel(abs_filepath + "\\data\\dg_cus_df.xlsx")
        cq_cus_df.to_excel(abs_filepath + "\\data\\cq_cus_df.xlsx")
        dg_wh_cus_df.to_excel(abs_filepath + "\\data\\dg_wh_cus_df.xlsx")
        cq_wh_cus_df.to_excel(abs_filepath + "\\data\\cq_wh_cus_df.xlsx")


        return

    def compute_wh_transit_cost(self, var_dg_wh_cus, var_cq_wh_cus):
        d_truck = self.data.d_truck
        d_cus = self.data.d_cus
        d_line = self.data.d_line
        config = self.config

        truck_dg_cost = 0
        line_dg_cost = 0
        for cus in d_cus.keys():
            cus_dg_wgt = d_cus[cus]['dg_wgt']
            for wh in d_truck.keys():
                truck_dg_cost += d_truck[wh]['dg_truck_cost'] * cus_dg_wgt / config.wgt_per_pallet / config.pallet_per_car * var_dg_wh_cus[wh, cus]
                line_dg_cost += (d_line[wh, cus]['base_price']  + (cus_dg_wgt - d_line[wh, cus]['base_wgt']) * \
                                 d_line[wh, cus]['cont_wgt']) * var_dg_wh_cus[wh, cus]

        truck_cq_cost = 0
        line_cq_cost = 0
        for cus in d_cus.keys():
            cus_cq_wgt = d_cus[cus]['cq_wgt']
            for wh in d_truck.keys():
                truck_cq_cost += d_truck[wh]['cq_truck_cost'] * cus_cq_wgt /config.wgt_per_pallet / config.pallet_per_car * var_cq_wh_cus[wh, cus]
                line_cq_cost += d_line[wh, cus]['cont_wgt'] * cus_cq_wgt * var_cq_wh_cus[wh, cus]

        wh_transit_cost = truck_dg_cost + line_dg_cost + truck_cq_cost + line_cq_cost
        return wh_transit_cost

    def compute_src_transit_cost(self, var_dg_cus, var_cq_cus):
        d_cus = self.data.d_cus

        air_dg_cost = 0
        car_dg_cost = 0
        for cus in d_cus.keys():
            cus_dg_wgt = d_cus[cus]['dg_wgt']
            air_dg_cost += d_cus[cus]['dg_air_price'] * cus_dg_wgt * var_dg_cus[cus]
            car_dg_cost += d_cus[cus]['dg_car_price'] * cus_dg_wgt * var_dg_cus[cus]

        air_cq_cost = 0
        car_cq_cost = 0
        for cus in d_cus.keys():
            cus_cq_wgt = d_cus[cus]['cq_wgt']
            air_cq_cost += d_cus[cus]['cq_air_price'] * cus_cq_wgt * var_cq_cus[cus]
            car_cq_cost += d_cus[cus]['cq_car_price'] * cus_cq_wgt * var_cq_cus[cus]

        src_transit_cost = air_dg_cost +car_dg_cost + air_cq_cost + car_cq_cost
        return src_transit_cost

    def compute_wh_cost(self, var_wh, var_dg_wh_cus, var_cq_wh_cus):
        config = self.config
        d_cus = self.data.d_cus
        d_wh = self.data.d_wh

        wh_cost = 0
        for wh in d_wh.keys():
            wh_wgt = 0
            for cus in d_cus.keys():
                wh_wgt += d_cus[cus]['dg_wgt'] * var_dg_wh_cus[wh, cus]
                wh_wgt += d_cus[cus]['cq_wgt'] * var_cq_wh_cus[wh, cus]
            wh_cost += wh_wgt / config.inbound_days_1m / config.wgt_per_pallet * config.turnover_days \
                      * config.wh_coeff * d_wh[wh]
        return wh_cost

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值