3

I want to minimise a simple function where x1 is continuous and i1 is an integer.

The below example gives me a Can not multiply with type <class 'mip.entities.LinExpr'>

Is it really true that MIP cannot handle multiplications?

from mip import Model, CONTINUOUS, INTEGER, minimize, xsum
import numpy as np

m = Model()

def func(x1, i1):
  return (x1 - .5) * (i1 - 1)
print(func(0, 0))
print(func(.5, 1))

x1 = m.add_var(var_type=CONTINUOUS)
i1 = m.add_var(var_type=INTEGER)

# constraint
m += x1 + i1 >= 0

m.objective = func(x1, i1)
# m.objective = minimize(xsum((x1 - .5) * (i1 - 1)))

status = m.optimize()
print(status)
print(m.objective_value)

for v in m.vars:
  print(v.name, v.x)

Dirk Nachbar
  • 542
  • 4
  • 16
  • Multiplication of decision-variables is (in general) non-convex (= non-linear) and it's no surprise that mixed-integer "linear" programming can't handle it. You need to linearize it. The `continuous * integer` case is not the easiest, but also not the worst. MAybe start with this [blog](https://orinanobworld.blogspot.com/2013/07/integer-variables-and-quadratic-terms.html). – sascha Apr 30 '21 at 08:29

2 Answers2

0

You would need to use a different solver that can handle nonlinear expressions. You could use the academic solver PySCIPOpt or the commercial, free-for-academics solver Gurobi - both have a very good and intuitive Python interface that looks very similar to your code.

mattmilten
  • 6,242
  • 3
  • 35
  • 65
0

You can use Google-ortools CP-SAT solver. It has some constraints which can handle non-linear expression easily. you can easily install via pip install ortools . One drawback - it can natively handle only integer values. But we can circumvent this by scaling continuous values to integer, and then scaling them back before we report the solution. Please have a look at the below code listing

from ortools.sat.python import cp_model as cp

model = cp.CpModel()

scaling_factor = 100  # higher value for more numerical precision

i1 = model.NewIntVar(0, 100, "")
x1 = model.NewIntVar(0, 100 * scaling_factor, "")

model.Add(x1 + i1 >= 0)

# (x1 - .5)
dv_x1_part = model.NewIntVar(0, 100 * scaling_factor, "")
model.Add(dv_x1_part == x1 - int(0.5 * scaling_factor)) # scaling 0.5 also, since we are scaling x1

# (i1 - 1)
dv_i1_part = model.NewIntVar(0, 100, "")
model.Add(dv_i1_part == i1 - 1)

objective_function = model.NewIntVar(0, 10000000000, "")

# (x1 - .5) * (i1 - 1)
model.AddMultiplicationEquality(objective_function, [dv_x1_part, dv_i1_part])

model.Minimize(objective_function)

solver = cp.CpSolver()
solver.Solve(model) # 4 means optimal

objective_fun_value = solver.ObjectiveValue() / scaling_factor

# inspect decision variable values
x1_value = solver.Value(x1) / scaling_factor
i1_value = solver.Value(i1)