Python GEKKO:非线性优化的优化性能

时间:2019-10-14 14:30:16

标签: python nonlinear-optimization gekko

我正在使用GEKKO‍解决非线性编程问题。我的目标是将GEKKO‍的性能与其他方法进行比较,因此,我想确保自己从GEKKO‍获得了最好的性能。

n 个二进制变量,每个变量都分配了一个权重,每个权重是间隔 [0,1] 中的一个数字(即满足 0 <= w <= 1 的有理数 w )。每个约束都是线性的。目标函数是非线性的:它是非零变量的权重的乘积,目标是使乘积最大化。

我首先将目标函数指定为

m.Obj(-np.prod([1 - variables[i] + weights[i] * variables[i] for i in range(len(variables))]))

但是我会碰到APM model error: string > 15000 characters。所以我使用if3函数切换为辅助变量

aux_variables = [m.if3(variables[i], weights[i], 1) for i in range(len(variables))]
m.Obj(-np.prod(aux_variables))

我手动设置的唯一全局参数在以下代码中。

# initialize model

m = GEKKO(remote=False)


# set global variables

m.options.SOLVER = 1 # APOPT solver
# "APOPT is an MINLP solver"
# "APOPT is also the only solver that handles Mixed Integer problems."

m.options.IMODE = 3 # steady state optimization

m.solver_options = ['minlp_maximum_iterations 500', \
                    # minlp iterations with integer solution
                    'minlp_max_iter_with_int_sol 10', \
                    # treat minlp as nlp
                    'minlp_as_nlp 0', \
                    # nlp sub-problem max iterations
                    'nlp_maximum_iterations 50', \
                    # 1 = depth first, 2 = breadth first
                    'minlp_branch_method 1', \
                    # maximum deviation from whole number
                    'minlp_integer_tol 0.05', \
                    # covergence tolerance
                    'minlp_gap_tol 0.01']

# initialize variables
variables = m.Array(m.Var, (number_of_vars), lb=0, ub=1, integer=True)

# set initial values
for var in variables:
    var.value = 1

问题:

就全局参数和目标函数的表示而言,我还能做些什么来优化GEKKO‍的性能以解决此特定问题?

同时,我希望GEKKO‍产生不错的结果。

1 个答案:

答案 0 :(得分:1)

重新定义问题以提高速度的一种方法是使用中间变量。

原始(0.0325秒,#Var = 5)

m.Obj(-np.prod([1 - variables[i] + weights[i] * variables[i] \
      for i in range(len(variables))]))

已修改(0.0156秒,#Var = 5)

ival = [m.Intermediate(1 - variables[i] + weights[i] * variables[i]) \
                       for i in range(len(variables))]
m.Obj(-np.prod(ival))

这还应该帮助您避免字符串长度的问题,除非您的number_of_vars非常大。似乎最佳解决方案将始终是variables[i]=1时的weights[i]=1variables[i]=0时的weights[i]=0。对于np.prod,这意味着整个目标函数为零,而乘积项中的任何一项为零。将单个乘积值设置为等于1而不是使用目标函数查找值是否有帮助?帮助APOPT找到正确解决方案的一件事是在您的中间声明中使用类似1.1的东西,而不是1.0。因此,在最大化时,它会尝试避免使用0.1的值,而希望找到一个给出1.1的解决方案。

from gekko import GEKKO
import numpy as np
m = GEKKO(remote=False)
number_of_vars = 5
weights = [0,1,0,1,0]
m.options.IMODE = 3
variables = m.Array(m.Var, (number_of_vars), lb=0, ub=1, integer=True)
for var in variables:
    var.value = 1
ival = [m.Intermediate(1.1 - variables[i] + weights[i] * variables[i]) \
                       for i in range(len(variables))]
# objective function
m.Obj(-np.prod(ival))
# integer solution with APOPT
m.options.SOLVER = 1
m.solver_options = ['minlp_maximum_iterations 500', \
                    # minlp iterations with integer solution
                    'minlp_max_iter_with_int_sol 10', \
                    # treat minlp as nlp
                    'minlp_as_nlp 0', \
                    # nlp sub-problem max iterations
                    'nlp_maximum_iterations 50', \
                    # 1 = depth first, 2 = breadth first
                    'minlp_branch_method 1', \
                    # maximum deviation from whole number
                    'minlp_integer_tol 0.05', \
                    # covergence tolerance
                    'minlp_gap_tol 0.01']
m.solve()
print(variables)

对于求解器来说,找到诸如m.sum()之类的求和解也容易得多,并且它给出与variables选项相同的np.prod()解。

# objective function
m.Obj(-m.sum(ival))

您可以添加一条后处理行以恢复将是01的产品目标函数。

if3函数对于您的应用程序不是一个很好的选择,因为切换条件为0,并且微小的数值变化将导致不可靠的结果。根据选项0,求解器将0.050.951minlp_integer_tol=0.05视为整数解。此选项允许整数解足够接近整数值时接受它们。如果variables[i]的值为0.01,则if3函数将在选择True选项时选择False选项。如果您在二进制值(例如if3)之间进行切换,则仍可以使用m.if3(variables[i]-0.5, weights[i], 1)函数。但是,解决问题的方法比使用if3函数更简单。