'ORTools CP-SAT Solver. Constraint to require two lists of variables to be drawn from the same set of integers

I have two lists of variables M and T. I would like to create a constraint where the set of unique values between M and T are identical.

From the solution variables I would like:

set(T) == set(M) -> True

So far, I have tried creating a matrix of the differences between each element of M and T

diffs = M[:, None] - T

Then building a constraint that the product of each element in individual row and every individual column of diffs is 0. This should ensure that each element of M has an element in T that it is equal to and vice versa.

for m in range(num_groups):
    model.AddMultiplicationEquality(0, diffs[m, :])
for t in range(num_groups):
    model.AddMultiplicationEquality(0, diffs[:, t])

Upon solving this model with no objective or other constraints I receive an invalid status. I am new to ORTools.

Full Program

ortools==9.3.10497

from ortools.sat.python import cp_model
import numpy as np

model = cp_model.CpModel()
num_groups = 4
STATUS  = ['UNKNOWN', 'MODEL_INVALID', 'FEASIBLE', 'INFEASIBLE', 'OPTIMAL']
M = []
for m in range(num_groups):
    M.append(model.NewIntVar(lb=0, ub=num_groups, name=f'M_{m}'))
T = []
for t in range(num_groups):
    T.append(model.NewIntVar(lb=0, ub=num_groups, name=f'T_{t}'))
M = np.array(M)
T = np.array(T)


diffs = M[:, None] - T
for m in range(num_groups):
    model.AddMultiplicationEquality(0, diffs[m, :])
for tt in range(num_groups):
    model.AddMultiplicationEquality(0, diffs[:, tt])

solver = cp_model.CpSolver()
status = solver.Solve(model)
print(STATUS[status])


Solution 1:[1]

This is catastrophic. Multiplications are very slow.

just create one Boolean variable per value, one Boolean variable per value and per variable.

Now, you want to link everything together.

for a variable x in either set and a value v:

    assign = {}
    assign[x, v] = model.NewBoolVar(f'assign_{x}_{v}')
    model.Add(x == v).OnlyEnforceIf(assign[x, v])
    model.Add(x != v).OnlyEnforceIf(assign[x, v].Not())

for a value v:

    appears = {}
    appears[v] = model.NewBoolVar(f'appears_{v}')

    # If v does not appear, no variable can be assigned its value.
    for x in T U M:
        model.AddImplication(appears[v].Not(), assign[x, v].Not())

    # If v appears, at least one variable in both T and M must be assigned to v.
    model.AddBoolOr(assign[x, v] for x in T).OnlyEnforceIf(appears[v])
    model.AddBoolOr(assign[x, v] for x in M).OnlyEnforceIf(appears[v])

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1