注意:在本節中,我們描述了CVX的一些更進階的功能。我們建議你先跳過這一節,直到你對上面描述的基本能力感到滿意為止。
11.1消除二次型
我們強烈建議的一個特殊的改寫是消除二次型- -即像sum _ square,sum ( square ( . ) )或quad_ form這樣的函數- -隻要有可能使用範數來構造等價模型。我們的經驗告訴我們,二次型對于CVX所使用的底層求解器來說常常是一個數值挑戰。
我們承認,這種建議違背了傳統的智慧:二次型是典型的光滑凸函數,而範數是非光滑的,是以是笨拙的。但是對于CVX使用的圓錐曲線求解器,這種智慧恰恰是倒退的。它是最适合于圓錐體配方和解決方案的規範。實際上,二次形式是通過将它們轉換為圓錐形形式使用規範來處理的!這個轉換過程提出了一些有趣的縮放挑戰。如果模組化者能夠消除執行這種轉換的需要,那就更好了。
對于這種變化的一個簡單例子,考慮目标
minimize( sum_square( A * x - b ) )
在精确算術中,這恰好等價于
minimize( square_pos( norm( A * x - b ) ) )
但是如果我們完全消去平方,等價性也被保留了:
minimize( norm( A * x - b ) )
x的最優值在所有三種情況下都是相同的,但最後一個版本可能會産生更準确的結果。當然,如果你需要平方範數的值,你可以通過在事實之後平方範數來恢複它。
使用Quadrature _ Form的轉換有時會比較困難。例如,考慮
quad_form( A * x - b, Q ) <= 1
其中Q是一個正定矩陣。等效規範版本是
norm( Qsqrt * ( A * x - b ) ) <= 1
其中,Qsqrt是Q的一個合适的矩陣平方根。一種選擇是計算對稱平方根Qsqrt = sqrtm ( Q ),但這種計算破壞了稀疏性。如果Q是稀疏的,那麼計算一個基于Cholesky的稀疏平方根可能是值得的:
[ Qsqrt, p, S ] = chol( Q );
Qsqrt = Qsqrt * S;
有時候,有效的重新表述需要對問題等價的含義有實際的了解。例如,假設我們想在上面的目标中添加一個' 1正則項,由一些固定的、正的lambda權重:
minimize( sum_square( A * x - b ) + lambda * norm( x, 1 ) )
在這種情況下,我們通常不關心λ的特定的值;,而我們在一系列不同研究之間的權衡的剩餘*取向和x的1-norm。相同的權衡可以通過檢查這個修改模型研究:
minimize( norm( A * x - b ) + lambda2 * norm( x, 1 ) )
這是不完全相同的模型;λ和lambda2設定為相同的值不會産生相同的值(x)。但這兩種模型跟蹤相同的權衡曲線第二種形式可能會産生更精确的結果。
11.2雙變量索引
在一些模型,限制的數量取決于模型參數不隻是他們的大小。要建立這樣的模型很簡單在廢用,Matlab for循環。為了配置設定這些限制一個單獨的二進制變量,我們必須找到一個方法來調整雙變量的數量。出于這個原因,CVX支援索引雙變量。
在現實中,他們隻是标準Matlab細胞陣列的條目CVX雙變量對象。讓我們通過例子說明如何聲明和使用索引雙變量。考慮以下的半定規劃SeDuMi例子:

這個問題最小化半正定矩陣的主對角線的權重和,同時保持每個對角線上的和不變。問題的參數為向量b∈Rn的元素,優化變量為對稱矩陣X∈Rn × n。此模型的CVX版本是
cvx_begin
variable X( n, n ) symmetric
minimize( ( n - 1 : -1 : 0 ) * diag( X ) );
for k = 0 : n-1,
sum( diag( X, k ) ) == b( k+1 );
end
X == semidefinite(n);
cvx_end
如果我們想要獲得n個簡單等式限制的對偶資訊,我們需要一種方法來為for循環中的每個限制配置設定一個單獨的對偶變量。具體如下:
cvx_begin
variable X( n, n ) symmetric
dual variables y{n}
minimize( ( n - 1 : -1 : 0 ) * diag( X ) );
for k = 0 : n-1, sum( diag( X, k ) ) == b( k+1 ) : y{k+1};
end
X == semidefinite(n);
cvx_end
語句對偶變量y { n }配置設定一個包含n個對偶變量的單元格數組,并将結果存儲在Matlab變量Z中。for循環中的等式限制以y { k + 1 }為參考進行了增廣,使得每個限制被配置設定一個單獨的對偶變量。當發出cvx _ end指令時,CVX将計算這些對偶變量的最優值,并将它們存入n個單元數組y中。
這個例子固然有點簡單化。經過仔細的安排,可以重寫這個模型,以便将n個等式限制合并為一個向量限制,而這反過來又隻需要一個向量對偶變量。1對于不适合這種簡化的更複雜的示例,請參見檔案
examples/cvxbook/Ch07_statistical_estim/cheb.m
在Cvx分布中。在這個問題中,for循環中的每個限制是一個線性矩陣不等式,而不是一個标量線性方程;是以,索引對偶變量是對稱矩陣,而不是标量。
11.3 逐漸逼近法
注意:如果您被CVX的警告消息引用到此網頁:歡迎!請仔細閱讀本節,充分了解為什麼在CVX模型中使用log、exp等函數需要特别小心。
在1.2版之前,指數家族的函數exp、log、log _ det和其他函數不能在CVX中使用。直到最近,CVX使用了所謂的對稱原/對偶求解器,這些求解器根本無法支援這些函數( 2 )。最近,諸如Mosek等求解器增加了支援。
對于指數錐。
對于不支援指數錐的求解器,我們構造了一個連續近似啟發式,允許對稱的原始/對偶求解器支援指數族函數。對該方法的精确描述超出了本文的範圍,但大緻來說,該方法的過程如下:
1 .選擇一個初始近似中心點xc = 0。
2 .對每個log / exp /熵項構造多項式逼近,在xc的鄰域内精确。
3 .求解這個近似模型得到它的最優點~ x。
4 .如果~ x滿足原始模型達到足夠精度的最優性條件,則退出。
5 .否則,将xc移向~ x,并重複步驟2 - 5。
再次,這是一種高度簡化的描述方法;例如,我們實際上同時使用原解和對偶解來指導我們對xc和終止的判斷。
這種方法對于許多問題已經被證明是非常有效的。然而,與許多啟發式方法一樣,它并不完美。即使對于已知有解決辦法的問題,它有時也無法收斂。即使當它收斂時,由于它的疊代方法,它也比标準求解器慢幾倍。是以,最好是謹慎和謹慎地使用它。以下是一些具體的使用技巧:
首先,如果您有權通路Mosek,請使用它,因為在版本9中添加了對指數錐的本機支援。
在許多情況下,完全等效的模型可以在沒有它們的情況下建構,并且應該總是首選。例如,限制sum_log(x) >= 10
可以表達為geo_mean功能
geo_mean(x) >= log(10)^(1/length(x))
許多因素最大化問題通常使用log_det編寫,但事實上,往往是不必要的。例如,考慮目标
minimize( log_det(X) )
CVX實際上把這個内部:
minimize( n*log(det_rootn(X)) )
是以你能做的隻是把對數,而解決這個:
minimize( det_rootn(X) )
log_det(X)的值可以在模型完成後簡單計算出來。不幸的是,這隻有在log_det是目标中唯一的項時才有效;是以,例如,這個函數不能,不幸的是,以類似的方式轉換。
minimize( log_det(X) + trace(C*X) )
-第三,嘗試不同的求解器。SeDuMi的逐次逼近法往往比SDPT3更有效。是以,如果預設的求解器選擇不能給你的模型一個解決方案,嘗試切換到這些求解器中的一個。-
第三,嘗試你的問題的小執行個體。如果它們在大執行個體失敗的情況下成功了,那麼至少你可以在考慮其他選項(如不同的求解器)之前确認模型的行為是否符合你的期望。
不幸的是,底線是我們不能保證逐次逼近法能成功處理你的特定模型。如果你遇到了問題,請你送出一份錯誤報告,但我們不能保證能修複。
11.3.1 抑制警告
由于所有這些注意事項,我們認為有必要在使用時發出警告,以便使用者了解其實驗性質。當你第一次試圖在CVX中指定一個使用需要逐次逼近法的函數的模型時,這個警告就會出現。事實上,這個警告很可能把你帶到本手冊的這一部分。
如果你想在将來抑制這個警告,隻需在構模組化型前發出
cvx_expert true
指令即可。如果您希望在今後所有的MATLAB會話中抑制這一資訊,請在這一指令之後再執行cvx_save_prefs指令。
11.4 幂函數和p值
為了實作幂函數xp的凸或凹分支以及p值的p值‖x‖p,CVX使用了[AG00]所述的SDP/SOCP轉換方法的增強版。這種方法是精确的--隻要指數p是有理的。為了确定積分值pn, pd,使pn/pd=p,CVX使用Matlab的rat函數,其預設公差為10-6。目前還沒有辦法改變這個公差。更多細節請參見MATLAB的rat函數文檔。
所得模型的複雜性大緻取決于值pn和pd的大小。讓我們來介紹一下這種複雜性的更精确的衡量标準。對于p=2,一個限制xp≤y正好可以用一個2×2的LMI表示。
對于p = pn/pd的其他值,CVX會産生一些取決于pn和pd的2×2的LMI;我們用k(pn, pd)表示這個數字。 (在某些情況下還會産生額外的線性限制,但我們在此分析中忽略它們)。例如,對于p=3/1,我們有
是以k(3,1)=2。一項經驗研究表明,對于p = pn/pd > 1,我們有
其中α(pn)項與log2項相比增長非常緩慢。事實上,對于pn≤4096,我們已經驗證了α(pn)通常是1或2,但偶爾是0或3。在0<p<1和p<0的情況下也得到了類似的結果。
這種SDP表示法的成本對于幾乎所有有用的p值來說都是比較小的。如果這個門檻值不适合你,你可以使用指令cvx_power_warning(thresh)來改變它,其中thresh是所需的截止值。将門檻值設定為Inf可以完全禁用它。和cvx_precision指令一樣,你可以在一個模型内調用cvx_power_warning來改變單個模型的門檻值;或者在一個模型外進行全局改變。該指令總是傳回門檻值的先前值,是以如果你願意,你可以儲存它并在完成模型後恢複它。您可以通過調用沒有參數的 cvx_power_warning 來查詢目前值。
11.5 過度确定的問題
當變量或集合中的結構沒有被正确識别時,通常會出現過度确定的狀态資訊。例如,考慮尋找矩陣W∈Rn×n的最小對角線加法以使其成為正半定的問題。
CVX中,這個問題可能是表示如下:
n = size(W,1);
cvx_begin
variable D(n,n) diagonal;
minimize( trace( D ) );
subject to
W + D == semidefinite(n);
cvx_end
如果我們将此規範應用于矩陣W=randn(5,5),就會發出警告:
警告:等價限制過度;問題可能不可行。
變量cvx_status被設定為過度。這裡發生的情況是,semidefinite(n)語句傳回的未命名變量是對稱的,但W是固定的、不對稱的。是以,如上所述,該問題是不可行的。但這裡還有n2個平等限制,而且隻有n + n ∗ (n + 1)/2個唯一的自由度,是以問題是過度确定的。我們可以通過将平等限制替換為70 第11章 糾正這個問題。 sym( W ) + D == semidefinite(n); sym是我們提供的一個函數,可以提取其參數的對稱部分;也就是說,sym(W)等于0.5 * ( W + W' )。
11.6 向原子庫添加新函數
CVX允許定義新的凸函數和凹函數,并将其添加到原子庫中,有兩種方法,在本節中介紹。第一種方法很簡單,CVX的很多使用者都可以(也應該)使用,因為它隻需要了解基本的DCP規則集。第二種方法非常強大,但有點複雜,應該被認為是一種進階技術,隻有那些真正熟悉凸分析、嚴謹的凸程式設計和CVX目前狀态的人才能嘗試。
如果你已經實作了一個你認為對其他使用者有用的凸或凹函數,請告訴我們;我們将很高興在未來的版本中加入它。
11.6.1 通過DCP規則集的新函數
建構一個能在CVX中工作的新函數的最簡單方法是使用完全符合DCP規則集的表達式來建構它。例如,考慮一下閉區間函數
要在CVX中實作這個函數,隻需建立一個包含函數
y = deadzone( x )
y = max( abs( x ) - 1, 0 ) 的deadzone.m檔案。
這個函數的工作原理與你在CVX之外所期望的一樣--也就是說,當它的參數是數值的時候。但是由于Matlab的運算符重載功能,如果調用一個仿射參數,它也會在CVX中工作。CVX将正确地得出結論,這個函數是凸的,因為所有進行的操作都符合DCP的規則:abs被認為是一個凸函數;我們可以從它那裡減去一個常數,我們可以取結果和0的最大值,這就得到了一個凸函數。是以,我們可以在CVX規範中任何可能使用abs的地方自由使用deadzone,比如說,因為CVX知道它是一個凸函數。
我們要強調的是,以這種方式定義函數時,你使用的表達式必須符合DCP規則集,就像它們直接插入到CVX模型中那樣。例如,如果我們用min代替max.
函數y = deadzone_bad( x )
y = min( abs( x ) - 1, 0 )
那麼這個修改後的函數就不能滿足DCP規則集。該函數在CVX規範之外也能工作,對于一個數字參數x,它能愉快地計算出min{|x|-1, 0}的值。但在CVX規範之内,如果用一個非常數參數調用,它将産生一個錯誤。
11.6.2 通過部分指定問題的新函數
在CVX中定義新函數的更進階方法依賴于以下凸分析的基本結果。
假設S⊂Rn×Rm是一個凸集,g : (Rn×Rm) → (R ∪+∞) 是一個凸函數。
那麼f : Rn → (R ∪ +∞), f (x) , inf { g(x, y) | ∃y, (x, y) ∈S }也是一個凸函數。
(這個規則有時被稱為部分最小化規則。)我們可以把凸函數f看作是凸優化問題系列的最優值,以x為索引或參數,最小化g(x, y),服從(x, y)∈S,優化變量為y。
有一個特例應該非常熟悉:如果m = 1,g(x, y) , y,那麼f (x) , inf { y | ∃y, (x, y) ∈S }就給出了f的經典表征:epi f = S + ({0} × R+) ,其中0∈Rn。
在CVX中,你可以用這種方式定義一個凸函數,即作為一個參數化的有規律的凸程式家族的最優值。我們把這種情況下的底層凸程式稱為不完全規範--之是以這樣稱呼是因為在建構規範時參數(也就是函數輸入)是未知的。不完全規範的概念起初看起來有點複雜,但它是非常強大的機制,使CVX能夠支援各種各樣的函數。
讓我們看一個例子,看看它是如何工作的。考慮機關半寬的Huber懲罰函數h(x):
我們可以用以下凸QP族來表達Huber函數,以x為參數:
我們注意到,這個QP中的目标函數和限制函數在v、w和x中是(共同)凸的。我們可以在CVX中實作Huber懲罰函數如下:
function cvx_optval = huber( x )
cvx_begin
variables w v;
minimize( w^2 + 2 * v );
subject to abs( x ) <= w + v;
w <= 1; v >= 0;
cvx_end
如果huber被調用時有一個數字值x,那麼在到達cvx_end語句時,CVX将找到一個完整的規範,并解決這個問題以計算結果。CVX将最佳目标函數值放入變量cvx_optval中,函數将該值作為其輸出傳回。當然,通過解QP來計算一個數值x的Huber函數是非常低效的。但它确實給出了正确的值(在核心求解器的精度範圍内)。
然而,最重要的是,如果在CVX規範中使用Huber,并以仿生CVX表達式作為其參數,那麼CVX将做正确的事情。特别是,CVX将識别出Huber函數,并以仿生參數調用,作為一個有效的凸表達式。在這種情況下,函數Huber将包含一個特殊的Matlab對象,在約
束條件和目标中代表函數調用。是以,根據DCP規則集,函數huber可以用在任何可以使用傳統凸函數的地方,在限制條件或目标函數中使用。
對于凹函數也有一個相應的發展。如上所述,給定一個凸集S,和一個凹函數g:(Rn × Rm) → (R ∪ -∞),函數
是凹的。如果g(x,y) ,y,那麼
給出f的超圖表示:
在CVX中,凹形不完全規範是指使用最大化目标而不是最小化目标的規範;如果建構得當,它可以在CVX規範中的任何地方使用傳統的凹形函數。
關于凹形不完全規範的例子,請看以下函數
它的超圖可以用一個線性矩陣不等式來表示:
是以我們可以在CVX中實作這個函數如下:
function cvx_optval = lambda_min_symm( X )
n = size( X, 1 );
cvx_begin
variable y;
maximize( y );
subject to X + X' - y * eye( n ) == semidefinite( n );
cvx_end
如果提供了一個X的數值,這個函數将傳回min(eig(X+X'))(在數值公差範圍内)。然而,這個函數也可以在CVX限制條件和目标中使用,就像原子庫中的任何其他凹形函數。
在使用不完整規格定義函數時,有兩個實際問題,我們将用上面的 huber 例子來說明這兩個問題。首先,按照寫法,這個函數隻對标量值起作用。要把它(按元素)應用于一個向量,需要我們在for循環中周遊元素--這是一個非常低效的做法,特别是在CVX中。一個更好的方法是擴充 huber 函數來處理向量輸入。事實上,這樣做相當簡單:我們隻需建立一個多目标版本的問題。
function cvx_optval = huber( x )
sx = size( x );
cvx_begin
variables w( sx ) v( sx );
minimize( w .^ 2 + 2 * v );
subject to
abs( x ) <= w + v;
w <= 1;
v >= 0;
cvx_end
這個版本的 huber 實際上将并行地建立問題的 sx "執行個體";并且當用于 CVX 規範時,将被正确處理。
第二個問題是,如果huber的輸入是數字,那麼直接計算是一種比解決QP更有效的計算結果的方式。(更重要的是,多目标版本不能用于數字輸入)。一個解決方案是将兩個版本放在一個檔案中,用一個适當的測試來選擇要使用的正确版本。
function cvx_optval = huber( x )
if isnumeric( x ),
xa = abs( x );
flag = xa < 1;
cvx_optval = flag .* xa.^2 + (~flag) * (2*xa-1);
else,
sx = size( x );
cvx_begin
variables w( sx ) v( sx );
minimize( w .^ 2 + 2 * v );
subject to
abs( x ) <= w + v;
w <= 1; v >= 0;
cvx_end
end
或者,您可以建立兩個不同版本的函數,一個用于數字輸入和一個用于CVX表達式,并将廢版本在一個叫@cvx的子目錄。(不包括這個目錄在Matlab路徑;隻包括其母公司)。Matlab将自動調用@cvx目錄中的版本,當其中一個參數是一個廢變量。這是方法的版本huber CVX原子庫中找到。
一個好方法學習更多關于使用不完整的規範是檢查的一些例子已經在CVX原子庫。不錯的選擇包括胡貝爾,inv_pos、lambda_min lambda_max, matrix_frac, quad_over_lin, sum_largest等等。一些有點難以閱讀,因為診斷或錯誤檢查代碼,但這些都是相對簡單的。