Деление этажа с помощью Gekko

В этой задаче оптимизации (моя упрощенная версия с одной переменной) у меня есть одна переменная, и я пытаюсь максимизировать цель. Ответ должен быть x = 4 с objfcnval, равным 2, поскольку по мере увеличения x это будут вычисления: 0 - 0 = 0, 1 - 2 = -1, < strong> 2 - 2 = 0, 3 - 2 = 1, 4 - 2 = 2, 5 < / сильный> - 4 = 1.

Вот код:

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'

Проблема в том, что, видимо, такая операция не поддерживается. Как я могу использовать Gekko для таких проблем?


person Mathias Sven    schedule 01.06.2020    source источник


Ответы (1)


Вдохновленный еще одним обсуждением, один из способов реализации функция этажа - создать новую целочисленную переменную y, ограниченную 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))

Это дает решение для x, y и целевой функции:

4.0 1.0
Objective: 2.0

Эта стратегия также работает, если x не является целочисленной переменной, но Gekko дает немного другой ответ:

3.99999996 1.0
Objective: 1.99999996

Если есть надежный метод, возможно, нам следует добавить в gekko функцию floor или ceil, аналогичную некоторым другим функциям в документация по построению модели. Не могли бы вы держать нас в курсе вашего тестирования и какой подход работает лучше всего?

person John Hedengren    schedule 01.06.2020
comment
Тем не менее, спасибо за ваш ответ, я видел, как применить ваш ответ к моей реальной проблеме, и не понимаю, как это сделать. В моем коде 27 переменных, где от x [0] до x [2] зависит от того, что есть от x [11] до x [26]. Например, если сумма от x [11] до x [27] равна 9, мне нужно, чтобы x [0] или x [1] или x [3] умножались на потолок (9, 2), поэтому 5, если сумма равна 15, мне нужно, чтобы ее умножили на 8. Для контекста, скажем, x [0], x [1], x [3] - это разные типы генераторов, которые увеличивают мощность в блоках по 2 и x [11] через x [26] - улучшения, требующие питания. - person Mathias Sven; 02.06.2020
comment
Возможно, самый простой способ справиться с этим - создавать дополнительную переменную каждый раз, когда вам нужно оценить потолок переменной. Функция gekko, такая как y = m.ceil(x/2), может быть даже лучше для управления этими функциями в сложных моделях. Не могли бы вы добавить запрос функции в gekko на Github, если хотите, чтобы это было добавлено? github.com/BYU-PRISM/GEKKO/issues - person John Hedengren; 02.06.2020