piecewise.py#

#!/usr/bin/env python3.11

# Copyright 2024, Gurobi Optimization, LLC

# This example considers the following separable, convex problem:
#
#   minimize    f(x) - y + g(z)
#   subject to  x + 2 y + 3 z <= 4
#               x +   y       >= 1
#               x,    y,    z <= 1
#
# where f(u) = exp(-u) and g(u) = 2 u^2 - 4 u, for all real u. It
# formulates and solves a simpler LP model by approximating f and
# g with piecewise-linear functions. Then it transforms the model
# into a MIP by negating the approximation for f, which corresponds
# to a non-convex piecewise-linear function, and solves it again.

import gurobipy as gp
from math import exp


def f(u):
    return exp(-u)


def g(u):
    return 2 * u * u - 4 * u


try:
    # Create a new model

    m = gp.Model()

    # Create variables

    lb = 0.0
    ub = 1.0

    x = m.addVar(lb, ub, name="x")
    y = m.addVar(lb, ub, name="y")
    z = m.addVar(lb, ub, name="z")

    # Set objective for y

    m.setObjective(-y)

    # Add piecewise-linear objective functions for x and z

    npts = 101
    ptu = []
    ptf = []
    ptg = []

    for i in range(npts):
        ptu.append(lb + (ub - lb) * i / (npts - 1))
        ptf.append(f(ptu[i]))
        ptg.append(g(ptu[i]))

    m.setPWLObj(x, ptu, ptf)
    m.setPWLObj(z, ptu, ptg)

    # Add constraint: x + 2 y + 3 z <= 4

    m.addConstr(x + 2 * y + 3 * z <= 4, "c0")

    # Add constraint: x + y >= 1

    m.addConstr(x + y >= 1, "c1")

    # Optimize model as an LP

    m.optimize()

    print(f"IsMIP: {m.IsMIP}")
    for v in m.getVars():
        print(f"{v.VarName} {v.X:g}")
    print(f"Obj: {m.ObjVal:g}")
    print("")

    # Negate piecewise-linear objective function for x

    for i in range(npts):
        ptf[i] = -ptf[i]

    m.setPWLObj(x, ptu, ptf)

    # Optimize model as a MIP

    m.optimize()

    print(f"IsMIP: {m.IsMIP}")
    for v in m.getVars():
        print(f"{v.VarName} {v.X:g}")
    print(f"Obj: {m.ObjVal:g}")

except gp.GurobiError as e:
    print(f"Error code {e.errno}: {e}")

except AttributeError:
    print("Encountered an attribute error")