Gekko, pass dynamic parameter to pwl

Viewed 74

This example code demonstrates my problem perfectly

from gekko import GEKKO
model = GEKKO(remote=False)
x = model.Array(model.Var,(10),lb=0, ub=2,value=0)

b = model.Array(model.Var,(3))
p = []
p.append(model.Param(sum(x)/10+0.25))
p.append(model.Param(sum(x)/10))
d = 1e-5
x_data = [-1e5,0.25,0.25+d,1,1+d,1.5,1.5+d,1e5]
y_data = [0.1,0.1,0.75,0.75,1.25,1.25,1.7,1.7]
model.pwl(p[0], b[0], x_data, y_data)
model.pwl(p[1], b[1], x_data, y_data)
model.pwl(x[0], b[2], x_data, y_data)

model.options.IMODE = 2
model.options.SOLVER = 1
model.Obj(-1*(b[0]+b[1]))
model.solve()
print(x)
print(p)
print(b)

This has a successful solution with an objective of 7.6 (not even sure where that comes from), but all x values are set to 0 except x[1] which is 1, which would mean that p[0] is 0.35 while p[1] is 0.1. This is not the case as both are equal to zero. b[0] and b[1] are equal to 1.7 which shouldn't be the case even if p[0] and p[1] were correct. b[2] is correctly set to 0.75.

1 Answers

When p[0] and p[1] are parameters, the values are specified at initialization and are not updated with new values of x. To update them with values of x, you can specify them as variables m.Var() and add a couple equations.

from gekko import GEKKO
model = GEKKO(remote=False)
x = model.Array(model.Var,10,lb=0, ub=2,value=0)

b = model.Array(model.Var,3)
p = model.Array(model.Var,2)
model.Equation(p[0]==model.sum(x)/10+0.25)
model.Equation(p[1]==model.sum(x)/10)
d = 1e-5
x_data = [-1e5,0.25,0.25+d,1,1+d,1.5,1.5+d,1e5]
y_data = [0.1,0.1,0.75,0.75,1.25,1.25,1.7,1.7]
model.pwl(p[0], b[0], x_data, y_data)
model.pwl(p[1], b[1], x_data, y_data)
model.pwl(x[0], b[2], x_data, y_data)

model.options.IMODE = 3
model.options.SOLVER = 1
model.Maximize(b[0]+b[1])
model.solve()
print('x:' + str(x))
print('p:' + str(p))
print('b:' + str(b))

I also switched to model.Maximize() instead of model.Obj(-1*()) and replaced the Python sum with the gekko model.sum() that is more efficient, especially for large-scale problems. You can also run in IMODE=3 because you only have one instance of your model that is solved. IMODE=2 is for data regression problems where you have multiple data points and the same model applied to each of them. The updated problem gives the solution:

x:[[1.0] [0.54918319668] [0.54918319668] [0.54918319668] [0.54918319668]
 [0.54918319668] [0.54918319668] [0.54918319668] [0.65581762324] [2.0]]
p:[[1.00001] [0.75001]]
b:[[1.7] [1.7] [0.75]]

There may be some contribution to the objective function from the PWL slack variables. I recommend that you don't use the solver objective but instead re-calculate the objective after the solution is reported. Detailed on the PWL function are given in the documentation.

Related