Paradigm Shift Design

ISHITOYA Kentaro's blog.

行列演算ライブラリEigenをiOSで利用する

喪中です。ことよろ。
まーにあっくまーにあっくー。


活性拡散アルゴリズムというのがありまして、それをiOS上で2次元配列を使って計算していたのだけれども、速度が遅いこと、行列演算でバグが混入する可能性があることから、ライブラリを使って実装したいなと思いました。

せっかちなひとむけ

  • Eigenからダウンロード
  • バージョンは3.0.4以降を使う
  • Eigenをxcode経由でプロジェクトに追加しない
    • 解凍したディレクトリのEigenをプロジェクトのソースコードから見える位置にFinderで追加する
  • Eigenを利用するソースコードのFile TypeをObjective-C++ sourceにする
  • #include "Eigen/Core"
  • using namespace Eigen;

Eigenライブラリとは

iOSにはAccelerate.Frameworkというのがあって、行列演算、デジタル信号処理、大数処理、画像処理なんぞができるそうです。

なんかをみる限りいろいろできそうで、行列演算に関してはBLASLAPACK使ってるので早いですよとか書いてある。ので、これを使うのを前提に調べていたのだけれど、行列の定義がポインタだし、乗算したいだけなのに関数呼ばないとならないし、オブジェクト指向的では全くないので、手をのばせていませんでした。


で、ググってたら、

に、Dean Poveyさんという方の

Eigen is a lightweight C++ linear algebra package which provides could matrix, vector and quaternion support. While I have not used it in anger, it seems to have a much nicer interface than BLAS/LAPACK and supports a bunch of things those libraries don't


EigenはライトウェイトなC++線形代数パッケージで、行列・ベクトル・クォータニオンをサポートしてるよ。他のBLAS/LAPACKライブラリがサポートしているインターフェースよりずっとよくてイライラしないよ。(超訳

とかいう素敵なコメントを発見し、

にたどり着きました。


OverViewの所を読んでもらえれば特徴はわかると思いますが、Requirementsのほうが重要かと思います。

Requirements
Eigen doesn't have any dependencies other than the C++ standard library.

We use the CMake build system, but only to build the documentation and unit-tests, and to automate installation. If you just want to use Eigen, you can use the header files right away. There is no binary library to link to, and no configured header file. Eigen is a pure template library defined in the headers.


EigenはSTL以外のC++ライブラリに依存していません。

CMakeを使っていますが、ドキュメントの生成、ユニットテスト、それからインストールの自動化にのみ使っています。Eigenを使いたいだけならヘッダファイルがそのまま使えます。ライブラリをリンクしたり、ヘッダを設定したりする必要はありません。Eigenはヘッダに定義された純粋なテンプレートライブラリです。(超訳

つまり、iOS上でもEigenを突っ込めば使えるということです。


で…問題は実際にどうやって使うの!?ってことなんですが、それがわからなくて一苦労しました。結果からいうと、ファイルタイプさえ設定すれば簡単に使えます。

xcodeで使う

まず、Eigenから3.0.4以降のバージョンをダウンロードしてきます。それ以前だとiOSでエラーがでるようです。

解凍したディレクトリの中の「Eigen」というディレクトリが、Eigenライブラリの本体です。


まず、パスの通った場所にこのEigenディレクトリをおきます。システムのincludeに入れれば、それこそ何も考えずに、

#include <Eigen/Core>

と書けば使えちゃいます。


しかしながら、リポジトリにコミットできた方がチームで開発している場合には有利でしょうから、プロジェクトのパスが通ったところにEigenライブラリをおきましょう。


例えばsampleプロジェクトをxcodeで作ると

- sample
|- sample.xcodeproj
|- sampleTexts
|- sample

という構造になるかと思います。sample/sampleの中に、Eigenディレクトリをコピって入れれば良いです。

ただし、このとき、xcodeから追加しないようにしてください

[WARN]Warning: Multiple build commands for output file /Users/ishitoya/Library/Developer/Xcode/DerivedData/sample-cdtjyyonwkgkupadfkjaxzadhzaa/Build/Products/Debug-iphonesimulator/sample.app/CMakeLists.txt

とかいう警告がたくさんでたりします。

で、実際にコードを書くわけですが、何も考えずに

#import "TestEigen.h"
#import "Eigen/Core"

@implementation TestEigen
@end

とか書くと、

In file included from /Users/ishitoya/Documents/sample/sample/Eigen/Core:35:
In file included from /Users/ishitoya/Documents/sample/sample/TestEigen.m:10:
/Users/ishitoya/Documents/sample/sample/Eigen/src/Core/util/Macros.h:187:5: error: unknown type name 'namespace' [1]
namespace Eigen {
^
/Users/ishitoya/Documents/sample/sample/Eigen/src/Core/util/Macros.h:187:20: error: expected ';' after top level declarator [1]
namespace Eigen {
^
;
fix-it:"/Users/ishitoya/Documents/sample/sample/Eigen/src/Core/util/Macros.h":{187:20-187:20}:";"
In file included from /Users/ishitoya/Documents/sample/sample/TestEigen.m:10:
/Users/ishitoya/Documents/sample/sample/Eigen/Core:144:10: fatal error: 'cerrno' file not found [2]
#include
^
3 errors generated.

というエラーがでます。でobjcでc++を使ったことがない私は、ここで詰まり、なんだEigen使えねぇんじゃねぇか!といって、またググる訳で…


原因はEigenのバグではなく、私の無知でした。
XCode4なら画面右上のViewからUtilities Viewを開いて、Identity and TypeのFile Typeを「Default-Objective-C source」から「Objective-C++ source」にかえれば、エラーが消えます。

Eigenの使い方

あとは、公式のサンプルがかなり充実しているので、

を読めば大体わかると思います。日本語だと

がとてもわかりやすかったです。


私のようにObjective-C++になれていない場合のTipsとしては、

#include "Eigen/Core"
#include <iostream>

using namespace std;
using namespace Eigen;

のように、デバッグのためiostreamヘッダを読み込んでおくことと、namespaceを使いますよ宣言をしておくことくらいでしょうか。

VectorXf v1 = VectorXf::Ones(5);
cout << v1 << endl;

とかして出力を得ることができます。


サンプルと呼べるかどうかわかりませんが、kent013/SpreadingActivationCalculator · GitHubに、Eigenを使ったプロジェクトをおいておきます。SpreadingActivationCalculator/SpreadingActivation/SpreadingActivationCalculator.m at master · kent013/SpreadingActivationCalculator · GitHubがEigenをちょろっと使ってるコードです。


以上〜