I'm trying to use cvxpy to solve a knapsack problem with varying available quantities of items, and seeing it run much slower with some quantities than others.
(My objective here is to minimize wasted capacity, so values=weights.)
import cvxpy as cp
from cvxpy.atoms.affine.binary_operators import multiply as element_multiply
import time
weights = [1190, 1380, 715, 1372, 735, 1360, 775, 930, 1352, 870, 1225, 1185, 1180, 1100, 1220, 890, 840, 935, 1215, 1060,
1202, 1095, 1200, 1105, 1164, 1140, 900, 650, 1080, 725, 660, 1070, 905, 1044, 910, 1000, 977, 950, 750, 945,
920, 770, 940, 810, 795, 860, 855, 845, 836, 865, 625, 915, 680, 885, 880, 825, 850, 830, 730, 700, 790, 740,
675, 690, 655, 695, 1370, 1210, 720, 975, 745, 685, 1135, 1160, 1010, 1150, 1090, 1020, 635, 1015, 995, 765,
990, 665, 960, 800, 710, 895, 612, 645, 815, 844, 670, 640, 820, 780, 842]
limits1 = [2, 1, 2, 0, 1, 0, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 1, 5, 0, 1, 1, 0, 1, 0, 0, 0, 2, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 3, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 2, 3, 1, 3, 0, 2, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
limits2 = [2, 1, 2, 0, 1, 0, 3, 2, 0, 1, 0, 1, 1, 2, 1, 2, 2, 6, 0, 1, 1, 0, 1, 0, 0, 0, 2, 0, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 3, 1, 0, 1, 1, 0, 1, 0, 0, 2, 0, 2, 3, 1, 3, 0, 2, 1, 1, 0, 1, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
limits3 = [3, 1, 2, 0, 1, 0, 3, 2, 0, 1, 1, 1, 2, 2, 1, 2, 2, 7, 0, 1, 1, 0, 1, 0, 0, 0, 3, 0, 0, 2, 2, 1, 1, 1, 1, 0, 1, 1, 0, 1, 3, 1, 3, 3, 1, 0, 1, 1, 1, 1, 1, 0, 2, 0, 2, 3, 2, 3, 0, 2, 1, 1, 0, 1, 0, 2, 0, 0, 1, 0, 2, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
limits4 = [3, 2, 2, 0, 1, 1, 4, 3, 0, 1, 1, 1, 2, 2, 2, 3, 2, 8, 0, 1, 1, 0, 1, 0, 0, 0, 3, 0, 0, 2, 2, 1, 2, 1, 1, 0, 1, 1, 0, 1, 3, 1, 4, 4, 1, 0, 1, 1, 1, 1, 1, 0, 2, 0, 2, 4, 2, 4, 1, 3, 1, 1, 0, 1, 0, 2, 0, 0, 1, 0, 2, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
w = cp.Constant(weights)
x = cp.Variable(len(weights),integer=True)
v = cp.Parameter(shape=(len(weights),))
kstart = time.time()
prob = cp.Problem(cp.Maximize(sum(element_multiply(w,x))),[sum(element_multiply(w,x)) <= 8350,
x >= 0,
x <= v])
kend = time.time()
print("Setup time:", kend-kstart)
kstart = time.time()
v.value = limits1
prob.solve(solver = 'GLPK_MI',warm_start=True)
kend = time.time()
print("First set time:", kend-kstart)
kstart = time.time()
v.value = limits2
prob.solve(solver = 'GLPK_MI',warm_start=True)
kend = time.time()
print("Second set time:", kend-kstart)
kstart = time.time()
v.value = limits3
prob.solve(solver = 'GLPK_MI',warm_start=True)
kend = time.time()
print("Third set time:", kend-kstart)
kstart = time.time()
v.value = limits4
prob.solve(solver = 'GLPK_MI',warm_start=True)
kend = time.time()
print("Fourth set time:", kend-kstart)
Out:
Setup time: 0.00698089599609375
First set time: 0.06086540222167969
Second set time: 4.375271320343018
Third set time: 2.5631792545318604
Fourth set time: 0.003981351852416992
These are 4 iterations out of about 20 I'm running with increasing item limits. Most of the other iterations, like the first and fourth here, are < 0.1s. I've tried running each variation as a model with only the non-zero items available, and it gives me the same result.
I don't understand what's happening here. What can I do to get these ones in line?