恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
GAMS二次开发教程(05):集合与数据结构——SETS、子集、多维集合与动态集合
首页
资讯中心
/
GAMS二次开发教程(05):集合与数据结构——SETS、子集、多维集合与动态集合
GAMS二次开发教程(05):集合与数据结构——SETS、子集、多维集合与动态集合
发布时间:2026/10/9 12:58:47
GAMS二次开发教程05集合与数据结构——SETS、子集、多维集合与动态集合版本与许可声明工具/软件GAMS版本号以官方发行说明为准。集合语法与集合运算表取自官方Set Definition“Dynamic Sets”Sets as Sequences: Ordered Sets三章。语言/环境GAMS 语言。本篇示例全部不调用SOLVE因此不需要求解器许可只需要 GAMS 能正常启动与编译。本文目标把索引这一层从会写几个集合名升级为能用集合表达业务结构与数据筛选。许可边界本篇不涉及求解故不触碰许可但其中按数据筛集合的写法直接决定大规模模型的内存与求解时间这是后续所有工程化章节的基础。一句话结论GAMS 里的集合分三类状态——静态集元素在编译期固定可作域、可用ord、动态集成员可在执行期用 yes/ no增删不能再用作其它符号的域、有序集一维 静态 定义顺序等于 GAMS 的进入顺序才允许用ord与 lag/lead而card对任何集合都可用用Subset绑定超集域传递是让编译器替你抓错的最便宜手段。〇、本篇要解决的认知问题Q1Set有哪几种初始化写法区间写法/i1*i10/的规则是什么Q2子集为什么能域传递不写超集的子集为什么合法但不推荐Q3多维集合到底在表达什么它和两个集合的笛卡尔积有什么区别Q4动态集合同静态集合的本质差别是什么为什么动态集不能当别的符号的域Q5Alias、ord、card、sameAs各自解决什么业务问题一、机制解析1.1 集合的三态静态、动态、有序GAMS 集合最重要的一张心智图是三态——很多诡异的报错都源于把三者混为一谈通用集Universal Set标识符写成 * ▲ │ 域传递domain checking沿箭头向上检查 │ ┌──────────── i 静态集 ─────────────────┐ │ 元素在编译期确定斜杠列表 / 区间 / 从 GDX 载入│ │ 可用作其它符号的域可被 ord 使用须一维且有序│ │ 一旦有子集被赋值超集成员的冻结状态即确定 │ └───────┬───────────────────────┬─────────┘ │ subsett(i) │ subset 未绑定超集 ▼ ▼ ┌──────────── t 子集 ──┐ ┌──────── nt合法但不推荐──┐ │ 域检查生效t 的每个 │ │ 域检查失效元素拼错不会 │ │ 元素必须属于 i │ │ 报错错误潜伏到结果里 │ └───────┬────────────────┘ └───────────────────────────┘ │ 一旦被赋值t(x) yes ▼ ┌──────────── 动态集 ──────────────────────┐ │ 成员可在执行期增删yes / no │ │ 不能再用作其它集合/变量/参数/方程的域 │ │ card 可用ord 与 lag/lead 需一维有序 │ └─────────────────────────────────────────┘ 有序集 一维 静态 定义顺序 GAMS 进入顺序(entry order) 只有它才允许 ord 与 lag/lead可用 $offOrder 放宽但有代价三条判定必须背下来看起来有序 ≠ 有序——GAMS 按标签首次出现登记唯一元素表某个标签若在更早的语句里出现过它在当前集合里的内部顺序就不是你书写的顺序官方反例中t2因此不是有序集对它用ord会报官方错误 198。card与ord适用范围不同——card返回元素个数对任何集合都可用静态/动态、有序/无序ord返回相对位置默认只能用于一维的、静态的、有序的集合。域传递只有绑定了超集才发生——官方明确说定义一个不参照更大集合的子集是合法的但不明智因为域检查无法执行services拼错也不会报错模型可能给出错误结果。最佳实践每一个子集都绑定超集写成t(i)而不是裸的t。这不是风格偏好它把逻辑关系写进模型让编译器在编辑阶段就抓出拼写与集合归属错误。1.2 初始化写法枚举、区间、引用既有集合写法例子适用场景枚举Set m / m1, m2, m3 /少量、彼此无规律的标签区间星号Set y / 2021*2026 /有规律的连续标签也支持递减/ 2026*2021 /引用既有集合Set k / #i, set.j /合并已有集合的元素两种记号含义相同带 text 的元素Set cf / syncrude refined crude (mil bbls) /需要单位与说明从 GDX 载入$GDXIN$load元素由外部生成区间写法的规则要精确官方说明是——如果两个端点标签只有数字部分不同左侧数字为L、右侧数字为R则为L到R之间每个整数构造一个标签任何非数字差异或不一致都会报错。所以Set g1 / a1bc * a20bc /合法20 个成员而/ a1x1 * a9x9 /与/ a1 * b9 /非法又因为a01bc与a1bc是两个不同标签/ a01bc * a20bc /与/ a1bc * a20bc /只有 11 个共同成员。经验法则用区间写法时左右端点的前后缀必须逐字符一致。工程上更安全的做法是区间只用来生成序号型标签pl1*pl20、2021*2030带业务语义的编号一律显式枚举。1.3 多维集合它在表达映射不是表达笛卡尔积多维集合最容易误解的一处是Set route(pl,mk)声明的不是pl 与 mk 的笛卡尔积而是允许存在的配对。官方给出的例子是铝业模型里的矿区—港口映射in(i,n) mines to ports map / china.shanghai, ghana.accra, eeussr.leningrad, s-leone.freetown /——点号把两个标签粘成一个元组(i,n)让 GAMS 对每半个标签分别做域检查。若写成先声明两个集合、再在方程里用它们的笛卡尔积你得到的会是全部组合如 4×312而真正的允许关系可能只有 6 条。这个差别就是稀疏结构与稠密结构的分水岭也是规模控制的核心武器。铁律 9工程化目录纪律把允许关系写成多维集合而不是在方程里用$条件现场判断——多维集合是声明式的、可被域检查的、可被复用的而散落在方程里的条件判断既不能复用也无法被编译器检查。模型的结构知识应当集中在集合声明区。1.4 动态集合与集合运算动态集合的赋值语法非常窄官方给出的形式是set_name(index_list | label) yes | no ;只有yes非零视为真与no零视为假两种取值。官方特别提醒不能对集合像对参数那样做算术运算——但提供了专门的集合运算运算运算符含义i是静态超集j/k是其动态子集并集 Unionj(i) k(i)属于 j 或属于 k 的元素交集 Intersectionj(i) * k(i)同时属于 j 与 k 的元素补集 Complementnot j(i)属于 i 但不属于 j 的元素差集 Differencej(i) - k(i)属于 j 但不属于 k 的元素官方同时给出了每一种运算的条件赋值等价写法例如交集可以写成inter(item) yes $ (subitem1(item) and subitem2(item)) ;并指出索引操作sum可用于集合并集、prod可用于集合交集。动态集合最常用的场景有两个作为条件赋值的筛选器subitem2(item) $ subitem1(item) yes ;——按已有数据筛出子集作为方程、变量、参数的过滤器x(i,j)$active(i)只对激活的 i 生效。但有一条硬限制必须记住动态集一般不允许用作集合、变量、参数、方程声明中的域。官方的技巧是——把方程声明在整个域上但只在该动态子集上定义它例如resource1(r).. activity1(r) l data(r,resource-1) ;resource1声明在allr上。这就是分组求解把若干区、装置、场景分组共用一套数据与逻辑在 GAMS 里可行且优雅的原因。铁律 10数值不臆造动态集合经常被用来做数据驱动的分组而分组依据往往是业务口径例如负荷率高于某阈值。这些阈值必须来自你的数据源或官方文档并明确标注不能凭印象写一个看起来合理的数。1.5 Alias、ord、card、sameAs四个索引级工具工具作用典型用途关键限制Alias给一个已声明集合起第二个名字同一集合内部两两作用距离矩阵、先后关系语句里恰好一个集合必须已定义ord返回元素在集合中的相对位置从 1 开始序号化、阈值判断、上三角矩阵默认仅限一维静态有序集card返回集合的元素个数端点判断最后一个时期、长度、比例任何集合都可用sameAs判断两个标签是否相同逻辑条件对角元、自身匹配是预定义符号不作为普通数据写入 GDX两个组合模式值得背下来均来自官方示例上三角矩阵a(i,j) $(ord(i) ord(j)) ord(i) ord(j) ;端点判断c.fx(t)$(ord(t) card(t)) demand(t) ;。官方专门表扬后者它使得集合成员可以安全变化而这条语句永远作用于最后一个元素——相比之下把t(2026)硬编码进去一旦时期集合变了就会静默失效。经验法则凡是位置相关的逻辑第几期、上三角、相邻项、端点优先用ord/card表达不要在代码里硬编码标签名——硬编码标签会让改数据变成改代码这是长期维护成本最高的反模式之一。二、完整代码与逐行剖析代码 5-1ch05_sets.gms—— 静态集合、子集、多维集合与 Alias完整可运行$title ch05_sets - 静态集合、子集、多维集合、Alias 与 ord/card * 适用分发口径以 gams.com/latest/docs 当前分发为准版本号以官方发行说明为准 * 求解许可本段不调用 SOLVE无需求解器许可 * 平台GAMS 语句通用 * ---- 初始化写法一区间星号。左右端点只允许数字部分不同 ---- * 把时间类集合放在最前面声明是为了让标签的进入顺序与你写的顺序一致 Set yr planning years / 2021*2026 / ; * ---- 初始化写法二枚举。元素间用逗号或换行分隔可带 text ---- Set pl plants / pl1, pl2, pl3, pl4 / mk markets / mk1, mk2, mk3 / ; * ---- 子集集合名后跟超集名域传递由此建立 ---- * 域检查会保证 coastal 的每个元素都必须是 pl 的元素 Set coastal(pl) plants with sea access / pl1, pl3 / ; * ---- 多维集合表达允许的配对而不是两个集合的笛卡尔积 ---- * 点号把两个标签粘成一个元组每种写法都受域检查保护 Set route(pl,mk) allowed plant-to-market routes / pl1.mk1 pl1.mk2 pl2.mk1 pl3.mk2 pl3.mk3 pl4.mk3 / ; * ---- Alias为同一集合起第二个名字用于自己与自己的两两索引 ---- * 官方限制语句里恰好一个集合必须是此前已定义过的 Alias (pl, plp) ; Alias (mk, mkm) ; * ---- ord 与 card ---- Scalar nPlant number of plants (card) ; Parameter seq(pl) relative position of each plant (ord) gap(pl,plp) difference of ord between two plants onCoast(pl) 1 if the plant belongs to the coastal subset ; nPlant card(pl) ; seq(pl) ord(pl) ; * 用 Alias 得到的第二个名字做两两比较$-条件把作用范围限制在有序对上 gap(pl,plp)$(ord(pl) ord(plp)) ord(plp) - ord(pl) ; * 用集合成员关系做条件赋值属于子集则为 1否则保持默认值 0 onCoast(pl) 1 $ coastal(pl) ; Display nPlant, seq, gap, onCoast, coastal, route ;逐行剖析Set yr ... / 2021*2026 / ;用区间写法且放在文件最前面是刻意安排——唯一元素表按首次出现登记标签先出现才能保证内部顺序等于书写顺序coastal(pl) ... / pl1, pl3 / ;是绑定超集的子集写成裸的coastal会让域检查失效pl1拼成p11也不报错这是本篇第一条肌肉记忆route(pl,mk)只有 6 个元组而pl × mk是 12 个组合这个差别是稀疏建模的全部意义Alias (pl, plp) ;之后两个名字指同一个集合官方要求语句里恰好一个集合是已定义过的nPlant card(pl) ;对任何集合都可用而seq(pl) ord(pl) ;要求pl一维、静态且有序gap(pl,plp)$(ord(pl) ord(plp)) ord(plp) - ord(pl) ;演示$写在赋值左侧表示只对命中元组赋值onCoast(pl) 1 $ coastal(pl) ;把集合成员关系直接用作条件——集合成员可以作为逻辑条件。代码 5-2ch05_dyn.gms—— 动态集合、集合运算与 sameAs完整可运行$title ch05_dyn - 动态集合、集合运算、条件赋值与 sameAs * 适用分发口径集合运算与 sameAs 的语义以官方 Dynamic Sets 与 Conditional Expressions 章节为准 * 求解许可本段不调用 SOLVE无需求解器许可 * 平台GAMS 语句通用 * 静态超集本篇所有动态集合都绑定在它上面以便保留域检查 Set item all items / dish, ink, lipstick, pen, pencil, perfume / ; * 子集声明给它们赋值之后它们就变成动态集合 Set subitem1(item) first subset of item / pen, pencil / subitem2(item) second subset of item ; * ---- 动态集合的成员增删取值只有 yes / no ---- * 注意这会让超集 item 的成员状态冻结此后 item 不再接受新的元素 subitem1(ink) yes ; subitem1(dish) yes ; subitem2(item) yes $ subitem1(item) ; * 条件赋值按 subitem1 筛出 subitem2 subitem2(pen) no ; * 从动态集合里移除一个元素 * ---- 集合运算并、交、补、差 ---- Set uni(item) union of subitem1 and subitem2 inter(item) intersection of subitem1 and subitem2 comp(item) complement of subitem1 in item diff(item) subitem2 minus subitem1 ; uni(item) subitem1(item) subitem2(item) ; inter(item) subitem1(item) * subitem2(item) ; comp(item) not subitem1(item) ; diff(item) subitem2(item) - subitem1(item) ; * ---- sameAs判断两个标签是否相同预定义符号用作逻辑条件---- Alias (item, itemp) ; Parameter diagFlag(item,itemp) 1 where the two labels coincide ; diagFlag(item,itemp)$sameAs(item,itemp) 1 ; * ---- 单元素集合Singleton Set赋值会先清空整个集合 ---- Singleton Set pick(item) the single currently selected item / ink / ; pick(pen) yes ; * 这一句不是添加而是替换 Display subitem1, subitem2, uni, inter, comp, diff, diagFlag, pick ;逐行剖析subitem1(ink) yes ;有两个副作用——给subitem1增加成员以及让它的超集item从此刻起成为静态集合、成员状态被冻结subitem2(item) yes $ subitem1(item) ;的$在右侧官方指出这种形态隐含 if-then-else、else 分支自动为 0与$在左侧只赋值命中项截然不同这是 GAMS 里最容易记混的一对uni/inter/comp/diff四行是官方集合运算的等价写法官方同时指出sum可用于并集、prod可用于交集diagFlag(item,itemp)$sameAs(item,itemp) 1 ;是sameAs的规范用法——用Alias得到两个不同的名字、同一个集合再判断标签是否相同Singleton Set的赋值会先清空集合所以pick(pen) yes是替换而非叠加官方配套选项strictSingleton默认 1在右侧含多个元素时报错默认行为更安全。代码 5-3ch05_ordered.gms—— 有序集合、lag/lead 与端点判断完整可运行$title ch05_ordered - 有序集合、ord/card 与线性 lag * 适用分发口径$onUELList 与 lag 语义以官方 Ordered Sets 与 Dollar Control Options 章节为准 * 求解许可本段不调用 SOLVE无需求解器许可 * 平台GAMS 语句通用 * 打开唯一元素表让你亲眼看到进入顺序与字典序的差别 $onUELList * 时间集合必须先声明才能保证内部顺序 书写顺序有序集的前提 Set t planning periods / 2021*2026 / ; * 用 Alias 得到第二个名字才能在 sum 里对同一集合的另一个副本做遍历 Alias (t, tt) ; Parameter dem(t) demand in period t / 2021 100, 2022 120, 2023 130, 2024 125, 2025 140, 2026 150 / cum(t) cumulative demand up to and including t prevDem(t) demand of the previous period (linear lag reference) lastFlag(t) 1 only for the last period grow(t) growth rate versus the previous period ; * ord 用于序号化只对位置不晚于当前期的期间求和 cum(t) sum(tt$(ord(tt) ord(t)), dem(tt)) ; * 线性 lag 用在右侧 引用第一期没有前一期引用返回默认值 0 prevDem(t) dem(t-1) ; * 增长率演示把相对上一期的运算与防止除零的 $ 条件放在一起 grow(t) (dem(t) - dem(t-1)) / dem(t-1) $ (ord(t) 1) ; * 端点判断不硬编码最后一年而是用 ord card 判断 lastFlag(t) 1 $ (ord(t) card(t)) ; Display t, dem, cum, prevDem, grow, lastFlag ;逐行剖析$onUELList会把唯一元素表打进.lst官方形态是先按进入顺序、再按字典序各列一遍——这是判断集合到底有没有序的唯一实证手段Alias (t, tt) ;让sum(tt$(...), dem(tt))有可用的遍历指标tt与t是同一集合的两个名字cum那一行演示内层$写在sum指标后面表示求和范围只取满足条件的tt与写在赋值左侧的$语义不同prevDem(t) dem(t-1) ;用的是线性 lag 的引用形态官方规则是引用不存在的元素取默认值 0而对不存在的元素赋值则不会发生任何赋值——这条差异是 lag/lead 全部陷阱的根源官方同时提醒lag/lead 不能与算术运算符混用lastFlag(t) 1 $ (ord(t) card(t)) ;是官方推荐的端点写法期间集合改变时它自动作用于新的最后一期而硬编码t(2026)会静默失效。三、常见报错与排查报错 3-1**** $170 Domain violation for element域违反。现象集合元素录入行报$170。根因元素拼写与声明不一致或元素本来就不在集合里含子集元素不属于超集。解法对照声明逐字核对若你写的是未绑定超集的子集域检查不会执行应先把子集改写成sub(t)形式再排查。报错 3-2**** $171域错误索引位置用错集合。现象索引个数正确但集合不对例如route(pl,mk)被写成route(mk,pl)。根因官方说明为A domain error. The wrong set is referenced for the respective index position.。解法把声明处与引用处的索引列表逐位置对齐抄写注意$148是索引个数不符、$171是集合用错。报错 3-3**** $172 Element is redefined元素重复定义。现象Set c / barley, wheat, soy, wheat, rice / ;报$172官方消息原文即172 Element is redefined。根因同一元素在一个集合里出现两次或给同一个符号写了第二条数据语句默认一个符号最多只能有一条数据语句。解法删掉重复元素确实要分批追加元素时使用美元控制选项$onMulti。报错 3-4**** $198对非有序集用ord或 lag/lead。现象用ord(t2)或x(t-1)却报错。根因该集合不是一维 静态 定义顺序等于进入顺序的有序集——官方反例中某标签在更早的集合里出现过导致进入顺序先于你书写的位置。解法把该集合的声明前移到最开始用$onUELList打出唯一元素表核验顺序不要用$offOrder掩盖问题官方明确说代价是系统无法诊断错误的数据与公式。报错 3-5Multiple assignment to Singleton Set not allowed (see option strictSingleton)。现象给单元素集合赋值时右侧含多个元素。根因单元素集合的赋值会先清空集合且默认strictSingleton1不允许右侧出现多个元素。解法确保右侧只产生一个元素不建议把strictSingleton设为 0——那只是取第一个元素会把逻辑错误变成静默错误。报错 3-6动态集合被用作域导致报错。现象把动态集合用在Variable/Parameter/Equation的声明括号里。根因官方明确动态集合一般不允许作为声明中的域静态子集可以。解法按官方技巧在完整域上声明、在动态子集上定义——方程声明成resource1(allr)方程体写成resource1(r).. activity1(r) l data(r,resource-1) ;。报错 3-7集合成员赋值写了非yes/no的数值。现象赋值不报错但成员关系与预期不符。根因官方说明——GAMS 允许给集合赋任意数值非零视为属于、零视为不属于所以t(light-ind) 0.5不会报运行时错误而是被解释为属于。解法集合成员赋值一律只用yes/no。四、动手练习练习 1静态结构运行代码 5-1。判定(a)nPlant为 4(b)seq给出 pl1…pl4 依次为 1…4©gap只在满足ord(pl) ord(plp)的元组上有值其余为默认 0(d)onCoast只有 pl1 与 pl3 为 1。练习 2稀疏 vs 稠密把route(pl,mk)改成route2(pl,mk)并赋全部 12 个组合打印card(route)与card(route2)对比。判定能说出两个数字并用一句话解释为什么多维集合表达的是映射而不是笛卡尔积。练习 3两种$位置运行代码 5-2再把subitem2(item) yes $ subitem1(item) ;改写成subitem2(item) $ subitem1(item) yes ;比较两次Display subitem2。判定能说明$在右侧隐含 else0、$在左侧只影响命中项并解释改写后成员为何更多。练习 4有序集与端点运行代码 5-3。判定(a)cum单调递增且最后一期等于dem六期之和(b)prevDem第一期2021为 0其余等于上一期©lastFlag只在 2026 为 1(d) 把t改成/ 2021*2028 /并补数据后lastFlag自动落在新的最后一期。练习 5有序性实证把t的声明刻意移到dem声明之后或先声明另一个含 “2026” 的集合用$onUELList观察唯一元素表再尝试ord(t)。判定能复现对非有序集使用ord/lag 报错的现象并说出根因与两种修法前移声明或重新声明同名新集合。五、小结与下一篇预告本篇把索引这一层讲透核心是三条判定集合三态静态可作域、动态可增删但不可作域、有序才能用ord与 lag/lead、域传递子集必须绑定超集否则域检查失效、位置而非标签凡是第几期/上三角/端点/相邻的逻辑都用ord/card表达绝不硬编码标签名。工具层面记住四个Alias给同一集合第二个名字、ord取相对位置、card取元素个数任何集合都可用、sameAs/diag是预定义符号只作逻辑判断。同时把两条纪律带下去结构知识集中在集合声明区铁律 9阈值与规模类数值必须可追溯铁律 10。第 06 篇《参数、标量、表格与数据录入》转向数据这一层Parameter/Scalar/Table三者的语法差异与选型、列表式与表格式数据录入的取舍、$include拆出独立数据文件的多文件工程、编译期$if/$set与运行期双横线参数--scenariox的配合以及$GDXIN$load从 GDX 取数的第一步 —— 那是把数据进模型从手工抄写升级为流水线的起点。本篇认知问题回显FAQQ1Set 有哪几种初始化写法区间写法 /i1*i10/ 的规则是什么A主要有五种枚举Set m / m1, m2, m3 /、区间星号写法Set y / 2021*2026 /官方也支持递减、引用既有集合Set k / #i, set.j /两种记号含义相同、带 text 的元素Set cf / syncrude refined crude (mil bbls) /、以及从 GDX 载入$GDXIN与$load。区间规则若两个端点标签只有数字部分不同设左侧数字为 L、右侧为 R则构造 L 到 R 之间每个整数对应的标签任何非数字差异都会报错因此/ a1bc * a20bc /合法/ a1x1 * a9x9 /与/ a1 * b9 /非法。列表可省略此时只声明而不定义。Q2子集为什么能域传递不写超集的子集为什么合法但不推荐A子集的语法是set set_ident1(set_ident2)即子集名后跟超集名如t(i) traded sectors / light-ind, foodagr, heavy-ind /。它建立域传递关系子集的每个元素必须也是超集的元素GAMS 在引用域时执行域检查强制执行所以元素拼错、缺失、子集越界都会在编译期被抓出来。反之官方明确指出定义一个不参照更大集合的子集是合法的但不明智——域检查无法执行services拼错不会有任何报错但模型可能给出错误结果。因此最佳实践是每个子集都绑定超集。注意子集可作为其它符号的域前提是它尚未变成动态集合。Q3多维集合在表达什么它和两个集合的笛卡尔积有什么区别A多维集合表达的是允许存在的映射/配对而不是笛卡尔积。语法上把标签用点号粘成元组如in(i,n) mines to ports map / china.shanghai, ghana.accra, eeussr.leningrad, s-leone.freetown /这样in只有 4 个元素而不是 i 与 n 的 4×416 个组合元组写法同样受域检查。两种形态一对一、多对多语法无差别差别在稀疏度与业务含义。这是稀疏建模的关键把允许关系写进多维集合后方程里的sum只遍历真实存在的配对。Q4动态集合同静态集合的本质差别是什么为什么动态集不能当别的符号的域A静态集合元素在编译期确定斜杠列表、区间或从 GDX 载入执行期成员不变动态集合的成员可在执行期增删赋值语法只有set_name(index_list | label) yes | no且不能像参数那样做算术运算只能用官方集合运算并、交*、补not、差-。官方限制是动态集一般不允许作为集合、变量、参数、方程声明中的域静态子集可以。官方技巧是在完整域上声明、在动态子集上定义把方程声明成resource1(allr)方程体写成resource1(r).. activity1(r) l data(r,resource-1)就能对任意分组反复求解同一模型。副作用一旦某个超集的子集被赋值该超集的成员状态就冻结。Q5Alias、ord、card、sameAs 各自解决什么业务问题AAlias给一个已声明的集合起第二个名字语句里恰好一个集合必须已定义用于同一集合内部两两作用如厂间运输成本矩阵、期间先后关系。ord返回元素的相对位置从 1 开始官方默认限制是只能用于一维、静态、有序的集合典型用法是序号化、上三角矩阵a(i,j)$(ord(i) ord(j))与端点判断c.fx(t)$(ord(t) card(t))。card返回元素个数对任何集合都可用常用于长度、比例与端点判断。sameAs与diag是 GAMS 的预定义符号用于判断两个标签是否相同diag像sameAs但对 TRUE 返回数值 1适合放在逻辑条件里但不应像用户自定义符号那样被写入 GDX。