Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用自定义约束实现Python解算器_Python_Scipy_Linear Programming - Fatal编程技术网

使用自定义约束实现Python解算器

使用自定义约束实现Python解算器,python,scipy,linear-programming,Python,Scipy,Linear Programming,我有两个相互关联的变量,我想找到一个最优解,在这种情况下是它们之和的最小值。现在,让我们将它们称为X和Y,它们与预定义的常量一起,加起来就是一组“变量”s1和s2(这些变量稍后会提供约束): 在搜索SciPy文档时,我遇到了一个解决方案,其中我有最小化函数(在本例中,X+Y)和一组不等式和等式约束,我的变量绑定到这些约束。就我而言,它们如下: X>=0,Y>=0 s1>=1,s2>=1 s2/(s1+s2)=0.0001% 对于这种特定情况,代码很容易实现: 来自scipy.optimize

我有两个相互关联的变量,我想找到一个最优解,在这种情况下是它们之和的最小值。现在,让我们将它们称为
X
Y
,它们与预定义的常量一起,加起来就是一组“变量”
s1
s2
(这些变量稍后会提供约束):

在搜索SciPy文档时,我遇到了一个解决方案,其中我有最小化函数(在本例中,
X+Y
)和一组不等式和等式约束,我的变量绑定到这些约束。就我而言,它们如下:

  • X>=0,Y>=0
  • s1>=1,s2>=1
  • s2/(s1+s2)=0.0001%
对于这种特定情况,代码很容易实现:

来自scipy.optimize import linprog
lstConst=[105896649.59,-6738.82]
#要最小化的功能:X+Y
c=[1,1]
#s2/(s1+s2)=0.0001%方程的左侧
#即-0.000001*X+0.999999*Y
Aeq=[-0.000001,0.999999]]
#等式的右侧
beq=[0.000001*(lstConst[0]+lstConst[1])-lstConst[1]]
#确保最小值不能为负数
minX=max(1,max(1-lstcont[0],0))
minY=max(1,max(1-lstcont[1],0))
X_界限=(最小值,无)
Y_界限=(最小,无)
res=linprog(c,A_eq=Aeq,b_eq=beq,bounds=[X_bounds,Y_bounds])
因此我们有
X
Y
的值,以最小化
X
参数上的函数:

In [1]: res.x
Out[1]: array([1.00000000e+00, 6.84471676e+03])

我想在此基础上:

  • 事实上,还有另一组限制:
    s1
    s2
    也必须是整数(注意
    X
    Y
    作为浮点数没有问题)
  • 与其为
    s1
    s2
    之间的比率定义单个值,我将提供一个不同可能比率的列表
  • 本质上,我想找出
    X+Y
    函数的最小值,给定
    s1
    s2
    之间的几个不同比率。这可以通过迭代列表来实现,在每次迭代中定义
    Aeq
    beq
    ,或者定义其他限制(如果可能)

    然而,对于整数限制以及如何使线性规划算法考虑到它,我一无所知


    如果有人建议使用SciPy和
    linprog
    以外的库/优化器,也欢迎使用。

    首先,重新说明问题:

    minimize x + y, subject to:
    
        k1 + x = s1
        k2 + y = s2
        x >= 0
        y >= 0
        s1 >= 1
        s2 >= 1
        s2 / (s1 + s2) = k3
    
    Where:
    
        k1 = 105896649.59
        k2 = -6738.82
        k3 = 0.000001
    
    注意,您不需要使用
    s1
    s2
    变量在
    linprog
    中对问题进行编码。如果没有辅助变量
    s1
    s2
    ,问题在于:

    minimize x + y, subject to:
    
      x >= 0
      y >= 0
      x + k1 >= 1,
      y + k2 >= 1,
      (1-k3)y - k3x = (k1 + k2)k3 - k2
    
    linprog
    中,哪一个更易于阅读和编码:

    import numpy as np
    from scipy.optimize import linprog
    k1, k2, k3 = 105896649.59, -6738.82, 0.000001
    A_ub = -np.eye(2)
    b_ub = [k1-1, k2-1]
    A_eq = [[-k3, (1-k3)]]
    b_eq = (k1 + k2)*k3 -k2
    res = linprog([1,1], A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=[[0,None], [0, None]])
    print(res)
    
    这就给出了
    [0,6844.71675549]
    当x=1时的位置,因为实际上您已经将x和y的下限设置为1(我认为这是一个拼写错误…),但在所问问题的上下文中,这并不重要:


    关于这个问题:

    。。。对于整数限制以及如何使线性规划算法将其考虑在内,我一无所知

    如果有人建议使用SciPy和linprog以外的库/优化器,那也很受欢迎

    你的要求是什么。MILP和线性规划(LP)通常使用不同的算法求解,而MILP问题通常更难精确求解。SciPy Optimize不支持MILP。有许多开源工具可以做到这一点,比如和,它是一个Python包装器


    PySCIPOpt中的示例:

    PySCIPOpt很好,因为它有一个约束编程类型API。在PySCIPOpt中,您的问题很容易以可读的形式陈述。重新引入辅助变量后,我们几乎可以逐字输入约束:

    from pyscipopt import Model
    
    k1, k2, k3 = 105896649.59, -6738.82, 0.000001
    model = Model()
    x = model.addVar(vtype="CONTINUOUS", name="x", lb=0)
    y = model.addVar(vtype="CONTINUOUS", name="y", lb=0)
    s1 = model.addVar(vtype="CONTINUOUS", name="s1", lb=None, ub=None)
    s2 = model.addVar(vtype="CONTINUOUS" name="s2", lb=None, ub=None)
    o = model.addVar(vtype="CONTINUOUS", name="Objective Value", lb=0, ub=None)
    model.addCons(k1 + x == s1)
    model.addCons(k2 + y == s2)
    model.addCons(s1 >= 1)
    model.addCons(s2 >= 1)
    model.addCons(s2/(s1+s2) == k3)
    model.addCons(x + y == o)
    model.setObjective(o, "minimize")
    model.optimize()
    print('x + y = o -> (%.4f + %.4f = %.4f)' % (model.getVal(x), model.getVal(y), model.getVal(o)))
    
    给出与
    linprog
    相同的答案,因为它只是一个线性程序。然而,由于SCIP支持MILP,我们可以引入整数变量。要处理您的情况#1,只需将s1和s2更改为整数:

    ...
    s1 = model.addVar(vtype="INTEGER", name="s1", lb=None, ub=None)
    s2 = model.addVar(vtype="INTEGER", name="s2", lb=None, ub=None)
    
    给出:

    ...
    SCIP Status        : problem is solved [optimal solution found]
    Solving Time (sec) : 0.00
    Solving Nodes      : 1
    Primal Bound       : +1.10089229999989e+05 (1 solutions)
    Dual Bound         : +1.10089229999989e+05
    Gap                : 0.00 %
    x + y = o -> (103244.4100 + 6844.8200 = 110089.2300)
    
    这是一个完全不同的解决方案。。。但这就是为什么MILP不是LP


    从上面的示例中,通过阅读,您应该能够了解如何对您的#2案例进行编码-基本上类似于
    1/k3
    成为模型中的另一个整数变量。

    FYI您的代码中有另一个关于
    max(1,max(1-lstcont[0],0)]的输入错误。
    这相当于
    max(1-lstcont[0],1)
    但是评论说这只是为了确保数字不是负数。我没有意识到没有必要更详细,我认为如果我没有这样设置,
    lstcont
    的符号会影响边界,谢谢你的实现你确实需要它来编码不平等,只是它应该是
    minX=max(1-lstcont[0],0)
    而不是
    max(1,max(1-lstcont[0],0))
    AFAICT。我使用了linprog不等式约束来解决这些问题。在安装
    pyscipot
    时遇到了一些问题,但最终成功地使其运行。MILP的复杂性是否使其运行相对较慢?我跑了15分钟,原始边界和双重边界之间仍然有1.5%的差距。确切的代码是??一般来说,MILP是NP难的(参见维基百科文章链接ni答案),是的,比LP难。但在这种情况下,只有两个变量,应该很容易解决。在我的系统上花了0.00秒。我更新了答案以显示更多的输出。这也可能是因为我安装的解算器的可用性,而您没有。我不确定。是的,我实际上复制了你的代码来检查它的性能。可能是因为我使用的是特定的发行版吗?在我的例子中,因为我有蟒蛇,我必须通过
    pi安装
    pyscipot
    ...
    SCIP Status        : problem is solved [optimal solution found]
    Solving Time (sec) : 0.00
    Solving Nodes      : 1
    Primal Bound       : +1.10089229999989e+05 (1 solutions)
    Dual Bound         : +1.10089229999989e+05
    Gap                : 0.00 %
    x + y = o -> (103244.4100 + 6844.8200 = 110089.2300)