自分でインストールした CBCソルバをPuLPで使用する

筆者の環境
MacOS Mojave v10.14.3, Python v3.7.2, PuLP v1.6.9, CBC v2.9.9


## PuLPから利用できるSolver

[PuLP](https://pythonhosted.org/PuLP/index.html)は線形計画問題を解くための Python パッケージです. PuLPのインストール時に, 合わせてCBCソルバもインストールされます. 別途、**GLPK**（無料）、**SCIP**(学術利用は無料, 商用有料), **Gurobi**（有料）、**CPLEX**（有料）などをインストールして使用することもできます.

PuLPのデフォルトソルバは, PuLPと一緒にインストールされるCBCソルバです. しかし, より新しいバージョンのCBCソルバを使用したい場合もあるでしょう. その場合は, 次のような処理をします.


## 最新版のCBCをインストールする
[公式サイト](https://projects.coin-or.org/Cbc)または, maxOSの場合は`homebrew`を使ってインストールすることができます. そのときは

```bash
brew tap coin-or-tools/coinor
brew install cbc --with-parallel --with-suite-sparse
```

を実行します. (`--with-parallel`で並列処理ができるようになります. `--with-suite-sparse`はおまけです)
> brew でインストールする際に使用できるオプションは
> `brew options <formula>`で確認できます.

`solver = COIN_CMD()`で使用されるCBCソルバは(下記「ソルバ指定」節参照), PuLPの設定ファイル(`pulp.cfg.*`)の`CbcPath`で指定されたソルバが使用されます (デフォルトではターミナル上で`cbc`と打ったときに使用されるソルバ). なので, 方法としては以下の2通りあります.

1. **自分でインストールしたcbcソルバにパスを通す**
2. **PuLPの設定ファイルを書き換える**

なので, **1か2のどちらか**を行えば十分です.

### 方法1. cbcソルバにパスを通す

maxOSの環境に合わせて話を進めます.
`brew`では特にインストール先を変更していない場合は`/usr/local/Cellar/`配下にバージョンごとにディレクトリが作成されます.[^1]
そのディクレトリ内のcbcフォルダのbinフォルダを環境変数PATHに追加してやれば良いです。下記の行を.bashrcや.zshrcに記載しておくことで、 ターミナル上で`cbc`を実行したときに, インストールしたcbcのバイナリファイルが使用されます.

```
PATH=usr/local/Cellar/cbc/2.9.9_1(自分がインストールしたバージョン)/bin:$PATH
```

 これでターミナル上で`cbc`を実行すれば, インストールしたcbcが使用されます. (ダメな場合はsource読み込みやterminal再起動などを試してみてください)

```bash
$ cbc
Welcome to the CBC MILP Solver 
Version: 2.9.9 
Build Date: Mar  1 2019 

CoinSolver takes input from arguments ( - switches to stdin)
Enter ? for list of commands or help
Coin:
```

これで, `COIN_CMD`により, このソルバが使用されます.


### 方法2. PuLPの設定ファイルを書き換える
`pulp.__path__`によって確認できるPulPモジュールの保存先には, `pulp.cfg.*`ファイルがあり, maxOSの場合は`pulp.cfg.osx`に使用するソルバのパスなどの情報が書かれています. そのcbcに関するパスを下のように書き換えます.

```bash
# CbcPath = cbc
CbcPath = /usr/local/Cellar/cbc/2.9.9_1(自分がインストールしたバージョン)/bin/cbc
```

こうすれば, `COIN_CMD`によりリンク先のCBCソルバーが使用されることになります.


### ソルバ指定

```python
from pulp import LpProblem
m = LpProblem()

# COIN CBCソルバ
solver = pulp.COIN_CMD()
m.solve(solver)
```

あとは, 上記のようにsolverとして`COIN_CMD`を指定すれば, 自分でインストールしたCBCを使用することができます.
> `solver = pulp.PULP_CBC_CMD()`とすると, PuLPと一緒にインストールされるCBCソルバを指定できます.

## オプション
おまけで, `COIN_CMD`, `PULP_CBC_CMD`共通で使用できるオプションの紹介です.

```python
PULP_CBC_CMD(path=None, keepFiles=0, mip=1, msg=0,
cuts=None, presolve=None, dual=None, strong=None,
options=[], fracGap=None, maxSeconds=None, threads=None)
```


- `keepFiles`を1(True)に設定すると, 定義した問題が記録されたmpsファイルとその解.solファイルが削除されずに残ります.
- 解きたい問題に整数変数が含まれる場合は`mip`をTrueに設定します.
  整数変数が含まれない場合はFalseに設定して解くことができます.
- `cuts` (Default: True)
  - cut generator (枝刈り)を行なって, 探索をより効率的に行います.
- `preserve` (Default: True)
  - モデルを分析して、冗長な制約, いくつかの変数を固定する制約、範囲に変換できる制約などを見つけます. 問題を最初に解決するには、効果がないことがわかっていない限り、これを行う価値があります.
- `strong` (Default: 5)
  - 強分岐で調べる変数の数を決定します.  どの変数に分岐するかを決めるために、コードはこの数までの満たされていない変数を選び、最小の上下の分岐を試みます.  
- `fracGap`は計算終了の判定となる, 解の上界と下界のGapのしきい値を指定できます.
- `maxSeconds`は最大計算時間を指定できます. (単位は秒)
- `threads`はソルバー実行の並列数を指定できます.
- `options`ではそれ以外のCBCオプションを設定できます.
  - 例えば`maxsol`オプションを使用する場合は
    `options = ['maxsol 1']`とします.
    - maxsolオプションは, 暫定解が何個見つかった時に計算を終了するかを指定できます. 最適解でなくても実行可能解が１つでも欲しい場合は`maxsol 1`とすればより早い時間で求めることができます.

[^1]: [【Homebrew】brewコマンドのインストール先を確認する](http://tweeeety.hateblo.jp/entry/2018/01/22/231003)