Search code examples
pythonsolveror-toolscp-sat

Setting different values with a gap for intvars using a CP-SAT solver


I am using a CP-SAT solver for optimization purposes using Python.

I have a certain amount of IntVars with their names representing events. I would like to have a minimum delay between each var without any particular order in the events. I have tried many things, but the closest I've come to a solution is using boolvars like this (I've tried with abs() but it seems the library does not accept it) :

dictio_bool[k] = model.NewBoolVar('') #dictio_bool is a dictionary to stock boolvars
dictio_bool[k + 1] = model.NewBoolVar('')

model.Add(date[event1] > delay + date[event2]).OnlyEnforceIf(dictio_bool[k]) #date is a dictionary to stock intvars

model.Add(date[event1] < delay + date[event2]).OnlyEnforceIf(dictio_bool[k + 1])

model.AddBoolXOr([dictio_bool[k], dictio_bool[k + 1]])

However, when I use this, the code always decide to put the first bool at False and the second one at True. I have many others constraints that work. I might be a bit confused sorry, but do you know how to make the code choose the status of the bool depending on other constraints and not always 0 then 1.

To be more precise, How to set different values for some intvars with a minimum amount between them and no particular order ?


Solution

  • for abs, you need to write ( I use the CP-SAT 9.9 python API)

    model.add_abs_equality(target_expr, expr)
    

    when all expressions are of the form a * var + b (a, b integers). So x, x - 5, 3 * x are all valid.

    Furthermore, to write a disjunction, just use a single Boolean variable.

    model.add(x < y + delay).only_enforce_if(b)
    model.add(y < x + delay).only_enforce_if(~b)
    

    using bool_xor will force all literals to be alternating (true, false, true, false...) or (false, true, false, true, ...)

    There is another model using scheduling.

      x = [ my integer variables ]
      intervals = [model.new_fixed_size_interval_var(local_x, delay, '') for local_x in x]
      model.add_no_overlap(intervals)