添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

PuLP 有一些辅助函数,允许用户查询哪些求解器可用,并从其名称初始化一个求解器。

import pulp as pl
solver_list = pl.listSolvers()
print(solver_list)
# ['GLPK_CMD', 'PYGLPK', 'CPLEX_CMD', 'CPLEX_PY', 'CPLEX_DLL', 'GUROBI', 'GUROBI_CMD', 'MOSEK', 'XPRESS', 'PULP_CBC_CMD', 'COIN_CMD', 'COINMP_DLL', 'CHOCO_CMD', 'MIPCL_CMD', 'SCIP_CMD']

如果传递了 onlyAvailable=True 参数,PuLP 会列出当前可用的求解器:

import pulp as pl
solver_list = pl.listSolvers(onlyAvailable=True)
print(solver_list)
# ['GLPK_CMD', 'CPLEX_CMD', 'CPLEX_PY', 'GUROBI', 'GUROBI_CMD', 'PULP_CBC_CMD', 'COIN_CMD']

此外,还可以通过使用求解器的名称来获取求解器对象。传递给此函数的任何参数都会传递给构造函数:

import pulp as pl
solver = pl.getSolver('CPLEX_CMD')
solver = pl.getSolver('CPLEX_CMD', timeLimit=10)

在接下来的章节中,我们将解释如何配置一个求解器以便PuLP可以访问。

什么是环境变量

环境变量可能在 其他地方 有更好的解释。为了本文档的目的,它是一个在你的会话期间存储的文本值,允许你配置一些使用它们的应用程序。例如,当你写:

python

在命令行中,它通常会打开一个Python控制台。但是你的电脑是如何知道在哪里找到Python的呢?它知道是因为有一个名为“PATH”的环境变量,它存储了你硬盘上的一系列位置,你的电脑会在这些位置查找与你输入的内容匹配的可执行文件。

它有许多优点,例如在电脑上不留任何痕迹,并且具有相当好的跨平台性,以及其他许多优点。

PuLP 集成(API)到求解器的类型

API 意为“应用程序编程接口”。PuLP 通常有几种方式连接到求解器。根据连接求解器的方式,配置连接可能会有所不同。我们可以将集成总结为两大类:

  • 使用求解器的命令行界面。

  • 使用求解器的Python库。

  • 并非所有求解器都有Python库,但大多数都有命令行接口。如果你想知道自己使用的是哪一个,这很简单。如果求解器API的名称以``CMD``结尾(例如``PULP_CBC_CMD``、CPLEX_CMD``GUROBI_CMD``等),那么它是前者。否则,它是后者。

    配置求解器路径

    为了让 PuLP 能够通过 CMD API 使用求解器,求解器需要通过命令行由 PuLP 执行。为此,需要以下两种情况之一:

  • 用户将求解器的路径传递给求解器初始化。

  • 用户已将 PATH 环境变量配置为求解器所在的目录。

  • 我们将在Windows上为CPLEX做示例,但这个想法对其他求解器和其他操作系统也是一样的

    这两个选项都意味着要知道求解器的位置。所以我们首先要去电脑中查找它。我的在 C:\Program Files\IBM\ILOG\CPLEX_Studio128\cplex\bin\x64_win64\cplex.exe

    想象使用 CPLEX_CMD 求解器,第一个非常简单:

    path_to_cplex = r'C:\Program Files\IBM\ILOG\CPLEX_Studio128\cplex\bin\x64_win64\cplex.exe'
    import pulp as pl
    model = pl.LpProblem("Example", pl.LpMinimize)
    solver = pl.CPLEX_CMD(path=path_to_cplex)
    _var = pl.LpVariable('a')
    _var2 = pl.LpVariable('a2')
    model += _var + _var2 == 1
    result = model.solve(solver)
    

    唯一要做的事情是查找 ‘cplex.exe’ 文件(如果你在 Windows 上,对于 Linux 和 Mac 则查找 ‘cplex’ 文件),并将绝对路径传递给求解器。

    第二个稍微麻烦一点,但每台机器只需做一次。你需要配置 PATH 环境变量,使其包含 C:\Program Files\IBM\ILOG\CPLEX_Studio128\cplex\bin\x64_win64 目录的路径。

    以下是一个关于编辑环境变量的随机指南:WindowsLinux 或 Mac。其理念是,一旦正确配置,你就可以忘记它(直到你更换电脑或求解器版本)。

    一旦我们完成了那一步,我们只需做一些与前一个示例非常相似的事情:

    import pulp as pl
    model = pl.LpProblem("Example", pl.LpMinimize)
    solver = pl.CPLEX_CMD()
    _var = pl.LpVariable('a')
    _var2 = pl.LpVariable('a2')
    model += _var + _var2 == 1
    result = model.solve(solver)
    

    唯一的区别是我们不需要告诉 PuLP 求解器的位置。系统会像上面的 python 示例一样,使用 PATH 环境变量找到它。太神奇了!

    每个求解器的附加环境变量

    有时,仅提供求解器的路径是不够的。这可能是因为求解器需要知道其他文件的位置(运行时将使用的动态库),或者 PuLP API 需要导入一些与求解器一起部署的特定 Python 包(对于那些没有以 _CMD 结尾的求解器)。

    无论出于什么原因,安全总比后悔好,这意味着要知道哪些变量通常被哪个求解器使用。以下是每个求解器所需的必要环境变量。该过程与我们使用 PATH 变量的做法非常相似:有时你需要编辑现有的环境变量,有时你需要创建一个新的环境变量。为了看起来明确,我将使用我自己的变量路径,但你将不得不将它们适应到你的实际路径(例如,如果求解器的版本不同)。我将使用我的 Linux 路径,因为这仅仅意味着复制我的 ~.bashrc 文件的最后一行。我已经将它们适应到 Windows 命令行,但最好是通过 Windows 的 GUI 来编辑它们。

    CPLEX

    Linux / Mac: 将以下行添加到 ~.bashrc(或 ~.profile 或 /etc/profile 或 /etc/bash.bashrc)文件中:

    export CPLEX_HOME="/opt/ibm/ILOG/CPLEX_Studio128/cplex"
    export CPO_HOME="/opt/ibm/ILOG/CPLEX_Studio128/cpoptimizer"
    export PATH="${PATH}:${CPLEX_HOME}/bin/x86-64_linux:${CPO_HOME}/bin/x86-64_linux"
    export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${CPLEX_HOME}/bin/x86-64_linux:${CPO_HOME}/bin/x86-64_linux"
    export PYTHONPATH="${PYTHONPATH}:/opt/ibm/ILOG/CPLEX_Studio128/cplex/python/3.5/x86-64_linux"
    

    Windows:添加以下环境变量(通过命令行或图形用户界面):

    set CPLEX_HOME=C:/Program Files/IBM/ILOG/CPLEX_Studio128/cplex
    set CPO_HOME=C:/Program Files/IBM/ILOG/CPLEX_Studio128/cpoptimizer
    set PATH=%PATH%;%CPLEX_HOME%/bin/x64_win64;%CPO_HOME%/bin/x64_win64
    set LD_LIBRARY_PATH=%LD_LIBRARY_PATH%;%CPLEX_HOME%/bin/x64_win64;%CPO_HOME%/bin/x64_win64
    set PYTHONPATH=%PYTHONPATH%;/opt/ibm/ILOG/CPLEX_Studio128/cplex/python/3.5/x64_win64
    

    GUROBI

    Linux / Mac: 将以下行添加到 ~.bashrc(或 ~.profile 或 /etc/profile 或 /etc/bash.bashrc)文件中:

    export GUROBI_HOME="/opt/gurobi801/linux64"
    export PATH="${PATH}:${GUROBI_HOME}/bin"
    export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${GUROBI_HOME}/lib"
    

    Windows:添加以下环境变量(通过命令行或图形用户界面):

    set GUROBI_HOME=/opt/gurobi801/linux64
    set PATH=%PATH%;%GUROBI_HOME%/bin
    set LD_LIBRARY_PATH=%LD_LIBRARY_PATH%;%GUROBI_HOME%/lib
    

    配置CMD求解器写入临时文件的位置

    在使用命令行(再次强调,那些以 CMD 结尾的)的求解器API的情况下,有时用户希望控制文件的写入位置。有很多选项可供选择。

    默认情况下,PuLP 不会保留中间文件(*.mps, *.lp, *.mst, *.sol),它们会被写入操作系统的临时目录中。PuLP 会按顺序查找 TEMP、TMP 和 TMPDIR 环境变量来写入文件。使用后,PuLP 会删除这些文件。如果在求解前更改了这些环境变量中的任何一个,您应该能够选择希望 PuLP 将结果写入的位置。

    import pulp as pl
    model = pl.LpProblem("Example", pl.LpMinimize)
    _var = pl.LpVariable('a')
    _var2 = pl.LpVariable('a2')
    model += _var + _var2 == 1
    solver = pl.PULP_CBC_CMD()
    result = model.solve(solver)
    

    另一个选项是向求解器传递参数 keepFiles=True。使用此选项,求解器会在当前目录中创建文件,并且这些文件不会被删除(尽管如果你重新执行,它们会被覆盖)。

    import pulp as pl
    model = pl.LpProblem("Example", pl.LpMinimize)
    _var = pl.LpVariable('a')
    _var2 = pl.LpVariable('a2')
    model += _var + _var2 == 1
    solver = pl.PULP_CBC_CMD(keepFiles=True)
    result = model.solve(solver)
    

    最后,可以在实际求解之前手动编辑求解器对象的 tmpDir 属性。

    import pulp as pl
    model = pl.LpProblem("Example", pl.LpMinimize)
    _var = pl.LpVariable('a')
    _var2 = pl.LpVariable('a2')
    model += _var + _var2 == 1
    solver = pl.PULP_CBC_CMD()
    solver.tmpDir = 'PUT_SOME_ALTERNATIVE_PATH_HERE'
    result = model.solve(solver)
    

    要使此求解器工作,唯一的选择是安装与 gurobi 安装一起提供的 python 包。

    按照我的安装路径,它将是(Linux):

    cd /opt/gurobi801/linux64/
    sudo python3 setup.py install
    

    如你所见,安装它需要管理员权限。

    使用特定求解器的功能

    为了访问此功能,用户需要使用 PuLP 问题中包含的求解器对象。PuLP 使用问题对象上的 solverModel 属性。当执行 buildSolverModel() 方法时,此属性被创建并填充。

    例如,使用 CPLEX_PY API,我们可以在求解完成后访问api对象:

    import pulp
    x = pulp.LpVariable('x', lowBound=0)
    prob = pulp.LpProblem('name', pulp.LpMinimize)
    prob += x
    solver = pulp.CPLEX_PY()
    status = prob.solve(solver)
    # you can now access the information from the cplex API python object
    prob.solverModel
    

    此外,您可以在求解之前通过使用较低级别的方法访问python api对象:

    import pulp
    x = pulp.LpVariable('x', lowBound=0)
    prob = pulp.LpProblem('name', pulp.LpMinimize)
    prob += x
    solver = pulp.CPLEX_PY()
    solver.buildSolverModel(prob)
    # you can now edit the object or do something with it before solving
    # for example, load a MIP_START file for CPLEX_PY:
    solver.solverModel.MIP_starts.read(SOME_MST_FILE)
    # the, you can call the solver to solve the problem
    solver.callSolver(prob)
    # finally, you fill the PuLP variables with the solution
    status = solver.findSolutionValues(prob)
    

    关于如何使用 solverModel 的更多信息,需要根据所使用的求解器查阅官方文档。

    导入和导出求解器

    导出一个求解器可能有助于备份用于求解模型的配置。

    为了导出它,可以将其导出为字典或json文件:

    import pulp
    solver = pulp.PULP_CBC_CMD()
    solver_dict = solver.toDict()
    

    返回的字典结构非常简单:

    {'keepFiles': 0,
     'mip': True,
     'msg': True,
     'options': [],
     'solver': 'PULP_CBC_CMD',
     'timeLimit': None,
     'warmStart': False}
    

    也可以直接将其导出到json文件:

    solver.toJson("some_file_name.json")
    

    为了导入它,需要执行:

    import pulp
    solver = pulp.getSolverFromDict(solver_dict)
    

    或从文件中:

    import pulp
    solver = pulp.getSolverFromJson("some_file_name.json")
    

    对于json,我们使用基础的 json 包。但如果 ujson 可用,我们会使用它,以便导入/导出可以非常快。