§ 2 LINGO中的集说明,实际问题建模时,总会遇到一群或多群相互联系的对象,
如工厂、消费者群体、交通工具和雇工等等。
LINGO允许把这些相联系的对象聚合成集( sets)。一旦把对象聚合成集,就可利用集来最大限度的发挥 LINGO建模语言的优势。
现深入介绍如何创建集,并用数据初始化集的属性。
学完本节后,对集如何引入模型会有一个基本的理解。
2.1 为什么使用集集是 LINGO建模语言基础,是程序设计最强有力的基本构件。
借助集,能够用一个单一的、长的、简明的复合公式表示一系列相似的约束,快速方便地表达规模较大的模型。
集:一群相联系的对象集的成员:相联系的对象。
说明:一个集可能是一系列产品、卡车或雇员。
属性:每个集成员可能有的一个或多个与之有关联的特征。
属性值可以预先给定,也可以是未知的,有待于 LINGO求解。
举例:
产品集中的每个产品可以有一个价格属性;
卡车集中的每辆卡车可以有一个牵引力属性;
雇员集中的每位雇员可有一个薪水属性,也可有一个生日属性集的类型:原始集 (primitive set)、派生集 (derived set)。
原始集:由一些最基本的对象组成派生集:由一个或多个其它集定义,即其成员来自其它已存在的集
2.2 什么是集集部分,可选部分,使用前,必须在集部分事先定义。
以关键字,sets:”开始,,endsets”结束。
一个模型可以没有集部分,或有一个简单集部分,或有多个集部分一个集部分可以放置于模型的任何地方,但是一个集及其属性在模型约束中被引用之前必须是已经定义。
2.3.1 定义原始集定义一个原始集,必须作如下详细声明:
·集的名字
·可选,集的成员
·可选,集成员的属性
2.3 模型的集部分定义原始集语法格式:
setname[/member_list/][:attribute_list];
注意:,[]”表示该部分内容可选。
Setname,集的名字,可读性要强,必须严格符合标准命名规则:
以字母或下划线( _)为首字符,其后是字母( A— Z)、下划线、
数字( 0,1,…,9)组成的总长度不超过 32个字符的字符串,不区分大小写。
注意,该命名规则同样适用于集成员名和属性名等的命名。
Member_list,集成员列表。
说明:
若集成员放在集定义中,则可采取显式罗列或隐式罗列方式定义。
若集成员不放在集定义中,则可在随后的数据部分定义它们。
例 2.1 定义一个名为 students的原始集,有成员 John,Jill、
Rose,Mike,属性有 sex,age:
sets:
students/John Jill,Rose Mike/,sex,age;
endsets
① 显式罗列成员时,必须为每个成员输入一个不同名字,中间用空格或逗号搁开,允许混合使用。
② 隐式罗列成员时,不必罗列出每个集成员。
语法格式:
setname/member1..memberN/[,attribute_list];
member1是集的第一个成员名,memberN是集的最末一个成员名。
自动产生中间的所有成员名。
也接受一些特定的首成员名和末成员名,以创建一些特殊的集。
列表如下:
隐式成员列表格式 示 例 所产生集成员
1..n 1..5 1,2,3,4,5
StringM..StringN Car2..car14 Car2,Car3,Car4,…,Car14
DayM..DayN Mon..Fri Mon,Tue,Wed,Thu,Fri
MonthM..MonthN Oct..Jan Oct,Nov,Dec,Jan
MonthYearM..MonthY
earN
Oct2001..Jan2
002
Oct2001,Nov2001,Dec2001,
Jan2002
例 2.2
!集部分 ;
sets:
students:sex,age;
endsets
!数据部分 ;
data:
students,sex,age= John 1 16
Jill 0 14
Rose 0 17
Mike 1 13;
enddata
注意,开头用感叹号( !),末尾用分号( ;)表示注释,可跨多行说明:
集部分只定义了一个集 students,并未指定成员。
数据部分罗列了集成员 John,Jill,Rose,Mike,并对属性 sex、
age分别给出了值。
集成员无论用何种字符标记,其索引都是从 1开始连续计数。
③ 集成员不放在集定义中,在随后的 数据部分 来定义可以把集、集成员和集属性同 C语言中的结构体作类比。
如下图:
集 ←→ 结构体集成员 ←→ 结构体的域集属性 ←→ 结构体实例
LINGO内置的建模语言是一种描述性语言,用它可以描述现实世界中的一些问题,然后再借助于 LINGO求解器求解。
因此,集属性的值一旦在模型中被确定,就不可能再更改。
只有在 初始部分 中给出的集属性值在以后的求解中可更改。
这与前面并不矛盾,初始部分是 LINGO求解器的需要,并不是描述问题所必须的。
attribute_ list,指定一个或多个集成员属性,
之间必须用逗号隔开。
为定义派生集,必须详细声明:
·集的名字
·父集 的名字
·可选,集成员
·可选,集成员的属性语法格式:
setname(parent_set_list)[/member_list/][:attribute_list];
Setname:集的名字。
parent_set_list:已定义的集的列表,多个时必须用逗号隔开。
若没指定成员列表,则自动创建父集成员所有组合为派生集成员。
派生集的父集既可以是原始集,也可以是其它的派生集。
2.3.2 定义派生集生成三个父集的所有组合共八组作为 allowed集的成员。列表如下:
编号 成员
1 (A,M,1)
2 (A,M,2)
3 (A,N,1)
4 (A,N,2)
5 (B,M,1)
6 (B,M,2)
7 (B,N,1)
8 (B,N,2)
稠密集,成员由父集成员所有组合构成的派生集(如成员列表被忽略)。
稀疏集,限制派生集的成员,使它成为父集成员所有组合构成的集合的一个子集的派生集。
同原始集一样,派生集成员的声明也可放在数据部分。
例 2.3
sets:
product/A B/;
machine/M N/;
week/1..2/;
allowed(product,machine,week):x;
endsets
派生集的成员列表生成方式(两种):
①显式罗列,必须显式罗列出所有要包含在派生集中的成员,并且罗列的每个成员必须属于稠密集。
显式罗列派生集的成员举例:如上面例子
allowed(product,machine,week)/A M 1,A N 2,B N 1/;
② 设置成员资格过滤器:
若需要生成一个大的、稀疏的集,显式罗列很麻烦。
一般情况下许多稀疏集的成员都满足一些条件以和非成员相区分。
可把这些逻辑条件看作过滤器,在生成派生集的成员时把使逻辑条件为假的成员从稠密集中过滤掉。
例 2.4
sets:
!学生集:性别属性 sex,1表示男性,0表示女性;年龄属性 age.;
students/John,Jill,Rose,Mike/:sex,age;
!男学生和女学生的联系集:友好程度属性 friend,[0,1]之间的数。 ;
linkmf(students,students)|sex(&1) #eq# 1 #and# sex(&2)
#eq# 0,friend;
!男学生和女学生的友好程度大于 0.5的集 ;
linkmf2(linkmf) | friend(&1,&2) #gt# 0.5,x;
endsets
data:
sex,age = 1 16
0 14
0 17
1 13;
friend = 0.3 0.5 0.6 0.8;
enddata
说明,竖线( |)标记一个成员资格过滤器的开始。
#eq#:逻辑运算符,判断是否,相等,,可参考 § 4.
&1:派生集的第 1个原始父集的索引,它取遍该原始父集所有成员;
&2:派生集的第 2个原始父集的索引,它取遍该原始父集所有成员;
若派生集 B的父集是另外派生集 A,则原始父集是集 A向前回溯到最终的原始集
,其顺序保持不变,且派生集 A的过滤器对派生集 B仍然有效。因此,派生集索引个数是最终原始父集的个数,索引取值是从原始父集到当前派生集所作限制的总和。
总结,可识别的集只有两种类型:原始集、派生集。
原始集是基本的对象,不能再被拆分成更小的组分,可由显式罗列和隐式罗列两种方式定义。
显式罗列方式时,需在集成员列表中逐个输入每个成员。
隐式罗列方式时,只需在集成员列表中输入首成员和末成员,中间成员由 LINGO产生。
派生集由其它集创建。这些集被称为该派生集的父集(原始集或其它的派生集)。
一个派生集既可是稀疏的,也可是稠密的。
稠密集包含了父集成员的所有组合(也称为父集的笛卡尔乘积)。
稀疏集仅包含了父集的笛卡尔乘积的一个子集,可通过显式罗列和成员资格过滤器两种方式定义。
显式罗列方法就是逐个罗列稀疏集成员。
成员资格过滤器方法通过使用稀疏集成员必须满足的逻辑条件从稠密集成员中过滤出稀疏集的成员。
不同集类型的关系见下图。
集稠密集原始集显式罗列稀疏集过滤器派生集
LINGO集类型