我最近在研究一個問題的解決方案時,找到了一種基於最優化理論的方法。即通過「定義目標函數」—「給出約束條件」—「找到最優解」的流程找到問題的答案。由於目標函數中存在二次項,且變量從{0,1}中取值,因此,該問題屬於目標函數中含有二次項的混合整數規划問題,簡稱MIQP(mixed integer programs with quadratic terms in the objective function)。
老實講,我已經把原本就學得不是很好的運籌學知識全部還給老師了,現在能記住的,除了「分支定界」、「模擬退火」等少數幾個算法的名稱外,就只剩下課本黃色的封皮了。於是,趁着這個機會,我查了一些資料,首先解決「怎么用」的問題,然后再研究如何去優化。
1、利用Pyomo來進行建模
1.1 Pyomo簡介
在學生時代,用的最多的工具非MATLAB莫屬了,由於集成了各種工具箱,它的功能確實非常強大。不過,我所尋找的解決方案(如果成功驗證后)是要集成到產品中去的,在軟件許可方面可能會遇到問題。隨着開源軟件的崛起,一些優秀的項目在性能和易用性等方面已經不輸商業軟件了。因此,為了實現這個方案,我的第一想法就是搜索看是否有用python開發的解決方法。
接下來就發現了Pyomo這個軟件包。從其主頁描述可以知道,它可以用來定義、求解和分析各種優化問題的模型。包括:
- 線性規划
- 二次規划
- 非線性規划
- 混合整數線性規划
- 混合整數二次規划(這個就是我的場景)
- 混合整數非線性規划
更多支持問題的類型,可以從主頁獲取。
需要注意的是,上面說的定義模型,指的是Pyomo有一套自己的語言來將數學中用各種符號描述的優化模型程序化,從而使之符合python的語法要求;而求解實際上是利用了第三方的解算器。也就是說,Pyomo本身不具備求問題解的功能,而是定義了一套規范,並調用其他的解算器來求解。
我理解的這樣做的好處在於,不同的解算器有着不同的使用方法,而Pyomo對這些接口進行了規范化,從而使用戶更關注於模型本身;此外,python代碼所具備的高可讀性,也更容易讓人將數學模型轉化為代碼腳本。
1.2 Pyomo安裝
可以使用conda或者pip來進行安裝,與安裝其他的第三方python包並無區別。
強烈建議在安裝前先創建一個干凈的虛擬環境,這對於包的管理是非常方便的。特別是——在后面會看到——對於這種會利用其他第三方軟件包(解算器)的軟件包!
1.3 示例
直接給出官網的一個簡單示例:
import pyomo.environ as pyo
# 創建一個模型實例
model = pyo.ConcreteModel()
# 向模型實例添加變量,x是變量組成的向量,維度是2,並且,每個變量都是非負實數
model.x = pyo.Var([1, 2], domain=pyo.NonNegativeReals)
# 向模型實例添加目標函數,目標函數是由向量中的各個變量與其系數組成
model.OBJ = pyo.Objective(expr=2 * model.x[1] + 3 * model.x[2])
# 添加約束,由於在添加變量的時候已經指定了非負實數,因此,這里的約束條件只剩下一個了
model.Constraint1 = pyo.Constraint(expr=3 * model.x[1] + 4 * model.x[2] >= 1)
模型構建好了以后,接下來就是調用解算器進行求解了。這一步只需要兩行代碼:
opt = pyo.SolverFactory('glpk')
opt.solve(model)
第一行,實例化了一個解算器,並指定了利用“glpk”這個解算器;第二行,調用解算器的solve方法,對模型進行求解。
前面提到,解算器是需要額外安裝的。因此,如果不在環境中安裝“glpk”這個解算器,那么上述代碼是會報錯的,所以,需要首先安裝glpk。
glpk是一個開源軟件,用於解決大規模的線性規划、混合整數規划等問題。可以直接利用conda進行安裝:
conda install glpk
安裝完成后,上述代碼就可以成功運行。求解完成后,我們可以通過下述代碼獲取到最優解:
print('x1: ', pyo.value(model.x[1]))
print('x2: ', pyo.value(model.x[2]))
打印的內容:
x1: 0.333333333333333
x2: 0.0
1.4 總結
從上面的過程可以看出,利用Pyomo求解的基本過程就是:「建立模型」—「調用解算器」—「得到結果」。針對不同類的問題,建模的過程會有所不同。
2、解算器
上面提到的“glpk”是解算器的一種,但它仍有一定的限制:
- 不能解決非線性規划問題
- 與商業的解算器相比仍有一定的性能差距
為了解決我的問題,必須尋求其他的解算器,在參考的論文中,作者使用的是GAMS平台的CPLEX解算器。
CPLEX是IBM推出的一款用於構建和求解大規模、復雜的優化模型的產品。准確來說,產品的名稱是:IBM ILOG CPLEX Optimization Studio,分為試用版和付費版兩種。按照國外產品一貫的行為標准,試用版對問題規模有限制,付費版沒有限制可價格很貴。這里我使用的是試用版。
實際上,完全可以把我的模型用IBM的產品寫出來(即不用python),但這樣的話發布可調用的API就成了一個問題。所以,我還是選擇用Pyomo寫模型,然后調用IBM的求解器。
不過我找了一圈,貌似沒有直接的CPLEX求解器文件可供下載,這也是可以理解的,畢竟人家是一個完整的產品,不太可能將產品的零部件拆出來供人下載。所以,要想利用這個求解器,就得先安裝整個試用版的軟件,然后從軟件安裝目錄里把求解器模型找到。
我用的是mac,安裝好之后,求解器文件的位置是:/Applications/CPLEX_Studio_Community201/cplex/bin/x86-64_osx,其中有一個cplex的可執行文件,這就是我們要找的模型文件了,將其拷貝出來,然后在代碼中指定好位置即可,像下面這樣:
opt = pyo.SolverFactory('cplex', executable='/path/to/models/cplex')
