I currently have a python script to create a .gdx file using the Python API. The core of the script looks something like this:
db = gams.GamsWorkspace(workdir, gamspath).add_database()
set = db.add_set(set_name, set_dim, explanatory_text=“”)
set_values = [‘A’, ‘B’, ‘C’]
for s in set_values:
set.add_record(s)
After processing all sets and parameters, I then export the database to create a gdx file.
The problem that I am facing is that the order of the set elements in the gdx file is not always the same as it was in the original Python list. My hypothesis is that sets are treated like dictionary/hash maps under the hood and therefore we have no control about the element order. Is that correct? Is there a way to guarantee a particular order of the set elements?
After further investigation, I’ve been able to create a minimum reproducible example. Consider the following code:
import gams
import os
workdir = ...
gamspath = ...
gdx_file_name = os.path.join(workdir, 'mre.gdx')
db = gams.GamsWorkspace(workdir, gamspath).add_database()
p = db.add_parameter('test_param', 1, explanatory_text="")
param_values = [('s_8',1), ('s_9',2)]
for name, value in param_values:
p.add_record(name).value = value
test_set = db.add_set('test_set', 1, explanatory_text="")
set_values = [f's_{i}' for i in range(10)]
for s in set_values:
test_set.add_record(s)
db.export(file_path=gdx_file_name)
In the created file, the elements of the set are ordered as [s_8, s_9, s_0, s_1, … , s_7] and not in the original order. If we reverse the order of operations and include in the database first the set and then the parameter, then the ordering is preserved for the set. If all elements of the set are present in the parameter (and in order), then there is no problem either.
The obvious workaround is to be very precise about the order of definition of all symbols, but I still wonder if there is a better solution.
mre.gdx (480 Bytes)
Hi @bfsantoro,
The behavior you are experiencing is expected and a feature of GAMS, although sometimes it can feel like an annoyance (it’s actually a core attribute of the GAMS design tho). Unique labels are create in a single “universe set” and area added to GAMS (or GDX) as they are encountered in data. This means that the order that symbols are added to the database could disrupt the expected order. In this example, you have a parameter that is declared over the universe set (not test_set
). This declaration means that you will be able write this data without issue, but also without real regard to the order of the unique elements. Writing the symbols in the correct order is natural if you declare the test_param
over the set test_set
, which is perhaps in the spirit of what your example is doing.
best,
adam
Thank you for your reply, @achristensen. Indeed it makes sense to declare the base set and then the parameters that depend on such a set, because that’s what we do when writing a model in GAMS.
It was not clear that the same rule should be followed in the manipulation of the GDX, because the code doesn’t throw any exception to enforce the such order. Anyway, I will be more careful about the order of declaration.