Stability of variables indices
TLDR
def test_variable_stability_add_variables():
model = Model()
model.add_variables(1, (0, 1), name="B")
idx0 = model.idx(("B", 0))[0]
model.add_variables(1, (0, 1), name="A")
idx1 = model.idx(("B", 0))[0]
assert idx0 == idx1, f"Indices are not stable after adding variables: idx0={idx0} idx1={idx1}"
The issue
- There are two "types" of indices:
- those used by the user to refer to variables, that are either of the form
(variable_name: str, idx: int)
, or justidx: int
that are interpreted as('X', idx: int)
where 'X' is the default variable name. - those used inside the
Model
class to build a constraint network that will in fine correspond to vertex indices
- those used by the user to refer to variables, that are either of the form
- Currently, there is no distinction between them
- Those indices are computed as follows:
- the dictionnary
Model._domains
maps tuples(variable_name: str, idx: int)
to lists of domains (List[FiniteDomain]
) - to compute the index of a variable (
Model.idx
), we traverse the dictionnary's items and compute an offset based on the number of domains "before" the one designated by the variable - Issue 1: the
Dict
class should not be relied upon to provide a consistent traversal order (althoughcollection.OrderedDict
provides an alternative) - Issue 2: adding variables with a name already present would "shift" all the variables indices
- the dictionnary
My solution
- add a dictionary
Model.variables_to_indices
that maps variables(variable_name: str, idx: int)
to "vertex" indices (int
) - add a counter
Model.next_variable_index
to generate unique "vertex" indices - populate the dictionary when adding variables:
Model.add_variables
- change the
Model.idx
method to use the query the dictionnary instead - change the
Model.write_graph
method accordingly - add the unit test presented above to infrared.py. It can be run with
python3 -m pytest src/infrared/infrared.py
. - Note: if the user only uses variables with the same name, then the "vertex" indices will correspond with other indices since
Model.next_variable_index
starts from 0. This is important since the user may provide variables to functions/constraints without wrapping them withModel.idx
.
What I did to ensure that the modifications don't break anything
- I read the CPP part, and it only deals with vertex indices, no tuple of the form
(variable_name: str, idx: int)
or call toModel._domains
or equivalent is used. - The constraint network passed to the CPP part of the code is built from
Model.bindependencies
that is built fromModel.dependencies
that is built from the vertex indices inside the functions/constraints - I added an integration test in
Test/integration/proper_coloring.py
that attempts to colors random graphs, it can be run withpython3 -m pytest Test/integration/proper_coloring.py
. I don't know how to run the CPP tests, but believe they are independant of my changes.
More generally
Add a bash script to run tests ?
Edited by Samuel Gardelle