1

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?

sascha
  • 32,238
  • 6
  • 68
  • 110
  • This is common. These solvers are *heuristic-driven*: sometimes it works, sometimes it does not. Performance variability is a huge topic for NP-hard problems and heuristic-driven solving. There are many source, see [Performance variability in mixed integer programming](https://coral.ise.lehigh.edu/mip-2008/talks/danna.pdf), but in your case this might be the most obvious: optimization-landscape -> some instances are harder than others (given a heuristic-driven solver). You cannot do much except for stronger formulations (might be very costly) or switching to more robust (commercial) solvers. – sascha Apr 10 '21 at 12:53
  • You should use `cp.sum` instead of sum – linello May 07 '21 at 07:03

0 Answers0