犬ぶよツールズ制作記録

Javaによる研究生活のためのパッケージ、犬ぶよツールズ。
その開発と保守のための備忘録

千反田さんpython版

2012-10-31 21:31:16 | about
このツイートで着想を得て
発表されたcoffeeスクリプトがあります。
これをpythonで実装してみました。

watashi_kininarimasu.py (Gist)
※scriptの埋め込みはできないようです。

実行してみると

ちゃんとできてますね。

ここで定義している関数toKanji()は「極」まで扱えます。
1から10の52乗-1までの整数に対応していることになります。


インタフェース IterableIntegerArray の実装5種

2012-10-31 00:48:50 | about
● 概要
インタフェース IterableIntegerArray
パッケージjp.inubuyo.brain.utilに配置した。
そして、その実装5種類をパッケージjp.inubuyo.brain.util.implに入れた。
これらは、多重ループとN進数(あるいは重複順列)、順列、組合せ、重複組合せの仮想コレクションである。
これらの使い方をjythonで示す。

● 多重ループ
クラスNLoop_IterableIntegerArrayにより多重ループが出来る。
1つ目の変数iをi0からi1まで、2つ目の変数jをj0からj1まで走らせる2重ループは
NLoop_IterableIntegerArray([i0, j0], [i1, j1])で初期化する。
for文の慣習に従い、i0, j0などはループに含み、i1, j1などはループに含まない。

コレクションの内容をjythonで表示させると次のようになる。


Jython 2.5.2 (Release_2_5_2:7206, Mar 2 2011, 23:12:06)
[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_37
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import jp.inubuyo.brain.util as util
>>> import jarray
>>> tray = jarray.array([0, 0], 'i')
>>> loop = util.impl.NLoop_IterableIntegerArray([0, 0], [2, 3])
>>> for x in loop.iterator(tray, 0, 2):
. . .    print x, tray
. . .
0 array('i', [0, 0])
1 array('i', [0, 1])
2 array('i', [0, 2])
3 array('i', [1, 0])
4 array('i', [1, 1])
5 array('i', [1, 2])
>>>


xがインタフェースIteratorのメソッドnext()の戻り値、trayが仮想コレクションのトレイである。
tray[0]が外側のループの変数、tray[1]が内側のループの変数になっている。

● N進数
RadixN_IterableIntegerArrayによりN進数を順に挙げることができる。

次の例は2桁の3進数を全て挙げる。

>>> import jp.inubuyo.brain.util as util
>>> import jarray
>>> tray = jarray.array([0, 0], 'i')
>>> loop = util.impl.RadixN_IterableIntegerArray(3)
>>> for x in loop.iterator(tray, 0, 2):
. . .    print x, tray
. . .
0 array('i', [0, 0])
1 array('i', [0, 1])
2 array('i', [0, 2])
3 array('i', [1, 0])
4 array('i', [1, 1])
5 array('i', [1, 2])
6 array('i', [2, 0])
7 array('i', [2, 1])
8 array('i', [2, 2])
>>>


桁数はメソッドiterator()の2番目と3番目の引数で決まる。
同じRadixN_IterableIntegerArrayのインスタンスから桁数の異なるIteratorを得ることが出来る。
上のコードに続けて下のようにすれば、3桁になる。

>>> tray = jarray.array([0, 0, 0], 'i')
>>> for x in loop.iterator(tray, 0, 3):
. . .    print x, tray
. . .
0 array('i', [0, 0, 0])
1 array('i', [0, 0, 1])
2 array('i', [0, 0, 2])
3 array('i', [0, 1, 0])
4 array('i', [0, 1, 1])
5 array('i', [0, 1, 2])
6 array('i', [0, 2, 0])
7 array('i', [0, 2, 1])
8 array('i', [0, 2, 2])
9 array('i', [1, 0, 0])
10 array('i', [1, 0, 1])
11 array('i', [1, 0, 2])
12 array('i', [1, 1, 0])
13 array('i', [1, 1, 1])
14 array('i', [1, 1, 2])
15 array('i', [1, 2, 0])
16 array('i', [1, 2, 1])
17 array('i', [1, 2, 2])
18 array('i', [2, 0, 0])
19 array('i', [2, 0, 1])
20 array('i', [2, 0, 2])
21 array('i', [2, 1, 0])
22 array('i', [2, 1, 1])
23 array('i', [2, 1, 2])
24 array('i', [2, 2, 0])
25 array('i', [2, 2, 1])
26 array('i', [2, 2, 2])
>>>


● 組合せ
n個の数からk個を選び出す組合せはCombination_IterableIntegerArray(0, n, k)で得られる。
Combination_IterableIntegerArray(a, n, k)とすれば、aに続くn個の数から選び出す。

0から3までの4個の数から2個を選び出す例。

>>> loop = util.impl.Combination_IterableIntegerArray(0, 4, 2)
>>> tray = jarray.array([0, 0], 'i')
>>> for x in loop.iterator(tray, 0, 2):
. . .    print x, tray
. . .
0 array('i', [0, 1])
1 array('i', [0, 2])
2 array('i', [0, 3])
3 array('i', [1, 2])
4 array('i', [1, 3])
5 array('i', [2, 3])
>>>



● 順列
n個の数からk個を並べる順列はPermutation_IterableIntegerArray(0, n, k)で得られる。
Permutation_IterableIntegerArray(a, n, k)とすれば、aに続くn個の数から取り出して並べる。

0から3までの4個の数から2個を並べる例。

>>> loop = util.impl.Permutation_IterableIntegerArray(0, 4, 2)
>>> tray = jarray.array([0, 0], 'i')
>>> for x in loop.iterator(tray, 0, 2):
. . .    print x, tray
. . .
0 array('i', [0, 1])
1 array('i', [0, 2])
2 array('i', [0, 3])
3 array('i', [1, 0])
4 array('i', [1, 2])
5 array('i', [1, 3])
6 array('i', [2, 0])
7 array('i', [2, 1])
8 array('i', [2, 3])
9 array('i', [3, 0])
10 array('i', [3, 1])
11 array('i', [3, 2])
>>>


● 重複組合せ
n個の数からk個を重複して取り出す重複組合せはMulticombination_IterableIntegerArray(0, n, k)で得られる。
Multicombination_IterableIntegerArray(a, n, k)とすれば、aに続くn個の数から取り出して並べる。

0から3までの4個の数から2個を重複して取り出す例。

>>> loop = util.impl.Multicombination_IterableIntegerArray(0, 4, 2)
>>> a = jarray.array([0, 0], 'i')
>>> for x in loop.iterator(a, 0, 2):
. . .    print x, tray
. . .
0 array('i', [0, 0])
1 array('i', [0, 1])
2 array('i', [0, 2])
3 array('i', [0, 3])
4 array('i', [1, 1])
5 array('i', [1, 2])
6 array('i', [1, 3])
7 array('i', [2, 2])
8 array('i', [2, 3])
9 array('i', [3, 3])
>>>


● 重複順列
n個の数からk個を重複して並べた重複順列は、k桁のn進数と1対1に対応する。
つまりRadixN_IterableIntegerArray(0, n, k)で得られる。

0から3までの4個の数から2個を重複して並べる例。

>>> loop = util.impl.RadixN_IterableIntegerArray(4)
>>> a = jarray.array([0, 0], 'i')
>>> for x in loop.iterator(a, 0, 2):
. . .    print x, tray
. . .
0 array('i', [0, 0])
1 array('i', [0, 1])
2 array('i', [0, 2])
3 array('i', [0, 3])
4 array('i', [1, 0])
5 array('i', [1, 1])
6 array('i', [1, 2])
7 array('i', [1, 3])
8 array('i', [2, 0])
9 array('i', [2, 1])
10 array('i', [2, 2])
11 array('i', [2, 3])
12 array('i', [3, 0])
13 array('i', [3, 1])
14 array('i', [3, 2])
15 array('i', [3, 3])
>>>


● 応用
以上のクラスは数を並べたものを生成するだけだが、オブジェクトの配列を介せば、
任意のオブジェクトの集合について、部分集合や置換を取ることができる。

配列['neko', 'cat', 'gato']から2つの元を選んで並べる例。

>>> b = ['neko', 'cat', 'gato']
>>> loop = util.impl.Permutation_IterableIntegerArray(0, 3, 2)
>>> tray = jarray.array([0, 0], 'i')
>>> for x in loop.iterator(tray, 0, 2):
. . .    print x, b[tray[0]], b[tray[1]]
. . .
0 neko cat
1 neko gato
2 cat neko
3 cat gato
4 gato neko
5 gato cat
>>>


● まとめ
多重ループとN進数(あるいは重複順列)、順列、組合せ、重複組合せの仮想コレクションを作った。
これを使えば、任意のオブジェクトの集合について部分集合や置換を取ることができる。

インタフェース IterableIntegerArray

2012-10-26 03:03:44 | Weblog
インタフェースjava.util.Iteratorは、コレクションを走査するためのものだ。
コレクションには実際にオブジェクトが収められている。
これに対し、順序を持った有限個のデータの集合を生成する規則が与えられれば、
実際にオブジェクトを保有していなくても、メソッドnext()が呼び出される度に
データを生成して返すこともできる。
通常のコレクションである前者を「実コレクション」、
後者を「仮想コレクション」と呼ぶことにしよう。

同じデータを保持しているなら、実コレクションより仮想コレクションの方が
少ないメモリ量で済む。
また、仮想コレクションを走査するIteratorが与えられれば、
next()で得られたオブジェクトをコピーすることで、実コレクションを作ることができる。
従って、計算量を大きく増やさずに仮想コレクションとして提供できるデータならば、
実コレクションとして提供するよりも仮想コレクションとして提供する方が優れている。

仮想コレクションも実コレクション同様、コレクションを表すクラスと
その上を走査するIteratorから成る。
実コレクションはjava.lang.Iterableを実装し、メソッドiterator()を持つ。
仮想コレクションも新規のIteratorを返すメソッドiterator()を持つ。

仮想コレクションではnext()の際、新しいインスタンスを作る必要が無い。
同じオブジェクトの内容を書き換えれば十分だ。
next()を呼び出した側がオブジェクトを書き換えたければ、
そこでコピーして書き換えればいい。
この書き換えるオブジェクトのことをトレイ(tray)と呼ぼう。

iterator()によって新規のIteratorのインスタンスを作る際には、
複数のスレッドで走査することを可能にするため、
トレイを新しく作る必要がある。

以上の考察をまとめると:
+ 仮想コレクションはデータを生成する規則への入力パラメータを保持し、
新規のIteratorを返すメソッドiterator()を持つ。
+ メソッドiterator()は新しいIteratorを生成する。
このIteratorはトレイを持つ。
+ Iteratorはメソッドnext()の度にトレイの内容を更新する。

このような仮想コレクションの基本的なものとして、トレイがint[]型のものを考える。
N重ループに相当するイテレータや、N桁のn進数を順に返すイテレータが、
長さNの配列で実装できる。

トレイをint[]にする場合、必ずしも全要素を使うは必要なく、
first番からn個の範囲を使うようにすることができる。
これらを利用者が指定できるようにするには、
メソッドの引数にしてiterator(int[], int, int): Iteratorとする。

これにより、インタフェースIterableIntegerArrayを定めることができる。
これはただひとつのメソッドiterator(int[], int, int): Iteratorを持つ。

この場合、トレイへの参照は呼び出し側が初めから持っているから、
Iteratorのメソッドnext()はトレイを返す必要が無い。
代わりにより有用な情報として、次のデータが本来何番目のデータなのかを
返すようにできる。
メソッドremove()が何もしない場合には、
これはもちろんforループにカウンタを付ければ済む。
だが、メソッドremove()がその意味通りに実装される場合には、
本来何番目かという情報は意義を持つ。
データは規則によって生成されているので、
データの内容だけから何番目かを求めることは出来る。
とはいえ、その計算はIterator内で行う方が簡単である。
こうしたことから、インタフェースIterableIntegerArrayのIteratorの
メソッドnext()はjava.lang.Integerを返すことにする。
つまり、Iterator<Integer>となる。

まとめ

healpyのコンベンション(pixelfunc)

2012-10-06 11:31:28 | Weblog
healpyのレファレンスだけでは
はっきりしない動作を確認してみる。
まずはpixelfuncから。

● 極座標の取り方
ang2vec()の動作から。


inubuyo@~$ python
Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import healpy
>>> healpy.pixelfunc.ang2vec(0, 0)
array([ 0., 0., 1.])

この座標の北極方向。


>>> import math
>>> healpy.pixelfunc.ang2vec(math.pi, 0)
array([ 1.22464680e-16, 0.00000000e+00, -1.00000000e+00])

南極方向。


>>> healpy.pixelfunc.ang2vec(math.pi, math.pi)
array([ -1.22464680e-16, 1.49975978e-32, -1.00000000e+00])

極方向では、結果は第2引数に対し精度の範囲で変わる。

赤道方向。

>>> healpy.pixelfunc.ang2vec(math.pi/2, 0)
array([ 1.00000000e+00, 0.00000000e+00, 6.12323400e-17])
>>> healpy.pixelfunc.ang2vec(math.pi/2, math.pi/2)
array([ 6.12323400e-17, 1.00000000e+00, 6.12323400e-17])
>>> healpy.pixelfunc.ang2vec(math.pi/2, math.pi)
array([ -1.00000000e+00, 1.22464680e-16, 6.12323400e-17])


ang2vec()の戻り値、vec2ang()の引数はnumpyのarrayである。

>>> import numpy
>>> healpy.pixelfunc.vec2ang(numpy.array([1, 0, 0]))
(array([ 1.57079633]), array([ 0.]))
>>> healpy.pixelfunc.vec2ang(numpy.array([0, 1, 0]))
(array([ 1.57079633]), array([ 1.57079633]))
>>> healpy.pixelfunc.vec2ang(numpy.array([0, 0, 1]))
(array([ 0.]), array([ 0.]))
>>> healpy.pixelfunc.vec2ang(numpy.array([-1, 0, 0]))
(array([ 1.57079633]), array([ 3.14159265]))
>>> healpy.pixelfunc.vec2ang(numpy.array([0, -1, 0]))
(array([ 1.57079633]), array([ 4.71238898]))
>>> healpy.pixelfunc.vec2ang(numpy.array([0, 0, -1]))
(array([ 3.14159265]), array([ 0.]))


これらは逆関数になっている。

>>> healpy.pixelfunc.vec2ang(healpy.pixelfunc.ang2vec(math.pi/2, math.pi/2))
(array([ 1.57079633]), array([ 1.57079633]))
>>> healpy.pixelfunc.vec2ang(healpy.pixelfunc.ang2vec(math.pi/2, math.pi))
(array([ 1.57079633]), array([ 3.14159265]))
>>> healpy.pixelfunc.vec2ang(healpy.pixelfunc.ang2vec(math.pi/2, 0))
(array([ 1.57079633]), array([ 0.]))


逆の合成は、そのままだと型が合わない。

>>> healpy.pixelfunc.ang2vec(healpy.pixelfunc.vec2ang(numpy.array([1, 0, 0])))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ang2vec() takes exactly 2 arguments (1 given)


戻り値をばらす。

>>> x =healpy.pixelfunc.vec2ang(numpy.array([1, 0, 0]))
>>> healpy.pixelfunc.ang2vec(x[0], x[1])
array([[ 1.00000000e+00, 0.00000000e+00, 6.12323400e-17]])


ベクトルの絶対値は1でなくても正ならよい。

>>> healpy.pixelfunc.vec2ang(numpy.array([3, 0, 0]))
(array([ 1.57079633]), array([ 0.]))


以上で任意の方向を表すベクトルと極座標の変換ができる。

● ピクセル番号と方向の変換

ピクセル番号に対する方向はpix2ang()とpix2vec()で得られる。
基本となるNSIDE=1の場合の12個のピクセルの方向は、極座標で以下の通り。

>>> healpy.pixelfunc.pix2ang(1, 0)
(0.84106867056793033, 0.78539816339744828)
>>> healpy.pixelfunc.pix2ang(1, 1)
(0.84106867056793033, 2.3561944901923448)
>>> healpy.pixelfunc.pix2ang(1, 2)
(0.84106867056793033, 3.926990816987241)
>>> healpy.pixelfunc.pix2ang(1, 3)
(0.84106867056793033, 5.4977871437821371)
>>> healpy.pixelfunc.pix2ang(1, 4)
(1.5707963267948966, 0.0)
>>> healpy.pixelfunc.pix2ang(1, 5)
(1.5707963267948966, 1.5707963267948966)
>>> healpy.pixelfunc.pix2ang(1, 6)
(1.5707963267948966, 3.1415926535897931)
>>> healpy.pixelfunc.pix2ang(1, 7)
(1.5707963267948966, 4.7123889803846897)
>>> healpy.pixelfunc.pix2ang(1, 8)
(2.3005239830218631, 0.78539816339744828)
>>> healpy.pixelfunc.pix2ang(1, 9)
(2.3005239830218631, 2.3561944901923448)
>>> healpy.pixelfunc.pix2ang(1, 10)
(2.3005239830218631, 3.926990816987241)
>>> healpy.pixelfunc.pix2ang(1, 11)
(2.3005239830218631, 5.4977871437821371)


関数pix2vec()と、ang2vec()とpix2ang()の合成は値は同じであるが、型と精度が異なる。

>>> healpy.pixelfunc.pix2vec(1, 0)
(0.52704627669472992, 0.52704627669472981, 0.66666666666666663)
>>> x = healpy.pixelfunc.pix2ang(1, 0)
>>> healpy.pixelfunc.ang2vec(x[0], x[1])
array([ 0.52704628, 0.52704628, 0.66666667])


同様に、関数pix2ang()と、vec2ang()とpix2vec()の合成は値は同じであるが、型と精度が異なる。

>>> healpy.pixelfunc.pix2ang(1, 0)
(0.84106867056793033, 0.78539816339744828)
>>> healpy.pixelfunc.vec2ang(numpy.array(healpy.pixelfunc.pix2vec(1, 0)))
(array([ 0.84106867]), array([ 0.78539816]))


pix2ang()の第2引数は配列にできる。

>>> healpy.pixelfunc.pix2ang(1, [0, 4])
(array([ 0.84106867, 1.57079633]), array([ 0.78539816, 0. ]))


順序は自由、同じ値が入っても大丈夫。

>>> healpy.pixelfunc.pix2ang(1, [4, 0])
(array([ 1.57079633, 0.84106867]), array([ 0. , 0.78539816]))
>>> healpy.pixelfunc.pix2ang(1, [0, 0])
(array([ 0.84106867, 0.84106867]), array([ 0.78539816, 0.78539816]))


pix2ang()の第1引数も配列にできる。

>>> healpy.pixelfunc.pix2ang([1, 2], 0)
(array([ 0.84106867, 0.41113786]), array([ 0.78539816, 0.78539816]))


だが、両方の引数を配列にしてしまうと、第2引数は最初の要素のみが使われる。

>>> healpy.pixelfunc.pix2ang([1, 2], [0, 1])
(array([ 0.84106867, 0.41113786]), array([ 0.78539816, 2.35619449]))
>>> healpy.pixelfunc.pix2ang([1, 2], 0)
(array([ 0.84106867, 0.41113786]), array([ 0.78539816, 0.78539816]))


pix2ang()の逆がang2pix()である。

>>> healpy.pixelfunc.ang2pix(1, 0.84106867, 0.78539816)
0

もちろん、あるピクセルに対応するのは1点ではなく、広さを持った領域である。

>>> healpy.pixelfunc.ang2pix(1, 0.84, 0.78)
0

合成すればピクセルの中心への射影になる。

>>> healpy.pixelfunc.pix2ang(1, healpy.pixelfunc.ang2pix(1, 0.84106867, 0.78539816))
(0.84106867056793033, 0.78539816339744828)


今日はここまで。

Mac OS X 10.7にhealpyを入れる

2012-10-05 15:34:08 | Weblog
● 概要
Mac OS X 10.7上のpython 2.7にhealpyをインストールしたときの注意点です。

● 手順
+ 本家からzipballをダウンロードする。
現在の最新版は1.4。

+ zip内のREADME.rstを一応見る。
インストールについてはINSTALLを見ろと書いてある。

+ INSTALLを確認する。
INSTALLの70行目以降にMac OS Xの場合の奨励される方法が書いてある。


Compile on OSX
--------------

Suggested compilation on OSX Lion is installing pyfits, cython and cfitsio using mac ports and run:
>>> python setup.py --without-openmp


これに基づき、pyfitsとcfitsioを用意しておく。
pyfitsは本家からソースをダウンロードし

> sudo python setup.py install

でOK。
cfitsioはHomebrewで入れられる。

> brew install cfitsio

でOK。
cythonは無くても大丈夫。

+ 環境変数を設定する。
INSTALLの20行目付近の記述

Either define the environment variable CFITSIO_EXT_PREFIX where to find the
cfitsio library and include file (eg /usr/local, so that
/usr/local/include/fitsio.h and /usr/local/lib/libcfitsio.a exists),

に従って環境変数CFITSIO_EXT_PREFIXをする。
Homebrewで入れたなら/usr/localになっているので
CFITSIO_EXT_PREFIX=/usr/localとする。

+ ビルドする。
これでビルドできる。

> python setup.py --without-openmp build


+ インストールする。
Homebrewでcfitsioを入れた場合、
このままインストールするとhpbeta/config/config.healpy_osxに問題があってうまくいかない。
9行目に

CFITSIO_EXT_PREFIX ?= /opt/local

となっている箇所があるので、これを

CFITSIO_EXT_PREFIX ?= /usr/local

に変更しておく。

以上の後に、

> sudo python setup.py --without-openmp install

でOK。

ちなみに、--without-openmpは必須らしい。
これが無いとインストールはできるものの、
import時に

Symbol not found: _GOMP_loop_dynamic_next

と出る。