Есть ли способ увеличить длину строки для уравнения в Gekko после получения «Ошибка модели APM: строка> 15000 символов»? - PullRequest
1 голос
/ 19 сентября 2019

Я использую Gekko для задачи оптимизации с ограничениями, которые требуют суммирования по переменным массива.Поскольку эти массивы длинные, я получаю сообщение об ошибке: APM model error: string > 15000 characters

Суммирование необходимо суммировать по трем переменным: i в диапазоне (1, годы), n в диапазоне (1, i) иj в диапазоне (1, рецепторы).По мере компиляции число переменных, включаемых в каждое суммирование, увеличивается.Я хочу оставить код в виде суммирования со следующей строкой:

m.Equation(emissions[:,3] == sum(sum(sum(f[n,j]*-r[j,2]*unit *(.001*(i-n)**2 + 0.062*(i-n)) for i in range(years)) for n in range(i))for j in range(rec)))

Однако эти ограничения приводят к ошибке более 15 000 символов для строки.

Ранее я решил проблему, используя циклы for и промежуточные элементы для решения всех этих переменных вне среды «ограничений».Он дал мне правильный ответ, но на сборку модели уходит много времени (свыше 4 часов на сборку модели и менее 3 минут на ее решение).Код выглядел так:

for i in range(years): 
    emissions[i,0] = s[i,1]
    emissions[i,1] = s[i,3]
    emissions[i,2] = s[i,5] 
    emissions[i,3] = 0
    emissions[i,4] = 0
    emissions[i,5] = 0
    for n in range(i):
        for j in range(rec): 
            #update + binary * flux * conversion * growth 
            emissions[i,3] = m.Intermediate(emissions[i,3] + f[n,j] * - rankedcopy[j,2] * unit * (.001*(i-n)**2 + 0.062*(i-n)))
            emissions[i,4] = m.Intermediate(emissions[i,4] + f[n,j] * - rankedcopy[j,3] * unit * (.001*(i-n)**2 + 0.062*(i-n)))
            emissions[i,5] = m.Intermediate(emissions[i,5] + f[n,j] * - rankedcopy[j,4] * unit * (.001*(i-n)**2 + 0.062*(i-n)))

Я надеюсь, что избегание циклов for увеличит эффективность, что позволит мне расширить модель, но я не уверен, как увеличить строку модели APMпредел.

Я также открыт для других предложений о том, как встраивать промежуточные продукты в суммирование.

1 Ответ

1 голос
/ 19 сентября 2019

Попробуйте использовать функцию m.sum() как встроенный объект GEKKO.Если вы используете функцию Python sum, то она создает большое уравнение суммирования, которое необходимо интерпретировать во время выполнения и может превысить предел размера уравнения.Вместо этого m.sum() создает суммирование в байт-коде.

m.Equation(emissions[:,3] == \
   m.sum(m.sum(m.sum(f[n,j]*-r[j,2]*unit *(.001*(i-n)**2 + 0.062*(i-n)) \
   for i in range(years)) for n in range(i))for j in range(rec)))

Вот простой пример, показывающий разницу в производительности.

from gekko import GEKKO
import numpy as np
import time
n = 5000
v = np.linspace(0,n-1,n)

# summation method 1 - Python sum
m = GEKKO()
t = time.time()
s = sum(v)
y = m.Var()
m.Equation(y==s)
m.solve(disp=False)
print(y.value[0])
print('Elapsed time: ' + str(time.time()-t))
m.cleanup()

# summation method 2 - Intermediates
m = GEKKO()
t = time.time()
s = 0
for i in range(n):
    s = m.Intermediate(s + v[i])
y = m.Var()
m.Equation(y==s)
m.solve(disp=False)
print(y.value[0])
print('Elapsed time: ' + str(time.time()-t))
m.cleanup()

# summation method 3 - Gekko sum
m = GEKKO()
t = time.time()
s = m.sum(v)
y = m.Var()
m.Equation(y==s)
m.solve(disp=False)
print(y.value[0])
print('Elapsed time: ' + str(time.time()-t))
m.cleanup()

Результаты

12497500.0
Elapsed time: 0.17874956130981445
12497500.0
Elapsed time: 5.171698570251465
12497500.0
Elapsed time: 0.1246955394744873

Ограничение в 15 000 символов для одного уравнения является жестким ограничением.Мы думали о том, чтобы сделать его регулируемым с m.options.MAX_MEMORY, но тогда большие уравнения могут сделать очень плотные матричные факторизации для решателя.Часто лучше разбить уравнение или использовать другие методы, чтобы уменьшить размер уравнения.

...