python 非线性规划中的整数决策变量

emeijp43  于 2022-12-17  发布在  Python
关注(0)|答案(3)|浏览(159)

我想最大化两个linear函数的商,我想我的决策变量是Binary,也就是说,它们必须是integers,并且只能取01的值。
我想知道我如何才能实现这一点?我正在寻找使用像SLSQP这样的算法,我已经看过scipy,但遗憾的是,它没有限制决策变量的值为二进制和整数。
有没有人知道有一个接口简单易懂的库,我可以用它来实现这一点?或者有没有任何方法可以通过scipy本身来实现这一点。Restrict scipy.optimize.minimize to integer values
但是在这三个解决方案中,我认为没有一个是有效的。如果能提供任何帮助,那就太好了。

7hiiyaii

7hiiyaii1#

由于没有约束条件,除了变量必须是二进制之外,最大化非常简单,只需根据分子和分母中对应系数的比值对决策变量进行排序,假设所有系数都是非负的,并且分子和分母中存在偏差(以避免被零除),则可以使用下面的实现。

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)))
dgiusagp

dgiusagp2#

我完全是即兴表演的......但下面是我对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.pyhttps://github.com/uqfoundation/mystic/blob/master/examples2/olympic.py

fdbelqdn

fdbelqdn3#

Python中有几个包可以用来解决MINLP问题,包括pyomogekko。下面是一个用Python Gekko(我维护的一个包)解决MINLP问题的方法,作为一个简单的例子。安装gekko包,其中包括用pip解决APOPT MINLP问题的程序:

pip install gekko

MINLP解决方案

Gekko还可以解决Mixed Integer Nonlinear Programming (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求解器使用branch and bound solution approach和非线性规划(NLP)子问题来查找整数解。此处列出了几个附加软件包:Python Mixed Integer Linear Programming的MILP(和一些与MINLP)求解器。Scipy包将有一个混合整数线性规划(MILP)求解器在下一个版本,但这并不有助于您的MINLP问题。Gurobi,CPLEX,和Mosel-Xpress是领导者在MILP/MIQP求解器,但都是商业求解器。我最近还添加了一个答案后,你引用:Restrict scipy.optimize.minimize to integer values在您寻找一个MINLP求解器。如果您的问题可以重新制定为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

相关问题