GAMS Notes


1. GAMS简介


2. GAMS基本结构[3]

GAMS基础概述

GAMS中使用的术语

针对GAMS的一般性说明:

2.1集合

2.2 数据

2.2.1 列表数据输入(列表赋值)

Parameter
  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 /;

2.2.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;

2.2.3 直接赋值数据输入

Parameter c(i,j) 'transport cost in thousands of dollars per case';
c(i,j) = f*d(i,j)/1000;

2.3 变量

表达gams模型的决策变量(又称为内生变量)必须用variable(s)语句声明,之后每个变量都给定一个名字、一个域(如果适合)、文件文本(可选项),如:

Variable
   x(i,j) 'shipment quantities in cases'  # 为每对(i,j)声明运输变量
   z      'total transportation costs in thousands of dollars'; # z是标量,没有声明域

2.4 方程

GAMS建模的功能主要通过建立方程和不等式表现出来,在GAMS中所有的方程和不等式同时建立

2.4.1 方程声明和定义

通过关键字equation进行方程声明,后面紧跟着名字、域和被声明方程或不等式的文本(一组或多组),例如:

Equation
   cost      'define objective function' # cost没有域,所以是一个单一方程
   supply(i) 'observe supply limit at plant i' # supply表示在域i上定义的不等式集合
   demand(j) 'satisfy demand at market j';

2.4.2 GAMS求和或求积符号

求和

GAMS的求和语句在求和思想的基础上带有两个参数的操作符,即sum(合计的索引,被加数),两个参数之间用逗号间隔,其中,第二个参数可以是任何数学表达式(包括求和),例如:

sum(j,x(i,j)) # 1
sum((i,j),c(i,j)*x(i,j)) # 2
sum(i,sum((i,j),c(i,j)*x(i,j))) # 嵌套求和

求积

GAMS使用和求和相同的格式定义乘积,只需用prod替代sum即可,例如:

prod(j,x(i,j)) # 相当于\prod_{j}x_{ij}

2.4.3 定义方程

方程定义的组成及其顺序

在GAMS中,方程定义是最复杂的语句,以下是方程定义的组成及其顺序

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);

Notes

2.5 目标函数

GAMS没有被称为目标函数的外在实体,为了指定最优化的函数,必须创建以个变量(variable),这个变量取任意值(不受符号约束),是标量(没有范围),并且出现在等同目标函数的方程定义

2.6 模型和求解语句

模型(model)一词在gams表示方程的集合的含义的,如同其它的gams实体(声明)一样,模型在声明中必须给予一个名字,声明格式如下:关键字model声明后紧跟模型的名称,再跟着用斜线括住的方程名称列表

Model transport / all /; # /all/表示包括以前定义的所有方程

Model transport /cost, supply, demand /; # 只写以前定义的需要的方程的名称

一旦模型已经声明且已经给方程赋值,接下来就可以使用一个求解语句来调用求解器:

solve transport using lp minimizing z;

2.6 显示语句

对于求解器的输出,如最优值,通过 display可以在gams中显示这些结果,如:

display x.l, x.m; # l 表示求解变量的最终值,m表示求解变量的边际值

2.7 '.lo / .l / .up / .m'数据库

gams设计了一个小型数据系统,用来维护变量和方程的记录,.lo / .l / .up / .m是每个记录最重要的字段,其中.lo表示下限.up表示上限.l表示水平值或初值或最终值.m表示边际值或对偶值格式:变量跟着字段名,如果需要可在字段中加入域或者域的某个元素

2.7.1 变量的边界和初始值的赋值

变量的上下界是根据变量类型设置的,但是这些边界可以被新gams语句覆盖

# 假设capacity(i,j)是一个以前被声明和赋值的参数
# 以下语句必须出现在variable(变量)声明之后和solve语句之前
# 直接赋值的所有数学表达式都可以放在右边

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

2.7.2 最优值的转换和显示

Sovle语句调用最优化程序后,计算出的初始值和边际值的数值放在了数据库的.l / .m字段中,这可以通过gams的display语句显示出来

# 计算各个市场的需求占每个工厂的百分比

parameter pctx(i,j) percent of market j's demand filled by plants i;
pctx(i,j)=100.0*x.l(i,j)/b(j);
display pctx;

Note: 涉及边际值的内容,参考<用户指南> ———— 2.10.2 最优值的转换和显示

2.8 GAMS输出

2.8.1 返回输出

GAMS运行输出的第一部分:输入文件的返回或拷贝

2.8.2 错误信息

当gams编译器在输入文件里遇见错误时,会在lst文件(lst是gams输出文件的后缀名,gms是gams的程序语句文件的后缀名)中的返回输出的出错行处插入编码错误的信息,这些错误信息具有固定的显示格式:在出错语句的下一行,以****开始,之后紧跟$符号,$紧跟一个数字错误代码,之后另起一行对这个错误代码详细说明

# a
set s season time /spring,sum,fall,winter /;

# b
# 对于缺少分号,可以通过浏览对照表中的c条目和赋值状况来发现
Parameter c(i,j) 'transport cost in thousands of dollars per case' # 省略了分号
c(i,j) = f*d(i,j)/1000;

# c
Set
   i 'canning plants' / seattle,  san-diego /

Parameter
   a(i) 'capacity of plant i in cases'
        / seatle    350   # 是seattle,不是seatle
          san-diego  600 /

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

2.8.3 引用映射

2.8.4 方程列表

方程列表(Equation Listing)

方程列表可用于研究GAMS是否生成了想要的模型
gams中,输入约束通常是一般约束,而在输出约束中是特定约束(对于每个一般方程的默认输出是三个特定方程的约束最大值,如是325而不是比325小的值),不过,可以通过下列语句改变默认输出个数:

option limrow=r; # r是希望的行数,可是以任何数字

纵向列表(Column Listing)

纵向列表类似于方程列表,它对每个一般变量它会显示相应的特定变量的系数
可以通过下面语句改变每个一般变量的特定纵向输出的默认数值:

option limcol=c; # c是希望的列数,可是以任何数字
option limcol=r, limcol=c; #可以合并

2.8.5 模型统计

2.8.5 状态报告

求解器执行后,gams在Solution Report部分会输出一份简要的求解摘要,求解器状态(SOLVER STATUS)和模型状态(MODEL STATUS)是最重要的条目

2.8.6 求解报告

检查完求解器状态和模型状态后可以检查最优化结果(Optimal Solution: solEQU和solVAR),最优化结果会根据特定方程的名字进行分组打印输出下限值、水平值、上限值和边际值

在求解器求解报告的末尾是非常重要的报告摘要(Report Summary),它给出了非优化、不可行、无界的行列数

2.8.7 结果显示

由求解器获得的所有水平值和边际值都保存到gams数据库的.l.m字段中,这些值可以转换并且在任何需要的报告中显示出来,只需要列出要显示的数量(如,x),gams就会自动格式化并标准一个合适的数组,如:

display x.l, x.m;

小结


3. GAMS程序

GAMS是一种程序设计语言,GAMS程序通常使用自带的gams文本编辑器编写输入文件和查阅输出文件

3.1 GAMS程序的结构

GAMS程序由一个或多个语句构成,语句的作用在于定义数据结构、初值、数据修改、符号关系(方程)

3.1.1 GAMS输入格式

3.1.2 GAMS语句的分类

GAMS中的每个语句可以被分为两组:声明和定义(赋值)语句和执行语句

声明和定义语句

声明语句描述语句(符号)的种类,然后对其赋值或定义

执行语句

执行语句是完成行动的指令(集)

3.1.3 GAMS程序的组织

GAMS程序语句顺序虽然自由,但是有两种常用的顺序

3.2 数据类型和定义

gams有五种基本的数据类型,分别是set、parameter、variable、equation、model,每个标识符(符号)必须要声明为其中的一种,值得注意的是,scalar和tables不是单独的数据类型,而是声明某个符号是parameter的一种快速方法,并且用一个特有的格式初始化数字格式的数据类型
五种基本的数据类型的格式

> parameter        a     (i,j)    comment  # Note:域的列表和文本是可选的
> 数据类型关键字    标识符   域列表     文本

> variable x,y,z; # 许多标识符用一个语句声明,标识符之间用逗号隔开

3.3 语言条目

GAMS的基本符号又被为语句要素,是gams语言的基本结构要素,是辨认和书写gams语句的基本规则,它们分别是字符、分隔符、变迁、保留字和标记、注释、文本、数字、标识符和空格


4. 集合定义

gams中,集合是基本的模块。关于集合的内容,主要是声明、初始化、赋值、lag、lead等语句,更复杂的概念包括在模型的不同部分对集合赋值、改变集合的成员、联合、补余、交集等,这里仅仅涉及集合的基本部分,如:集合的声明、名称、文本、元素

集合语句以关键字set开始,之后紧跟集合的名称(内部标识符),然后是用于描述集合的解释性文本(text),然后是集合的元素(标签,label),注意,不同于数学中集合的元素用大括号括起来,这里用斜杠括起来

4.1 集合与多重集合的声明

# 同时声明
Set
   i canning plants / seattle,  san-diego/
   j  markets        / new-york, chicago, topeka/;

# 分开声明
Set i  canning plants / seattle,  san-diego/; # 注意每个声明语句完全结束后添加分号
Set j  markets        / new-york, chicago, topeka/;

4.2 集合名称、文本与元素

Set
   i 'canning/plants' / seattle,  san-diego / # 文本使用了引号,故可以泗洪斜杆而不产生错误
   j  markets        / new-york, chicago
                            topeka /

   a 'canning plants' / "seattle",  "san-diego" /
   b 'canning plants' / seattle 解释1 # 可同时加,也可同时不加,也可只加一个
                        san-diego 解()2/

# 使用星号 *
set t time /2000 * 2021/;
set n number /a1ba * a25bc/# 注意 /a1ba * a25bc/不同于 /a01ba * a25bc/

4.3 alias语句:集合的多重命名

当同一个集合需要使用不同的名字时,可以使用alias为原集合定义多个新名字来作为原始集合可选择的名字,但新命名的集合与原集合的元素是相同的,注意alias语句中集合的顺序不重要

set i /i1,i2/;
alias (i,ii); # ii是用来替代原始集合i的新集合
alias (ii,i); # alias语句中集合的顺序不重要
alias (i,ii,iii,iii);# ii、iii、iiii都是用来替代原始集合i的新集合

4.4 子集和范围检查

Set ac /sec1,sec2,labor,capital,finaluse,total/;
Set i(ac) /sec1,sec2/;

4.5 多维集合

gams通过使用多维集合(最多10维)来为不同集合元素之间提供映射或对应关系

Set
   i       'mining regions'  # 提供矿产的国家
           / usa      , w-europe
             china             /

   g       'seven region groupings' # 国家所属地区
           / n-america, west-eur, asia-x/

   # 圆点用来建立上述两个元素之间的一对一的关系
   # 圆点两边可自由使用空格,便于易读
   # 当一个元素匹配诸多元素时,用括号将诸多元素括起来
   # (g,i)表示每对的第一个成员是区域元素,第二个成员是国家元素(域检查的又一作用)
   gi(g,i) 'map of seven regional groups to mines' # 建立地区与国家集合
           / n-america.usa, west-eur.w-europe
             asia-x.  china
Set
   i       'mining regions'  # 提供矿产的国家
           / usa      , w-europe , n-austral, w-austral
              china   ,o-asia                           /

   g       'seven region groupings' # 国家所属地区
           / n-america, west-eur, japan+oc,asia-x/

   # 圆点用来建立上述两个元素之间的一对一的关系
   # 圆点两边可自由使用空格,便于易读
   # 当一个元素匹配诸多元素时,用括号将诸多元素括起来
   # (g,i)表示每对的第一个成员是区域元素,第二个成员是国家元素(域检查的又一作用)
   gi(g,i) 'map of seven regional groups to mines' # 建立地区与国家集合
           / n-america.usa, west-eur.w-europe
             japan+oc.  (n-austral,w-austral) # 一对多的映射,当然可以有多对一和多对多的映射,方法一样
             asia-x.  (china,o-asia) # 可分开写:asia-x. o-asia, asia-x. china

5. 数据输入

gams有三种基本的数据类型,分别是标量(单一)数据、定向列表数据、定向表格数据(二维或多维)数据,它们在gams中的输入分别对应着三种gams语句,分别是scalar(标量)、parameter(参数)、table(表格)语句

5.1 标量

scalar语句用来声明和初始化一个零维gams参数

5.2 参数

parameter包含scalar和table的数据类型

5.3 表格

对于二维及以上的参数,由于表格类型数据(table)中每个标签只出现一次,故表格类型数据的输入方法比列表类型数据输入方法更简洁

5.4 缩写

缩写是一种特殊的数据类型,它允许使用字符串作为值


6. 带参数的数据处理

gams中,赋值语句、内置函数和拓展范围算法为数据操作提供了便利,如通过使用这些语句或方法可以对已经初始化的数据进行处理

6.1 赋值语句

赋值语句作为gams中基本的数据处理语句,它可以用于定义或改变任何集合、参数、变量和方程的值

6.2 表达式

表达式是计算方法的详细描述,可使用括号明确运算顺序
带索引操作、函数、拓展范围算法有助于增加表达式计算能力和灵活性

6.2.1 标准的算数操作符

6.3 增加表达式计算能力和灵活性

6.3.1 带索引操作(Indexed Operation)

6.3.2 函数

gams提供了常用的数学函数,具体函数内容可以点击链接进行查看,这里仅列出最常见的几中函数

Function Description
exp(x) 指数函数
log(x) 自然对数
power(x,n) x为底数n为指数(整数)的幂函数
abs(x) x的绝对值
round(x) 对x进行四舍五入
sqr(x) x的平方
sqrt(x) x的平方根
max(x,y,...) 所有参数中的最大值
min(x,y,...) 所有参数中的最小值
normal(x,y) 平均数为x,标准偏差为y的正太分布随机数
uniform(x,y) x和y之间均匀分布的随机数

6.3.3 拓展范围算法和错误处理

gams使用拓展范围算法处理缺失的数据、未定义操作的结果和求解器系统认为的无限边界的表达方法

special value Description mapval
INF Plus infinity(正无穷) 6
-INF Minus infinity(正无穷) 7
NA Not available(不可用) 5
UNDF Undefined(未定义) 4
EPS A stored zero value(非常接近零,但是不为零) 8


15. Put输出工具

put输出工具的用途在于在格式控制下输出个别项目到不同类别的文档中,如,excel文档

15.1 Put语法的基本结构

# 定义一个多多个要写入的文件
# fname是gams模型中外部文件的名称
file fname;

# 指定其中一个文件作为要写入的当前文件
put fname;

# 当前文件的实际输出项
# item是输出的任意类型,如文本、标签、参数、变量、方程等
put item;

例子:放在模型的末尾输出报告

# 定义名为fac.csv的外部文件在gams内部中的文件名称为factors
#这里指定了两个文件
file factors /fac.csv/, results /res.csv/;
# 指定fac.csv为当前可写入的文件
# 注意这里的语句只能是内部名称
put factors;

# 使用put语句将文本内容Transportion Model Factors写入文档
# 不可以省略文本引号(单引号)
# 短斜线代表回车(一条两条三条都可以)
put 'Transportion Model Factors' ///

# f表示标量
#输出项目用分隔符逗号或空格隔开,但是逗号是更强的格式,可以排除任何歧义
'freight cost', f,

# 通过语句中的光标控制符号#和@可以把光标定位到紧跟其后的数字所表示的列和行
@1#6, 'plant capacity'/;  # 把光标定位到第六行第一列,另写一个文本项

# put语句用分号结束
loop(i,put@3,i.tl,@15,a(i)/);

put /'market demand'/;
loop(j,put@3,j.tl,@15,b(j)/);
put results;
put 'Transportion Model Results' //;
loop((i,j), put i.tl,@12,j.tl,@24,x.l(i,j):8:4/);


  1. 官网:https://www.gams.com ↩︎

  2. 《可计算一般均衡模型的基本原理与编程》GAMS程序:http://www.hibooks.cn/gao/kejian.asp ↩︎

  3. 本节使用的语句来自于 A Transportation Problem,由Dantzig贡献,可在GAMS的Model Library中下载 ↩︎