I want to solve an assignment problem: putting items in containers.
Each container must contain:
- a certain amount of items (
sizes
) - certain allowed items (
possibilities
) - at least one subset of items within a predefined subsets list (
obligations
)
So far, I can easily program the 2 first constraints with OR-tools, but I'm struggling with the third one.
Here is my attempt with toy data (12 items and 3 containers).
from ortools.sat.python import cp_modelclass SolutionPrinter(cp_model.CpSolverSolutionCallback): def __init__(self, x, containers, items): cp_model.CpSolverSolutionCallback.__init__(self) self.__x = x self.containers = containers self.items = items def on_solution_callback(self): print({container: [item for item in self.items if self.BooleanValue(self.__x[container, item])] for container in self.containers})# Amount of items per container (sums to the total amount of items)sizes = [5, 3, 4]# Which container the items can possibly belong to.possibilities = [[False, True, False], [True, False, False], [True, False, True], [True, True, True], [True, False, True], [True, False, False], [True, False, False], [True, True, False], [False, False, True], [False, True, True], [False, False, True], [True, True, True]]# The containers must contain one of these subsets.obligations = {0: [[1, 2, 3], # container 0 must contain at least the items (1, 2, 3) or the items (5, 6, 7). [5, 6, 7]], 1: [], # container 1 does not have such constraint 2: [[2, 3, 4], [8, 9], [9, 10, 11]]}num_containers = len(sizes)num_items = sum(sizes)model = cp_model.CpModel()# Variablesx = {}for container in range(num_containers): for item in range(num_items): x[container, item] = model.NewBoolVar(f"x[{container},{item}]") if possibilities[item][container] else False# Constraintsfor item in range(num_items): model.AddExactlyOne(x[container, item] for container in range(num_containers))for container in range(num_containers): model.Add(sum(x[container, item] for item in range(num_items)) == sizes[container])# TODO: 3rd constraintsolver = cp_model.CpSolver()solution_printer = SolutionPrinter(x, range(num_containers), range(num_items))solver.parameters.enumerate_all_solutions = Truestatus = solver.Solve(model, solution_printer)
Expected solutions:
{0: [1, 4, 5, 6, 7], 1: [0, 3, 11], 2: [2, 8, 9, 10]}{0: [1, 2, 5, 6, 7], 1: [0, 3, 11], 2: [4, 8, 9, 10]}{0: [1, 2, 3, 5, 6], 1: [0, 7, 11], 2: [4, 8, 9, 10]}
I need to generate all the possible solutions.
Filtering out solutions that do not respect the 3rd constraint afterwards is not an option.