M1/M2 macでPython−MIPを動かすには？（Rosettaを使わない方法）


:::note info
本稿は、brew によるインストール環境や python, pip の動作環境、Command Line Tools, Git 等のビルド環境が整った環境での操作を前提としております。
:::

## M1/M2でPython−MIPは動かない？ 
2024年1月の時点では、M1/M2 macでは数理最適化のライブラリであるPython−MIPはすんなりと動作しません。それは @SaitoTsutomu さんが、『[M1/M2 macでPython−MIPを動かすには？](https://qiita.com/SaitoTsutomu/items/fbc33299e1906a238f53)』で解説されている通り、`pip install mip`でインストールされるPython−MIPに同梱されているソルバーのCBCライブラリが、x86_64で動作するバイナリ（cbc-c-darwin-x86-64.dylib）だからです。公開されている[python-mipのGitHub](https://github.com/coin-or/python-mip/)の中身をみてみても、既にビルドされたバイナリのライブラリが含まれており、ソースコードからビルドされるような仕組みにはなっておりません。本家の[Python−MIP](https://www.python-mip.com/)のサイトでは、
> Comes with CBC binaries
> The Python-MIP package comes pre-installed with CBC binaries for most used operational systems (Windows, MacOS and Linux). Super easy to run!

という特徴が掲げられており、それが仇になっているようです。今後、arm64対応のCBCソルバーが同梱される方向性だとは思いますが、現時点では工夫して動作するようにしなければなりません。

本稿では、次のように Python 3.12.1 で動作を確認します。
```shell
% python -V
Python 3.12.1
```
とりあえず、何も考えずにpipで Python−MIP をインストールしてみます。
```shell
% pip install mip
（中略）
Successfully installed mip-1.14.2
```
（`pip install mip==1.15.0`で最新版を指定してインストールすることはできませんでしたが、ここでは動作させることを目指すことを目的としますので、最新版ではないことについては目をつぶって進めさせて頂きます。）
早速モデルを作って動かそうとしてみると、次のように想定どおりエラーとなります。
```shell
% python -c 'import mip; m = mip.Model()'

An error occurred while loading the CBC library:　（中略）'.../site-packages/mip/libraries/cbc-c-darwin-x86-64.dylib'
 (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64')),
（中略）
NameError: name 'cbclib' is not defined
```
x86_64で動作するバイナリを使おうとしていて、arm64用ライブラリが必要ですというエラーが起きます。

## M1/M2でPython−MIPを動かす方法
CBCのライブラリを動かすためには、次の3通りの方法が考えられそうです。

1. **x86_64エミュレータ「Rosetta2」を有効にして、CBCライブラリをx86_64バイナリのまま利用する方法**
こちらの方法は、前出の @SaitoTsutomu さんのエントリで詳しく解説されております。[そちら](https://qiita.com/SaitoTsutomu/items/fbc33299e1906a238f53)をご覧ください。
1. **arm64で動作するCBCライブラリをビルドして、そのライブラリを利用する方法**
本家 Python−MIP サイトの Installation の説明のなかにある [Using your own CBC binaries (optional)](https://python-mip.readthedocs.io/en/latest/install.html#using-your-own-cbc-binaries-optional) でふれられている方法です。_以降でその操作を見ていきましょう。_
1. **dockerで動かす方法**
[Python-MIP をM1 Mac × dockerで動かす](https://zenn.dev/snail_tanishi/scraps/9174c51981cade) に詳しく書かれております。本質的ではないように思えますので本稿では踏み込んで言及しません。

## arm64で動作するCBCライブラリをビルドする

Python−MIP サイトには、Ubuntu等のLinuxを前提としたガイドが次のように記されております。それぞれの操作について日本語でコメントを追記して紹介します。
```shell
#### (1) ビルドするための関連するパッケージをインストールする
# install dependencies to build
sudo apt-get install gcc g++ gfortran libgfortran-9-dev liblapack-dev libamd2 libcholmod3 libmetis-dev libsuitesparse-dev libnauty2-dev git
#### (2) ダウンロードしてCBCをコンパイルするためのディレクトリを準備する 
# directory to download and compile CBC
mkdir -p ~/build ; cd ~/build
#### (3) 以下の手順を進めるためのスクリプト coinbrew をダウンロードする
# download latest version of coinbrew
wget -nH https://raw.githubusercontent.com/coin-or/coinbrew/master/coinbrew
#### (4) coinbrew を使って、CBCと関連するソースコードをダウンロードする
# download CBC and its dependencies with coinbrew
bash coinbrew fetch Cbc@master --no-prompt
#### (5) coinbrew を使って、CBCライブラリをビルドして　--prefix で指定されたフォルダにインストールする
# build, replace prefix with your install directory,  add --enable-debug if necessary
bash coinbrew build Cbc@master --no-prompt --prefix=/home/haroldo/prog/ --tests=none --enable-cbc-parallel --enable-relocatable
```
この記述はLinuxを対象としていますが、手順(1)をM1/M2 macに合わせた手順で環境を整えられれば、手順(2)〜(5)は同じ手順で進められます。

#### 手順(1) ビルドするための関連するパッケージをインストールする
私はこの手順に最も苦労しました。本稿最初に記載しましたが、ビルド環境が整っていることを前提としておりますが、読者の皆さまの環境に応じて必要となる操作が異なるケースもございます。手順(5)のビルドのタイミングでビルドエラーが色々と出てしまうのは、この環境が整っていないことによる可能性が高いと考えられます。`brew install gcc git` だけでも手順(2)以降に進むことができますので、途中でエラーが発生したら不足しているパッケージを追加する方針でもよいかと思います。私の環境では、`brew install bash`（理由は手順（４）に後述）と`brew install suite-sparse`が必要でした。なお、`gfortran`は `gcc` に含まれているので特に指定したインストールは不要でした。
#### 手順(2) ダウンロードしてCBCをコンパイルするためのディレクトリを準備する 
こちらはそのままの通り、作業用のディレクトリを準備します。
```shell
mkdir -p ~/build ; cd ~/build
```
#### 手順(3) 以下の手順を進めるためのスクリプト coinbrew をダウンロードする
mac で wget コマンドを使おうとすると、`brew install wget` でインストールしなければなりません。その代わりに、curl コマンドが標準で備わっていますので、次の操作でダウンロードします。
```shell
curl -OL https://raw.githubusercontent.com/coin-or/coinbrew/master/coinbrew
```
#### 手順(4) coinbrew を使って、CBCと関連するソースコードをダウンロードする
手順(3)でダウンロードしたファイル`coinbrew`をbashで実行すると必要なソースコードをgitを使ってダウンロードしてくれます。その操作において、macが標準で備えているbashを使うと以下のようなエラーが発生して処理が進められません。
```shell
% bash coinbrew fetch Cbc@master --no-prompt

Welcome to the COIN-OR fetch and build utility, version 2

To use the legacy version of coinbrew, '$ wget https://raw.githubusercontent.com/coin-or/coinbrew/v1.0/coinbrew'
For help, run script with --help or see https://coin-or.github.io/coinbrew
Please report issues at https://github.com/coin-or/coinbrew
Detailed build documentation at https://coin-or.github.io

Error: This script requires bash version 4 or greater.
You are probably on macOS, which comes with version 3.
Please install a recent bash using homebrew (https://brew.sh).
Exiting.
```
エラーの内容から、macOSのbashはバージョンが3系であり、このスクリプトはbashバージョンが4系以降を要求されております。そこで手順(1)に戻る必要があり、`brew install bash`でバージョン5系（私の環境ではバージョン5.2.21）をインストールして、優先的にそのコマンドが動作するようにします。
改めて同じ操作をすると、次のようにモジュールのダウンロードが始まります。
※ダウンロードには少々時間がかかります。
```shell
% bash coinbrew fetch Cbc@master --no-prompt

Welcome to the COIN-OR fetch and build utility, version 2
（中略）
##################################################
### Fetching Cbc master
##################################################
（中略）
From https://github.com/coin-or/Cbc
```
念のため途中でエラーなどが発生してないことを確認してください。

#### 手順(5) coinbrew を使って、CBCライブラリをビルドして--prefixで指定されたフォルダにインストールする
```shell
% bash coinbrew build Cbc@master --no-prompt --prefix=/opt/local --tests=none --enable-cbc-parallel --enable-relocatable

Welcome to the COIN-OR fetch and build utility, version 2
（中略）
################################################
### Building version master
### with existing versions of dependencies.
### Ctrl-c and run 'fetch' to switch versions
### or to ensure correct dependencies
################################################
（中略）
Install completed. If executing any of the installed
binaries results in an error that shared libraries cannot
be found, you may need to
  - add 'export LD_LIBRARY_PATH=/opt/local/lib' to your ~/.bashrc (Linux)
  - add 'export DYLD_LIBRARY_PATH=/opt/local/lib' to ~/.bashrc (OS X)
```
途中WARNINGが数行出力されますが、ERRORでなければビルドとインストールは成功しています。`--prefix`で指定したフォルダの下の`/opt/local/lib`に次のようなライブラリがインストールされます。

libCbc.dylib
libCgl.dylib
libClp.dylib
libCoinUtils.dylib
libOsi.dylib
libOsiCbc.dylib
libOsiClp.dylib
libOsiCommonTest.dylib
※これらはシンボリックリンクです。ファイル名に".0."が途中に入るファイル（例： libCbc.0.dylib）が実体です。このほかに、拡張子が".la"の静的リンク用のライブラリもインストールされます。

なお、ビルドの手順の最後に出力されている`add 'export DYLD_LIBRARY_PATH=/opt/local/lib' to ~/.bashrc (OS X)`は、環境変数にダイナミックリンクライブラリのファイルパスを指定する指示ですが、macOS ではセキュリティのために環境変数`DYLD_LIBRARY_PATH`の指定は無効となります。デフォルトのシェル zsh の`~/.zprofile`や`~/.zshrc`に記載しても設定されません。
## arm64で動作するCBCライブラリを利用する

デフォルトのシェル zsh の`~/.zprofile`もしくは`~/.zshrc`に、以下の記述を追加します。この環境変数`PMIP_CBC_LIBRARY`は、Python-MIPで利用するCBCライブラリを強制的に指定することができます。
```shell
export PMIP_CBC_LIBRARY=/opt/local/lib/libCbc.dylib
```
記載したら、設定を反映させます。
```shell
% exec $SHELL -l
```

pip install mip した直後にエラーとなったモデルを作った処理を改めて実行してみましょう。すると以下のように正常な処理がされていることを確認できます。
```shell
% python -c "import mip; m = mip.Model()"

（エラーなど何も表示されない＝正常終了する）
```

【参考】pipインストールされたライブラリ cbc-c-darwin-x86-64.dylib を、ここでビルドした libCbc.0.dylib に強引に置き換えてしまう[^1]ということも可能ですが、環境変数`PMIP_CBC_LIBRARY`でライブラリを指定して動作を変えることが推奨されると思います。

### 謝辞
本稿は、@SaitoTsutomu さんのエントリをお手本にして、まとめております。@SaitoTsutomu さんに感謝を申し上げます。

[^1]:[Installing on a Mac M1](https://groups.google.com/g/python-mip/c/0R2NC_URD6M/m/9b7yUaY6AAAJ)にライブラリをコピーコマンドで書き換えてしまう方法が紹介されています。