首页 附录 LINGO10.0 新增功能介绍

附录 LINGO10.0 新增功能介绍

举报
开通vip

附录 LINGO10.0 新增功能介绍 附录 LINGO10.0新增功能介绍 A.1 新增功能简介 2006 年初,LINDO 系统公司正式发布了 LINGO 10.0 版本。与 LINGO 9.0 及更早的版 本相比,该版本的主要改进包括三个方面: 1.LINGO 10.0 最显著的新特征在于增强了用 LINGO 编程的能力。这主要包括: (1) 程序流程的控制 在 LINGO 9.0 及更早的版本的计算段(CALC)中,控制程序流程的只有一种语句,即 集合循环函数@FOR 引导的语句,此外所有计算段中的语句是顺序执行的。LING...

附录 LINGO10.0 新增功能介绍
附录 LINGO10.0新增功能介绍 A.1 新增功能简介 2006 年初,LINDO 系统公司正式发布了 LINGO 10.0 版本。与 LINGO 9.0 及更早的版 本相比,该版本的主要改进包括三个方面: 1.LINGO 10.0 最显著的新特征在于增强了用 LINGO 编程的能力。这主要包括: (1) 程序 流程 快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计 的控制 在 LINGO 9.0 及更早的版本的计算段(CALC)中,控制程序流程的只有一种语句,即 集合循环函数@FOR 引导的语句,此外所有计算段中的语句是顺序执行的。LINGO10.0 在 计算段中增加了控制程序流程的语句,主要包括条件分支控制(@IFC 或@IFC/@ELSE 语 句)、条件循环控制(@WHILE 语句)、循环跳出控制(@BREAK 语句)、程序暂停控制 (@PAUSE 语句)以及程序终止控制(@STOP 语句)。 (2) 子模型(SUBMODEL) 在 LINGO 9.0 及更早的版本中,在每个 LINGO 模型窗口中只允许有一个优化模型,可 以称为主模型(MAIN MODEL)。在 LINGO 10.0 中,每个 LINGO 模型窗口中除了主模型 外,用户还可以定义子模型(SUBMODEL)。子模型可以在主模型的计算段中被调用,这就 进一步增强了 LINGO 的编程能力。相应的新增函数还包括@SOLVE、@GEN、@PIC、 @SMPI、@RELEASE 等。 (3) 其他新增函数 LINGO10.0 增加了输出函数@TABLE,可以更方便地以 格式 pdf格式笔记格式下载页码格式下载公文格式下载简报格式下载 化的表格形式输出数据; 新增了数学函数@NORMSINV,即 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 正态分布的分布函数的逆函数;新增了缺省输出设 备(文件)的重定义函数@DIVERT;新增了参数设置函数@SET 和@APISET 等。 2.对 LINGO 内部采用的一些求解程序(如混合整数规划、非线性优化和全局优化求 解程序,包括一些相应的选项)的功能进行了完善和改进,使求解过程更快速、更可靠,对 模型进行调试的能力和对模型错误进行更准确定位的能力也得到了进一步增强。 3.增加了对一些新的软硬件的支持,如支持 64 位运算和更大的内存等,以及支持 Java JNI 接口技术,新的@ODBC 函数支持 Microsoft SQL Server 等。 我们下面只对第1类新增功能(增强 LINGO 编程能力的功能)进行简要介绍,关心第 2、3类新增功能的读者请直接阅读 LINGO 在线帮助文件或相关介绍文档。 A.2程序流程的控制 A.2.1 条件分支控制 在计算段(CALC)中,如果只有当某个条件满足时才执行某个或某些语句,则可以使 用@IFC 或@IFC/@ELSE 语句,其中@ELSE 部分是可选的(在下面的语法中用方括号表示)。 其基本的使用语法是: @IFC(condition: executable statements(可执行语句 1); [@ELSE executable statements(可执行语句 2);] ) 其中 condition 是一个逻辑表达式(表示相应的条件),当 condition 的逻辑值为“真” (条件成立)时,程序执行语句 1;否则程序执行语句 2。 我们以本书第五章 5.2 节(有瓶颈设备的多级生产 计划 项目进度计划表范例计划下载计划下载计划下载课程教学计划下载 快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题 )中的数据来说明这个语句 的用法。在该问题中,项目间的消耗系数 Req是一个非常稀疏的矩阵,仅有 6个非零元。如果 我们想输出这个矩阵,但不显示其中的零元素(即显示为空),可以在原来的程序(本书 177-178 页的程序 exam0502.lg4)中增加以下的计算段: calc: @WRITE( ' 项目间的消耗系数如下:'); @WRITE( @NEWLINE(1)); @WRITEFOR(PART(J): 5*' ', PART(J)); @FOR( PART(I): @WRITE( @NEWLINE(1), PART(I)); @FOR( PART(J): @IFC( Req(i,j) #GT# 0.0: @write( @FORMAT( Req(i,j), '#5.0f')); @ELSE @WRITE(' '); ); ); ); @WRITE( @NEWLINE(2)); endcalc 运行修改后的程序,相应的输出如下(只列出与计算段的输出相关的部分): 项目间的消耗系数如下: A B C D E F G A B 5. C 7. D 9. E 11. F 13. G 15. 下面我们作几点说明: 1.请注意上面程序中的函数@WRITE 和@WRITEFOR,他们在 LINGO9.0 中也出现过 (参见本书 112 页),但当时主要是用在程序的数据段(DATA)方便用户控制输出格式,所 输出的变量的取值是程序运行结束后最后结果的相关数据, 并且输出必须定向到@TEXT 函 数,即通过@TEXT 函数输出到缺省的输出设备(通常就是报告窗口)或文本文件。LINGO10.0 中,这两个函数也是为了方便用户控制输出格式,但它们还可以出现在计算段(CALC)随时 输出中间结果,并且不需要使用@TEXT 函数,输出的结果也是被定向到缺省的输出设备(通 常就是标准的报告窗口)。如果希望改变缺省的输出设备,可以采用@DIVERT 函数(参见 本附录 A.4.3 节)。 作为一个简单例子,我们可以编写以下程序,说明在计算段中可以随时输出中间结果。 calc: a=5; @write('a= ',a,@newline(1)); b=8; a=a+b; @write('a= ',a,@newline(1)); endcalc 以上程序中第 3 行和第 6 行的语句是一样的,但输出结果却会不一样: a= 5 a= 13 2. 请读者特别注意,条件分支控制语句的用法只能出现在计算段(CALC)中。这也意 味着,我们不应该对程序运行结束后才能得到最后结果、计算段中尚未确定具体取值的变量 进行上述判断和输出。否则,输出的取值可能只是变量的初始值或中间计算结果。读者可能 会觉得既然如此,那么这种控制语句的用处就不大了,因为计算段处理的似乎都是已知参数 (或从已知参数很容易直接计算得到的变量值)。实际上并非如此,这是由于 LINGO10.0 增加了子模型功能,而子模型又是可以在计算段进行求解的,这时计算段中的变量所取的值 可能既不是初始参数,又不是整个模型最后的结果,但仍然可以输出中间结果。 而且,LINGO10.0 中还增加了条件循环(@WHILE 语句)等其他复杂的控制语句,它 们通常也要用到@IFC 语句。我们将在后面介绍子模型和条件循环控制时再通过例子进行说 明。 3.请读者注意,@IFC 函数和以前用过的@IF 函数的功能是不同的:@IFC 是引导流程 控制语句的函数(按照不同条件选择不同的程序分支进行执行),而@IF 是一个算术函数, 按照不同条件返回不同的计算结果或表达式(参见本书 114 页的介绍)。 A.2.2 条件循环控制及相关语句 在 LINGO 9.0 及更早的版本中,只有一种控制程序流程的语句,即集合循环函数@FOR 引导的语句,该函数对集合的元素逐个进行循环。在 LINGO 10.0 中,如果只要当某个条 件满足时就反复执行某个或某些语句,直到条件不成立为止,则可以使用@WHILE 语句。 其基本的使用语法是: @WHILE(condition: executable statements(可执行语句); ) 其中 condition 是一个逻辑表达式(表示相应的条件),当 condition 的逻辑值为“真” (条件成立)时,程序就执行相应的语句,直到条件不成立为止。请注意,条件循坏控制也 只能出现在计算段(CALC)中。 在条件循环控制中,还经常会使用到循坏跳出控制(@BREAK 语句)、程序暂停控制 (@PAUSE 语句)以及程序终止控制(@STOP 语句): z @BREAK 函数不需要任何参数,其功能是立即终止当前循环,继续执行当前循环 外的下一条语句。这个函数可以用在条件循环语句(@WHILE 语句)中,也可以 用在集合循环语句(@FOR 语句)中。此外,由于一般是在满足一定的特定条件 时才终止当前循环的执行,所以函数@BREAK 一般也要结合@IFC/@ELSE 使用。 z @PAUSE 函数暂停程序执行,并弹出一个窗口,等待用户选择继续执行(RESUME) 或者终止程序(INTERRUPT)。如果希望在弹出的窗口中显示某些文本信息或某 个变量的当前取值,只需要将这些文本信息或变量作为@PAUSE 的调用参数即可。 z @STOP 函数终止程序的运行,并弹出一个窗口,说明程序已经停止运行。如果希 望在弹出的窗口中显示某些文本信息或某个变量的当前取值,只需要将这些文本或 变量作为@STOP 的调用参数即可。 例如,如果希望从一个递增排列的正整数数列 X 中找到某个具体的数 KEY 在数列 X 中 所在的位置, 可以采用二分搜索算法。具体的程序是(原程序位于 LINGO 安装目录的 examples 目录下,文件名为 LOOPBINS.LG4,这里加上了中文注释): MODEL: TITLE 二分搜索; !Binary-search; SETS: S1: X; ENDSETS DATA: KEY = 16; ! 想要找到的数; X = 2 7 8 11 16 20 22 32; !递增排列的正整数数列; ENDDATA CALC: IB = 1; ! 搜索位置的最小值; IE = @SIZE( S1); ! 搜索位置的最大值(数列中元素的个数); @WHILE( IB #LE# IE: LOC = @FLOOR((IB + IE)/2); ! 二分法; @IFC( KEY #EQ# X(LOC): @BREAK; ! 找到结果,结束循环; @ELSE @IFC( KEY #LT# X( LOC): IE = LOC-1; @ELSE IB = LOC+1; ); ); ); @IFC( IB #LE# IE: @PAUSE( '找到位置: ', LOC); ! 显示结果; @ELSE @STOP( ' 数列中找不到相应的数!!!'); !程序停止运行; ); ENDCALC END 注:这里集合 S1没有显式地定义元素,但由于其属性 X有 8个元素,因此 LINGO自 动认为集合 S1={1,2,3,4,5,6,7,8}。 本程序运行时,将找到 KEY = 16位于数列 X中的第 5个位置,于是通过@PAUSE语句 将这一信息报告给用户;如果取 KEY = 15, 由于数列 X 中没有 15, 程序运行时通过@STOP 语句将这一信息报告给用户。 请读者注意,由于@BREAK函数不需要参数,因此程序中的语句直接写成“@BREAK;”。 而函数@PAUSE 和@STOP 是可以有参数的,所以程序中即使不给出参数,语句也应该写成 “@PAUSE();”和“@STOP();”,即标示参数表的小括号不能省略,否则就会出现语法错误。 这和以前用过的函数@TEXT的用法非常类似。 A.3子模型功能介绍 A.3.1子模型的定义及求解 在 LINGO 9.0 及更早的版本中,在每个 LINGO 模型窗口中只允许有一个优化模型,可 以称为主模型(MAIN MODEL)。在 LINGO 10.0 中,每个 LINGO 模型窗口中除了主模型 外,用户还可以定义子模型(SUBMODEL)。子模型可以在主模型的计算段中被调用,这就 进一步增强了 LINGO 的编程能力。 子模型必须包含在主模型之内,即必须位于以“MODEL:”开头、以“END”结束的模 块内。同一个主模型中,允许定义多个子模型,所以每个子模型本身必须命名,其基本语法 是: @SUBMODEL mymodel: 可执行语句(约束+目标函数); ENDSUBMODEL 其中 mymodel 是该子模型的名字,可执行语句一般是一些约束语句,也可能包含目标 函数,但不可以有自身单独的集合段、数据段、初始段和计算段。也就是说,同一个主模型 内的变量都是全局变量,这些变量对主模型和所有子模型同样有效。 如果已经定义了子模型 mymodel,则在计算段中可以用语句“@SOLVE( submodel);”求 解这个子模型。 我们来看一个背包问题(Knapsack Problem)的例子:王先生想要出门旅行,需要将一 些旅行用品装入一个旅行背包。旅行背包有一个重量限制,装入的旅行用品总重量不得超过 30千克。候选的旅行用品有8件,其重量依次为3、4、6、7、9、10、11、12(千克); 王先生认为这8件旅行用品的价值(或重要性)依次为4、6、7、9、11、12、13、15。那 么,为了使背包装入的旅行用品的总价值最大,王先生应该选择哪几件旅行用品? 我们用 VAL(I)、WGT(I)分别表示第 I 件物品的价值和重量,CAP 表示背包的重量 限制,用 Y(I)表示是否装入第 I件物品(0-1决策变量,1 表示装,0 表示不装)。容易建 立如下优化模型(直接按 LINGO 的程序格式写出,命名为文件 knapsack01.lg4): MODEL: SETS: ITEM: WGT, VAL, Y; ENDSETS DATA: VAL = 4 6 7 9 11 12 13 15; WGT = 3 4 6 7 9 10 11 12; CAP = 30; ENDDATA MAX = OBJ; [Objective] OBJ= @SUM( ITEM(j): VAL(j)*Y(j)); !目标; [Capacity] @SUM( ITEM(j): WGT(j)*Y(j)) <= CAP;!重量约束; @FOR( ITEM(j): @BIN( Y(j))); !0/1变量; END 求解本模型,可得到最优解 Y(2)=Y(4)=Y(5)=Y(6)=1(其他 Y(I)为 0),最优值 OBJ=38。 对于这样一个简单的模型,上面的程序中只有主模型。作为一种练习,我们也可以将这 个模型定义为子模型,然后在 CALC 中进行求解,相应的程序为(命名为文件 knapsack02.lg4)): MODEL: SETS: ITEM: WGT, VAL, Y; ENDSETS DATA: VAL = 4 6 7 9 11 12 13 15; WGT = 3 4 6 7 9 10 11 12; CAP = 30; ENDDATA SUBMODEL KNAPSACK: !开始定义子模型KNAPSACK; MAX = OBJ; [objective] OBJ= @SUM( ITEM(j): VAL(j)*Y(j)); !目标; [capacity] @SUM( ITEM(j): WGT(j)*Y(j)) <= CAP;!重量约束; @FOR( ITEM(j): @BIN( Y(j))); !0/1变量; ENDSUBMODEL ! 完成子模型KNAPSACK的定义; CALC: @SOLVE(KNAPSACK); ! 求解子模型KNAPSACK; ENDCALC END 求解本模型,得到的结果与不用子模型时相同。 A.3.2 求背包问题的多个最好解的例子 对于上面的背包问题,最优解并不是唯一的。如果我们希望找到所有的最优解(最优值 OBJ=38 的所有解),有没有办法呢?更一般地,能否找出前 K 个最好的解?这样我们可以 把这 K 个最好的解全部列出来,供王先生(决策者)选择。 为了得到第 2 个最好的解,我们需要再次求解子模型 KNAPSACK,但必须排除再次找到 刚刚得到的解 Y(2)=Y(4)=Y(5)=Y(6)=1(其他 Y(I)为 0)。因此,我们需要在第 2 次求解子模型 KNAPSACK时,增加一些约束条件(一般称为“割”)。生成“割”的方法可能有很多种, 这里我们介绍一种针对 0-1变量的特殊处理方法。 对于我们刚刚得到的解 Y(2)=Y(4)=Y(5)=Y(6)=1(其他 Y(I)为 0),显然满足 Y(1) - Y(2) + Y(3) - Y(4) - Y(5) - Y(6) + Y(7) + Y(8) = -4; 这个等式左边就是将刚刚得到的解中取 1 的 Y(I)的系数定义为-1,取 0 的 Y(I)的系数定义 为 1,然后求代数和;等式右边就是解中取 1 的 Y(I)的个数的相反数。 为了防止再次求解子模型 KNAPSACK时这个解再次出现,就是要防止 Y(2),Y(4),Y(5), Y(6)同时取 1 的情况出现。下面的约束就可以保证做到这一点: Y(1) - Y(2) + Y(3) - Y(4) - Y(5) - Y(6) + Y(7) + Y(8) >= -3; 这个约束就是将上面等式中的右端项增加了 1,将等号“=”改成了“>=”。显然,这 个约束排除了 Y(2),Y(4),Y(5),Y(6)同时取 1 的情况,因为 Y(2),Y(4),Y(5),Y(6)同时 取 1(其他 Y(I)=0)不能满足这个约束。其次,由于 Y(I)只能取 0 或 1,这个约束除了排除 Y(2),Y(4),Y(5),Y(6)同时取 1 的情况外,没有对原可行解空间增加任何新的限制。 可以想象,增加这个约束后,新的最优解一定与 Y(2)=Y(4)=Y(5)=Y(6)=1(其他 Y(I)为 0)不同。这种处理方法具有一般性,可以用于找出背包问题的前 K 个最好解。 具体的程序如下(以下程序中取 K=7,命名为文件 knapsack03.lg4)): SETS: ITEM: WGT, VAL, Y; SOLN: RHS; ! RHS表示根据每个最优解生成“割”时的右端项; SXI(SOLN,ITEM): COF; ! “割”的系数,即1或-1; ENDSETS DATA: K=7; VAL = 4 6 7 9 11 12 13 15; WGT = 3 4 6 7 9 10 11 12; CAP = 30; SOLN = 1..K; ENDDATA SUBMODEL KNAPSACK: MAX = OBJ; OBJ= @SUM( ITEM(j): VAL(j)*Y(j)); !目标; @SUM( ITEM(j): WGT(j)*Y(j)) <= CAP; !重量约束; @FOR( ITEM(j): @BIN( Y(j))); !0/1变量; @FOR( SOLN(k)| k #LT# ksofar: !"割去"(排除)已经得到的解; @SUM( ITEM(j): COF(k,j)*Y(j)) >= RHS(k); ); ENDSUBMODEL CALC: @divert('knapsack.txt'); ! 结果保存到文件knapsack.txt; @FOR( SOLN(ks): ! 对ks=1,2,…,K进行循环; KSOFAR = ks; ! KSOFAR表示当前正在计算的是第几个最优解; @SOLVE( KNAPSACK); RHS(ks) = 1; ! 以下打印当前(第ks个)最优解Y及对应的最优值OBJ; @WRITE(' ',ks,' ', @FORMAT( OBJ,'3.0f'),':'); @writefor(ITEM(j):' ',Y(j)); @write(@newline(1)); ! 以下计算这个解生成的“割”的系数; @FOR( ITEM(j): @IFC( Y(j) #GT# .5: COF(KS,j) = -1; RHS(ks) = RHS(ks) - 1; @ELSE COF(KS,j) = 1; ); ! 分支 @IFC / @ELSE 结束; ); ! 循环 @FOR( ITEM(j)结束; ); ! 对ks的循环结束; @divert();! 关闭文件knapsack.txt,恢复正常输出模式; ENDCALC 注:计算段中的语句@divert('knapsack.txt')的含义是,将此后的输出定向到文 本文件knapsack.txt(参见本附录A.4.3节)。 运行这个程序以后,文件 knapsack.txt中将包括以下输出(其他输出略去): 1 38: 0 1 0 1 1 1 0 0 2 38: 1 1 1 1 0 1 0 0 3 38: 1 1 0 0 0 0 1 1 4 37: 1 1 0 0 0 1 0 1 5 37: 0 1 1 1 0 0 0 1 6 37: 1 1 1 1 1 0 0 0 7 37: 0 1 1 0 1 0 1 0 可见,前 7 个最好的解中,最优值为 OBJ=38 的解一共有 3 个,而 OBJ=37 的解至少有 4 个(因为我们只计算了前 7 个最好的解,我们暂时还无法判断 OBJ=37 的解是否只有 4 个), 每个解(Y 的取值)也显示在结果报告中了。 A.3.3 多个子模型的例子 同一个 LINGO 主模型中,允许定义多个子模型。例如,如果我们希望分别求解以下 4 个优化问题: (1) 在满足约束 x2+4y2≤ 1且 x,y非负的条件下,求 x-y的最大值; (2) 在满足约束 x2+4y2≤ 1且 x,y非负的条件下,求 x+y的最小值; (3) 在满足约束 x2+4y2≤ 1且 x,y可取任何实数的条件下,求 x-y的最大值; (4) 在满足约束 x2+4y2≤ 1且 x,y可取任何实数的条件下,求 x+y的最小值。 我们可以编写如下 LINGO 程序: MODEL: SUBMODEL OBJ1: MAX=X-Y; ENDSUBMODEL SUBMODEL OBJ2: MIN=X+Y; ENDSUBMODEL SUBMODEL CON1: x^2+4*y^2<=1; ENDSUBMODEL SUBMODEL CON2: @free(x); @free(y); ENDSUBMODEL CALC: @write('问题1的解:', @newline(1)); @solve(OBJ1,CON1); @write('问题2的解:', @newline(1)); @solve(OBJ2,CON1); @write('问题3的解:', @newline(1)); @solve(OBJ1,CON1,CON2); @write('问题4的解:', @newline(1)); @solve(OBJ2,CON1,CON2); ENDCALC END 这个程序中定义了4个子模型,其中OBJ1和OBJ2只有目标(没有约束),而CON1和CON2 只有约束(没有目标)。在计算段,我们将它们进行不同的组合,分别得到针对问题(1)~(4) 的优化模型进行求解。但需要注意,每个@solve命令所带的参数表中的子模型是先合并后求解 的,所以用户必须确保每个@solve命令所带的参数表中的子模型合并后是合理的优化模型,例 如最多只能有一个目标函数。 运行这个后,得到的正是我们预想的结果(只列出部分相关的输出结果): 问题1的解: Objective value: 1.000000 Variable Value Reduced Cost X 1.000000 0.5198798E-08 Y 0.4925230E-08 1.000000 问题2的解: Objective value: 0.2403504E-09 Variable Value Reduced Cost X 0.000000 1.000000 Y 0.000000 1.000000 问题3的解: Objective value: 1.118034 Variable Value Reduced Cost X 0.8944272 0.000000 Y -0.2236068 0.000000 问题4的解: Objective value: -1.118034 Variable Value Reduced Cost X -0.8944272 0.000000 Y -0.2236068 0.000000 这4个问题都是非常简单的问题,最优解和最优值很容易用解析方法计算得到,读者不 妨用解析方法计算和验证一下以上得到的解的正确性。 A.3.4 其他相关函数 1.@GEN 这个函数只能在计算段使用,功能与菜单命令 LINGO|Generate 和 LINGO 行命令 GEN 类似(参见本书 118 页和 132 页),即生成完整的模型并以代数形式显示(主要作用是可供 用户检查模型是否有误)。当不使用任何调用参数时,“@GEN();”语句只对主模型中出现 在当前“@GEN();”语句之前的模型语句进行处理。 例如,如果在上面 A..3.1 节的文件 knapsack01.lg4 中增加以下的计算段: calc: @gen(); endcalc 则程序运行时报告窗口的显示为: MODEL: [_1] MAX= OBJ ; [OBJECTIVE] OBJ - 4 * Y_1 - 6 * Y_2 - 7 * Y_3 - 9 * Y_4 - 11 * Y_5 – 12 * Y_6 - 13 * Y_7 - 15 * Y_8 = 0 ; [CAPACITY] 3 * Y_1 + 4 * Y_2 + 6 * Y_3 + 7 * Y_4 + 9 * Y_5 + 10 * Y_6 + 11 * Y_7 + 12 * Y_8 <= 30 ; @BIN( Y_1); @BIN( Y_2); @BIN( Y_3); @BIN( Y_4); @BIN( Y_5); @BIN( Y_6); @BIN( Y_7); @BIN( Y_8); END 用户可以指定@GEN 处理哪个(或多个)子模型,这只需要将子模型名(可以多个) 作为调用@GEN 函数的参数即可。如果为@GEN 函数指定多个子模型作为调用参数,则显 示的是这几个子模型合并后的结果。 例如,如果在上面 A..3.1 节的文件 knapsack02.lg4 的计算段中增加以下语句: @gen(KNAPSACK); 则程序运行时报告窗口的显示与上面的显示相同(因为 knapsack02.lg4 的子模型 KNAPSACK 与 knapsack01.lg4 的主模型本质上是一样的)。 注意:如果在上面 A..3.2 节的文件 knapsack03.lg4 的计算段中不同的位置增加 @gen(KNAPSACK)语句,将得到不同的输出结果。这是因为在计算段中不同的位置,子模 型 KNAPSACK 的具体内容是有可能发生变化的(因为“割”在不断增加)。例如,如果将 @gen(KNAPSACK)语句增加在计算段的最后,得到的输出为(可以看出此时模型中有 6个 “割”,即约束[_4]~[_9]): MODEL: [_1] MAX= OBJ ; [_2] OBJ - 4 * Y_1 - 6 * Y_2 - 7 * Y_3 - 9 * Y_4 - 11 * Y_5 - 12 * Y_6 - 13 * Y_7 - 15 * Y_8 = 0 ; [_3] 3 * Y_1 + 4 * Y_2 + 6 * Y_3 + 7 * Y_4 + 9 * Y_5 + 10 * Y_6 + 11 * Y_7 + 12 * Y_8 <= 30 ; [_4] Y_1 - Y_2 + Y_3 - Y_4 - Y_5 - Y_6 + Y_7 + Y_8 >= - 3 ; [_5] - Y_1 - Y_2 - Y_3 - Y_4 + Y_5 - Y_6 + Y_7 + Y_8 >= - 4 ; [_6] - Y_1 - Y_2 + Y_3 + Y_4 + Y_5 + Y_6 - Y_7 - Y_8 >= - 3 ; [_7] - Y_1 - Y_2 + Y_3 + Y_4 + Y_5 - Y_6 + Y_7 - Y_8 >= - 3 ; [_8] Y_1 - Y_2 - Y_3 - Y_4 + Y_5 + Y_6 + Y_7 - Y_8 >= - 3 ; [_9] - Y_1 - Y_2 - Y_3 - Y_4 - Y_5 + Y_6 + Y_7 + Y_8 >= - 4 ; @BIN( Y_1); @BIN( Y_2); @BIN( Y_3); @BIN( Y_4); @BIN( Y_5); @BIN( Y_6); @BIN( Y_7); @BIN( Y_8); END 2.@PIC 这个函数只能在计算段使用,功能与菜单命令 LINGO|Picture 和行命令 Pic 类似(参见本 书 118 页和 61 页),即以图形形式显示模型的大致模样(主要作用是可供用户检查模型是 否有误)。其使用方法与@GEN 完全类似。 例如,如果将@pic(KNAPSACK)语句增加在文件 knapsack03.lg4 计算段的最后,得到的 输出为: Y Y Y Y Y Y Y Y O ( ( ( ( ( ( ( ( B 1 2 3 4 5 6 7 8 J ) ) ) ) ) ) ) ) 1: 1 ' ' MAX 2: 1-4-6-7-9-B-B-B-B = 0 3: ' 3'4 6 7'9 B B'B < B 4: ' 1-1 1-1-1-1 1 1 >-3 5: '-1-1-1-1 1-1 1 1 >-4 6: '-1-1 1 1'1 1-1-1 >-3 7: '-1-1 1 1 1-1 1-1 >-3 8: ' 1-1-1-1 1 1 1-1 >-3 9: '-1-1-1-1-1 1 1'1 >-4 对于其中系数矩阵和右端项的字符的含义,可以参考相应的行命令 Pic(参见本书 61 页)。 3.@SMPI 这个函数只能在计算段使用,功能与 LINGO 行命令 SMPI 类似(参见本书 132 页),即 以 MPI 文件格式(这是 LINDO API 专用的一种文件格式)将模型保存到文件,在需要时这 个文件可供 LINDO API 使用。 调用@SMPI 时的第一个参数必须是将要保存到的文件的文件名,其他参数的要求与 @GEN 相同。也就是说,子模型(一个或多个)也是可以保存为 MPI 格式的文件。 4.@RELEASE 一般来说,如果一个变量 X 在计算段中被赋值(或通过计算确定了它的值),这个变量 在模型求解时就被认为是常数,不再作为决策变量进行优化。如果希望在模型求解时仍然将 它作为决策变量进行优化,可以在计算段中使用@RELEASE 函数。其用法是: @RELEASE(X); A.4其他新增函数 A.4.1 函数@NORMSINV 的用法 该函数是一个一元函数,即标准正态分布的分布函数的逆函数,其输入参数必须是一个 不超过1的非负数。记输入参数 p,则@NORMSINV(p)计算标准正态分布 N(0,1)的 p 分 位数,结果可以取任意实数。 例如,如果在 LINGO 中输入以下语句(注意这里的@free(y)语句是为了让 y 有机会取负 值,因为 LINGO 中变量缺省为非负): x=@normsinv(0.5); y=@normsinv(0.2); @free(y); z=@normsinv(0.8); 得到的输出为(注意 x 并不严格等于精确值0,这是由于计算精度的影响): X 0.1490050E-07 Y -0.8416212 Z 0.8416212 容易知道,对于一个一般的正态分布 N(u,s2),则其 p 分位数为 u+s2* @NORMSINV(p)。 A.4.2 函数@TABLE 的用法 该函数以表格形式输出与集合和集合的属性相关的数据,并且只能在数据段(DATA) 中使用。目前该函数仅用于将数据输出到结果报告窗口或文本文件中,而不能输出到数据库 或电子表格(EXCEL)文件中。也就是说,只能输出到@TEXT 函数,而不能输出到@OLE 和@ODBC 函数。 如果该函数只有一个输入参数,则该输入参数必须是一个集合名或者是集合的某个属性 名:当输入参数是一个集合名时,则显示该集合的成员(元素),对应的位置显示为“X” (其他位置显示为空);当输入参数是一个属性名时,则对应的位置显示该属性(数组变量) 的具体取值。 例如,对于第三章例 3.5(最短路问题),如果在程序的数据段(DATA)中增加以下语句: @text()=@table(ROADS); @text()=@table(D); 得到的输出为: S A1 A2 A3 B1 B2 C1 C2 T S X X X A1 X X A2 X X A3 X X B1 X X B2 X X C1 X C2 X T S A1 A2 A3 B1 B2 C1 C2 T S 6 3 3 A1 6 5 A2 8 6 A3 7 4 B1 6 7 B2 8 9 C1 5 C2 6 T 我们作几点说明: 1.如果某一行显示不下,则会简单地换行进行显示。如果对应的集合只是一维的,则 显示时集合的元素(属性的下标)按列向量排列。如果对应的集合为二维或更多,则将最后 一维显示在水平行,其他维显示在纵向列中。 例如,如果编写以下简单的程序: sets: Set_a/1 2/; Set_b/a b/; Set_c/x,y/; Set_d/m,n/; set(set_a,set_b,set_c,set_d); endsets data: @text()=@table(set); enddata 显示的结果为: M N 1 A X X X 1 A Y X X 1 B X X X 1 B Y X X 2 A X X X 2 A Y X X 2 B X X X 2 B Y X X 2.以上这种显示顺序也是可以由用户控制的: (1) 如果在@table 的第一个输入参数(集合名或者是集合的某个属性名)后面写上 一个正整数 H 作为第二个输入参数,则将最后 H 维显示在水平行(自然,H 不应该超过集 合的最大维数),其他维显示在纵向列中。因此,如果将上面的语句@text()=@table(set) 改为@text()=@table(set,1),效果是一样的;如果改为@text()=@table(set,2),则 将最后 2 维(第 3、4维)显示在水平行,效果如下所示: X X Y Y M N M N 1 A X X X X 1 B X X X X 2 A X X X X 2 B X X X X (2) 如果集合的维数是 n,在@table 的第一个输入参数(集合名或者是集合的某个属 性名)后面可以写上 n 个正整数 k1,k2,..., kn(这是 1,2,..., n 的一个排列),则显示时按照第 k1,k2,..., kn 维的顺序输出 , 并将第 kn 维显示在水平行。因此,上面例子中的语句 @text()=@table(set)与@text()=@table(set,1,2,3,4)的效果是一样的;如果改为 @text()=@table(set,4,3,2,1),显示如下所示: 1 2 M X A X X M X B X X M Y A X X M Y B X X N X A X X N X B X X N Y A X X N Y B X X (3)如果集合的维数为 n,并在@table 的第一个输入参数(集合名或者是集合的某个 属性名)后面写上 n 个正整数 k1,k2,..., kn(这是 1,2,..., n 的一个排列),此外再增加一个正 整数 H, 则显示时按照第 k1,k2,..., kn 维的顺序输出, 并将 k1,k2,..., kn 中最后面的 H 维显示 在水平行(其中 H 不应该超过 n-1)。因此,上面例子中的语句@text()=@table(set)与 @text()=@table(set,1,2,3,4,1) 的 效 果 也 是 一 样 的 ; 如 果 改 为 @text()=@table(set,4,3,2,1,2),显示如下所示(注意此时最后两维也就是原 set 集合 的第 2维和第 1维): A A B B 1 2 1 2 M X X X X X M Y X X X X N X X X X X N Y X X X X 我们这里给出的例子都是针对输出集合元素的,对于输出属性变量的情形,使用方法与 此完全类似。这里的例子中 set 是一个稠密集合,对于稀疏集合的情形,使用方法也与此完 全类似。 A.4.3 函数@DIVERT 的用法 该函数只能用在计算段(CALC),可以改变缺省的输出设备。其用法与数据段(DATA) 中的@TEXT 函数类似,即具体用法是: @DIVERT('filename') 其中 filename 是表示文件名的字符串(最好写上完整的路径名,以方便找到这个文件)。 程序运行时将生成文本文件 filename(如果这个文件已经存在,旧文件将被新生成的文件覆 盖), 以后的输出直接写入到这个文件,直到再次遇到“@DIVERT()”语句时关闭这个文件, 结束这一输出模式。 在 A.3.2 节,我们已经使用过这个函数。我们下面再举一个例子: sets: Set_a/1 2/; Set_b/a b/; Set_c/x,y/; Set_d/m,n/; set(set_a,set_b,set_c,set_d); endsets calc: @divert('abc.txt'); @writefor(set(i,j,p,r):i+j+p+r, ' '); @divert(); endcalc 运行后,文本文件 abc.txt的内容为: 4 5 5 6 5 6 6 7 5 6 6 7 6 7 7 8 如果文本文件已经存在,而希望将新的输出结果追加到原文件内容后面,可以通过增加 一个参数’A’实现。例如,如果将上面的计算段改为: @divert('abc.txt','a'); @write (@newline(1)); @writefor(set(i,j,p,r):i+j+p+r, ' '); @divert(); 再运行一次,发现文本文件 abc.txt的内容为: 4 5 5 6 5 6 6 7 5 6 6 7 6 7 7 8 4 5 5 6 5 6 6 7 5 6 6 7 6 7 7 8 最后指出,@divert函数是可以嵌套使用的,从而在计算段中就可以实现将不同的内容写 入到多个文件中去。读者不妨自己试试。 A.4.4 函数@SET 和@APISET 的用法 在以前的 LINGO 版本中,LINGO 系统的各种控制参数和选项只能通过菜单命令 LINGO|Options(Ctrl+I)进行修改(参见本书 119-130页),或者通过命令行命令 SET 和 APISET 进行修改(参见本书 132 页)。在 LINGO10.0 中,则允许用户在计算段中通过函数@SET 和@APISET 对各种控制参数和选项进行修改(@SET 只能修改 LINGO 系统的参数,而 @APISET 可以修改 LINDO API 的所有参数)。这些修改后的参数取值只有当当前模型运行 (求解)时有效,一旦当前模型的求解完成(程序运行结束),所有参数值就会自动恢复到 原有的状态。这两个函数同样只能在计算段中使用。 我们下面只给出几个例子,详细内容请参看 LINGO 在线帮助文件或其他相关文档。 @SET(‘IPTOLR’, .05); ! 将参数 IPTOLR 的值设为 0.05; @SET(‘IPTOLR’);
本文档为【附录 LINGO10.0 新增功能介绍】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_042127
暂无简介~
格式:pdf
大小:159KB
软件:PDF阅读器
页数:16
分类:
上传时间:2010-09-28
浏览量:35