linear-programminggurobimixed-integer-programming

Enforce a piecewise linear constraint when indicator variable is true in Gurobi


I want to trigger a piecewise linear (PWL) constraint in Gurobi when an indicator variable is true, else the PWL could be violated. Is there a way to achieve this ? I am facing some difficulties when using the addGenConstrIndicator function in Gurobi.


Solution

  • In Gurobi, I don't think that we can directly state b = 1 => y = f(x) where b is the indicator variable and f is any general constraint like piecewise linear constraint. But we can achieve the purpose by having another intermediate variable, say, z and the write the constraint as:

    b = 1 => z = y
    

    So you can use z in place of y (y becomes redundant now). Whenever b is true, z = y (PWL constraint enforced), else when b is false then constraint (z = y) could be violated.

    Example

    import gurobipy as gp
    from gurobipy import GRB
    
    model = gp.Model("")
    
    x = model.addVar(vtype = GRB.INTEGER, lb = 0, ub = 10)
    y = model.addVar(vtype = GRB.CONTINUOUS, lb = 0, ub = 100)
    
    z = model.addVar(vtype = GRB.CONTINUOUS, lb = 0, ub = 100)
    b = model.addVar(vtype = GRB.BINARY)
    
    model.addGenConstrPWL(x, y, [0, 1, 2, 3, 4, 5], [1.5, 0, 3, 5, 7, 2], "myPWLConstr")
    
    model.addGenConstrIndicator(b, 1, z == y)
    
    # artificially making the indicator variable true,
    # thus enforcing PWL constraint
    model.addConstr(b == 1)
    
    model.setObjective(z, sense = GRB.MAXIMIZE)
    
    model.optimize()
    
    print("x = " + str(x.X)) #4
    print("b = " + str(b.X)) #1
    print("z = " + str(z.X)) #7
    

    PWL constraint is enforced, and value of z = 7, which is maximum you can hit given the PWL constraint in place.

    However, if you make b = 0, then value of z (which we are maximising) goes upto 100, which is upper bound of z