我想最大化两个linear
函数的商。我希望我的决策变量在此处为Binary
,即它们必须为integers
,并且只能采用0
和1
的值。
我想知道如何实现?我正在寻找使用SLSQP
之类的算法,而我已经研究过scipy
,但可悲的是,它并没有将决策变量的值限制为二进制和整数。
有人知道一个带有易于理解的界面的库吗?或者,是否有任何方法可以通过scipy
本身来实现。
我已经阅读了以下问题:Restrict scipy.optimize.minimize to integer values
但是在提供的三种解决方案中,我认为其中没有一种是有效的。 如果能提供任何帮助,那将真的很有帮助。
答案 0 :(得分:0)
由于您没有任何约束,除了变量应该是二进制的之外,最大化非常简单。您可以根据分子和分母中相应系数的比率对决策变量进行排序。 假设所有系数均为非负数,并且分子和分母都有偏差(以避免除以零),则可以在下面使用我的实现。
import numpy as np
def maximize(numer, denom):
"""
Function that maximizes an expression on the form
a[0]*x[0] + a[1]*x[1] + ... + a[n-1]*x[n-1]
-----------------------------------------
b[0]*x[0] + b[1]*x[1] + ... + b[n-1]*x[n-1]
where a[i] >= 0, b[i] >= 0, x[i] in [0,1] for 0 < i < n (non-negativity)
and
a[0] >= 0, b[0] > 0, x[0] = 1 (no division by zero)
"""
ratios = numer / denom
indices, ratios = zip(*sorted(enumerate(ratios), key = lambda x: - x[1]))
decision = np.zeros_like(numer)
decision[0] = 1 # the bias is always enabled
best_value = np.sum(decision * numer) / np.sum(decision * denom)
for index, ratio in zip(indices, ratios):
if index == 0:
continue
if ratio > best_value:
decision[index] = 1
best_value = np.sum(decision * numer) / np.sum(decision * denom)
else:
# no more ratios can increase the cumulative ratio
break
return decision
这是示例用法
if __name__ == "__main__":
numer = np.array([1, 3, 4, 6])
denom = np.array([1, 2, 2, 3])
print("Input: {} / {}".format(",".join([str(x) for x in numer]), ",".join([str(x) for x in denom])))
decision = maximize(numer, denom)
print("Decision: {}".format(decision))
print("Objective: {}".format(np.sum(decision * numer) / np.sum(decision * denom)))
答案 1 :(得分:0)
我已经完全完成了这个准备工作……但是这就是我将如何使用mystic
来做的事情。
>>> equations = """
... 3.*x0 + 5.*x1 + 7.*x2 + 9.*x3 = 1.*x0 + 2.*x1 + 3.*x3
... """
>>> bounds = [(0,None)]*4
>>>
>>> def objective(x):
... return x[0]**2 + 2*x[1] - 2*x[2] - x[3]**2
...
>>> from mystic.symbolic import generate_penalty, generate_conditions
>>> pf = generate_penalty(generate_conditions(equations))
>>> from mystic.constraints import integers
>>>
>>> @integers()
... def round(x):
... return x
...
>>> from mystic.solvers import diffev2
>>> result = diffev2(objective, x0=bounds, bounds=bounds, penalty=pf, constraints=round, npop=20, gtol=50, disp=True, full_output=True)
Optimization terminated successfully.
Current function value: 0.000000
Iterations: 121
Function evaluations: 2440
>>> result[0]
array([0., 0., 0., 0.])
现在稍微修改方程式...
>>> equations = """
... 3.*x0 + 5.*x1 + 7.*x2 + 9.*x3 = 5 + 1.*x0 + 2.*x1 + 3.*x3
... """
>>> pf = generate_penalty(generate_conditions(equations))
>>> result = diffev2(objective, x0=bounds, bounds=bounds, penalty=pf, constraints=round, npop=20, gtol=50, disp=True, full_output=True)
Optimization terminated successfully.
Current function value: 3.000000
Iterations: 102
Function evaluations: 2060
>>> result[0]
array([1., 1., 0., 0.])
如果要使用二进制变量而不是整数,则可以使用bounds = [(0,1)]*4
或将@integers()
替换为@discrete([0.0, 1.0])
。
虽然上面的结果不太有趣,但是在mystic的GitHub上有一些经过深思熟虑的具有整数编程和广义约束的全局优化示例: https://github.com/uqfoundation/mystic/blob/master/examples2/integer_programming.py https://github.com/uqfoundation/mystic/blob/master/examples2/olympic.py