Одним из способов переформулировать вашу проблему для увеличения скорости является использование промежуточных переменных.
Оригинал (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]=1
и variables[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))
Вы можете добавить постобработанную строку для восстановления целевой функции продукта, которая будет либо 0
, либо 1
.
. Функция if3
не годится. вариант для вашего приложения, потому что условие переключения на 0 и небольшие числовые изменения приведут к ненадежным результатам. Решатель считает 0
до 0.05
и 0.95
до 1
целочисленными решениями в соответствии с опцией minlp_integer_tol=0.05
. Это опция, которая позволяет принимать целочисленные решения, когда они достаточно близки к целочисленному значению. Если значение variables[i]
равно 0.01
, то функция if3
выберет опцию True
, когда она должна выбрать опцию False
. Вы все еще можете использовать функцию if3
, если вы установили точку переключения между двоичными значениями, такими как m.if3(variables[i]-0.5, weights[i], 1)
. Однако, есть более простые способы решения вашей проблемы, чем использование функции if3
.