Chandler@Berlin -7ページ目

Chandler@Berlin

ベルリン在住

私には様々な国の出身の友人がいる.そのような友人達とパーティでよく議論になるのは,それぞれの言語の特徴である.ドイツ語の文法の難しさ,日本語の漢字の多さと物の数え方の特殊さ,英語の語彙の豊富さなどの特徴がある.いつの頃からか,私は言語の難しさとは何だろうか,それを測定することはできないだろうか?と考えるようになった.

今回私は友人の協力を得て,ある日本語の文書をドイツ語と英語に翻訳し,それをエントロピー圧縮プログラムで圧縮してファイルのサイズを比較してみた.これはファイルの持つ情報量を示す指標になっているはずであり,それが言語の持つ複雑さに関係しているのではないかと思ったのだ.つまり,「同じ内容の文書は言語によってどれだけの情報エントロピーの差がでるのだろうか?」ということを測定してみたのだ.

これからのこ話題に関して何回かに分けて書いていきたい.
self.face_idx_list へのアクセス方法.extracting a numpy.int64 type failed

前回と違うのは,numpy.array には numpy.float64 ではなく,numpy.int64 が入っている点である.しかし.numpy.float64 は,

vec[i] = boost::python::extract< float >(
    float32_3_obj.attr("__getitem__")(i));

つまり, boost::python::extract< float >(f) で float 値に変換できた.しかし,numpy.int64を

vec[i] = boost::python::extract< int >(
    int32_3_obj.attr("__getitem__")(i));

つまり,boost::python::extract< int >(i) で int 値に変換しようとするとできないのである.そうしようとすると,

 TypeError: No registered converter was able to produce a C++ rvalue of
 type int from this Python object of type numpy.int64.

というエラーに出会うことになる.これに関しては web を探してみると,http://boost.2283326.n4.nabble.com/extracting-a-numpy-int32-type-td2701573.html という記事があった.どうやら numpy では numpy.float64 から float への converter が register されているのだが,numpy.int64 に関しては 64bit マシンではそういう converter がないようだ.python の世界では int(i) を使えばいいとあるが,C++の世界ではそうはいかない.そこで以下のようなトリックを使う.

int vec[] = {0, 0, 0};
for(int i = 0; i < 3; ++i){
    object int64_obj = int32_3_obj.attr("__getitem__")(i);
    vec[i] = boost::python::extract< int >(
        int64_obj.attr("__int__")());
}

このトリックは一度 numpy.int64 を python の object として取り出し,その attribute にある int への変換メンバを使う.

ここでヒントを一つ.どうやったらそんな変換関数があるのがわかるのだろうか?それは python のオブジェクト自身に尋ねることができる.python の object のattribute はそれ自身 python のシーケンスとして見ることができる.つまり,python の interpreter から, type() を使うと以下のような出力が得られる.

>>> import numpy
>>> a = numpy.array([1,2,3])
>>> type(a[0])
<type 'numpy.int64'>

つまり numpy.array の要素は 'int' ではなく, numpy.int64 であることがわかる.このタイプの object も python の object であるから,どんな attributeを持っているかは, dir()を使えば見ることができる.そうすると,intへの変換が用意されていることがわかる.それを使ってみよう.

>>> type(a[0].__int__())
<type 'int'>

今度は 'int' が取り出せた.この object なら extract< int >で C++ の intが取り出せる.

基本的にここにあるようにすれば,ユーザ側で定義した python の内容を C++に渡すことができる.

この情報が誰かの役に立ったら嬉しいです.


self.vertex_list へのアクセス方法.

今回は self.vertex_list へのアクセスである.これは, float の長さ 3 の numpy.array の list である.list の取り出し方は,http://shitohichiumaya.blogspot.com/2010/08/boostpython-how-to-pass-python-object.html  で dict の keylist として説明した.

list の要素の float の numpy.array の要素へのアクセスをどうするかは以下のようになっている.

void print_float32_3(boost::python::object const & float32_3_obj)
{
    // check sequence length is 3 or not.
    if(boost::python::len(float32_3_obj) != 3){
        std::string const objstr =
            boost::python::extract< std::string >(
                boost::python::str(float32_3_obj));
        std::cerr << "print_float32_3: arg is not a float[3] obj ["
                  << objstr << "]" << std::endl;
        return;
    }

    float vec[] = {0.0f, 0.0f, 0.0f};
    for(int i = 0; i < 3; ++i){
        vec[i] = boost::python::extract< float >(
            float32_3_obj.attr("__getitem__")(i));
    }
    std::cout << "float[3] = " << vec[0] << " " << vec[1] << " "
              << vec[2] << std::endl;
}


まずは,numpy.arrayは sequence なので boost::python::len() を使って,長さが 3 であるかどうかをチェックしている.その後に __getitem__ のattribute を通して各要素にアクセスしている.numpy.array にはnumpy.float64 が入っているが,extract< float > で要素にアクセスすることができる.

最後の int の array も同じ,と言いたいのだが,実は問題につきあたってしまったので,それは次回に回そう.