Как использовать if2 / 3 в Gekko

Проблема, которую я оптимизирую, - это строительство электростанций в сети передачи. Для этого я размещаю электростанции на каждом автобусе и позволяю оптимизатору подсказать мне, какие из них следует построить, чтобы минимизировать эксплуатационные расходы.

Чтобы смоделировать размещение растения, я попытался использовать массив двоичных переменных, которые будут отмечать, т.е. быть единицей, если растение используется вообще, и 0 в противном случае. Затем в функции Objective для минимизации умножаю этот массив на константу: USEW.

Я сделал несколько попыток, но не работал. Тот, который, казалось, работал, использовал if2 Gekko прямо в Obj. func. Однако я получаю действительно странные результаты. Мой код немного длинный, поэтому я опубликую только соответствующие строки, надеюсь, идея будет ясна, если нет, пожалуйста, дайте мне знать, и я публикую все это.

bus=node=24
t=24
Sbase=100.
Gen = 12
VOLL = 10000.
VOLW = 50.
USEW = 100.
Pw = m.Array(m.Var,(bus,t), lb=0., ub=0., value=0.)
for b in range(bus):
    m.Minimize( np.sum(VOLL*lsh[b,:] + VOLW*Pc[b,:])*Sbase \
               + m.if2(-1.*Sbase*m.sum(Pw[b,:]),1,0)*USEW )

Проблема в if2 части. Если я удалю его, я получаю ожидаемые результаты, но тогда теряется решение о том, какое растение разместить. Я тоже пробовал с if3, но тоже не вышло. Из того, что я вижу, похоже, что оптимизатор пытается минимизировать Pw[b,:], потому что результат содержит только нули. Как-то миновать if2 часть и попасть во внутреннюю sum.

Судя по документации, эта часть: m.if2(-1.*Sbase*m.sum(Pw[b,:]),1,0) должна возвращать 0 или 1, но не похоже, что это делает. Я умножаю на -1, потому что Pw всегда положительно, и я хочу определить, когда Pw>0.

Мне нужна помощь в том, как правильно использовать условную функцию для этой цели. Спасибо

EDIT1 Рассмотрим следующий случай:

from gekko import GEKKO
m = GEKKO(remote=False)
Sbase=100.
Pw = array([[[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.0], [0.0], [0.0], [0.0], [0.0]],
   [[10.0], [10.0], [10.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], [0.0], [0.0]]], dtype=object)

# for np.sum(Pw[0,:])=0.0
print('sum of Pw[0,:]=', np.sum(Pw[0,:]))
print(m.if3(-1.*Sbase*np.sum(Pw[0,:]),1,0).value)
print(m.if3(-1.*Sbase*np.sum(Pw[0,:]),0,1).value)
# for np.sum(Pw[1,:])=30.0
print('sum of Pw[1,:]=', np.sum(Pw[1,:]))
print(m.if3(-1.*Sbase*np.sum(Pw[1,:]),1,0).value)
print(m.if3(-1.*Sbase*np.sum(Pw[1,:]),0,1).value)

Результат всегда один: 0. Не имеет значения, поменяю ли я местами x1 и x2 или если условие> = 0 или ‹0:

0.0
sum of Pw[0,:]= 0.0
0 #result 1
0 #result 2
sum of Pw[1,:]= 30.0
0 #result 3
0 #result 4

person Arraval    schedule 19.05.2020    source источник


Ответы (1)


Вы можете попробовать использовать точку переключения 1e-3 (или определенный минимум) вместо нуля. Когда точка переключения находится в нуле и условие равно 1e-10, тогда выход будет 1, потому что он больше точки переключения. Это необходимо, потому что Gekko использует оптимизаторы на основе градиента, которые имеют допуск решения 1e-6 (по умолчанию), поэтому решение в пределах этого допуска является приемлемым.

В документации есть несколько примеров, которые также могут помочь. Вы также можете посмотреть на функции _4 _ / _ 5_ и _6 _ / _ 7_, которые также могут дать вам желаемый результат.

if2 Документация

Условная IF с переменной-переключателем ограничения дополнительности. Традиционный метод для операторов IF не является непрерывно дифференцируемым и может привести к тому, что оптимизатор на основе градиента не сможет сойтись. Метод if2 использует двоичную переменную переключения, чтобы определить, y=x1 (когда condition<0) или y=x2 (когда condition>=0):

if3 Документация

Условный IF с двоичной переменной-переключателем. Традиционный метод для операторов IF не является непрерывно дифференцируемым и может привести к тому, что оптимизатор на основе градиента не сможет сойтись. Метод if3 использует двоичную переменную переключения, чтобы определить, y=x1 (когда condition<0) или y=x2 (когда condition>=0).

Использование

y = m.if3(condition,x1,x2)

Входные данные:

  • condition: переменная, параметр или выражение GEKKO
  • x1 и x2: переменная, параметр или выражение GEKKO

Вывод:

  • y = x1 когда condition<0
  • y = x2 когда condition>=0
from gekko import GEKKO
m = GEKKO(remote=False)
p = m.Param()
y = m.if3(p-4,p**2,p+1)

# solve with condition<0
p.value = 3
m.solve(disp=False)
print(y.value)

# solve with condition>=0
p.value = 5
m.solve(disp=False)
print(y.value)

Существует дополнительная информация о логических условиях с оптимизаторами на основе градиентов и различиях между Типы 2 (MPCC) и 3 (binary).

Ответ на EDIT1

Поскольку Gekko всегда использует условие переключения 0, мы можем изменить условие переключения с помощью condition<swc и уместить его обратно в форму gekko с помощью condition-swc<0. Из примера в моем ответе мы можем переместить условие переключения на swc=0.1.

swc = 0.1
y = m.if3(p-4-swc,p**2,p+1)

В вашем случае вы можете использовать swc=1e-3 или что-то немного выше, чтобы избежать решений прямо в состоянии переключения. Хотя решение if3 обычно занимает больше времени, я обычно получаю результаты лучше, чем if2, особенно если есть конкурирующие цели, которые мешают if2 MPCC.

person John Hedengren    schedule 19.05.2020
comment
Привет, спасибо за ответ. Первый абзац вашего ответа содержит несколько концепций, которые я не могу разделить. Как я могу установить точку переключения на 1e-3? как я вижу, точка переключения жестко запрограммирована как для if2 / 3, так и для 0: условие ‹0 и условие› = 0. Затем вы говорите, когда точка переключения находится на нуле ... но в предыдущем предложении она была установлена ​​на 1e-3. Я знаю, что мое замешательство глупо, но, пожалуйста, потерпите меня. - person Arraval; 20.05.2020