x
1
≤
2 x
2
x
1
, x
2
≥
0 为整数
该模型输入 LINGO1 模型窗口后的形式见图 6。对照第 2 章 2.6 节,我们可以看出用 LINGO 解 QP 比用 LINDO 解要容易输入模型。注意:原来的整数限定语句―GIN X1‖和―GIN X2‖这里 变成了―@GIN(X1)‖和―@GIN(X2)‖;但是,在 LINDO 下也可以写成―GIN 2‖,这里却不可 以写成―@GIN(2)‖,否则 LINGO 将把这个模型看成没有整数变量。在 LINGO 中,以―@‖开头 的都是函数调用,我们将在后面(本章 3.5 节)详细介绍 LINGO 中能够使用的所有函数。 图 6
5
Page 6 图 7
现在运行菜单命令―LINGO|Solve‖,则可以得到图 7 所示的解答报告,最优整数解 X=(35, 65),最大利润=11077.5。结果中最优整数解与第 2 章 2.6 节相同,但最优值略有不同,估计是
计算误差引起的。此外,LINGO 是将它作为 PINLP(纯整数非线性规划)来求解,因此只告诉我们
找到的是局部最优解(为什么 LINGO 不将它作为 PIQP(纯整数二次规划)来求解?本人也不清楚)。
你还可以选择运行菜单命令―WINDOW|Status Window‖看到图 8 所示的状态窗口(这时我们已经
把该规划模型保存到了文件 IQP0302B.LG4 中,所以这个名字现在也出现在了状态窗口中),从中
可以看到目前为止找到的最佳目标值―Best Obj‖与问题的上界―Obj Bound‖已经是一样的,当前 解的最大利润与这两个值非常接近,估计是计算误差引起的差异。实际上,如果采用全局最优求解
程序(我们将在后面介绍―LINGO|Options‖菜单命令时介绍如何激活全局最优求解程序),可以验
证它就是全局最优解。 图 8
6
Page 7 在本节的最后,我们对 LINGO 的基本用法指出几点注意事项:
1) 变量和行名可以超过 8 个字符,但不能超过 32 个字符,且必须以字母开头。
2) 与 LINDO 相同,用 LINGO 解规划时已假定各变量非负(除非用限定变量取值范围的函数@free
或@sub 或@slb 另行说明)。
3) 与 LINDO 不同,变量可以放在约束条件的右端(同时数字也可放在约束条件的左端)。但为
了提高 LINGO 求解时的效率,应尽可能采用线性表达式定义目标和约束(如果可能)。
3.3 在 LINGO 中使用集合
3.3.1 集合的基本用法
我们前面说过,LINGO 同时也是优化问题的一种建模语言。有了它,使用者可以只用键入一行 文字就可以建立起含有大规模变量的目标函数和成千上万条约束。掌握这种最优化模型语言是非常
重要的,与 LINDO 相比,这可使输入较大规模问题的过程得到简化。
理解 LINGO 建模语言最重要的是理解―集合‖(SET)及其―属性‖(Attribute)的概念。 什么是集合呢?我们通过下面的一个简单例子开始来进行介绍。
例:SAILCO 公司需要决定下四个季度的帆船生产量。下四个季度的帆船需求量分别是 40 条, 60 条,75 条,25 条,这些需求必须按时满足。每个季度正常的生产能力是 40 条帆船,每条船的
生产费用为 400 美元。如果加班生产,每条船的生产费用为 450 美元。每个季度末,每条船的库
存费用为 20 美元。假定生产提前期为 0,初始库存为 10 条船。如何安排生产可使总费用最小? 我们用 DEM,RP,OP,INV 分别表示需求、正常生产的产量、加班生产的产量、库存量,则 DEM,RP,OP,INV 对每个季度都应该有一个对应的值,也就说他们都应该是一个由 4 个元素组成的
数组,其中 DEM 是已知的,而 RP,OP,INV 是未知数。现在我们可以写出这个问题的模型。首先,
目标函数是所有费用的和: MIN
∑
=
+ +
4, 3, 2, 1
)} ( 20 ) ( 450
) ( 400 {
I
I INV I OP I RP
约束条件主要有两个: 1)能力限制: RP(I)<40,I=1,2,3,4; 2)产品数量的平衡方程:
INV(I)=INV(I-1)+RP(I)+OP(I)-DEM(I),I=1,2,3,4; INV(0)=10;
当然,还要加上变量的非负约束,构成了这个问题的模型(可以看出是 LP 模型)。
可以看出,如果利用数组的概念,这个模型是比较容易建立的。然而,由于 LINDO 中没有数 组这样的数据结构,我们只能对每个季度分别定义变量,如正常产量就要有 4 个变量 RP1,RP2, RP3,RP4 等;对未知数 OP,INV 也是一样。这样,写起来就比较麻烦,尤其如果不是 4 个季度而
是更多(如 1000 个季度)的时候。
记四个季度组成的集合 QUARTERS={1,2,3,4},它们就是上面数组的下标集合,而数组 DEM,RP,OP,INV 对集合 QUARTERS 中的每个元素 1,2,3,4 分别对应于一个值,如图 9 所示。
LINGO 正是充分利用了这种数组及其下标的关系,引入了―集合‖及其―属性‖的概念,把 QUARTERS={1,2,3,4}称为集合,把 DEM,RP,OP,INV 称为该集合的属性。
7
Page 8 QUARTERS 集合的属性 OP INV DEM RP 2 3 4 1
QUARTERS 集合 图 9 集合及其属性
该 LP 模型在 LINGO 中的一个典型输入方式见图 10。我们可以看到这个输入以―MODEL:‖
开始,以―END‖结束,它们之间由语句组成,可以分成三个部分:前一部分(从―SETS:‖到―ENDSETS‖)
是定义集合及其属性,后一部分(从―DATA:‖到―ENDDATA‖)是给出常量 DEM 的值,中间部
分给出优化目标和约束。 图 10
目标函数是用求和函数‖@SUM(集合:表达式)‖的方式定义的,这个函数的功能是对冒号―:‖ 后面的表达式,按照冒号―:‖前面的下标集合指定的下标进行求和。由于本例中目标函数对所有 下标都要求和,所以我们连下标 i 也省去了;如果不省略,目标函数也可以等价地写成 ―@SUM(QUARTERS(i): 400*RP(i) +450*OP(i) +20*INV(i) )‖。
约束是用循环函数‖@FOR(集合:约束关系式)‖的方式定义的,意思是对冒号―:‖前面的集 合的每个元素(下标),冒号―:‖后面的约束关系式都要成立。由于下标 i=1 时的约束关系式与
i=2,3,4 时有所区别,所以对下标集合的元素(下标)加了一个―i#GT#1‖的限制条件,而把 i=1 时的约束关系式单独写出。限制条件―i#GT#1‖是一个逻辑表达式,意思就是 i>1;―#GT#‖ 是逻辑运算符号,意思是―大于‖(其他逻辑运算符将在本章后面 3.4 节介绍)。
8
Page 9 现在运行菜单命令―LINGO|Solve‖,则可以得到图 11 所示的解答报告,全局最优解 RP=(40, 40,40,25),OP=(0,10,35,0),最小成本=78450。这就是我们模型的计算结果。 图 11
一般来说, LINGO 中建立的优化模型由四个部分组成,或称为四―段‖(SECTION): (1)集合段(SETS):这部分要以 SETS: 开始,以 ENDSETS 结束,作用在于定义必要的 集合变量(SET)及其元素(MEMBER,含义类似于数组的下标)和属性(ATTRIBUTE,含义类似
于数组)。如上例中定义了集合 quarters(含义是季节),这里它包含四个元素即四个季节指标 (1,2,3,4),每个季节都有需求(DEM)、正常生产量(RP)、加班生产量(OP)、库存量(INV) 等属性(相当于数组,数组下标由 quarters 元素决定)。一旦这样的定义建立起来,如果 quarters 的数量不是 4 而是 1000,只需扩展其元素为 1,2,...,1000,每个季节仍然都有 DEM,RP,OP,INV 这样的属性(这些量的具体数值如果是常量,则可在数据段输入;如果是未知数,则可在初始段输
入初值)。自然,当 quarters 的数量不是 4 而是 1000 时,我们也没有必要把 1,2,...,1000 全部一个一个列出来,而是可以如下定义 quarters 集合: quarters/1..1000/:DEM,RP,OP,INV;
即―1..1000‖的意识就是从 1 到 1000 的所有整数(我们的例子中只有 4 个元素,所以没有写成 ―1..4‖而是全部列出来了)。
(2)目标与约束段:这部分实际上定义了目标函数,约束条件等。一般要用到 LINGO 的内部 函数,可在具体使用中体会其功能和用法(详见 3.5 节)。上例中定义的目标函数与 quarters 的
9
Page 10 元素数目是 4 或 1000 并无具体的关系。约束的表示也类似。
(3)数据段(DATA):这部分要以 DATA: 开始,以 ENDDATA 结束,作用在于对集合的属
性(数组)输入必要的常数数据。格式为:attribute = value_list。常数值列表(value_list) 中数据之间可以用逗号―,‖分开,也可以用空格分开(回车的作用也等价于一个空格),如上面 对 DEM 的赋值也可以写成―DEM=40 60 75 25‖。
在 LINGO 模型中,如果想在运行时才对参数赋值,可以在数据段使用输入语句。但这仅用于 对单个变量赋值,而不能用于属性变量(数组),输入语句格式为:―变量名 = ?;‖。例如, 上面的例子中如果需要在求解模型时才给出初始库存量(记为 A),则可以在模型中数据段写上―A
= ?;‖语句, 在求解时 LINDO 系统给出提示界面,等待用户输入变量 A 的数值。 (4)初始段(INIT):这部分要以 INIT: 开始,以 ENDINIT 结束,作用在于对集合的属 性(数组)定义迭代初值,如果有一个接近最优解的初值,对 LINGO 求解模型是有帮助的。格式
为:attribute = value_list;上例中没有初始化部分,我们将在下一个例子中举例说明。 实际上,LINGO 模型在求解时也是要展开成与 LINDO 模型类似的形式的。选择菜单命令 ―LINGO|Generate|Disply model‖(Ctrl+G),可以得到展开形式的模型如图 12 所示,这 与我们在 LINDO 下的模型输入形式很类似,只是在 LINDO 中不允许有这种数组形式的变量。注意:
如果目标或约束中有非线性变量项,对应的非线性变量前的系数将以问号(―?‖)显示。 图 12
3.3.2 基本集合与派生集合
我们下面再用 LINGO 来解在第一章 1.5 节中介绍的如下料场选址问题:
某公司有 6 个建筑工地要开工,每个工地的位置(用平面坐标 a, b 表示,距离单位:公里)及 水泥日用量 d(吨)由表 3 给出。目前有两个临时料场位于 P (5, 1), Q (2, 7) ,日储量各有 20 吨。
假设从料场到工地之间均有直线道路相连,试制定每天的供应计划,即从 A, B 两料场分别向各工地
运送多少吨水泥,使总的吨公里数最小。为了进一步减少吨公里数,打算舍弃两个临时料场,改建
两个新的,日储量仍各为 20 吨,问应建在何处,节省的吨公里数有多大。 1 2 3 4 5 6 a 1.25 8.75 0.5 5.75 3 7.25 b