The Numpy count
function does not provide gradients for the solvers and is therefore not supported in gekko equations. An alternative way to solve the problem is to use a binary variable b
to determine which 2 numbers are selected between 0 and 10.
from gekko import GEKKO
model = GEKKO()
model.options.SOLVER = 1
n = 10
b = model.Array(model.Var, 11, lb=0, ub=1, integer=True)
y = [model.Intermediate(b[i]*i) for i in range(11)]
model.Equation(model.sum(b)==2)
model.Minimize(model.sum(y))
model.solve()
print('b: ' + str(b))
print('y: ' + str(y))
The solution is:
b: [[1.0] [1.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0]]
y: [[0.0], [1.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]]
It is correct because 0 and 1 are selected to minimize the summation. If you switch to m.Maximize(model.sum(y))
then the solver selects 9 and 10.
b: [[0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [1.0] [1.0]]
y: [[0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [9.0], [10.0]]
This doesn't give the solution for x
as an array of only 2 numbers. It is also possible that you could use y
in your application.
Here is a way to condense y
down to x
:
from gekko import GEKKO
model = GEKKO()
model.options.SOLVER = 1
b = model.Array(model.Var, (11,2), lb=0, ub=1, integer=True)
x = [None]*2
for j in range(2):
x[j] = model.sum([model.Intermediate(b[i,j]*i) for i in range(11)])
model.Equations([model.sum(b[:,j])==1 for j in range(2)])
model.Equations([model.sum(b[i,:])<=1 for i in range(11)])
model.Minimize(model.sum(x))
model.solve()
print('b: ' + str(b))
print('x: ' + str(x))
This gives the solution:
b: [[[0.0] [1.0]]
[[1.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]
[[0.0] [0.0]]]
x: [[1.0], [0.0]]
This method requires more binary variables but the solution is still fast.