zoukankan      html  css  js  c++  java
  • PuLp之一: 线性规划问题求解的一般步骤

    使用PuLp求解

    我们解决线性规划问题一般是通过以下三个步骤。
    1.列出约束条件及目标函数
    2.画出约束条件所表示的可行域
    3.在可行域内求目标函数的最优解及最优值

    使用pulp工具包,我们只需要做第一步即可,使用pulp提供的API提供目标函数及约束条件就可以直接求解,非常方便。
    Exported Classes:

    LpProblem – Container class for a Linear programming problem
    LpVariable – Variables that are added to constraints in the LP
    LpConstraint – A constraint of the general form
    a1x1+a2x2 …anxn (<=, =, >=) b
    LpConstraintVar – Used to construct a column of the model in column-wise modelling
    

    Exported Functions:

    value() – Finds the value of a variable or expression
    lpSum() – given a list of the form [a1*x1, a2x2, …, anxn] will construct a linear expression to be used as a constraint or variable
    lpDot() –given two lists of the form [a1, a2, …, an] and [ x1, x2, …, xn] will construct a linear epression to be used as a constraint or variable
    

    1、安装PuLp并导入, 下载地址:https://github.com/coin-or/pulp
    pip install pulp
    from pulp import *

    2、定义线性规划问题
    Prob = LpProblem ( "problem_name" , sense )
    定义Prob变量,用来定义一个LP问题实例,其中problem_name指定问题名(输出信息用),sense值是LpMinimize或LpMaximize中的一个,用来指定目标函数是求最大值还是最小值。

    4、定义决策变量
    有两种方式, 一种是定义单个变量(适用于变量个数不多的情况)
    DV = LpVariable ( decision variable name , lowbound , upbound ,category )
    decision variable name指定变量名,lowBound和upBound是下界和上界, 默认是none, 分别代表负无穷和正无穷, category用来指定变量是离散(LpInteger,LpBinary)还是连续(LpContinuous),

    还有一种方式是用dict方式来定义大量的变量,如下:
    Ingredients = ['Chicken','Beef','Mutton','Rice','Wheat','Gel']
    variables = LpVariable.dicts ("Ingr",Ingredients,0)
    上面两行代码输出的变量字典是:
    {'Chicken': Ingr_Chicken, 'Beef': Ingr_Beef, 'Mutton': Ingr_Mutton, 'Rice': Ingr_Rice, 'Wheat': Ingr_Wheat, 'Gel': Ingr_Gel}

    5、添加目标函数和约束条件
    先增加目标函数:
    Prob += linear objective in equantion from objective name= XXX
    注意: Prob += A 意思是 Prob = Prob + A, 但要注意这两者还是有区别的,可以参考:https://www.sohu.com/a/337619727_571478
    再设置约束条件:
    Prob += linear objective in equantion from constraint name

    6、写入LP文件
    Prob.writeLP ( filename )

    7、模型求解
    Prob.slove ( )
    输出的结果是’Optimal’,说明找到了最优解。my_lp_problem.status是一个常量,pulp.LpStatus是一个dict,把常量变成可读的字符串:

    LpStatus = {
        LpStatusNotSolved:"Not Solved",
        LpStatusOptimal:"Optimal",
        LpStatusInfeasible:"Infeasible",
        LpStatusUnbounded:"Unbounded",
        LpStatusUndefined:"Undefined",
        }
    

    这些常量的含义是:

    Not Solved:还没有调研solve()函数前的状态。
    Optimal:找到了最优解。
    Infeasible:问题没有可行解(比如定义了constraints x <= 1并且x >=2这样的约束)。
    Unbounded:约束条件是无界的(not bounded),最大化会导致无穷大(比如只有一个x >= 3这样的约束)。
    Undefined:最优解可能存在但是没有求解出来。
    

    8、结果显示
    check status : pulp.LpStatus[Prob.status]
    注意:LpStatus是dict

    PuLP支持很多开源的线性规划求解器(solver),比如CBC和GLPK;此外它也支持商业(收费)的求解器比如Gurobi和IBM的CPLEX。
    默认的是CBC,安装PuLP是默认就会安装。对于大部分问题来说,来自 COIN-OR 的CBC开源求解器就够用了。

    下面我们来求解:
    my_lp_problem.solve()
    print(pulp.LpStatus[my_lp_problem.status])

    思考程序本质
      problem对象是如何通过不断加来获得目标函数和约束的?熟悉python或者c++的朋友可能会想到一个词:操作符重载。
      没错,就是这么实现的,上述的对象几乎都实现了不同的重载。
      首先是Problem对象prob,全名pulp.pulp.LpProblem;当打印输出(print)时,会打印出问题名,当不断增加目标函数、约束时,也会随着print输出;而它的__add__一定是被定义过了,我们先说其他对象。
      当我们定义一个变量时,它的类型是pulp.pulp.LpVariable,当我们对这些变量和其他变量做加法、和其他常数做乘法时,它会返回一个新的对象,经检测,这个新对象的类名叫pulp.pulp.LpAffineExpression,顾名思义,叫做关系表达式;如果print,会打印这个关系表达式。
      而如果对关系表达式做出:>=、<=、==时,会返回新的对象,类名叫做pulp.pulp.LpConstraint,即约束对象;如果print,会打印这个约束。
      将关系表达式(pulp.pulp.LpAffineExpression)与问题(pulp.pulp.LpProblem)相加时,会返回新的问题对象,并且新的问题对象会将这个关系表达式作为目标函数。
      将约束对象(pulp.pulp.LpConstraint)与问题(pulp.pulp.LpProblem)相加时,会返回新的问题对象,并且这个新的问题对象会多出约束对象所代表的约束条件。
      调用问题对象的solve方法,解出线性规划的解。
      访问问题对象的objective成员变量,会得到目标函数(关系表达式对象)。
      调用pulp的value方法,将获得对变量代入值的结果,如果是关系表达式对象,将获得优化结果;如果是变量对象,将获得优化结果达到时的变量取值;如果是None,说明你忘调用solve了。

    其它参考资料:
    https://github.com/benalexkeen/Introduction-to-linear-programming
    https://www.codercto.com/a/109524.html
    https://www.jianshu.com/p/9be417cbfebb

  • 相关阅读:
    pandas 和反射联合使用
    反射
    获取Cookie 遇到的问题
    接口自动化之 问题
    接口自动化之 数据库操作
    logging日志模块
    数据驱动 --ddt
    logging--日志打印模块
    APP专项测试5 --PFS
    Monkey 参数
  • 原文地址:https://www.cnblogs.com/treasury-manager/p/13747308.html
Copyright © 2011-2022 走看看