Expression for the capacity of a cumulative constraint seems to trigger safening, which doesn't allow for the "None" argument in the constraint.
Minimal example:
import cpmpy as cp
def original_model():
p = cp.boolvar(name='p')
start_array_0 = cp.intvar(0, 10, name='start_array_0')
start_array_1 = cp.intvar(0, 10, name='start_array_1')
start_array_2 = cp.intvar(0, 10, name='start_array_2')
constraints = [
(p).implies((p > cp.Cumulative([start_array_0, start_array_1, start_array_2], [1, 4, 3], None, [4, 5, 7], 10))),
]
return cp.Model(constraints)
def model():
p = cp.boolvar(name='p')
start_array_0 = cp.intvar(0, 10, name='start_array_0')
start_array_1 = cp.intvar(0, 10, name='start_array_1')
start_array_2 = cp.intvar(0, 10, name='start_array_2')
_IV0 = cp.intvar(0, 0, name='_IV0')
constraints = [
(p).implies((p > cp.Cumulative([start_array_0, start_array_1, start_array_2], [1, 4, 3], None, [4, 5, 7], cp.sum([10, (-_IV0)])))),
]
return cp.Model(constraints)
if __name__ == '__main__':
model().solve()
original_model().solve()
Traceback (most recent call last):
File "/home/thomserg/Documents/programming/fuzz-tester/bug.py", line 29, in <module>
model().solve()
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/model.py", line 194, in solve
s = SolverLookup.get(solver, self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/solvers/utils.py", line 148, in get
return solver_cls(model, subsolver=subname, **init_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/solvers/ortools.py", line 140, in __init__
super().__init__(name="ortools", cpm_model=cpm_model)
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/solvers/solver_interface.py", line 95, in __init__
self += cpm_model.constraints
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/solvers/ortools.py", line 455, in add
for con in self.transform(cpm_expr):
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/solvers/ortools.py", line 420, in transform
cpm_cons = no_partial_functions(cpm_cons, safen_toplevel=frozenset({"div", "mod"})) # before decompose, assumes total decomposition for partial functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/transformations/safening.py", line 109, in no_partial_functions
new_args = no_partial_functions(args, _toplevel, _nbc, safen_toplevel=safen_toplevel)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/transformations/safening.py", line 109, in no_partial_functions
new_args = no_partial_functions(args, _toplevel, _nbc, safen_toplevel=safen_toplevel)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/transformations/safening.py", line 109, in no_partial_functions
new_args = no_partial_functions(args, _toplevel, _nbc, safen_toplevel=safen_toplevel)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/thomserg/Documents/programming/fuzz-tester/libraries/cpmpy/cpmpy/transformations/safening.py", line 99, in no_partial_functions
assert isinstance(cpm_expr, Expression), f"each `cpm_expr` should be an Expression at this point, not {type(cpm_expr)} {lst_of_expr}"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: each `cpm_expr` should be an Expression at this point, not <class 'NoneType'>
Expression for the capacity of a cumulative constraint seems to trigger safening, which doesn't allow for the "None" argument in the constraint.
Minimal example: