技术背景

线性规划是常见的问题求解形式,可以直接跟实际问题进行对接,包括目标函数的建模和各种约束条件的限制等,最后对参数进行各种变更,以找到满足约束条件情况下可以达到的最优解。Cplex是一个由IBM主推的线性规划求解器,可以通过调用cplex的接口,直接对规定形式的线性规划的配置文件.lp文件进行求解。这里我们介绍一下,基于docker来调用cplex的python接口,对线性规划问题进行求解。

基于Docker部署Cplex环境

由于cplex依赖于python3.7版本,而我们本地使用的python版本是python3.8,因此我们考虑使用docker容器来制作一个python37+cplex的容器镜像,用于计算线性规划的问题。关于docker容器的使用,在另外3篇博客(博客1博客2博客3)。首先我们在dockerhub上面找一个python37的镜像:



这里我们习惯性的选择星星最高的那个,然后下载到本地:

[dechin-root cplex]# docker pull rackspacedot/python37
Using default tag: latest
latest: Pulling from rackspacedot/python37
Digest: sha256:5ae238bd5d6b06af739ac1b2666111955966d563cb6aea8b366fb446425eb299
Status: Downloaded newer image for rackspacedot/python37:latest
docker.io/rackspacedot/python37:latest

下载完成后,可以在本地的镜像仓库中看到这个新的镜像:

[dechin-root cplex]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rackspacedot/python37 latest ab7083b6c7c4 3 months ago 1.02GB

下载完成后我们可以进入这个镜像,用pip安装一个最新的cplex。其实cplex的安装还是非常简单的,只是对于python的版本有要求而已。

[dechin-root cplex]# docker run -it rackspacedot/python37 /bin/bash
root@c766ed62d149:/# python3 -m pip install cplex
Collecting cplex
Downloading cplex-20.1.0.1-cp37-cp37m-manylinux1_x86_64.whl (30.9 MB)
|████████████████████████████████| 30.9 MB 347 kB/s
Installing collected packages: cplex
Successfully installed cplex-20.1.0.1

安装完成后,我们可以进入python3的命令行界面,测试一下cplex的安装情况:

root@c766ed62d149:/# python3
Python 3.7.9 (default, Nov 18 2020, 14:29:12)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cplex
>>> exit()

这里如果没有报错,就表示安装成功了。那么最后,我们需要把刚才对容器镜像的修改永久的保留下来,我们先用ps查看刚才的修改被保存到哪里:

[dechin-root cplex]# docker ps -n 2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c766ed62d149 rackspacedot/python37 "/bin/bash" 2 minutes ago Exited (0) 6 seconds ago xenodochial_ardinghelli
af037db88540 cplex "/bin/bash" 48 minutes ago Up 48 minutes magical_cori

在过去的2条记录中我们发现对容器镜像的修改被保存到c766开头的容器中,这时我们可以直接对这个编号的容器进行提交保存:

[dechin-root cplex]# docker commit c766 cplex-py37
sha256:34e2729697010b1320c2f7dbfd1fc45004e9ffae6a1d26ffb8748b5627cb2224

如果出现以上的反馈,就表示我们成功的把刚才下载cplex的这一修改永久的保存进cplex-py37这个新容器中,这样就可以在本地的容器仓库里面看到这个新的容器:

[dechin-root cplex]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
cplex-py37 latest 34e272969701 About a minute ago 1.15GB

到这里,我们使用docker部署的cplex求解器的环境就已经完成了,下一步我们用真实的线性规划的问题来进行测试。

线性规划问题求解

上面的章节主要是为了展示基于docker的cplex环境部署,用同样的方法我们此前已经制作好了一个名为cplex的容器镜像,这里我们直接用来测试。容器的拉起方法,要绑定本地存放有线性规划问题定义的文件所在的目录:

[dechin-root cplex]# docker run -it -v /home/dechin/projects/2021-quantum/cplex/:/home/ cplex /bin/bash

线性规划问题定义

Cplex可以识别lp格式的文件,这里我们展示一个测试用例来说明这个线性规划的问题是如何定义的:

[dechin-root cplex]# cat test.lp
Maximize
obj: 2 x1 + 3 x2 + 4 x3
Subject To
c1: 3 x1 + 4 x2 + 5 x3 <= 8
Bounds
0 <= x1 <= 1
0 <= x2 <= 1
0 <= x3 <= 1
Binary
x1 x2 x3
End

在这个问题中,我们的目标是优化这样的一个函数:

\[max\{2x_1+3x_2+4x_3\}
\]

就是找这么一个函数的最大值,这些参数\(x_1,x_2,x_3\)都是二元变量,即\(x\in\{0,1\}\),而且需要满足给定的约束条件:

\[3x_1+4x_2+5x_3\leq8
\]

问题解析与代码求解

其实这是一个典型的单背包问题的案例:给定一个承重量为8的背包,需要装3个物品\(\{x_1,x_2,x_3\}\)中的某几个拿去卖。这三个物品的重量分别是\(\{3,4,5\}\),因此我们没办法将所有的物品一次性装到包里面,因为这会超过背包的承重量。而这3个物品的收益分别是\(\{2,3,4\}\),对于这个问题来说,就是要最大化这个收益。比如说,我们只装\(x_1,x_2\)两个物品,也就是\(x_1=1,x_2=1,x_3=0\),那么总重量是7,并没有超过背包的承重量,而总的收益是5。这是一组可行解,但不一定是最优解,接下来我们看看cplex是否有可能找到这个问题的最优解。

root@af037db88540:/home# python3
Python 3.7.9 (default, Nov 18 2020, 14:29:12)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cplex
>>> lp = cplex.Cplex() # 初始化对象
>>> lp.read('test.lp') # 读取线性规划文件
>>> lp.solve() # 求解
Version identifier: 12.10.0.0 | 2019-11-27 | 843d4de
CPXPARAM_Read_DataCheck 1
Found incumbent of value 0.000000 after 0.00 sec. (0.00 ticks)
Tried aggregator 1 time.
MIP Presolve eliminated 1 rows and 3 columns.
MIP Presolve modified 3 coefficients.
All rows and columns eliminated.
Presolve time = 0.00 sec. (0.00 ticks) Root node processing (before b&c):
Real time = 0.00 sec. (0.00 ticks)
Parallel b&c, 8 threads:
Real time = 0.00 sec. (0.00 ticks)
Sync time (average) = 0.00 sec.
Wait time (average) = 0.00 sec.
------------
Total (root+branch&cut) = 0.00 sec. (0.00 ticks)
>>> lp.solution.get_objective_value() # 获取求解的目标函数值
6.0
>>> lp.solution.get_values() # 获取最终的参数值
[1.0, 0.0, 1.0]

这个示例中我们将每一步的含义都直接注释在代码中,我们直接调用cplex的接口,写好lp文件,就可以很轻松的进行求解了。得到的最终的解是\(\{1,0,1\}\),也就是总重量为8,未超过承重量,而总收益为6,高于我们刚才手工找到的可行解的收益值。同时这也是这个问题的唯一最优解,这一点其实我们可以手工验证。

总结概要

在这篇文章中我们介绍了如何使用docker去搭建一个cplex线性规划求解器的编程环境,制作完docker容器,我们也展示了如何写一个线性规划问题定义的文件,并使用cplex对给定一个背包问题的线性规划(实际上是一个二元规划问题)文件进行求解。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/cplex.html

作者ID:DechinPhy

更多原著文章请参考:https://www.cnblogs.com/dechinphy/

参考链接

  1. https://blog.csdn.net/qq_33670304/article/details/102882863

在docker容器中使用cplex-python37的更多相关文章

  1. Docker容器中运行ASP.NET Core

    在Linux和Windows的Docker容器中运行ASP.NET Core 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott Hanselman就捷足先登了. ...

  2. 在 docker 容器中捕获信号

    我们可能都使用过 docker stop 命令来停止正在运行的容器,有时可能会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程.这些操作的本质都是通过从主机向容器发送信号 ...

  3. Docker容器中开始.NETCore之路

    一.引言 开始写这篇博客前,已经尝试练习过好多次Docker环境安装,.Net Core环境安装了,在这里替腾讯云做一个推广,假如我们想学习.练手.net core 或是Docker却苦于没有开发环境 ...

  4. 隔离 docker 容器中的用户

    笔者在前文<理解 docker 容器中的 uid 和 gid>介绍了 docker 容器中的用户与宿主机上用户的关系,得出的结论是:docker 默认没有隔离宿主机用户和容器中的用户.如果 ...

  5. Docker容器中开始.Net Core之路

    开始写这篇博客前,已经尝试练习过好多次Docker环境安装,.Net Core环境安装了,在这里替腾讯云做一个推广,假如我们想学习.练手.net core 或是Docker却苦于没有开发环境,服务器也 ...

  6. Docker容器中找不到vim命令

    docker容器中,有的并未安装vi和vim,输入命令vim,会提示vim: command not found(如下图).此时我们就要安装vi命令 执行命令:apt-get update apt-g ...

  7. docker容器中Postgresql 数据库备份

    查看运行的容器: docker ps 进入目标容器: docker exec -u root -it 容器名 /bin/bash docker 中,以root用户,创建备份目录,直接执行如下命令, p ...

  8. .NetCore下使用IdentityServer4 & JwtBearer认证授权在CentOS Docker容器中运行遇到的坑及填坑

    今天我把WebAPI部署到CentOS Docker容器中运行,发现原有在Windows下允许的JWTBearer配置出现了问题 在Window下我一直使用这个配置,没有问题 services.Add ...

  9. 一个docker容器中运行多个服务还是弄一堆docker容器运行?

    不建议直接在单个 Docker 容器中运行多个程序. 以 2017年 10 月18 日 Docker 官方支持 Kubernetes 为分水岭计算,Kubernetes 赢得容器编排之战的最终胜利已经 ...

随机推荐

  1. JavaScript 词法 All In One

    JavaScript 词法 All In One JavaScript 词法 这部分描述了JavaScript 的词法(lexical grammar). ECMAScript 源码文本会被从左到右扫 ...

  2. WebSocket All In One

    WebSocket All In One WebSocket heartbeat WebSocket 心跳检测 ping pong refs xgqfrms 2012-2020 www.cnblogs ...

  3. CSS Learning Paths

    CSS Learning Paths CSS Expert refs https://developer.mozilla.org/en-US/docs/Web/CSS https://css-tric ...

  4. React Hooks in depth

    React Hooks in depth React Hooks https://reactjs.org/docs/hooks-rules.html https://www.npmjs.com/pac ...

  5. git in depth

    git in depth git delete remote branch # Deleting remote branches in Git $ git push origin --delete f ...

  6. 软件工程中的CI&CD

    wiki 在软件工程中,CI/CD或CICD通常是指持续集成以及持续交付或持续部署的组合实践 持续集成 在软件工程中,持续集成(CI)是每天将所有开发人员的工作副本合并到共享主线中的一种做法.[1] ...

  7. express+apollo+mongodb

    阿波罗服务器入门 λ yarn add --dev @babel/core @babel/cli @babel/preset-env λ yarn add --dev nodemon // " ...

  8. css整理之-----------布局相关

    文档流 文档流指的是元素排版布局过程中,元素会默认自动从左往右,从上往下的流式排列方式布局,文档流可以分为定位流.浮动流.普通流三种 普通流(Normal flow) 在常规流中,盒一个接着一个排列, ...

  9. django学习-21.优化表数据的标题展示

    目录结构 1.前言 2.表数据的标题默认展示的数据格式是[模型类名 object(主键名)]的相关信息 3.优化表数据的标题展示的数据格式是[改成我们想要展示的数据格式]的相关完整操作步骤 3.1.第 ...

  10. .Net Core 3.1浏览器后端服务(三) Swagger引入与应用

    一.前言 前后端分离的软件开发方式已逐步成为互联网项目开发的业界标准,前后端分离带来了诸多好处的同时,也带来了一些弊端. 接口文档的维护就是其中之一,起初前后端约定文档规范,开发的很愉快,随着时间推移 ...