2

我正在使用 Gekko 解决需要对数组变量求和的约束的优化问题。因为这些数组很长,所以我不断收到错误消息:APM model error: string > 15000 characters

求和需要对三个变量求和:i in range(1, years)、n in range(1, i) 和 j in range(1,receptors)。随着它的编译,每个总和中包含的变量数量会增加。我想将代码保留为以下行的总和:

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 模型字符串限制的方法。

我也对如何将中间体嵌入总和的其他建议持开放态度。

4

1 回答 1

1

尝试将该m.sum()函数用作内置 GEKKO 对象。如果您使用 Pythonsum函数,那么它会创建一个需要在运行时解释的大型求和方程,并且可能超出方程大小限制。而是以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但大型方程可以为求解器进行非常密集的矩阵分解。通常最好分解方程或使用其他方法来减小方程的大小。

于 2019-09-19T13:58:37.797 回答