是否有很好的方法可以在.run
文件中的AMPL中遍历模型/数据集对?
假设您有两个针对相同优化问题的不同模型和四个数据集。我到目前为止要做的是为每个模型/数据集对创建一个.run
文件,并分别运行每个脚本,或者为每个模型保留一个脚本,并通过修改data (file);
手动求解每个数据集命令。但这对于大型项目显然是乏味且不可行的。
那么有什么好办法吗?我尝试过的操作类似于以下内容(为清楚起见,只是一个框架):
# Some global options
for {model_ in {'1.mod', '2.mod'}} {
reset;
model (model_);
for {dat in {'1.dat', '2.dat', '3.dat', '4.dat'}} {
update data;
data (dat);
solve;
# Do some post-processing
}
}
但是AMPL
抱怨在model
和data
命令中使用for循环的虚拟变量。我尝试声明symbolic
参数来存储模型和数据文件的名称,但也没有用。
当然,只有在模型足够相似的情况下,这才有意义,因为它们可以用相同的方式进行后处理。但是至少应该有 一种方法来遍历一个模型中的数据文件而不必像这样
update data;
data 1.dat;
solve;
update data;
data 2.dat;
solve;
update data;
data 3.dat;
solve;
[...]
update data;
data 427598.dat;
solve;
对吗?
答案 0 :(得分:1)
您的示例代码在循环内有一个reset
。这将重置循环参数,这将导致问题。例如,如果您运行以下命令:
for {modelname in {"itertest1.mod","itertest2.mod"}}{
display (modelname);
for {dataname in {"itertest_a.dat","itertest_b.dat"}}{
display (dataname);
}
}
它将打印出我们希望的文件名:
modelname = itertest1.mod
dataname = itertest_a.dat
dataname = itertest_b.dat
modelname = itertest2.mod
dataname = itertest_a.dat
dataname = itertest_b.dat
但是,如果我们添加一条reset语句:
for {modelname in {"itertest1.mod","itertest2.mod"}}{
reset; ### this is the only line I changed ###
display (modelname);
for {dataname in {"itertest_a.dat","itertest_b.dat"}}{
display (dataname);
}
}
然后我们得到一个错误:modelname is not defined
(因为我们只是重置了它)。
但是,即使没有这个问题,我们仍然会抱怨使用循环变量。
根据所运行的内容,您可能会看到一条错误消息,建议您使用commands
语句,如下所示:
reset;
for {scriptname in {"script1.run", "script2.run"}}{
commands (scriptname);
}
然后它将运行列出的.run文件中的任何命令,并且您应该能够嵌套该命令以调用单独的脚本来定义模型和数据。由于您不能在不终止循环参数的情况下使用全部重置,因此您将需要使用其他选项来更新模型文件。 AMPL提供了定义多个“问题”并在它们之间进行切换的选项,这在这里可能有用也可能没有帮助;我没有探索过。
commands
语句已记录在here中,尽管TBH我发现该文档有点难以理解。
如果其他所有方法均失败,则可以编写一个迭代的AMPL脚本,该脚本将生成(并可选地运行)包含您要运行的所有模型/数据组合的第二个脚本,如下所示:
param outfile symbolic := "runme_temp.run";
for{i in 1..3}{
for{j in 1..4}{
printf "\nreset;" > (outfile);
printf "\nmodel model%s;",i > (outfile);
printf "\ndata data%s;",j > (outfile);
printf "\nsolve;" > (outfile);
# add post-processing here as desired
}
}
close (outfile);
include runme_temp.run;
这将创建并调用如下所示的“ runme_temp.run”:
reset;
model model1;
data data1;
solve;
reset;
model model1;
data data2;
solve;
等等等。由于可以通过 使用毯子reset;
,因此可以简化清理先前模型的过程。不是最尊严的解决方案,但它可以工作,并且可以适应各种情况。
这可以通过取消嵌套循环来改善:
param outfile symbolic := "runme_temp.run";
for{i in 1..3, j in 1..4}{
printf "\nreset;" > (outfile);
printf "\nmodel model%s;",i > (outfile);
printf "\ndata data%s;",j > (outfile);
printf "\nsolve;" > (outfile);
# add post-processing here as desired
}
close (outfile);
include runme_temp.run;
在这个特定的例子中,它并没有太大的区别,但是多重嵌套循环在AMPL中可能会运行缓慢;使用单个多索引for
可以对性能产生很大的影响,因此养成这种习惯可能会更好。