Mentions légales du service

Skip to content

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 just idx: 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
  • 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 (although collection.OrderedDict provides an alternative)
    • Issue 2: adding variables with a name already present would "shift" all the variables indices

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 with Model.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 to Model._domains or equivalent is used.
  • The constraint network passed to the CPP part of the code is built from Model.bindependencies that is built from Model.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 with python3 -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