无法让 Gekko 处理中等规模的 MINLP 问题

问题描述

我有一个问题,希望最大化一个目标函数,即比率。

对象:sum(Ax)/Bx

对于具有相同维度的矩阵 AB随机零和一)。问题是不受约束的。所以基本上我想找到一个由 0 和 1 组成的 x 来最大化给定的比率。

这是我的问题的最小可重现示例(下面的第 2 项):

import numpy as np
import pandas as pd
from gekko import GEKKO

# Number of columns and rows for the given matrices
C = 43
R = 20

# Name columns since I will need to work with dataframes
names = ['n'+str(i) for i in range(C)]
names2 = ['d'+str(i) for i in range(C)]

# Toy example of random distribution of zeros and ones
num = np.random.randint(2,size=(R,C))
den = np.random.randint(2,C))
df_num = pd.DataFrame(columns=names,data=num)
df_den = pd.DataFrame(columns=names2,data=den)

# Start Gekko model
m = GEKKO(remote=False)
x = m.Array(m.Var,(df_num.shape[1]),lb=0,ub=1,integer=True)
for i in x:
    i.value = np.random.randint(2,size=1)[0]
m.solver_options = ['minlp_as_nlp 1']
ival1 = m.Intermediate(df_num.mul(x).sum(1).sum())
ival2 = m.Intermediate(df_den.mul(x).sum(1).sum())
m.Obj(-np.divide(ival1,ival2))
m.options.soLVER = 1 # APOPT solver
m.solve(disp=True)

我尝试按照 herehere 以及其他一些地方给出的说明进行操作,因此我使用 minlp_as_nlp 1 选项来放宽整数限制,并使用中间变量来查看是否有帮助,但是,我无法让模型工作。

基本上会发生以下两个问题:

1.找不到解(x 全为零)

那时我遇到了一个非常小的问题(如上面的那个,但列数为 42 或更少,但是,我的实际问题范围从 10k x 5e2 到 7e6 x 5e2)。我希望 x 能够找到最终值,但它全为零。这是 APM 打印出来的:

----------------------------------------------------------------
 APMonitor,Version 0.9.2
 APMonitor Optimization Suite
 ----------------------------------------------------------------
 
 
 --------- APM Model Size ------------
 Each time step contains
   Objects      :            0
   Constants    :            0
   Variables    :           42
   Intermediates:            2
   Connections  :            0
   Equations    :            3
   Residuals    :            1
 
 Number of state variables:             42
 Number of total equations: -            0
 Number of slack variables: -            0
 ---------------------------------------
 degrees of freedom       :             42
 
 ----------------------------------------------
 Steady State Optimization with APOPT Solver
 ----------------------------------------------
Iter:     1 I:  0 Tm:      0.04 NLPi:   18 Dpth:    0 Lvs:    0 Obj: -2.17E+00 Gap:  0.00E+00
 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :   4.780000000027940E-002 sec
 Objective      :   -2.16666666666667     
 Successful solution
 ---------------------------------------------------

2.运行时错误

当我将列数增加到 43(如上或更多)时,出现以下错误(已编辑以适应空间):

----------------------------------------------------------------
 APMonitor,Version 0.9.2
 APMonitor Optimization Suite
 ----------------------------------------------------------------
 
 
 @error: Max Equation Length
 Error with line number:           48
 i28=(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0)*(int_v1))
 +((0)*(int_v2)))+((0)*(int_v3)))+((1)*(int_v4)))+((1)*(int_v5)))+((1)*(int_v6))
 )+((0)*(int_v7)))+((1)*(int_v8)))+((0)*(int_v9)))+((1)*(int_v10)))+((0)*(int_v1
.
.
.
_v31)))+((0)*(int_v32)))+((0)*(int_v33)))+((1)*(int_v34)))+((1)*(int_v35)))+((1
 )*(int_v36)))+((1)*(int_v37)))+((0)*(int_v38)))+((0)*(int_v39)))+((0)*(int_v40)
 ))+((0)*(int_v41)))+((0)*(int_v42)))+((1)*(int_v43))))
 
 APM model error: string >       15000  characters
 Consider breaking up the line into multiple equations
 
 The may also be due to only using newline character CR
   instead of CR LF (for Windows) or LF (for MacOS/Linux) 
 To fix this problem,save APM file with appropriate newline characters
 
 STOPPING...
 

---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-50-5885f6e9b4ca> in <module>
      6 m.Obj(-np.divide(ival1,ival2))
      7 m.options.soLVER = 1
----> 8 m.solve(disp=True)

/anaconda_env/personal/rafaeldasilv/py3/lib/python3.7/site-packages/gekko/gekko.py in solve(self,disp,debug,GUI,**kwargs)
   2128                 print("Error:",errs)
   2129             if (debug >= 1) and record_error:
-> 2130                 raise Exception(apm_error)
   2131 
   2132         else: #solve on APM server

Exception: @error: Max Equation Length
 Error with line number:           48
 i28=(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0)*(int_v1))
 +((0)*(int_v2)))+((0)*(int_v3)))+((1)*(int_v4)))+((1)*(int_v5)))+((1)*(int_v6))
 )+((0)*(int_v7)))+((1)*(int_v8)))+((0)*(int_v9)))+((1)*(int_v10)))+((0)*(int_v1
 1)))+((1)*(int_v12)))+((1)*(int_v13)))+((0)*(int_v14)))+((1)*(int_v15)))+((1)*(
.
.
.
 )+((1)*(int_v27)))+((0)*(int_v28)))+((1)*(int_v29)))+((0)*(int_v30)))+((0)*(int
 _v31)))+((0)*(int_v32)))+((0)*(int_v33)))+((1)*(int_v34)))+((1)*(int_v35)))+((1
 )*(int_v36)))+((1)*(int_v37)))+((0)*(int_v38)))+((0)*(int_v39)))+((0)*(int_v40)
 ))+((0)*(int_v41)))+((0)*(int_v42)))+((1)*(int_v43))))
 
 APM model error: string >       `15000`  characters
 Consider breaking up the line into multiple equations
 
 The may also be due to only using newline character CR
   instead of CR LF (for Windows) or LF (for MacOS/Linux) 
 To fix this problem,save APM file with appropriate newline characters
 
 STOPPING...

有人能猜到我在这里可能遗漏了什么,或者即使这是正确的方法吗?谢谢!

编辑:运行建议的代码更改后的解决方案(R=400,C=76):

----------------------------------------------------------------
 APMonitor,Version 0.9.2
 APMonitor Optimization Suite
 ----------------------------------------------------------------
 
 
 --------- APM Model Size ------------
 Each time step contains
   Objects      :          802
   Constants    :            0
   Variables    :        61678
   Intermediates:            0
   Connections  :        62402
   Equations    :        60801
   Residuals    :        60801
 
 Number of state variables:          61678
 Number of total equations: -        61602
 Number of slack variables: -            0
 ---------------------------------------
 degrees of freedom       :             76
 
 ----------------------------------------------
 Steady State Optimization with APOPT Solver
 ----------------------------------------------
Iter:     1 I:  0 Tm:      1.60 NLPi:    3 Dpth:    0 Lvs:    3 Obj: -1.00E+00 Gap:       NaN
--Integer Solution:   0.00E+00 Lowest Leaf:  -1.00E+00 Gap:   1.00E+00
Iter:     2 I:  0 Tm:      0.44 NLPi:    2 Dpth:    1 Lvs:    2 Obj:  0.00E+00 Gap:  1.00E+00
Iter:     3 I:  0 Tm:      1.37 NLPi:    2 Dpth:    1 Lvs:    4 Obj: -1.00E+00 Gap:  1.00E+00
--Integer Solution:  -1.00E+00 Lowest Leaf:  -1.00E+00 Gap:   2.82E-06
Iter:     4 I:  0 Tm:      0.45 NLPi:    2 Dpth:    2 Lvs:    4 Obj: -1.00E+00 Gap:  2.82E-06
 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :    4.02930000000015      sec
 Objective      :  -0.999995215333898     
 Successful solution
 ---------------------------------------------------
 

Runtime: 1568.80s

解决方法

尝试使用 Gekko 求和来避免长符号表达式。

m.Maximize(m.sum(Ax)/m.sum(Bx))

没有找到解决方案,因为分母变为零,创建了无穷大的目标。这可以通过在分母上添加一个小常数来避免,例如:

m.Maximize(m.sum(Ax)/(m.sum(Bx)+1e-3))

没有 m.sum() 的当前版本会生成超过 15,000 个字符的目标函数表达式。

我还改用 A@xB@x 来简化矩阵乘法表达式,但您原来的 Pandas 表达式也可以使用。

import numpy as np
import pandas as pd
from gekko import GEKKO

# Number of columns and rows for the given matrices
C = 43
R = 20

# Name columns since I will need to work with dataframes
names = ['n'+str(i) for i in range(C)]
names2 = ['d'+str(i) for i in range(C)]

# Toy example of random distribution of zeros and ones
A = np.random.randint(2,size=(R,C))
B = np.random.randint(2,C))

# Start Gekko model
m = GEKKO(remote=False)
x = m.Array(m.Var,C,lb=0,ub=1,integer=True)
for i in x:
    i.value = np.random.randint(2,size=1)[0]
m.solver_options = ['minlp_as_nlp 1']

# Calculate Ax and Bx
Ax = A@x
Bx = B@x

# Maximize ratio
m.Maximize(m.sum(Ax)/(m.sum(Bx)+1e-3))

# Solve
m.options.SOLVER = 1 # APOPT solver
m.solve(disp=True)

解决方案:

 Iter    Objective  Convergence
   30 -2.19956E+00  1.30104E-18
   31 -2.19956E+00  6.93889E-18
   32 -2.19956E+00  6.93889E-18
 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :  0.13 sec
 Objective      :  -2.1995600879824035
 Successful solution
 ---------------------------------------------------

编辑:替代矩阵乘法

如果有更大的矩阵,请使用 Gekko 求和进行矩阵乘法。

# Calculate Ax and Bx
#Ax = A@x
#Bx = B@x
Ax = [m.sum([A[i,j]*x[j] for j in range(C)]) for i in range(R)]
Bx = [m.sum([A[i,j]*x[j] for j in range(C)]) for i in range(R)]

这对 C=43R=20 求解成功,但也适用于更大的矩阵。