NISHIO Hirokazu's website > NISHIO HIROKAZU # Archived COREBlog
これは2004年11月4日から2006年2月18日までZopeで運用していたCOREBlogの静的なアーカイブです。
新しい日記は「西尾泰和の日記」で運用しています。
現在選ばれているカテゴリー
- Python
絞り込む
マルチカテゴリでの絞り込み機能は静的アーカイブ化の際に停止しました。
[EnglishImprinter]
[Eclipse]
[雑記]
[リンク]
[PostScript]
[Java]
[英語の勉強]
[Jython]
[GRINEdit]
RSSを取得するプログラム
EnglishImprinterに貼り付ける英文をスラッシュドットのRSSから取ってきたら面白いかと思ってRSSの取り方を調べる。
import feedparser
d=feedparser.parse("http://slashdot.org/index.rss")
return d.entries[0].description
えっ、3行…。さすがPython…。
追記@2004/12/09 このエントリはJythonでRSSを取得とRSSを取得するプログラム-補足から参照されています。
JythonでRSSを取得
Pythonならfeedparserを使って3行でRSSを読めるけど、Jythonではつかえないという話の続編。
仕方がないので自分で実装したよ。30行。行数が10倍に増えた!なんて重労働だ!(笑)
ちなみに最新のPythonでは「xmllibじゃなくてxml.saxを使え」と警告が出るんだけど、xml.saxがJythonにはないんじゃないかと思ったのであえて古いxmllibで実装してみた。で、Jythonで動作チェックしたらちゃんと動いたのでEnglishImprinter v0.46リリース。
Continue reading "JythonでRSSを取得"
RSSを取得するプログラム-補足
RSSを取得するプログラムの「えっ、3行…。さすがPython…。」にれり氏から激しいつっこみがあったので補足記事
y: なあなあ
p: なになに
y: 別にライブラリがあるから3行なだけでpythonがすごいとは思わないんだが
p: 3行でかけちゃうライブラリがあるところがすごいんだよ。Pythonって言語の性能がすごいんではないw
y: さすがpythonってかかれるとpythonがすごいようにみえるさ
y: まあ、なんかライブラリレベルで使ったものにたいして3行で短いからすごいって言われるのに納得がいかなかっただけさ
p: Schemerらしい発言だw
y: そうかねw
p: 現実問題として、実装がラクならそれが言語の機能としてだろうがライブラリとしてだろうがどっちだってかまわんw
y: このJAVAも上手くラップすれば簡単に使えるようになるんじゃないかねえ
(編注:InformaってJavaのライブラリ、いろんなライブラリを呼んでるせいで4メガもあって、しかもライセンスがまちまちという代物)
p: つか、ラップすれば簡単になるのは当たり前で、ライブラリって結局全部そうじゃん
y: そうだよ
p: ようは自分がラップするの面倒ってことさw
y: いやだからJAVAだって3行近くになるってことさ。
p: きれいにラップされたライブラリがすでにあるのが重要なんだよw可能性があるだけじゃダメだw
y: わかってるよ、いいたいことはw
p: ならいいやw
y: いいたいことはわかってるけど、あの文章を見ると納得がいかんだけだw
y: (こんなに簡単に使えるものが標準で用意されてるなんて)さすがPython...
y: と補えばいいんだな。
p: まぁ、標準じゃないんだがw
y: 違うのかよw
p: 違うんだよw
y: 誰かが作ったライブラリかよ
p: だよw
y: 論外じゃん・・・
p: なにがだよw
y: もうあんな文章消せw
p: なんだよもうw
p: わかったよ捕足記事書いとくよw
といういきさつですw
えーと、先日の記事はfeedparserっていうライブラリをダウンロードしてきてライブラリフォルダにぽいっとほりこんだ後での話です。このことを書き忘れたことによってPythonのすごさを誇張してしまったこととについてここにお詫びします。
オチがないなぁ。
Pydev
---
http://pydev.sourceforge.net/
Eclipse用のPythonプラグイン。
Some features provided are:
# Code Completion (disabled by default - check the preferences page.)
# Refactoring with bicycle repair man
おおっと。補完機能が実装済みじゃないか。
バージョンはまだ1.0ではないけどとりあえず試してみよう。
PyX
PyX(PythonのPostScriptライブラリ)のドキュメントを読んでみたけど
なかなかよさそう。
TeX/LaTeXとシームレスに接続されているっぽい。
まだざっと読んだだけなので試してみないとどれほどのものかわからないけど、
今後は論文とかの執筆にPyXを使うことになるかもなぁ。
今までTeXでストレスなくやっていた部分はPyXからTeXを呼んで、
\specialを使ったりepsファイルを取り込んだりしていた部分は直接Pythonで書くとか。
PythonでSWFを出力
よく考えたら、SOMの学習過程を表示するのに、
プログラムから連番BMPを出力して、それをSWF(Flash)に変換しているのって変だよね。
最新のはAVIに変換しているから特に急ぎの需要はないのだけど、
SWFはベクターフォーマットじゃん?
だったらベクターをそのまま書き出したら劣化しなくて綺麗なんじゃないの?
でも直接SWFを出力するプログラムって面倒かな?
PythonでSWFを出力するライブラリがないか探してみるか。
PS: http://packages.qa.debian.org/libm/libming.html
PythonでSOM
SOMのライブラリ
らしきものは発見したけど、微妙〜。まぁ検討しておこう。
更新更新
WindowsUpdate1件
PyXインストール。「RuntimeError: no information for font 'cmr10' found in font mapping file, aborting」とか言うのでフォントの設定の仕方を調べよう。
Eclipseを3.0にアップ。
必要なのは
eclipse-SDK-3.0.1-win32.zip
と
NLpack-eclipse-SDK-3.0.x-win32.zip
だった。ランゲージパック(NL〜)をLhaplusで解凍しようとしたらエラーが出たので適当に別のアーカイバを入れようと探して「解凍レンジ」をインストール。無事解凍できた。
Eclipse3でEclipse2のワークスペースを開くことができないか試し見たら、ワークスペースがEclipse2でも読めなくなってしまった。
Eclipse3でちまちまファイルシステムからのインポートを使ってプロジェクトを作ろう。
Eclipse用のプロファイラと、Pydevをインストールしたけどまだ試してない。
Pydev試してみた。Pythonでもメソッド一覧とかが出るし、クラスや関数をたためるし、便利だなぁ。
CVSからチェックアウトしてプロジェクトを作成できる。
SourceForgeに入れてあったプロジェクトは簡単に復元できた。
それはそうとSourceForge.jpに入れてもSourceForge.netの検索にはひっかからないんだなぁ。当然ソフトウェアマップにも登録されていないんだろうなぁ。
オープンにしたいからオープンソースにしてるのに、
日本国内だけにしかオープンされてないのか。
うーん、それじゃSourceForge.jpを選ぶメリットって何?
メニューとかが日本語ってところだけ?
もう8時だから朝ごはんを食べて、それから、
BeadsModdelerをEclipse3にインポートして、
プロファイラを試して、
リファクタリングしてSourceForge.jpに入れよう。
ifだってgotoですよ?
gotoを使って汚く書かくとあまりに読みにくいコードになるせいで、
「gotoは悪」という考え方が蔓延していますよね。
でもそれって手段と目的が入れ替わっているのではないでしょうか。
gotoを使わないことが重要なのではなくて、論理の筋道がわかりやすいことが重要なんですから。
結局のところ、順次実行以外はifだろうがbreakだろうが、すべて実行する位置がジャンプするという意味ではgotoなのですし。
というわけで悪いコードの例。
for id in idList:
try:
f=getCacheFilename(id)
data=file(f).read() # キャッシュから読めるか試す
except:
try:
# キャッシュになかったので外部サーバから読む
url=getUrl(id)
data=urlopen(url).read()
except:
# それすらもできなかったのでデータはなし
print "Error", f
data=None
if data != None: # データが取れていればキャッシュに保存
file(f, "w").write()
if data != None:
doSomeProcess(data)
不必要なジャンプがいくつかあります。
より大きなジャンプを使うことで取り除くことができます。
改良案はExtendの中に。
Continue reading "ifだってgotoですよ?"
WIN32 Python ming-0.2aを作る方法
---
http://redhot.pepper.jp/ming/python_ming_win32.html
とりあえずメモ。これを使って球面SOMの解析結果をSWFで吐き出すライブラリを作ろうかと思っているけどとりあえず他にすることもあるし保留かな。
PyXで矢印つきの円弧を書くには…
さっきまでPyPSで正二十面体の再帰的分割の図を作ってました。いやぁ、いい感じにできた。拡大縮小しても荒れない。やっぱりEPSはいいなぁ。でもPythonで出力したPSファイルを、GIMPでトリミングをやってEPSで保存をしたら、もー、台無しになってた。仕方がないので結局PSファイルをテキストエディタでいじってt自分でEPSを作ったり。難しい作業ではないんだけど、やっぱ心理的抵抗は高いかもなぁ。
で、そんなことはさておき、矢印を多用した(そしてその図を描くためだけにPowerPointを使ったw)図をPyXで作り直したらもっとかっこよくなるかなぁ、とチャレンジしてたんだがね。うーん、PyXでpath.arcにdeco.earrow.normal()と矢印でデコレーションするように指示しても
AttributeError: 'arc' object has no attribute 'normpath'
と言われる。connector.arcを使わないといけないっぽいけど、なんかサンプル集を見た限りだとテキストボックスの結合に特化してるっぽいなぁ…。まぁいいか。
最悪サイズ0のテキストボックスとか使えば何とかなるだろう。
PyDev メリット・デメリット
PyDev(EclipseのPython用プラグイン)のコード補完機能をいまさらながら使ってみる。
うーん、微妙。
Javaのような静的型付けの言語なら、実行しないでも名前の一覧を取得できたりするわけだけど
Pythonのような動的型付けの言語じゃぁ、実行してみないことには何もわからないわけだ。
そもそも実行時に動的に変えられると言うことがJavaにないアドバンテージなわけだし。
で、コード補完のためにPyDevでは補完キーを押すたびにスクリプトが実行されるわけだ。
うん。トップレベルで1/0って書くと補完がきかなくなるし、
10000回のループを書いてみたらEclipseごとハングアップした。
補完を使うソースコードで記述するのは関数とクラスの定義だけにしておくのが無難だなぁ。
Pythonでの開発で、標準添付のエディタ「IDLE」を使わずにPyDevを用いたときのメリット。
まず、Eclipseのアウトライン表示機能を援用してクラスや関数名の一覧が表示され、
ダブルクリックでジャンプできる。エディタ上でCtrl+クリックでもジャンプできる。
コードの行数が3桁を超えるようになると便利だと思う。
あと人の作ったライブラリを読む場合にも。
クラスや関数単位でソースコードを畳む機能があって、最初見たときはちょっと喜んだけど、
…これはそんなに使わないなぁ。
MDIでコンソール出力とエディタとが並んでいるので画面を切り替える必要がなくていい。
ただし画面が狭い場合には逆にストレスになるかも。
エラーが起きたときにクリックでその行へ飛ぶことができる。これは1画面でおさまらないコード量になるとかなり便利。
おそらく実行ごとにインタプリタを新しいプロセスとして走らせているのでライブラリを修正した場合に明示的にリロードしなくても新しいほうが使われると思われる。まだ確認してないけど。
デメリット。
実行方法の設定がちょっと面倒。
あと、対話的インタプリタじゃないので直接コードを打ち込んでテストすることができないね。
そしてコード補完でスクリプトを実行されてしまうので、
関数やクラスの定義だけを書いたスクリプトと、
その適当な関数を呼ぶテスト用スクリプトの最低2つが必要になるわけですな。
でも、ジャンプ機能だけでここに書いたデメリットを補って余りある気がするなぁ。
なんてことをつぶやきながらAlgoを実装してみた。
ルールは白黒の要素をなくしたシンプルなものだけど、一応遊べるのでいいとしよう。
まだAIが「すでに開かれている札から判断して一番当たる確率の高いところに当てに行き、当たったら必ずステイする」
というシンプルなものだから弱い弱い。
伏せ札を(n)で表現すると、例えば
「(0) (1) (2) 4」という札の並びならば、各数字1枚しかなくて、小さい順に並べられているので、
(0)の札は0か1でしかありえないんだけど、今は「4未満」としか判断できてないからね。
その実装はまた今度気の向いたときに。
Pythonにおけるタプルの存在意義
入室だけして忙しくて読んでなかったチャットのログを読んでみた。
「要素を追加できないのがタプル」というような発言に対して
「固定長なだけじゃなくて、要素の変更もできない」という趣旨の言葉をかなり言葉足らずに投げっぱなしだったのでアフターサービスw
どうもその後は「変更できない配列なんて何に使うんだ」「コサイン値のテーブルを作ったりするのに使うんじゃないか」という話になっていた模様。
うーん、あんまりPythonみたいな高級言語でコサイン値をテーブルで保持するような低級なことをする人は居ないねぇ。
変更可能(mutable)な「リスト」に対して、「文字列」と「タプル」は変更不可能(immutable)なんだが、なんで変更できないなんていうデメリットのようなものを残してあるのだろうか。これは「変更できない」を「変更されていないことを保証できる」と言い換えればメリットにもなる。
この「変更されていないことを保証できる」という特長をによって、immutableなオブジェクトはある値(ハッシュ値)と一意に対応付けることができる。つまり、ハッシュ(辞書)のキーとして用いることができる。これがタプルというものの存在する最大のメリットだと思う。
data={} # dataは空の辞書
position=(x, y) # positionは2つの値のタプル(この場合はたぶん2次元のベクトル)
data[position]=z # タプルをキーにして辞書に値を入れることができる
Pythonの辞書(いわゆるハッシュ)は非常に強力な組み込みデータ型で、
immutableなオブジェクトならどんなものでもキーとして用いることができるんだ。
data[1]もOK、data[3.14]もOK、data[(1.0, 3.5)]もOK、さらに言えば
maxTemperature[('大阪市', (2005, 1, 16))]なんて感じにいろんなオブジェクトをくっつけて一つにしたモノだってキーにできる。
そして当たり前だけど値のほうにはmutable/immutable関係なくどんなオブジェクトでもつっこむことができる。
for pos in data.keys(): # data.keys()はdataと書いても実はかまわない
(x, y)=pos # tuple unpacking
print x, data[pos] # xとzの関係を表示
タプルやハッシュの強力さのおかげでPythonでプロトタイプを作るのはかなり楽チンなんだけど、問題点もある。それは「要素が1個のタプル」を直感的に(x)と書きたいんだけど、それじゃ演算の優先順序を変える(x+y)*zの括弧と区別できない、って点。それが原因で要素が一つのタプルは(x,)なんていう気持ちの悪い書き方をしないといけなかったりする。
100日目の求め方
100日目は先に手計算で求めちゃったんだけど、ついでなので1000日目まで100日刻みに計算してみた。Pythonではdatetimeライブラリの中にあるtimedeltaで時間の差分を表現できる。
これをつかうと普通の算術式で日付を計算できてとても便利。
>>> import datetime
>>> start=datetime.date(2004, 12, 25)
>>> delta=datetime.timedelta(days=100)
>>> start+delta
datetime.date(2005, 4, 4)
>>> start+delta*2
datetime.date(2005, 7, 13)
>>> for i in range(11):
date=start+delta*i
print date.strftime("%Y/%m/%d"), "%d日目"%(i*100)
2004/12/25 0日目
2005/04/04 100日目
2005/07/13 200日目
2005/10/21 300日目
2006/01/29 400日目
2006/05/09 500日目
2006/08/17 600日目
2006/11/25 700日目
2007/03/05 800日目
2007/06/13 900日目
2007/09/21 1000日目
携帯のメールをバックアップ
携帯のメールをパソコンにバックアップするソフトはいろんな種類があるけれど、よく考えたら僕のThinkPad T40pには赤外線ポートが付いているのだから、これを使って携帯と通信できないかな?
と思って探してみたらあるある。
Ir全件転送
赤外線ポートとの間合いのとり方がよくわからなくて試行錯誤したけど、D504iではちゃんと転送ができましたよ。無料で。
細かい話はExtendsの中に。
Continue reading "携帯のメールをバックアップ"
Pythonでprintの結果を文字列として手に入れたい時
Zopeの「return printed」みたいなことをやりたかったわけです。意外と簡単。
import sys
stdout=sys.stdout
import cStringIO
tmpout=cStringIO.StringIO() # 一時的出力先
sys.stdout=tmpout
exec(self.script) # スクリプトを実行する
sys.stdout=stdout
tmpout.seek(0)
return tmpout.read()
と、スクリプトを実行する間だけ一時的に出力先を変えてやるだけ。
catchPrinted
catchPrinted.py
import sys
import cStringIO
def open():
tmpout=cStringIO.StringIO()
stdout=sys.stdout
sys.stdout=tmpout
class buffer:
def close(self):
tmpout.seek(0)
sys.stdout=stdout
return tmpout.read()
return buffer()
usecase
import catchPrinted
(snip)
def render(self):
buffer=catchPrinted.open()
exec(self.script)
return buffer.close()
使いまわすためにライブラリに切り出したらこんなふうになりました。
「bufferを閉じてreturnする」って言葉遣いがおかしいような。
「catchするのをやめて、中身を全部出す」というような意味の英単語があれば(そんな都合のいいものがあるわけない)
やっぱ「この関数の中でprintされた文字列を、この関数の帰り値として返す」みたいなアスペクトを織り込むのが(マテ
Pythonのsum
おっと、Pythonのsumって数値限定なんだ?
>>> sum([[1,2,3], [4,5,6]])
TypeError: unsupported operand type(s) for +: 'int' and 'list'
僕の中ではこういう動作を期待したんだが。
>>> from operator import add
>>> reduce(add, [[1,2,3], [4,5,6], [7,8,9]])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Python3.0からreduceがなくなっちゃうんだよなぁ…。うーん。面倒だなぁ。
今日の呪文
bounds=[b for b in bounds if b]
誰だこんなコード書いたのは!(自分)
やっぱbounds=filter(None, bounds)のほうがよっぽど可読性が高いと、え、ダメですかそうですかゴメンナサイせめて変数名変えるべきですねソウデスネ
統計言語RをPythonから呼ぶ方法
RPyってライブラリを使えばRのすべての関数をPythonから呼ぶことが出来るそうな。
see dW
PythonをCで拡張してみた
大学の元同級生れり氏がPythonをCで拡張するのに挑戦中。
僕もCやDelphiやJavaからPythonを呼ぶのはやったことがあるけど、PythonのライブラリをCで作ったことがないので相乗りしてみた。
Windows上でビルドする方法がまだよくわからないのだけど、れり氏のLinuxや学校のFreeBSDでは非常に簡単。れり氏にもらったsetup.py
from distutils.core import setup, Extension
setup(name="cons", version="1.0",
ext_modules=[Extension("cons", ["cons.c"])])
を「python setup.py build」ってやるだけでbuildディレクトリが作られてその中に環境の名前のディレクトリが出来て、その中に*.soが出来ている。「gccの-Iって何だっけ」とかそんなことはそもそも考える必要ないのか。
で、出来たライブラリを使ってテストするにはそのsoが検索パスに入るようにしてやればいい。というわけで僕は
import sys
sys.path.append("build/lib.freebsd-4.8-STABLE-i386-2.2/")
で始まるテストコードを作って実行することにした。
とりあえず、れり氏のconsライブラリに(1 . (2 . (3 . 4)))を( 1 2 3 . 4 )と表示する機能を付けてみた。面白いなぁ。というか想像以上に簡単だな、PythonをCで拡張するのって。
今後Pythonスクリプトでスペック上の問題が出たらCで拡張することにするか(って最近Jython使いなのでそうも行かない罠)
Pythonの長整数を使ってdoubleを超える精度を出す
doubleは15桁しか精度がないという話を見て、ちょっとプログラムを書いてみました(そんなことしてないで書類書けって自分
3.141592653589793238462643383279502884197169399375105820974944*
を2進法で表すと
11.0010010000
1111110110
1010100010
0010000101
1010001100
0010001101
0011000100
1100011001
1000101000
1011100000
0011011100
0001110011
0100010010
1001000000
1001001110
0000100010
0010100110
0111110011
0001110100
000000*
になります。*は「その桁が何か確定しない」という意味で使っています。
ソースコードはたいしたことなくて(15分もかかってないので怒らないで下さい>書類を待っている人)
num=141592653589793238462643383279502884197169399375105820974944
ub=1000000000000000000000000000000000000000000000000000000000000
lb=1
while True:
num*=2
lb*=2
if num + lb >= ub:
if num < ub:
print "*"
break
else:
print 1,
num-=ub
else:
print 0,
こんなかんじ。円周率の真の値をPIとすると、
num/ub <= PI < (num+lb)/ub
が成り立つように3つの変数の値を決めてやって、
後はその誤差lbのせいで桁が確定しなくなるまで展開してやっているだけです。
つか、別に2進法にするとかは重要じゃなくて、長整数を組み合わせてこういう方法を取れば「メモリの許す限り精度の高い実数」
が実装できるということのほうが重要な気がしてきた。
Python初学者向けライブラリ
結局のところ、初学者って「ここでこの変数はリストで何番目の値は何々だ」ってのがわからなかったり、文字列の'111'と整数の111を区別してなかったりしているので、それを見やすくしよう、ってライブラリなんだけどね。
ほんとはGUIにしてリストオブジェクトからは矢印がいっぱい生えて他のオブジェクトに刺さっているみたいな表示が出来るようにしたり、ついでにそれに自動レイアウティングを入れたりすればツリーだろうがリンクリストだろうが一般的に表示できて中級者にも便利〜とか考えたんだけど時間がないのでとりあえず。
だから今は循環参照があるとエラーになります。
import pyShowObj
pyShowObj.showObject(globals())
と書いて実行すると
タイプ:辞書(dict)
キー「__builtins__」に対応する値:
タイプ:module
値:<module '__builtin__' (built-in)>
キー「pyShowObj」に対応する値:
タイプ:module
値:
キー「__name__」に対応する値:
タイプ:文字列(str)
値:'__main__'
キー「__doc__」に対応する値:
タイプ:NoneType
値:None
改行キーを押すと続行します...
と表示されます。
もちろん、初学者には自分の作ってない変数がうじょうじょ出てきても驚くだけなので
import pyShowObj
a=1
b=3.14
c=[a,b]
pyShowObj.showNamespace(globals())
ってやれば
変数名「a」:
タイプ:整数(int)
値:1
変数名「c」:
タイプ:リスト(list)
0番目の値:
タイプ:整数(int)
値:1
1番目の値:
タイプ:実数(float)
値:3.1400000000000001
変数名「b」:
タイプ:実数(float)
値:3.1400000000000001
改行キーを押すと続行します...
ってなるようになっています。
なお「改行キーを押すと続行します」って機能がなぜあるかというと、
ループを理解できていない生徒には
import pyShowObj
input=[1,2,3,4]
sum=0
for i in input:
pyShowObj.showNamespace(globals())
sum+=i
pyShowObj.showNamespace(globals())
こんな風にして変数が変わっていく様子を順繰りに見てもらおうということです。
さて、肝心のソースコードですが、まぁここにはっつけてもどうせすぐ埋もれるのでSF.jpにプロジェクトを登録してきました。承認され次第ベータ版として公開するとしませう。
再起呼び出しはそもそもそんなに必要なのか?
渡辺さんの日記の(フィボナッチ数列を求めるプログラムを書けといわれて)「再帰を使わずに何とかしようとする奴も駄目だな。」という友達の言葉に過剰反応していいですか(なぜ疑問形)
巷に転がっている教科書には再起呼び出しの解説に階乗やフィボナッチ数列の計算を使っているものもなぜかたくさんあるようにも思うけど、それを鵜呑みにしてフィボナッチ数列を求めるプログラムに再起呼び出しなんか使うのはどうかと思う。だってまずもって再起呼び出しの必要性が薄いのに関数呼び出しの高いコストを支払うメリットが見えないし、そもそもそれってn^22^nのオーダーじゃない?
というわけで(自然言語で書くより先にコードを書いちゃったので)長いけど貼り付けてみる。
# -*- coding: cp932 -*-
from time import clock
N=30
# 再起呼び出しによるシンプルな方法
def fib(n):
assert isinstance(n, int) and n > 0
if n==1 or n==2:
return 1
return fib(n-1)+fib(n-2)
t=clock()
#print fib(N)
print clock()-t
# 再起呼び出しで結果をキャッシュする方法
cache={}
def fib(n):
assert isinstance(n, int) and n > 0
if n==1 or n==2:
return 1
if not(cache.has_key(n)):
cache[n]=fib(n-1)+fib(n-2)
return cache[n]
t=clock()
print fib(N)
print clock()-t
# 再起呼び出しを使わない方法(ダメだといわれている例)
def fib(n):
assert isinstance(n, int) and n > 0
if n==1 or n==2:
return 1
buf=[None]*n
buf[0]=1
buf[1]=1
for i in range(2,n):
buf[i]=buf[i-1]+buf[i-2]
return buf[n-1]
t=clock()
print fib(N)
print clock()-t
# 再起呼び出しを使わない方法(僕ならこう書く)
def fib(n):
assert isinstance(n, int) and n > 0
if n==1 or n==2:
return 1
v1=1
v2=1
for i in range(n-2):
(v1, v2)=(v2, v1+v2)
return v2
t=clock()
print fib(N)
print clock()-t
この実行した結果はこう。(読みやすく適当に整形した)
再起呼び出しによるシンプルな方法:1.74567242485秒
再起呼び出しで結果をキャッシュする方法:0.00460421645768秒
再起呼び出しを使わない方法(ダメだといわれている例):0.00455057835563秒
僕ならこう書く:0.00448269263272
まぁ、問題条件に「パフォーマンスを気にしろ」という条件がないのなら再起呼び出しで書いたっていいとは思うけど…高々fib(30)を求めるだけに380倍のパフォーマンスの差が出てるのはあんまりなぁ…。
うーん、それとも、再起呼び出しを使ってフィボナッチ数列を求める効率のいいアルゴリズムがあるのかなぁ。単に僕の使い方がまずいだけで。
まぁ、そんなこんなで僕が渡辺さんの友達にプログラミングスキルを判定してもらうときっと「駄目な奴」という烙印を押されて帰ってくる羽目になるんだろうけど、別にいいや(笑)
個人的には再起呼び出しを教えるならL-Systemで木の絵を書くとかハノイの塔の問題を解くとかがいいんじゃないかと思います。あと木を縦型探索とかグラフの全域木を作るとかかな。
GMailFS - Gmail Filesystem
---
http://lowlife.jp/yasusii/stories/20.html
いや、別にGMailをファイルシステムとして使いたいわけではないんだけど
>Linux には FUSE (Filesystem in USErspace) というカーネルモジュールがありまして、これを使うとファイルシステムがユーザランドのプログラムとして書けてしまうんです。
>GmailFS は Python を使って書かれています。
ほー。僕も何かファイルシステムを作ってみようかな…。
出来た出来た
ふぅ。例のPython初学者用ライブラリのにGraphVizで可視化する機能を付けました。
showNamespace(g)とshowNamespaceAsGraph(g)は引数としてglobals()が渡されることを期待していて、showObj(o)とshowObjAsGraph(o)は任意のオブジェクトが渡されるのを期待しています。ってかこういうことはコードの中にコメントで書いておいたほうがいいか。
*AsGraphを使う場合は
dotpos=r"C:\PROGRA~1\ATT\Graphviz\bin\dot.exe"
のところを書き換えるか、使用するときに
import pyObjVis
pyObjVis.dotpos=r"d:\tools\Graphviz\bin\dot.exe"
とでもやってGraphVisのdot.exeがどこにあるかを指定してやる必要があります。まぁ、プログラミングに不慣れな人に使わせるって目的から考えるとコードを書き換えておいてあげるのが手っ取り早いのかな。
後は…クラスや関数が持っている参照は可視化してませんが…需要あるかなぁ。まぁ、とりあえず公開しておいて、反響次第で考えよう。
import pyObjVis
b=[1, "hoge"]
def foo():
pass
obj=(1,(2.5,({"hoge": foo},b)),(b,ord))
pyObjVis.showObjAsGraph(obj)
で
って感じに。
import pyObjVis
obj=(1,(2,(3,(4,(5,None)))))
pyObjVis.showObjAsGraph(obj)
なら
って感じですね。こういうツリー状のものならコンソール表示も出来て、そっちは前と同様日本語で表示されます。こんな感じ。
タイプ:タプル(tuple)
0番目の値:
タイプ:整数(int)
値:1
1番目の値:
タイプ:タプル(tuple)
0番目の値:
タイプ:整数(int)
値:2
1番目の値:
タイプ:タプル(tuple)
0番目の値:
タイプ:整数(int)
値:3
1番目の値:
タイプ:タプル(tuple)
0番目の値:
タイプ:整数(int)
値:4
1番目の値:
タイプ:タプル(tuple)
0番目の値:
タイプ:整数(int)
値:5
1番目の値:
タイプ:NoneType
値:None
これでとりあえず二分木だのリストだのを教えるのは楽になるかな。既知の問題点は関数やクラスが持っている参照を表示していないことと、ハッシュが本当はimmutableなオブジェクトなら何でもキーに出来る以上タプルなんかも入るけどいまはreprしてキーのところに表示しているあたりかな。まぁ、でも、それをしっかりやるとかえって理解しにくいものになっちゃうかな〜。
とりあえず
とりあえずキーボードをフックするプログラムは
def showMozilla(param):
(w,l)=param
import virtualKeys
if virtualKeys.code2str(w)=="M":
from win32gui import FindWindow, SetForegroundWindow
hWnd=FindWindow("MozillaWindowClass",None)
SetForegroundWindow(hWnd)
keyListenerList.append(showMozilla)
とか書いておくと「Mを押せばMozillaが表示される」という機能が追加できるようになりました。まぁもちろんMでMozillaが立ち上がっていたんじゃ文章かけないんで、その辺は適当なメタキーと組み合わせたり、複数ストロークに意味を持たせたり、USBのテンキーを丸ごと特殊機能キーにしたり、さらにテンキーを解体して足踏みボタンに接続したり…ということをやる必要がありますが、まぁその辺はPythonでちょこっと書けばいいだけですね(もちろん足踏みボタンはPythonでは作れないけど)
ところで、キーに機能を割り当てたりした場合、その機能を入力しただけなのにエディタにキーが打ち込まれてしまうと嬉しくなかったりしますよね。フック関数の中で呼んでいる
CallNextHookEx(hndHook, code, wParam, lParam);
のParamとかを書き換えればいいのかな、と思ってとりあえず試しに
CallNextHookEx(hndHook, code, wParam+1, lParam);
ってやってみたんですよ、wParamは仮想キーコードなのでこうすればAを押したときにエディタにはBが入るかなぁ…と。
でもAが入ってしまう。何か考え違いをしているらしい。
あと、テンキーは想像していたよりインテリジェントだということが判明。ただのスイッチの集まりのように考えていたんだけど、5のキーを押して離す過程で
VK_NUMLOCK key down
VK_NUMLOCK key up
VK_NUMPAD5 key down
VK_NUMPAD5 key up
VK_NUMLOCK key down
VK_NUMLOCK key up
こんだけのメッセージがとんでくる。このテンキーだけの仕様だろうか?どちらかというと余計な機能のついていないシンプルなののほうが改造しやすいと思うんだけどな。
それはさておき僕はテンキーで数字を打つ習慣がないから、いっそテンキー入力はすべてエディタに中継しないことにして、テンキーまるごとメタキーにするってのはどうだろう。つまり例えばテンキーの5に「Firefox」ってラベルを貼って、テンキーの5を押しながら右矢印ならタブ移動とか…。あー、でもテンキーを押すのに手を一本使ってしまうとせっかくもう片方のキーボードとの組み合わせで膨大な操作が登録できるのに片手操作か…。やっぱメタキーは足踏みがいいか…。
これだけ使ってかまわないスペースがたくさんあれば、住所や電話番号なんかを登録してしまうのも手だな。というかテンキーを0.5秒ほど長押しすると続くコマンドの候補がガイド表示されるようにすると便利かな…。
まぁ、ぼちぼち考えよう。もうそろそろ丸一日遊んでるから研究に戻らないと…。
ごめんなさい
研究に戻るって言ったのに…pyObjVisで
埋め込むオプションを付けてみました。
あと、クラスとインスタンスの可視化にも着手してみたんだけど、
ツリー上であることを仮定して文字列で表示するアルゴリズムがリファクタリングするうえでジャマだ。つかGraphVisで日本語が使えないんだったらなぁ…。ツリーを仮定して文字列で表示するシンプルなバージョンと、GraphVisを使うバージョンを別のライブラリに分けようかな。それはそれで重複するコードが多い気もするけどなぁ。
そうか、ぶっちゃけグラフで見ることができる以上、僕に文字列でなんとか見やすくしようというモチベーションがわかないんだな。じゃぁ、今のバージョンを公開しておいて、今後は日本語文字列表示を削ったバージョンを開発していくとするか。あー、でもEXPAND_MODULEってオプションをつけることを今考えているんだけど、これに関しては文字列表示のほうが見やすいかもなぁ…。うーん。
まぁ、やっぱグラフ表示のほうに重点を起きたいな。
文献管理
ふぅ、書類書き終わった。
やっぱり文献を管理してくれるソフトがほしいなぁ。
自分の5つの論文を管理するだけで色々大変だからこれが今後どんどん増えると考えると今のうちになんとかしておくべきなんだよなぁ。
とかいうことを前に書類書いたときも考えて、何かプログラムを書いたはずなのにどこに行ったかわかんないし(ぉぃぉぃ)
うーん、むずかしいなぁ。何が難しいって、いろいろ(ぇ)
まぁ冗談はさておき、
「Volume VII」って書いてあるのを「Vol. 8」と表記するのはかまわないのかどうか、とか。これはまぁ同一視していいとしても、numberとvolumeは同一視しちゃいけないでしょ。その境目をどこに引くべきなのか、というのが難しい。
それから、BibTeXはInBookとInProceedingを区別しているけど、みんなって区別しているのかな。僕はいまこうやってデータを打ち込んでいて気づいたんだがSCI2004のProceedingってISBNが振ってあるんだよ。これってInProceedingじゃなくてInBookにすべきってことなの?そもそもこれ区別する必要があるのかなぁ…。
RECOMBのProceedingはProc. of RECOMB2004と書くべきか、それともタイトルに忠実に「Currents in Computational Molevular Biology」にすべきか。というのも、Proceedings of the ...ってタイトルの冊子は別にあって、それじゃない側に載っているんだよ…。ISBNが振ってあればタイトルに忠実にするんだけど、これはどうしたものか…BibTeXのbookletに相当するんだろうか…でもletは指小語尾だよなぁ。普通の本より大きなものにletをつけるのは違和感が…。
そして3つ目まで打ち込み終わったところでWSOM2003の原本がここにはないことに気がついた。というかどこにあるんだろう。先生が出張から帰ってきたら聞いてみよう。
nilは比較できるといい?
arai blogの同名記事にRubyのnilは数値と比較できないうんぬんの話が書かれている。
Rubyのnilって、Javaのnullとはまったくの別物なんじゃないかと思うんだけどどうなんだろう?
コメントを見ていると「あれ?nilはnullなの?」と言う気にもなるけど、
そんな設計になってるのかなぁ。
まぁ、Rubyのことは詳しく知らないのでPythonの話をしよう。
PythonのNoneはnullのような目的で使われるオブジェクトで
>>> None < 1
True
>>> None > 1
False
って感じに、「すべてのオブジェクトより小さいオブジェクト」になっています。
ああ、積読本の山から引っ張り出した「プログラミングRuby」によればnilはNilClassクラスの単一のインスタンスみたいですな。ってことはPythonとほぼ同じだと考えてかまわないかな。
となると、Rubyでnilと比較をしたときに例外が投げられるのは、単に「まつもとさんのポリシー」ってことになりますかな。
- ヌルオブジェクトはすべてのオブジェクトより小さい(Python流)
- ヌルオブジェクトと他のオブジェクトの比較は例外を投げる(Ruby流)
- ヌルオブジェクトと他のオブジェクトの比較は常にFalseが返る(arai流)
の3つを比べると、
個人的な好みでは「Ruby流〜Python流>arai流」になるかなぁ。
arai流は「a < b が falseで a > b も false だけど a == b ではない」とか「(a < b || a >= b) が false になる時がある」というのが数学的に気持ち悪い。
Ruby流は「すべてのオブジェクトが『比較可能』ではない」という仕様なので、例えば比較不可能なオブジェクトが混ざりこんだリストをソートしようとすると例外が起こるだろうね。Pythonは「すべてのオブジェクトが『比較可能』である」という仕様だから、どんなオブジェクトが入ったリストでもソートできる。
だからこんなトリッキーなこともできる。
>>> INFINITY="+∞"
>>> class NegInfinity:
def __repr__(self):
return "-∞"
>>> NEG_INFINITY=NegInfinity()
>>> list=[0.0, -1e+99, 1e+99, INFINITY, NEG_INFINITY]
>>> print list
[0.0, -9.9999999999999997e+098, 9.9999999999999997e+098, '+∞', -∞]
>>> list.sort()
>>> print list
[-∞, -9.9999999999999997e+098, 0.0, 9.9999999999999997e+098, '+∞']
このPythonの「すべてのオブジェクトが『比較可能』」という仕様は、比較可能かどうかがものによって違う仕様よりはシンプルで数学的に美しいんだけれども、美しさが必ずしもよいとは限らない。
人間はミスをする生き物だから「変なことをしても止まらないシステム」よりも「変なことをしたらすぐに止まって、変なことをしてしまったことにすぐ気づくシステム」のほうがよい場合もある。
Pythonの場合、関数の中でreturnするのを忘れるとNoneが返ってくるので、たまに意図しないところにNoneが入っていて、加算をしたりすると
TypeError: unsupported operand type(s) for +: 'float' and 'NoneType'
なんて怒られ方をする。
加算ではこう例外が投げられるけど比較では例外が投げられないわけなので、意図と違うオブジェクトが代入されていることに気づくのが遅れる可能性はある。
バグに気づくのがそれだけ後回しになるわけで、また発覚するポイントが実際の問題点からそれだけ離れたところになるわけで、
これはあんまりよろしくない。
だからRuby方式のほうが個人的には好み…と書こうとしたんだけど、よく考えたらRubyって確か最後に評価したものを返してくるから「意図しない実数値」が入っている可能性があるんだなぁ…。それだと演算可能性で例外が投げられることはないからシビアなバグに直結しかねない…うーん、どっちもどっちだなぁ。
ベクトル計算ライブラリ
さっきふと思ったんだけど、
Pythonのベクトル演算をCやJavaにくくりだして高速化しようとしても、ぶっちゃけ「3次元のベクトルが1万個ある。この中から点Pに一番近いものを選べ」なんてユースケースではいろんなオーバーヘッドのせいであんまり高速化できない気がする。
「一つのベクトルを一つのモノと見る」ってアプローチではなくて、「『たくさんのベクトルの集まり』を一つのモノと見る」というアプローチが必要なのかもしれないね。
つまり、「ループをライブラリにくくりだす」っていうアプローチ。
あー。というか、ループをライブラリ側にくくりだすってだけならRPyでRにベクトル計算をさせるという手があるか…。
プログラミングスキル判定問題
前に渡辺さんの日記にからんでいたときに(からんでたのかよ!)
裏でいろいろと「じゃぁどんな問題なら判定できるかなぁ」という話をしていて、そこで僕が提案したのが「ハノイの塔をforで解く(再起呼び出し禁止)」という問題だったのだけど…これは難しすぎて自分でやる気をなくしたので放置していました。
で、いま友達の日記を見ていてふとそれを思い出したので「ハノイの塔をwhileで解く(再起呼び出し禁止)」に緩めればだいぶ楽だなぁ…と。実装してみました。まぁ、元の問題もfor(int i=0; i < 2**HEIGHT-1; i++)を想定していたとはいえ、for(;!stack.isEmpty();)を明確に禁止していなかったので…(言い訳)
ちなみに、再起呼び出しバージョン
def hanoi(frm, to, spare, height):
if height==1:
print "%d->%d"%(frm, to)
else:
hanoi(frm, spare, to, height-1)
hanoi(frm, to, spare, 1)
hanoi(spare, to, frm, height-1)
Continue reading "プログラミングスキル判定問題"
一時間で
一時間で覚えるRuby
1時間で覚える?Python
読むのは24分だが書くのは5時間もかかってしまった、何やってんだ僕。全然やる必要性のないことを…。うーん…。でも、まぁ、ゲームしているよりはマシかな…。
素数を2進法で表示(副題:Pythonで画像を出力するには)
画像を作ってみたけど面白くなかった。ソースコードはExtendの中に。
タイトルとは無関係だけど、もうちょっと労力と時間をかけてPIL(Python Imaging Library)の簡単な説明くらいを書いたほうが世の為にはなるんだろうなぁ、とは思いつつ、ソースコードだけ貼って続きを書く気をなくしてしまう。これはBlogのメリットなのかなぁ、デメリットなのかなぁ。書く作業の敷居を下げて、こまごまとしたことはたくさん書くようになったけど、逆にS/N比は低下した。文章のクオリティはBlogの管轄外だといわれてしまえばそれまでだけども…
Continue reading "素数を2進法で表示(副題:Pythonで画像を出力するには)"
PyInlineでCのコードをPythonに埋め込む
http://pyinline.sourceforge.net/
まだ試してないのだけど、PyInlineを使えばホットスポットだけCで高速化する、なんてことがかなりえげつない方法で(ほめ言葉…?)可能になるようだ。
便利だとは思うけど、可読性が…。PyInlineを学ぶのに要する労力をCで拡張ライブラリを書く方法を学ぶのに回したほうがいいのではないかと思うが…。まぁ、選択肢がたくさんあるのはいいことなんだろう。
Pythonの構文木
parserライブラリを使えばPythonコードから構文木を作って観察することも出来るんだが…作って眺めてみて、これをいじるのはイヤだと思った。やたら汚いし、構文木はバージョン間で互換性が保証されないし。簡単に出来そうならPythonでインライン展開を出来るようにして可読性を保ったまま高速に実行させようと思ったんだけどね…。Psycoがサポートしてくれないかなぁ。(実はもうしてたりして)
de Casteljau's algorithm
実はさっきのエントリーで初めてまともにPythonImagingLibraryを使ったんだけど、面白かったのでついでにWikipediaに載ってたベジエ曲線描画のアルゴリズム「de Casteljau's algorithm」の擬似コードをPythonで実装してみたり。ついでだからWikipediaに載せてきたり。
de Casteljau's algorithm
ほとんど擬似コードと同じだね、Python。まぁ、Pythonが実行可能な擬似コードだってのはよく言われる話だ。(そしてPerlは実行可能な回線ノイズだとも。)
しまった、寝てないのに眠くなくなってきた…。
Pythonでフラクタル(ジュリア集合)
ジュリア集合の定義を調べるのにかかった時間のほうが実装にかかった時間より長い…。やっぱスクリプト言語って楽でいいな。
もっとはやくPILを勉強すればよかった。ものすごく遅いんじゃないかと不安だったけれども0.3秒くらいでした。でもこの2倍のサイズにすれば1.2秒だと考えるとリアルタイム性はないな。JAVAで仮に10倍早くなればまだ可能性はあるか…(何の可能性だ)
あー。こういうきれいなところは発散するまでに時間がかかるところだから計算時間も余計にかかるか…。0.7秒。いやなに、MATRIXの3番目のオープニングみたいなフラクタルの中に入っていく画像が作りたかっただけなんだけど。やっぱり各フレームBMPで吐き出しておいてAVIMakerでつなぐとするかな…。
import Image
import ImageDraw
SIZE=128
image = Image.new("L", (SIZE, SIZE))
d = ImageDraw.Draw(image)
c = 0.5 + 0.2j
for x in range(SIZE):
for y in range(SIZE):
re=(x*2.0/SIZE)-1.0
im=(y*2.0/SIZE)-1.0
z=re+im*1j
for i in range(128):
if abs(z) > 2.0: break
z = z * z + c
d.point((x,y),i*2)
image.save(r"c:\julia.png", "PNG")
どうでもいいことだけど、クォータニオンを使えば4次元空間上に(げふんげふん) 実際に動画作りに使うとしたらcの値とzの範囲を引数として与えられるようにすべきですな。
c=-0.78+i*0.002+0.23j(i<40), center=-0.5+0.2j, scale=1.0。この手の動画ってMPEGで圧縮するととんでもないことになりそうなので無圧縮AVI(2メガ弱)
25フレーム目から30フレーム目の間くらいのパラメータをゆっくり進みながらカメラが脇の黒い部分を通り抜けていくというのが映像としては面白いのかな。
しかし圧縮できないとなると…このサイズで40フレームで2メガだから…うーん、やる気が萎えた…。
干支計算スクリプト
>>> JIKKAN=["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
>>> JUUNISHI=["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
>>> def eto(seireki):
y = seireki-4
m10 = y % 10
m12 = y % 12
return JIKKAN[m10]+JUUNISHI[m12]
>>> eto(1924) # 甲子園の出来た年
'甲子'
超整理手帳に和暦西暦対応表を入れようかと思ってね。
ゲノムの可聴化
「アイネ クライネ ゲノムジーク」ってタイトルを見て思った。ゲノムを1塩基が8部音符くらいの縮尺で音楽にするとどう考えても「小さい音楽」にならないね。小さいバクテリアのゲノムよりも、ジャンクDNAにまみれた人間なんかの巨大なゲノムを使ったほうが面白そうなんだけど、この縮尺では現実的ではない。
というわけでゲノム→音楽マッピングの方法を先に決めるのではなく、好ましい縮尺から先に決めてみよう。
19MbpのヒトY染色体が数分に納まるくらいの縮尺が好ましいかな。
そうなると、10万塩基対で1秒くらいかな。それなら3分ちょい。10万ヘルツ…100KHzか、人間が聞こえる上限って20KHzだっけ…。
うーん、でもとりあえず聞いてみたい気分になった。
Pythonのwaveモジュールを参考に。
import wave
w=wave.open(r"c:\tmp.wav", "w")
w.setnchannels(1)
w.setsampwidth(1)
w.setframerate(10000)
for i in range(10000):
w.writeframes("asdfghjk")
w.close()
ほほう、ちゃんとwaveファイルが出来て蚊の鳴くような音が聞こえる。じゃぁこれでゲノムを可聴化してみよう。
サンプリングレート100000でY染色体をそのままつっこんだwav。バイナリエディタで見ると配列が見えます。(サイズが大きいのに別に面白くないので消しました)
サンプリングレート10000でY染色体70塩基中に含まれるAの個数をつっこんだwav。これラジオの音だって言われたら信じそう。
RPyをインストールした
SF.netから0.4.0をダウンロードしてインストールしようとパスを通したりしたんだけれども
error: Python was built with version 6 of Visual Studio, and extensions need to
be built with the same version of the compiler, but it isn't installed.
といわれてしょぼーん(´・ω・`)
0.3.6のWindows用バイナリ配布をダウンロードしたらマウスをカチカチするだけでインストールされた。うーん。まぁこれでいいか。
インストールは出来たのに「from rpy import *」をするとIDLEがrestartされてしまうと思ったら、インストールされているRが1.9.1なのにこのRPyは2.0.0用だった。うん、Rの新しいバージョンを入れることにしよう。…2.0.0と2.0.1と2.1.0があるなぁ。2.0.0を入れれば問題なく動くだろうけど、やっぱ最新版を入れてみたいなぁ。
うーむ。最新版を入れたら、plotで開いたRのWindowが固まってしまい、それを強制終了したらIDLEもrestartされた。やっぱり2.0.0にするしかなさそうだな。
うーん。ハングアップしたように見えたのは単に描画に時間がかかりすぎているだけなのだろうか。でもたいしたものを描画しているわけではないし、1回目の描画命令を実行して固まっているところへもう一回同じ描画命令を投げるとすぐに表示されたりもする。メッセージのハンドリングにバグがあるのかなぁ。
プログラミング演習
比較ゲノム学講座的プログラミング演習の目次を変えてみた。
とりあえずぼちぼちとadvancedの講義資料を作っていこう。うわー、すごいな、関数やクラスの説明はどこにもない(ぇ)
PythonでPCA(主成分分析)
作ったんで載せてみます。outputのところは自分の見たいものが何かによって違うだろうし、そもそも第一主成分軸だけが欲しいならソートしなくてもいいですね。その辺は読んで理解して自分で書き換えてください。ちなみにコメント込み87行で、実行時間のほとんどはsummationのところで消費されます(もちろんデータのサイズによって違うでしょうけど)
#
# PCA_TSV:
# Pricipal Component Analysis of Tab Separated Values
#
#
# settings
datafile="methano.fna.FI"
#
# load datafile
print "loading data"
data=[]
for line in file(datafile):
items=line.split()
data.append([float(x) for x in items])
N=len(data)
DIM=len(data[0])
#
# make covariance matrix
# init average list
ave=[0.0] * DIM
# init covar matrix
covar=[]
for i in range(DIM):
covar.append(
[0.0] * DIM
)
# summation
print "summating"
for d in data:
for i in range(DIM):
for j in range(i, DIM):
covar[i][j] += d[i] * d[j]
ave[i] += d[i]
# calc average
for i in range(DIM):
ave[i] /= N
# calc covariance
for i in range(DIM):
for j in range(i, DIM):
v = covar[i][j]/N - ave[i] * ave[j]
covar[i][j] = v
covar[j][i] = v
#
# diagonalise the covar matrix
print "diagonalising"
from numarray import array
import numarray.linear_algebra as la
(eigenval, eigenvec) = la.eigenvectors(array(covar))
#
# sort eigenvectors by eigenvalue
print "sorting"
def inv_cmp(x, y):
return cmp(y, x)
axis=zip(eigenval, eigenvec)
axis.sort(inv_cmp)
sumVar=sum(eigenval)
#
# output
fo=file("pca.txt", "w")
for i in range(10):
(v, vec) = axis[i]
print v/sumVar
fo.write(
"\t".join([str(x) for x in vec])
)
fo.write("\n")
fo.close()
1/fゆらぎ壁紙
「1/fゆらぎの壁紙を作ったことがあるけどちっとも癒されなかった」と言ったら見たいといわれたのでまた作ってみた。
#
# 1/f yuragi wall paper
#
#
# setting
WIDTH=1024
HEIGHT=100
MAX_PERIOD=1024
OFFSET = (200, 255, 200)
DCOLOR = (0, -50, 50)
#
# summate waves
from math import sin, pi
from random import uniform
values=[0.0] * WIDTH
for period in range(1, MAX_PERIOD):
phase = uniform(0, 2*pi)
w = period / pi / 2.0
intensity = 1.0 / period
for x in range(WIDTH):
values[x] += sin(x / w + phase) * intensity
#
# normalize values
upper = max(values)
lower = min(values)
colors=[]
for x in range(WIDTH):
v = (values[x] - lower) / (upper - lower)
color = [int(o + d * v) for (o, d) in zip(OFFSET, DCOLOR)]
colors.append(color)
#
# make image
import Image
import ImageDraw
image = Image.new("RGB", (WIDTH, HEIGHT))
d = ImageDraw.Draw(image)
for x in range(WIDTH):
for y in range(HEIGHT):
d.point((x,y), tuple(colors[x]))
image.save(r"c:\yuragi.png", "PNG")
PythonでHTTPステータスコード取得
>>> import urllib
>>> try:
urllib.URLopener().open("http://www.python.jp/doc")
except IOError, e:
print e
('http error', 301, 'Moved Permanently', <httplib.HTTPMessage instance at 0x02706300>)
リンク先が移転して301(Moved Permanently)を返しているときはリンクを張り替えるべきだけど、それを人手で調べるのは面倒なので、そういうことをやってくれるものを作ろうと思っています。いました。今さっき思い出したのでステータスコードの取り方を調べてみました。
ちなみに「openに成功した場合にcloseしなくていいのか?」という質問ですが、いいんです。一応確認してみましたが
def __del__(self):
self.close()
と、デコンストラクタで自分自身をクローズしています。今回の場合、openに成功したとしても変数に参照されないのでガベージコレクトされて、そのときにcloseされる、というわけです。
betterCopy Project
とりあえず、バックアップ支援プログラムに着手することにしました。色々構想は練っていたけれども、とりあえず今寮で寝ているタワーの中身をきれいにバックアップしてラボに運んでLinuxでも入れて有効活用しよう、という目的に向かって必要最小限だけ実装することにします。というわけでJavaでかっこいいGUIを作ろうかとも思っていたけどそれは保留にしてとりあえずPythonで。
>>> wd=r"c:\nishio\projects"
>>> printInfo(wd)
1.2GB matrix
97.2MB www
64.0MB EngAmbient
34.3MB meishi
26.1MB enumGraph
22.7MB GenomeV4Apache
(略)
>>> cd("matrix")
Now in c:\nishio\projects\matrix
>>> printInfo(wd)
437.8MB bmp_genome
435.1MB prosym.avi
292.3MB bmp
23.0MB back.avi
22.6MB matrix.avi
3.0MB zoomin.avi
(略)
現状はこんな感じであるディレクトリの中身をそのサブディレクトリも含めてサイズを集計して多い順でソートしてくれる、という昨日の実装が終わったところ。
これ僕の雑多なプロジェクトがつっこまれているProjectsフォルダの中身なんだけども、これを何も考えないでコピーすると2ギガかそこらあるのね。でも調べてみるとmatrixフォルダが半分以上を占めている。これは当たり前でこれはマトリックス風のムービーを作るプロジェクトのフォルダだからその過程で作った各フレームのBMPファイルがフォルダの中にあるわけですよ。そんなものはバックアップとらなくていい、と。そういうわけで次は「拡張子がbmpのものは省け」と指定できる機能を実装しよう…
できたできた。先ほどのprintInfoにfilterを指定できるようにした。
noBMP_noAVI=And(
ExcludeExt("bmp"),
ExcludeExt("avi"))
こんなフィルタを指定してやると上のような結果が下のような結果に変わる。
c:\nishio\projects\matrix: 1.2GB...
437.8MB 35.7% + bmp_genome
435.1MB 35.5% prosym.avi
292.3MB 23.8% + bmp
23.0MB 1.9% back.avi
22.6MB 1.8% matrix.avi
3.0MB 0.2% zoomin.avi
(略)
c:\nishio\projects\matrix: 1.6MB...
520KB 31.8% matrix_py.exe
424KB 25.9% matrix.exe
412KB 25.2% wavelike3.png
52KB 3.2% wavelike3.jpg
28KB 1.7% wavelike1.png
24KB 1.5% + .xvpics
12KB 0.7% mainpy.dcu
12KB 0.7% init.py
8KB 0.5% vector3.pyc
8KB 0.5% mainpy.~pas
8KB 0.5% mainpy.pas
(略)
何も考えずにバックアップを取っていたら1.2GB使っていたところを1.2MBに抑えることができました。で、新しい結果を眺めると…、ああ「.xvpics」はGIMPが勝手に生成するファイルだからバックアップはいらないな、*.pycもPythonが自動生成したバイナリだし、*.~pasはDelphiが作ったバックアップファイルだな。これらのファイルは他のプロジェクトでもバックアップ取らなくていいや。
Pythonでフォルダかどうか判定
やり方をGoogleで検索したけども見つけられなかったので書いてみました。
os.stat(path).st_modeでパーミッションなどの情報が得られます。8進数表示をしてみると手元のWinXPではフォルダの時に040777、ファイルの時に100666になりました。dwrxwrxwrxから勝手にフォルダなら1777でファイルなら0666かな、と思っていたのですけど、他にもいろんな情報が積んであるようです…。確信はもてないのですが100000の桁が0ならフォルダだということにしてしまうと
def isDir(path):
return (os.stat(path)[0] & 0100000) == 0
自信はないので「間違ってる!」と思った方はコメントしていただけると幸いです。
Pythonでファイルサイズの取得(と切り上げ)
ファイルの中身が1バイトしかなくても、ディスクは4096バイト占有されるって知ってますか〜?(もちろんファイルシステムや設定によって占有されるブロックのサイズは異なります)
というわけで、ディスク上での実際のサイズを知るためにはファイルサイズを取得した上で、4096の倍数になるように切り上げてやる必要があるわけです。
# 切り上げ
def ceil(i, unit):
return ((i + unit - 1) / unit) * unit
BLOCK_SIZE=4096
def getSize(file):
filesize=os.stat(file).st_size
realsize=ceil(filesize, BLOCK_SIZE)
return (filesize, realsize)
この切り上げの仕方はやねう企画はスーパープログラマ集団ではない!を見て知りました。
世の中にはいろんな価値観があるということを説明するのにちょうどいいので後輩に教えるときに使っています。
まともなコンパイラならこれくらい小さい関数ならinline宣言して置けばインライン展開してくれるはずなので、自分でインラインで書くより関数にくくりだして置くべきだ、というのが僕の価値観であると同時に、切り上げを行うことと副作用のないことさえ明確にわかるなら関数の実際の実装が魔法じみていてもかまわない、というのも僕の価値観だったりするわけです。
def ceil2(i, unit):
if i % unit == 0:
return i
else:
return (i / unit + 1) * unit
def ceil3(i, unit):
if i % unit:
return i / unit * unit + unit
else:
return i
def ceil4(i, unit):
import math
return int(math.ceil(float(i) / unit) * unit)
同じことをするのにも書き方はいくらでもあって、その背後にはそれを書いた人の価値観や文化、思想、哲学、経験、スキルが潜んでいるんですよね。宗教の押し付けや洗脳にならないようにプログラミングを教えるのは難しい。
Pythonでマウスの位置を移動
デュアルモニタしていると画面が広くなったぶんマウスを移動するのが面倒くさい。というわけで
import win32api
win32api.SetCursorPos((x, y))
もう「Pythonで」というよりWindowsAPIで、ですな。
PythonでXML-RPCを試してみた
XML-RPCってなんか名前がいかついのでちょっとビビっていたのだけど、やってみるとまったく難しくなかった。まずはGoogleで検索して
Python での XML-RPC の使い方を見つける。一つ上に上がるとXML-RPCについての説明もある。
Pythonでの使い方のページ前半はRedhat用の説明と書いてあったので無視して、とりあえずライブラリをダウンロード。setup.pyが入っていたのでとりあえずpython setup.py installしてみたらうまくインストールされたようなのでよしとしよう(WindowsXP)
最新のPythonなら最初から入ってるようだ。
サンプルを見ながら
>>> import xmlrpclib
>>> server = xmlrpclib.Server('http://xmlrpc-c.sourceforge.net/api/sample.php')
>>> server
<ServerProxy for xmlrpc-c.sourceforge.net/api/sample.php>
>>> result = server.sample.sumAndDifference(10,20)
>>> result
{'sum': 30, 'difference': -10}
XMLのことなんか何も気にしないでも使えますね。イントロスペクションも試す。
>>> server.sample.listMethods()
Traceback (most recent call last):
(略)
Fault:
>>> server.system.listMethods()
['sample.add', 'debug.authInfo', 'sample.sumAndDifference', 'system.listMethods', 'system.methodHelp', 'system.methodSignature']
>>> server.system.methodHelp('sample.add')
'Add two numbers'
>>> server.system.methodSignature('sample.add')
[['int', 'int', 'int']]
>>> server.system.methodSignature('sample.sumAndDifference')
[['struct', 'int', 'int']]
methodSignatureは先頭の1つが返り値の型なんだな。
Boxcarringについても勉強。
多くのファンクションコールをする XML-RPC クライアントを書い ているなら、インターネットのバックボーンのレーテンシー (待ち時間) が短いおかげで、応答時間がかなり速いことを気づくかもしれません。い くつかのサーバは次の機能を使うことで複数の要求を一括処理 (batching) できます。
うわー。すごい皮肉だ(笑) もちろんインターネットのレイテンシはかなり大きいので、例えば1クリックのたびに100回XMLをやり取りするようなプログラムを書くとかなり待たされることになるんだよね。だから依存関係のない要求は一括処理したいわけなんだ。
点を美しく配置するには
今日は朝から
「正方形の中に美しく指定された個数の点を打つ方法」について考えていた。
比戸君と話していて、
とりあえず1辺の頂点数が奇数個であるような正方形格子状に限定して力学的に反発する点を位置エネルギーが最小になるように配置する、という方法である程度配置してみて、その結果から規則性を抽出して高速に美しく配置するアルゴリズムを作ろうと思い立ったのがちょうど100分前。
で、結果は出たんだけど
…3とか7とか10とか11とか14とか…美しくない…。15なんか、なにそれ、イトマキエイ?
>>> draw()
1
*
0.0593424583292
2
- - *
- - -
* - -
0.0770097875568
3
- - *
- - -
* - *
0.0756780540544
4
* - *
- - -
* - *
0.0737931776245
5
* - *
- * -
* - *
0.0751659777989
6
* * *
- - -
* * *
0.0781143972209
7
* * *
- - *
* * *
0.0798704863328
8
* * *
* - *
* * *
0.0825395406399
9
* * *
* * *
* * *
0.07647033352
10
* - * - *
- - - * -
* - * - *
- - - - -
* - * - *
9.37996197841
11
* - * - *
- - - * -
* - - - *
- * - * -
* - * - *
19.8308106198
12
* - * - *
- * - * -
* - - - *
- * - * -
* - * - *
31.0727969616
13
* - * - *
- * - * -
* - * - *
- * - * -
* - * - *
47.1632179509
14
* - * * *
- * - - *
* - - * -
- * - - *
* - * * *
56.0500784318
15
* * - * *
* - * - *
- * - - *
* - - * -
* * * - *
52.5275826956
16
* * - * *
* - * - *
- * - * -
* - * - *
* * - * *
41.2388608049
17
* * * * *
* - - - *
* - * - *
* - - - *
* * * * *
28.7111300459
18
* * * * *
* - - - *
* - * - *
* - * - *
* * * * *
16.9885030081
19
* * * * *
* - * - *
* - - * *
* - * - *
* * * * *
8.46026967115
20
* * * * *
* - * - *
* * - * *
* - * - *
* * * * *
3.58321518517
21
* * * * *
* * - * *
* - * - *
* * - * *
* * * * *
1.30305248293
22
* * * * *
* * - * *
* - * - *
* * * * *
* * * * *
0.52957596566
23
* * * * *
* * * * *
* - * - *
* * * * *
* * * * *
0.299685015833
24
* * * * *
* * * * *
* * - * *
* * * * *
* * * * *
0.203836800487
しょんぼりですな。どうしようか。
正方格子上に配置するのをあきらめれば同心円状に配置する方法が考えられるが…。うーん。
おまけのえぐいソースコード。まぁ、高々48行だけどもね。体に悪い電波が出てそうなコードだ。
class RecPlace:
def __init__(self, num, width):
self.end = width * width
self.width = width
self.minPower = num * num
self.dig([], 0, 0.0, num - 1)
def dig(self, curList, start, curPower, level):
for i in range(start, self.end - level):
x = i % self.width
y = i / self.width
incPower = 0.0
for (px, py) in curList:
incPower += 1.0 / ((px - x) ** 2 + (py - y) ** 2)
nextPower = curPower + incPower
nextList = curList + [(x, y)]
if nextPower > self.minPower:
continue
if level == 0:
self.minPower = nextPower
self.minList = nextList
continue
self.dig(nextList, i + 1, nextPower, level - 1)
def draw():
from math import sqrt, ceil
from time import clock
for n in range(1,25):
start = clock()
print n
# minimal covering square
root = -1
while True:
root += 2
if n <= root * root:
break
r = RecPlace(n, root)
for i in range(root):
for j in range(root):
if (i,j) in r.minList:
print "*",
else:
print "-",
print
print clock() - start
print
Pythonで変化しない計算結果をキャッシュ
ちょっとトリッキーな方法。
class Hoge:
def calcSomething(self):
pass # すごく重たい計算のつもり(resultに結果が入ったつもり)
self.calcSomething = lambda :result # キャッシュ
return result
キャッシュされてなかった関数に1行書き足すだけでキャッシュされるようになります。
でもlambdaを使うのは避けたほうがいいのかなぁ。将来のことを考えると。
まぁこれは引数を取らないからこういう手が使えるわけで、引数を取るようなものならまぁハッシュを使うのが妥当かと思います。
PythonでTOEIC用アラーム(45秒に1回)
調べてみたらTOEICのReadingSectionって100問で75分でした。つまり1問45分。練習問題を解くのに、45秒でわからない問題をずるずると90秒とか考えてしまう癖をつけるとよくないだろうから、45秒ごとに45秒たったことを知らせてくれるプログラムを作ってみました。
FREQ1 = 256
FREQ2 = 512
DURATION = 100
import winsound, sched, time, thread
SCHED = sched.scheduler(time.time, time.sleep)
def shortBeep(when):
SCHED.enter(when, 1, winsound.Beep, (FREQ1, DURATION))
def longBeep(when):
SCHED.enter(when, 1, winsound.Beep, (FREQ2, DURATION * 10))
def plan4sec(): # 4 sec timer for a test
for i in range(1,4):
shortBeep(i)
longBeep(4)
thread.start_new_thread(SCHED.run, ())
def planToeic(numQuestion = 20, secPerQ = 45):
for i in range(0, numQuestion * secPerQ, secPerQ):
shortBeep(i)
longBeep(numQuestion * secPerQ)
thread.start_new_thread(SCHED.run, ())
plan4secを呼ぶと、時報のような「ピ、ピ、ピ、ポーン」という音が鳴ります。で、planToeicを引数なしで呼ぶと20問15分コース。問題数や1問にかける時間を変えたければ引数で指定できます。
さてと。ツールは作ったので後は自分が頑張る番…。
45秒で問題を解いて45秒で答えあわせという方針で行けるかな〜?
Pythonでsubprocess
この前作った手軽に4個ずつスレッドに入れてくれるライブラリは、実際にラボのクラスタマシンで動かしてみると各CPUの占有率が25%程度になってしまい、合計では結局100%前後になる現象が確認されました。で、調べてみたら悲しいことが判明。1つのPythonインタプリタはGCがスレッドセーフでない(スレッドセーフにするとめちゃ遅くなる)関係で実質的にスレッドが同時には1つしか動かないらしいです。しょんぼり。
そういうわけでこの前作ったライブラリと同じくらい手軽にループをサブプロセスに刻むライブラリをTA(ただ働き)の空き時間に作ってみました。たとえば下のような重たい処理の関数があったとします(RandomGraphStrictの実装は長くて重たいので省略)
def calc(prob):
result = ""
for i in range(100):
g = RandomGraphStrict(100, prob)
result += g.batchCalc()
fo = open("randomGraphStrict_prob=%s.txt"%(prob), "a")
fo.write(result)
fo.close()
この関数をいろいろテストした上で、いざいろんなパラメータについて試そうと思ったら下の6行を書き足すだけ。
import breakIntoProcesses
breakIntoProcesses.do(
"randomGraph.py", calc,
[0.05, 0.15, 0.25, 0.35, 0.45]
)
スクリプトの本体は下のような感じ。余計なものをロードして無駄なオーバーヘッドにならないようにインポートもクラス宣言もifの中という少し気持ち悪いコードだけども、前回のライブラリ同様一度に起動するプロセスを4つまでに制限する機能付き。
def do(script, todo, params):
from sys import argv
if len(argv) == 1:
from pickle import dumps
from subprocess import call
from threading import Thread, Semaphore
COMMAND = "python"
NUM_CPU = 4
class SubprocessPerCPU(Thread):
sem = Semaphore(NUM_CPU)
def __init__(self, args):
Thread.__init__(self)
self.args = args
def run(self):
self.sem.acquire()
call(self.args)
self.sem.release()
for param in params:
if not(isinstance(param, tuple)):
param = param,
sparam = dumps(param)
SubprocessPerCPU([COMMAND, script, sparam]).start()
else:
from pickle import loads
param = loads(argv[1])
apply(todo, param)
実際にこれを使ってみると、4つのCPUがいっぱいまで使われてめでたしめでたし。でも結果のファイル出力がかち合う可能性は回避できてないなぁ…。でもそんなことを行ったら読み込みともかち合っちゃいけないし、計算内容が今回みたいにディスクから読み込まずにたくさん書くようなものなのか、それともゲノム解析のようにたくさん読み込んで少しだけ書き出すようなものなのか、それによって違いが出てくるから難しいか…。
Gimp-Python
画像処理ソフトGimpのプラグインをPythonで作るライブラリ。でもGimpのScript-FuってSchemeで、十分高級だから別にPythonでできるようになったことにそれほど大きなメリットがあるとは言いがたい…前置構文が嫌いな人にはいいかも。
GIMPユーザーズマニュアルに懇切丁寧にSchemeのことから説明が書かれている→マイクテリーのScript-Fu黒帯道場。なんで黒帯道場なのかと思ったらKang-fuから名前を取ってるのか、Script-fuって。
というか、使う言語が何なのかということよりも、どういうAPIが公開されているのかということのほうが僕にとっては重要なんだけど、そういうのの一覧はどこにあるんだろう…。やりたいことに近いことをやっているScript-fuを読めってことでしょうか。
XML-RPCでPython→Java→Python
「Java での XML-RPC の使い方」
を参考にしてJavaでサーバを作る。
とりあえず
Apache XML-RPC
のをダウンロードしてxmlrpc-2.0.jarをビルドパスに追加する。
参考文献のコードはserver.addHandlerの次の行にserver.start()が抜けているのでサーバが稼動しないので要注意。
また、サーバが稼動してもリクエストを投げるとエラーが表示されるので何かと思ったら、クラスが見つからない系エラー。
Jakarta Commons Codecのcommons-codec-1.3.jarをビルドパスに入れて直した。
参考文献の独立型サーバを走らせておいて、
以下の3行のコードを実行すると一番下の行の出力が得られる。
import xmlrpclib
server = xmlrpclib.Server('http://localhost:8080/RPC2')
print server.sample.sumAndDifference (10, 20)
{'sum': 30, 'difference': -10}
想像以上に簡単ですね。
XML-RPCを使ってPythonとJavaの間のやり取りをする一番のメリットは、多言語へも手を広げやすい点でしょうか。
次がPython側とJava側が別のマシンで動くことが可能な点で、
逆にデメリットはPython/Javaに特化していないプロトコルだから特化しているJythonに比べれば変換周りが面倒な点かな。
すべての素因数が偶数個
結城さんの日記を読んで、数学的に考えるよりも先にコードを書いてしまう僕はやっぱり何かに毒されているんじゃないかと思う今日この頃。
# -*- coding: cp932 -*-
#
# 1..n-1の整数の積のすべての素因数が偶数個ずつあるnを出力
#
primes = []
sumPrimes = {}
for n in range(2,10000):
# n以下の素数を求める
for i in range(2, n):
if n % i == 0:
break
else:
primes.append(n)
sumPrimes[n] = 0
# nを素因数分解
m = n
while m != 1:
for p in primes:
while m % p == 0:
m /= p
sumPrimes[p] += 1
# 条件を満たすものを出力
for p in sumPrimes:
if sumPrimes[p] % 2 != 0:
break
else:
print n, sumPrimes
10000までやってみて存在しないので、そこで初めて「じゃぁ証明しようか」となるわけだが、脳の数学野がしばらく使わないうちに弱ってしまっていることに気づいたので出直してきます。