Gmm++ の深い内部¶
linalg_traits 構造体¶
Gmm++ の主な原則は,それぞれのベクトルと行列の型(これはインスタンス化されません)が linalg_traits
という名前の対応する構造体を持っているということです.この構造体にはすべての情報が含まれています.例えば,この構造体の要素 linalg_type
は,対応する型がベクトルまたは行列を表す場合には, abstract_vector
または abstract_matrix
に設定されます. V
がベクトルのインターフェイス型で, M
が行列のインターフェイス型である場合,次のようにしてこのコンポーネントにアクセスできます.
typename gmm::linalg_traits<V>::linalg_type ... // should be abstract_vector
typename gmm::linalg_traits<M>::linalg_type ... // should be abstract_matrix
型 abstract_vector
と abstract_matrix
は gmm/gmm_def.h
で定義されています .これらは汎用アルゴリズムを特殊化できるvoid型です.
ベクトル型では,次の情報を使用できます.
typename gmm::linalg_traits<V>::value_type --> type of the components of the
vector
typename gmm::linalg_traits<V>::reference --> type of reference on a component
typename gmm::linalg_traits<V>::is_reference --> if the vector is a simple
reference or an instantiated vector
typename gmm::linalg_traits<V>::linalg_type --> should be abstract_vector
typename gmm::linalg_traits<V>::index_sorted --> linalg_true or linalg_false
typename gmm::linalg_traits<V>::const_iterator --> const iterator to iterate on the
components of the vector in
order to read them.
typename gmm::linalg_traits<V>::iterator --> iterator to iterate on the
components of the vector in
order to read or write them.
typename gmm::linalg_traits<V>::storage_type --> should be abstract_sparse,
abstract_skyline or
abstract_dense
typename gmm::linalg_traits<V>::origin_type --> the type of vector itself
or the type of referenced
vector for a reference.
gmm::linalg_traits<V>::size(v) --> a method which gives the size of the vector.
gmm::linalg_traits<V>::begin(v) --> a method which gives an iterator on the
beginning of the vector
gmm::linalg_traits<V>::end(v) --> iterator on the end of the vector
gmm::linalg_traits<V>::origin(v) --> gives a void pointer allowing to identify
the vector
gmm::linalg_traits<V>::do_clear(v) --> make a clear on the vector
gmm::linalg_traits<V>::access(o, it, ite, i) --> return the ith component or a
reference on the ith component. o is a
pointer o type ``origin_type *'' or
``const origin_type *''.
gmm::linalg_traits<V>::clear(o, it, ite) --> clear the vector. o is a
pointer o type ``origin_type *'' or
``const origin_type *''.
行列型の場合
typename gmm::linalg_traits<M>::value_type --> type of the components of the
matrix
typename gmm::linalg_traits<M>::reference --> type of reference on a component
typename gmm::linalg_traits<M>::is_reference --> if the matrix is a simple
reference or an instantiated matrix
typename gmm::linalg_traits<M>::linalg_type --> should be abstract_matrix
typename gmm::linalg_traits<M>::storage_type --> should be abstract_sparse,
abstract_skyline or
abstract_dense
typename gmm::linalg_traits<M>::index_sorted --> linalg_true or linalg_false
typename gmm::linalg_traits<M>::sub_orientation --> should be row_major, col_major
row_and_col or col_and_row.
typename gmm::linalg_traits<M>::sub_col_type --> type of reference on a column
(if the matrix is not row_major)
typename gmm::linalg_traits<M>::const_sub_col_type --> type of const reference on a
column
typename gmm::linalg_traits<M>::col_iterator --> iterator on the columns
typename gmm::linalg_traits<M>::const_col_iterator --> const iterator on the columns
typename gmm::linalg_traits<M>::sub_row_type --> type of reference on a row
(if the matrix is not col_major)
typename gmm::linalg_traits<M>::const_sub_row_type --> type of const reference on a
row
typename gmm::linalg_traits<M>::const_row_iterator --> const iterator on the rows
typename gmm::linalg_traits<M>::row_iterator --> iterator on the rows
typename gmm::linalg_traits<M>::origin_type --> the type of vector itself
or the type of referenced
vector for a reference.
gmm::linalg_traits<M>::nrows(m) --> methods which gives the number of rows of
the matrix
gmm::linalg_traits<M>::ncols(m) --> number of columns
gmm::linalg_traits<M>::row_begin(m) --> iterator on the first row (if not col_major)
gmm::linalg_traits<M>::row_end(m) --> iterator on the end of the rows
gmm::linalg_traits<M>::col_begin(m) --> iterator on the first column
(if not row_major)
gmm::linalg_traits<M>::col_end(m) --> iterator on the end of the columns
gmm::linalg_traits<M>::row(it) --> gives the reference on a row with an iterator
(if not col_major)
gmm::linalg_traits<M>::col(it) --> gives the reference on a column with an
iterator (if not row_major)
gmm::linalg_traits<M>::origin(m) --> gives a void pointer allowing to identify
the matrix
gmm::linalg_traits<M>::access(it,i) --> return the ith component or a reference
on the ith component of the row or
column pointed by it.
gmm::linalg_traits<M>::do_clear(m) --> make a clear on the matrix
これは,新しいベクトルまたは行列型をインタフェースするために入力する必要がある構造です.例は gmm/gmm_interface.h
で見ることができます.ほとんどの汎用的なアルゴリズムは gmm/gmm_blas.h
にあります.
ベクトルのコンポーネントをイテレートする方法¶
ベクトルの成分を累積する例を次に示します. V
はベクトル型であり, v
はインスタンス化されたベクトルであると仮定します.
typename gmm::linalg_traits<V>::value_type r(0); // scalar in which we accumulate
typename gmm::linalg_traits<V>::const_iterator it = vect_const_begin(v); // beginning of v
typename gmm::linalg_traits<V>::const_iterator ite = vect_const_end(v); // end of v
for (; it != ite; ++it) // loop on the components
r += *it; // accumulate the components
このコードは,あらゆる種類のインターフェイスされたベクトルで動作します.
疎なベクトルやスカイラインなベクトルでは,イテレータが指すコンポーネントのインデックスを it.index()
で取得することができます. V1
と V2
が2つのベクトル型であり, v1
と v2
が対応する2つのインスタンス化されたベクトルであると仮定した場合の,2つの疎ベクトルまたはスカイラインベクトルのスカラー積の例を次に示します.
typename gmm::linalg_traits<V1>::const_iterator it1 = vect_const_begin(v1),
typename gmm::linalg_traits<V1>::const_iterator ite1 = vect_const_end(v1);
typename gmm::linalg_traits<V2>::const_iterator it2 = vect_const_begin(v2),
typename gmm::linalg_traits<V2>::const_iterator ite2 = vect_const_end(v2);
typename gmm::linalg_traits<V1>::value_type r(0); // it is assumed that V2 have a
// compatible value_type
while (it1 != ite1 && it2 != ite2) { // loops on the components
if (it1.index() == it2.index()) {
res += (*it1) * (*it2)); // if the indices are equals accumulate
++it1;
++it2;
}
else if (it1.index() < it2.index())
++it1;
else
++it2;
}
このアルゴリズムでは,インデックスが疎ベクトルで増えているという事実を使用します.密なベクトルイテレータには it.index()
というメソッドがないので,このコードは密なベクトルに対しては動作しません.
行列をイテレートする方法¶
行列が列行列でない場合は行を反復し,行行列でない場合は行列の列を反復します( gmm::dense_matrix<T>
の型は col_and_roxのような副方向型なので,行と列の両方で反復することができます).
最適化する必要がない場合は,次のような基本的なループを使用できます.
for (size_t i = 0; i < gmm::mat_nrows(m); ++i) {
typename gmm::linalg_traits<M>::const_sub_row_type row = mat_const_row(M, i);
...
std::cout << "norm of row " << i << " : " << vect_norm2(row) << std::endl;
}
しかし,次のようにイテレータを使用することもできます.
typename gmm::linalg_traits<M>::const_row_iterator it = mat_row_const_begin(m);
typename gmm::linalg_traits<M>::const_row_iterator ite = mat_row_const_end(m);
for (; it != ite; ++it) {
typename gmm::linalg_traits<M>::const_sub_row_type
row = gmm::linalg_traits<M>::row(it);
...
std::cout << "norm of row " << i << " : " << vect_norm2(row) << std::endl;
}
アルゴリズムをすべての型の行列で動作させる方法¶
このためには,一般的に特化する必要があります.例えば, gmm::nnz
のコードを見てみましょう.これは保存されているコンポーネント(実際には,実数の gmm::nnz
アルゴリズムはほとんどの場合特化されており,コンポーネントを1つずつ数えたりはしません)の数を数えます.
template <class L> inline size_type nnz(const L& l) {
return nnz(l, typename linalg_traits<L>::linalg_type());
}
template <class L> inline size_type nnz(const L& l, abstract_vector) {
typename linalg_traits<L>::const_iterator it = vect_const_begin(l);
typename linalg_traits<L>::const_iterator ite = vect_const_end(l);
size_type res(0);
for (; it != ite; ++it) ++res;
return res;
}
template <class L> inline size_type nnz(const L& l, abstract_matrix) {
return nnz(l, typename principal_orientation_type<typename
linalg_traits<L>::sub_orientation>::potype());
}
template <class L> inline size_type nnz(const L& l, row_major) {
size_type res(0);
for (size_type i = 0; i < mat_nrows(l); ++i)
res += nnz(mat_const_row(l, i));
return res;
}
template <class L> inline size_type nnz(const L& l, col_major) {
size_type res(0);
for (size_type i = 0; i < mat_ncols(l); ++i)
res += nnz(mat_const_col(l, i));
return res;
}
パラメータがベクトルまたは行列の場合,最初の関数は2番目または3番目の関数にそれぞれディスパッチされます.行列がrow_majorまたはcolumn majorの場合,3番目の関数はそれぞれ4番目と5番目の関数に再ディスパッチされます.もちろん,関数は inline
で宣言されているので,少なくとも2つのディスパッチャ関数は実装されません.つまり,この構築はコストがかからないということです.