MATLABのGlobal Optimization Toolboxの使い方（GA実践編）

# 概要
Global Optimization Toolboxには大域的最適解（最小値）を求めるのに特化した関数が用意されています．
私は普段その中のメタヒューリスティック的な最適化手法の関数（Simulated annealing, Particle swarm, Genetic algorithm）を用いています．
数理最適化はツールとして用いており，専門ではありません・・・
ですので，専門用語など間違っていましたらご指摘お願い致します．
最適化の理論的な部分は今回省かせていただいて，Genetic algorithm（以下GA）を例に実際の使い方について書かせていただきます．
基本的な使い方は他の最適化手法の関数（特にParticle swarm）についても同様です．
Global Optimization Toolboxの関数それぞれの公式ドキュメントはいまだ英語の物が多く，触りたての時とまどいました．
しかし公式ドキュメントの数は非常に手厚いです（英語と格闘する必要はありますが）．
ざっくり触ってみたい，いますぐ使いたいんだ！という方のお役に立てれば幸いです．

## GAの理論の参考資料
[2021/5/4 追記] 下記2つはリンクが切れておりましたので，打ち消し線を追加しておきました．
こちらのページはとてもわかりやすく，大変お世話になりました．
 ~~http://ipr20.cs.ehime-u.ac.jp/column/ga/index.html~~
こちらは専門用語の英語と日本語がまとまっているのでリファレンスを解読するのに助かりました．
 ~~https://www.sist.ac.jp/~suganuma/kougi/other_lecture/SE/opt/GA/GA.htm~~

# 関数`ga`の使い方
それではここからGAの関数`ga`を使っていきます．
公式ドキュメントはこちらです
https://jp.mathworks.com/discovery/genetic-algorithm.html
https://jp.mathworks.com/help/gads/ga.html

## 入力引数・出力引数
ます，`ga`の基本的な構成です．

`x = ga(fun,nvars,A,b,Aeq,beq,lb,ub,nonlcon,IntCon,options)`

入力引数について軽く説明します．

- `fun`・・・最適化の目的関数．
- `nvars`・・・最適化したい変数の個数．変数をそのまま受け渡すのではないので注意
- `A`, `b`・・・線形不等式制約の行列とベクトル
- `Aeq`, `beq`・・・線形等式制約の行列とベクトル
- `lb`・・・下限
- `ub`・・・上限
- `nonlcon`・・・非線形制約
- `IntCon`・・・整数制約のベクトル．ここで指定された変数は正の整数として最適化される．これありがたいんじゃ〜
- `options`・・・オプション

`fun`と`nvars`は必須です．
そのほかの使わない引数は空行列として渡します．
注意しなければならないのは，例えばこのうち`Aeq`と`beq`使わないけど続く`lb`と`ub`は指定するという場合，`Aeq`と`beq`に空行列を渡さなければなりません．
忘れるとエラーとなります．
末尾`options`までかなりの引数があるので，そのほかの指定しない引数に空行列渡すのを忘れがちです・・・
逆に`ub`よりあとの引数（`nonlcon,IntCon,options`）は特に指定しないという場合，空行列を渡さず省略することができます．
これらすべての引数は構造体にして渡すことができますので，その方がミスが少ないかもしれません．

次に出力引数です．

`[x,fval,exitflag,output,population,scores] = ga(_)`

- `x`・・・最適値
- `fval`・・・最適値における目的関数の値
- `exitflag`・・・アルゴリズムの停止条件．この説明は割愛させていただきます（https://jp.mathworks.com/help/gads/ga.html#d117e51449）
- `output`・・・解法プロセスの概要が構造体として渡されます．目的関数の問題のタイプや乱数発生器の状態など（https://jp.mathworks.com/help/gads/ga.html#d117e51449）
- `population`・・・変数それぞれの最終的な個体集団
- `scores`・・・適合度


## 目的関数の作成
基本的に引数`fun`には関数ハンドルを渡します．
つまり目的関数を関数として記述し，その関数名のまえに@をつけたものを引数`fun`として与えればOKです．
たとえばベンチマーク関数Beale functionを使って作ってみます．
![Beale.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238878/c98d6927-7bfd-a167-4c50-4c9330fc003f.png)

Beale functionの式は以下です．

```math
f(x_1,x_2)=(1.5−x_1+x_1x_2)^2+(2.25−x_1+x_1x^2_2)^2+(2.625−x_1+x_1x^3_2)^2\\\
f_{min}(3,0.5)=0
```

そして次のように目的関数を作成します．

```matlab:Beale.m
function fval=Beale(x)
x1=x(1);
x2=x(2);
fval=(1.5-x1+x1*x2)^2+(2.25-x1+x1*(x2)^2)^2+(2.625-x1+x1*(x2)^3)^2;
```

メインスクリプトは次のようになります．

```matlab:ga_test.m
fun=@(x)Beale(x); %objective fuction
[x,fval]=ga(fun,2); %nvars=2
```

## 線形制約・非線形制約
`ga`では線形や非線形の等式・不等式制約を設けることができます．
上限下限の指定では対応できない場合や変数同士の関係が決まっている場合に用いています．
公式日本語ドキュメントが非常に詳しいです．
線形制約の指定方法についてはこちら
https://jp.mathworks.com/help/optim/ug/linear-constraints.html
非線形制約についてはこちら
https://jp.mathworks.com/help/optim/ug/nonlinear-constraints.html

## 上限下限
上限下限を指定します．
`lb`，`ub`のベクトルの長さは`nvars`と一致させてください．
Beale fuctionにおけるGAの探索範囲を

```math
-4.5 \leq x_1 \leq 4.5,\\ -4.5 \leq x_2 \leq 4.5,
```

とすると，

```matlab:ga_test.m
fun=@(x)Beale(x); %objective fuction
[x,fval]=ga(fun,2,[],[],[],[],[-4.5;-4.5],[4.5;4.5]); %nvars=2
```

となります．
`ga`では`lb`,`ub`は`nvars`行1列のベクトルで指定します．
しかし，Simulated Annealing(`simulannealbnd`, https://jp.mathworks.com/help/gads/simulannealbnd.html ) やParticle Swarm（`particleswarm`, https://jp.mathworks.com/help/gads/particleswarm.html ） では1行`nvars`列ベクトルで指定するので，最適化手法を切り替えた時に注意しなければならない点です．

## オプション
オプションではその他様々な設定ができます．
オプションは以下のように記述します．

`options = optimoptions('ga','Display','off'); % 最適化完了時の最適値の状態のメッセージを表示しない`

オプションはかなり種類が多いので，まだ理解が追いついていない部分が多いです．
そこで，私が普段使っている`options`を紹介したいと思います．

### 初期集団の指定
デフォルトでは，初期集団には乱数が与えられます．
`InitialPopulationMatrix`オプションを使えば，初期集団を指定することが可能です．
指定するには以下のように記述します．
Beale fuctionの最適解[3,0.5]から少し離れた初期集団を作成します．

```matlab:ga_test.m
x0=[4,4]; %start point
initpop=10*randn(20,2) + repmat(x0,20,1); %平均x0，分散10で正規分布する初期集団を作成
options=optimoptions('ga','InitialPopulationMatrix',initpop);
[x,fval]=ga(fun,2,[],[],[],[],[-4.5;-4.5],[4.5;4.5],[],options);
```

### GAの並列処理
GAやParticle Swarmでは並列処理が可能です．
デフォルトではオフになっています．

`options=optimoptions('ga','UseParallel',true);`

[2021/5/6追記]
並列処理のオプションをtrueにする場合は，並列 for ループ(`parfor`)などの入れ子とならないように注意してください．
実行自体は可能ですが，GAの並列処理オプションは無視され，逐次処理されます．
MATLAB R2020b以降では警告メッセージがでます．

# おわりに

6種の最適化手法（fminunc,patternsearch,ga,particleswarm,surrogateopt,GlobalSearch）のベンチマークのページがありますのでこちらもご覧ください．
https://jp.mathworks.com/help/gads/example-comparing-several-solvers.html
また，最適化手法のベンチマーク関数がこちらの記事でまとめられております．
https://qiita.com/tomitomi3/items/d4318bf7afbc1c835dda

それでは楽しいMATLABライフを！