Question: I've run into an issue where I can't get APOPT to optimize an unconstrained single piecewise linear, and it's really throwing me for a loop. I feel like there's something I'm not understanding about model.pwl, but it's hard (for me) to find documentation outside of the GEKKO docs. Here's my minimal example: model = GEKKO(remote=False) model.options.SOLVER = 1 model.solver_options = ["minlp_as_nlp 0"] x = model.sos1([0, 1, 2, 3, 4]) # This can also be model.Var(lb=0, ub=4), same result. pwl = model.Var() model.pwl(x, pwl, [0, 1, 2, 3, 4], [30, 30.1, 30.2, 30.3, 30.4], bound_x=True) model.Minimize(pwl) model.solve(display=True) print(x.value) print(pwl.value) print(model.options.objfcnval)  The output that I get is:  ---------------------------------------------------------------- APMonitor, Version 1.0.3 APMonitor Optimization Suite ---------------------------------------------------------------- --------- APM Model Size ------------ Each time step contains Objects : 1 Constants : 0 Variables : 2 Intermediates: 0 Connections : 2 Equations : 1 Residuals : 1 Piece-wise linear model pwl1points: 5 Number of state variables: 12 Number of total equations: - 5 Number of slack variables: - 0 --------------------------------------- Degrees of freedom : 7 ---------------------------------------------- Steady State Optimization with APOPT Solver ---------------------------------------------- Iter Objective Convergence 0 3.39503E+01 3.01000E+01 1 3.22900E+01 1.00000E-10 2 3.22000E+01 2.22045E-16 4 3.22000E+01 0.00000E+00 Successful solution --------------------------------------------------- Solver : APOPT (v1.0) Solution time : 3.819999999541324E-002 sec Objective : 32.2000000000000 Successful solution --------------------------------------------------- 2.0 30.2 32.2  This is unexpected to me, as the obvious minimal value is 30 for the pwl.

Answer: A cubic spline is much more reliable in optimization than a piecewise linear function because it doesn't rely on slack variables and switching conditions. from gekko import GEKKO model = GEKKO(remote=False) model.options.SOLVER = 1 x = model.Var(lb=0, ub=4, integer=True) y = model.Var() model.cspline(x, y, [0, 1, 2, 3, 4], [30, 30.1, 30.2, 30.3, 30.4], bound_x=True) model.Minimize(y) model.solve(display=True) print(x.value) print(y.value) print(model.options.objfcnval)  Here is the output:  ---------------------------------------------------------------- APMonitor, Version 1.0.3 APMonitor Optimization Suite ---------------------------------------------------------------- --------- APM Model Size ------------ Each time step contains Objects : 1 Constants : 0 Variables : 2 Intermediates: 0 Connections : 2 Equations : 1 Residuals : 1 Number of state variables: 2 Number of total equations: - 1 Number of slack variables: - 0 --------------------------------------- Degrees of freedom : 1 ---------------------------------------------- Steady State Optimization with APOPT Solver ---------------------------------------------- Iter: 1 I: 0 Tm: 0.00 NLPi: 2 Dpth: 0 Lvs: 0 Obj: 3.00E+01 Gap: 0.00E+00 Successful solution --------------------------------------------------- Solver : APOPT (v1.0) Solution time : 1.970000000437722E-002 sec Objective : 30.0000000000000 Successful solution --------------------------------------------------- [0.0] [30.0] 30.0  A few other notes:  Use m.Var(integer=True) instead of m.sos1() when potential values are integers. The m.sos1() function is for discrete non-integer values. There is more information on the PWL function in the APMonitor documentation. Gekko is an interface to the APMonitor Modeling Language and writes gk0_model.apm as a text file in the run directory m._path (or open tmp folder with m.open_folder()).