coin-or / python-mip

Python-MIP: collection of Python tools for the modeling and solution of Mixed-Integer Linear programs
Eclipse Public License 2.0
518 stars 92 forks source link

Constraint creation with 0 coefficient, taken from NumPy array, leads to boolean instead. #162

Closed rschwarz closed 2 years ago

rschwarz commented 3 years ago

Constraints are built with coefficients that are in a NumPy array (float64). A coefficient of 0.0 multiplied with with the left-hand side leads to the value True of type numpy.bool_, rather than a mip.LinExpr.

Consider this example:

import mip
import numpy

m = mip.Model()

x = m.add_var(name="x")
y = m.add_var(name="y")

coeffs = numpy.array([0.0])
lhs = x * coeffs[0]
rhs = y + 1.0
print("lhs: ", lhs, type(lhs))
print("rhs: ", rhs, type(rhs))

cons1 = lhs == rhs
cons2 = rhs == lhs
print("cons1: ", cons1, type(cons1))
print("cons2: ", cons2, type(cons2))

This results in

lhs:  0.0 <class 'numpy.float64'>
rhs:  + y + 1.0 <class 'mip.entities.LinExpr'>
cons1:  True <class 'numpy.bool_'>
cons2:  + y  = - 1.0 <class 'mip.entities.LinExpr'>

I would have expected that both cons1 and cons2 yield a LinExpr.

Note that the problem does not occur if:

The behavior is strange to me, since it's the case that isinstance(coeffs[0], float) gives True, so it should be handled the same way when the mip library compares agains numbers.Real.

So, is this a problem with __add__ in some numpy type?

rschwarz commented 3 years ago

Using Pdb and stepping into the constraint creation, it seems that LinExp.__eq__ is called after all, but for some reason, it still returns a numpy.bool_.

sebheger commented 2 years ago

@rschwarz With #244 your issue should be solved. I have updated some of the arithmetic to be fully commutative.

sebheger commented 2 years ago

Fixed with Release 1.14.0