加油,陌生人!

导航

Cplex解决JSP问题

我的上一篇博客Cplex解决FSP问题 - 加油,陌生人! - 博客园 (cnblogs.com)用Cplex完成了FSP的建模,这篇文章主要是解决JSP问题(车间调度问题)。

JSP问题:n个工件,m台机器,每个工件都有自己的加工路线,要求找出最佳的加工顺序,使得完工时间最小。从问题的描述来看,FSP是一种特殊的JSP,因为它所有工件的加工路线都是相同的。

下面就来考虑如何解决JSP问题。

先附上数据文件(.dat),如下

数据文件.dat

n=4;//工件数量
m=3;//机器数量
p=[[20,87,31],
   [25,32,24],
   [72,23,28],
   [86,76,97]];//各工件在各机器上的加工时间
/*prec=[[1,3,2],
        [3,1,2],
        [3,2,1],
        [2,3,1]];*/
temp=[  [[0,0,0,0],//表示加工顺序
         [0,0,0,1],
         [0,0,0,0],
         [0,0,1,0]],
        [[0,0,0,0],
         [0,0,1,0],
         [0,0,0,0],
         [0,1,0,0]],
        [[0,0,0,0],
         [0,0,0,0],
         [0,1,0,0],
         [0,0,1,0]],
        [[0,0,0,0],
         [0,0,0,0],
         [0,0,0,1],
         [0,1,0,0]] ];

p表示各工件在各机器上的加工时间,例如工件1在机器1上的加工时间为20。temp用来表示每个工件的加工工艺,是个三维矩阵,里面包含了n个(m+1)*(m+1)的二维矩阵。例如在第一个二维矩阵arr中

可以看到arr[1][3]=1,表示机器1-->机器3;arr[3][2]=1,表示机器3-->2。于是工件1的加工顺序为m1-->m3-->m2,其他的工件也是类似的原理。

模型文件.mod

int n=...;//工件数量
int m=...;//机器数量,也可以理解为工序数量,因为一道工序只有一台机器
int M=100000;//一个非常大的数
range r1=1..n;
range r2=1..m;
int temp[r1][0..m][0..m]=...;


dvar float+ c[r1][r2];//表示完工时间
int p[r1][r2]=...;

dvar boolean a[r1][0..m][0..m];//i,h,k.机器h优先于机器k加工工件i
dvar boolean x[0..n][0..n][r2];//i,j,k.工件i优先于工件j在机器k上加工

minimize max(i in r1,k in r2) c[i][k];//机器i在机器k上的完工时间

subject to{
    forall(i in r1,h in r2,k in r2)
      c[i][k]-p[i][k]+M*(1-a[i][h][k])>=c[i][h];//机器h优先于机器k加工工件i
    forall(i in r1,j in r1,k in r2)
      c[j][k]-c[i][k]+M*(1-x[i][j][k])>=p[i][k];//工件i优先于工件j在机器k上加工
    forall(j in r1,k in r2)
      //对于任意一台机器上的工件j,必然有一个紧前作业i
      sum(i in 0..n) x[i][j][k]==1;
    forall(i in r1,k in r2)
      //对于任意一台机器上的工件i,必然有一个紧后作业j
      sum(j in 0..n) x[i][j][k]==1;
    forall(k in r2)
      //对于每台机器来说,只能由一个作业位于最后
      sum(i in 0..n) x[i][0][k]<=1;
    forall(k in r2)
      //对于每台机器来说,只能有一个作业首先加工
      sum(j in 0..n) x[0][j][k]<=1;
    /*************************/  
    forall(i in r1,k in r2)
      //对于任意一个工件,必然有一个紧前工序
      sum(h in 0..m) a[i][h][k]==1;
    forall(i in r1,h in r2)
      //对于任意一个工件,必然有一个紧后工序
      sum(k in 0..m) a[i][h][k]==1;
    forall(i in r1)
      //对于每个工件来说,只能有一个工序处于第一位
      sum(k in 0..m) a[i][0][k]<=1;
    forall(i in r1)
      //对于每个工件来说,只能有一个工序处于最后一位
      sum(h in 0..m) a[i][h][0]<=1;
    /************************/
    forall(i in r1)
      sum(h in 0..m,k in 0..m) temp[i][h][k]*a[i][h][k]==2;
}
execute{
    writeln("每台机器上工件加工的顺序:");
    for(var k in r2){
        for(var i in r1){
            for(var j in r1){
                if(x[i][j][k]==1){
                    writeln(k+":"+i+"-->"+j);                
                }            
            }        
        }    
    }
    writeln("每个工件的加工顺序:")
    for(var i in r1){
        for(var h in r2){
            for(var k in r2){
                if(a[i][h][k]==1){
                    writeln(i+":"+h+"-->"+k);                
                }            
            }        
        }    
    }
}

结果:

// solution (optimal) with objective 220
// Quality Incumbent solution:
// MILP objective                                2.2000000000e+002
// MILP solution norm |x| (Total, Max)           2.58900e+003 2.20000e+002
// MILP solution error (Ax=b) (Total, Max)       0.00000e+000 0.00000e+000
// MILP x bound error (Total, Max)               0.00000e+000 0.00000e+000
// MILP x integrality error (Total, Max)         0.00000e+000 0.00000e+000
// MILP slack bound error (Total, Max)           0.00000e+000 0.00000e+000
// 

c = [[0
             118 31]
             [87 220 62]
             [148 76 0]
             [220 0 97]];
a = [[[0 1 0 0]
                 [0 0 0 1]
                 [1 0 0 0]
                 [0 0 1 0]]
             [[0 0 0 1]
                 [0 0 1 0]
                 [1 0 0 0]
                 [0 1 0 0]]
             [[0 0 0 1]
                 [1 0 0 0]
                 [0 1 0 0]
                 [0 0 1 0]]
             [[0 0 1 0]
                 [1 0 0 0]
                 [0 0 0 1]
                 [0 1 0 0]]];
x = [[[0 0 0]
                 [1 0 0]
                 [0 0 0]
                 [0 0 1]
                 [0 1 0]]
             [[0 0 0]
                 [0 0 0]
                 [1 1 1]
                 [0 0 0]
                 [0 0 0]]
             [[0 1 0]
                 [0 0 0]
                 [0 0 0]
                 [1 0 0]
                 [0 0 1]]
             [[0 0 0]
                 [0 1 1]
                 [0 0 0]
                 [0 0 0]
                 [1 0 0]]
             [[1 0 1]
                 [0 0 0]
                 [0 0 0]
                 [0 1 0]
                 [0 0 0]]];
/*----------------脚本信息---------------*/

// solution (optimal) with objective 220
每台机器上工件加工的顺序:
1:1-->2
1:2-->3
1:3-->4
2:1-->2
2:3-->1
2:4-->3
3:1-->2
3:2-->4
3:3-->1
每个工件的加工顺序:
1:1-->3
1:3-->2
2:1-->2
2:3-->1
3:2-->1
3:3-->2
4:2-->3
4:3-->1

 

posted on 2022-02-24 09:26  加油,陌生人!  阅读(380)  评论(3编辑  收藏  举报