はじめに
擬似逆行列の計算をC言語で実装する必要に迫られた。手段を探すと、GNU Scientific Library (GSL) が便利に使えそうだった。 そこで、簡単に使えるようにしたサンプルコードを公開するのが本記事の主旨である。
準備:GSLのインストール
Ubuntuならばaptからインストールできる。
sudo apt-get install libgsl-dev
macならばHomebrewからインストールできる。
brew install gsl
実装
以下に置いた。Enjoy!
関数 pseudo_inverse が擬似逆行列を計算する関数であり、今回の主役である。この記事の読者は、自由にコピペして使ってよい。ただしGSLのライセンスはGPLなので、本ソースコードもそれに従う。ライセンスの例外規定もあるだろうけども、検討するのが面倒なので。main関数は実装をテストするためのサンプルコードである。
コンパイル
GSL由来の関数をソースコードに組み込んだ場合、コンパイルは専用のライブラリをリンクする必要がある。 すなわち、
-lgsl -lgslcblas -lm
をコンパイラのオプションにつけねばならない。Macの場合はさらに、ヘッダファイルの場所と静的ライブラリの場所を、それぞれ -I オプションと -L オプションによってコンパイラに指示する必要がある。
実はgsl-config という便利コマンドがあり、--cflagsをつけて実行すると -I オプション付きでヘッダファイルの場所を標準出力し、--libsをつけて実行すると -L オプション付きで静的ライブラリの場所とリンクオプションを標準出力してくれる。
出力例はUbuntuだと以下の通り(% はプロンプト)。
% gsl-config --cflags -I/usr/include % gsl-config --libs -L/usr/lib/x86_64-linux-gnu -lgsl -lgslcblas -lm
Macの出力例は以下の通り。Macの場合は -lm が付かない。
% gsl-config --cflags -I/opt/homebrew/Cellar/gsl/2.8/include % gsl-config --libs -L/opt/homebrew/Cellar/gsl/2.8/lib -lgsl -lgslcblas
そこで gsl-config の出力をうまく活用すれば、コマンドラインに絶対パスやリンクオプションを明示的に書く手間がなくなるので嬉しいわけである。
実際のコンパイルコマンド例は次に示す通り。ソースコードのファイル名がgsl_pinv.c で 出力ファイル名を gsl_pinv としている。最適化オプションはお好みで。
cc -O2 -Wall $(gsl-config --cflags) gsl_pinv.c $(gsl-config --libs) -o gsl_pinv
シェルスクリプトに書いておくならば、例えばこれぐらいで済む。
#!/bin/bash SOURCE=gsl_pinv.c TARGET=gsl_pinv CFLAGS="-O2 -Wall" cc ${CFLAGS} $(gsl-config --cflags) ${SOURCE} $(gsl-config --libs) -o ${TARGET}
実行例
実行例は以下の通り。再構成誤差(フロベニウスノルムで計算)が十分小さい範囲に収まり、期待通りの擬似逆行列が計算できている。
Original Matrix A: 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 Pseudo Inverse A+: -1.333333 -0.333333 0.666667 1.083333 0.333333 -0.416667 Reconstruction Error: 2.521942e-15
おわりに
C言語で擬似逆行列を計算するためにGSLを使ってみるのは初めてだったのだが、十分使いやすいライブラリだと感じた。
擬似逆行列を計算するためのライブラリはGSL以外にも存在し、例えばLAPACKEとCBLASがある。前者によって特異値分解を計算し、後者によって行列どうしの積を計算する。十分に便利なのだが、GSLのほうがインタフェースが整っており、ユーザフレンドリーである。