線性規劃是不少數模培訓講的第一個算法,算法很簡單,思想很深入。html
要經過線性規劃問題,理解如何學習數學建模、如何選擇編程算法。python
『Python小白的數學建模課 @ Youcans』帶你從數模小白成爲國賽達人。算法
線性規劃 (Linear Programming,LP) 是不少數模培訓講的第一個算法,算法很簡單,思想很深入。編程
線性規劃問題是中學數學的內容,雞兔同籠就是一個線性規劃問題。數學規劃的題目在高考中也常常出現,有直接給出線性約束條件求線性目標函數極值,有間接給出約束條件求線性目標函數極值,還有已知約束條件求非線性目標函數極值問題。網絡
所以,線性規劃在數學建模各種問題和算法中確實是比較簡單的問題。下面咱們經過這個比較簡單、也比較熟悉的問題,分析一下數學模型問題的方法、算法和學習方案。探討這些容易混淆的概念,也便於你們理解本系列教程的初衷和特點。框架
歡迎關注 『Python小白的數學建模課 @ Youcans』,每週更新數模筆記
Python小白的數學建模課-01.新手必讀
Python小白的數學建模課-02.數據導入
Python小白的數學建模課-03.線性規劃
Python數模筆記-PuLP庫
Python數模筆記-StatsModels統計迴歸
Python數模筆記-Sklearn
Python數模筆記-NetworkX
Python數模筆記-模擬退火算法函數
解決線性規劃問題有不少數學方法,例如:工具
雖然不一樣的求解方法都是面對線性規劃問題,也就必然會異曲同工,但它們在思想上就存在着本質區別,在求解方法和步驟上也就徹底不一樣。性能
不誇張地說,對於不少小白,學沒學過單純性法,對於學習啓發式方法可能徹底沒有區別。學習
這意味着什麼呢?這就是說,對於非數學專業的同窗,對於學習數學建模的同窗,針對每一類問題,徹底不必學習各類解決方法。即使是數學專業的同窗,也不可能在數模學習期間把各類方法都學會。
對於小白,本文推薦選擇較爲通用、相對簡單(思路簡單、程序簡單)的方法來進行學習,不必貪多求新。
算法,跟方法有什麼不一樣呢?
算法的定義是「解題方案的準確而完整的描述」,是一系列解決問題的清晰指令,算法表明着用系統的方法描述解決問題的策略機制。
我對「方法」的理解是思想方法,是求解問題整體框架,而「算法」是具體和明確的實現步驟,在計算機編程中至關於詳細的流程圖。
在每一種方法的基本思想和方案提出後,每每都會有不少變形、改進和發展的算法。極少的改進算法具備實質貢獻而成爲主流的經典算法,即使如此每每也只是性能、效率上的提高,對於求解數模競賽中的問題基本沒有影響。
而絕大多數改進算法只是針對某些特殊狀況、特殊問題(自稱)有效,經常使用於大量的灌水論文。對於數學建模來講,學習基本算法或者目前的經典算法就足夠了,不須要聽信改進算法中自稱的優勢,那都是莆田系的廣告。
有一種例外狀況,就是一些算法是有適用範圍和限制條件的。舉個例子,內點法的基本算法不能處理等式約束,最短路徑問題中 Dijkstar算法不能處理負權邊。這種狀況下若是選錯算法,問題是沒法求解的。因此對咱們來講,搞清楚算法的適用範圍,比理解算法自己更重要。
回到本節的標題,對於線性規劃問題,什麼算法是最快的呢?答案是:猜。不是讓你猜,而是說求解線性規劃問題,猜起來比較快。不是開玩笑,我是認真的。
佐治亞理工學院彭泱教授在 2021年計算機理論頂會 SODA2021 得到最佳論文(Best paper award at ACM-SIAM symposium on discrete algorithms 2021),正是研究線性規劃問題的求解——「Solving sparse linear systems faster than matrix multiplication」,所用的全新思路是:猜,反覆猜,迭代猜。
固然,猜起來比較快只是在某些特殊條件下才有效的,至於在什麼條件下猜,怎麼猜,這不是咱們所要關心,所能理解的問題了。只是以此說明,簡單的問題也有複雜的狀況,每一個問題都有不少求解的思路、方法和算法。
編程方案是我杜撰的術語。我所要表達意思是,在選擇了求解方法和算法之後,是本身按照算法步驟一步步編程實現,或者找到例程調試使用,仍是調用第三方工具包/庫函數來完成呢?
首先,對於學習數學建模、參加數模競賽,不建議本身按照算法步驟去編程。咱們在《01.新手必讀》中討論過這個問題,對於數學小白兼計算機小白,這樣作既不可行也不必;即便你願意挑戰自我去試試,那其實已是走在學習另外一門計算機或算法課程的路上了。
其次,要不要找到例程本身調試、使用?不少數模培訓就是這麼說,這麼作的,並且把這些收集的例程看成核心機密吸引同窗。我不反對這樣作,這種學習方法對於理解算法、提升編程能力頗有幫助;可是並不推薦這樣作,緣由是:(1)我認爲學習數學建模、參加數模競賽,重點應該放在識別問題、分析問題、解決問題,能使用算法和編程就足夠了;(2)第三方庫與例程沒有本質區別,第三方庫就是經典的、規範的、標準化的例程,既然選擇例程爲何不選擇優秀的例程——第三方庫呢?(3)大部分例程都存在不少問題,即便調試經過仍然有不少坑,並且新手難以識別。
因此我是明確推薦優選直接使用第三方庫來解決問題,這也是 Python 語言「不要重複造輪子」的思想。
進一步地,不少工具包/庫函數都能實現經常使用的算法,應該如何選擇呢?
若是你對某個工具包已經很熟悉,又能實現所要的算法,這固然是理想的選擇。若是你是小白,就跟着我走吧。
本系列選擇第三方工具包的原則是:(1)優選經常使用的工具包;(2)優選通用功能的工具包和函數(例如,最好既能實現線性規劃,又能實現整數規劃、非線性規劃);(3)優選安裝簡單、使用簡單、配置靈活的工具包;(4)優選兼模型檢驗、圖形繪製的工具包。
線性規劃是研究線性等式或不等式約束條件下求解線性目標函數的極值問題,經常使用於解決資源分配、生產調度和混合問題。
通常線性規劃問題的標準形式爲:
知足全部約束條件的解,稱爲線性規劃問題的可行解;全部可行解構成的集合,稱爲可行域。
使目標函數達到最小值的解,稱爲最優解。
線性規劃問題的建模和求解,一般按照如下步驟進行:
不少 Python 的第三方包,都提供求解線性規劃問題的算法,有的工具包還提供整數規劃、非線性規劃的算法。例如:
此外,SKlearn、DOcplex、Pymprog 等不少第三方工具包也都能求解線性規劃問題。
例題 1:
下面以該題爲例講解 PuLP 求解線性規劃問題的步驟:
(0)導入 PuLP庫函數
import pulp
(1)定義一個規劃問題
MyProbLP = pulp.LpProblem("LPProbDemo1", sense=pulp.LpMaximize)
pulp.LpProblem 是定義問題的構造函數。
"LPProbDemo1"是用戶定義的問題名(用於輸出信息)。
參數 sense 用來指定求最小值/最大值問題,可選參數值:LpMinimize、LpMaximize 。本例 「sense=pulp.LpMaximize」 表示求目標函數的最大值。
(2)定義決策變量
x1 = pulp.LpVariable('x1', lowBound=0, upBound=7, cat='Continuous') x2 = pulp.LpVariable('x2', lowBound=0, upBound=7, cat='Continuous') x3 = pulp.LpVariable('x3', lowBound=0, upBound=7, cat='Continuous')
pulp.LpVariable 是定義決策變量的函數。
'x1' 是用戶定義的變量名。
參數 lowBound、upBound 用來設定決策變量的下界、上界;能夠不定義下界/上界,默認的下界/上界是負無窮/正無窮。本例中 x1,x2,x3 的取值區間爲 [0,7]。
參數 cat 用來設定變量類型,可選參數值:'Continuous' 表示連續變量(默認值)、' Integer ' 表示離散變量(用於整數規劃問題)、' Binary ' 表示0/1變量(用於0/1規劃問題)。
(3)添加目標函數
MyProbLP += 2*x1 + 3*x2 - 5*x3 # 設置目標函數
添加目標函數使用 "問題名 += 目標函數式" 格式。
(4)添加約束條件
MyProbLP += (2*x1 - 5*x2 + x3 >= 10) # 不等式約束 MyProbLP += (x1 + 3*x2 + x3 <= 12) # 不等式約束 MyProbLP += (x1 + x2 + x3 == 7) # 等式約束
添加約束條件使用 "問題名 += 約束條件表達式" 格式。
約束條件能夠是等式約束或不等式約束,不等式約束能夠是 小於等於 或 大於等於,分別使用關鍵字">="、"<="和"=="。
(5)求解
MyProbLP.solve() print("Status:", pulp.LpStatus[MyProbLP.status]) # 輸出求解狀態 for v in MyProbLP.variables(): print(v.name, "=", v.varValue) # 輸出每一個變量的最優值 print("F(x) = ", pulp.value(MyProbLP.objective)) #輸出最優解的目標函數值
solve() 是求解函數。PuLP默認採用 CBC 求解器來求解優化問題,也能夠調用其它的優化器來求解,如:GLPK,COIN CLP/CBC,CPLEX,和GUROBI,但須要另外安裝。
例程 1:求解線性規劃問題
# mathmodel04_v1.py # Demo01 of mathematical modeling algorithm # Solving linear programming with PuLP. # Copyright 2021 Youcans, XUPT # Crated:2021-05-28 import pulp MyProbLP = pulp.LpProblem("LPProbDemo1", sense=pulp.LpMaximize) # 求最大值 x1 = pulp.LpVariable('x1', lowBound=0, upBound=7, cat='Continuous') x2 = pulp.LpVariable('x2', lowBound=0, upBound=7, cat='Continuous') x3 = pulp.LpVariable('x3', lowBound=0, upBound=7, cat='Continuous') MyProbLP += 2*x1 + 3*x2 - 5*x3 # 設置目標函數 MyProbLP += (2*x1 - 5*x2 + x3 >= 10) # 不等式約束 MyProbLP += (x1 + 3*x2 + x3 <= 12) # 不等式約束 MyProbLP += (x1 + x2 + x3 == 7) # 等式約束 MyProbLP.solve() # youcans@xupt print("Status:", pulp.LpStatus[MyProbLP.status]) # 輸出求解狀態 for v in MyProbLP.variables(): # youcans print(v.name, "=", v.varValue) # 輸出每一個變量的最優值 print("Max F(x) = ", pulp.value(MyProbLP.objective)) #輸出最優解的目標函數值
例程 1 運行結果:
Welcome to the CBC MILP Solver Version: 2.9.0 Build Date: Feb 12 2015 Status: Optimal x1 = 6.4285714 x2 = 0.57142857 x3 = 0.0 Max F(x) = 14.57142851
例程01 程序說明:
求解線性規劃問題的方法很是簡單,本文實際上並未講解具體的算法。
但願經過對求解方法、算法和編程方案的講解,闡明做者對於數學建模學什麼、怎麼學的理解,也使讀者能瞭解本系列教程的特色:本教程不打算詳細講解各類算法的具體方法,重點介紹如何使用第三方包實現算法、解決問題。
【本節完】
版權說明:
歡迎關注『Python小白的數學建模課 @ Youcans』 原創做品
原創做品,轉載必須標註原文連接(https://www.cnblogs.com/youcans/p/14836629.html)。
Copyright 2021 Youcans, XUPT
Crated:2021-05-29
歡迎關注 『Python小白的數學建模課 @ Youcans』,每週更新數模筆記
Python小白的數學建模課-01.新手必讀
Python小白的數學建模課-02.數據導入
Python小白的數學建模課-03.線性規劃
Python小白的數學建模課-04.整數規劃
Python小白的數學建模課-05.0-1規劃
Python小白的數學建模課-06.固定費用問題
Python小白的數學建模課-07.選址問題
Python小白的數學建模課-09.微分方程模型
Python數模筆記-PuLP庫
Python數模筆記-StatsModels統計迴歸
Python數模筆記-Sklearn
Python數模筆記-NetworkX
Python數模筆記-模擬退火算法