GNU Scientific Library (GSL) を使って擬似逆行列(pseudo-inverse)を計算するサンプルコードを書いた

はじめに

擬似逆行列の計算を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のほうがインタフェースが整っており、ユーザフレンドリーである。