1 带有下标的优化模型
优化问题大部分情况下,参数有很多,约束也有很多,但大部分参数和约束都是同类型的,在数学表达式中往往都以下标来区分,例如《运筹学》(罗纳德 L. 拉丁)中的Pi Hybrids问题的优化模型的数学表示:
注,这是来自书中的截图,这里的demands错误,d的下标应该为h,r
。
另一方面,为了让程序具有通用性,都是模型与数据分开的,即放在两个文件中,这样改数据的时候可以不用动模型。
我们以《运筹学》(罗纳德 L. 拉丁)中的Pi Hybrids问题为例来说明模型与数据分离时如何写程序,同时使用下标来表达多参数、多约束的模型。
2 编写模型
第一步是写模型,新建一个名为pi_hybrids.mod的模型文件,这个上节讲过怎么操作,文件内容如下:
model; # 声明此部分为模型部分
# param定义基本符号参数:设备、品种、销售地
param l; # l台设备
param m; # m个玉米杂交品种
param n; # n个销售地
# set定义序列,这里定义的是标引(下标)的取值范围
set facils := 1 .. l; # 设备编号范围,这里facils是一个序列,类似于python中的range用法
set hybrs := 1 .. m; # 玉米杂交品种编号范围
set regns := 1 .. n; # 销售地编号范围
# 定义其他符号参数,这里用下标的方式,使用一条param语句同时定义一组参数
# 下面的像f、h、r这些标引,都不需要单独定义,但它们每次出现,
# 都需要使用花括号声明其范围,同一条语句只需要声明一次
param u{f in facils}; # 编号为f的设备的加工能力,即设备f处理玉米谷粒的能力
param a{h in hybrs}; # 生产一袋h品种玉米杂交种所需的谷粒数量
param p{f in facils, h in hybrs}; # 设备f生产一袋h品种的生产成本(金钱成本)
param d{h in hybrs, r in regns}; # 销售地r对h品种的需求量
param s{f in facils, h in hybrs, r in regns}; # 从设备f,将一袋h品种玉米杂交种运输到销
# 售地r的运输成本
# 定义决策变量及其类型约束,这里同样使用下标的方式,可以通过一条var语句同时定义一组决策变量
var x{f in facils, h in hybrs} >= 0; # 使用设备f,生成品种h的袋数
var y{f in facils, h in hybrs, r in regns} >= 0; # 从设备f,运输品种h,到销售地r的袋数
# 定义目标函数,这里sum是求和符号,通过下标定位参数或决策变量,需要通过[]
minimize tcost: sum{f in facils, h in hybrs} p[f, h]*x[f, h]
+ sum{f in facils, h in hybrs, r in regns} s[f, h, r]*y[f, h, r];
# 定义主约束,使用下标的方式,通过一条语句同时定义一组约束
subject to
fcap{f in facils}: sum{h in hybrs} a[h]*x[f, h] <= u[f]; # 设备能力约束
rdems{h in hybrs, r in regns}: sum{f in facils} y[f, h, r] = d[h, r]; # 运输等于需求
psbal{f in facils, h in hybrs}: sum{r in regns} y[f, h, r] = x[f, h]; # 运输等于生产
由于CSDN中没有AMPL代码格式,我用截图看起来能更方便一些,因为关键字有颜色:
我们可以归纳一下上述程序的步骤:
(1)定义基本符号参数,如l m n
;
(2)定义下标的范围,通过定义序列来进行;
(3)通过下标定义其他参数;
(4)定义决策变量及其类型约束;
(5)定义主约束。
这五步通常是AMPL写模型的标准流程,是层层递进的关系。
2 组织数据
在与py_hybrids.mod文件的同目录下新建一个名为py_hybrids.dat的文件,也可以是其他名字(以容易识别为准),但后缀必须是.dat,新建的时候可以在“File Extension”中选择:
py_hybrids.dat内容如下:
data; # 声明此部分为模型部分
# 给没有下标的基本参数赋值
param l := 2; # “:=”表示赋值
param m := 4;
param n := 3;
# 以列表形式,给只有单个下标的参数赋值
param u := 1 2200 2 2555; # u[1]为2200,u[2]为2555
param a := 1 7 2 11 3 6 4 18;
# 以表格形式,给多重下标的参数赋值,为了方便观察,建议用tab隔开
# 二重下标
param p: 1 2 3 4 :=
1 1.10 0.89 2.05 1.45
2 1.55 1.13 2.15 1.56 ;
param d : 1 2 3 :=
1 123 119 500
2 311 281 333
3 212 188 424
4 189 201 440 ;
# 三重下标
param s: 1 2 3 :=
1 1 0.89 0.91 0.77
1 2 1.00 0.84 0.89
1 3 0.77 0.76 0.78
1 4 0.99 1.03 0.85
2 1 0.92 0.89 0.92
2 2 0.87 0.95 0.90
2 3 0.91 0.83 0.77
2 4 0.89 0.79 0.86 ; # s[2, 4, 1]即为0.89,列标表示最后一个下标
截图看的更清晰:
书中还是有错的,因为p[f, h],f=1, ... , l l=2
那么f只能等于1或2,所以参数p只能有两行,但书中有4行,我删掉了后面两行,否则后面运行命令data pi_hybrids.dat;
时会报错。
3 控制台运行
控制台输入如下数据:
ampl: reset;
ampl: model pi_hybrids.mod;
ampl: data pi_hybrids.dat;
ampl: option solver cplex;
ampl: solve;
结果:
可能是书中的数据没有组织好,导致约束无法被满足,即约束之间相互冲突,所以这里报错。当然,我们这里只是过一下案例,知道怎么操作模型与数据分离、带有下标的情况就行了,具体结果这里不重要。