Toby
Toby

Reputation: 2294

Check if assigned elements satisfy a condition in OR-Tools

I have say 100 elements that I want to assign to say 10 spots.

# the elements list holds 100 variables that signify the assignment to a spot
elements = [model.NewIntVar(1, 10) for i in range(100)]

Each of my element has a specific size. Now I want to model one (set of) constraint(s) per spot that says: The added sizes of all elements assigned to this spot lies in a fixed range.

So if spot 1 gets elements 1, 16 and 64 assigned, and their sizes are 1521, 1732, 1431 and my range is (3000, 6000) that would be ok. But if too many or too large elements (or too few/small) get assigned to spot 1, that would not be ok.

Something like the following, which does not work:

for spot in range(10):
    sum_ = sum([get_size(e) for e in elements if e == spot]) # if think if e == spot is what fails
    model.Add(sum_ >= 3000)
    model.Add(sum_ <= 6000)

How can I model such a thing? I have looked at channeling constraints but I can't quite wrap my head around it.

Upvotes: 0

Views: 1162

Answers (1)

Stradivari
Stradivari

Reputation: 2766

I think it is better to model the assignment as a boolean:

from ortools.sat.python import cp_model

model = cp_model.CpModel()
solver = cp_model.CpSolver()

all_spots = range(10)
all_elems = range(100)
elements = {
    (elem, spot): model.NewBoolVar(f"{elem} in spot {spot}")
    for elem in all_elems
    for spot in all_spots
}

# only one spot for element
for elem in all_elems:
    model.Add(sum(elements[elem, spot] for spot in all_spots) == 1)

for spot in all_spots:
    # taking the element id as its size
    sum_ = sum(elements[elem, spot] * elem for elem in all_elems)
    model.Add(sum_ >= 0)
    model.Add(sum_ <= 500)

solver.Solve(model)

for (elem, spot), boolean in elements.items():
    if solver.Value(boolean):
        print(boolean)

See:

Upvotes: 3

Related Questions