可変長疎ベクトル var_len_vec

可変長の疎ベクトルをつくってみた.
機械学習とかでは,
特徴量の数が最初から決まってないことがあって,
学習の途中で追加なんてこともあります.

key-value型でデータを保存するようにして,
keyに特徴量の情報を入れられると.

ソースは,bitbucketに置きました.
https://bitbucket.org/ryoma_kawajiri/var_len_vec
templateを使ったheaderだけのコードです.

使い方

unordered_mapとかmapを継承して,
四則演算のoperatorとかを追加して実装しているだけなので,
親のmember functionとかももちろんそのまま使えちゃいます.
keyの型には色々使えます.

var_len_vec<double> v1, v2;

v1[1] = 1.0;
v1["-1<x<=0"] = (-1 < x && x <= 0) ? 1:0;
v1["0<x<=1"] = (0 < x && x <= 1) ? 1:0;
v1["gauss:mu=0:sigma=1"] = exp(-x*x / sigma);

var_len_vec<double> v3 = v1 * v2;
double d1 = inner_product(v1 * v2);
double d2 = v1.sum();

あとは,testコードとかも見てもらえばいいと思います.

仕組み

keyの型が何でもいいのは,
implicit conversion (暗黙的変換?)を使って,
stringに変換しているから.
一意に変換出来れば,どんな方法でも大丈夫.

こんなクラスを作った.

class common_key:
  public std::string{
public:
  // implicit conversion
  template<class Any>
  common_key(const Any & any):
  std::string(to_string(any)) {}

private:
  template<class Any>
  std::string to_string(const Any & any) const
  {
    std::stringstream ss;
    int status = 0;
    ss << abi::__cxa_demangle(typeid(any).name(), 0, 0, &status) 
    // ss << __PRETTY_FUNCTION__
       << " "
       << any;
    return ss.str();
  }
};

あとは,mapとかunordered_mapで使えるように,
hashとかequal_toとかの関数を定義してあげれば良いと.
serializationとかも使えるかと思ったけど,
バージョン情報とかを埋め込まれちゃうから,
一意に決まらないことも.

ただ,typeidでRTTIを使ってて効率が悪い.
型はコンパイル時にわかるからいい方法がないかな?
__PRETTY_FUNCTION__とか使うと,
余計なものがたくさん付いちゃうし悩ましいところ.
特徴量作るときだけだから,とりあえず仕方ない.

最後に

keyを文字列にしてるので,
最近,流行りのTRIE木とかの実装をラップすると,
効率が良くなるかな.

あと,RTTIを使わないでいい方法を考えてみる.
boostのserializationとかはどうやっているんだろう?