技术背景

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

    2020 Web 全栈面经 1.简历 2. 技术 3. 项目 4. 架构 5. 沟通,协作 6.成长 7. 面试技巧 准备 电话确认,面试流程,五险一金缴纳情况 有无笔试,几轮,面试时间,答复时间 细 ...

  2. React Hooks: useState All In One

    React Hooks: useState All In One useState import React, { useState } from 'react'; function Example( ...

  3. Android APP 多端适配

    Android APP 多端适配 传统的多终端适配方案,是为大尺寸 Pad开发一个特定的 HD版本. 但是目前支持 Android 系统的设备类型越来越丰富,不同类型的设备尺寸也越来越多样化,特定的H ...

  4. 如何用 js 实现一个 bind 函数

    如何用 js 实现一个 bind 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...

  5. alipay 小程序开发教程

    alipay 小程序开发教程 https://opendocs.alipay.com/mini/00ccmd 或访问开放平台:https://opendocs.alipay.com/mini/00cc ...

  6. Flutter:发布包

    [package] 生成包含模块化Dart代码的可共享Flutter项目 [plugin] 生成一个可共享的Flutter项目, 在Dart代码中包含带有API的API, 针对Android的平台特定 ...

  7. CSS前端性能优化

    1.Google 资深web开发工程师Steve Souders对CSS选择器的效率从高到低做了一个排序: 1. id选择器(#myid) 2. 类选择器(.myclassname) 3. 标签选择器 ...

  8. [Python学习笔记]文件的读取写入

    文件与文件路径 路径合成 os.path.join() 在Windows上,路径中以倒斜杠作为文件夹之间的分隔符,Linux或OS X中则是正斜杠.如果想要程序正确运行于所有操作系统上,就必须要处理这 ...

  9. winform导出excel

    public void AllDataSetToExcel(DataSet ds) { string saveFileName = ""; bool fileSaved = fal ...

  10. 死磕Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...