在docker容器中使用cplex-python37


技術背景

線性規划是常見的問題求解形式,可以直接跟實際問題進行對接,包括目標函數的建模和各種約束條件的限制等,最后對參數進行各種變更,以找到滿足約束條件情況下可以達到的最優解。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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM