当前位置:文档之家› GAMS中文教程

GAMS中文教程

GAMS中文教程
GAMS中文教程

二GAMS简明教程由Richard E. Rosenthal编著

(译者:该翻译由华中科技大学能源与动力工程学院小海完成,由于译者水平有限,其中肯定会有些问题,欢迎大

家阅读并批评指正!)

2.1 简介

这本书的简介部分以一个详细的例子结束,这个例子是一个用GAMS进行表达、解决和分析的小而简单的优化问题。

由来自蒙特利尔市Naval研究生院的Richard E.Rownthal编写。通过这个例子我们可以对GAMS有一个快速而全面的

了解。很多地方引用到本书其他章节的知识,方便大家进一步查阅;而阅读这一部分即使不看本书其他章节也能看

懂并且有所收获。

例子是一个关于运输的线性规划问题,这个问题在最优化技术发展过程中曾经被当做实验对象。用这个例子展示

GAMS这类代数建模语言的强大功能是很好的选择,因为不管手头要处理的问题有多大,运输问题本身具有一个简

单的、可用的代数结构。你可以发现,如果要解决一个非常大的运输问题,我们将呈现的用于解决小规模运输问题

的GAMS输入文件中的内容并不需要改变多少。

在熟悉的运输问题中,我们考虑几个工厂的供应和几个市场的需求的商品,我们也给出从工厂运输商品到市场的单

位花费。这其中的经济学问题是:怎样安排运输使得我们的总运输成本最小?

这个问题的代数表达常常采用下列方式:

Indices:

i = plants

j = markets

Given Data:

i

a= supply of commodity of plant i (in cases)

ij

b= demand for commodity at market j

ij

c = cost per unit shipment between plant i an

d market j ($/case)

Decision Variables:

ij

x = amount of commodity to ship from plant i to market j (cases),

Where

ij

x ≥0, for all i, j

Constraints:

Observe supply limit at plant i:

j

ij j

a x≤∑for all i (cases)

Satisfy demand at market j:

ij j

i

x b ≥∑for all j (cases)

Objective Function: Minimize

ij ij

ijcx ∑∑($K)

注意这个例子显示了一些一般情况下我们认为是好习惯的建模方式,这些在GAMS里面被继承了。首先,模型程序

中的各组成部分都按类型分组定义了。其次,GAMS程序各组成部分先后次序已经定好了,因此没有标识符能在被

定义之前使用。第三,各组成部分都有特定的单位。第四,选择的单位要使优化过程中得到的数值具有相对较小的

绝对数量级。(例如标识$K表示dollar的千倍)

各组成部分类型的名称在不同的模型中可能不一样。例如,经济学家分别用外生变量和内生变量来表示已知数据和

决策变量。(译者:在经济模型中,内生变量是指该模型所要决定的变量。外生变量指由模型以外的因素所决定的

已知变量,它是模型据以建立的外部条件。内生变量可以在模型体系内得到说明,外生变量决定内生变量,而外生

变量本身不能在模型体系中得到说明。参数通常是由模型以外的因素决定的,因此也往往被看成外生变量。例:

P=a+bQ,表示价格与数量的关系,则a、b是参数,都是外生变量;P、Q是模型要决定的变量,所以是内生变量。

除此之外,譬如相关商品的价格,人们的收入等其他于模型有关的变量,都是外生变量)在GAMS中,被采用的相关术语是:sets表示指数下标,parameters表示已知数,variables 表示决策变量,equations

表示约束方程和目标方程。

运输问题的GAMS语言表述紧密的联系了上述几个部分。最主要的区别在于GAMS表述可以被电脑读取和运行。

作为运输问题的例子,假设有两个罐头厂和三个市场,已知数据如表2.1所示。运输距离的单位是千英里,运输成

本是$90.00每箱每千英里。这个例子的GAMS表述是:

Sets

i canning plants / seattle, san-diego /

j markets / new-york, chicago, topeka / ;

Parameters

a(i) capacity of plant i in cases

/ seattle 350

san-diego 600 /

b(j) demand at market j in cases

/ new-york 325

chicago 300

topeka 275 / ;

Table d(i,j) distance in thousands of miles

new-york chicago topeka

seattle 2.5 1.7 1.8

san-diego 2.5 1.8 1.4 ;

Scalar f freight in dollars per case per thousand miles /90/ ;

Parameter c(i,j) transport cost in thousands of dollars per case ;

c(i,j) = f * d(i,j) / 1000 ;

Variables

x(i,j) shipment quantities in cases

z total transportation costs in thousands of dollars ;

Positive Variable x ;

Equations

cost define objective function

supply(i) observe supply limit at plant i

demand(j) satisfy demand at market j ;

cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ;

supply(i) .. sum(j, x(i,j)) =l= a(i) ;

demand(j) .. sum(i, x(i,j)) =g= b(j) ;

Model transport /all/ ;

Solve transport using lp minimizing z ;

Display x.l, x.m ;

如果你在GAMS中建立一个文件,将以上内容输入进去,运输模型就可以被建立和进行计算了。要使GAMS在不同

的计算机上运行需要改变一些细节,但是最简单的方法(不提供非必要服务的方法)是在输入文件的名字后面加上

GAMS这几个字母。在程序运行过程中,你将看到一些精练的描述GAMS运行过程的字符行,包括了写入输出结果

的文件名。当GAMS程序结束时,检查文件,如果一切正常的话,那么最优化运输方案将显示如下:

new-york chicago topeka

seattle 50.000 300.000

san-diego 275.000 275.000

你还可以得到如下所示边际成本(单纯形乘数):

chicago topeka

seattle 0.036

san-diego 0.009

这些结果表明,举例来说,采用最优化方案就不要从Seattle送货到Topeka,但是你坚持要这样做的话,你将比最

优化方案多付0.036$K($36.00)每箱的成本。(你能从优化运输方案和已知数据中证明这个数据的正确性吗?)

(译者:可以这样想,因为只能由Seattle和San Diego向Topeka送货,为了满足Topeka市场275箱的需求,从San

Diego少送一箱就要从Seattle补送一箱,这样算来,多出的成本就等于(1.8‐1.4)*90=36)2.2 GAMS模型的结构

本章的剩余部分我们将讨论GAMS模型的基本组成部分,还是以上面提到的运输问题为例。表2.2列出了基本组成

部分。

GAMS中有可供用户选择的输入模块,例如编辑损坏数据的检查信息和要求显示客户结果列表。其他可供选择的高

级特征包括保存和恢复原模型,以及在一次运行中创建联合模型,但是这个教程仅仅讨论基本的部分。

在开始介绍各个部分之前,以下几点需要说明:

1. GAMS模型是指一组GAMS语言表述的集合。而组织这些表述的唯一规则是在模型的一个部分被声明之前它是

无法被引用的。

2. GAMS的表述能以任何一种吸引人的排版方式呈现在用户眼前,一个表述占用多行,插入空白行,以及一行中

多个表述都是可以的。在这个教程中你可以了解那些是被允许的格式,但是一些更详细的规则将在下一章给出。

3. 如果你是GAMS新手,你应该在每一个表述的最后加上分号,如例中所示。GAMS编译器不区分大小写字母,

你可以随意使用。

4. 说明文档方便用户看懂数学模型。说明文档整个集中的被包含在模型表述中比把它分开书写要更为有效(往往

也更为准确)。至少有两种方法向GAMS模型中插入此类说明文件。第一,GAMS编译器将把以一个星号开头的

行作为注解行。第二,或许更为重要,可以用特定的GAMS语句插入说明文档。在运输模

型中所有的小写文字

都是以第二种形式插入的说明文档。

Inputs:

Sets

Declaration

Assignment of members

Data (Parameters, Tables, Scalars)

Declaration

Assignment of values

Variables

Declaration

Assignment of type

Assignment of bounds and/or initial values (optional)

Equations

Declaration

Definition

Model and Solve statements

Display statement (optional)

Outputs:

Echo Print

Reference Maps

Equation Listings

Status Reports

Results

Table 2.2: The basic components of a GAMS model

5. 正如你看到的以上输入部分,建构GAMS组成部分包括两个部分:声明以及赋值或者定义。声明是指表明其存

在性并且给其取个名字。赋值或者定义是指给其赋予某个值或者格式。以equations为例,你必须用单独的GAMS

表述声明和定义它。然而对于其他所有的GAMS组成部分,你可以选择在同一个表述中或者单独对其进行声明

或赋值。

6. 模型各组成部分的名字必须以字母开头,并且长度不超过31个字符,除第一个字符外可以使用字母或数字。

2.3 Sets 指数下标

Sets是GAMS模型基本的组成部分,它如同数学公式中的指数下标。运输例子中该部分表述如下:

Sets

i canning plants / seattle, san-diego /

j markets / new-york, chicago, topeka / ;

本表述的作用很明显。我们声明了两个指数下标并且给它们起名为i 和j。我们还给它们赋了值:

i = {Seattle, San-Diego}

j = {New York, Chicago, Topeka};

你应该注意到GAMS格式和一般数学格式对于列举指数下标元素的区别。GAMS用‘/’斜杠而不是用‘{}’大括号,

这是因为不是所有的电脑键盘都有大括号这个键。同时注意到在这里多字名如‘New York’不能使用而用了连字号。

Sets表述中小写文字被称为文本。文本可有可无。它们仅为内部文档存在,在模型中没有正式的作用。GAMS编译

器不会在意文本的含义,但是为了方便用户,会保留文本并呈现给用户多次。

将i 和j 的表述合并并不是必要的。我们也可以将它们分开:

Set i canning plants / seattle, san-diego / ;

Set j markets / new-york, chicago, topeka / ;

至于使用多少空格和空行(如用大或者小写一样)完全取决于用户。每一个GAMS用户都愿意遵从自己的格式习惯。

(用单数set还是负数sets也取决于用户。在进行单个声明的表述中用set,在进行多个声明的表述中用sets,这是

符合英语语法的,但是GAMS不区分set和sets。)

当要赋的值是一个系列的时候,用星号*是很方便的。例如:

Set t time periods /1991*2000/;

Set m machines /mach1*mach24/;

这就相当于:

t = {1991,1992,1993, ....., 2000}

m = {mach1, mach2,......, mach24};

这里将赋的值看成字符串,所以t的值不是数字。

另外一个好用的表述是alias,它可以给先前声明的set另外一个名字。例如:

Alias (t,tp);

在一般数学表达中tp和t’相似。这对于包含有同一个set中元素交互作用的模型很有用。例子所示的i,j,t 和m是静态的指数下标,它们包含的元素由用户赋予并且不会改变。GAMS有一定的建立动态

指数下标的能力,这要求它们包含的元素执行集理论和进行逻辑操作。章节12第107面将讨论动态指数下标。另

外一个有价值的高级特征是多维指数下标,将在4.5节,39页进行说明。

2.4 数据

运输模型GAMS表述展示了所有的三种基本的数据输入格式。它们是列表、表格和直接赋值。

下面三个小节将讨论这三种格式。

2.4.1 列表数据输入

第一种数据输入方式由例子中首个Parameters表述呈现出来:

Parameters

a(i) capacity of plant i in cases

/ seattle 350

san-diego 600 /

b(j) demand at market j in cases

/ new-york 325

chicago 300

topeka 275 / ;

这个表述的意思仍然是很明显的,但是有必要分析下其中的细节。这个表述声明了两个参量的存在,取名为a和b,

并分别给出了指数域i 和j(指数域是指指数下标,或者指数小标元组,参量、变量或者方程式在其中被定义)。该

表述同时给出了每个参量的说明文档并且对于每个i 和j 赋予了a(i)和b(j)相应的值。如果你愿意的话,也可以用两

个表述来代替这一个表述:

Parameters a(i) capacity of plant i in cases

/ seattle 350

san-diego 600 / ;

Parameters b(j) demand at market j in cases

/ new-york 325

chicago 300

topeka 275 / ;

当使用列表方式输入数据时应该注意:

1. 只要你愿意你可以以几乎所有的方式呈现出指数域元素和与它们对应的各参量值的列表。唯一的规定是整个列

表需要用斜杠包括起来,并且各个元素和它们对应的值必须用逗号分开或者从不同的行中输入。

2. 在该列表中不需要用分号将名字、指数域和说明文档隔开。这是因为当你使用列表方式时这个表述即被当做声

明过程又被当做赋值过程。(这种列表本身不能被GAMS识别,将会导致报错)

3. GAMS编译器有一个称为域检查的特征,它将确认域中各元素是否是相应指数下标中的元素。例如,你把set i

的声明中的“Seattle”在后面的元素值列表中误拼成“Seatle”,GAMS编译器将报错并给出信息指出“Seatle”

不属于set i。

4. 所有参量的默认值是0。因此,你只需要在列表中输入非零量即可,输入的顺序任意。

5. 标量是指没有域的参量,通过Scalar表述来声明和赋值,标量只有一个值,如下所示运输模型中的表述:

Scalar f freight in dollars per case per thousand miles /90/;

如果一个参量的域是二维或者多维的,它仍然可以用列表格式输入其值。这对于输入稀疏的(有少数非零值)和非

常稀疏的(有少数不等的非零值)矩阵很有帮助。

2.4.2 表格数据输入

有时候优化工作者会注意到一个大模型的输入数据源于一些相对较小的数据表格。那么,用表格形式来输入数据是

很方便的。下面是运输模型中的一个二维表格:

Table d(i,j) distance in thousands of miles

new-york chicago topeka

seattle 2.5 1.7 1.8

san-diego 2.5 1.8 1.4 ;

这个表述的作用是声明了参量d并且如同i 和j 的笛卡尔积一样按顺序排好相应域。d的值在对应的标题下被给出。

在表格中出现空白输入的话将被看做0对待。

就像在列表格式中,GAMS在这里也将用域检查来确定行名和列名是不是相应域下的元素。而对于在一行中无法输

入所有列值的表格和大于二维的表格将会在章节5,43页中讨论。

2.4.3 直接赋值输入

与其上述两种输入方式不同,直接赋值输入通过不同的表述将声明过程和赋值过程分开。运输模型中对应的这种输

入方法是:

Parameter c(i,j) transport cost in thousands of dollars per case ;

c(i,j) = f * d(i,j) / 1000 ;

这里要强调一下第一行最后的分号。如果没有这个分号,GAMS编译器将把两行当做同一个表述的两个部分。(GAMS

将不能分辨有效的解释,因此将发给用户一个精炼的有用的错误报告)

第一行的表述的作用是声明参量c,指明域(i,j),并且给出说明文档。第二行的表述给c (i,j)赋值,这些值由

f和d(i,j)决定。当然,只有在先前的表述中给f和d(i,j)赋值过这里才不会出错。直接赋值作用了所有c(i,j)的指数域。如果你想给特定的某个c(i,j)赋值,你应该写上相应域元素的名字并用

引号括起来。如下所示:

c('Seattle','New-York') = 0.40;

这是一个有效的GAMS表述。

同一个参量可以被多次赋值。每个赋值表述在下一个赋值表述之前有效。(相比之下,同一个参量不能被多次声明。

这是GAMS中的一种错误检查,它使你避免对两个不同的东西使用同一个名字)

赋值表述的右边可以包含一系列数学表达和内建函数。假如你熟悉某种科学程序语言例如FORTRAN或者C,那么在

GAMS中写赋值表述对于你而言就很简单了。(需要注意的是,GAMS有些东西与FORTRAN 和C都不一样,例如,

我们不用循环语句就可以对所有的c(i,j)赋值)

GAMS的标准操作和提供的函数将随后给出。接下来是一些有效赋值的例子。在所有情况下,确保左边的参量都已

经被声明并且右边的参量都已经在前面的表述中被赋值。

csquared = sqr(c);

e = m*csquared;

w = l/lamda;

eoq(i) = sqrt( 2*demand(i)*ordcost(i)/holdcost(i));

t(i) = min(p(i), q(i)/r(i), log(s(i)));

euclidean(i,j) = qrt(sqr(xi(i) - xi(j) + sqr(x2(i) - x2(j)));

present(j) = future(j)*exp(-interest*time(j));

之后介绍的求和和乘积算子也能被直接用于赋值。

2.5 变量

在GAMS模型中的决策变量(内生变量)必须用Variables表述予以声明。每个变量都会有一个名字,合适的话就有

对应的一个域,还有说明文档(不是必须的)。运输模型中的相关表述如下所示:

Variables

x(i,j) shipment quantities in cases

z total transportation costs in thousands of dollars ;

这个表述为每一对(i,j)做出了装载变量声明。(在章节8,65页,你将看到GAMS是怎样解决现实世界的问题,

在这个过程中只允许(i,j)的子域用于运输装载)

变量z被声明却没有给出指数域是因为它与取值是一一对应的关系。每一个GAMS优化模型必须包括这样一个变量,

它是最小化或者最大化的目标。

一旦被声明,每一个变量都必须被赋予一个类型。表2.3给出了可用的类型:

作为最小化或者最大化的目标的变量必须是变量性质的并且属于free类型。在这个运输模型例子中,z默认是free

类型,但是x(i,j)通过以下表述限制成非负值:

Positive variable x ;

注意,x的指数域不要在类型表述中出现。域中所有的条目有相同的类型。

2.10小节将说明如何规定变量的上下边界和初始值。

2.6 方程式

GAMS的代数建模语言在创建模型的方程和不等式的时候功能很强大。这是因为当一组方程式具有相同代数结构的

时候,它们是同时而不是一个个被创建。

2.6.1 方程式声明

GAMS中要用单独的表述对方程式进行声明和定义。其声明的格式与声明GAMS其他部分相同。首先,在这里要用

到关键字Equations,之后是名字,指数域和一组或者多组被声明方程式或不等式的说明文档。运输模型中的表述如

下所示:

Equations

cost define objective function

supply(i) observe supply limit at plant i

demand(j) satisfy demand at market j ;

要记住的是Equation这个词在GAMS中意思很宽泛。它包含了等式和不等式,而GAMS中一个Equation的名字可以

对应一个或者多个式子。例如,cost没有指数域所以是一个单独的式子,而supply对应指数域i 下定义的一组式子。

2.6.2 GAMS求和(连乘)符号

在介绍方程式定义之前我们先说明一下GAMS中的求和符号。GAMS是以标准键盘和逐行输入检查为标准设计的,

所以在做求和时是不能用标准数学符号的(尽管这对用户造成不便)。

GAMS中的求和符号可用于简单和复杂的表达式中。它的格式是基于对求和的一般思维过程,这样的算符有两个自

变量:Sum(index of summation,summand)用一个逗号分隔两个自变量,如果第一个自变量中用到逗号则用括号

括起来。第二个自变量可以是任意一种数学表达式包括求和表达式。

举一个简单的例子,运输模型包含表述:

Sum(j, x(i,j))

这与ij

j

x ∑等价。

再举一个稍微复杂点的例子:

Sum((i,j), c(i,j)*x(i,j))

这与ij ij

ijcx ∑∑等价。

最后一个例子也可以写成包含嵌套求和运算的表述:

Sum(i, Sum(j, c(i,j)*x(i,j)))

在11.3节,100页,我们会介绍如何使用dollar算符给求和算符加上约束使得满足特定条件的i 和j 才可以被求和。

GAMS中定义的连乘符号的格式与求和符号一样,用Prod取代Sum。例如:

prod(j, x(i, j))

等价于ij

j

x ∏。

求和符号和连乘符号可以用在对参数的直接赋值表述中。例如:

scalar totsupply total supply over all plants;

totsupply = sum(i, a(i));

2.6.3 方程式定义

方程式定义因为其种类繁多而成为GAMS中最为复杂的表述。一个方程式定义包括,按顺序:

1. 被定义方程式的名字

2. 指数域

3. 指数域约束条件(可选)

4. 符号“..”

5. 左手边表达式

6. 关系算符:=l=,=e=,或者=g=

7. 右手边表达式

运输模型包含有三个这种表述:

cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ;

supply(i) .. sum(j, x(i,j)) =l= a(i) ;

demand(j) .. sum(i, x(i,j)) =g= b(j) ;

以下是一些要注意的地方:

?指数域对用单个GAMS表述联立方程组进行控制。例如,约束demand的定义产生了对域j 中每个元素的约束,

GAMS输出显示为:

DEMAND(new-york).. X(seattle,new-york)+ X(san-diego,new-york) =G=325 ;

DEMAND(chicago).. X(seattle,chicago) + X(san-diego,chicago) =G=300 ;

DEMAND(topeka).. X(seattle,topeka) + X(san-diego,topeka) =G=275 ;

?这里的关键是,无论是解决一个像例子那样的小规模模型或者是有20000个数据的现实问题,对于demand的

约束都是一样的。不管是哪种情况,用户只需要输入一个代数方程式,GAMS就可以建立特定的与当前模型相

适应的方程式。(使用一些其他的优化包,就像上述的一样,它是作为输入的一部分而不是输出的一部分)

?在很多现实问题中,因为存在某种例外,一些方程式指数域中的元素需要被忽略或者区别对待。GAMS可以很

快的用一种被称为dollar或者“such‐that”的有力方式来调整结构的损失,这里不会对此进行说明。为了使现

实世界的模型在解决的范围以内,对于域的约束性质是完全必要的。

?关系算符含义如下:

=l= 小于等于

=g= 大于等于

=e= 等于

?分清楚“=”和“=e=”是很重要的。“=”只被用于直接赋值,而“=e=”只被用于方程式定义。这两者含义相差

很大。直接赋值是指在运算之前赋予某参量一个特定的值。一个方程式定义也描述了一个特定的关系,但是在

运算开始之前它是不能成立的。由此可见,方程式定义必须含有变量而直接赋值不能含有变量。

?变量可以出现在方程式的左边或者右边或者两边。同一个变量可以在方程式中出现多次。在进行运算之前,GAMS

运算器会自动将其转化为标准形式(变量在左,且合并变量系数)。

?只要方程式定义中包含的所有的方程式、变量和参量在先前就声明过,该定义可以出现在GAMS输入的任何地

方。(注意,出现在方程式中的参量可以在方程式定义后再被赋值和重新赋值。这对于运行同一个GAMS输入下

的联合模型时是很方便的)方程式不必按照声明它们的顺序来进行定义。

2.7 目标函数

GAMS中没有称为目标函数的特定的组成部分。为了区分要被优化的函数,你必须建立一个变量,它的类型是free

(在符号上没有限制)并且与其取值是一一对应的(没有指数域),还要在方程式定义中将它等同于目标函数。

2.8 模型和运算表述

单词model在GAMS中有很明确的意思。它是指一系列方程式。就像其他GAMS组成部分一样,在声明过程中我们

要给它一个名字。对模型进行声明的格式是在关键字model后面输入模型的名字,随后在斜杠中输入该模型所包含

的方程式的名字。如果模型包含之前所有定义的方程式,你可以输入/all/来代替它们名字的详细列表,表述如下:

model transport /all/ ;

这个表述看起来是多余的,但是对于在同一个GAMS文件中可能建立多个模型的高级用户来说是有用。如果我们要

用详细列表,上述表述替换为:

model transport / cost, supply, demand / ;

因为指数域不是方程式的名字,在这里它们被省略了。当且仅当现存方程式的子域包含有一个正在建立的模型(或

者说是子模型)时,列表才会被使用。

一旦一个模型被声明和赋予了方程式,就做好了运算的准备了。这时我们会用到solve表述:solve transport using lp minimizing z ;

如下为solve表述的格式:

1. 关键字solve

2. 要计算的模型的名字

3. 关键字using

4. 选择一个可用的运算程序。所有可用的程序列表如下:

lp 线性规划

qcp 二次约束规划

nlp 非线性规划

dnlp 具有非连续倒数的非线性规划

mip 混合整数规划

rmip 宽松混合整数规划

miqcp 具有二次约束的混合整数规划

minlp 混合整数非线性规划

rmiqcp 具有二次约束的宽松混合整数规划

rminlp 宽松的很合整数非线性规划

mcp 混合互补问题

mpec 具有平衡约束的数学规划

cns 约束非线性系统

5. 关键字“minimizing”或者“maximizing”

6. 被优化的变量名字

2.9 显示表述

在执行Solve表述后会引发一些事件。比如,有关模型的具体的相关的例子会被生成,为了将问题导入运算过程而

生成了合适的数据结构,算法将被调用,同时来自运算的输出也会打印到一个文件中。为了获得最初的以及/或者

双重变量的最优化值,我们可以查看运算的输出,或者如果愿意的话,我们可以要求GAMS 显示出这些。例子中包

含如下表述:

display x.l, x.m ;

x.l要求打印出变量的最终值,x.m要求打印出装载变量x(i,j)的边界值。GAMS将自动将这些输出生成带有合适

标题的表格。

2.10 “.lo,.l,.up,.m”数据库

GAMS被设计带有一个小的数据库系统,它用于维护关于变量和方程式的记录。记录中最为重要的领域是:

.lo 下边界

.l 当前值或者初始值

.up 上边界

.m 边界值或者双重变量

引用这些相关量的格式是,变量或者方程式的名字,随后是领域名,(如果需要的话)再是指数域(或者指数域中

的元素)。

GAMS允许用户完成读取和写入数据库。现在这些或许对你没有什么用,但是对于高级用户而言这是一个相当有价

值的特点。以下举一些使用数据库的例子。

2.10.1 赋值变量边界值和初始值

变量的下边界和上边界根据变量的类型(free,positive,negative,binary,integer)而自动的设定,但是用户可以

重新设定这些边界。下面是一些例子:

x.up(i,j) = capacity(i,j) ;

x.lo(i,j) = 10.0 ;

x.up('seattle','new-york') = 1.2*capacity(seattle','new-york') ;

第一个和第三个例子中假定capacity(i,j)这个参量已经被声明和赋值过了。这些表述必须在声明变量之后,在solve

表述之前。右手边可以使用所有赋值过程中可用的数学表达。

在非线性规划问题中,建模过程要尽可能的缩小上下边界之间的差值,这对于运算过程很重要,而为搜寻最优化值

的运算指出一个初始值也很重要。例如,在一个带有约束的库存模型中,变量是quantity(i),而且已知非约束情

况下的最优化值是eoq(i)。作为对约束情况的猜测,我们输入:

quantity.l(i) = 0.5*eoq(i) ;

(一般情况下默认的初始值被设为0,除非0不在边界范围内,而在这种情况下,它取最接近0的边界值)

注意,.lo和.up值完全由用户控制。相比之下,虽然.l和.m 也要用户赋予初始值,但是它们由算法控制。

2.10.2 最优化值的变形和显示

(如果要求的话这一小节可以被跳过)

当solve表述引用优化器后,优化器初次和第二次计算的变量的结果将会在数据库中的.l 和.m 项列出。我们可以应

用相应的GAMS语句来调用查看这些结果。

例如,在运输问题中,假设我们想知道各个工厂对每个市场需求的占有率。在solve表述后,我们要输入:

parameter pctx(i,j) perc of market j's demand filled by plant i;

pctx(i,j) = 100.0*x.l(i,j)/b(j) ;

display pctx ;

依靠这些对于原始运输问题的指令我们可以得到如下输出结果:

pctx percent of market j's demand filled by plant I

new-york chicago topeka

seattle 15.385 100.000

san-diego 84.615 100.000

在一个包含边际值的例子中,我们简单的考虑比率约束,它在混合和提炼问题中很常见。这些线性规模型需要决定

每种可用的原材料用于每种需求的产品的优化量。设定变量y(i ,j)表示用于生成产品j 的原材料i 的吨数。假设比率

约束为任何一种产品中同一种成分的含量不超过25%,也就是:

y(i,j)/q(j) =l= .25 ;

对于所有的i 和j,为了保证模型的线性,约束将被写成:

ratio(i,j).. y(i,j) - .25*q(j) =l= 0.0 ;

这样比直接表示为比率关系要更好。

这里的问题在于ratio.m(i, j)(与约束的线性表达方式相关的边际值)没有固有的含义。在优化问题中,它表示了在

不考虑约束以上比率约束时我们至少能获利多少。但是这没有什么实际意义。我们关心的约束是比率约束的非线性

形式。例如,我们希望知道当比率约束上升时能获取的边际收益

y(i,j)/q(j) =l= .26 ;

实际上我们可以通过输入如下有关非所求边际值的语句看来获取所关注的边际值:

parameter amr(i,j) appropriate marginal for ratio constraint ;

amr(i,j) = ratio.m(i,j)*0.01*q.l(j) ;

display amr ;

注意amr在数据库中对应的.m 和.l项的赋值表述。在这个等价变形的表述中我们需要注意的是

y(i,j)/q(j) =l= .26 ;

等价于

y(i,j) - .25*q(j) =l= 0.01*q(j) ;

2.11 GAMS输出

GAMS的默认输出包含的内容很广泛,信息量大。在一个完整的讨论中,见章节10,79页,它把输出分为以下几部

分来叙述:

Echo Print Reference Maps Status Reports

Error Messages Model Statistics Solution Reports

一些教科书和用户手册说准确的运用高级软件对于任何正常人来说都是轻而易举的,这给读者留下了错误的印象,

并引起了不必要的恐慌。GAMS在设计的时候考虑的是即使是最有经验的用户也会犯错误。GAMS将尽快的发现错

误并最小化它们的影响。

2.11.1 Echo Prints

不管错误是不是阻碍你的优化问题被解决,输出的第一个部分是你输入文件的一个echo,或者说是拷贝。为了方便

后面引用,GAMS在每一行的前面都加上了行号。在我们的运输例子中,有幸的是这个例子不含任何错误,echo print

部分是:

3 Sets

4 i canning plants / seattle, san-diego /

5 j markets / new-york, chicago, topeka / ;

6

7 Parameters

8

9 a(i) capacity of plant i in cases

10 / seattle 350

11 san-diego 600 /

12

13 b(j) demand at market j in cases

14 / new-york 325

15 chicago 300

16 topeka 275 / ;

17

18 Table d(i,j) distance in thousands of miles

19 new-york Chicago topeka

20 seattle 2.5 1.7 1.8

21 san-diego 2.5 1.8 1.4 ;

22

23 Scalar f freight in dollars per case per thousand miles /90/ ;

24

25 Parameter c(i,j) transport cost in thousands of dollars per case;

26

27 c(i,j) = f * d(i,j) / 1000 ;

28

29 Variables

30 x(i,j) shipment quantities in cases

31 z total transportation costs in thousands of dollars ;

32

33 Positive Variable x ;

34

35 Equations

36 cost define objective function

37 supply(i) observe supply limit at plant i

38 demand(j) satisfy demand at market j ;

39

40 cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ;

41

42 supply(i) .. sum(j, x(i,j)) =l= a(i) ;

43

44 demand(j) .. sum(i, x(i,j)) =g= b(j) ;

45

46 Model transport /all/ ;

47

48 Solve transport using lp minimizing z ;

49

50 Display x.l, x.m ;

51

这个echo print从行号3开始而不是行号1是因为输入文件包含了两个dollar打印控制表述。这种说明控制了输出

打印,但是既然它与优化模型的定义无关,在echo中它就被忽略了。Dollar打印控制符必须出现在第一列。

$title a transportation model

$offuppper

$title会让它后面的文本内容显示在输出的每一页的顶部。$offupper允许echo中包含大写和小写。其他说明在附录

D,193页给出。

2.11.2 Error Message

当GAMS编译器在输入文件中碰到一个错误,它将在echo现实中错误发生的下一行插入一个编了号的错误信息。

这些信息通常由****开头并且包含有一个“$”,它位于编译器认定的错误发生行的下一行。$后面是错误代码,它

将在echo内容之后被解释。以下是一些例子。

例1:输入表述

set q quarterly time periods / spring, sum, fall, wtr / ;

在echo中会的得到:

1 set q quarterly time periods / spring, sum, fall, wtr / ;

**** $160

在这种情况下,GAMS编译器暗示set元素中的sum存在错误。在echo显示的底部,我们将看见杜宇错误代码160

的解释:

Error Message

160 UNIQUE ELEMENT EXPECTED

这里的错误在于sum是一个代表加法运算的关键字,所以我们的set元素中不能使用它而要用其他的像是“summer”

这样的字符串来代替。这是一个初学者容易犯的错误。所有关键字的列表将在下一章中给出。

例2:另外一个普遍的错误是在直接赋值或等式定义前遗漏了分号。在我们的运输例子中,假设我们遗漏了c(i, j)

赋值表达前面的分号:

parameter c(i,j) transport cost in 1000s of dollars per case

c(i,j) = f * d(i,j) / 1000 ;

那输出将会是:

16 parameter c(i,j) transport cost in 1000s of dollars per case

17 c(i,j) = f*d(i,j)/1000

**** $97 $195$96$194$1

Error Message

1 REAL NUMBER EXPECTED

96 BLANK NEEDED BETWEEN IDENTIFIER AND TEXT

(-OR-ILLEGAL CHARACTER IN IDENTIFIER)

(-OR-CHECK FOR MISSING ';' ON PREVIOUS LINE)

97 EXPLANATORY TEXT CAN NOT START WITH '$', '=', or '..'

(-OR-CHECK FOR MISSING ';' ON PREVIOUS LINE)

194 SYMBOL REDEFINED

195 SYMBOL REDEFINED WITH A DIFFERENT TYPE

像遗漏一个分号这样的小问题导致产生5条可怕的错误信息的情况并不少见。这里要表明的是:请把重点放在第一

条错误上先忽略其他错误!在第17行检测道德第一个错误,代码97,表示GAMS认为17行中出现的字符是16行

中解释文档的后续内容而不是我们想要的直接赋值表述。错误信息也适当的建议我们检查上一行是否遗漏了分号。

不幸的是,你不可能总是得到错误信息的准确建议。编译器无法解读你的想法。它有时无法理解你的意图,所以有

必要学会顺着GAMS给你的错误提示来寻找错误。例如,遗漏的分号可以通过查阅对照表(将在下一部分介绍)中

输入项c来检测,我们注意到它并没有被赋值。

SYMBOL TYPE REFERENCES

C PARAM DECLARE

D 15 REF 17

例3:很多错误仅仅是因为拼写错误造成的,这些错误将在它们造成影响之前被检测出来。例如,在表格中“Seattle”

的拼写不同于它在set声明中的拼写,我们将会看到如下错误信息。

4 sets

5 i canning plants /seattle, san-diego /

6 j markets /new-york, chicago, topeka / ;

7

8 table d(i,j) distance in thousand of miles

9 new-york chicago topeka

10 seatle 2.5 1.7 1.8

**** $170

11 san-diego 2.5 1.8 1.4 ;

Error Message

170 DOMAIN VIOLATION FOR ELEMENT

例4:类似的,如果我们错误的在需求约束的右边输入dem(j)而不是b(j),结果是

45 demand(j) .. sum(i, x(i,j) ) =g= dem(j) ;

**** $140

Error Message

140 UNKNOWN SYMBOL, ENTERED AS PARAMETER

例5:这个例子中出现的是数学错误,有些时候建模新手会犯这样的错误,而GAMS善于检测这样的错误。下面的表

述在数学上是不连续的,所以它表意不明确。

For all i,100

ij

i

x = ∑

在这个等式中有两个错误,它们都因为指数运用而造成。对指数i 限定的太多,而对指数j 限定的太少。

你应该发现对指数i 的限定是有冲突的。“For all i”表示i 在等式中是固定不变的。但是,后面的加法运算中i 又不

断在变化。i 无法同时满足这两个条件。然而,对指数j 没有任何限定,所以我们不知道将会用到它的哪些可能的取

值。

如果我们将这个表述输入到GAMS中,两个错误都将被准确的纠正。

meaninglss(i) .. sum(i, x(i,j)) =e= 100 ;

**** $125 $149

ERROR MESSAGES

125 SET IS UNDER CONTROL ALREADY [This refers to set i]

149 uncontrolled set entered as constant [This refers to set j]

更多关于错误信息的报告将会在章节10.6,92页中给出。理解好错误侦测和精心设计的错误消息对于顺利快捷的进

行模型的计算是有很大帮助的。

2.11.3 关系图

输出的下一个部分是一对关系图,为了纠错和形成文档,它们包含有对输入文件的概括与分析,而当错误被侦测到

以后这将会是输出的最后一个部分。

第一个关系图是一个对照表,在多数现代的编译器中都可以找到。它列举出模型中出现的所有元素(sets, parameters,

variables, equations)。这个对照表中显示了每个元素的类型以及它们在输入文件中出现的行号。对于运输模型这个

对照表是(这里没有显示完整的对照表):

SYMBOL TYPE REFERENCES

A PARAM DECLARED 9 DEFINED 10 REF 42

B PARAM DECLARED 13 DEFINED 14 REF 44

C PARAM DECLARE

D 25 ASSIGNED 27 REF 40

COST EQU DECLARED 36 DEFINED 40 IMPL-ASN 48

REF 46

D PARAM DECLARED 18 DEFINED 18 REF 27

DEMAND EQU DECLARED 38 DEFINED 44 IMPL-ASN 48

REF 46

F PARAM DECLARED 23 DEFINED 23 REF 27

SET DECLARED 4 DEFINED 4 REF 9

18 25 27 30 37 2*40

2*42 44 CONTROL 27 40 42

44

J SET DECLARED 5 DEFINED 5 REF 13

18 25 27 30 38 2*40

42 2*44 CONTROL 27 40 42

44

SUPPL Y EQU DECLARED 37 DEFINED 42 IMPL-ASN 48

REF 46

TRANSPORT MODEL DECLARED 46 DEFINED 46 IMPL-ASN 48

REF 48

X V AR DECLARED 30 IMPL-ASN 48 REF 33

40 42 44 2*50

Z V AR DECLARED 31 IMPL-ASN 48 REF 40

48

例如,这个对照表告诉我们符号A是一个参量,它在第10行被声明,在第11行被定义,在第43行被引用过。符

号I在对照表中是一个信息更为复杂的元素。它被看成是一个在第5行被声明和定义的指数

GAMS中文教程

二 GAMS简明教程由Richard E. Rosenthal编著 (译者:该翻译由华中科技大学能源与动力工程学院小海完成,由于译者水平有限,其中肯定会有些问题,欢迎大 家阅读并批评指正!) 简介 这本书的简介部分以一个详细的例子结束,这个例子是一个用GAMS进行表达、解决和分析的小而简单的优化问题。 由来自蒙特利尔市Naval研究生院的Richard 编写。通过这个例子我们可以对GAMS有一个快速而全面的 了解。很多地方引用到本书其他章节的知识,方便大家进一步查阅;而阅读这一部分即使不看本书其他章节也能看 懂并且有所收获。 例子是一个关于运输的线性规划问题,这个问题在最优化技术发展过程中曾经被当做实验对象。用这个例子展示 GAMS这类代数建模语言的强大功能是很好的选择,因为不管手头要处理的问题有多大,运输问题本身具有一个简 单的、可用的代数结构。你可以发现,如果要解决一个非常大的运输问题,我们将呈现的用于解决小规模运输问题 的GAMS输入文件中的内容并不需要改变多少。 在熟悉的运输问题中,我们考虑几个工厂的供应和几个市场的需求的商品,我们也给出从工厂运输商品到市场的单 位花费。这其中的经济学问题是:怎样安排运输使得我们的总运输成本最小 这个问题的代数表达常常采用下列方式: Indices: i = plants j = markets

Given Data: i a= supply of commodity of plant i (in cases) ij b= demand for commodity at market j ij c = cost per unit shipment between plant i an d market j ($/case) Decision Variables: ij x = amount of commodity to ship from plant i to market j (cases), Where ij x ≥0, for all i, j Constraints: Observe supply limit at plant i: j ij j a x≤∑ for all i (cases) Satisfy demand at market j: ij j i x b ≥∑ for all j (cases) Objective Function: Minimize ij ij ijcx ∑∑ ($K) 注意这个例子显示了一些一般情况下我们认为是好习惯的建模方式,这些在GAMS里面被继

GAMS简明教程中文版

二 GAMS 简明教程 由Richard E. Rosenthal 编著 (译者:该翻译由华中科技大学能源与动力工程学院小海完成,由于译者水平有限,其中肯定会有些问题,欢迎大家阅读并批评指正!) 2.1 简介 这本书的简介部分以一个详细的例子结束,这个例子是一个用GAMS 进行表达、解决和分析的小而简单的优化问题。由来自蒙特利尔市Naval 研究生院的Richard E.Rownthal 编写。通过这个例子我们可以对GAMS 有一个快速而全面的了解。很多地方引用到本书其他章节的知识,方便大家进一步查阅;而阅读这一部分即使不看本书其他章节也能看懂并且有所收获。 例子是一个关于运输的线性规划问题,这个问题在最优化技术发展过程中曾经被当做实验对象。用这个例子展示GAMS 这类代数建模语言的强大功能是很好的选择,因为不管手头要处理的问题有多大,运输问题本身具有一个简单的、可用的代数结构。你可以发现,如果要解决一个非常大的运输问题,我们将呈现的用于解决小规模运输问题的GAMS 输入文件中的内容并不需要改变多少。 在熟悉的运输问题中,我们考虑几个工厂的供应和几个市场的需求的商品,我们也给出从工厂运输商品到市场的单位花费。这其中的经济学问题是:怎样安排运输使得我们的总运输成本最小? 这个问题的代数表达常常采用下列方式: Indices: i = plants j = markets Given Data: i a = supply of commodity of plant i (in cases) ij b = demand for commodity at market j ij c = cost per unit shipment between plant i and market j ($/case) Decision Variables: ij x = amount of commodity to ship from plant i to market j (cases), Where ij x ≥0, for all i, j Constraints: Observe supply limit at plant i: j ij j a x ≤∑ for all i (cases) Satisfy demand at market j: ij j i x b ≥∑ for all j (cases) Objective Function: Minimize ij ij i j c x ∑∑ ($K) 注意这个例子显示了一些一般情况下我们认为是好习惯的建模方式,这些在GAMS 里面被继承了。首先,模型程序中的各组成部分都按类型分组定义了。其次,GAMS 程序各组成部分先后次序已经定好了,因此没有标识符能在被定义之前使用。第三,各组成部分都有特定的单位。第四,选择的单位要使优化过程中得到的数值具有相对较小的绝对数量级。(例如标识$K 表示dollar 的千倍)

GAMS中文教程

二GAMS简明教程由Richard E. Rosenthal编著 (译者:该翻译由华中科技大学能源与动力工程学院小海完成,由于译者水平有限,其中肯定会有些问题,欢迎大 家阅读并批评指正!) 2.1 简介 这本书的简介部分以一个详细的例子结束,这个例子是一个用GAMS进行表达、解决和分析的小而简单的优化问题。 由来自蒙特利尔市Naval研究生院的Richard E.Rownthal编写。通过这个例子我们可以对GAMS有一个快速而全面的 了解。很多地方引用到本书其他章节的知识,方便大家进一步查阅;而阅读这一部分即使不看本书其他章节也能看 懂并且有所收获。 例子是一个关于运输的线性规划问题,这个问题在最优化技术发展过程中曾经被当做实验对象。用这个例子展示 GAMS这类代数建模语言的强大功能是很好的选择,因为不管手头要处理的问题有多大,运输问题本身具有一个简 单的、可用的代数结构。你可以发现,如果要解决一个非常大的运输问题,我们将呈现的用于解决小规模运输问题 的GAMS输入文件中的内容并不需要改变多少。 在熟悉的运输问题中,我们考虑几个工厂的供应和几个市场的需求的商品,我们也给出从工厂运输商品到市场的单 位花费。这其中的经济学问题是:怎样安排运输使得我们的总运输成本最小? 这个问题的代数表达常常采用下列方式: Indices: i = plants j = markets Given Data: i a= supply of commodity of plant i (in cases) ij b= demand for commodity at market j ij c = cost per unit shipment between plant i an d market j ($/case) Decision Variables: ij x = amount of commodity to ship from plant i to market j (cases), Where ij x ≥0, for all i, j Constraints: Observe supply limit at plant i: j ij j

相关主题
文本预览
相关文档 最新文档