生产中常会遇到通过切割、剪裁、冲压等手段,将原材料加工成所需大小这种工 艺过程,称为原料下料(cutting stock)问题。按照进一步的工艺要求,确定下料方案, 使用料最省或利润最大,是典型的优化问题。本节通过一个实例讨论用数学规划模型解 决这类问题的方法。 另一个实例:易拉罐下料问题: 用数学建模优化生产管理问题 - CSDN博客
目录
问题描述
某钢管零售商从钢管厂进货,将钢管按照顾客的要求切割后售出。从钢管厂 进货时得到的原料钢管都是 19m 长。
(1)现有一客户需要 50 根 4m 长,20 根 6m 长和 15 根 8m 长的钢管。应如何下 料最节省?
(2)零售商如果采用的不同切割模式太多,将会导致生产过程的复杂化,从而增 加生产和管理成本,所以该零售商规定采用的不同切割模式不能超过 3 种。此外,该客户除需要(1)中的三种钢管外,还需要 10 根 5m 长的钢管。应如何下料最节省?
1.1 问题(1)的求解
1 问题分析
首先,应当确定哪些切割模式是可行的。所谓一个切割模式,是指按照客户需要在原料钢管上安排切割的一种组合。例如,我们可以将 19m 长的钢管切割成 3 根 4m 长的钢管,余料为 7m;或者将 19m 长的钢管切割成 4m,6m 和 8m 长的钢管各 1 根, 余料为 1m。显然,可行的切割模式是很多的。
其次,应当确定哪些切割模式是合理的。通常假设一个合理的切割模式的余料不应该大于或等于客户需要的钢管的最小尺寸。例如,将 19m 长的钢管切割成 3 根 4m 的钢管是可行的,但余料为 7m,可以进一步将 7m 的余料切割成 4m 钢管(余料为 3m), 或者将 7m 的余料切割成 6m 钢管(余料为 1m)。在这种合理性假设下,切割模式一共 有 7 种,如表 3 所示。
模式类别 | 4m钢管根数 | 6m钢管根数 | 8m钢管根数 | 余料(m) |
模式 1 | 4 | 0 | 0 | 3 |
模式 2 | 3 | 1 | 0 | 1 |
模式 3 | 2 | 0 | 1 | 3 |
模式 4 | 1 | 2 | 0 | 3 |
模式 5 | 1 | 1 | 1 | 1 |
模式 6 | 0 | 3 | 0 | 1 |
模式 7 | 0 | 0 | 2 | 3 |
问题化为在满足客户需要的条件下,按照哪些种合理的模式,切割多少根原料钢 管,最为节省。而所谓节省,可以有两种标准,一是切割后剩余的总余料量最小,二是 切割原料钢管的总根数最少。下面将对这两个目标分别讨论。
2 模型建立
- 决策变量:
用 表示按照第i种模式(i = 1 2,,,7)切割的原料钢管的根数,显然它们应当是非负整数。 决策目标:以切割后剩余的总余料量最小为目标,则由表 3 可得
( 1 )
以切割原料钢管的总根数最少为目标,则有 ( 2 )
下面分别在这两种目标下求解。 约束条件:为满足客户的需求,按照表 3 应用
( 3 )
( 4 )
3 模型求解
i)将式(1)和(3)构成的整数线性规划模型(加上整数约束)输入 LINGO
model:
TITLE 钢管下料-最小化余量;
sets: col/1..7/:c,x;
row/1..3/:b;
link(row,col):a;
endsets
data:
c=3 1 3 3 1 1 3;
b=50 20 15;
a=4 3 2 1 1 0 0
0 1 0 2 1 3 0
0 0 1 0 1 0 2;
enddata
min=@sum(col:c*x);
@for(row(i):@sum(col(j):a(i,j)*x(j))>=b(i));
@for(col:@gin(x));
end
求得按照模式 2 切割 12 根原料钢管,按照模式 5 切割 15 根原料钢管,共 27 根, 总余料量为 27m。但 4m 长的钢管比要求多切割了 1 根,6m 长的钢管比要求多切割了 7 根。显然,在总余料量最小的目标下,最优解将是使用余料尽可能小的切割方式(模 式 2 和模式 5 的余料为 1m),这会导致切割原料钢管的总根数较多。
ii)将式(2)~(4)构成的整数线性规划模型输入 LINGO
model:
TITLE 钢管下料-最小钢管数;
sets: col/1..7/:c,x;
row/1..3/:b;
link(row,col):a;
endsets
data:
c=3 1 3 3 1 1 3;
b=50 20 15;
a=4 3 2 1 1 0 0
0 1 0 2 1 3 0
0 0 1 0 1 0 2;
enddata
min=@sum(col:c*x);
@for(row(i):[con1]@sum(col(j):a(i,j)*x(j))>=b(i));
@for(col:@gin(x));
[remainder]y=@sum(col:c0*x);
end
求得按照模式 2 切割 15 根原料钢管,按模式 5 切割 5 根,按模式 7 切割 5 根,共 25 根,可算出总余料量为 35m。但各长度的钢管数恰好全部满足要求,没有多切割。 与上面得到的结果比较,总余料量增加了 8m,但是所用的原料钢管的总根数减少了 2 根。在余料没有什么用途的情况下,通常选择总根数最少为目标。
1.2 问题(2)的求解
(1)问题分析
按照问题(1)的思路,可以通过枚举法首先确定哪些切割模式是可行的。但由于需要的钢管规格增加到 4 种,所以枚举法的工作量较大。下面介绍的整数非线性规划模 型,可以同时确定切割模式和切割计划,是带有普遍性的方法。 同问题(1)类似,一个合理的切割模式的余料不应该大于或等于客户需要的钢管的最小尺寸(本题中为 4m),切割计划中只使用合理的切割模式,而由于本题中参数都 是整数,所以合理的切割模式的余量不能大于 3m。此外,这里我们仅选择总根数最少为目标进行求解。
(2)模型建立
决策变量:由于不同切割模式不能超过 3 种,可以用 表示按照第 j 种模式(j=1,2,3 )切割的原料钢管的根数,显然它们应当是非负整数。设所使用的第 j 种切割模式下每根原料钢管生产 4m 长,5m 长,6m 长和 8m 长的钢管数量分别为
(非负整数)。记客户需求的 4 种钢管的长度为 ,所以 数量为 ( i =1,2,3,4 ),即
4m钢管根数 | 5m钢管根数 | 6m钢管根数 | 8m钢管根数 | 余料(m) | |
模式 1 | |||||
模式 2 | |||||
模式 3 |
决策目标:以切割原料钢管的总根数最少为目标,即目标为 ( 5 )
约束条件:为满足客户的需求,应有 ( 6 )
每一种切割模式必须可行、合理,所以每根原料钢管的成品量不能超过 19m,也 不能少于 16m(余量不能大于 3m),于是
( 7 )
由于 所以
有的小伙伴私信问我怎么用MATLAB实现它,其实就是把上面的式子(6)和(7)展开就好啦,也就是对于式子(6)有:
(4米的钢管需求为50根);
(5米的钢管需求为10根)
(6米的钢管需求为20根)
(8米的钢管需求为15根)
对于式子(7)有:
; ;
; ;
(3)模型求解
式(5)~(7)构成这个问题的优化模型。由于在式(5)~(7)中出现了决 策变量的乘积,所以这是一个整数非线性规划模型,虽然用 LINGO 软件可以直接求解, 但我们发现有时 LINGO 软件运行很长时间也难以得到最优解。为了减少运行时间,可 以增加一些显然的约束条件,从而缩小可行解的搜索范围。
例如,由于 3 种切割模型的排列顺序是无关紧要的,所以不妨增加以下约束: ( 8 )
又如,我们注意到所需原料钢管的总根数有着明显的上界和下界。首先,无论如何,原料钢管的总根数不可能少于 [ ( 4*50+5*10+6*20+8*15 ) /19] = 26 (根)。其次,考虑一种非常特殊的生产计划:第一种切割模式下只生产 4m 钢管,1 根原料钢管切割 成 4 根 4m 钢管,为满足 50 根 4m 钢管的需求,需要 13 根原料钢管;第二种切割模式 下只生产 5m、6m 钢管,一根原料钢管切割成 1 根 5m 钢管和 2 根 6m 钢管,为满足 10 根 5m 钢管和 20 根 6m 钢管的需求,需要 10 根原料钢管;第三种切割模式下只生产 8m 钢管,1 根原料钢管切割成 2 根 8m 钢管,为满足 15 根 8m 钢管的需求,需要 8 根原料 钢管。于是满足要求的这种生产计划共需 13+10+8= 31 根原料钢管,这就得到了最 优解的一个上界。所以可增加以下约束:
( 9 )
将式(5)~(9)构成的模型输入 LINGO 如下:
model:
Title 钢管下料 - 最小化钢管根数的LINGO模型;
SETS:
NEEDS/1..4/: LENGTH,b;
CUTS/1..3/:X;
PATTERNS(NEEDS,CUTS):R;
ENDSETS
DATA:
LENGTH=4 5 6 8;
b=50 10 20 15;
CAPACITY=19;
ENDDATA
min=@SUM(CUTS(I): X(I) );
@FOR(NEEDS(I):@SUM(CUTS(J):X(J)*R(I,J))>b(I) );
@FOR(CUTS(J):@SUM(NEEDS(I):LENGTH(I)*R(I,J))<CAPACITY ); @FOR(CUTS(J):@SUM(NEEDS(I):LENGTH(I)*R(I,J))>CAPACITY-@MIN(NEEDS(I): LENGTH(I))); @SUM(CUTS(I):X(I))>26; @SUM(CUTS(I):X(I)) <31; !人为增加约束; @FOR(CUTS(I)|I#LT#@SIZE(CUTS):X(I)>X(I+1) ); !人为增加约束;
@FOR(CUTS(J): @GIN(X(J))) ;
@FOR(PATTERNS(I,J):@GIN(R(I,J)));
end
得到按照模式 1,2,3 分别切割 10,10,8 根原料钢管,使用原料钢管总根数为 28 根。第一种切割模式下 1 根原料钢管切割成 2 根 4m 钢管、1 根 5m 钢管和 1 根 6m 钢管;第二种切割模式下 1 根原料钢管切割成 3 根 4m 钢管和 1 根 6m 钢管;第三种模 式下 1 根原料钢管切割成 2 根 8m 钢管。
对于问题2 的MATLAB求解方式,相当于有15个未知数。 由于没有等式约束,我们用空矩阵[ ]表示。我们采用fmincon函数求解最小值。有目标函数为:;
由于MATLAB中的线性不等式形如,所以有 【线性(不等式)约束】为
;
;
;
;
;
;
非线性(不等式)约束条件为
;
;
所以求解的MATLAB代码如下,由于没有增加整数约束,导致求出来的结果是小数,还望大神在评论区告诉我怎么加整数约束。
clc
clear
%close all
x0 =rand(15,1); %15个未知数
fun =@(x)x(1)+x(2)+x(3); % 目标函数
%用x(4)、x(5)、x(6)表示r11 、r12 、r13
%用x(7)、x(8)、x(9)表示r21、 r22、 r23
%用x(10)、x(11)、x(12)表示r31 、r32 、r33
%用x(13)、x(14)、x(15)表示r41 、r42 、r43
% c 为10个线性(不等式)约束,需要转换成小于等于0的形式
A= [-1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0;
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0;
-1 1 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 -4 0 0 -5 0 0 -6 0 0 -8 0 0;
0 0 0 0 -4 0 0 -5 0 0 -6 0 0 -8 0;
0 0 0 0 0 -4 0 0 -5 0 0 -6 0 0 -8;
0 0 0 4 0 0 5 0 0 6 0 0 8 0 0;
0 0 0 0 4 0 0 5 0 0 6 0 0 8 0;
0 0 0 0 0 4 0 0 5 0 0 6 0 0 8;
];
b = [-26;31;0;0;-16;-16;-16;19;19;19];
%c为非线性(不等式)约束,需要转换成小于等于0的形式
c=@(x)[ -x(1)*x(4)-x(2)*x(5)-x(3)*x(6) +50;
-x(1)*x(7)-x(2)*x(8)-x(3)*x(9) +10;
-x(1)*x(10)-x(2)*x(11)-x(3)*x(12) +20;
-x(1)*x(13)-x(2)*x(14)-x(3)*x(15) +15;
];
nonlinfon = @(x)deal(c(x));
lb = [0;0;0;0;0;0;0;0;0;0;0;0;0;0;0] % 所有的x都大于等于0
%
options = optimoptions(@fmincon,'MaxIter',10000);
options=optimoptions(@fmincon,'MaxFunEvals',100000);
[x fval exitflag] = fmincon(fun,x0,A,b,[],[],lb,[],nonlinfon,options)
另外关于exitflag 为-1和-2说明没找到最优解;为1-5说明找到了(局部)最优解。为0是迭代次数很多但仍不收敛,可考虑修改最大迭代次数。
x =[ 16.4649; 0.0001; 0.0000;
0.1654; 1.1044; 1.0892
0.2021; 0.8803; 0.9247
0.2394; 0.7258; 0.7205
0.3166; 0.5630; 0.5527 ].
fval = 16.4649
exitflag = 0