Floor division using Gekko

Viewed 228

In this optimization problem (a single variable simplified version of mine) I have one variable and I am trying to maximize the objective. The answer should be x = 4 with an objfcnval equal to 2 since as x increases these will be the calculations 0 - 0 = 0, 1 - 2 = -1, 2 - 2 = 0, 3 - 2 = 1, 4 - 2 = 2, 5 - 4 = 1.

Here is the code:

def my_ceiling(elem1, elem2):
    if (elem1 // elem2) == (elem1 / elem2):
        return elem1 / elem2
    else:
        return (elem1 // elem2) + 1


m = gekko.GEKKO(remote=False)
m.options.SOLVER = 1

x = m.Var(value=0, lb=0, ub=5, integer=True)

m.Obj((-1) * (x - 2 * my_ceiling(x, 4)))

m.solve(disp=False)

print('Objective: ' + str((-1) * m.options.objfcnval))
    if (elem1 // elem2) == (elem1 / elem2):
TypeError: unsupported operand type(s) for //: 'GKVariable' and 'int'

The problem is that apparently this kind of operation is not supported. How would I go about using Gekko for problems like these?

1 Answers

Taking inspiration from another discussion, one way to implement the floor function is to create a new integer variable y that is bounded by x/4 > y >= x/4 + 1e-8.

import gekko
m = gekko.GEKKO(remote=False)
m.options.SOLVER = 1

x = m.Var(value=0, lb=0,ub=5,integer=True)
y = m.Var(lb=0,ub=5,integer=True)

m.Equations([y<x/4,y>=x/4+1e-8])
m.Maximize((x - 2*y))

m.solve(disp=False)

print(x.value[0],y.value[0])
print('Objective: ' + str((-1)*m.options.objfcnval))

This produces a solution for x, y, and the objective function:

4.0 1.0
Objective: 2.0

This strategy also works if x is not an integer variable but Gekko gives a slightly different answer:

3.99999996 1.0
Objective: 1.99999996

If there is a reliable method, perhaps we should add a floor or ceil function in gekko that is similar to some of the other functions in the model building documentation. Could you keep us updated on your testing and what approach works best?

Related