PythonのSDP実行時間比較

本記事ではSDPを解くためのpythonライブラリである`PICOS`と`CVXPY`のSDP実行時間を比較します．

# SDP（半正定値計画問題）
**半正定値計画問題(SDP; SemiDefinite Programming)**は凸最適化問題の一種です．
数理計画やシステム制御の分野で注目を浴びており，現在盛んに研究されています．

[半正定値計画問題-wikipedia](https://ja.wikipedia.org/wiki/%E5%8D%8A%E6%AD%A3%E5%AE%9A%E5%80%A4%E8%A8%88%E7%94%BB%E5%95%8F%E9%A1%8C)

SDPは例えば以下のような問題です．

>正方行列$A$が与えられたとする．
$P\succ0$, $PA-A^TP\prec0$
を満たす行列Pを求めよ．
（$P \succ 0$は $P$ が正定行列であることを表す．）

SDPでは制約条件が**線形行列不等式（LMI;Linear Matrix Inequality）**で与えられます．

この問題に解Pが存在することとAの固有値の実部が全て負であることは同値です．
よって，この問題が解ければAの固有値が全て負であることを確認することができます．

この例だとAの固有値を直接計算した方が早いと言われてしまいますが，
**複数のLMI制約**が組み合わさったり，**目的関数を最適化**したい場合にはSDPとして解く必要があります．
システム制御の分野では制御仕様を複数のLMI制約で表現できる場合があり，
SDPを解けることは非常に有用です．

SDPを数値的に解くツールとして`MATLAB`や`Python`が利用できます．

# PythonのSDPライブラリ
PythonでSDPを解くためのライブラリは私の知る限り`PICOS`，`CVXPY`，`PYLMI-SDP`の3つです．
そのうち`PYLMI-SDP`は使用例やドキュメントを発見できなかったため扱いません．

`PICOS`や`CVXPY`は記述されたSDPをソルバーに渡すインターフェースの役割をしています．
ソルバーは実際に問題を解く作業を請け負っている部分です．

`PICOS`と`CVXPY`でサポートされているSDPソルバーを以下に示します．

**表：`PICOS`, `CVXPY`が対応するSDPソルバー**

||*CVXOPT*|*MOSEK*|*SMCP*|*SCS*|*SDPA-P*|
|:---:|:---:|:---:|:---:|:---:|:---:|
|`PICOS`|○|○|○|-|○|
|`CVXPY`|○|○|-|○|-|


#### 各ソルバーの説明
- ***CVXOPT***・・・`PICOS`, `CVXPY`と一緒にインストールされる．
- ***MOSEK***・・・商用．アカデミックライセンスは無料．
- ***SMCP***・・・[この論文](https://link.springer.com/article/10.1007%2Fs12532-010-0016-2)に基づいて作られた．
- ***SCS***・・・[この論文](https://web.stanford.edu/~boyd/papers/scs.html)に基づいて作られた．`CVXPY`と一緒にインストールされる．
- ***SDPA-P***・・・多分[この論文](https://www.researchgate.net/publication/247456489_SDPA_SemiDefinite_Programming_Algorithm_User's_Manual_-_Version_600)に基づいて作られた．

上記の通り，たくさんのライブラリおよびソルバーがあります．
多くの人が開発し充実しているのは良いのですが，**どれを使うべきなのか分かりません**．
そこで，これらを使ったSDPの実行時間を比較してみようと思います．

今回は上の表のうち`SMCP`と`SDPA-P`を除いた以下の5つの組み合わせを比較します．
`PICOS`×***CVXOPT***, `PICOS`×***MOSEK***
`CVXPY`×***CVXOPT***, `CVXPY`×***MOSEK***, `CVXPY`×***SCS***

*他のソルバーも今後掲載予定

# 手順
1. 定数行列 $A$ を`numpy.random`で生成．
1. 以下のSDPを解く．   
$ ~~~~~~~~~~~~~~~~~ \rm{min}~~\rm{trace}(\it{P}) ~~~ \rm{s.t.} ~~ \it{P}\succ \rm{0},~\it{PA-A^TP}\prec \rm{0}.$ 
1. `%timeit`で平均実行時間を計測．
1. 以下のパラメータ毎に計測する．

　・定数行列 $A$ および変数行列 $P$ の次数 $n$
$ ~~~~~~~~~~~~~~~~~  1\leq n \leq20$
　・許容誤差 $tol$
$ ~~~~~~~~~~~~~~~~~ tol=\{ 10^{-4},10^{-6},10^{-8},10^{-10},10^{-12} \}$



# 実行コード
https://github.com/teatea6666/sdpcmp/blob/master/SDPSpeedCompare.ipynb

# 実行環境
|ライブラリ|バージョン|
|:---:|:---:|
|anaconda| 2019.03|
|python| 3.7|
|Jupyter Lab|
|picos| 2.0.0|
|cvxpy| 1.0.28|
|cvxopt| 1.2.0|
|mosek| 9.1.13|
|scs| 2.1.1.2|


# 結果
![matsize.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372117/99056ec7-9ba9-1485-5149-b985798a386e.jpeg)
横軸は行列のサイズで，縦軸は実行時間です．
許容誤差は $tol=1e-08$ で固定しています．

一番速いのは`PICOS`×___MOSEK___です．
次点は`PICOS`×***CVXOPT***です．
それ以外はほぼ同じです．

![tolerance.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372117/16bcd4ef-dcf1-4da3-3198-81ad690da299.jpeg)
横軸は許容誤差で，縦軸は実行時間です．
行列のサイズは $n=2$ で固定しています．

一番速いのは`PICOS`×___MOSEK___です．
次点は`PICOS`×***CVXOPT***です．
それ以外はほぼ同じです．
ただし，`PICOS`×***MOSEK***は $10^{-10}$ 以上の許容誤差では小さすぎる旨のエラーが出て実行できませんでした．

#まとめ
・変数や制約が大量にあったり，大量のSDPを解く場合には，`PICOS`×***MOSEK***がおすすめ．
・***MOSEK***の商用ライセンスまたは無料アカデミックライセンスを利用できない方は`PICOS`×***CVXOPT***を使いましょう．

*※各ソルバーは異なるアルゴリズムを採用しているので，問題の性質によって結果が変わる可能性があります．*

# 備忘録
・`PICOS`は最近ver2.0にアップデートされてバグあり(2020/3/22現在)．
　→ライブラリを書き換えてしのぐ．
　（searchTime の Zero Division Error ： 該当行をコメントアウトし, 適当な値(overheadTime=1)を入れる．）
・`PICOS`×***MOSEK***ではobjectiveを'find'に設定するとエラーが出る．'min'で適当な関数を入れて解く．
・`CVXPY`で謎のverboseが発生するバグが発生，anacondaをアップデートしたら解決．

# 参考にした情報
・[PICOSドキュメント](https://picos-api.gitlab.io/picos/)
・[CVXPYドキュメント](https://www.cvxpy.org/)
・[PICOSメモ (半正定値計画問題)](http://szmlb.hatenablog.com/entry/2018/01/01/231055)
・[PICOSを使って錐計画問題を解く](http://www.mathopt.sakura.ne.jp/picos.html)
・[Semidefinite programming in Python](https://peterwittek.com/sdp-in-python.html)
・[LMIによるシステム制御 - ロバスト制御系設計のための体系的アプローチ](https://www.amazon.co.jp/LMI%E3%81%AB%E3%82%88%E3%82%8B%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E5%88%B6%E5%BE%A1-%E3%83%AD%E3%83%90%E3%82%B9%E3%83%88%E5%88%B6%E5%BE%A1%E7%B3%BB%E8%A8%AD%E8%A8%88%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E4%BD%93%E7%B3%BB%E7%9A%84%E3%82%A2%E3%83%97%E3%83%AD%E3%83%BC%E3%83%81-%E8%9B%AF%E5%8E%9F%E7%BE%A9%E9%9B%84/dp/4627921012/ref=asc_df_4627921012/?tag=jpgo-22&linkCode=df0&hvadid=288872634447&hvpos=&hvnetw=g&hvrand=17342343416617666624&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009330&hvtargid=pla-528868170218&psc=1&th=1&psc=1)
・[行列不等式アプローチによる制御系設計 (システム制御工学シリーズ) ](https://www.amazon.co.jp/%E8%A1%8C%E5%88%97%E4%B8%8D%E7%AD%89%E5%BC%8F%E3%82%A2%E3%83%97%E3%83%AD%E3%83%BC%E3%83%81%E3%81%AB%E3%82%88%E3%82%8B%E5%88%B6%E5%BE%A1%E7%B3%BB%E8%A8%AD%E8%A8%88-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E5%88%B6%E5%BE%A1%E5%B7%A5%E5%AD%A6%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E5%B0%8F%E5%8E%9F-%E6%95%A6%E7%BE%8E/dp/4339033235/ref=pd_aw_sbs_14_7?_encoding=UTF8&pd_rd_i=4339033235&pd_rd_r=3012d9b4-51ca-4be3-bcd5-36cd21bdbdab&pd_rd_w=d3p5i&pd_rd_wg=gyoow&pf_rd_p=1893a417-ba87-4709-ab4f-0dece788c310&pf_rd_r=QVTZB96NPTWPADNZBQRH&psc=1&refRID=QVTZB96NPTWPADNZBQRH)