Quantcast
Channel: Yet Another Math Programming Consultant
Viewing all articles
Browse latest Browse all 809

2d bin packing with Google OR-Tools CP-SAT, how to fix?

$
0
0

In [1] I looked at some MIP formulations for a 2d bin packing problem. OR-Tools has a nice model.AddNoOverlap2D constraint function. So, I was excited to try this out. (In these times I get quickly enthusiastic about these things). OK, so I started coding:


from ortools.sat.python import cp_model

#---------------------------------------------------
# data
#---------------------------------------------------

data = {'bin':{'h':60,'w':40},
'cat1':{'w': 7,'h':12,'items':10},
'cat2':{'w': 9,'h': 3,'items':10},
'cat3':{'w': 5,'h':14,'items':10},
'cat4':{'w':13,'h': 9,'items':10},
'cat5':{'w': 6,'h': 8,'items': 5},
'cat6':{'w':20,'h': 5,'items': 5}}

#
# extract data for easier access
#

# bin width and height
H = data['bin']['h']
W = data['bin']['w']

# h,w,cat for each item
h = [data[cat]['h'] for cat in data if cat!='bin'for i in range(data[cat]['items'])]
w = [data[cat]['w'] for cat in data if cat!='bin'for i in range(data[cat]['items'])]
cat = [cat for cat in data if cat!='bin'for i in range(data[cat]['items'])]
n = len(h) # number of items
m = 10# number of bins

#---------------------------------------------------
# or-tools model
#---------------------------------------------------


model = cp_model.CpModel()

#
# variables
#

# x1,x2 and y1,y2 are start and end
x1 = [model.NewIntVar(0,W-w[i],'x1{}'.format(i)) for i in range(n)]
x2 = [model.NewIntVar(w[i],W,'x2{}'.format(i)) for i in range(n)]

y1 = [model.NewIntVar(0,H-h[i],'y1{}'.format(i)) for i in range(n)]
y2 = [model.NewIntVar(h[i],H,'y2{}'.format(i)) for i in range(n)]

# interval variables
xival = [model.NewIntervalVar(x1[i],w[i],x2[i],'xival{}'.format(i)) for i in range(n)]
yival = [model.NewIntervalVar(y1[i],w[i],y2[i],'yival{}'.format(i)) for i in range(n)]

# bin numbers
b = [model.NewIntVar(0,m,'b{}'.format(i)) for i in range(n)]

# b2[(i,j)] = true if b[i]=b[j] for i<j
b2 = {(i,j):model.NewBoolVar('b2{}.{}'.format(i,j)) for j in range(n) for i in range(j)}

# used bins
u = [model.NewBoolVar('u{}'.format(k)) for k in range(m)]


#
# constraints
#

# no overlap for items in same bin
for j in range(n):
for i in range(j):
model.Add(b[i] != b[j]).OnlyEnforceIf(b2[(i,j)].Not())
model.AddNoOverlap2D([xival[i],xival[j]],[yival[i],yival[j]]).OnlyEnforceIf(b2[(i,j)])

# used bin
for i in range(n):
for k in range(m):
model.Add(b[i]<k).OnlyEnforceIf(u[k].Not())

# objective
model.Minimize(sum([u[k] for k in range(m)]))


#
# solve model
#
solver = cp_model.CpSolver()
rc = solver.Solve(model)
print(rc)
print(solver.StatusName())


Work in progress, so I expect to see problems. When I run this I see:

OK. That is not helpful. After a bit of trial and error, it looks like OnlyEnforceIf is not implemented for the AddNoOverlap2D constraints. Indeed, we can verify this with solver.parameters.log_search_progress = True [2].  At first, I did not see anything (I was running this in a Jupyter notebook on colab.google.com). Running it locally from the command line, I saw:

Enforcement literal not supported in constraint: enforcement_literal: 256 no_overlap_2d { x_intervals: 0 x_intervals: 1 y_intervals: 50 y_intervals: 51 }

This confirms this is not supported.

I am not sure how to fix this with a simple work-around. If desperate, I could try to use some of the MIP formulations we did earlier.


References




Viewing all articles
Browse latest Browse all 809

Trending Articles