[英]How can I write an IF condition for my decision variable for Mixed Integer Linear Programming (MILP) using PuLP GLPK on Python?
[英]Integer decision variable in non linear programming
我想最大化两个linear
函数的商。 我希望我的决策变量在这里是Binary
的,即它们必须是integers
并且只能0
和1
。
我想知道我怎样才能做到这一点? 我正在寻找使用像SLSQP
这样的算法并且我看过scipy
但遗憾的是它没有将决策变量的值限制为二进制和整数。
有谁知道一个界面易于理解的库,我可以用它来实现这个目标? 或者是否有任何方法可以通过scipy
本身实现这一目标。 我读过这个问题: Restrict scipy.optimize.minimize to integer values
但是在提供的三种解决方案中,我认为它们都不是有效的。 如果可以提供任何帮助,那将非常有帮助。
由于您没有任何约束,除了变量应该是二进制的之外,最大化非常简单。 您可以根据分子和分母中相应系数的比率对决策变量进行排序。 假设所有系数均为非负数,并且分子和分母都有偏差(以避免除以零),则可以使用下面的实现。
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)))
我完全在即兴地做这件事...但是这就是我如何用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
有一些包可用于 Python 中的 MINLP 解决方案,包括pyomo
和gekko
。 这是一个使用Python Gekko (我维护的包)解决 MINLP 问题的方法作为一个简单的例子。 使用pip
安装包含 APOPT MINLP 求解器的gekko
包:
pip install gekko
MINLP解决方案
Gekko 还解决了混合整数非线性规划 (MINLP)问题,例如:
from gekko import GEKKO
m = GEKKO(remote=False)
x = m.Array(m.Var,5,lb=0,ub=1,integer=True)
def f(x):
return ((5+x[0])/(4+x[1])) \
+(365.54/(3+x[2]))/(375.88/(3+x[3]))\
+(379.75/(3+x[4]))
m.Minimize(f(x))
m.Equation(sum(x)==2)
m.options.SOLVER=1
m.solve()
print(x)
这给出了解决方案:
Iter: 1 I: 0 Tm: 0.00 NLPi: 4 Dpth: 0 Lvs: 3 Obj: 9.69E+01 Gap: NaN
--Integer Solution: 9.69E+01 Lowest Leaf: 9.69E+01 Gap: 2.89E-04
Iter: 2 I: 0 Tm: 0.00 NLPi: 1 Dpth: 1 Lvs: 3 Obj: 9.69E+01 Gap: 2.89E-04
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 9.000000001833541E-003 sec
Objective : 96.9099912206023
Successful solution
---------------------------------------------------
[[0.0] [1.0] [0.0] [0.0] [1.0]]
APOPT 求解器使用带有非线性规划 (NLP) 子问题的分支定界求解方法来查找整数解。 这里列出了几个附加包:用于 MILP(和一些带有 MINLP)求解器的Python 混合整数线性规划。 Scipy 包将在下一个版本中提供混合整数线性规划 (MILP) 求解器,但这对您的 MINLP 问题没有帮助。 Gurobi、CPLEX 和 Mosel-Xpress 是 MILP/MIQP 求解器的领导者,但都是商业求解器。 我最近还在您引用的帖子中添加了一个答案: Restrict scipy.optimize.minimize to integer values in your search for an MINLP solver。 如果您的问题可以重新表述为 MILP,那么这将打开您对许多其他包的解决方案。
MILP解决方案
下面是一个脚本示例,它通过使用integer=True
指定上限和下限来解决变量限制为二进制值(0 或 1)的线性规划问题:
from gekko import GEKKO
m = GEKKO()
x,y = m.Array(m.Var,2,integer=True,lb=0,ub=1)
m.Maximize(y)
m.Equations([-x+y<=1,
3*x+2*y<=12,
2*x+3*y<=12])
m.options.SOLVER = 1
m.solve()
print('Objective: ', -m.options.OBJFCNVAL)
print('x: ', x.value[0])
print('y: ', y.value[0])
这将生成解决方案:
Iter: 1 I: 0 Tm: 0.00 NLPi: 2 Dpth: 0 Lvs: 0 Obj: -1.00E+00 Gap: 0.00E+00
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 1.369999999951688E-002 sec
Objective : -1.00000000000000
Successful solution
---------------------------------------------------
Objective: 1.0
x: 1.0
y: 1.0
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.