如何解决具有自定义函数的 Gekko 优化约束
我目前正在尝试使用 Gekko 解决混合整数非线性问题,使用它的 Branch&Bound 实现以及它的热启动方法,以加速和改进与 vanilla branch& bound 相比的收敛过程。 该算法在很短的时间内找到解决方案。然而,它损害了我可能错误定义的约束:我有一个 gekko 数组变量 X 并且需要另一个 gekko 数组变量“indices_open”来保存 x == 1 的每个 x 索引。这个“indices_open”进入另一个自定义函数,它期望“indices_open”作为一个 numpy 数组,并且不接受 gekko 中间变量的列表或 gekko 数组。自定义函数返回一个numpy数组。这个最终数组将用于 m.Equations 中,因此我将其转换为 gekko 变量数组。 不用说,出了问题,当前的解决方案损害了不等式约束,而满足了等式约束。在分析结果时,我得出的结论是“indices_open”似乎在每次迭代中都没有更新。
以下是我目前的尝试:
m = GEKKO()
m.options.soLVER = 1 # APOPT is an MINLP solver
# optional solver settings with APOPT
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']
#Declare x
x = m.Array(m.Var,(65),lb=0,ub=1,integer=True)
for i,xi in enumerate(x[0:65]):
xi.value = np.random.choice(np.arange(0,2),1,p=[0.4,0.6])[0]
#constr
m = ineq_constraint_new(x,m)
m = eq_constraint_new(x,m)
#target
m = objective(x,m)
#STArt
start_time = time.time()
#m.solve(disp=False)
m.solve()
print('Objective: ' + x)
print('Objective: ' + str(m.options.objfcnval))
# save x
m.x = [x[j].value[0] for j in range(65)]
def eq_constraint_new(x,m):
mask = np.isin(list_unique,specific_value)
indices_fixed = np.nonzero(mask)[0]
m.Equations([x[j] == 1 for j in indices_fixed])
return m
def ineq_constraint_new(x,m):
indices_open = [j for j in range(65) if x[j].value == 1]
# DOes not work
#indices_open_banks = [m.Intermediate(j) for j in range(65) if x[j].value == 1]
array_perc,_,_ = self_defined_f(indices_open,some_value)
#convert to gekko variables
gekko_vec_perc_upper_bound = m.Array(m.Var,(65))
for i,xi in enumerate(gekko_vec_perc_upper_bound[0:65]):
xi.value = some_array[i]
gekko_arr_perc = m.Array(m.Var,xi in enumerate(gekko_arr_perc[0:65]):
xi.value = arr_perc[i]
diff = gekko_vec_perc_upper_bound - gekko_arr_perc
m.Equations([diff[j] >= 0 for j in range(65)])
return m
def objective(x,m):
indices_open = [j for j in range(65) if x[j].value == 1]
_,arr_2,arr_3,arr_4 = self_defined_f(indices_open,some_value )
# intermediates for objective
res_dist = [None] * self.ds.n_banks
res_wand = [None] * self.ds.n_banks
res_wand_er = [None] * self.ds.n_banks
x_closed = np.array([1]*len(x)) - x
for j in range(self.ds.n_banks):
res_dist[j] = m.Intermediate(arr_2[j] * some_factor )
res_wand[j] = m.Intermediate(arr_3[j] * some_factor)
res_wand_er[j] = m.Intermediate(arr_4[j] * some_factor)
res_sach = some_factor * (some_vector * x_closed)
# Will be added together
m.Minimize(sum(res_dist))
m.Minimize(sum(res_wand))
m.Minimize(sum(res_wand_er))
m.Maximize(sum(res_sach))
return m
解决方法
有一个未定义的函数 _,arr_2,arr_3,arr_4 = self_defined_f(indices_open,some_value )
阻止代码运行。从代码的快速扫描,一个表达式如下:
indices_open = [j for j in range(65) if x[j].value == 1]
是不允许的,因为 gekko 要求所有方程都在 m.solve()
命令之前定义。不允许在 Python 中回调函数。相反,应该使用二进制变量来打开或关闭优化问题中的某些内容。这可以是一个方程,例如二元变量 b
:
b = m.Var(lb=0,ub=1,integer=True)
m.Equation(x*(1-b)<=0)
m.Equation(x*b>=0)
如果 b
小于零,则 x
的值等于 0,如果 b
大于零,则 x
等于 1。 APMonitor documentation 中的 if3()
函数教程也可能有用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。