Python接口

安装说明

目前,杉数求解器的Python接口支持Python 2.7, 3.6-3.12版本。 其中,对于Python 3.8-3.12版本,COPT的MacOS-Universal可提供支持;对于Python 2.7, 3.6-3.7版本,则只有MacOS-X86。

使用Python接口前,请用户确保已正确安装和配置杉数求解器,详情可参考 如何安装杉数求解器 。 用户可以从 Anaconda发行版 或者 Python官方发行版 下载并安装Python。我们推荐用户 安装Anaconda发行版,因为它对Python新手使用更加友好与方便(对于Windows系统,请勿使用 通过Microsoft Store安装的Python)。若使用官方发行版本或系统自带版本,则应确保已安装 pipsetuptools Python工具包。

注意

我们推荐使用3.8-3.12版本,因为COPT-Python接口的矩阵建模功能最低版本要求是3.8。2.7, 3.6-3.7版本除非必要,不推荐首选。

Windows

方式一:通过pip install的方式(推荐)

打开cmd命令行窗口(若Python是Anaconda发行版,则打开Anaconda命令行窗口),输入如下命令:

pip install coptpy

若已安装了旧版本的 coptpy 包,请在cmd命令行窗口(若Python是Anaconda发行版,则打开Anaconda命令行窗口), 输入如下命令,以升级到最新版本的 coptpy 包:

pip install --upgrade coptpy

方式二:通过COPT安装包

对于Windows系统,假定杉数求解器安装路径为:C:\Program Files\copt71,则切换目录到 C:\Program Files\copt71\lib\python ,并在命令行窗口上执行如下命令:

python setup.py install

注意: 若杉数求解器安装在系统盘(一般为C盘),则需要 以管理员权限执行 打开命令行窗口。 为测试Python接口是否正确安装,用户可切换目录至 C:\Program Files\copt71\examples\python , 并在命令行窗口上执行如下命令:

python lp_ex1.py

若模型正确执行,则表示已正确安装杉数求解器的Python接口。

注意: 若使用Python官方发布的Python 3.8版本,假定安装路径为:"C:\Program Files\Python38", 则需要将杉数求解器安装路径的 "bin" 子目录下的 copt_cpp.dll 文件复制到杉数求解器的 Python接口安装路径:"C:\Program Files\Python38\Lib\site-packages\coptpy" 以解决动态库依赖问题。

目前, coptpy 已经支持type hints,用户可以在命令行窗口(若Python为Anaconda发行版,请打开Anaconda Prompt),执行如下命令:

pip install coptpy-stubs

安装成功后,在Python IDE中编写代码时,会提示变量名补全及函数参数可取值。

Linux

方式一:通过pip install的方式(推荐)

打开终端,输入如下命令,安装COPT Python接口

pip install coptpy

若已安装了旧版本的 coptpy 包,请打开终端,输入如下命令,以升级到最新版本的 coptpy

pip install --upgrade coptpy

方式二:通过COPT安装包

对于Linux系统,假定杉数求解器安装路径为:/opt/copt71 ,则切换目录到 /opt/copt71/lib/python ,并在终端上执行:

sudo python setup.py install

对于使用Anaconda发行版的用户,若执行上述命令失败,则需要使用Anaconda发行版Python可执行文件 的完整路径执行安装命令。假定Anaconda安装路径为:"/opt/anaconda3",则在终端上执行下述 命令安装杉数求解器的Python接口:

sudo /opt/anaconda3/bin/python setup.py install

为测试Python接口是否正确安装,用户可切换目录至 /opt/copt71/examples/python , 并在命令行窗口上执行如下命令:

python lp_ex1.py

若模型正确执行,则表示已正确安装杉数求解器的Python接口。

目前, coptpy 已经支持type hints,用户可以在终端执行如下命令:

pip install coptpy-stubs

安装成功后,在Python IDE中编写代码时,会提示变量名补全及函数参数可取值。

MacOS

方式一:通过pip install的方式(推荐)

打开终端terminal,输入如下命令,安装COPT Python接口:

pip install coptpy

若已安装了旧版本的 coptpy 包,请打开终端,输入如下命令,以升级到最新版本的 coptpy

pip install --upgrade coptpy

方式二:通过COPT安装包

对于MacOS系统,假定杉数求解器的安装路径为:/Applications/copt71 ,则切换目录到 /Applications/copt71/lib/python ,并在终端上执行:

sudo python setup.py install

为测试Python接口是否正确安装,用户可切换目录至 /Applications/copt71/examples/python , 并在终端执行如下命令:

python lp_ex1.py

若模型正确执行,则表示已正确安装杉数求解器的Python接口。

目前, coptpy 已经支持type hints,用户可以在终端执行如下命令:

pip install coptpy-stubs

安装成功后,在Python IDE中编写代码时,会提示变量名补全及函数参数可取值。

示例解析

本章通过一个简单的示例演示如何使用杉数求解器的Python接口,待求解的问题数学形式如 公式 5 所示:

(5)\[\begin{split}\text{最大化:} & \\ & 1.2 x + 1.8 y + 2.1 z \\ \text{约束:} & \\ & 1.5 x + 1.2 y + 1.8 z \leq 2.6 \\ & 0.8 x + 0.6 y + 0.9 z \geq 1.2 \\ \text{变量范围:} & \\ & 0.1 \leq x \leq 0.6 \\ & 0.2 \leq y \leq 1.5 \\ & 0.3 \leq z \leq 2.8\end{split}\]

使用杉数求解器的Python接口求解与分析上述问题的代码见 代码 6

代码 6 lp_ex1.py
 1#
 2# This file is part of the Cardinal Optimizer, all rights reserved.
 3#
 4
 5"""
 6The problem to solve:
 7
 8  Maximize:
 9    1.2 x + 1.8 y + 2.1 z
10
11  Subject to:
12    1.5 x + 1.2 y + 1.8 z <= 2.6
13    0.8 x + 0.6 y + 0.9 z >= 1.2
14
15  where:
16    0.1 <= x <= 0.6
17    0.2 <= y <= 1.5
18    0.3 <= z <= 2.8
19"""
20
21import coptpy as cp
22from coptpy import COPT
23
24# Create COPT environment
25env = cp.Envr()
26
27# Create COPT model
28model = env.createModel("lp_ex1")
29
30# Add variables: x, y, z
31x = model.addVar(lb=0.1, ub=0.6, name="x")
32y = model.addVar(lb=0.2, ub=1.5, name="y")
33z = model.addVar(lb=0.3, ub=2.8, name="z")
34
35# Add constraints
36model.addConstr(1.5*x + 1.2*y + 1.8*z <= 2.6)
37model.addConstr(0.8*x + 0.6*y + 0.9*z >= 1.2)
38
39# Set objective function
40model.setObjective(1.2*x + 1.8*y + 2.1*z, sense=COPT.MAXIMIZE)
41
42# Set parameter
43model.setParam(COPT.Param.TimeLimit, 10.0)
44
45# Solve the model
46model.solve()
47
48# Analyze solution
49if model.status == COPT.OPTIMAL:
50  print("Objective value: {}".format(model.objval))
51  allvars = model.getVars()
52
53  print("Variable solution:")
54  for var in allvars:
55    print(" x[{0}]: {1}".format(var.index, var.x))
56
57  print("Variable basis status:")
58  for var in allvars:
59    print(" x[{0}]: {1}".format(var.index, var.basis))
60
61  # Write model, solution and modified parameters to file
62  model.write("lp_ex1.mps")
63  model.write("lp_ex1.bas")
64  model.write("lp_ex1.sol")
65  model.write("lp_ex1.par")

接下来我们将基于上述代码分步骤讲解求解与分析过程,详细的Python接口使用说明请用户查阅 Python API参考手册

导入Python接口

使用杉数求解器的Python接口,需要首先导入Python接口库。

import coptpy as cp
from coptpy import COPT

创建环境

对于任意求解任务,杉数求解器要求首先创建求解环境。

# Create COPT environment
env = cp.Envr()

创建问题

创建求解环境成功后,用户需要创建模型,模型中将包括待求解的变量、约束等信息。

# Create COPT model
model = env.createModel("lp_ex1")

添加变量

创建变量时允许同时指定变量在目标函数中的系数、变量上下界等信息。 本示例中创建变量时仅指定上下界和名称信息,其它为默认值。

# Add variables: x, y, z
x = model.addVar(lb=0.1, ub=0.6, name="x")
y = model.addVar(lb=0.2, ub=1.5, name="y")
z = model.addVar(lb=0.3, ub=2.8, name="z")

添加约束

添加变量成功后,进一步添加作用于变量的约束条件。

# Add constraints
model.addConstr(1.5*x + 1.2*y + 1.8*z <= 2.6)
model.addConstr(0.8*x + 0.6*y + 0.9*z >= 1.2)

设置目标函数

添加完变量和约束后,进一步指定模型的目标函数。

# Set objective function
model.setObjective(1.2*x + 1.8*y + 2.1*z, sense=COPT.MAXIMIZE)

设置求解参数

用户可以在求解模型前设置求解参数,如设置求解时间限制为10秒。

# Set parameter
model.setParam(COPT.Param.TimeLimit, 10.0)

求解模型

调用下述方法求解模型。

# Solve the model
model.solve()

分析结果

求解完成后,首先获取模型求解状态,若状态为找到了最优解,则进一步获取目标函数值、各变量的取值及其 基状态信息。

# Analyze solution
if model.status == COPT.OPTIMAL:
  print("Objective value: {}".format(model.objval))
  allvars = model.getVars()

  print("Variable solution:")
  for var in allvars:
    print(" x[{0}]: {1}".format(var.index, var.x))

  print("Variable basis status:")
  for var in allvars:
    print(" x[{0}]: {1}".format(var.index, var.basis))

文件输出

用户可以将当前求解的模型保存为标准的MPS模型文件,以及输出变量结果文件、基状态信息文件和修改过的 参数文件。

  # Write model, solution and modified parameters to file
  model.write("lp_ex1.mps")
  model.write("lp_ex1.bas")
  model.write("lp_ex1.sol")
  model.write("lp_ex1.par")

最佳实践

升级新版本

对于已经安装了COPT python包的用户,如果想升级到最新版本,建议先卸载旧版本的coptpy,然后再 安装新版本。旧版本的COPT python包可以从Python的 site-package 的子目录 coptpy 中找到。

多线程编程

COPT的建模API并不保证可重入性,在多线程编程时如果共享模型对象可能造成数据错误。一般来说, 在多个线程下共享COPT环境类Envr是可以的。但是,注意不要共享模型类,除非用户明确知道自己的行为后果。 举例来说,如果在两个线程里共享同一个模型类,确保建模和求解只在其中一个线性进行;在另外一个线程里, 可以对求解过程监督,然后在合适的时候通过 interrupt() 中断任务执行,比如任务超时了。

Python的字典顺序

Python默认的字典是无序的,也就是说,遍历次序和数据加入的次序可能不同。例如,输入数据是 {'fruits': ['apple', 'orange'], 'veggies': ['carrot', 'pea']} ,但是输出的是 {'veggies': ['carrot', 'pea'], 'fruits': ['apple', 'orange']}

从Python 3.6开始,Python字典的内部实现变成有序了。特别是Python 3.7及以后,保持字段顺序成为其自带要求。

如果用户有保持字典次序的需求,请使用基于Python 3.7或更新版本的COPT python包。 例如,下面的程序如果是在Python 2.7里运行:

m = Envr().createModel("customized model")
vx = m.addVars(['hello', 'world'], [0, 1, 2], nameprefix = "X")
# add a constraint for each var in tupledict 'vx'
m.addConstrs(vx[key] >= 1.0 for key in vx)

那么,模型里的约束的次序可能是 {R(hello,1), R(hello,0), R(world,1), R(world,0), R(hello,2), R(world,2)}

尽可能使用quicksum和psdquicksum

COPT的Python接口支持直观地创建线性、二次和半定表达式。对于线性和二次表达式,建议使用 quicksum() 来创建表达式对象; 对于线性和半定表达式,建议使用 psdquicksum() 来创建表达式对象。他们都优化 了表达式项的求和,比直接使用加号运算符在性能上会好很多。

对模型进行批量操作

COPT的Python接口提供相关函数,支持用户方便地对模型进行批量操作,例如:

  • 批量添加一组变量或约束: Model.addVars()/Model.addConstrs()

  • 批量修改变量在模型中的系数 Model.setCoeffs()注意: 待修改变量和约束的下标对不能重复出现);

  • 批量修改变量或约束的名称: Model.setNames()

请参考 Python API参考手册:Model类 查看函数说明。