I'm trying to solve a non-linear optimization problem. I've duplicated my issue by creating the code below. Python returns TypeError: object of type 'int' has no len()
. How can I include an IF statement in my constraint functions?
Console prints the following:
File "<ipython-input-196-8d29d410dcea>", line 1, in <module>
runfile('C:/Users/***/Documents/***/Project/untitled.py', wdir='C:/Users/***/Documents/***/***/Project')
File "C:\Users\***\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 704, in runfile
execfile(filename, namespace)
File "C:\Users\***\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 108, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/***/Documents/***/***/Project/untitled.py", line 27, in <module>
m.Equation(Cx(x1,x2,x3,x4) < 0)
File "C:/Users/***/Documents/***/***/Project/untitled.py", line 17, in Cx
if K > 15:
File "C:\Users\***\Anaconda3\lib\site-packages\gekko\gk_operators.py", line 25, in __len__
return len(self.value)
File "C:\Users\***\Anaconda3\lib\site-packages\gekko\gk_operators.py", line 134, in __len__
return len(self.value)
TypeError: object of type 'int' has no len()
from gekko import GEKKO
m = GEKKO()
def Cr(x1,x2,x3,x4):
return (x1*x4*(x1+x2+x3)+x3**2)
def Cw(x1,x2,x3,x4):
return x1*x2*x3*x4
def Ck(x1,x2,x3,x4):
return x1*x2*x3*x4+1
def Cx(x1,x2,x3,x4):
K = Ck(x1,x2,x3,x4)
if K > 15: #Issue here
K = 15
return x1**2+x2**2+x3**2+x4**2 - K
x1 = m.Var(value=1,lb=-5000,ub=5000)
x2 = m.Var(value=1,lb=-5000,ub=5000)
x3 = m.Var(value=1,lb=-5000,ub=5000)
x4 = m.Var(value=1,lb=-5000,ub=5000)
m.Equation(Cw(x1,x2,x3,x4) >= 14)
m.Equation(Cx(x1,x2,x3,x4) < 0)
m.Obj(Cr(x1,x2,x3,x4))
m.solve(disp=False)
print(x1.value)
print(x2.value)
print(x3.value)
print(x4.value)
I am looking to have GEKKO run with the IF statement in the constraint, I'm not concerned if the optimization problem in the code has a solution. Thank you in advance.
(Disclaimer: i don't know this lib or what it will do for you)
The if-statement makes this problen non-differentiable which invalidates the assumption of NLP solvers (like Ipopt).
In terms of MINLP solvers (Bonmin, Couenne), this could be achieved by reformulation (and the resulting problem is differentiable when the needed auxiliary binary variables have been relaxed). It's hardly questionable to expect the lib to do it for you.
So it seems you need to play by the rules of some MINLP model like for example described by Bonmin here. There is no concept for "if-based branching".
Either introduce an indicator-variable like it's common in the MIP world, see here. Ignoring the overhead the idea would be something like:
K_ = Ck(x1,x2,x3,x4)
I = K_ > 15 (binary variable; see link for formulation idea)
return x1**2+x2**2+x3**2+x4**2 - I*15 - (1-I) * K_
This is an MINLP then.
You might get away without using an additional binary variable (and touching MINLPs) when interpreting your equation like:
return x1**2+x2**2+x3**2+x4**2 - min(Ck(x1,x2,x3,x4), 15)
This is also non-differentiable, but can be easily reformulated (with a quirk) like:
return x1**2+x2**2+x3**2+x4**2 - A
# extra constraints
A <= Ck(x1,x2,x3,x4)
A <= 15
if we could enforce moving towards the biggest A possible. This means, it must be part of the objective:
m.Obj(Cr(x1,x2,x3,x4) + c * A) (if it's a maximization problem)
This would be a NLP then, but the value of c needs some care (it must be big enough).
I recommend that you use the min2 or min3 functions or the recently added if3 function in GEKKO.
K = m.min3(Ck(x1,x2,x3,x4),15)
Here is additional information on MPCCs and Binary Switching variables. You can't use functions that have non-continuous gradients because it causes problems with the solvers and how they search for a solution. The min3 and if3 functions use binary variables and solve the problem as a Mixed Integer problem and min2 uses MPCCs. Here is a short example that demonstrates the use of min2 and min3.
import numpy as np
import matplotlib.pyplot as plt
from gekko import GEKKO
m = GEKKO(remote=False)
p = m.Param(value=np.linspace(10,20,21))
x = m.Var()
m.Equation(x==p)
# with MPCCs
y2 = m.min2(p,15)
# with integer variables
y3 = m.min3(p,16)
m.options.IMODE = 2
m.solve()
plt.plot(p,x,'b-',label='x')
plt.plot(p,y2,'g:',label='MPCC')
plt.plot(p,y3,'r--',label='Integer Switch')
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With