Gurobi笔记(使用手册)
一、基本了解
1、求解范圍
函數(shù)形式可以是高階多項式、對數(shù)、指數(shù)、三角函數(shù)等非線性函數(shù),那么Gurobi 會對這些函數(shù)自動分段線性化進行近似,用戶可以通過參數(shù)來平衡近似的精度和速度。這樣我們就允許在傳統(tǒng)的線性和二次型模型中看到這些非線性函數(shù),大大擴展了Gurobi求解器的適用范圍,而且這些結果也具有全局最優(yōu)性。
2、求解速度
線性規(guī)劃速度 > 0-1 整數(shù)線性規(guī)劃 > 整數(shù)線性規(guī)劃 > 混合整數(shù)線性規(guī)劃 > 非線性規(guī)劃
在現(xiàn)實問題中,應用最廣泛的數(shù)學規(guī)劃問題類型是混合整數(shù)線性規(guī)劃(MILP)。
3、學習資料
- 安裝目錄 examples, docs 目錄下有完整的范例和使用手冊、參考手冊
- 官網(wǎng) www.gurobi.com
- 在線手冊:http://www.gurobi.com/documentation/
- 視頻:http://www.gurobi.com/resources/seminars-andvideos/seminars-videos
- 在線課程:http://www.gurobi.com/academia/for-online-courses
- 中文網(wǎng)站 www.gurobi.cn
二、快速入門
1.常規(guī)步驟
MODEL = gurobipy.Model()#創(chuàng)建模型x = MODEL.addVars(創(chuàng)建變量, vtype=gurobipy.GRB.CONTINUOUS, name="X")#創(chuàng)建變量MODEL.update()#更新變量環(huán)境MODEL.setObjective(創(chuàng)建目標函數(shù), sense=gurobipy.GRB.MINIMIZE)#創(chuàng)建目標函數(shù)MODEL.addConstrs(創(chuàng)建約束條件) #創(chuàng)建約束條件MODEL.optimize() #執(zhí)行最優(yōu)化2.基礎模型
3.詳細步驟
3.1 實例化求解器
MODEL = gurobipy.Model(name="") name 為模塊名默認為空 import gurobipy as GRB MODEL = GRB.Model("Model_name") #創(chuàng)建模型3.2 添加決策變量
(1) 單個變量
x = MODEL.addVar(lb=0.0, ub=gurobipy.GRB.INFINITY, vtype=gurobipy.GRB.CONTINUOUS, name="") lb = 0.0 #變量的下界,默認為 0 ub = GRB.INFINITY: 變量的上界,默認為無窮大 vtype = GRB.CONTINUOUS #變量的類型,默認為連續(xù)型,可改為 GRB.BINARY 0-1變量,GRB.INTEGER 整型 name = "" #變量名,默認為空 x1 = MODEL.addVar(lb=0, ub=1, name="x1")(2) 多個變量
x = MODEL.addVars(*indexes, lb=0, ub=gurobipy.GRB.INFINITY, vtype=gurobipy.GRB.CONTINUOUS, name="") # *indexes 不能含有中文字符 索引的集合x = MODEL.addVars(3, 4, 5, vtype=gurobipy.GRB.BINARY, name="C") # 創(chuàng)建 3*4*5 個變量,使用 x[1,2,3] 進行訪問3.3 更新變量空間
MODEL.update()3.4 添加目標函數(shù)
(1) 單目標函數(shù)
MODEL.setObjective(expression, sense=None) expression #表達式,可以是一次或二次函數(shù)類型 sense #求解類型,可以是 GRB.MINIMIZE(最小值) 或 GRB.MAXIMIZE(最大值) MODEL.setObjective(8 * x1 + 10 * x2 + 7 * x3 + 6 * x4 + 11 * x5 + 9 * x6, GRB.GRB.MINIMIZE)(2) 多目標函數(shù)
MODEL.setObjectiveN(expression, index, priority=0, weight=1.0, abstol=0, reltol=0, name="") expression # 表達式,可以是一次或二次函數(shù)類型 index # 目標函數(shù)對應的序號 (默認 0,1,2,…), 以 index=0 作為目標函數(shù)的值, 其余值需要另外設置參數(shù) priority # 分層序列法多目標決策優(yōu)先級(整數(shù)值), 值越大優(yōu)先級越高 weight #線性加權多目標決策權重(在優(yōu)先級相同時發(fā)揮作用) abstol # 分層序列法多目標決策時允許的目標函數(shù)值最大的降低量 reltol #分層序列法多目標決策時允許的目標函數(shù)值最大的降低比率 reltol*|目標函數(shù)值|注意: 所有的目標函數(shù)都為線性的,并且目標函數(shù)的優(yōu)化方向一致(全部最大化或全部最小化)。可以通過乘以 -1 實現(xiàn)不同的優(yōu)化方向。
1.合成型
# Obj1 = x + y weight = 1 # Obj2 = x - 5 * y weight = -2 # MODEL.setObjectiveN(x + y, index=0, weight=1, name='obj1') # MODEL.setObjectiveN(x -5 * y, index=1, weight=-2, name='obj2') # 即轉化為: (x + y) - 2 * (x - 5 * y) = - x + 11 * y2.分層型
# Obj1 = x + y priority = 5 # Obj2 = x - 5 * y priority = 1 # MODEL.setObjectiveN(x + y, index=0, priority=5, name='obj1') # MODEL.setObjectiveN(x -5 * y, index=1, priority=1, name='obj2') # 即轉化為: 先優(yōu)化 Obj1,再優(yōu)化 Obj2(按照 priority 的大小關系)注意: Gurobi 按照優(yōu)先級大小優(yōu)化(先優(yōu)化Obj1),若沒有設定abstol或reltol,在優(yōu)化低優(yōu)先級目標時,不會改變高優(yōu)先級的目標值。假設Obj1=10,在優(yōu)化 Obj2 時只能在使得 Obj1=10 的所有解中挑選最優(yōu)解
3.混合型
MODEL.setObjectiveN(x + y, index=0, weight=1, priority=5, name='obj1') MODEL.setObjectiveN(x -5 * y, index=1, weight=-2, priority=1, name='obj2') # 則 先優(yōu)化 Obj1 再優(yōu)化 Obj2 最后相加作為目標值, 由于優(yōu)先級不同, weight不會起作用4.獲取目標函數(shù)值
通過參數(shù) ObjNumber 選擇特定的目標,進而獲得對應的目標函數(shù)值。
MODEL.setParam(gurobipy.GRB.Param.ObjNumber, i) # 第 i 個目標 print(MODEL.ObjNVal) # 打印第 i 個值 for i in range(model.NumObj): model.setParam(GRB.Param.ObjNumber, i) print('Obj%d = ' %(i+1), model.ObjNVal)(3) 分段目標函數(shù)
setPWLObj(var,x,y) ? var #指定變量的目標函數(shù)是分段線性 ? x #定義分段線性目標函數(shù)的點的橫坐標值(非減序列) ? y #定義分段線性目標函數(shù)的點的縱坐標值例1:
注意: 對一些非線性模型,可以使用這一功能去線性逼近。
例2:
3.5 添加約束條件
(1) 創(chuàng)建正常約束
MODEL.addConstr(expression, name="") expression # 布爾表達式,可以是一次或二次函數(shù)類型 name # 約束式的名稱# 單個約束 MODEL.addConstr(12 * x1 + 9 * x2 + 25 * x3 + 20 * x4 + 17 * x5 + 13 * x6 >= 60, "c0")# 多個約束 x = MODEL.addVars(20, 8, vtype=gurobipy.GRB.BINARY) # 寫法 1 for i in range(20):MODEL.addConstr(x.sum(i, "*") <= 1) # 寫法 2 MODEL.addConstrs(x.sum(i, "*") <= 1 for i in range(20)) # 寫法 2 的等價寫法: MODEL.addConstrs(sum(x[i, j] for j in range(8) <= 1 for i in range(20))(2) 創(chuàng)建廣義約束
1. 最大值Max
addGenConstrMax(resvar, vars, constant, name ) ? resvar 變量(x = max(x1,x2,10)) ? vars 一組變量(可以包含常數(shù)) ? constant 常數(shù) ? name 廣義約束名稱例如: z = max(x, y, 3)
m.addGenConstrMax(z, [x, y], 3, "maxconstr") m.addGenConstrMax(z, [x, y, 3], name="maxconstr")換成一般的約束表達方式:
m.addConstr(z == max_([x, y, 3]), "maxconstr") m.addConstr(z == max_(x, y, 3), "maxconstr")2. 最小值Min
addGenConstrMin( resvar, vars, constant, name ) ? resvar 變量(x = min(x1,x2,10)) ? vars 一組變量(可以包含常數(shù)) ? constant 常數(shù) ? name 廣義約束名稱例如: z = min(x, y, 3)
m.addGenConstrMin(z, [x, y], 3, "minconstr") m.addGenConstrMin(z, [x, y, 3], name="minconstr")換成一般的約束表達方式:
m.addConstr(z == min_([x, y, 3]), "minconstr") m.addConstr(z == min_(x, y, 3), "minconstr")3. 絕對值Abs
addGenConstrAbs( resvar, argvars, name ) ? resvar 變量 ? argvar 變量 ? name 廣義約束名稱例如: x = |y|
m.addGenConstrAbs(x, y, "absconstr")換成一般的約束表達方式:
m.addConstr(x == abs_(y), "absconstr")4. 和
一組變量的值全等于1,則取1,否則取0。
addGenConstrAnd( resvar, vars, name ) ? resvar 變量 ? vars 一組變量 ? name 廣義約束名稱例如: x = 1且y = 1,那么z = 1,否則 z = 0
m.addGenConstrAnd(z, [x,y], "andconstr")換成一般的約束表達方式:
m.addConstr(z == and_(x, y), "andconstr")5. 與
一組變量的值有一個等于1,則取1,否則取0。
addGenConstrOr( resvar, vars, name ) ? resvar 變量 ? vars 一組變量 ? name 廣義約束名稱例如: x = 0且y = 0,那么z = 0,否則 z = 1
m.addGenConstrOr(z, [x,y], "orconstr")換成一般的約束表達方式:
m.addConstr(z == or_(x, y), "orconstr")6. 范圍約束
MODEL.addRange(expression, min_value, max_value, name="") # 表達式 min_value<=expression<=max_value 的簡寫, 但這里的 min_value, max_value 必須是具體的實數(shù)值, 不能含有變量例如: 5 <= x + y + z <= 10
m.addRange(x+y+z, 5, 10, "c")換成一般的約束表達方式:
m.addConstr(x+y+z==[5,12])7. 指示變量
MODEL.addGenConstrIndicator(binvar, binval, expression, name="") # 指示變量 binvar 的值取 binval 時, 進行約束 expression # 指示變量的值為1,約束成立,否則約束可以被違反。 # 案例: 如果生產(chǎn)某一類型汽車 (x[i] > 0), 則至少要生產(chǎn) 80 輛 # %% 方法一 for i in range(3):MODEL.addGenConstrIndicator(y[i + 1], 0, x[i + 1] >= 80)MODEL.addGenConstrIndicator(y[i + 1], 1, x[i + 1] == 0)# 以上代碼等價于 for i in range(3):MODEL.addConstr(x[i + 1] >= 80 * y[i + 1])MODEL.addConstr(x[i + 1] <= 1000 * y[i + 1])例2: 如果 z = 1,則 x+y <= 4
m.addGenConstrIndicator(z, True, x + y, GRB.LESS_EQUAL, 4, 'indicator')換成一般的約束表達方式:
m.addConstr((z == 1) >>(x + y<= 4))3.6 執(zhí)行最優(yōu)化
MODEL.Params.LogToConsole=True # 顯示求解過程 MODEL.Params.MIPGap=0.0001 # 百分比界差 MODEL.Params.TimeLimit=100 # 限制求解時間為 100s MODEL.Params.Presolve = -1 # 預處理程度, 0關閉,1保守,2激進 MODEL.Params.MIPFocus = 0 # 求解側重點. 1快速找到可行解, 2證明最有, 3側重邊界提升, 0均衡搜索 MODEL.Params.SolutionLimit = inf # 求解數(shù)量, 默認求所有解, 比較出最優(yōu)的結果, 只需要可行解時可以設置該參數(shù)為1 MODEL.Params.NonConvex = 1 # 默認求解器,改為 2 時可以解決非凸二次優(yōu)化問題 ? MODEL.optimize()整數(shù)規(guī)劃/混合整數(shù)規(guī)劃問題評價準則: 百分比界差
OPT 為當前的最優(yōu)解,LP 為去掉整數(shù)約東后的松弛最優(yōu)解百分比界差是數(shù)學規(guī)劃領域常用的評價參數(shù),具體可視為在去除問題參數(shù)整數(shù)取值的限制后,問題松弛解與最優(yōu)解之間的絕對差距
3.7 查看模型結果
#單目標獲得目標值和單個變量值 print("Obj = ",m.ObjVal) for i in range(N): print(y[i].VarName,' = ',y[i].x) # 查看多個變量取值 for var in MODEL.getVars():print(f"{var.varName}: {round(var.X, 3)}") # 查看多目標規(guī)劃模型的目標函數(shù)值 for i in range(MODEL.NumObj):MODEL.setParam(gurobipy.GRB.Param.ObjNumber, i)print(f"Obj {i+1} = {MODEL.ObjNVal}")三、常用的線性化方法
1. 最大值Max
2. 最小值Min
3. 絕對值Abs
4. Maxmin/Minmax目標函數(shù)
5. 帶fixed cost目標函數(shù)
6. 分式目標函數(shù)
7. 邏輯或
8. 乘積式
9. 分段整數(shù)變量
四、進階
(1) 列表、元組和字典建模
在建模過程中,經(jīng)常要對帶下標數(shù)據(jù)做挑選,不同下標的數(shù)據(jù)進行組合,這樣面臨著二個處理方法。
這樣的處理方法沒有效率
如果我們使用Gurobi對其進行建模,一般有下面3(或者說4)種方法:
- 按行建模:逐行進行建模。通過使用quicksum 或者創(chuàng)建表達式LinExpr對象結合addTerms,拼湊表達式,最后使用Model.addConstr完成添加約束的操作,從而完成建模;
- 按列建模:逐列進行建模。通過創(chuàng)建Column對象,使用addTerms函數(shù)拼湊好Column對象,最后使用Model.addVar函數(shù)直接完成建模。
- 按非零系數(shù)建模:類似于逐列進行建模,可以使用addTerms拼湊表達式。具體實現(xiàn)跟按行建模類似。
- 按矩陣方式建模:通過拼湊約束系數(shù)矩陣,然后將決策變量轉化為MVar的對象,最后直接使用重載運算符@完成約束的添加,即如Model.addConstr(A @ x == b),就可以完成建模。
列表、元組和字典建模優(yōu)點
- 添加約束代碼量少,只需要拼湊好系數(shù)矩陣,即可一行代碼搞定約束的添加;
- 便于直接得到對偶問題的系數(shù)矩陣,從而快速得到對偶問題的具體形式。
列表、元組和字典建模缺點
-
對于約束系數(shù)稀疏的模型,會占用不必要的內(nèi)存來存儲那些系數(shù)為0的部分,模型較大時,有可能導致內(nèi)存溢出;
-
雖然可以得到對偶問題的具體形式,但是對偶問題的公式形式卻不能得出(這個嚴格來講不算是這種建模方式的缺點)。
-
不方便對每個決策變量賦予獨一無二的變量名。
import gurobipy as grb import numpy as npif __name__ == "__main__":m = grb.Model("LP")m.setParam('OutputFlag', 1)x = m.addMVar(2, lb=0, ub=grb.GRB.INFINITY)c = np.array([[3, 5]])A = np.array([[1, 0],[0, 2],[3, 2]])b = np.array([4, 12, 18])m.addConstr(A @ x <= b)m.Params.timelimit = 9999999999999999999999m.setObjective(c @ x, grb.GRB.MAXIMIZE)m.update()m.optimize()print('x_1={}'.format(x[0].x))print('x_2={}'.format(x[1].x))
例題
(2) 初始解設置
求解器支持用戶向模型輸入一個或多個已知的全部或部分可行解(一個可行解包括了模型所有變量的取值)。例如,當前問題的可行方案,以及用戶通過其他算法獲得的可行解等,都可以直接輸入給求解器以期加速或幫助求解器進行求解。
- 利用決策變量的Start屬性直接設置變量的初始值
# 將變量x_1_12的初值設置為0 x[0,12].start = 1.0# 循環(huán)為x_ij賦值完整的一組初始解,data為存放初始解的矩陣 for i in range(len(data)):for j in range(len(data[i])):x[i,j].start = data[i][j]
詳細參考:https://mp.weixin.qq.com/s/R76jmojKGqm6ZC1dy7hSQQ
(3) Solution Pool
3.1 什么是Solution Pool
在默認狀態(tài)下,Gurobi的目標是為具有單一目標函數(shù)的MIP模型尋找一個最優(yōu)解。然而在Gurobi的branch and cut算法迭代的過程中,可能會通過啟發(fā)式算法(也就是求解日志行首標注為H的行)得到整數(shù)可行解,也有可能通過分支切割得到整數(shù)可行解(也就是求解日志行首標注*的行)。所以在求解MIP的過程中,求解器往往會得到多個次優(yōu)的可行解(Sub-Optimal Solutions)。
Solution Pool(以下簡稱Pool)顧名思義就是將迭代過程中產(chǎn)生的整數(shù)可行解存儲下來的集合。(solution pool存儲的只是一部分整數(shù)可行解,并不是MIP的所有可行解)。許多情況下這些可行解能夠為我們提供有價值的信息,因此為方便用戶了解這些解的具體情況,Gurobi提供了Solution Pool一系列相關的操作方法。
3.2 Solution Pool參數(shù)與屬性
Solution Pool相關Parameters:
具體可參考該文章:https://zhuanlan.zhihu.com/p/545591977
五、數(shù)學模型
1. 線性規(guī)劃
-
例1. 最簡單的線性規(guī)劃模型
from gurobipy import * # 在Python中調(diào)用gurobi求解包 M_LP=Model("LP_Exam") # 創(chuàng)建模型# 變量聲明 OF =M_LP.addVar(lb=-GRB.INFINITY,ub=GRB.INFINITY, name="OF") x1 =M_LP.addVar(lb=-GRB.INFINITY,ub=GRB.INFINITY, name="x1") x2 =M_LP.addVar(lb=-GRB.INFINITY,ub=GRB.INFINITY, name="x2") x3 =M_LP.addVar(lb=-GRB.INFINITY,ub=GRB.INFINITY, name="x3")# 設置目標函數(shù) M_LP.setObjective(x1+3*x2+3*x3,GRB.MINIMIZE)# 添加約束 M_LP.addConstr(x1+2*x2>=3,"Con1") M_LP.addConstr(x2+x3>=5,"Con2") M_LP.addConstr(x1+x3==4,"Con3")# Optimize model M_LP.optimize() # 輸出名為‘LP_Expression’的 .lp文件 M_LP.write("LP_Expression.lp") # 輸出結果 print('**************') print(' The optimal solution ') print('**************') print('OF is :',M_LP.ObjVal) # 輸出目標值 print('x1 is :',x1.x) # 輸出 X1 的值 print('x2 is :',x2.x) print('x3 is :',x3.x)
-
例2. 具有邊界的變量
2. 混合整數(shù)線性規(guī)劃
-
例1.
M_LP=Model("LP_Exam2")N_i=4N_j=4# 設置變量x =M_MIP.addVars(N_i,N_j,vtype=GRB.BINARY, name="x")# 設置約束M_MIP.addConstrs((sum(x[i,j] for j in range(N_j))<=1 for i in range(N_i)),"Con1")M_MIP.addConstrs((sum(x[i,j] for i in range(N_i))<=1 for j in range(N_j)),"Con2")# 匯總解x_c=np.zeros((N_i,N_j))for i in range(N_i):for j in range(N_j):x_c[i,j]=x[i,j].x3. 非線性規(guī)劃
在新的Gurobi求解器(9.0以上版本)中,包含了非線性/非凸問題的求解。注意:
- 需要設置參數(shù)’NonConvex=2’;
- Gurobi接受的冪函數(shù)中,次數(shù)最大值為2.
- 雖然有解,但不一定是最優(yōu)值。
- 求解時間看模型規(guī)模。
例1. 多個線性變量相乘
解決辦法:添加中間變量from gurobipy import *# 創(chuàng)建模型 M_NLP=Model("NLP")# 變量聲明 x1 =M_NLP.addVar(lb=1,ub=3, name="x1") x2 =M_NLP.addVar(lb=1,ub=3, name="x2") x3 =M_NLP.addVar(lb=1,ub=3, name="x3") x4 =M_NLP.addVar(lb=1,ub=3, name="x4")y14 =M_NLP.addVar(lb=0,ub=300, name="y14") y23 =M_NLP.addVar(lb=0,ub=300, name="y23")# 設置目標函數(shù) M_NLP.setObjective(y14*(x1+x2+x3)+x2,GRB.MAXIMIZE)# 添加約束 M_NLP.addConstr(y14*y23>=20,"Con1") M_NLP.addConstr(x1*x1+x2*x2+x3*x3+x4*x4==30,"Con2")# 表示乘積項 M_NLP.addConstr(y14==x1*x4,"Con_y14") M_NLP.addConstr(y23==x2*x3,"Con_y23")M_NLP.Params.NonConvex=2 ###求解重點# Optimize model M_NLP.optimize()M_NLP.write("NLP.lp")print('**************') print(' The optimal solution ') print('**************') print('Obj is :',M_NLP.ObjVal) # 輸出目標值 print('x1 is :',x1.x) # 輸出 x1 的值 print('x2 is :',x2.x) # 輸出 x2 的值 print('x3 is :',x3.x) # 輸出 x3 的值 print('x4 is :',x4.x) # 輸出 x4 的值
總結
以上是生活随笔為你收集整理的Gurobi笔记(使用手册)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单据模板显示公式使用
- 下一篇: C语言《检测按键》