Search code examples
pythonmixed-integer-programming

MIP Objective with xsum()


With mip I want to involve cardinality in the objective function. I don't understand why the following doesn't give a solution where all lists in x have precisely four binary variables set.

from mip import Model, xsum, maximize, BINARY

model = Model()

x = [[model.add_var(var_type=BINARY) for _ in range(6)] for _ in range(5)]

def f(x):
  return xsum([4 <= xsum(v) for v in x]) - xsum([4 < xsum(v) for v in x])                                                                    #2*x[0] + 3*x[1] - 4*x[2]

model.objective = maximize(f(x))

model.optimize()

for v in x:
  print([a.x for a in v])

Thanks for any hint!


Solution

  • I have expressed the problem in google ortool's linear solver.

    from ortools.linear_solver import pywraplp
    
    solver = pywraplp.Solver("penalty_obj",pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING)
    
    x = [[solver.BoolVar("") for _ in range(6)] for _ in range(5)]
    
    xsum = [solver.IntVar(lb = 0, ub = 6, name = "") for _ in range(len(x))]
    
    for i in range(len(xsum)):
        solver.Add(xsum[i] == sum(x[i]))
        
    grt_eq_4 = [solver.BoolVar("") for _ in range(len(xsum))]
    grt_4 = [solver.BoolVar("") for _ in range(len(xsum))]
    
    for i in range(len(grt_eq_4)):
        # if sum is >= 4 => grt_eq_4 == 1
        solver.Add(xsum[i] - (100 * grt_eq_4[i]) <= 4 - 1)
        
    for i in range(len(grt_4)):
        # if sum is > 4 (or sum >= 5) => grt_4 == 1
        solver.Add(xsum[i] - (100 * grt_4[i]) <= 5 - 1)
        
    solver.Maximize(sum(grt_eq_4) - sum(grt_4))
    solver.Solve()
    
    solver.Objective().Value()
    

    Objective function return 5 which is length of x