Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# gc_pwl_func.py

    #!/usr/bin/env python3

    # Copyright 2025, Gurobi Optimization, LLC

    # This example considers the following nonconvex nonlinear problem
    #
    #  maximize    2 x    + y
    #  subject to  exp(x) + 4 sqrt(y) <= 9
    #              x, y >= 0
    #
    #  We show you two approaches to solve this:
    #
    #  1) Use a piecewise-linear approach to handle general function
    #     constraints (such as exp and sqrt).
    #     a) Add two variables
    #        u = exp(x)
    #        v = sqrt(y)
    #     b) Compute points (x, u) of u = exp(x) for some step length (e.g., x
    #        = 0, 1e-3, 2e-3, ..., xmax) and points (y, v) of v = sqrt(y) for
    #        some step length (e.g., y = 0, 1e-3, 2e-3, ..., ymax). We need to
    #        compute xmax and ymax (which is easy for this example, but this
    #        does not hold in general).
    #     c) Use the points to add two general constraints of type
    #        piecewise-linear.
    #
    #  2) Use the Gurobis built-in general function constraints directly (EXP
    #     and POW). Here, we do not need to compute the points and the maximal
    #     possible values, which will be done internally by Gurobi.  In this
    #     approach, we show how to "zoom in" on the optimal solution and
    #     tighten tolerances to improve the solution quality.
    #

    import math
    import gurobipy as gp
    from gurobipy import GRB

    def printsol(m, x, y, u, v):
        print(f"x = {x.X}, u = {u.X}")
        print(f"y = {y.X}, v = {v.X}")
        print(f"Obj = {m.ObjVal}")

        # Calculate violation of exp(x) + 4 sqrt(y) <= 9
        vio = math.exp(x.X) + 4 * math.sqrt(y.X) - 9
        if vio < 0:
            vio = 0
        print(f"Vio = {vio}")

    try:
        # Create a new model
        m = gp.Model()

        # Create variables
        x = m.addVar(name="x")
        y = m.addVar(name="y")
        u = m.addVar(name="u")
        v = m.addVar(name="v")

        # Set objective
        m.setObjective(2 * x + y, GRB.MAXIMIZE)

        # Add constraints
        lc = m.addConstr(u + 4 * v <= 9)

        # Approach 1) PWL constraint approach

        xpts = []
        ypts = []
        upts = []
        vpts = []

        intv = 1e-3

        xmax = math.log(9)
        t = 0.0
        while t < xmax + intv:
            xpts.append(t)
            upts.append(math.exp(t))
            t += intv

        ymax = (9.0 / 4) * (9.0 / 4)
        t = 0.0
        while t < ymax + intv:
            ypts.append(t)
            vpts.append(math.sqrt(t))
            t += intv

        gc1 = m.addGenConstrPWL(x, u, xpts, upts, "gc1")
        gc2 = m.addGenConstrPWL(y, v, ypts, vpts, "gc2")

        # Optimize the model
        m.optimize()

        printsol(m, x, y, u, v)

        # Approach 2) General function constraint approach with auto PWL
        #             translation by Gurobi

        # restore unsolved state and get rid of PWL constraints
        m.reset()
        m.remove(gc1)
        m.remove(gc2)
        m.update()

        # u = exp(x)
        gcf1 = m.addGenConstrExp(x, u, name="gcf1")
        # v = y^(0.5)
        gcf2 = m.addGenConstrPow(y, v, 0.5, name="gcf2")

        # Use the equal piece length approach with the length = 1e-3
        m.Params.FuncPieces = 1
        m.Params.FuncPieceLength = 1e-3

        # Optimize the model
        m.optimize()

        printsol(m, x, y, u, v)

        # Zoom in, use optimal solution to reduce the ranges and use a smaller
        # pclen=1-5 to solve it

        x.LB = max(x.LB, x.X - 0.01)
        x.UB = min(x.UB, x.X + 0.01)
        y.LB = max(y.LB, y.X - 0.01)
        y.UB = min(y.UB, y.X + 0.01)
        m.update()
        m.reset()

        m.Params.FuncPieceLength = 1e-5

        # Optimize the model
        m.optimize()

        printsol(m, x, y, u, v)

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

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

Help and Feedback

Press `/` or click to search this documentation | Gurobi website | Gurobi community forum
Go to other Gurobi documentation | Gurobi download | Contact support