If I have a number of named parameters in an AMPL model, and a table (either in an Excel spreadsheet or in AMPL’s built-in format) with columns ParamName
, ParamValue
, is there a nice way to read these values in so that the parameter with name ParamName
gets the value ParamValue
?
For example, if I had a file called params.tab
with the contents
ampl.tab 1 1
ParamName ParamVal
n 9
max 100
min 0
is there a way to get an equivalent result to loading a data file containing
param n := 9;
param max := 100;
param min := 0;
?
In particular, I would like an approach that is flexible to changes in what parameters are involved, by which I mean that if I add a new parameter to the model I’d like to just add it as a new row in the table and not have to modify the commands used to load it in too much.
If it simplifies things, it’s safe to assume that all of the parameters have the same type (e.g. integer).
I can think of two approaches that I will write up as a self-answer, but I would very much appreciate any better options.
Approach 1: Read from indexed array to parameters
So the first thing I thought of is to load the table into an indexed array, then assign the values in the array into the parameters.
This would look something like:
set PARAMNAMES;
param ParamValues {PARAMNAMES};
table Params IN "params.tab":
PARAMNAMES <- [ParamNames], ParamValues;
read table Params;
let n := ParamValues[n];
let max := ParamValues[max];
let min := ParamValues[min];
The main problem with this approach is the need to have a laundry list of let
statements that stays in sync with the model parameters and the input file.
Approach 2: Replace the parameters with an indexed array
The second thing I thought of is to do away with individual parameters in the model itself, and instead store them in an array that can be directly read in from the table as above. So in the model I would have a declaration like
set PARAM_NAMES := { n max min };
param params {PARAM_NAMES};
in the model do a find-and-replace changing n
with params[n]
, etc., and then use a read table
statement like in Approach 1 to load the values from the table.
The main drawbacks I see with this are:
- I’m not sure how easy it is to specify individual default values for each parameter.
- The names become clunkier, which might make the model harder to read.