面对Flow-shop调度问题如何优化?可用MindOpt来决策

生产调度

生产调度是组织执行生产进度计划的工作。现代工业企业,生产环节、协助关系复杂,情况变化快,如果某一措施没有按期实现,常常会波及整个生产系统的运行。因此,加强生产调度工作,对于及时了解、掌握生产进度,研究分析影响生产的各种因素,根据不同情况采取相应对策,使差距缩小或恢复正常是非常重要的。

流线型调度问题- Flow shop

Flow-shop的调度问题可以描述为:已知条件为有一批k个需要n道工序进行加工的工件,分别在n台不同的机器上进行加工,并且加工的顺序是一致的并且给定的,任一工件j(1<=j<=m)的l工序(1<=l<=n)的生产时间是已知的,要求合理地调度各工件的各生产工序在每台机器上的顺序。
Flow-shop特征:

  1. 各工件均需在所有机器(集)上加工;
  2. 每个工件的各操作仅能在某一台机器(集)上加工;
  3. 所有工件预先给定工艺路线,且工艺路线相同;
  4. 工件不可重入。

Flow Shop 是调度领域中的经典模型:

  • 给定一组机器和一批工件,所有工件都按相同顺序依次流过这些机器;
  • 工件在各台机器上的加工时长为给定值,一旦工件进入机器的时长已达相应加工时长,工件立即离开该机器;
  • 在任何时刻,一台机器仅能加工最多一个工件;
  • 优化的目标为最小化makespan,即最后完成所有加工的时间;
  • 决策为确定工件之间的先后顺序。

image.png

该问题可以通过黑盒方法或混合整数规划的方法进行求解,在求解过程中,对某个候选解与理论最优解的距离进行估计,可以帮助我们评估解的质量。为获得下界的估计,我们可以松弛混合整数规划模型中的整数约束,得到一个线性规划,求解该松弛问题,即可得到原问题的一个下界。

Flow Shop 调度的MIP模型及其LP松弛

变量

  • x i j x_{ij} xij, 工件 i i i 比工件 j j j 先加工时取 1;否则取 0;( i , j ∈ { 1 , … , J } ,    i ≠ j i,j\in\{1,\ldots,J\},\; i\neq j i,j{1,,J},i=j)
  • s m i s_{mi} smi, 工件 i i i 比在机器 m m m 上开始加工的时间;( m ∈ { 1 , … , M } ,    i ∈ { 1 , … , J } m\in\{1,\ldots,M\},\; i\in\{1,\ldots,J\} m{1,,M},i{1,,J})
  • C max C_{\text{max}} Cmax,最大完工时间,即 makespan

目标

  • min ⁡    C max \min \; C_{\text{max}} minCmax

约束

  • 工件 i i i 比工件 j j j 先加工,则工件 j j j 必然比工件 i i i 后加工,即 x i j = 1 x_{ij}=1 xij=1 时, x j i = 0 x_{ji}=0 xji=0,反之亦然,因此,我们有: x i j + x j i = 1 ,    i , j = 1 , … J ,    i ≠ j x_{ij}+x_{ji} = 1, \; i,j=1,\ldots J, \; i\neq j xij+xji=1,i,j=1,J,i=j
  • 当工件 i i i 比工件 j j j 先加工,在任何机器上工件 j j j的开始时间都不早于工件 i i i的结束时间(即 s m i + P i , m s_{mi}+P_{i,m} smi+Pi,m),用 Z 表示某一“足够大”的正实数,我们有: s m j ≥ s m i + P i , m + ( x i j − 1 ) Z ,    m = 1 , … , M ,    i , j = 1 , … , J ,    i ≠ j s_{mj} \geq s_{mi} + P_{i,m} + (x_{ij}-1)Z, \; m=1,\ldots,M, \; i,j=1,\ldots,J,\; i\neq j smjsmi+Pi,m+(xij1)Z,m=1,,M,i,j=1,,J,i=j
  • 工件在后续机器上的开始时间不得早于当前机器上的结束时间,即: s m + 1 , i ≥ s m i + P i , m ,    m = 1 , … , M − 1 ,    i = 1 , … , J s_{m+1,i} \geq s_{mi}+P_{i,m},\; m=1,\ldots,M-1,\; i=1,\ldots,J sm+1,ismi+Pi,m,m=1,,M1,i=1,,J
  • 据最大完工时间的定义,有: C max ≥ s M i + P i , M ,    i = 1 , … , J C_{\text{max}} \geq s_{Mi}+P_{i,M}, \; i=1,\ldots, J CmaxsMi+Pi,M,i=1,,J
  • 变量的取值范围:对任意 i , j ( i ≠ j ) , m i,j (i\neq j), m i,j(i=j),m x i j ∈ { 0 , 1 } ,    s m i ≥ 0 ,    C max ≥ 0 x_{ij}\in\{0,1\}, \; s_{mi}\geq 0,\;C_{\text{max}} \geq 0 xij{0,1},smi0,Cmax0

MIP模型

KaTeX parse error: Unknown column alignment: a at position 18: …egin{array}{rrca̲ll} \min\; & C_…

LP松弛模型

将上述MIP模型中的整数要求( x i j ∈ { 0 , 1 } x_{ij}\in\{0,1\} xij{0,1})化成区间约束: 0 ≤ x i j ≤ 1 0\leq x_{ij}\leq 1 0xij1,即得到相应的LP松弛:**


KaTeX parse error: Unknown column alignment: a at position 18: …egin{array}{rrca̲ll} \min\; & C_…


数据

假设有如下的数据(实际业务数据会更多)。下面我们将用如下数据,会在代码中体现。


# the flow shop scheduling instance ta001 from the Taillard Flow Shop Scheduling Benchmarks

#number of machines
M = 5 

#number of jobs
J = 20   

TA001_Proc_Times = [54,83,15,71,77,36,53,38,27,87,76,91,14,29,12,77,32,87,68,94, \
              79,3,11,99,56,70,99,60,5,56,3,61,73,75,47,14,21,86,5,77, \
              16,89,49,15,89,45,60,23,57,64,7,1,63,41,63,47,26,75,77,40, \
              66,58,31,68,78,91,13,59,49,85,85,9,39,41,56,40,54,77,51,31, \
              58,56,20,85,53,35,53,41,69,13,86,72,8,49,47,87,58,18,68,28]

2.使用MindOpt求解器的API

直接采用求解器的API,需要查阅API文档来理解API的意思,没有建模语言可读性高。请参阅https://solver.damo.alibaba.com/doc/html/API%20reference/API-python/index.html来查看PythonAPI的使用说明。

关于Python的例子,在使用文档的5.建模与优化求解章节有Python的示例。这里是个LP的问题,我们可以参考:https://solver.damo.alibaba.com/doc/html/model/lp/linear%20optimization-python.html

下面我们分两种方式描述在本平台环境中的运行方法:

方法1:cell中直接输入代码运行

请运行下面cell中的代码,点击本窗口上面的播放△运行,或者摁shift+enter键运行:

# LP_3_flowshop.py

'''
Lower Bound Calculation for Flow Shop Scheduling Optimization
with MindOpt LP Solver

This program builds linear program relaxation (LPR) for the flow shop scheduling
instance ta001 from the Taillard Flow Shop Scheduling Benchmarks, and solve
the LPR with the LP Solver of the MindOpt Optimization Suite.
'''

from mindoptpy import *

##############################
#model data
##############################

#number of machines
M = 5 

#number of jobs
J = 20   

#processing time data from the benchmark:
TA001_Proc_Times = [54,83,15,71,77,36,53,38,27,87,76,91,14,29,12,77,32,87,68,94, \
              79,3,11,99,56,70,99,60,5,56,3,61,73,75,47,14,21,86,5,77, \
              16,89,49,15,89,45,60,23,57,64,7,1,63,41,63,47,26,75,77,40, \
              66,58,31,68,78,91,13,59,49,85,85,9,39,41,56,40,54,77,51,31, \
              58,56,20,85,53,35,53,41,69,13,86,72,8,49,47,87,58,18,68,28]

#data utility function
def processTimeOf(m, j):
    '''
    m: int, index of a machine
    j: int, index of a job
    retrieve the processing time of job j on machine m
    '''
    i = m*J+j                    #the index in the data array
    return TA001_Proc_Times[i]   #the processing of job j at machine m

# the large enough number Z (usually referred to as bigM)
Z = 1.0e7

##############################
#setup and solve the model 
##############################


if __name__ == "__main__":
    '''
    call MindOpt to build and solve the LPR
    '''
    try:
        ###################################
        #step1: initialize MindOpt model 
        model = MdoModel()
        
        ###########################################
        #step2: build the linear programming model
        
        #2.1 setup the optimization direction/sense to 'min'
        model.set_int_attr('MinSense', 1)
        
        #2.2 setup variables
        INF = MdoModel.get_infinity()

        #lowerbound, upperbound, coefficient in objective
        cmax = model.add_var(0.0, INF, 1.0, None, 'Cmax', False)
        
        s = {}
        for m in range(M):
            for i in range(J):
                sname = 's_%d_%d'%(m,i)
                s[sname] = model.add_var(0.0, INF, 0.0,None,sname,False)
        
        x = {}
        for i in range(J):
            for j in range(J):
                if i != j:
                    xname = 'x_%d_%d'%(i,j)
                    x[xname] = model.add_var(0.0, 1.0, 0.0, None, xname, False)

        #2.3 setup constraints
        
        # x_ij + x_ji = 1
        for i in range(J):
            for j in range(J):
                if i<j:
                    cname = 'ExclusiveOrder_%d_%d'%(i,j)
                    expr = MdoExprLinear()
                    expr += x['x_%d_%d'%(i,j)]+ x['x_%d_%d'%(j,i)]
                    model.add_cons(1.0, 1.0, expr, cname)

        # s_mj >= s_mi + P_im + (x_ij -1) Z
        # => s_mi + Z x_ij - s_mj <= Z - P_im
        for m in range(M):
            for i in range(J):
                for j in range(J):
                    if i != j:
                        cname = 'Following_%d_%d_%d'%(m,i,j)
                        expr = MdoExprLinear()
                        expr += s['s_%d_%d'%(m,i)] + Z*x['x_%d_%d'%(i,j)] - s['s_%d_%d'%(m,j)]
                        rub = Z - processTimeOf(m,i) # Z - P_im
                        model.add_cons(-INF, rub, expr, cname)

        #s_(m+1),i >= s_mi + P_mi
        # => s_(m+1)i - s_mi >= P_mi
        for m in range(M-1):
            for i in range(J):
                cname='NextStart_%d_%d'%(m,i)
                proctm = processTimeOf(m,i)
                expr = MdoExprLinear()
                expr += s['s_%d_%d'%(m+1,i)] - s['s_%d_%d'%(m,i)]
                model.add_cons(proctm, INF, expr, cname)
        
        
        #cmax >= s_Mi + P_iM
        # => cmax - s_Mi >= P_iM
        for i in range(J):
            m = M-1
            cname = 'Cmax_%d'%(i)
            expr = MdoExprLinear()
            expr += cmax - s['s_%d_%d'%(m,i)]
            proctm = processTimeOf(m,i)
            model.add_cons(proctm, INF, expr, cname)
        

        #optional step: write to LP file for further use
        model.write_prob('model/LP_3_flowshop_ta001.lp')
        
        ###########################################
        #step 3: Serialize the model and settings for further submission
        
        model.set_int_param('NumThreads', 4)
        model.set_real_param('MaxTime', 3600.0)

        # Step 3. Solve the problem and populate the result.
        model.solve_prob()
        model.display_results()
        time.sleep(1) #for print

        status_code, status_msg = model.get_status()

        if status_msg == "OPTIMAL":
            print("----\n")

            model.write_soln('model/LP_3_flowshop_ta001.sol')

            print("The solver terminated with an OPTIMAL status (code {0}).".format(status_code))

            print("目标函数总收益是: {0}".format(model.get_real_attr("PrimalObjVal")))
            
            '''# 打印内容长
            print("原始解是:")
            for var_name,var_val in s.items():
                primal_soln = var_val.get_real_attr("PrimalSoln")
                print("{0:>20} : {1}".format(var_name,primal_soln))
            for var_name,var_val in x.items():
                primal_soln = var_val.get_real_attr("PrimalSoln")
                print("{0:>20} : {1}".format(var_name,primal_soln))
            '''
        else:
            print("Optimizer terminated with a(n) {0} status (code {1}).".format(status_msg, status_code))

    except MdoError as e:
        print("Received Mindopt exception.")
        print(" - Code          : {}".format(e.code))
        print(" - Reason        : {}".format(e.message))
    except Exception as e:
        print("Received exception.")
        print(" - Reason        : {}".format(e))
    finally:
        # Step 4. Free the model.
        model.free_mdl()

运行之后,得到如下结果:

Start license validation (current time : 17-JAN-2023 23:54:32).
License validation terminated. Time : 0.003s

Concurrent optimization started.
 - Num. threads       : 4
 - Num. optimizers    : 2
 - Registered optimizers.
   +                  : Simplex method (1 thread, enabled output)
   +                  : Interior point method (3 threads, disabled output)

Model summary.
 - Num. variables     : 481
 - Num. constraints   : 2190
 - Num. nonzeros      : 6280
 - Bound range        : [1.0e+00,1.0e+07]
 - Objective range    : [1.0e+00,1.0e+00]
 - Matrix range       : [1.0e+00,1.0e+07]

Presolver started.
Presolver terminated. Time : 0.013s

Simplex method started.
Model fingerprint: md3ZudWY3dmbmV2dm5WZ

    Iteration       Objective       Dual Inf.     Primal Inf.     Time
            0     1.01171e+12      1.0114e-01      4.9321e+10     0.02s    
          417     3.53000e+02      0.0000e+00      0.0000e+00     0.05s    
Postsolver started.
Simplex method terminated. Time : 0.037s

Concurrent optimization terminated.
Optimizer summary.
 - Optimizer used     : Simplex method
 - Optimizer status   : OPTIMAL
 - Total time         : 0.056s

Solution summary.       Primal solution
 - Objective          : 3.5300000000e+02 
----

The solver terminated with an OPTIMAL status (code 1).
目标函数总收益是: 353.0

方法2:命令行直接运行.py文件

上面是直接在cell中运行所有的脚本,我们也可以建立个新文档,将Python代码存在src/python_src文件夹的LP_3_flowshop.py文件,注意存文件的相对目录调整。然后在Launcher中打开Terminal,执行python xx.py文件来运行。

您也可以下载本.py文件,在自己的电脑上安装MindOpt求解器,然后在自己电脑的环境运行。

Luancher可以点击左上角的+打方块打开,Terminal在最下方,如截图示意。打开的窗口可以拖动调整位置。
image.png
然后在Terminal命令行里运行如下指令:

cd src/python_src
python LP_3_flowshop.py

运行得到的结果同方法1:
image.png

方法3: 云上建模平台复制项目运行

此案例已经在案例广场中,可以直接复制:生产调度
image.png

3.求解结果

目标函数最优值是: 353.0。文件src/model/LP_3_flowshop.sol存了本问题的优化解。
部分结果示例如下:


NAME             : 
PRIMAL OBJECTIVE : +3.53000000000000E+02
DUAL OBJECTIVE   : +3.53000000000000E+02
PROBLEM STATUS   : OPTIMAL

VARIABLES
Cmax                                     +3.53000000000000E+02
s_0_0                                    +0.00000000000000E+00
s_0_1                                    +0.00000000000000E+00
s_0_2                                    +0.00000000000000E+00
s_0_3                                    +6.00000000000000E+00
s_0_4                                    +0.00000000000000E+00
s_0_5                                    +0.00000000000000E+00
s_0_6                                    +4.50000000000000E+01
s_0_7                                    +0.00000000000000E+00
s_0_8                                    +0.00000000000000E+00
s_0_9                                    +0.00000000000000E+00
s_0_10                                   +0.00000000000000E+00
s_0_11                                   +0.00000000000000E+00
s_0_12                                   +6.60000000000000E+01
s_0_13                                   +0.00000000000000E+00
s_0_14                                   +8.00000000000000E+00
s_0_15                                   +0.00000000000000E+00
s_0_16                                   +0.00000000000000E+00
s_0_17                                   +0.00000000000000E+00
s_0_18                                   +0.00000000000000E+00
s_0_19                                   +0.00000000000000E+00
s_1_0                                    +5.40000000000000E+01

联系我们

钉钉答疑群:32451444
钉钉活动群:18890022111
邮箱地址:solver.damo@list.alibaba-inc.com
更多更新通知:https://solver.damo.alibaba.com

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值