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

Python GEKKO: optimizing performance of nonlinear optimization

我正在使用 GEKKO‍ 求解非线性规划问题。我的目标是将 GEKKO‍ 性能与替代方案进行比较,因此我想确保我从 GEKKO‍ 获得它所能提供的最佳效果。

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

我首先将 objective 函数指定为

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

问题:

根据 objective 函数的全局参数和公式,我还能做些什么来优化 GEKKO‍ 针对这个特定问题的性能?

同时,我希望GEKKO‍能取得不错的成绩。

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

原始(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 非常大。似乎最优解永远是weights[i]=1时的variables[i]=1weights[i]=0时的variables[i]=0。使用 np.prod 这意味着整个 objective 函数为零,任何一个乘积项为零。将单个产品值设置为等于 1 而不是使用 objective 函数来查找值是否有帮助?帮助 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() 之类的求和解,并且它给出与 np.prod() 选项相同的 variables 解。

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

您可以添加一个 post 流程线来恢复产品 objective 功能,该功能将是 01

if3 函数不适合您的应用程序,因为切换条件为 0,轻微的数值变化会导致结果不可靠。根据选项 minlp_integer_tol=0.05,求解器将 00.050.951 视为整数解。这是一个允许整数解在足够接近整数值时被接受的选项。如果 variables[i] 值为 0.01,那么 if3 函数将在应该 select False 选项时选择 True 选项。如果您在 m.if3(variables[i]-0.5, weights[i], 1) 等二进制值之间设置了切换点,您仍然可以使用 if3 函数。但是,有比使用 if3 函数更简单的方法来解决您的问题。