LINGO有9种类型的函数:
(1)基本运算符:包括算术运算符、逻辑运算符和关系运算符;
(3)金融函数:LINGO提供的两种金融函数;
(4)概率函数:LINGO提供了大量与概率相关的函数;
(5)变量界定函数:这类函数用来定义变量的取值范围;
(6)集操作函数:这类函数为集的操作提供帮助;
(7)集循环函数:遍历集的元素,执行一定的操作的函数;
(8)数据输入输出函数:这类函数允许模型和外部数据源相联系,进行数据的输入输出;
(9)辅助函数:各种杂类函数.
1.基本运算符
这些运算符是非常基本的,甚至可以不认为它们是一类函数.事实上,在LINGO中它们是非常重要的.
(1)算术运算符.
算术运算符是针对数值进行操作的.LINGO提供了5种二元运算符:
运算符的运算次序为从左到右按优先级高低来执行.运算的次序可以用圆括号“()”来改变,例如,2-5/3,(2+4)/5,等等.
(2)逻辑运算符.
在LINGO中,逻辑运算符主要用于集循环函数的条件表达式中,来控制在函数中哪些集成员被包含,哪些被排斥(见表1.4.1).另外,在创建稀疏集时用在成员资格过滤器中.
表1.4.1 LINGO的9种逻辑运算符
这些运算符的优先级由高到低为:
例1 逻辑运算符示例.
2#gt#3#and#4#gt#2,其结果为假(0).
(3)关系运算符.
在LINGO中,关系运算符主要被用在模型中,来指定一个表达式的左边是否等于、小于等于或者大于等于右边,形成模型的一个约束条件.关系运算符与逻辑运算符#eq#、#le#、#ge#截然不同,前者是模型中该关系运算符所指定关系的为真描述,而后者仅仅判断一个该关系是否被满足:满足为真,不满足为假.
LINGO有三种关系运算符:“=”、“<=”和“>=”.LINGO中还能用“<”表示小于等于关系,用“>”表示大于等于关系.LINGO并不支持严格小于和严格大于关系运算符.然而,如果需要严格小于和严格大于关系,比如让A严格小于B:
A<B
那么可以把它变成如下的小于等于表达式:
A+ε<=B
这里ε是一个小的正数,它的值依赖于模型中A小于B多少才算不等.
下面给出以上三类操作符的优先级:
2.数学函数(见表1.4.2)
表1.4.2 LINGO常用的标准数学函数
续表
例2 给定一个直角三角形,求覆盖该三角形的最小正方形.
解 如图1.4.1所示.
CE=asinx,AD=bcosx,DE=acosx+bsinx,求最小的正方形就相当于求如下的最优化问题:
图1.4.1 例2示意图
LINGO代码如下:
在上面的代码中用到了函数@bnd,详情请见本节5.变量界定函数.
3.金融函数
目前LINGO提供了两个金融函数.
(1)@fpa(I,n)
返回如下情形的净现值:单位时段利率为I,连续n个时段支付,每个时段支付单位费用.若每个时段支付x单位的费用,则净现值可用x乘以@fpa(I,n)算得.@fpa的计算公式为
净现值就是在一定时期内为了获得一定收益在该时期初所支付的实际费用.
例3(贷款买房问题) 贷款金额50000元,贷款年利率5.31%,采取分期付款方式(每年年末还固定金额,直至还清).拟贷款10年,每年需偿还多少元?
LINGO代码如下:
50000=x*@fpa(.0531,10);
答案是x=6 573.069元.
(2)@fpl(I,n)
返回如下情形的净现值:单位时段利率为I,第n个时段支付单位费用.@fpl(I,n)的计算公式为:
两个函数间的关系为:
4.概率函数
(1)@pbn(p,n,x)
二项分布的累积分布函数.当n或x不是整数时,用线性插值法进行计算.
(2)@pcx(n,x)
自由度为n的χ2分布的累积分布函数.
(3)@peb(a,x)
当到达负荷为a,服务系统有x个服务器且允许无穷排队时的Erlang繁忙概率.
(4)@pel(a,x)
当到达负荷为a,服务系统有x个服务器且不允许排队时的Erlang繁忙概率.
(5)@pfd(n,d,x)
自由度为n和d的F分布的累积分布函数.
(6)@pfs(a,x,c)
当负荷上限为a,顾客数为c,平行服务器数量为x时,有限源的Poisson服务系统的等待或返修顾客数的期望值.a是顾客数乘以平均服务时间,再除以平均返修时间.当c或x不是整数时,采用线性插值进行计算.
(7)@phg(pop,g,n,x)
超几何(Hypergeometric)分布的累积分布函数.pop表示产品总数,g是正品数.从所有产品中任意取出n(n≤pop)件.
(8)@ppl(a,x)
Poisson分布的线性损失函数,即返回max(0,z-x)的期望值,其中随机变量z服从均值为a的Poisson分布.
(9)@pps(a,x)
均值为a的Poisson分布的累积分布函数.
(10)@psl(x)
单位正态线性损失函数,即返回max(0,z-x)的期望值,其中随机变量z服从标准正态分布.
(11)@psn(x)
标准正态分布的累积分布函数.
(12)@ptd(n,x)
自由度为n的t分布的累积分布函数.
(13)@qrand(seed)
产生服从(0,1)区间的拟随机数.@qrand只允许在模型的数据部分使用,它将用拟随机数填满集属性.通常,声明一个m×n的二维表,m表示运行实验的次数,n表示每次实验所需的随机数的个数.在行内,随机数是独立分布的;在行间,随机数是非常均匀的.这些随机数是用“分层取样”的方法产生的.
例4 随机数的生成.
如果没有为函数指定种子,那么LINGO将用系统时间构造种子.
(14)@rand(seed)
返回0和1间的伪随机数,依赖于指定的种子.典型用法是
U(I+1)=@rand(U(I)).
注意:如果seed不变,那么产生的随机数也不变.
例5 利用@rand产生15个标准正态分布随机数和自由度为2的t分布随机数.
5.变量界定函数(见表1.4.3)
表1.4.3 变量界定函数
6.集操作函数
(1)@in(set_name,primitive_index_1[,primitive_index_2,…])
如果元素在指定集中,返回1;否则返回0.
例6 定义全集I的子集B的补集C.
(2)@index([set_name,]primitive_set_element)
该函数返回集set_name中原始集成员primitive_set_element的索引.如果set_name被忽略,那么LINGO将返回与primitive_set_element匹配的第一个原始集成员的索引.如果找不到,则产生一个错误.
例7 确定集成员是否属于某派生集.
看下面的例子,表明有时为@index指定集是必要的.
例8 为@index指定集.
I1的值是2,I2的值是3.我们建议在使用@index函数时最好指定集.(www.xing528.com)
(3)@wrap(index,limit)
该函数返回j=index-k*limit,其中k是一个整数,取适当值保证j落在区间[1,limit]内.该函数相当于index模limit,但在整除时返回的是除数而不是余数0.该函数在循环、多阶段计划编制中特别有用(参见本节例12).
(4)@size(set_name)
该函数返回集set_name的成员个数.在模型中明确给出集大小时最好使用该函数.它的使用使模型数据更加中立,集大小改变时也更易维护.
7.集循环函数
集循环函数遍历整个集进行操作.其语法为
@function(setname[(set_index_list)[|conditional_qualifier]]:expression_list);
@function相应于下面罗列的四个集循环函数之一;setname是要遍历的集;set_index_list是集索引列表;conditional_qualifier是用来限制集循环函数的范围,当集循环函数遍历集的每个成员时,LINGO都要对conditional_qualifier进行评价,若结果为真,则对该成员执行@function操作,否则跳过,继续执行下一次循环.expression_list是被应用到每个集成员的表达式列表,当用的是@for函数时,expression_list可以包含多个表达式,其间用逗号隔开.这些表达式将被作为约束加到模型中.当使用其余的三个集循环函数时,expression_list只能有一个表达式.如果省略set_index_list,那么在expression_list中引用的所有属性的类型都是setname集.
(1)@for
该函数用来产生对集成员的约束.基于建模语言的标量需要显式输入每个约束时,@for函数允许只输入一个约束,然后LINGO自动产生每个集成员的约束.
例9 产生序列{1,4,9,16,25}.
(2)@sum
该函数返回遍历指定的集成员的一个表达式的和.
例10 求向量[5,1,3,4,6,10]前5个数的和.
(3)@min和@max
返回指定的集成员的一个表达式的最小值或最大值.
例11 求向量[5,1,3,4,6,10]前5个数的最小值,后3个数的最大值.
下面看一个稍微复杂一点儿的例子.
例12(职员时序安排模型) 一项工作一周7天都需要有人(比如护士工作),每天(周一至周日)所需的最少职员数为20、16、13、16、19、14和12,并要求每个职员一周连续工作5天,试求每周所需最少职员数,并给出安排.注意我们考虑稳定后的情况.
解 设xi为第i天开始工作的人数,Ri为第i天最低需求人数,z为总人数.模型为
程序:
计算的部分结果为:
从而解决方案是:每周最少需要22名职员,周一安排8人,周二安排2人,周三无须安排人,周四安排6人,周五和周六都安排3人,周日无须安排人.
8.输入和输出函数
输入和输出函数可以把模型和外部数据比如文本文件、电子表格等连接起来.
(1)@file函数
该函数用于从外部文本文件中输入数据,可以放在模型中任何地方.该函数的语法格式为:
@file('filename').
这里filename是文件名,可以采用相对路径和绝对路径两种表示方式.
例13 以第一章第一节例2来讲解@file函数的用法.
注意到在例2的编码中有两处涉及数据:第一个地方是集部分的6个warehouses集成员和8个vendors集成员;第二个地方是数据部分的ca,d和c数据.
为了使数据和我们的模型完全分开,我们把它们移到外部的文本文件中.修改模型代码以便于用@file函数把数据从文本文件中拖到模型中来.修改后的模型代码如下:
模型的所有数据来自1_2.txt文件.其内容如下:
!warehouses成员;
WH1 WH2 WH3 WH4 WH5 WH6~
!vendors成员;
V1 V2 V3 V4 V5 V6 V7 V8~
!产量;
60 55 51 43 41 52~
!销量;
35 37 22 32 41 32 43 38~
!单位运输费用矩阵;
把记录结束标记(~)之间的数据文件部分称为记录.如果数据文件中没有记录结束标记,那么整个文件被看作单个记录.注意到除了记录结束标记外,模型的文本和数据同它们直接放在模型里是一样的.
我们来看一下在数据文件中的记录结束标记连同模型中@file函数调用是如何工作的.当在模型中第一次调用@file函数时,LINGO打开数据文件,然后读取第一个记录;第二次调用@file函数时,LINGO读取第二个记录,等等.文件的最后一条记录可以没有记录结束标记,当遇到文件结束标记时,LINGO会读取最后一条记录,然后关闭文件.如果最后一条记录也有记录结束标记,那么直到LINGO求解完当前模型后才关闭该文件.如果多个文件保持打开状态,可能会导致一些问题,因为这会使同时打开的文件总数超过允许同时打开文件的上限16.
当使用@file函数时,可把记录的内容(除了一些记录结束标记外)看作替代模型中@file('filename')位置的文本.也就是说,一条记录可以是声明的一部分、整个声明或一系列声明.在数据文件中注释被忽略.注意:在LINGO中不允许嵌套调用@file函数.
(2)@text函数
该函数被用在数据部分用来把解输出至文本文件中.它可以输出集成员和集属性值.其语法为
@text(['filename'])
这里filename是文件名,可以采用相对路径和绝对路径两种表示方式.如果忽略filename,那么数据就被输出到标准输出设备(屏幕).@text函数仅能出现在模型数据部分的一条语句的左边,右边是集名(用来输出该集的所有成员名)或集属性名(用来输出该集属性的值).
我们把用接口函数产生输出的数据声明称为输出操作.输出操作仅当求解器求解完模型后才执行,执行次序取决于其在模型中出现的先后.
例14 借用例12,说明@text的用法.
(3)@ole函数
@OLE是从EXCEL中引入或输出数据的接口函数,它是基于传输的OLE技术.OLE传输直接在内存中传输数据,并不借助于中间文件.当使用@OLE时,LINGO先装载EXCEL,再通知EXCEL装载指定的电子数据表,最后从电子数据表中获得Ranges(名称框).为了使用OLE函数,必须有EXCEL5及其以上版本.OLE函数可在数据部分和初始部分引入数据.
@OLE可以同时读集成员和集属性,集成员最好用文本格式,集属性最好用数值格式.原始集每个集成员需要一个单元(cell),而对于n元的派生集每个集成员需要n个单元,这里第一行的n个单元对应派生集的第一个集成员,第二行的n个单元对应派生集的第二个集成员,依此类推.
@OLE只能读一维或二维的Ranges(在单个的EXCEL工作表(sheet)中),但不能读间断的或三维的Ranges.Ranges是自左而右、自上而下来读.
例15 用@OLE函数对EXCEL文件进行读写.
代替在代码文本的数据部分显式输入形式,我们把相关数据全部放在如下电子数据表中来输入.下面是D:\IMPORT.XLS的图表(见图1.4.2).
图1.4.2 D:\IMPORT.XLS的内容
除了输入数据之外,我们也必须定义Ranges名:PRODUCT,MACHINE,WEEK,ALLOWED,x,y.具体地,我们需要定义如下的Ranges名:
为了在EXCEL中定义Ranges名,按照以下步骤操作:
①按鼠标左键拖曳选择Range;
②选择“插入|名称|定义”;
③输入希望的名字;
④点击“确定”按钮.
(4)@ranged(variable_or_row_name)
为了保持最优基不变,变量的费用系数或约束行的右端项允许减少的量.
(5)@rangeu(variable_or_row_name)
为了保持最优基不变,变量的费用系数或约束行的右端项允许增加的量.
(6)@status()
返回LINGO求解模型结束后的状态:
0 Global Optimum(全局最优)
1 Infeasible(不可行)
2 Unbounded(无界)
3 Undetermined(不确定)
4 Feasible(可行)
5 Infeasible or Unbounded(通常需要关闭“预处理”选项后重新求解模型,以确定模型究竟是不可行还是无界)
6 Local Optimum(局部最优)
7 Locally Infeasible(局部不可行,尽管可行解可能存在,但LINGO并没有找到)
8 Cutoff(目标函数的截断值被达到)
9 Numeric Error(求解器因在某约束中遇到无定义的算术运算而停止)
通常,如果返回值不是0、4或6时,那么解将不可信,几乎不能用.该函数仅被用在模型的数据部分来输出数据.
例16 显示求解状态.
部分计算结果为:
结果中的6就是@status()返回的结果,表明最终解是局部最优的.
9.辅助函数
(1)@if(logical_condition,true_result,false_result)
@if函数将评价一个逻辑表达式logical_condition,如果为真,返回true_result,否则返回false_result.该函数也可嵌套使用,来表示多分枝的分段函数.
例17 求解最优化问题:
其LINGO代码如下:
若
可使用嵌套格式,其LINGO代码如下:
(2)@warn('text',logical_condition)
如果逻辑条件logical_condition为真,则产生一个内容为'text'的信息框.
例18 x是正数时输出警示信息.
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。