【问题标题】:Extract data to update model parameters and solve maximization problem in GAMS提取数据以更新模型参数并解决 GAMS 中的最大化问题
【发布时间】:2025-12-10 06:25:01
【问题描述】:

我有几个农民,我想在 GAMS 中为每个农民进行优化(利润最大化)。我可以为一个农民做这个,所以我的问题是如何迭代地使它适用于多个农民。

我将数据记录在3个不同的.csv文件中,如下(见代码):

  • 1 个文件说明农民在他的农场上分配了多少资源(resource_allocation.csv 用于单个农民,resource_allocations.csv 用于多个农民)
  • 1 个文件说明农民拥有多少资源可供使用(resource_endowment.csv 用于单个农民,resource_endowments.csv 用于多个农民)
  • 1 个文件说明农民获得了多少毛利率(activity_gross_margin.csv 用于单个农民,activity_gross_margins.csv 用于多个农民)

以下代码可以满足我对单身农民案例的要求。

SETS
    resr                 resource of the farmer
    crop                 crops grown by the farmer
    ;

PARAMETERS
    resource_allocation  resource allocated by the farmer
    resEndow             resouce endowment of the farmer
    grosMarg             activities' gross margin of the farmer
    ;
    
$onEcho > resource_allocation.csv
resrs,Corn,    Bean,  Sorghum,  Peanut
Land,1,1,1,1
Labor,1.42,1.87,1.92,2.64
Mules,1.45,1.27,1.16,1.45
Market,0,0,0,0.98
$offEcho
$call csv2gdx resource_allocation.csv id=resource_allocation useHeader=y fieldSep=Comma index=1 values=2..lastCol trace=3 
$ifE errorLevel<>0 $abort Problems reading resource_allocation.csv!
$gdxIn resource_allocation.gdx
$load resr             = dim1
$load crop            = dim2
$load resource_allocation
$gdxIn
;

$onEcho > resource_endowment.csv
resr,resEndow
Labor,16.5
Land,5
Mules,10
Market,0.5
$offEcho
$call csv2gdx resource_endowment.csv id=resEndow useHeader=y fieldSep=Comma index=1 values=2 trace=3 
$ifE errorLevel<>0 $abort Problems reading resource_endowment.csv!
$gdxIn resource_endowment.gdx
$load resEndow
$gdxIn
;

$onEcho > activity_gross_margin.csv
crop,grosMarg
Corn,1372
Bean,1219
Sorghum,1523
Peanut,4874
$offEcho
$call csv2gdx activity_gross_margin.csv id=grosMarg useHeader=y fieldSep=Comma index=1 values=2 trace=3 
$ifE errorLevel<>0 $abort Problems reading activity_gross_margin.csv!

$gdxIn activity_gross_margin.gdx
$load grosMarg
$gdxIn
;

*DISPLAY resEndow, grosMarg, farmData;

VARIABLES

Prft Total gross margin
x(crop) activity levels
;

EQUATIONS

Profit definition of Z
RESCON ressouse constraint
NONNEG non-negativity condition;

Profit.. Prft =E= sum(crop, grosMarg (crop)*x(crop));
RESCON(resr).. sum(crop, resource_allocation(resr, crop)*x(crop)) =L= resEndow(resr);
NONNEG(crop).. x(crop) =G= 0;

model mayaland / Profit, RESCON, NONNEG /
;

SOLVE mayaland maximizing Prft using LP;
DISPLAY x.l, Prft.l;

我的问题是如何使上述模型适用于多个农民,并以全面的布局导出结果,根据农民的姓名、农民的地区和农民的实践清楚地识别每个农民(见下面的数据)。为此,我只展示了我的数据看起来如何。我对要编写的代码没有太多想法(这就是我问这个问题的原因)。请注意,在下面的数据中,我只是从单个农民数据集中复制了相同的信息,并添加了 3 个额外的列,以明确区分 farmer 1farmer 2。因此,我们希望这两种解决方案是相同的。我还希望将解决方案导出到.csv 文件,以便进一步处理。

*******************************************************************
* Here starts my problem: How can I run the above run over the 
* sets farmers, regions, and practices such that I get 1 solution 
* for each unique combination of(farmers, regions, practices)
*******************************************************************

SETS
    farmers
    regions
    practices
    resrs
    crops
;
PARAMETERS
    resource_allocations
    resource_endowments
    activity_gross_margins
    ;
    
SETS resrs, crops;

PARAMETERS
    farmDatas
    resEndows
    grosMargs
    ;
    
$onEcho > resource_allocations.csv
farmers,regions,practices,resrs,Corn,    Bean,  Sorghum,  Peanut
farmer 1,region 1,practice 1,Land,1,1,1,1
farmer 1,region 1,practice 1,Labor,1.42,1.87,1.92,2.64
farmer 1,region 1,practice 1,Mules,1.45,1.27,1.16,1.45
farmer 1,region 1,practice 1,Market,0,0,0,0.98
farmer 2,region 2,practice 2,Land,1,1,1,1
farmer 2,region 2,practice 2,Labor,1.42,1.87,1.92,2.64
farmer 2,region 2,practice 2,Mules,1.45,1.27,1.16,1.45
farmer 2,region 2,practice 2,Market,0,0,0,0.98
$offEcho
$call csv2gdx resource_allocations.csv id=resource_allocations useHeader=y fieldSep=Comma index=1..4 values=5..lastCol trace=3 
$ifE errorLevel<>0 $abort Problems reading resource_allocations.csv!
$gdxIn resource_allocations.gdx
$load farmers = dim1
$load regions = dim2
$load practices = dim3
$load resrs = dim4
$load crops = dim5
$load resource_allocations
$gdxIn
;

$onEcho > resource_endowments.csv
farmers,regions,practices,resrs,resEndows
farmer 1,region 1,practice 1,Labor,16.5
farmer 1,region 1,practice 1,Land,5
farmer 1,region 1,practice 1,Mules,10
farmer 1,region 1,practice 1,Market,0.5
farmer 2,region 2,practice 2,Labor,16.5
farmer 2,region 2,practice 2,Land,5
farmer 2,region 2,practice 2,Mules,10
farmer 2,region 2,practice 2,Market,0.5
$offEcho
$call csv2gdx resource_endowments.csv id=resEndows useHeader=y fieldSep=Comma index=1..4 values=5..lastCol trace=3 
$ifE errorLevel<>0 $abort Problems reading resource_endowments.csv!
$gdxIn resource_endowments.gdx
$load resEndows
$gdxIn
;

$onEcho > activity_gross_margins.csv
farmers,regions,practices,crops,grosMargs,
farmer 1,region 1,practice 1,Corn,1372,
farmer 1,region 1,practice 1,Bean,1219,
farmer 1,region 1,practice 1,Sorghum,1523,
farmer 1,region 1,practice 1,Peanut,4874,
farmer 2,region 2,practice 2,Corn,1372,
farmer 2,region 2,practice 2,Bean,1219,
farmer 2,region 2,practice 2,Sorghum,1523,
farmer 2,region 2,practice 2,Peanut,4874
$offEcho
$call csv2gdx activity_gross_margins.csv id=grosMargs useHeader=y fieldSep=Comma index=1..4 values=5..lastCol trace=3 
$ifE errorLevel<>0 $abort Problems reading activity_gross_margins.csv!

$gdxIn activity_gross_margins.gdx
$load grosMargs
$gdxIn
;

请注意,我已经问过这个问题here。但是,我无法解决从答案中得到的建议。也就是说,我对作为伪代码的工作流程有一点了解,但我无法将其转换为 GAMS 理解的实际代码。我知道我可以更新 loop 中的模型参数,但我无法从多个农民数据集中提取每个农民的数据。请注意,添加 3 个标识符列(即农民、地区、实践)后,数据的维度不再与模型方程中的相同。

根据我从上一个问题中得到的建议,我尝试组成一个集合frp 并循环通过它来提取单个农民数据并求解模型,如下面的代码块。

sets
    frp(farmers,regions,practices) the looping index
;

$onEcho > frp.csv
farmers,regions,practices,frp,
farmer 1,region 1,practice 1,1,
farmer 2,region 2,practice 2,2
$offEcho
$call csv2gdx frp.csv id=frp useHeader=y fieldSep=Comma index=1..3 values=4 trace=3 
$ifE errorLevel<>0 $abort Problems reading frp.csv!

$gdxIn frp.gdx
$load frp
$gdxIn
;

parameter results(farmers,regions,practices,*,*) 'collect results';

loop(frp(farmers,regions,practices),
* extract data for single case (I assume I need to update the following 3 parameters)
       resEndow(resr) =  resource_endowments(farmer,region,practice,resrs);
       grosMarg (crop) = activity_gross_margins (farmers,regions,practices,crops,grosMargs)
       resource_allocation(resr, crop) = resource_allocations(farmers,regions,practices,resrs)
* solve single case
       SOLVE mayaland maximizing Prft using LP;
* store results in parameter
       results(farmer,region,practice,'x',crops) = x.l(crops);
       results(farmer,region,practice,'profit','-') = Prft.l;
);
* export results to spreadsheet or csv file (have not even tried to export becuase I couldn't make the loop work).

我遇到了一堆错误,但第一个错误说:

**** 120 未知标识符按集合输入 **** 141 已声明符号但未分配任何值。检查是否丢失 **** 数据定义、赋值、数据加载或隐式赋值 **** 通过解决语句。 **** 一个狂野的镜头:您可能在解释中使用了虚假逗号 **** 声明文本。检查符号参考列表。

【问题讨论】:

  • “但是,我无法解决我从答案中得到的建议。” - 你能分享一下你尝试了什么并显示你遇到了什么错误吗?这样,提供一些帮助会更容易。
  • 嗨@Lutz,感谢您查看此内容。我更新了问题以显示我尝试过的内容。如果您需要我提供进一步的更新,请告诉我。

标签: gams-math


【解决方案1】:

在您尝试的代码中实际上并没有一个普遍的问题,但是您将不同符号的名称以及 GDX 文件的名称与从这些文件中加载的符号名称混淆了。但是,正如 GAMS 指出的那样,逐一解决您的错误是非常简单的。这是新的循环(我将您的代码保留为注释,并在下面保留了固定的代码):

loop(frp(farmers,regions,practices),
* extract data for single case (I assume I need to update the following 3 parameters)
*old       resEndow(resr) =  resource_endowments(farmer,region,practice,resrs);
       resEndow(resr) =  resEndows(farmers,regions,practices,resr);
*old       grosMarg (crop) = activity_gross_margins (farmers,regions,practices,crops,grosMargs)
       grosMarg (crop) = grosMargs (farmers,regions,practices,crop,'grosMargs');
*old       resource_allocation(resr, crop) = resource_allocations(farmers,regions,practices,resrs)
       resource_allocation(resr, crop) = resource_allocations(farmers,regions,practices,resr,crop);
* solve single case
       SOLVE mayaland maximizing Prft using LP;
* store results in parameter
*old       results(farmer,region,practice,'x',crops) = x.l(crops);
       results(farmers,regions,practices,'x',crop) = x.l(crop);
*old       results(farmer,region,practice,'profit','-') = Prft.l;
       results(farmers,regions,practices,'profit','-') = Prft.l;
);

【讨论】:

  • 谢谢@Lutz!这解决了我的问题。为什么grosMarg (crop) = grosMargs (farmers,regions,practices,crop,'grosMargs');中的grosMargs必须被引用,而不是resEndow(resr) = resEndows(farmers,regions,practices,resr);中的resr?显然,我需要了解集合在 GAMS 中的工作原理。你有一些参考资料可以建议学习 GAMS。用户指南对我理解 GAMS 帮助不大。
  • 引用的“grosMargs”是参数 grosMargs 的第 5 维中的一个特定元素。 (您也可以以不同的方式定义数据,以完全忽略该维度,但这是一个不同的主题)。相比之下 resr 本身就是一个集合(包含元素“土地”、“劳动力”、“骡子”、“市场”),您可以通过引用该集合来访问所有这些元素。我实际上认为 thge GAMS 文档中的教程是一个很好的起点,也可以了解集合的基本概念:gams.com/34/docs/UG_Tutorial.html
  • 嗨@Lutz,我又来了!我将此代码应用于一些真实数据并在引用的“grosMargs”上出现错误:**** 116 Label is unknown **** 148 Dimension different - The symbol is referenced with more/less **** indices as declared
  • 唯一的区别是真实数据比我们这里使用的数据要大,而且农民不一定拥有相同的作物、资源禀赋或毛利率。但是,这些都在模型中表示(在循环之前)。知道是什么导致了这个错误吗?我正在尝试重现错误,但我还没有成功。令我感到奇怪的是,当我显示文件时,该符号出现在 GDX 中。
  • 好吧,我想通了!这个问题在某种程度上与.csv 文件有关。 $onEcho ... $offEcho 似乎在每行的末尾添加了一个额外的逗号。这个额外的逗号使grosMargs 成为一个独立的维度。