*ポータブルテンプレート行列ライブラリ(Portable Tamplate Matrix library)

はじめに

VisualC++ 6, Borland C++, gccで動作するN,M行列ライブラリです. Springheadでも使用しており,Springheadに含まれています.
C++のテンプレートを使って,n行m列の行列計算ライブラリを作りました. テンプレートを用い,管理情報をメモリ上から追放したので,floatの配列を キャストして行列だと思って演算することなどができます.

リンク

このライブラリの特徴

テンプレートで解決

全てをテンプレートで静的に解決しています. 行列のサイズやポインタなどを保持するための管理領域を持ちません. そのため, 行列の一部(部分行列,ベクトル,行ベクトル,列ベクトル)などを 直接参照することができる(代入も可能). 配列をキャストして行列として使用することも可能. 行列の掛け算などで,行列のサイズが合わない場合,コンパイル時に コンパイラがエラーを出力する. 行列のサイズを動的に変更することができない. といった特徴をもちます.

移植性

処理系依存部分の多いテンプレート機能を活用していながら,全機能が, 3つのコンパイラで使用できます.サポートしているコンパイラは, CL (MS Visual C++ 6.0) bcc32(Borland C++ 5.5.1) gcc(GNU c compiler 2.95.3-5) です.

新たにクラスライブラリを作成した理由

すでに多くの行列ライブラリがありながら,新たに作成した理由は, TNT,MTL の行列は管理領域をメモリに持つため,配列をキャストして 行列として使用することができない. Blitz は TinyMatrix, TinyVector を持つが,Visual C++ で 使用できない. 私の知る限り,部分行列,部分ベクトルへの参照を返す行列ライブラリ は存在しない. からです.

使い方

ポータブル テンプレート 行列クラスライブラリは,ヘッダファイルだけからなる クラスライブラリなので, TMatrix.h, TMatrixUtility.h, TVector.h を同じフォルダに入れておき,.cppファイルからヘッダをインクルードするだけで 使用できます.

サンプル

簡単なサンプルです.適当なファイル名(たとえば sample.cpp) で保存して コンパイルしてください.コンパイルするためには, visual C++ の場合

cl -GX sample.cpp 

gccの場合

gcc sample.cpp -lstdc++ 

bcc の場合

bcc32 sample.cpp 

としてください.

#include "TMatrix.h"    //  行列ライブラリのインクルードする.
#include <iostream>
using namespace PTM;    //  行列クラスはPTM名前空間の中で宣言されている.
void main(){
    TMatrix<2,2,float> mat;     //  2行2列の行列を宣言
    mat[0][0] = 1;  mat[0][1] = 2;
    mat[1][0] = 3;  mat[1][1] = 4;
    TVector<2,float> vec;       //  2次元のベクトルを宣言
    vec[0] = 1; vec[1] = 0;
    std::cout << mat;
    std::cout << vec << std::endl;
    std::cout << mat * vec << std::endl;    //  掛け算
    std::cout << mat + mat << std::endl;    //  足し算
    std::cout << mat - mat << std::endl;    //  引き算
    std::cout << mat.trans() << std::endl;  //  転置
    std::cout << mat.inv() << std::endl;    //  逆行列
}

ベクトルの機能

次の演算ができます.

  1. :和, -:差, *:内積/定数倍, /:定数分の1 ==:比較, =:代入

    :出力, >>:入力 %:外積(2・3次元のみ) 次のメンバ関数を持ちます. unit(): 向きが等しい単位ベクトルを返す. norm(): ベクトルの大きさ(ノルム)を返す. sub_vector(): 部分ベクトルへの参照を返す.

行列の機能

次の演算ができます.

  1. :和, -:差, *:積/定数倍, /:定数分の1 ==:比較, =:代入

    :出力, >>:入力 次のメンバ関数を持ちます. det(): 行列式を返す. inv(): 逆行列を返す. gauss(): ガウスの消去法で方程式を解く. sub_matrix(): 部分行列への参照を返す. row(): 行ベクトルへの参照を返す. col(): 列ベクトルへの参照を返す. sub_matrix()やrow()には値を代入することもできます.

    TMatrix<3,3,float> mat; TVector<3, float> vec;
    mat.row() = vec;

履歴

  • 2001年6月14日 部分ベクトル取得関数のバグを修正.
  • 2001年6月10日 最初の版を公開.
  • 2001年10月6日 足し算・引き算ができないという大ボケバグの修正.
  • サンプルのミスを修正.
  • 2001年10月9日 10月6日分がアップロードミスしていたので再度アップロード.
  • 2001年11月19日 Affine行列クラスをパッケージに追加.
  • 2002年10月24日 == が動かなかった問題を修正,Affineをnamespaceから出す.
  • 2004年7月5日 長方形行列の演算が,一部うまく行かなかったのを修正.
  • 2004年7月26日 eCos上で使いたくなったので,gccでとおらなくなっていたのを修正.gcc-3.2.1を使用.

同じようなライブラリ

  • Graphics Math Template Library (GMTL) http://ggt.sourceforge.net/ 行列型が無いのかな? 部分ベクトルとかもなさそう.平面や三角形があるようです.
  • boost::ublas 演算子があまり充実していない気がします.

実装について

実装のルール

  • virtual禁止

最初の実装

  • 基本クラスがデータを持つ.
  • 要素のアクセスをオーバーライド. 問題:VCのデバッガで要素を見るのが大変.→と↓キーが壊れそう.

ublas

C++ template狂ライブラリ,boost の行列ライブラリ.

  • VCでは動かない.
  • 演算子が充実していない.
  • 後から,演算子を足すのが結構面倒. ためしにublasベースで作ることを試みるが断念.
  • 発見:ublasはデータが派生クラスにある. 基本クラスから派生クラスに触るためのトリック.
//基本クラス
template<class E> class TVectorBase {
	public:
	///	実体(派生クラス)へのアクセス
	E& expression(){ return *(E*)this; }	//<	注目
	void add(const E& b){
		E& a = expression();
		for(int i=0; i<a.size(); ++i){
			a.data[i] += b.data[i];
		}
	}
};

//派生クラス
class TVector: public TVectorBase<TVector> {
	public:
	float data[10];
	size_t size(){ return 10; }
};

派生クラスに自分をキャストするという,奇想天外な方法で,派生クラスのデータに, 基本クラスの関数がアクセスしています.

現在の実装

派生クラスに共用体と要素アクセス関数の実装

class TVec2:public PTM::TVectorBase<DIMENC(2), TVecDesc<TVec2<T>, T> >{
	public:
	union{
		T data[2];
		struct{
			T x,y;
		};
	};
	///	要素のアクセス
	T& item_impl(size_t i){ return data[i]; }
};
  • デバッガで見るとき,基本クラスを開かずに,x, y という変数名で値を確認できる.