技术背景

线性规划是常见的问题求解形式,可以直接跟实际问题进行对接,包括目标函数的建模和各种约束条件的限制等,最后对参数进行各种变更,以找到满足约束条件情况下可以达到的最优解。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. HTML <keygen> 标签(👎 已废弃)

    HTML 标签( 已废弃) 该标签在新的 Web 标准中已废弃. <!DOCTYPE html> <html> <head>  <meta charset=& ...

  2. Python Coding Interview

    Python Coding Interview Python Advanced Use enumerate() to iterate over both indices and values Debu ...

  3. Nestjs 上传文件到七牛云

    $ npm install qiniu import * as url from 'url'; import * as qiniu from 'qiniu'; @Post('upload') @Use ...

  4. VAST维萨币二月发行,高倍币重现江湖!

    市场长期的历史经验表明,经营盈利能力最好的企业,经常是那些现在的经营方式与5年前甚至10年前几乎完全相同的企业.这个经营模式放到币圈也是一样的,2020年的挖矿是最火的,这个模式现在在市场也同样受用. ...

  5. 为什么说NGK的去中心化预言机越来越受欢迎?

    2020年区块链市场非常火热,从年初的交易所杠杆,到Defi热潮,一波连着一波,风向不断切换,很多人无奈感叹跟不上时代,很多人欢欣雀跃登上了早班车.随着Defi的不断火热,预言机也进入了大众视野.NG ...

  6. 云原生系列6 基于springcloud架构风格的本地debug实现

    debug是程序员在日常开发中最常使用的操作, 那么,你是如何快速在微服务架构风格下快速debug后端服务呢? 开发现状 开发的理想状态 本地调测的使用步骤 登录智能网关 如果集成开发环境是在本地局域 ...

  7. django学习-4.url动态传值

    1.前言 我们在浏览器访问一个网页A是通过一个指定的url地址去访问的.但在浏览器用一个不存在的url地址去执行访问是打不开正确的网页的,只会打开一个浏览器自带的有错误提示的网页. 在django框架 ...

  8. java基础第12期——反射、注解

    一. 反射 反射: 将类的各个组成部分封装为其他对象. 1.1 获取class对象的方式 Class.forName("全类名"): 将字节码文件加载进内存,返回class对象 多 ...

  9. Redis集群简介及部署

    1简介 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  10. linux调度全景指南