4

I'm thinking if I can use GEKKO for the following problem. Please feel free to share your comments. Thank you in advance.

Given that I'd like to approximate some nonlinear functions by piece-wise linear(PWL) segments. For instance, I'd like to use N PWL segments to approximate the function of Gaussian. Is it possible to leverage GEKKO for the problem? What available examples do you suggest studying?

Thank you

NS Huang
  • 91
  • 3

2 Answers2

2

The link that Junho sent is good if you have discontinuous functions that are linear or nonlinear with switching conditions. If you have data then there is a PWL function in Gekko that you can use without binary or MPCC switching conditions. Below is a simple PWL example in Python. Instead of the data points I included, you can use PWL segments to approximate the Gaussian function.

PWL approximation

import matplotlib.pyplot as plt
from gekko import GEKKO
import numpy as np
m = GEKKO(remote=False)
m.options.SOLVER = 1
x = m.FV(value = 4.5)
y = m.Var()
xp = np.array([1, 2, 3, 3.5,   4, 5])
yp = np.array([1, 0, 2, 2.5, 2.8, 3])
m.pwl(x,y,xp,yp)
m.solve()
plt.plot(xp,yp,'rx-',label='PWL function')
plt.plot(x,y,'bo',label='Data')
plt.show()

If there is a data set with many points, sometimes it is desirable to fit just a few points with a PWL segments. This is another example that shows how to fit a PWL approximation. In this case you can't use the PWL object in Gekko.

PWL fit

from scipy import optimize
import matplotlib.pyplot as plt
from gekko import GEKKO
import numpy as np

m = GEKKO()
m.options.SOLVER = 3
m.options.IMODE = 2

xzd = np.linspace(1,5,100)
yzd = np.sin(xzd)

xz = m.Param(value=xzd)
yz = m.CV(value=yzd)
yz.FSTATUS = 1

xp_val = np.array([1, 2, 3, 3.5,   4, 5])
yp_val = np.array([1, 0, 2, 2.5, 2.8, 3])
xp = [m.FV(value=xp_val[i],lb=xp_val[0],ub=xp_val[-1]) for i in range(6)]
yp = [m.FV(value=yp_val[i]) for i in range(6)]
for i in range(6):
    xp[i].STATUS = 0
    yp[i].STATUS = 1
for i in range(5):
    m.Equation(xp[i+1]>=xp[i]+0.05)

x = [m.Var(lb=xp[i],ub=xp[i+1]) for i in range(5)]
x[0].lower = -1e20
x[-1].upper = 1e20

# Variables
slk_u = [m.Var(value=1,lb=0) for i in range(4)]
slk_l = [m.Var(value=1,lb=0) for i in range(4)]

# Intermediates
slope = []
for i in range(5):
    slope.append(m.Intermediate((yp[i+1]-yp[i]) / (xp[i+1]-xp[i])))

y = []
for i in range(5):
    y.append(m.Intermediate((x[i]-xp[i])*slope[i]))

for i in range(4):
    m.Obj(1000*(slk_u[i] + slk_l[i]))

m.Equation(xz == x[0]   + slk_u[0])
for i in range(3):
    m.Equation(xz == x[i+1] + slk_u[i+1] - slk_l[i])
m.Equation(xz == x[4] - slk_l[3])

m.Equation(yz == yp[0] + y[0] + y[1] + y[2] + y[3] + y[4])

m.solve()
#y_val = yz.value
#print(y_val)

import matplotlib.pyplot as plt
plt.plot(xp,yp,'rx-',label='PWL function')
plt.plot(xzd,yzd,'b.',label='Data')
plt.show()
John Hedengren
  • 12,068
  • 1
  • 21
  • 25
1

Please check out the link below for examples of PWL using binary decision variables.

Logical conditions in Optimization

Junho Park
  • 997
  • 4
  • 12