線性規劃(Linear Programming,LP)是很是經典的算法之一,而解決該問題的最經常使用方法是單純形法。本博文致力於用最簡單、最詳細的語言一步步解釋單純形算法的過程並加以詳細的解釋。算法
中學課程裏,咱們都簡單地接觸過線性規劃,那時候通常都是分析每一個約束,在二維平面上畫出直線,獲得可行域,而後以固定斜率做出目標函數直線,在可行域內移動直線,在y軸上的截距就是最優解。而每每最優解的地方是經過(凸)可行域的頂點。就像下面這個例子:
\[ \begin{equation} \begin{split} \max& \quad x_3+x_4 \\ s.t.& \quad -x_3+2x_4\leq 2 \\ &\quad 3x_3-2x_4\leq 6 \\ &\quad x_3, x_4\geq 0 \end{split} \end{equation} \]
函數
而咱們後面將證實,最優解必定是可行域(凸超幾何體)的頂點之一。那麼,咱們先假定這成立,就使用」改進-中止「(improve-stopping)的套路,即給定可行域的一個頂點,求值,沿一條邊到達下一個頂點,看是否能改善解,直到達到中止要求。學習
這裏就要問幾個問題了:爲何最優解必定在頂點處?怎麼獲得頂點?怎麼實現沿着一條邊到下一個頂點?何時中止?接下來,咱們將一一解答這些問題,當解答完這些問題,單純形法也就顯而易見了。spa
考慮最小化問題,目標函數\(\mathbf{c}^T \mathbf{x}\),有一個在可行域內部的最優解\(\mathbf{x}^{(0)}\),由於凸多邊形內部任一點均可以表示成頂點的線性組合,即對於頂點\(\mathbf{x}^{(k)}, k=1,2,\cdots, n\),有
\[ \mathbf{x}^{(0)}=\sum_{k=1}^{n}\lambda_k\mathbf{x}^{(k)}, \]3d
\[ \sum_{k=1}^n \lambda_k=1 \]blog
假設\(\mathbf{x}^{(i)}\)是全部頂點中使得\(\mathbf{c}^T \mathbf{x}\)最小的頂點,那麼有
\[ \begin{equation} \begin{split} \mathbf{c}^T\mathbf{x}^{(0)} &= \sum_{k=1}^{n}\lambda_k\mathbf{c}^T\mathbf{x}^{(k)} \\ &\geq \sum_{k=1}^{n}\lambda_k\mathbf{c}^T\mathbf{x}^{(i)} \\ &= \mathbf{c}^T\mathbf{x}^{(i)} \end{split} \end{equation} \]
所以,總有一個頂點,他的目標函數值不比內部點差。it
下面要說明的就是這樣一個定理:對於可行域方程組\(\mathbf{Ax=b}\),該方程肯定的凸多邊形的任意一個頂點對應\(\mathbf{A}\)的一組基。io
上面這個例子是鬆弛形式的約束,原來的變量有三個,加上後面4個後變成等式,造成的可行域如上圖所示。咱們取一個頂點(0,2,0)分析,代入約束中,能夠算出一個完整解\(x=(0,2,0,2,2,3,0)\)。取出矩陣\(\mathbf{A}\)中對應的\(x\)不爲0的列,即圖中標藍的幾列(用\(\mathbf{a}_2\),\(\mathbf{a}_4\),\(\mathbf{a}_5\),\(\mathbf{a}_6\)表示),那麼這幾列就是線線性無關的,考慮\(m<n\)(約束數目小於鬆弛後的變量個數),那麼自由解有\(n-m\)維,所以挑出來的列必有\(m\)個,構成一組基。下面主要說明他們爲何線性無關。假設他們線性相關,即存在一組\(\lambda\neq\mathbf{0}\),使得\(\lambda_2\mathbf{a}_2+\lambda_4\mathbf{a}_4+\lambda_5\mathbf{a}_5+\lambda_6\mathbf{a}_6=0\),也就是說,能夠構造\(\lambda=[0, \lambda_2, 0, \lambda_4, \lambda_5, \lambda_6, 0]\),使得\(\mathbf{A}\lambda=0\)。那麼還能夠再構造兩個異於\(x\)的解:\(x'=x+\theta\lambda\)和\(x''=x-\theta\lambda\)。他們都知足\(\mathbf{Ax=b}\)。而且能夠經過控制\(\theta\)取很小的正值,使得這兩個解知足都大於0的約束。由此這兩個解都在凸多面體內,而且有\(x=\frac{1}{2}(x'+x'')\),可是這是有問題的,由於一個凸多面體的頂點是不能被內部點線性表示的,所以這幾列是構成一組基的。
class
有了上面的知識,給定一組基\(\mathbf{B}\),咱們直接構造\(\mathbf{x}=[\mathbf{B^{-1}b}, \mathbf{0}]^T\),只要說明他不能被兩個異於他的內部點線性表示便可。假設有兩個內部點\(\mathbf{x}_1, \mathbf{x}_2\),知足\(\mathbf{x}=\lambda_1\mathbf{x}_1+\lambda_2\mathbf{x}_2\),因爲\(\mathbf{x_N}=0\),而且這些解的元素都大於等於0,所以\(\mathbf{x_1}_{\mathbf{N}}=\mathbf{x_2}_{\mathbf{N}}=0\)。而又由於\(\mathbf{Ax_1=Ax_2=b}\),所以\(\mathbf{x_1}_{\mathbf{B}}=\mathbf{x_2}_{\mathbf{B}}=\mathbf{B^{-1}b}\)。即這兩個解和\(\mathbf{x}\)相同,所以\(\mathbf{x}\)是頂點。效率
這裏是要研究怎麼改善一個解,咱們須要知道怎麼從一個頂點出發沿着邊找到另外一個頂點。前面咱們知道了一個頂點對應一組基,並且一個矩陣的基有多個,那麼是否能夠經過基的變換從而使得頂點變換呢?先來看一個例子。
證實:\(\mathbf{B'}=\mathbf{B}-\{\mathbf{a}_l\}+\{\mathbf{a}_e\}\)仍然是基。(l表示leave,e表示enter)
假設\(\mathbf{B'}\)線性相關,那麼存在\(<d_1,d_2,\ldots,d_{l-1},d_{l+1},\ldots,d_m, d_e>\neq0\),使得\(\sum_{k}d_k\mathbf{a}_k=0\)。而\(\mathbf{a}_e=\sum_{i=1}^m \lambda_i\mathbf{a_i}\),代入得:
\[ (d_1+d_e\lambda_1)\mathbf{a_1}+\ldots+(d_e\lambda_l)\mathbf{a}_l+\ldots+(d_m+d_e\lambda_m)\mathbf{a}_m=0 \]
這裏是證實的關鍵之處:咱們在設置\(\theta\)時的作法,假如最終選出來的使得\(\frac{x_i}{\lambda_i}\)最小的那一項下標爲\(p\),那麼獲得的新解的第\(p\)項必然爲0,至關於把\(\mathbf{a}_p\)換了出去。在上面這個例子重\(p=4\)。而由於咱們只考慮\(\lambda_i>0\)的基向量,所以被換出去的基\(\mathbf{a}_l\)對應的\(\lambda_l>0\),所以上式中有\(d_1=d_2=\ldots=d_m=d_e=0\),和原假設矛盾,所以\(\mathbf{B'}\)也是線性無關的。
截止到目前,咱們回答了三個問題,基本上單純形算法呼之欲出了,單純形算法就是經過反覆的基變換(經過向量的進出)來找頂點,從而找到達到最優值的頂點。可是仍是有些細節須要琢磨,好比,怎麼選入基向量?改善的過程何時中止?
以最小化問題爲標準,咱們的最終目標是最小化\(\mathbf{c^Tx}\),所以一個很天然的貪心想法是每步的改善都儘量地大,所以能夠計算一下更新的目標函數值和原來的差值,取使得變化大的頂點繼續下一步迭代。那麼這個差值怎麼可以向量化地計算呢?只有向量化地計算,才能避免一個一個地計算比較,提升效率。
假設\(\mathbf{B}=\{\mathbf{a}_1, \mathbf{a}_2,\ldots, \mathbf{a}_m\}\),那麼對於任何一個非基向量\(\mathbf{a}_e\),都有\(\mathbf{a}_e=\lambda_1\mathbf{a}_1+\ldots+\lambda_m\mathbf{a}_m\)。將\(\lambda\)寫完整:\(\lambda=[\lambda_1,\lambda_2,\ldots,\lambda_m,0,0,\ldots,-1,\ldots,0]^T\),差值\(\mathbf{c^Tx'-c^Tx=c^T(-\theta\lambda)=\theta(c_e-\sum_{a_i\in B}\lambda_ic_i)}\),所以咱們要選使得這個值的絕對值最大的\(\mathbf{a}_e\)。那麼何時表示找到最優值應該中止呢?很明顯,就是對於全部\(\mathbf{a}_e\),這個差值都大於等於0,即目標函數再也不減少。所以,每次迭代,先計算差值,若是存在小於0的,就選一個使得差值絕對值最大的做爲入基向量。
嗯,接下來就是要考慮向量化操做。首先咱們看一下\(\lambda\)能不能向量化表示:因爲\(\mathbf{B}\lambda=\mathbf{a}_e\)(\(\lambda\)只取基係數部分),所以\(\lambda=\mathbf{B^{-1}}\mathbf{a}_e\),若是對整個矩陣\(\mathbf{A}\)左乘\(\mathbf{B^{-1}}\),這就頗有意思了,全部的非基列將變成該非基向量用基向量表示的係數,而全部的基列將變成\(e_k\),即合起來成爲一個單位陣的形式。這是很關鍵的一步,在單純形算法實現中也涉及到,先記下。進一步,咱們取\(\mathbf{c}\)的基部分\(\mathbf{c_B}\),這樣\(\mathbf{c_B^TB^{-1}A}\)就等於了上式中的\(\sum_{\mathbf{a}_i\in \mathbf{B}}\lambda_i\mathbf{c}_i\)的向量化形式(對全部的非基向量一同操做)。而後再加上一部分,變成\(\mathbf{c^T-c_B^TB^{-1}A}\),這就是最終的形式,稱之爲檢驗數\(\bar{\mathbf{c}}\)。很容易驗證,基向量對應的檢驗數都是0,咱們的目標就是經過迭代,使得\(\bar{\mathbf{c}}\geq0\),這時對於任何一個可行解\(\mathbf{y}\)(\(\mathbf{Ay=b,y\geq0}\)),都有\(\mathbf{c^Ty}\geq\mathbf{c_B^TB^{-1}Ay=c_B^TB^{-1}b=c_B^Tx_B=c^Tx}\),即\(\mathbf{x}\)就是最優的。
終於,一系列的講解結束,單純性算法也就瓜熟蒂落了。要將上面的一堆東西整理成一個簡短高效的可行算法並不簡單。先貼上算法僞代碼:
到此,終於介紹完了單純形算法。其餘還有一些要注意的地方,好比必定要注意檢驗數和原目標函數的\(\mathbf{c}\)是徹底不同的概念,在原約束爲不等式,須要加鬆弛變量的狀況下,他們可能相等,但內心必定要區分它們,同時,這種狀況下,基很容易找,就是鬆弛變量的那幾列構成的單位陣。可是若是原約束是等式,就須要本身找基,而且這時檢驗數每每就和目標函數參數不一樣了。
最後,本文所用的截圖均來自中科院計算所B老師的課程PPT,本人在學習該課程時也受益良多,對單純形算法也鑽研了比較長的時間,所以撰寫本文,但願給你們一個學習參考!其中可能有錯誤之處,歡迎指正討論。
對於原創博文:如需轉載請註明出處http://www.cnblogs.com/Kenneth-Wong/