優化是各種行業和学科中使用的基礎工具,旨在給定的限制內做出最有可能的決策。無論是在供應鏈中減少成本,还是在能源系統中最大化效率,或者在機器學習模型中找到最佳參數,優化技術都是必不可少的。
Python以其簡潔和多用途而聞名,為優化問題提供了強大的庫。這些庫中,Pyomo是一個全面且靈活的庫,允許用戶无缝地定義和解決複雜的優化模型。
在這個教程中,我們將從基礎開始探索Pyomo。我們將涵蓋從安裝和設置求解器到 formulation 和解決不同的優化問題的一切!
在線性規劃中探索可行的解決方案。圖片作者。
Pyomo是什麼?
Pyomo 是一個開源庫,用於使用 Python 建立和解決優化模型的問題。它讓您以既嚴謹又對 Python 程式員而言 intuitive 的方式定義優化模型。它支持的問題類型非常廣泛,包括:
- 線性規劃 (LP):LP 涉及在最優化線性目標函數的前提下,考慮線性等式和不等式約束。它廣泛用於資源分配、計劃和財務計劃問題。
- 非線性規劃 (NLP): NLP 是針對優化非線性目標函數和非線性限制的領域。它通常用於工程和經濟學中,用於較為複雜的系統,其中關係不是線性的。
- 混合整數規劃 (MIP):MIP 涉及一些變量必須為整數,其他則可以是連續的 optimization problems。這在供應鏈設計或項目排程等情境中很有用,因為這些決定可以是離散的 (例如,開/關)。
- 隨機 Programming: 隨機 Programming 處理一些元素不确定的優化問題,並將這些不確定元素建模為隨機變量。它常應用於金融和供應鏈管理,以在不確定性下優化決策。
- 动态優化: 動態優化着重於随时间优化決策變量,通常涉及时动态演化的系統。它被用在像是過程控制、机器人學和經濟學等領域,以管理與時間相關的過程。
Pyomo的特點
既然我們更了解Pyomo了,讓我們回顧一下它最重要的特點。
靈活性与擴展性
Pyomo的靈活性來自於它使用標準Python結構來模擬複雜關係的能力。它與各種開源和商業解決方案結合,使得解決许多優化問題變得簡單。
Pythonic語法
Pyomo模型的建設基於Python,並使用標準Python語法撰寫。這使得熟悉Python的人學習曲線溫和地方,並允許您在您的模型中使用Python的廣泛庫。
強大的社群和 文档
Pyomo擁有強健的用戶社群和全面的 文档,其中包括示例和教程來幫助所有等級的用戶。
Pyomo的 使用案例
Pyomo在現實世界中具有廣泛的應用。以下是一些例子:
1. 供應鏈優化
供應鏈優化涉及改善物流、管理庫存水平以及創造有效的生產計劃。
這可能包括最小化運輸成本、優化倉庫位置或平衡供給和需求。
例如,一家公司可能需要在全球多個地區滿足客戶需求,同時最小化運送成本並维持每個分銷中心的庫存水平。
2. 財務建模
在財務建模中,優化有助於分配資源,例如資本,以最大化回報同時最小化風險。
這可以涉及投資組合優化,其中投資者通過選擇受預算限制、法規要求或風險容忍度等約束的資產組合,來平衡風險和回報。
財務模型確保財務策略與長期目標一致,同時降低潛在風險。
3. 能源系統
能源系統的優化專注於最大化發電、分配和消耗效率。
這可能涉及確定最佳的能源來源組合(例如,可再生能源與非可再生能源),同時降低燃料成本,滿足排放限值,並適應波動的需求。
這類優化在電網管理、發電廠運營及減少環境影響方面扮演著核心角色。
4. 機器學習和數據科學
優化在許多機器學習和數據科學任務中是核心,例如超參數調整和特徵選擇。
在超參數調節中,優化算法幫助尋找最佳模型的配置以提高預測性能。
另一個關鍵任務是特徵選擇,它涉及識別對模型準確性有最重要貢獻的特徵,幫助減少複雜性並提高效率。
既然已經 setting the context,讓我們開始實際操作並將 Pyomo 應用於一些示例建模問題!
設定 Pyomo
在我們開始建模之前,我們需要通過安裝 Pyomo 和選擇一個合適的求解器來設定我們的環境。
1. 前提條件
要使用 pyomo,您必須有 Python 3.6 或更高版本。Pyomo 可以通过 pip 安装。
pip install pyomo
本教程是使用 Pyomo 版本 6.8.0
創建的。
import pyomo print(pyomo.__version__)
輸出:
>>> 6.8.0
2. 選擇和安裝正確的求解器
在優化過程中,求解器是不可或缺的,因為它們是尋找您定義問題的最佳解決方案的算法。不同的求解器根據問題類型(如線性、非線性、整數)而有不同的適合性。Pyomo 是一個建模工具,它依賴於外部求解器來進行實際的計算。
讓我們回顧一些最常見的求解器。
開源求解器
1. GLPK(GNU 線性規劃套件)
GLPK 是一款popularly 用于解线性规划(LP)和混合整数规划(MIP)問題的tool。
它對於基本的线性優化任務來說是excellent 的選擇,並且在academic 和industrial 應用中都被广泛使用。
安裝
- Windows: 下載並安裝GLPK。
- macOS:
brew install glpk
- Linux:
sudo apt-get install glpk-utils
2. CBC (Coin-or Branch and Cut)
CBC 是一款開源的線性規劃(LP)和混合整數規劃(MIP)問題求解器。
它提供了一些進階功能和更佳的性能,在某些情況下,比GLPK更好,使其成為複雜優化任務的強烈選擇。
CBC 可以通过conda包管理器進行安裝。
conda install -c conda-forge coincbc
3. IPOPT (Interior Point OPTimizer)
IPOPT 是一款為大規模 非線性規劃(NLP)問題 設計的强大求解器。
它特別適合處理複雜的非線性模型,使其成為超出自線性優化問題的優秀選擇。
IPOPT可以通過conda包管理器進行安裝。
!conda install -c conda-forge ipopt
商業求解器
1. CPLEX
CPLEX是一款先進的優化求解器,能有效處理線性規劃(LP)、混合整數規劃(MIP)和四次方程式規劃(QP)問題。
它需要從IBM獲得許可證,但对學術用戶免费,使其成為研究和教育用途的優秀選擇。
2. Gurobi
Gurobi 是一款知名的商業求解器,以其解決線性規劃(LP)、混合整數規劃(MIP)、二次規劃(QP)以及非線性規劃(NLP)問題的速度和效率而聞名。
與CPLEX一樣,它需要許可證才能使用,但為學術用戶提供免費訪問。因此,它是業界標準的進階優化工具。
開源與商業求解器對比
開源求解器如GLPK和CBC是免費且足夠滿足大部分基本優化需求。它們是小型项目和教育培训的優秀選擇。
然而,商業求解器如CPLEX和Gurobi通常提供更高的性能,特別是對於更大、更複雜的問題。這些求解器具有進階功能,包括優化的二次方和 nonlinear 程式支援,並為大規模工業應用進行優化。
雖然開源求解器可以處理許多例行優化任務,但在處理更複雜、高性能要求時,商業求解器往往是更好的選擇。
請注意,商業求解器需要授權,雖然他們對學術用戶是免费的。
現在,我們來看看如何在Pyomo中配置一個求解器。在這個案例中,我會使用GLPK。
3. 在Pyomo中配置求解器
首先,確保在安裝後,求解器的可执行文件在您的系統PATHTags中。
然後,創建一個Python脚本並添加以下內容:
from pyomo.environ import SolverFactory solver = SolverFactory('glpk')
為了確定Pyomo和您的求解器都已經正確安裝,讓我們解決一個簡單的測試問題。
測試問題:簡單線性規劃
目標:最小化Z=x+y
限制於:
- x + 2y ≥ 4
- x – y ≤ 1
- x ≥ 0
- y ≥ 0
這個問題是要找出Z的最小可能值,x 和 y 的總和。然而,x 和 y 必須滿足某些條件。
首先,當你添加x和兩倍的y時,結果必須至少是4。其次,x減去y必須小於或等於1。最後, bothx和y必須是零或正數(它們不能是負數)。
目標是要找到x和y的值,滿足這些條件同時讓Z盡可能地小。
使用Pyomo實現:
import pyomo.environ as pyo # 建立模型 model = pyo.ConcreteModel() # 定義變量 model.x = pyo.Var(within=pyo.NonNegativeReals) model.y = pyo.Var(within=pyo.NonNegativeReals) # 定義目標 model.obj = pyo.Objective(expr=model.x + model.y, sense=pyo.minimize) # 定義限制 model.con1 = pyo.Constraint(expr=model.x + 2 * model.y >= 4) model.con2 = pyo.Constraint(expr=model.x - model.y <= 1) # 選擇求解器 solver = pyo.SolverFactory('glpk') # 解決問題 result = solver.solve(model) # 顯示結果 print('Status:', result.solver.status) print('Termination Condition:', result.solver.termination_condition) print('Optimal x:', pyo.value(model.x)) print('Optimal y:', pyo.value(model.y)) print('Optimal Objective:', pyo.value(model.obj))
如果一切正常运作,预期的輸出將會是:
Status: ok Termination Condition: optimal Optimal x: 0.0 Optimal y: 2.0 Optimal Objective: 2.0
讓我們來走走上面的程式碼:首先,它定義了兩個變量,x和y,它們只能取非負值。模型的目標是要最小化x和y的和(x + y)。程式碼將求解器設定為glpk
,以尋找x和y的最優值,這些值需要滿足這些限制同時最小化目標。
程式運行後,我們發現變數的最優值為x = 0.0及y = 2.0,此值能最小化目標函數Z = x + y。因此,目標函數的最小值为2.0,並滿足給定的限制條件。
Pyomo 建模基礎
了解如何在 Pyomo 中定義優化模型的基本组成部分,對於有效地設定和解決優化問題是必要的。
1. 定義變量
變量代表優化問題中需要做出的決定。在 Pyomo 中,變量是解算器將調整以優化目標函數同時滿足所有限制的量化。
純量變量
純量變量是没有在任何集合上索引的單個變量。要在 Pyomo 中定義一個純量變量,您使用從 pyomo.environ
模組中的 Var
類。
from pyomo.environ import Var model.x = Var()
我們首先導入 Var
,並使用 Var()
創建一個變量 x
。這個變量沒有指定的界限,意味著它可以取任何實數值,除非在模型的其他地方有限制。
添加界限
您可以通過指定範圍來限制變數可以取的值。範圍被定義為一個元組 (lower_bound
, upper_bound
):
from pyomo.environ import Var model.x = Var(bounds=(0, None))
指定領域
Pyomo 提供了预定义的領域,您可以使用它們來指定變數可以取的值的类型,例如 NonNegativeReals
, Integers
或 Binary
:
from pyomo.environ import Var, NonNegativeReals model.x = Var(domain=NonNegativeReals)
索引變數
當處理多種性质相似的變數,例如代表不同時間段或项目的變數時,使用索引變數是高效的。索引變數是定義在集合上的變數。
import pyomo.environ as pyo model.I = pyo.Set(initialize=[1, 2, 3]) model.y = pyo.Var(model.I, domain=pyo.NonNegativeReals)
假設您正在模擬三種產品的生產量。您可以定義:
model.Products = pyo.Set(initialize=['A', 'B', 'C']) model.production = pyo.Var(model.Products, domain=pyo.NonNegativeReals)
現在,`model.production[‘A’]`、`model.production[‘B’]` 和 `model.production[‘C’]` 分別代表產品A、B和C的生產數量。
2. 定義目標
目標函數是我们试图優化(最小化或最大化)的內容。它定了模型的目標,例如最小化成本或最大化利潤,通常表達為涉及其決定變量之一的數學方程式。
這可以用 `Objective` 類來定義:
from pyomo.environ import ConcreteModel, Var, Objective, minimize, maximize, NonNegativeReals # 創建模型 model = ConcreteModel() # 定義變量 model.x = Var(within=NonNegativeReals) model.y = Var(within=NonNegativeReals) # 最小化(成本) model.cost = Objective(expr=2 * model.x + 3 * model.y, sense=minimize) # 最大化利潤 - (一次只能有一個目標) # model.profit = Objective(expr=5 * model.x + 4 * model.y, sense=maximize)
3. 添加限制條件
限制定義問題的局限性或要求:
from pyomo.environ import Constraint model.con1 = Constraint(expr=model.x + model.y >= 10)
上面的例子使用 Constraint
類別在 Pyomo 模型中定義一個限制。限制 model.con1
指定變量 x 和 y 的總和必須大於或等於 10。
4. 模型的參數化
模型的參數是 optimization 過程中不變的已知量或常數。
它們有助於定義變量之間的關係和約束,通過纳入现实世界數據或假設,為模型提供結構:
from pyomo.environ import Param model.p = Param(initialize=5)
上面程式定义了一個在 Pyomo 模型中的參數 p
,並使用 Param
類別给它一個固定值 5。現在 p
這個參數可以在模型中使用,來表示 optimization 過程中不變的常數值。
現在,讓我們來解決一個端到端的優化問題!
Pyomo 端到端示例
讓我們看看使用 Pyomo 解優化問題的端到端示例。我們將模擬一個現實世界的情景,一個工廠生產兩種產品,目標是在考慮機械時間限制的同時最大化大利潤。
1. 問題陈述
一個工廠生產兩種產品,P1和P2。每個單位的面額是:
- P1:$40
- P2:$50
機器時間可供使用:
- 機器A:100小時
- 機器B:80小時
- 機器C: 90小時
每個單位所需時間:
產品 |
機器A (小時) |
機器B (小時) |
機器C (小時) |
P1 |
1 |
2 |
0 |
P2 |
2 |
1 |
3 |
目標: 最大化利益。
決策變量:
- x₁: 生產 P1 的數量。
- x₂: 产生P2的單位.
2. 數值化公式
目標方程式:
最大化Z = 40x₁ + 50x₂
限制:
- Machine A 容量: 1x₁ + 2x₂ ≤ 100
- 機械B能力:2x₁ + 1x₂ ≤ 80
- 機械C能力:3x₂ ≤ 90
- 非負性:x₁, x₂ ≥ 0
3. 实施
基於問題的目標和限制,以下是使用GLPK模型的Python程式碼來模擬它,再一次。
步驟 1: 匯入庫存 import pyomo.environ as pyo 步驟 2: 建立具體模型 model = pyo.ConcreteModel() 步驟 3: 定義決策變量 (生產 P1 和 P2 的單位) model.x1 = pyo.Var(within=pyo.NonNegativeReals) model.x2 = pyo.Var(within=pyo.NonNegativeReals) 步驟 4: 定義目標函數 (最大化大利潤) model.profit = pyo.Objective(expr=40 * model.x1 + 50 * model.x2, sense=pyo.maximize) 步驟 5: 定義限制 機器 A 容量的限制: 1x1 + 2x2 <= 100 model.machine_a = pyo.Constraint(expr=1 * model.x1 + 2 * model.x2 <= 100) 機器 B 容量的限制: 2x1 + 1x2 <= 80 model.machine_b = pyo.Constraint(expr=2 * model.x1 + 1 * model.x2 <= 80) 機器 C 容量的限制: 3x2 <= 90 model.machine_c = pyo.Constraint(expr=3 * model.x2 <= 90) 步驟 6: 使用 GLPK 解算器解模型 solver = pyo.SolverFactory('glpk') result = solver.solve(model) 步驟 7: 分析結果 步驟 8: 顯示解算器狀態及終止條件 print('Solver Status:', result.solver.status) print('Termination Condition:', result.solver.termination_condition) 步驟 9: 獲取並顯示 x1, x2 的最優值及最大大利潤 x1_opt = pyo.value(model.x1) x2_opt = pyo.value(model.x2) profit_opt = pyo.value(model.profit) print(f'Optimal production of P1 (x1): {x1_opt}') print(f'Optimal production of P2 (x2): {x2_opt}') print(f'Maximum Profit: ${profit_opt}')
輸出:
>>> Solver Status: ok >>> Termination Condition: optimal >>> Optimal production of P1 (x1): 25.0 >>> Optimal production of P2 (x2): 30.0 >>> Maximum Profit: $2500.0
在上述代碼中,我們定義了一個線性優化模型來最大化生產兩款產品(P1和P2)的利潤。目標函數被設定為最大化利潤,P1每單位貢獻$40,而P2每單位貢獻$50。
我們施加三個約束,代表A, B和C機器的時間限制。
最後,我們使用GLPK求解器來解決問題。
最終答案是生產25個P1和30個P2,我們的最大利潤將是$2,500。
高级功能在Pyomo
在上一節中,我們看到如何輕鬆地使用Pyomo實現端到端的優化問題。然而,大多數現實生活中的問題並不容易解決。
在這一節中,我將介绍一些您可以使用來解決更複雜情境的進階功能。
1. 非線性優化
非線性優化旨在最小化或最大化非線性目標函數,同時滿足非線性約束。讓我們看一個例子,我們最小化了滿足 circular 約束的平方差之和。
問題陈述
目標最小化:Z = (x – 1)² + (y – 2)²
限制:
- x² + y² ≤ 4
- x, y ≥ 0
在 Pyomo 中,我們可以定義決策變量 x 和 y,並給定界限為 0,以確保非負性。目標函數寫作從特定點的平方差之和,而約束則確保解決方案在於半徑為 2. 的圓內。
在這個情況下,IPOPT 求解器因其非線性優化問題解決能力而適合使用:
import pyomo.environ as pyo model = pyo.ConcreteModel() # 定義具有下限的變量 model.x = pyo.Var(bounds=(0, None)) model.y = pyo.Var(bounds=(0, None)) # 目標函數:最小化 (x - 1)² + (y - 2)² model.obj = pyo.Objective(expr=(model.x - 1)**2 + (model.y - 2)**2, sense=pyo.minimize) # 限制:x² + y² ≤ 4 (半徑為 2 的圓) model.circle = pyo.Constraint(expr=model.x**2 + model.y**2 <= 4) solver = pyo.SolverFactory('ipopt') result = solver.solve(model) print('Optimal x:', pyo.value(model.x)) print('Optimal y:', pyo.value(model.y)) print('Minimum Z:', pyo.value(model.obj))
2. 混合整數規劃(MIP)
當一些決策變量是整數(通常為二進制)而其他是連續時使用混合整數規劃。它在設施位置和生產計劃等決策問題上很有價值。
問題陈述
一家公司必須決定是否在A、B和C等地點开设倉庫。目標是最小化總成本,這包括开设倉庫的固定成本和運輸成本。
我們首先初始化數據,包括开设倉庫的固定成本、運輸成本、容量限制和總需求:
locations = ['A', 'B', 'C'] FixedCost = {'A': 1000, 'B': 1200, 'C': 1500} TransportCost = {'A': 5, 'B': 4, 'C': 6} Capacity = {'A': 100, 'B': 80, 'C': 90} Demand = 150 model = pyo.ConcreteModel() # 的二進制變量:如果倉庫Open则为1,其他情况為0 model.y = pyo.Var(locations, domain=pyo.Binary) # 連續變量:從倉庫运输的货物量 model.x = pyo.Var(locations, domain=pyo.NonNegativeReals) model.cost = pyo.Objective( expr=sum(FixedCost[i] * model.y[i] + TransportCost[i] * model.x[i] for i in locations), sense=pyo.minimize ) # 需求限制 model.demand = pyo.Constraint(expr=sum(model.x[i] for i in locations) >= Demand) # 容量限制 def capacity_rule(model, i): return model.x[i] <= Capacity[i] * model.y[i] model.capacity = pyo.Constraint(locations, rule=capacity_rule) solver = pyo.SolverFactory('cbc') result = solver.solve(model) for i in locations: print(f"Warehouse {i}: Open={pyo.value(model.y[i])}, Transported={pyo.value(model.x[i])}") print('Minimum Total Cost:', pyo.value(model.cost))
模型的決策變量分為兩類:一個二進制變量y
,表示倉庫是否開放(如果開放則為1,其他情況為0),以及一個連續變量x
,表示從每個倉庫运输的货物量。
目標函數總結每個倉庫的固定成本和運輸成本,並最小化了總成本。約束確保總运输货物滿足需求,且如果打開每個倉庫,則不會超過其容量。
3. 處理多個目標
有時,優化問題涉及其他目標,這些目標可能會發生衝突,例如在最大化利潤的同時最小化环境影响。常見的方法是加权總和法,其中每個目標都被分配一個權重以平衡其重要性。
問題陈述
我們旨在最大化盈利同時最小化環境影響:
- 盈利:Z₁ = 3x + 5y
- 環境影響:Z₂ = 2x + y
我們可以透過權重 w1=0.6
, w2=0.4
結合這些目標,其中總目標成為加權總和:
w1 = 0.6 w2 = 0.4 model.obj = pyo.Objective( expr=w1 * (3 * model.x + 5 * model.y) - w2 * (2 * model.x + model.y), sense=pyo.maximize )
在這個結合目標中,透過調整權重,我們可以最大化盈利同時最小化環境影響。
4. 使用外部數據來源
當處理大量數據集時,從外部來源如CSV文件導入數據通常很有用。Pyomo與Pandas协作很好,用於讀取和使用外部數據。
我們可以使用Pandas讀取CSV文件,並用數據初始化模型中的集合和參數:
import pandas as pd data = pd.read_csv('parameters.csv') # 使用CSV數據定義集合 model.I = pyo.Set(initialize=data['index'].unique()) # 使用CSV數據初始化參數 param_dict = data.set_index('index')['value'].to_dict() model.param = pyo.Param(model.I, initialize=param_dict)
使用Pyomo的窍門和最佳實踐
當使用Pyomo時,保持模型的效率、Documented和完善故障排除能力是重要的。
1. 除錯和故障排除
在Pyomo中建立優化模型時,常会遇到例如不可行解決方案、解算器失败或結果不正確等问题。以下是一些最佳實踐用於除錯:
- 檢查限制:如果你的模型未能產生可行的解決方案,請檢查你的限制。過緊的限制可能會使問題變得無可行性。使用 Pyomo 的
.display()
方法來打印變量和限制的值,以確認它們如预期般行為。 - 解算器輸出:通過在呼叫
solve()
方法時傳遞tee=True
,來啟用 detailed solver logs。這可以提供關於解算器可能在哪裡遇到困難的洞見,例如無界限的變量或無可行性。 - 首先測試簡單模型:處理複雜模型時,先測試簡化版本。這可以幫助隔離潛在問題,而不需要全 specification 的模型造成的開銷。
如果 systematically 分析限制、目標函數和解決器反饋,問題解決會簡單得多。
2. 建模效率
隨著模型大小的增加,最優化問題可能會變得計算上昂貴。為了確保建模效率,考慮以下建議:
- 使用稀疏性:在定義約束或目標時,避免遍歷不必要的索引。性问题中的稀疏性可减少計算時間。
- 二進制與連續變量:在可能的情況下,減少二進制或整數變量的數量。連續變量對求解器來說更容易處理,從而加快解決方案。
- 約束 formulated:盡可能保持約束尽可能簡單,無論在數學形式還是在實現上。避免不必要的非線性並將复雜的約束分解為更小、易於管理的約束。
有效的模型解決速度較快,且較容易進行除錯與維護。
3. 文档和維護
維護 properly-documented Pyomo 模型是長期使用和協作的良好習慣。良好的文档化也使得随時間重新訪問和更新模型更加容易:
- 使用內聯註釋: 總是為變量、限制和目標函數添加註釋以解釋其用途。在優化模型中,這特別重要,因為邏輯可能不會立即明顯。
- modularize 你的代碼: 將你的模型拆分成邏輯部分或甚至是獨立的函數。這種模組化的方法可以提高可讀性,並使 Debugging 和修改模型的特定部分變得更容易。
- 追蹤模型更改: 特別是如果你的模型在不斷演進,要保持模型的版本歷史。使用如 Git 的版本控制工具來追蹤更改,並確保任何更新或改進都能追溯到原始版本。
正確的文件化和結構化代碼將使你的 Pyomo 模型對未來的协作夥伴更易於接触,並使根據你的需求演變放大或修改變得更加容易。
結論
Pyomo 是一款強大且靈活的 Python 工具,用於建立和解決優化模型。在這個教程中,我們探讨了 Pyomo 是如何讓用戶模型的各種優化問題,從線性規劃到非線性和混合整數規劃。
凭借其易於使用的語法與優化器的整合,Pyomo 使得 formulated and solving real-world optimization problems accessible to both beginners and advanced users.
如果您對學習如何使用優化解決現實問題感興趣,請查看 DataCamp 上的 Python 優化简介 免费課程!