coin-or / CyLP

A Python interface to CLP, CBC, and CGL to solve LPs and MIPs.
Other
183 stars 69 forks source link

addVariable isInt not working? #94

Closed NOD507 closed 4 years ago

NOD507 commented 4 years ago

Hi, im trying to setup a model with CyLP, trying to test perfomance of another model from python-mip to see if it creates the model faster on CyLP.

Im starting with a simple knapsack example, even thought im setting the x variable as int, its returning floats.

Am i doing something wrong? I even tried in another machine with ubuntu (im on windows) and got the same results.

I would appreciate any help with this.

Heres the code:

import numpy as np
from cylp.cy import CyClpSimplex
from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray

s = CyClpSimplex()

p = CyLPArray([10, 13, 18, 31, 7, 15])
w = CyLPArray([11, 15, 20, 35, 10, 33])
c = 47

x = s.addVariable('x', len(w), isInt=True)
#s.setInteger(x)

s += 0 <= x <= 1 # x should be binary

s += w * x <= c

s.objective = p * x

s.optimizationDirection = 'max'
s.primal()

s.primalVariableSolution['x']

This is returning: array([1. , 0. , 1. , 0.45714286, 0. , 0. ])

It should be [1, 0, 0, 1, 0, 0]

tkralphs commented 4 years ago

The method you are using is part of the Clp interface and thus solves the problem as an LP regardless of the integrality status of the variables. To solve as an MILP, you need to use the Cbc interface.

cbc = s.getCbcModel()
cbc.solve()

See documentation here.

NOD507 commented 4 years ago

Thank you, that makes sense.

I tried making the change but it now returns: array([1., 1., 1., 0., 0., 0.])

import numpy as np
from cylp.cy import CyCbcModel, CyClpSimplex
from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray

model = CyLPModel()

p = CyLPArray([10, 13, 18, 31, 7, 15])
w = CyLPArray([11, 15, 20, 35, 10, 33])
c = 47

x = model.addVariable('x', len(w), isInt=True)

model += 0 <= x <= 1 # x should be binary

model += w * x <= c

model.objective = p * x

s = CyClpSimplex(model)

s.optimizationDirection = 'max'
#s.primal()

cbc = s.getCbcModel()

cbc.solve()

cbc.primalVariableSolution['x']

I also tried the example from the docs but it returns false instead of true. (just with a little change since it was not running without y == 0)

import numpy as np
from cylp.cy import CyCbcModel, CyClpSimplex
from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray
model = CyLPModel()

x = model.addVariable('x', 3, isInt=True)
y = model.addVariable('y', 2)

A = np.matrix([[1., 2., 0],[1., 0, 1.]])
B = np.matrix([[1., 0, 0], [0, 0, 1.]])
D = np.matrix([[1., 2.],[0, 1]])
a = CyLPArray([5, 2.5])
b = CyLPArray([4.2, 3])
x_u= CyLPArray([2., 3.5])

model += A*x <= a
model += 2 <= B * x + D * y <= b
model += y == 0
model += 1.1 <= x[1:3] <= x_u

c = CyLPArray([1., -2., 3.])
model.objective = c * x + 2 * y.sum()

s = CyClpSimplex(model)

cbcModel = s.getCbcModel()

cbcModel.branchAndBound
sol_x = cbcModel.primalVariableSolution['x']

(abs(sol_x - np.array([0, 2, 2])) <= 10**-6).all()
tkralphs commented 4 years ago

Yeah, you shouldn't use branchAndBound(), as I also just realized that it doesn't seem to work anymore. I didn't bother to figure out exactly why, since it's performance would be worse than the solve() method and users are not really supposed to directly call that method in the C++ interface anyway. It used to work, but something changed. Actually, it still gives the correct solution, but the return status is set incorrectly.

Anyway, I just removed the branchAndBound() method altogether, released a new version, and updated the documentation.

It looks to me like the optimum for your example is what you reported, is it not? I wrote the LP file out and solved it directly in Cbc and got the same result. If it's incorrect, it's a problem with Cbc, but it looks OK to me. Am I missing something?

NOD507 commented 4 years ago

Yeah thank you, the solution its actually a tie with the one i was expecting [1, 0, 0, 1, 0, 0]. Now i can continue testing with the bigger problem.

Greetings

tkralphs commented 4 years ago

Great, thanks!