« 2006年06月 | メイン | 2006年08月 »

2006年07月30日

日記

実家の鍵を持って帰るのを忘れたので割と動きづらい。

部屋はもうものすごい変わりようで、工事中のため廊下は土足だったりという状況。 そんなわけでPHS接続。

ゲド戦記4巻読了。劇場版のCMに出てくる女の子は4巻の主人公のテルーなのかなぁ。でもあんな大きな声ではっきり物を言う子じゃないんだけどな。5巻あたりで成長してはっきり物を言うようになるのかな。そして、3巻までは「子供に読ませたい本」だったけども、4巻は小学生時代の僕では理解できないのではないかと…力を手にして上り詰めた男が力を失った後の苦悩とか、熟年の恋とか、虐待を受けた上に火の中に捨てられて顔にケロイドのできた女の子とか、ちょっと小学生には重たすぎるような。小学生の時にあえて重たいのを読んでおいて、成長してから改めて読んで再発見するのがいいのかもしれないけど。

Rubyでオブジェクトのメソッド一覧を取得する方法を覚えたので 勉強が格段に進みやすくなりました。 やっぱリフレクションは重要ですね。 プログラミング初心者にプログラミングを教える際に 最初に教えるべきことはリフレクションなのではないでしょうか、 と煽ってみる(誰を)

ハッシュとかをto_sしてもべったり張り付いた見にくい文字列を返すので (なんでそんな文字列を返したいのか謎) 見やすい文字列を返すメソッドも絶対あるはずだと思ったのでした。 そしてそれはirbとかで評価したオブジェクトを表示するのに使われているはずで、その為にすべてのオブジェクトがそのメソッドを持っているはずだ、 と思ったのでメソッドの少なそうなnilのメソッド一覧を見ていたのでした。 目的の物はinspectですね。

どうしてRubyには同じ意味で違う書き方の物がいっぱいあるんだろう。 procとlambdaとか。実は微妙に違う意味なんだろうか。


__ 「ICTスクール2006」の実施及び参加高校生の募集について-文部科学省。そんなこんなで吹田にいます。

prototype.jsについてきたJavaScriptコンソールを複数行打ち込めるように改造してみました。

Avid Free DV

Inkscape. Draw Freely。なんかスクリーンショットにフラクタルなものがあるのでスクリプティングができるのかと思ったら

For file input/output, special features, etc. Inkscape is able to tie into external programs. Create new .inx files to hook these up for use in Inkscape. Also, if you're comfortable scripting in Perl, Python, etc. have a shot at improving the extensions, too!

だって!

2006年07月29日

日記

Rubyでは1 / 0.0 が Infinityというものになるみたい。1 / 0.0 * 0.0 は NaNになりました。Infinity - InfinityもNaNになるみたい。つじつまはあってそうですね。

DELLノートまた炎上 - Engadget Japanese。また燃えたのか…。何が原因なのかはっきりしないと怖い。とりあえずノートパソコンで重い計算を走らせたまま寝るのはやめた方がいいのだろうか?

高校生をインスパイアするためにいくつか本を持っていって「自由にお読みください」と置いておくことにしているのだけど、今回は東京からだから重い本を持って行くのは辛いなぁ。OS自作入門とか…。まぁ、興味のある人は本屋で見ることができるだろうから、本屋で見ることのできない物を主体にするか…。プロシーディングとか。日本顔学会誌、感性的ヒューマンインターフェース公開シンポ、第46回プログラミングシンポ(マンガの載っている論文誌)、ことば工学研究会、別冊数理科学 生命を作る、ComputarToday 神経情報処理最前線、あと自分の論文別刷り。うーん、アカデミックに偏りすぎているけど、OS自作入門は1冊でこれ全部より重いし…ふつうのHaskellを持って行っても高校生にはうけなさそうだしなぁ。あ、人工知能学会のボードゲーム「研究する人生」は受けそうだ。でもラボに置いて来ちゃった…。

もう14時だ。あるとよさそうな物を考え続けてないで、大阪行きの新幹線に乗るべきだ。完璧な準備は不可能だ。 GO!

Just Another Python Hacker, その2

>>> print (lambda a,t,g,c:''.join([chr(x)for x in[g-t-c*t&a,a&a*-a/g,a-c&a,g/t+a
-c&a,t*g&t,-a*a&a-t,-g-a%g*t&a,a+a*a*g&a,g/t+a-c&a,a&-c-c,g/c^g+c&g-c,a^a&c-a,t*
g&t,g&t-g-g,t+a+a+a+t&a,g/t+a-c&a,a&-c-c,a+a*a*g&a,-g-a%g*t&a,t*g&t,g+g%-c&a,g-a
+g&a,a^g*a+c&a,a&c-a-t%c-g,g/c^g+c&g-c,a^a&c-a,g%c*t-c&t]]))(*[ord(c)for c in un
icode('西尾泰和','sjis')])
Just Another Python Hacker,

自分専用JAPH。デフォルトエンコーディングの設定をきちんとやればエンコーディング指定の'sjis'はいらなくなると思います。ちなみにバイオに詳しくない人のために説明すると、ATGCは人間の遺伝情報を構成する4種類の部品の頭文字です。

ソースコードは、自分の得たい物が得られてしまうと他の人のために読みやすくしたりバグを取ったりするモチベーションがなくなるのでうまく動くかどうか知りませんが、一応公開しておきます。フォーマット文字列を使わないで西尾泰和の日記(2006-02-02)と同じ方法を使えばもっと短く書けたかもしれませんが…まぁいいや。


__ 追記。大文字の方がいいかも。

>>> print (lambda A,T,G,C:''.join([chr(N)for N in[G-T-C*T&A,A&A*-A/G,A-C&A,G/T+A
-C&A,T*G&T,-A*A&A-T,-G-A%G*T&A,A+A*A*G&A,G/T+A-C&A,A&-C-C,G/C^G+C&G-C,A^A&C-A,T*
G&T,G&T-G-G,T+A+A+A+T&A,G/T+A-C&A,A&-C-C,A+A*A*G&A,-G-A%G*T&A,T*G&T,G+G%-C&A,G-A
+G&A,A^G*A+C&A,A&C-A-T%C-G,G/C^G+C&G-C,A^A&C-A,G%C*T-C&T]]))(*[ord(N)for N in
unicode('西尾泰和','sjis')])
# -*- coding: cp932 -*-
#
# Just Another Python Hacker,
#
queryStr = "Just Another Python Hacker,"
query = [ord(c) for c in queryStr]

targetStr = "西尾泰和"
seeds = [ord(c) for c in unicode(targetStr, "sjis")]
print seeds

needs = []
for q in query:
    if not(q  in needs):
        needs.append(q)


caches = [{}]
numOp = {}
for i in range(4):
    caches[0][seeds[i]] = str(seeds[i])
    numOp[seeds[i]] = 0

def applyOpBuilder(c):
    def applyOp(p):
        return "%%s%s%%s" % c % p
    return applyOp

def applyOpBuilderInvert(c):
    def applyOp((x, y)):
        return "%%s%s%%s" % c % (y, x)
    return applyOp

operators = [applyOpBuilder(c) for c in "+-*/&|^"]
operators.extend([applyOpBuilderInvert(c) for c in "-/"])
operators.extend([applyOpBuilder(s) for s in ("%%",)])
operators.extend([applyOpBuilderInvert(s) for s in ("%%",)])

def evalAndCache(eq):
    try:
        v = eval(eq)
        if numOp.has_key(v):
            return
        if v < -50000 or 50000 < v:
            return
        numOp[v] = level
        eqs[v] = eq
        if v in needs:
            needs.remove(v)
    except Exception, e:
        print eq, e

try:
    for level in range(1, 100):
        print level
        eqs = {}
        for eq in caches[level - 1].values():
            evalAndCache("-%s" % eq)

        for i in range(level):
            j = level - i - 1
            if j < i: break
            for a in caches[i].values():
                for b in caches[j].values():
                    for f in operators:
                        eq = f((a, b))
                        evalAndCache(eq)
                        if needs == []:
                            caches.append(eqs) 
                            raise "Finished!!"



        caches.append(eqs)
except:
    data = "''.join([chr(x) for x in [%s]])" % ",".join(
        [caches[numOp[q]][q] for q in query])
    for i in range(4):
        data = data.replace(str(seeds[i]), "atgc"[i])
    print "print (lambda a,t,g,c:%s)(*unicode(targetStr, 'sjis'))" % data

2006年07月28日

プログラミング教育に関する考察

やろうと思いついけば1分で出来ることでも、やろうと思うまでは勝手には出来上がらない。作る技術も大事だけど、作ろうと思うことのほうがもっと大事。

大学や高校でかなりの人数にプログラミングを教えているはずなのに、プログラムを書ける人がこんなに少ないのは、「作ろうという思い」不在のまま「作る技術」だけを教えるからなんだ。僕のプログラミング演習ではそこんとこを何とかしたい。でも、モチベーションってのは教えたり与えたりするもんではないからなぁ。難しい。

2004/06/01 01:25:40の僕はこんなことを思っていたようです。今の僕なら「「作ろうという思い」不在のまま「作る技術」だけを教えるからではないだろうか。」と書くかもしれません。

渡辺さんの日記の「プログラムをゼロから教えるには、どんな形式で何コマかけてどこまで教えるべきだろうか。」という文章を読んでからいろいろなことを考えていますが、あまりまとまっていません。

もちろん、「作りたい物を作ることのできる」プログラマを育てるのなら、時間はたくさんあった方がいいのですが、現実的にはそんなにたくさんの時間を割くことができません。教える教師も、それなりに高いスキルを持った人間が一貫して教えるのが好ましいですが、結局のところプログラミングの専門家でも教育の専門家でもない、研究の専門家が片手間に教えることになる場合が多いかと思います。一貫して教える人を用意できなくて、複数人で持ち回りになったりするケースもよくあることです。

そして、やはりみんな「プログラミングは授業なんかで説明したって書けるようにならない、自分で手を動かして実装しないと」と思っているのでしょう、課題がたくさん出るわけです。 プログラミングの課題は、できる人にとっては軽い課題でも、できない人にとっては100倍もの負担となってのしかかります。半ば必然的に、「できる人」の書いたソースコードが出回り、できない人がそれを読解して改造して提出するというケースが出てきます。

「できる人」のソースコードや説明が、教師の作った講義資料よりもよいものなのであればそれは歓迎してもいいことなのかも知れませんが、そうとは限りません。学生たちは「ちょっとできる学生」が書いた「あまりよくないわかりにくいコード」を、それが課題の回答だからという理由で一生懸命読むかもしれないわけですよね。たとえそのコードに変数名の綴り間違いがあろうが、使われていない関数があろうが。

「コードを書いて、コンパイルエラーが取れて、実行したら期待した結果が出た」というのはゴールではないですよね。でも、現状の課題は「どんなに汚くても、人からのもらい物で中身を理解していなくても構わないから、とりあえず動く物を作る」という課題ではないでしょうか?そんな課題ではどんなにこなしてもプログラマは育たないのではないでしょうか。 僕自身は、大人数を相手に教えたことはないので、そういうシチュエーションでは実現不可能なことなのかも知れませんが、「とりあえず動くコード」を「わかりやすいコード」や「より高速に動くコード」に変える作業が抜けているように思います。生徒が自分で考えて作った「もつれたスパゲッティ」を、解きほぐして整理し、わかりやすくすることが必要なのではないでしょうか。

可能ならば、課題の提出が早い人にインセンティブを与えて「できる人」のコードを締め切り前に入手し、それを添削した上で無記名で公開してしまうというのがいいかもしれませんね。誰がその「添削」という労力を払うのかが難しい問題ですが。考えれば考えるほど、プログラミングの授業を1対多でやるのは難しいような気がしてきます。1対3くらいならまだなんとかなるかも知れませんが…。ううむ、そうか、僕が今まで教えてきたのは、全部最終的には1対1で目の前でコーディングしたり、できあがりのソースをメールで送らせてがりごり改良して送り返したりしているなぁ…。1対多には応用できないかも…。

思い出すことのできるメモに関する考察

過去の日記を読んでいて、今でも重要だと思える内容があったので転載してみました。2004/06/19 10:17:05。

以前どこかの大学の講演がストリーミングで視聴できるようになってるのをBGMにしてたな。と思い出して探す探す。 http://www.stanford.edu/class/ee380/

人間の記憶力は当てにならないからこそ、日記などの形で記録をとることと、 それを検索できるようにすることは重要なわけですがね。 いい方法ないもんですかね。 横着プログラミングを参考にしつつ考える。

僕は2001/4/29 12:3:35から2003/8/13 16:17:35までの間に2630個、3MB弱のメモを書いているのだけど、 現在の技術でこれを全文検索するのはちっとも難しくない。 今後も僕が書くメモは増え続けるだろうが、 メモの量の増加よりコンピューターの性能の向上のほうが早いだろうから、 今後も検索が容易であることは変わらないだろう。

一つ目の問題点は、「探す」ことは出来ても「思い出す」ことが出来ないことだ。 文字の発明によって、記憶の外部化が可能になり、 さらにその電子化によってその外部記憶の中から「探す」ことも容易になった。 しかし、「ふと思い出す」ということは出来ない。 このストリーミング放送にしても、今「以前、どこかの大学の講演をストリーミングで聴いていた」 という内部記憶を「ふと思い出した」からこそ外部記憶からそのURLを探し出すことが出来たのだ。 4月の頭から「英語力を鍛えなきゃ」と思っていたにもかかわらず、 「思い出す」のに80日もかかったことになる。

もう一つの問題点は、このメモの低水準さだ。 人間の脳の中のアイデアは、イメージが連想でつながりあったシーケンシャルでない形であって、 それを声という1次元的なデバイスに出力するために、 シーケンシャルな文章という形にコンパイルする必要性があったわけだ。 しかし、文字を使えばより高水準な表現手法が可能であって、その一つに 人生に奇跡を起こすノート術―マインド・マップ放射思考 のような脳内の連想を書き出す方法があるわけだ。 メモも、このような、より高水準な形で書き、高水準な形で検索が出来るようになって欲しいのだけど、 残念なことに電子的に高級なメモを書いたり検索したりする手法はまだまだ発展途上なんだよね。

フロー状態で文章を書くときって、 次から次から思いつく内容をそのまま文章の形で出力していくわけだが、 これってのは本来放射状の「マインドマップ」をシーケンシャルにたどっているものなわけなんだよね。 過去の日記を見れば、似たアイデアをいろんな文章で書いているんだが、 これがシーケンシャルなせいで容易にマージできない。 そこんとこなんとかならないものか。

とかとか思ったりもするんだけどまとまらないなぁ。 とりあえず、古いサーバーではNamazuを入れて全文検索できるようになっていた日記だけど、 今のサーバで書いてあるのは検索できないので後々不便に違いない。 そのうちに何とかしないと。 適切な形でエクスポートするのが一番手間が少ないだろうなぁ。むー。

高水準言語でメモを取る話に関しては、 どうせみんな読まないし(ぇ) 個人用のメモとして適当に実装してみるのも悪くないような気もする。

マインドマップをマインドマップの形のままやりとりしたり保管したり検索したりできるようになると、新しい世界が開けるのではないかと思います。

日記

PythonでWikiを作りかけたけども、やっぱり面倒だからPukiwikiを使おうかと思います。 reStructuredTextを使うとツリーとして扱うのも簡単だけども、別にツリーとして扱わないといけないほど複雑なことをするわけでもないですし。

大まかに説明すると「言語XでDxと書くことでできる処理は言語Yではどう書くのだ?」という質問に答えを出せるようなサービスを作るためには、言語Xで書かれたDxというコード片と言語Yで書かれたDyというコード片の対応付けが必要です。この対応付けは自動的に行うことが困難だと思われるので、何らかの形で「人がそれを入力することのできるシステム」が必要です。

あと、おそらくコード片の規模は数文字という訳にはいかないと思います。異なる言語のコードはそう簡単に対応づけられません。たとえばオブジェクトを文字列化するPythonのコードはstr(o)ですが、これはオブジェクトoが持っているメソッド__str__の呼び出しと同じなのでo.__str__()と書くこともできます。またこれに「オブジェクトの文字列化」という意味で対応するJavaのコードはo.toString()ですけど、「整数を文字列化」という意味で対応するのはString.valueOf(o)ですよね。これはJavaがオブジェクトとオブジェクトでないものの両方を持っているからなのですが、こういう個々の言語の仕様は知らなくても目的の物にたどり着ける設計が好ましいです。 そう考えると「いくつかの短めのコード片+簡単な説明」くらいの規模を単位にするのがいいと思います。

Wikiでそういうコード片の対応付けを収集しておいて、たとえば「Pythonの無名関数lambdaみたいなのをRubyで書くにはどうするんだ?」と思ったら、Pythonに関する記述の中からlambdaを検索して、対応するRubyの項目を読む、と。Pythonコンテキストに限定して検索することさえできるようにすればこういうことができるはずですし、コンテキストの限定も簡単に考えれば単にその部分だけ切り出して置いてその中から検索すればいいだけなので難しくありません。


__ とりあえずPythonでフラクタル(ジュリア集合) @ NISHIO HIROKAZU # Archived COREBlogとかで画像がリンク切れになっていて台無しだったのをなおしました。古いサーバのcoreblog/imagesにあったファイルを全部新しいサーバにアップし直し。あと古い日記の中からピックアップをすると「できたできた」系の「中身を表現していないタイトル」に怒りすら感じます(ぇ)

古い記事はwgetして新しいサーバにアップするだけでも構わないけども、修正の楽さなどを考えるとピックアップした物だけこのBlogに貼るのがいいのかも知れない。Zopeからエスクポートしたzexpファイルと、この前後輩に送ってもらったExtentionの中身のzipファイルと、ついでにwgetでHTMLにした物を作ってどこかにきちんとバックアップしておけばいいはず。

いちおう、プログラミング言語シソーラスの為のWikiを作ったけど、すぐ公開するか、ある程度中身が溜まってから公開するか悩みどころ。中身が溜まってから公開することにしたんだけども、どれくらい溜まったら公開するかも悩みどころ。Rubycoの日記を全部読み終わったら公開するかな。


__ 帰りの電車で思いついて変な物を作ってしまいました。Just Another Python Hacker, その2


__ 豚皿の中くらいのを買って帰ったらご飯が一合食べられてしまった。今度から小さいのにしようっと。

2006年07月27日

PythonとRubyでパスカルの三角形ワンライナー

rubyco(るびこ)の日記 - 呼び出し側のアスタリスクを読んで、「あ、そうか、それを使えば頭から二つずつ取ることができるか」とGame Scripting Memo - 続・パスカルの三角形のことを思い出しました。

>>> def get2(f, a, b, *rest):
	result = [f(a, b)]
	if rest:
		result += get2(f, *rest)
	return  result

>>> from operator import add
>>> def dup(aList):
	return reduce(add, [[v, v] for v in aList])

>>> dup([1,2,3])
[1, 1, 2, 2, 3, 3]
>>> def sandwich(bread, meat):
	return [bread] + meat + [bread]

>>> sandwich(0, dup([1, 2, 1]))
[0, 1, 1, 2, 2, 1, 1, 0]

>>> get2(add, *sandwich(0, dup([1, 2, 1])))
[1, 3, 3, 1]

とりあえずワンライナーにするために手を加えて…

>>> def get2(f, a, b, *rest):
	return rest and [f(a, b)] + get2apply(f, *rest) or [f(a, b)]

>>> def next(xs):
	return get2(add, *sandwich(0, dup(xs)))

>>> def next(xs):
	return get2(add, *sandwich(0, reduce(add, [[v, v] for v in xs])))

>>> def next(xs):
	return get2(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0])

>>> next([1])
[1, 1]
>>> next(_)
[1, 2, 1]
>>> next(_)
[1, 3, 3, 1]
>>> next(_)
[1, 4, 6, 4, 1]
>>> def next(xs):
	g = lambda f, a, b, *rest: rest and [f(a, b)] + g(f, *rest) or [f(a, b)]
	return g(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0])

>>> def next(xs): g = lambda f, a, b, *rest: rest and [f(a, b)] + g(f, *rest) or [f(a, b)]; return
g(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0])

>>> next([1])
[1, 1]

いちおうワンライナーになりました。

>>> lambda xs: (lambda g: (lambda *args: g(g, *args)))(lambda g, f, a, b, *rest: rest and [f(a, b)] +
 g(g, f, *rest) or [f(a, b)])(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0])
<function <lambda> at 0x0146BC70>
>>> _([1, 2, 1])
[1, 3, 3, 1]

これで文を使わない1つの式になりました。


__ Rubyは詳しくないので…ええっと、Proc.new{|x| x + 1}で無名関数のようなものができて、callでそれを呼べるんですかね。あ、 proc {...} で Proc.new{...} と同じだそうです。


$g = proc {|a, b, *rest|
	if rest.size == 1
		[a + b, rest[0]]
	else
		[a + b] + $g.call(*rest)
	end
}


(0..9).inject([1]){|xs, item|
	proc{|x| p x; x}.call(
		$g.call(0, *xs.map{|v| [v, v]}.flatten)
	)
}

三角形の頭が表示されないですけど一応動きました。


__

(0..9).inject([]){|xs, i|
  proc{|x| p x; x}.call(
    if i == 0
      [1]
    else
      proc{|xs|
        proc {|g|
          proc {|*args|
            g.call(g, *args)
          }
        }.call(
          proc {|g, a, b, *rest|
            if rest.size == 1
              [a + b, rest[0]]
            else
              [a + b] + g.call(g, *rest)
            end
          }
        ).call(
          0, *xs.map{|v| [v, v]}.flatten
        )
      }.call(xs)
    end
  )
}

できました。改行を取り除くのはお任せします。

PythonとRubyでデフォルト引数の評価されるタイミングは違う

驚きました。 rubyco(るびこ)の日記 - デフォルト引数は明示的に評価されると同じことをPythonで書いた場合、関数定義の時点で評価されます。

>>> def default(n):
	print "default", n
	return n + 1

>>> def foo(x, y = default(5)):
	print x, y

	
default 5

Rubyでは関数が呼ばれた時にデフォルト引数を評価するようです。しかも遅延評価とかではないようで、何度も関数を呼べば何度も実行されます。つまりPythonで書けば

>>> def foo(x, y = None):
	if y == None: y = default(5)
	print x, y

に相当する状態のようです。

Pythonで特定の何種類かの値からランダムに選んでリストを作る方法

勝手にどう書く0.0を読んで、勝手に抽象化しました。

>>> from random import choice
>>> [choice([0, 1]) for i in range(10)]
[1, 0, 1, 0, 0, 0, 0, 0, 1, 1]
>>> [choice("ATGC") for i in range(10)]
['C', 'A', 'C', 'G', 'C', 'C', 'T', 'G', 'C', 'C']

choiceは与えられたリストからランダムに選ぶ関数です。研究がゲノム関係だったので、ランダムなゲノム配列を作るのに重宝しました。

日記

だいぶわかってきた。「脱いだ服を床に散らかさない」は「~しない」だから「具体的に実行可能な行動」ではない。「脱いだ服をきちんと片付ける」は「きちんと」が定義されていないのでやっぱり「具体的に実行可能な行動」ではない。「脱いだ服は洗濯機の上の籠に入れる」ならOK。次に「服を脱いだら(即)籠に入れる」だと、籠に入っていない服が見つかったときに「失敗」になって無力感を味わうのだけど、「脱いだ服は籠に入れる」なら籠に入っていない服が見つかったときにそれを籠に入れて「成功」させ達成感を味わうことができる。

「毎日○○する」は1日失敗するだけで達成不可能になる。だから三日坊主になりやすい。「できたら○○する。○○した回数を数える」なら1回1回達成できる。とりあえずもうすぐ13時になるのに家でこんなことを書いている僕は「午前中にラボに行く」を目標にした方がいいかも。でも金曜から大阪だしなぁ。

「Rubyを勉強する」は具体的に実行不可能なので、「rubyco(るびこ)の日記を読む」にすれば…と読み始めてしまった。だからラボに行くのが先だって。冷房のついている部屋から出て駅まで行くのが無意識の足かせになっている。というか11~13時に出勤するので余計暑い。もっと早く行けばそんなに暑くないはずなんだけどね。

西尾泰和のブログ: PythonとRubyでデフォルト引数の評価されるタイミングは違う

よし、出かけるとするか。


__ ラボに来たけど誰もいない…。

Rubyはメソッド名に?や!を使えていいなぁ。以上以下があっていいなぁ。

下の二つは同じことなのかなぁ。

class Foo
    def Foo.bar
    end
end

class Foo end def Foo.bar end

全部が大文字じゃなくても、頭が大文字なだけで定数になるのですね。

しまった、もう5時半。何してるんだ自分。(Rubyの勉強?)


__ なんだか、4月の終わりにYouTubeが仕様変更をしたので昔僕が作ったダウンロード用スクリプトは使えなくなったそうです。新しい仕様では、tとlというパラメータが埋め込んであるので、何らかの方法でそれを取得しないといけません。

とりあえずダウンロードするスクリプトを書いてみたのですけど、ファイル名にタイトルが埋め込まれるようにしたらWindowsではUTF-8のままで書くと化けてSJISで書くと読め、Macではその逆。うーん。MacのFLVプレイヤーは知らないしWindowsで見るならSJISで出力すべきか。MacのPythonでSJIS出力をしようとするとSJISなんてエンコーディングは知らないと怒られたのでJapaneseCodecsをインストール。あー。MacでSJISのファイルを作成しようとしたらIOErrorになっちゃった。何か良くない文字でも含まれているのかな。仕方がない、urllib.quoteで変換しておいて、後で元に戻すとします。

さて、これで特定のキーワードで新しく見つかったまだダウンロードしていない動画を全部ダウンロードするスクリプトができたので、cronか何かで定期的に走らせればラーメンズのコントをもれなく自動的に収集できるはずです。


__ rubyco(るびこ)の日記 - マルチリンガルなシソーラス検索。欲しいなぁ。でも、データファイルを誰が整備するのか、を考えるとWikiを使ってデータ収集する方がいいのかも。Wikiに同じ内容のコードをいろいろな言語で書くと、その例えばPython部分のコードは"mltfind_python"という文字列がどこかに埋め込まれたページに出力され、同じ内容のコードをRubyで書いたページなどへのリンクが張られる、と。簡単にできそう。あー、でもその場合の問題点はGoogleがたとえ引用符で囲っていても"string->list"をstringとlistに分けちゃうことか…。検索をGoogleに丸投げではダメってことか…。 勝手に区切ったりしない全文検索を使うべきなんだろうなぁ。記号だらけだから。

帰ってきました。おなかいたい。

適当なWikiを改造したら簡単だ…と思ったのですけど、適当なWikiってどれでしょう…。うーん。大した機能は必要ないので作る方が手っ取り早いのかも。とりあえずDocutils: Documentation Utilitiesをインストールしてみました。reST rendererのソースがこれ。短い。

出力されたHTMLから正規表現で切り出したらいいと思っていたけども、ツリーで扱うことも簡単にできました。

XREA.COMにはdocutilsが入っておらず、docutilsを全部コピーしてみたけど「romanをimportできない」と怒られました。やれやれ。

あ、roman.pyだけdocutilsの中じゃなくてsite-packagesの中にありました。コピーしたら動きました。pywiki_0.01.py reStructuredTextを試せますが、書き換え保存はできません。

ここまでは簡単だったけど、編集がかぶったときの処理とか考えるの面倒だなぁ。


__ 4.4 difflib -- 差異の計算を助ける

タイミング: 基本的なRatcliff-Obershelpアルゴリズムは、予想の3乗、最悪の場合でも2乗となります。SequenceMatcher オブジェクトは、最悪のケースに比べて4倍、予想される挙動は、シーケンスの中にどのくらいの要素があるのか(最良なのは一列の場合)、というややこしい状況に依存しています。

4.4 difflib -- Helpers for computing deltas

Timing: The basic Ratcliff-Obershelp algorithm is cubic time in the worst case and quadratic time in the expected case. SequenceMatcher is quadratic time for the worst case and has expected-case behavior dependent in a complicated way on how many elements the sequences have in common; best case time is linear.

ふむ。2番目の文はややこしいなぁ。 SequenceMatcher has expected-case behaviorで、behavior depend on how many elements the sequences have in commonなんですよね。 データに依存しているということはわかるけど、日本語にはどう訳せばわかりやすいのかな…。

計算量: 基本的な Ratcliff-Obershelp アルゴリズムは、最悪の場合はデータ量の3乗のオーダーの時間がかかりますが、通常は2乗のオーダーになると予想されています。 SequenceMatcher は最悪の場合に2乗のオーダーの時間がかかり、 通常の挙動は与えられた配列の中のどれだけの要素が共通であるかによって複雑に変化します。最良の場合の計算量は線形です。

僕はやりたいときにやりたいだけを訳しているだけので気が楽だけど、こんな文章を訳さないといけないとは翻訳チームの人も大変ですね。


__ difflib.Differ().compare(a, b)で簡単に文字列の比較ができますね。

2006年07月26日

Pythonでアッカーマン関数

アッカーマン関数を素直に再帰で書いてみました。

>>> def ack(m, n, indent = 0):
	print "  " * indent + "ack(%d, %d)を計算…" % (m, n)
	if m == 0:
		result = n + 1
	elif n == 0:
		result = ack(m - 1, 1, indent + 1)
	else:
		result = ack(m - 1, ack(m, n - 1, indent + 1), indent + 1)
	print "  " * indent + "ack(%d, %d)は%d。" % (m, n, result)
	return result

>>> ack(2, 2)
ack(2, 2)を計算…
  ack(2, 1)を計算…
    ack(2, 0)を計算…
      ack(1, 1)を計算…
        ack(1, 0)を計算…
          ack(0, 1)を計算…
          ack(0, 1)は2。
        ack(1, 0)は2。
        ack(0, 2)を計算…
        ack(0, 2)は3。
      ack(1, 1)は3。
    ack(2, 0)は3。
    ack(1, 3)を計算…
      ack(1, 2)を計算…
        ack(1, 1)を計算…
          ack(1, 0)を計算…
            ack(0, 1)を計算…
            ack(0, 1)は2。
          ack(1, 0)は2。
          ack(0, 2)を計算…
          ack(0, 2)は3。
        ack(1, 1)は3。
        ack(0, 3)を計算…
        ack(0, 3)は4。
      ack(1, 2)は4。
      ack(0, 4)を計算…
      ack(0, 4)は5。
    ack(1, 3)は5。
  ack(2, 1)は5。
  ack(1, 5)を計算…
    ack(1, 4)を計算…
      ack(1, 3)を計算…
        ack(1, 2)を計算…
          ack(1, 1)を計算…
            ack(1, 0)を計算…
              ack(0, 1)を計算…
              ack(0, 1)は2。
            ack(1, 0)は2。
            ack(0, 2)を計算…
            ack(0, 2)は3。
          ack(1, 1)は3。
          ack(0, 3)を計算…
          ack(0, 3)は4。
        ack(1, 2)は4。
        ack(0, 4)を計算…
        ack(0, 4)は5。
      ack(1, 3)は5。
      ack(0, 5)を計算…
      ack(0, 5)は6。
    ack(1, 4)は6。
    ack(0, 6)を計算…
    ack(0, 6)は7。
  ack(1, 5)は7。
ack(2, 2)は7。
7

うひゃあ。たかが(2, 2)でこんなことになるのか…。すさまじいなぁ。


__

横軸m、縦軸nで原点を左上隅にして値を表示してみました。

      2   3   5  13
  2   3   5  13    
  3   4   7  29    
  4   5   9  61    
  5   6  11 125    
  6   7  13 253    
>>> 61 - 29
32
>>> 125 - 61
64
>>> 253 - 125
128

つまりack(m, n)は

	if m == 0:
		result = n + 1
	if m == 1:
		result = n + 2
	if m == 2:
		result = 3 + n * 2
	if m == 3:
		result = 8 * (2 ** n) - 3

ということみたいです。なおack(4, 0)は13で、ack(4, 1)は65533(これは2 ** 16 - 3)、ack(4, 2)は

>>> from math import log
>>> log(ack(4, 2))
45426.093625176574
>>> log(ack(4, 2) + 3) / log(2)
65536.0

というものすごく大きな数です。2万桁弱。アッカーマン関数がとんでもない関数だということがよくわかりました。


__ m = 0 の時 (n + 1)、m = 1 の時 (n + 1) + 1、m = 2 の時 (n + 1) * 2 + 1、と整理すると m = 3 の時 4 * (2 ** (n + 1) - 1) + 1 になって美しくない。 整理の仕方を間違えていたようです。まず記号を定義しないといけなさそうです。2 * n は 2 を n回足したもの、つまり + という演算をn回繰り返したものです。これを 2 +*n と書くことにします。次に、2 ** n は2をn回掛け合わせた物です。つまり+*という演算をn回繰り返したものなので、2 +**nと書くことにします。最後に、+**という演算をn回繰り返すことは+***nと書くことにします。そうするとアッカーマン関数は

m = 1のとき (2 +(n + 3)) - 3
m = 2のとき (2 +*(n + 3)) - 3
m = 3のとき (2 +**(n + 3)) - 3
m = 4のとき (2 +***(n + 3)) - 3

になる、と書けます。美しい。なお誤解を避けるために書いておきますと、数字の並びから推測してこうなりそうだと言っているだけで証明はしていません。


__ あれ?違う?

ああ、そうか、単に「n回繰り返す」と言っちゃダメなんですね。掛け算までは対称だからそれでも問題は起きないのだけども、累乗は対称ではないので(2 ** (2 ** (2 ** 2)))と(((2 ** 2) ** 2) ** 2)が一致しないわけです。正しいのは前者。

日記

体調悪いと思ったら昨日晩ご飯を食べるのを忘れていました。

Perlはやっぱもう駄目か(enbug diary(2006-07-22))。 を見て、言語間の優位関係はブール束だ、と思ったのですがリンクすべき解説を探して「ブール束」や「boole lattice」で検索しても見つからない。あれれ?と思ったらブール束は英語で「boolean lattice」でした。Boolean algebra - Wikipedia, the free encyclopedia。結局Wikipedia。{Ruby, Perl} > {Ruby}で{Ruby, Perl} > {Perl}だけども、Ruby と Perl の間に順序関係は定義できない、というもの。

うかうかしていられない、7月31日には大阪にいないといけないのだから冷蔵庫の中の物とかなんとかしなきゃ。

YouTube - ラーメンズ 「不思議の国の日本」 1 / 3 (前編)。僕はこれを見てラーメンズにはまったのです。公演の物なので、テレビ番組みたいにカメラワークが悪くて残念なことになったりしていないです。「この謎はおよそ14分後に解けます」とか時間の限られた番組では無理なので消される前にぜひご覧ください。

日経ソフトウェアで増田さんのPython連載が始まるんですね。

右手首がちょっと痛い…。うむむ。

昨日する予定だったデモをFLASHにしてみたのだけども、サイズが大きくて微妙です。全部続けて録画するんじゃなくて、もっと細切れにした方が良かったのかもしれません。

「ミサイルに核弾頭をつけないと費用の割に効果が少ないから、核弾頭の開発が済むまでは打ってこない」なんて言っている人はかつてこの国が何をしたのか忘れたんでしょうか。「人間1人+飛行機」を軍艦にぶつけても費用に見合う効果は得られなかったと思うけど。

サクセス頭皮スッキリ洗浄ブラシは単体で売っているなら買ってみようかと思います。値段次第ですけど。

最近、しゃべろうとして口を動かしているのに声帯のあたりで詰まってしまって声が出ないことが時々。この前ジュンク堂に行ったときに、声を出して読む本を買って、それを読んでみようとして思った通りの声がなかなか出せないことに改めて気づきました。うーむ。

31日から大阪で例のボランティアなので、29日に大阪に帰るとしますかね。服はさっき洗濯して干したし、後は冷蔵庫の野菜とソーセージを食べてしまえばOKかな。

Blog/2006-7-23 - Rocco の日記のコメントに書かれていた「アッカーマン関数を再帰を使わずに書く」というお題に挑戦したくなってしまったのですが「キミならどう書く 2.0」のネタにどうですか(ぇ) どこかで「ブログなんだからお題も募集すればいいのに」という意見を読んだような気がしますけど、中の人にもそれなりに予定があるでしょうから3.0あたりでそういうシステムに変えてみるとかどうでしょう(笑)

西尾泰和のブログ: Pythonでアッカーマン関数。アッカーマン関数がとんでもない関数だと言うことがよくわかりました。ack(4, 2)が2 ** 2 ** 2 ** 2 ** 2 - 3ですから…。mが5以上のことなんて考えたくもないですね。

で、結局また数学になっちゃったので「キミならどう書く 2.0」のネタにどうかという話はなかったことにしましょう。

No Free Lunch Theorem---理想の**の探し方---

AdaBoostを実装してみました。想像以上に簡単でした。

もう26時。照明を買おうかなぁ。明るさのなだらかに調節できるのを。作り付けの照明は夜に明るすぎて眠るモードになりにくい。

2006年07月25日

グラフ可視化ソフトGRINEditを使ったCollatz角谷問題の可視化その2

Blog/2006-7-17 - Rocco の日記。前回のGRINEditで可視化したFLASH(これ)は一気に全部を実行していたので、慣れない人にはわかりにくかったようです。そこでステップ実行のバージョンを作ってみました。PythonとXML-RPCとグラフ可視化ソフトGRINEditを使ったCollatz角谷問題の可視化

こうやって「うねうねつながったもの」がリアルワールドにあったとして、「頂点1から一番離れている頂点はどれ?」と聞かれたなら、1を持ってぶら下げて一番下にたれ下がるのがどれか見てみたくなりますよね。でも、無重力だとたれ下がってくれません。そこで重力を追加したわけです。

こうやって可視化することに意味があるのか、と問われるなら「ない」と答えるでしょうねぇ…。あえて言うなら「面白いから」でしょうか。まぁ、「キミならどう書く 2.0」の参加者は、面白いから解いているんであって、意味があるから解いているわけではないと思います。賛否両論あるみたいですけど、お祭りは楽しんだ方がいいのではないかと。

なおときどきの雑記帖 リターンズの「ソートのアルゴリズムの違いによる挙動の差とか、 木構造の構築、とくにAVL-treeとかの回転(rotate)なんかはこういう風に視覚化できると わかりやすいんじゃなかろうか? 」とのご指摘はもっともです。 それを目指してNarVisualizerを作り、去年の夏のプログラミングシンポジウムで発表したのですが、これ自体よりもこれの整形エンジンの方が需要が高そうだったのでこっちは塩漬けにしてGRINEditをやっています。将来的にはGRINEditの応用例としてNarVisualizerを吸収併合する予定です。

# -*- coding: cp932 -*-
import xmlrpclib
server = xmlrpclib.Server("http://localhost:8080/RPC2")
g = server.grinedit

g.initGraph()

existVertex = {
    1: g.addVertex("BoxVertex",
                   {"label": "1", "anchored": (0.0, 0.0)})
}

def addVertex(x):
    if not(x in existVertex):
        name = g.addVertex("BoxVertex", {"label": str(x)})
        existVertex[x] = name

    return existVertex[x]

def collatz(x):
    raw_input("...")
    # 次の数を求める
    if x % 2:
        y = x * 3 + 1
    else:
        y = x / 2

    print x, "の次は", y, "です"
    toReturn = y in existVertex
    v1 = addVertex(x)
    v2 = addVertex(y)
    g.addEdge("LinearEdge", {"v1": v1, "v2": v2, "directed": True})

    if toReturn:
        print y, "はすでに計算済みなので計算を中断します"
        return
    collatz(y)
        
for i in range(2, 11):
    if i in existVertex:
        print i, "はすでに計算済みなのでスキップします"
        continue
    print i, "についての計算を始めます"
    collatz(i)
    raw_input("...")

#g.addLaw("PL_Gravity", {})

日記

情報処理学会が学生会員という扱いになっていたのを正会員に変更、そうすると会費の請求額とは違う額を納めないといけないのでややこしいけど、ちゃんと計算したのでたぶんあっているはず。今まで学生会員4800円+研究会1個無料だったのが、正会員9600円+研究会(数理モデル化と応用)3885円で13485円。割と高いなと思ったけども、年間でこれくらいだったらそれほど高くもないのかな…。とりあえず今から振り込んできます。

振り込んで帰ってきたら先生が倒れて救急車で運ばれるところだったのでびっくり。

無事帰ってこられて一安心。

2006年07月24日

rpc用インターフェイス

現在、例えばlabelというフィールドを書き換えるメソッドはvoid rpc_label(Object)なのですけど、これはvoid setLabel(Object)にしてしまっても大丈夫な気がしてきました。XML-RPCで呼ぶときは"label"という文字列からリフレクションでrpc_labelメソッドを取得しているので、引数がObject型なのは変えられないのですが、メソッドの名前は別に今の物にこだわる必要はないわけです。で、Jythonインタプリタから操作する場合に、いちいちRPC用のと別にメソッドを用意しておくのは面倒です。そこでRPC用のメソッドを呼びたいわけですが、こちらは名前が裸で出るのでv.rpc_label("newLabel")なんて書くことになります。かっこわるいです。一方、v.setLabel("newLabel")ならごく自然です。

そもそも最初にsetLabelを使わなかったのは、JavaやPythonから呼び出す場合に引数がObjectでないといけないのはウザイかな、と思ったせいなのですが、上記の通りJythonからの呼び出しのために別口を作るのは面倒ですし、JavaやJythonからの呼び出しは同名でも別のシグネチャなら問題なく呼び出せますから、そもそもの心配が杞憂だったということになります。

むむ、メソッド名をsetBackgroundColorにするとXML-RPCの時に"BackgroundColor"をキーにするか、1文字目を大文字に変換する作業かどちらかになるか…。

大文字に変換するのの方が見栄えはよさそう。

GRINEditのデモ:Jythonコンソール。眺めるためのデモと読ませるためのチュートリアルの両方を作るべきなのかもしれない。これはソースコードを追おうとすると早すぎる。1ページに収まっているので、止まった後でじっくり読むことはできるけども。チュートリアルはNEXTボタンをぽちぽちクリックして自分のペースで読める方がいいし、デモはちまちまクリックさせられずにぼーっと眺められる方がいいのだろうと思う。

「キミならどう書く 2.0 Round2」は難しいのか、つまらないのか

キミならどう書く 2.0 - ROUND 2 の問題文がもしこう書かれていたら、世間の評判はどう変わったでしょうか。

ある1以上の整数 n に、

  • n が1なら停止する。
  • n が偶数の時は、nを2で割る。(n = n / 2)
  • n が1以外の奇数の時は、nを3倍して1を足す。(n = n * 3 + 1)

という手続き f を繰り返し適用することを考えます。どんな整数 n からスタートしても、繰り返し f を適用すると、かならずいつかは n が 1 になり停止するのではないかと思われています。(コラッツの問題 - Wikipedia)

例えば3からスタートすると、

3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 -> 停止

と、 手続き f を8回実行して停止します。これをステップ数と呼ぶことにします。 さて、「100までの整数で、停止するまでのステップ数が最も大きい数」はなんでしょうか?

「簡単すぎてつまらない」という人が増えたでしょうか。これを見て「なんだ、あの難しそうな問題文はそういう意味だったのか」と思う人も多いのでしょうか。

今回の問題は、問題文に使われている言語こそ難しかったですが、技術的に難しいところはありませんでした。問題が簡単すぎるという意味での「つまらない」という意見には、そういう意味では賛同します。この問題をゴールだと考えると簡単すぎてつまらないでしょうね。 でも、だからこそ一部のチャレンジングな人は、例えば「ものすごく大きい数についての計算に挑戦する」や「少ない文字数でコードを書くことに挑戦する」などの課題を自分で作り出してそれに挑戦していたのではないでしょうか。(僕の場合は「Schemeでdefineを使わずに書く」と「物理法則を使って可視化してみる」でした。)

お祭りは盛り上がらないと面白くないですから、難しすぎて挑戦者が少なすぎるよりは、簡単すぎる方がマシかと思います。簡単な問題なら、参加者が自分でもっと難しくすることができますから。でも今回の問題は、内容自体は簡単だったのに、問題文が難しすぎたようですね。例えば2文目の「Collatz予想とは,1以上の自然数 n に対して,次の関数 f(n) が必ず1を返すものとする.」も、関数fが再帰的な定義になっていて、慣れていない人にはわかりにくいですよね。hの定義も数学語で書かれていて読みづらいですよね。そういう難解な問題文を苦労して読解したら実はお題はすごく簡単だった、となるとガックリくる人も多いのかも知れませんね。

三すくみに関する考察

渡辺さんの日記に反応。

相対評価関数が「勝率」を使って定義され、値域が「-1 < f(a,b) < 1」になっているところから、エージェントの行動が非決定的だという仮定を置いているように思えます。三すくみを考察するときに、決定的なエージェントの方が考えやすいのか、非決定的なエージェントの方が考えやすいのかは僕にはわかりません。決定的な方がシンプルで考えやすい気もしますが、非決定的な方が偏微分したりできて面白い気もします。

とりあえず値域を-1 <= f(a,b) <= 1にしてみます。すると、f(a, b) = a[0]b[1] + a[1]b[2] + a[2]b[0] - a[1]b[0] - a[2]b[1] - a[0]b[2] という相対評価関数で 戦略ベクトルが(1, 0, 0), (0, 1, 0), (0, 0, 1)のどれかに制限されているエージェントを戦わせると、いわゆる「じゃんけん」になるわけですよね。

ところで、多数のエージェントがリーグ戦をする場合、相対評価関数は1対1のf(a, b)に限らなくても、f(x_i, x_0, ..., x_n)でいいような気がします。関数の値を勝率から定義してあると値の範囲に色々制限がつきますが、関数の値が単なるスコアなら何の気兼ねもなく全部足しあわせてしまって構わないですね。そうすると、x_0, ..., x_nを面倒なのでΦと書くことにすれば、エージェントiの学習はf(x_i, Φ)が大きくなるようにx_iを変えることですね。で、すべてのエージェントが同じタイミングで学習をする(「何もしない」という学習の仕方も含めて)なら、結局学習のステップというのは何か一つの関数Fを使ってΦnew = F(Φ)と書けることになります。このFがストレンジアトラクターを持っていたりするとエージェントを学習させている側としてはかなり嫌な感じですね。

と、話をふくらませただけで何の解決もせずにネットの海に投げ込んでみます。富栄養化(笑)

そうそう、じゃんけんみたいなわかりやすい三すくみではないけども、実際にプレイすると「すくんでいる」ような関係を設計する技術は、もしかしたらゲーム作りに役に立つのかも知れませんね。少なくとも、 名刺をトレーディングカードゲームにする話では、ある人の名刺がすごく強くて他の人を倒しまくってしまったりするとよろしくないので、うまい具合にすくませる必要がありますよね。プログラマはコンピュータに強く、普通の人はコンピュータに弱く、プログラマは普通の人に弱い。しまった、コンピュータは名刺を持っていないからプログラマが一方的に負けてしまう!(汗)

日記

ふぅ、電源があるとほっと一安心。

先日の「一単位の英語の勉強をするたびに1つの印をつけていく」という方法は行動分析学の言葉ではパフォーマンスフィードバックと言うようです。あと部屋全部を掃除するのは何度も挑戦して失敗しているので、確実に実行できるように「廊下を掃除する」という目標に変えた行動は神経言語プログラミングの言葉ではチャンキングと言うようです。

ちなみに昨日で生まれてから四半世紀が過ぎました。とか思っていたら親から電話がかかってきて「四半世紀過ぎたね」と言われました。思考回路一緒なんだなぁ…。

あと「四捨五入すると三十路」ってのもきっと誰かに言われるので先に書いておきます(笑)

ぎゃー。 小さい方のLinkStationの内容を大きい方のLinkStationに移動しよう…と週末ラボに放置しておいたのですが、今日になって中を見てみると何かおかしい…。何がおかしいのかというと、大きいLinkStationを買ったつもりが、一世代古い(HGじゃない)LinkStationを買っていて、今のLinkStationと同じ大きさでした!わー。どうしよう、これ…。

とりあえず移動したファイルをまた元に戻そう。古いLinkStationでもLinux化はできるようなので、CVS/SVNサーバにでもしようかなぁ…。

Macはやっぱりまだ慣れていないのでなかなかです。Deleteキーを押してもファイルが消えてくれないなぁ、とか、WindowsならAlt+F Rでプロパティが見られたのに、Macではいちいち画面を見てクリックしないといけないのかなぁ、とか。どこかを見ればキーアサインが書いてあるのかも知れないけど、メニュー自体に書いておいてくれれば楽に習得できるのになぁ、と思うわけです。まぁそれ以前にMacのキーボードではないのでほとんどのキーアサインが使い物にならないのですが。キーボードのマッピングを変えるソフトを探さなきゃねぇ。

とりあえず後輩に送ってもらった古いサーバのZopeのExtensionとProductsをコピーして以前のサイトをローカルで復元しました。これから時間のあるときにちまちまと以前のコンテンツを移植することにします。続きはまた今度。

明日GRINEditをラボ内でプレゼンするので久しぶりにJythonからグラフを操作しています。

MacでGRINEditを動かしてみたらUnsupportedClassVersionErrorが出ました。ふむ…これはJDK5.0を入れればいいのかな?いや、なんか入ってそうだ…でもどこにあるのかわからない…。

Apple - Support - Downloads - Java 2 SE 5.0 Release 1で見つけてインストールしようとしたら「このボリュームにはもっと新しいJavaが入っているからインストールできないよ」と言われました。やっぱりどこかに入っているそうです。

新しく来た「古いLinkStation」はファームウェアが3.01と最新のためtelnetで接続することすらできませんでした。Linux化するどころじゃない、と。したかったらHDDを取り出して別のマシンでマウントしないといけなさそう。うーん。そして古いバージョンだからUSB端子もないし、古いバージョンだから1000baseでもない。何に使おう、これ…。

GRINEditのデモ:Jythonコンソール。あ、最近FirefoxでFLASHが表示されなくて困っていたけど、ローカルのHTMLからリンクされているFLASHは問題なく表示されるので不審に思って調べていたらAdblockの設定でObjectタグが禁止されているのが原因かもという情報が。きっとそれですね。再起動してきます。

うかうかしていたら11時を過ぎていつもの路線で帰れなくなったので新橋→秋葉原経由で帰ってきました。

もう26時。最近、2袋目の無洗米がなくなったので買いに行ったところ、レイアウトが変わっていて無洗米が見つからなくなっていたので「金の芽ーがあーるきんめまーい」を買ってきました。これも無洗米らしいので。でも5キロ。今までお米は冷蔵庫の野菜室に入れていたのですが(狭くて野菜の入らない野菜室なので)5キロの袋はさすがに入りません。常温で置いておいて大丈夫なのかな。虫がわくのかな。無洗米でも?

とりあえず寝ます。

2006年07月23日

日記

ジュンク堂で久しぶりに本をたくさん読んだので疲れました。

Haskellが楽しそうでした。

あとなぜか眼がかゆいです。くしゃみも出ます。花粉?

例えば「毎日○○する」という目標だと1日成功してもあまり目標に近づいた感じがしないのに、1日失敗すると目標の達成が不可能になり一気にやる気が失せてしまいます。「気が向いたら○○する」で成功した日を記録していく方式なら、成功して記録用紙に記録するときに達成感を感じられるかも知れません。「これで10日目だ!」とか「3日連続だ!」という達成感も感じられ、後付で「次は20日を目指そう」とか「10日連続を目指そう」という目標ができあがるかも知れません。ただ、この方法は記録用紙自体をなくしてしまうと無力ですよね…難しい。あ、なくならないようにブログに書くのか、それはいいかも。

ゲド戦記は3巻まで読んだけども、CMの「命を大切にしないやつはだいっきらいだ!」の女の子は誰なのかさっぱりわかりません。オリジナルキャラですかね。それとも4巻に出てくるんですかね。

バッテリーが残り6パーセント。

2006年07月22日

日記

椅子届きました。これで背中にパイプが食い込むこともないでしょう。

片付けがなかなかできないのは、片付いた達成感を感じる経験が少ないからでは。というわけで、今日中に達成できそうな規模にタスクをブレイクダウンして片付けることにしました。「廊下を片付ける」と。お茶の箱が壁と癒着していたり、空だと思っていたコンビニ袋に使用済みのお茶のパックが入っていて汁が垂れていたり、いろいろハプニングはありましたが、きれいになりました。何にもなし。床の上とかに出しっぱなしだった食器を棚の中に詰め込んだので次はアレを片付けないといけませんが…、そういうことは考えずにとりあえず「廊下は片付いた!」と喜ぶべきなのでしょうかね。

バッテリーが少なくなってきてだんだん心細くなってきました。

どうしてGTDできないか、を考察してみたり。結局のところ、多種多様なタスク管理の手法があるにもかかわらずどれもうまく行かないというのは、「直すべき所」を間違えているからなのではないかと思いました。たとえばタスクを時間で区切って締め切りを設けることで集中力を上げようという戦略で「2時間に区切れ」という案や「2時間ではなく20分×6に区切れ」という案があったりするわけですけど、どちらが正しいのかはタスクの内容によって異なるわけだから本質的ではないわけです。で、2時間を試してみてダメで、20分を試してみてダメで…という試行錯誤の結果、正しい区切り方にたどり着く人もいるだろうけども、たどり着かない人もいるわけです。たどり着かない人は、まだ正しい区切り方に出会っていないのではなく、そもそも問題点が別の所にある可能性があります。習慣化能力とか。僕の場合は何か方針を定めても適切なタイミングでそれを思い出す能力が低いわけです。お風呂に入る前にタオルがあるか確認する、と決めても実際に入るときにそれを思い出せないので結局週に何回かはタオルがなくて濡れたままタオルを取りに出てこないといけないわけです。そういう「習慣化能力の低さ」を自覚して、習慣を定着させるにはどうしたらいいかを考えないといけないと思います。うーん。「習慣を定着させるためにこれをする」という習慣を作る方法では方向性としてダメですよね。


__ 習慣化に成功していることと、習慣化に失敗したことは何が違うのかを検討。

明日はジュンク堂や東急ハンズに行ってじっくり物色することにしようかと思います。

精神的な弱さの改善を精神論に頼るのはおかしいので、例えば自己暗示や教科学習(オペラント条件づけって言うのかな?)、薬物などの科学的な手法に頼るべきなのだと思う。

Installing a new habit and breaking an old oneNBonline(日経ビジネス オンライン):Lifehacks コラム・トップ。読み始めると途中でバッテリーがなくなりそうで。

バッテリー残り14%で明日1日を過ごさなければならない…。温存するか…。

2006年07月21日

日記

うー。今やっと、昨日走らせたジョブが終わった。

椅子を発送したそうなので明日か明後日には届くことでしょう。

楽天クレジットカードが未だに届かないのはなぜ。

クラスタ化インデックスを使うとソートされた状態で取り出せるらしい。


__ ラボのリフォーム。 Mac miniにZopeを入れ、古いサイトをエクスポートしておいた物をインポート。しかし、古いサーバの中のProductsとExtentionsがないとサイトは復元できないことに気がつく。

今日の行きの電車でゲド戦記3を読了。楽天ブックスで「エヌ氏の遊園地」(星新一)を購入。

「楽天ブックスの便利さ」ではなくて「『安い本でも送料無料』の便利さ」なのだけど、 1冊の文庫本を読もうと思ったその時に十数クリックすれば、数日後家のポストにそれが入っている、というのはとても便利。今まででも送料を気にしなければ同じ便利さを享受できたはずだけども、無産階級の悲しさで節約してしまう。


__ はてなでつまらないことを質問してしまった…。


__ この文章はMac miniから書いています。とりあえずCtrl+Shift+J で日本語モードになってCtrl+Shift+;で英語モードになるということは覚えました。本当はひらがなキーや英数キーでも切り替えられるんですけど、今つないでいるキーボードが英字配列なので、、、正確に言うとちょっと特殊で、左シフトキーの隣にあるキーには「Zㄈ重心」と書いてあるんですけどね。ㄋㄧ3で你が出るのだけど好を出そうとしてㄏㄚㄛと打ってもㄏㄛになってしまう。謎。あとコピペをしようとしてCtrl+C,Vを押したら期待と違う挙動をしたり。なかなかいいパズルです。

注音符号 - Wikipediaの図を見て、aoがないのでaとoを組み合わせてㄏㄚㄛにしたのだけど、正解はauと書いてあるㄠを使ってㄏㄠとするんだそうです。このページの下の方の説明を読むと確かにそう書いてありますね。あと注音符號 - Wikipediaを見るとおのおのの文字の由来が書いてあっていいですね。ㄒは下(xia)が元になっているから発音がXなんですね。ㄠはヤオチューハイのヤオですね(麻雀かよ!)


__ パソコンの電源を忘れたかも。というか探しても見つからないからたぶん忘れたんだろう。あーあ。


__ TAKESAKO @ Yet another Cybozu Labs: AJAJA - Yet Another Server Side JavaScript。 サーバサイドJavaScriptは久しぶりに目から鱗が落ちました。確かにサーバサイドをJavaやPHPでやって、間をXMLで通信して、クライアントサイドをJavaScriptでやるのはキメラみたいで変ですよね。サーバでJavaScriptが動いて、間の通信をJSONにすると、とてもすっきりしそう…。

とりあえずPPTをダウンロードして呼んでみたけども、僕にできることはなさそうです。僕もあまり浮気をしないでGRINEditを仕上げることに注力するべきかも知れません。今週は全然いじる時間を取れてないですけど。

とりあえず次の月曜にラボのMac miniにApacheとAJAJAを入れてみよう。


__ バッテリーが残り57%…。うーん。このバッテリーで土日を過ごすのは寂しいなぁ。

2006年07月20日

日記

昨日、ヨーグルトを服にこぼしてしまって、そのまま洗濯機に入れていいかどうかわからなかったので風呂場で水をかけて、びしょびしょだったので水が切れるまで置いておこうと思って、朝シャワーを浴びようと思ったらまだそこにありました。

いま洗濯機にかけたので、洗濯が終わるのを待って干さないと出かけられませんね…。

おー。できたできた。SQLiteで作っていた物が思い通りの挙動をしました。思い通りに動くようになってくると楽しいですね。


__ Mac miniにZopeをインストールしようかと思ったのですが、「makeがない」と言われて困る。アップル - Mac OS X - 開発ツールを入れるのですかね。どこからダウンロードするのかな…。あ、購入時についてきたCDに入っているんですか、なるほど。

そしてCDの中身をどこから参照するのかがさっぱりわからない…。デスクトップにアイコンがでるか、FinderのMacintosh HDのそばに並ぶか、と思ったけどもどちらも起こらないし、しかもドライブにイジェクトボタンがついていないからCDを取り出してやり直すこともできない。うーん。


__ 作ったプログラムは「SELECT * FROM table ORDER BY id」という感じのクエリーがほとんどの時間を食ってしまっています。ソートをしなければ早いのだろうとは思うんですけどもね。あらかじめソートしておけばいいのだけども、データを追加する際にソートされている状態を保つように注意して追加しないといけないですね。INSERTで追加した行はテーブルの最後につくと考えてもいいのかどうか…。こういう時系列のデータの扱いに便利なように設計されているのが Spatial and/or Temporal Databases (Resources / Survey) なんでしょうかね。


__ あー。なんかデータベースにところどころ同じデータが重複して入っている…。

いろいろな処理を投げて速度を比べてみようかと思ったのだけど、キャッシュとかがあると見えて実行の順番によって結果が変わりますね。ということは逆に今やっているような「すべてのデータをなめる処理」をやるには効率が悪かろうと想像できます。知れば知るほど、今やろうとしていることにリレーショナルデータベースは向いていないと思えてきます。 やっぱり時系列データベースですねぇ。K-nearest queryが使えるとやろうとしていたことが簡単にできそうです。距離関数を定義できるのなら。でも「論文としてすでに存在する」と「使えるツールとしてすでに存在する」は別物ですよね。「距離関数が決めうちのいくつかしかありません」なんてのじゃ使いものにならないですよね。ちょっと枠からはみ出したことをしようとすると結局データを全部取得して自分で距離を計算して見つけ出すか、もしくはデータを全部目的にあう形に変換したデータベースを作らなければならないわけで。うーん、自分で作るとしたらまずはもうちょっとデータベースの勉強をしてから…。

トランザクションの処理とかがいらなくて、ほとんどの処理が1方向になめる処理なのだから、オブジェクトを1つずつ永続化して行単位で出力しといて、使うときはファイルから1行ずつ読んでいくというのでもいい気がしますね。


__ 人間関係のグラフ表示をするならmixiよりSlashdotの方が面白そう。友達の他に「テキ」という人間関係があるので。テキリンクをマイナスとしてPageRankを計算したらどうなるのかな?


__ ふむふむ。データベースに追加した順で取り出せることは保証されていないようですね。じゃぁあらかじめソートしてから入れても意味がない、ということですね。たまたまソートされた状態で出てくる可能性が高くても、それに依存したコードを書くのは良くないですから…。

というか!今気づいた!ソートに時間がかかるのを「ソートには時間がかかるから仕方ないか…ソートを使わない方法はないだろうか…」と諦観していたけども、874件の行を整数の1列だけを見てソートするのに118秒かかるSQLiteがダメすぎるだけなんじゃなかろうか。あー、ORDER句でソートしないで、fecthallで取得した後のPyListのsortを呼んでソートさせたら9秒くらいしかかからない…。しかも取得に9秒でソートは一瞬。むう。仮にデータが文字列で保持されていて、毎回文字列から数値に変換してソートしているとしても118秒はおかしいよなぁ。何をしたらそんなに遅くなるんだろう…。

そんなわけで今まで100秒かかっていた処理が8秒で済むようになったので…それでも後10時間かかるのか…。うーん。ほとんどがデータベースからのデータの取得だから、やっぱり「扱うデータに向いているデータ構造を使うことで高速化」と行きたくなりますね。まぁ、今日の所はこのまま走らせて寝ることにします。

2006年07月19日

日記

冷えから脱水症状へのリレーが発生して夜の5時に飛び起きました。ふぅ。 睡眠不足気味です。

冷房つけていなかったのに、夜寝るときに肌寒かったので「今日は涼しいなぁ」と思っていたのですが、雨のせいで体が冷えていたようです。


__ The glider: an Appropriate Hacker Emblem。ハッカーエンブレム。Merchandise with Conway's Glider : CafePress.comでTシャツも売っています。欲しいけど、輸送費はいくらかかるのかな…。関税もかかるのか…。ややこしいなぁ…。


__ あ゛ー。わがっだ…。うー。

SQLを勉強中です。もっと小規模な物から始めりゃいいのにいきなり456MBのデータベースを作ったので、ちょっと設計を変更しようとすると結構時間がかかってしまったり、それだけ時間がかかった上にコミットし忘れて消滅したり、と馬鹿なことを繰り返しています。で昨日あたりに「データの一部だけを取り出して実験用の小さいデータベースを作ろう」と思って「select * from テーブル名 where 条件」とやったのですが、あるはずのテーブルが「no such table」と怒られ、テーブル一覧を出すクエリを投げても何も表示されず悩んでいたのでした。

で、結論はSQLiteでデータベースファイルを開く際、ファイルが存在しないと自動的に作ってくれるので、肝心のデータベースファイルがあるフォルダではなくてPythonインタプリタのデフォルトのワーキングフォルダに空っぽのデータベースファイルがごろごろ…。orz。

あとshow tables;じゃなくて.tableでテーブルの一覧、.schema tableNameとやればそのテーブルの定義を見ることができます。

2006年07月18日

日記

昨日の晩に沸かされて一晩冷やされたお茶が、今朝床に逃げてしまって悲しかった。


__ あんまりしっかり考えずにモニターを選んだせいで使い勝手が悪い…。16 x 9だし、むやみに明るいし…。動画鑑賞にフォーカスしたモニタだったみたいです…。

ノシロ語 - Wikipedia 。ほー。でも共用語を設計するのは楽しいかも知れませんね。顔文字(>ܫ<) の真ん中の文字はアラム文字で「歯」という意味だそうです。帝国アラム語の文字-アラム語の頁。アラビア数字とバングラ数字:アラビア文字moji-1


__ お風呂で渦を作っちゃおう。 こんどやってみよう。


__ 今日は私物のハブとケーブルを持って行ってMac miniをネットワークに接続しました。sshでリモート接続できるようにしようと調べたら、GUIで設定画面を出してチェックを入れるだけであっさりできてしまいました。明日はZopeをインストールして古いサーバのコンテンツをローカルでアーカイブ化しようかと思います。

2006年07月17日

西尾泰和の活動ダイジェスト

西尾泰和の過去の活動(主に日記)からピックアップしたページへのリンクです。

他の人によるピックアップ(このブログのはてなブックマークされている記事): 1人以上3人以上5人以上

同じくはてなブックマークされている旧サーバのコンテンツ: 1人以上

以下は他の多くの物と一緒に時系列で並べるよりもカテゴリごとに並べた方がよいと判断した物です。読み返してみると文章も雑だし、書き直して1枚にまとめたりした方がいいかもしれないですね。


メモ。発掘済み:archivedCoreblog - 287

PythonでYコンビネータを勉強

>>> (lambda f:((lambda p:(f(lambda x:(p(p)(x)))))(lambda p:(f(lambda x: (p(p)(x)))))))(lambda f:(lambda x: not(x) and 1 or x * f(x-1)))(5)
120

一応、階乗を再帰呼び出しで計算してみました。たぶん冗長な括弧があると思います。

Pythonで「例外が投げられた関数のローカル変数」を取得

ローカル変数は関数の外側から参照したり書き換えたりできない、というのはプログラムをモジュール化する上では非常に重要な特徴です。普通にプログラムを組む上では、この縛りを破るべきではないとは思います。 しかし、何か事件が起きたときにはルールに縛られずに思ったことができる力が欲しいですよね。例えば下のようなコード。

def someFunc():
  何かとても時間のかかる処理
  ファイルを開いて処理の結果を出力

いざ計算が終わってファイルに出力する段になって「しまった、出力先のファイルをエディタで開いていたせいで書き込みモードで開くのに失敗した!」なんていうシチュエーション、ありますよね。そんなときに泣きながらもう一度計算をやり直さないでいい方法がこちら。

def getLocals():
  import sys
  tb = sys.last_traceback
  while tb.tb_next:
    tb = tb.tb_next
  
  return tb.tb_frame.f_locals

これを対話型シェルに貼り付けて実行すれば、 getLocals()で例外の発生した関数のローカル変数が取得できるようになります。 たとえばresultという変数に結果が入っているのなら result = getLocals()["result"] などとやって変数を取得できます。なお、あまりおすすめはしませんがローカル変数を全部グローバル変数に変える(グローバルスコープに同じ名前の変数を作る)には globals().update(getLocals()) と書くといいでしょう。

日記

ゲド戦記2 壊れた腕輪、読了。一昨日注文して今朝届いたので…。通勤の電車で読むつもりで買ったのに面白すぎてついつい読んでしまいます。あと、やっぱり「ゲド戦記」というネーミングは良くなかったんじゃないですかね。以下内容に関することなので一応背景色。


__ 楽天アフィリエイト。ゲド戦記(1) ゲド戦記(2)

まぁ、楽天アフィリエイトはアマゾンアソシエイトと違って商品ページからアフィリエイトのリンクを求めることができなさそうなので不便ですね。労力の割にリターンも少ないですし。


__ 酸欠気味なので散歩に行ってきます。


__ 雨降るし。


__ アナログシンセモンスターThingamagoop - Engadget Japanese 。外見はさておき、光での入力で光と音の出力が変わるので、触手を曲げてやるとリカレントネットワークを作ることができる(ニューロン1個なのをネットワークと呼ぶのか?)のが面白いですね。おなかのダイヤルはディレイでしょうか。触手を2本と眼が2つにして、数十匹組み合わせてみたいです。さらに言えばタイヤもつけてbraitenberg vehicle - Google イメージ検索にすると楽しいことに…。作りたくなってしまうなぁ。

GRINEditにプラグインで追加した頂点と、それへのキャストを内部で行う物理演算とを追加することはできるだろうか。つまり、クラスローダがプラグインからクラスを読んだときに、そのクラスが参照している同じjar内のクラス定義を読んでくれるだろうか。それができるなら、「入力と出力のフィールドを持ち、レンダリング時に出力に応じた音を鳴らす『ニューロン』頂点」「根本のニューロンの出力を先のニューロンの入力に加算/減算する『軸索・シナプス』辺」「ニューロンの入力の値から出力の値を計算する物理法則」をプラグインで追加するだけで作れそうです。試してみる価値はあるかも知れませんね。


__ 楽天ブックスは今は送料が無料だからいいけれども、結局アマゾンに対してさほどメリットはないので送料無料キャンペーンが終わると使わないかも、と思うようになりました。さて。 星新一「きまぐれロボット」「エヌ氏の遊園地」「ボッコちゃん」はアマゾンでまとめて3円なのに送料手数料が1020円、楽天では新品で1冊490円。うーん。

星新一 お気に入り読書WEB で紹介されているうち「悪魔」「おーいでてこーい」「おみやげ」「ボッコちゃん」「殺し屋ですのよ」「ゆきとどいた生活」はオチを思い出せるのに、他の話は思い出せなくて気になっているんです。思い出せる6つの話が全部教科書に載っていたわけでもあるまいし、ボッコちゃんの本を持っていたような記憶もあるのに、どうして他の話は覚えていないのやら。

星新一の著作は1001話以上あるらしいです。全部読みたいです(ぇ)


__ 日経新聞によれば、教育免許を10年の有効期限つきにしようという中央教育審議会の最終答申が11日に出ていたそうです。案自体はよさそうですけど、はたしてどうなることやら。ゆとり教育も僕は案自体は良かったと思います。やりたいことがある子供が宿題に終われてやりたいことをやるゆとりがないのはもったいないですから。でもやりたいことの特にない子まで一律で授業時間を減らすのは何が目的だか。これも同じで、案は良くても「実質全員が更新される」とか「ノルマが決まっていてその人数の運の悪い人が切られるだけ」とか「いい教師ほど忙しくて更新試験のための勉強ができない」とかだったら本末転倒ですよねぇ。そうならないことを祈りたいです。


__ 今気がついた。 代金引換しか受け付けていないネットショップでも、楽天ポイントで支払えば代引き手数料がつかないじゃん。クレジットカードが使えなくても。


__ このブログが実名を冠しているところや、コメント・トラックバックが表示されないところは結城浩の日記にインスパイアされているのですが、そろそろ日記ダイジェストに相当する物も作るべきなのじゃないかと思いました。とりあえず作りました。COREBlogの記事を移植する際に画像を持ってくるのを忘れたの画像の出ていない記事がありますね…。あと前の研究室のサーバにある1時間で覚える?Pythonとかもこっちのサーバに持ってきて向こうのはリダイレクトに変えるべきですよね。まぁ、自宅は回線状況が良くないのでそのうちにラボでやることにしましょう。


__ 今日は部屋が片付いたわけでも、やろうと思っていたプログラムを書けたわけでもない。何をしていたんだ。カレーを作った?

2006年07月16日

日記

今日、再配達で掃除機がくる予定なんですけど、何時にくるのかわからないので出かけられません。むう。 出かけてやる!

プログラミングの最中に眉毛を抜くクセを直す方法をはてなで聞いて、「目の前に鏡を置いておくと自分が眉に手をやったときに気づくから直せる」と教わってなるほどと思ったのですが、ラボの机に鏡を置くのはなんかナルシストっぽくて嫌だなぁ。


__ はっ、月曜日も休みか! しまった、やっぱりラボからMac miniを持って帰ってきておくべきだった。


__ Texpointがシェアウェア化してどうしようかという話、Open Officeに移行してOOoLaTeXを使うという手もあるようです。フォントの美しさにこだわりがなくて、単に数式エディタがじゃまくさいだけならOpenOfficeの数式エディタはTeXっぽいコードで「int_{x=0}^{x=infty} x^2 dx」とか書けるのでそれで済んでしまうかも知れませんね。


__ タイトルのないだらだら書きにタイトルをつけたくなるのは、それを独立したエントリーにせよと言うことなのだろうか。とりあえずだらだら書きにタイトルをつけておいて、後から必要に応じて新しいエントリーにくくり出すのもありか。


__ BBC NEWS | Scientific brain linked to autism 「非常に分析的な考え方をするカップル(例えば科学者同士)は自閉症の子供を作る傾向があるかも知れない、とある専門家が主張している。( Highly analytical couples, such as scientists, may be more likely to produce children with autism, an expert has argued.)」

科学的には同意しそうになるのだけども、こんなことを言われるとただでさえ嫁のなり手が少ないのにますます減ってしまうので政治的な理由で反対してみます(ぇ)

結局のところ、論文へのリンクを張っておいてくれないと「自閉症」って言葉を「アスペルガーを含む自閉症スペクトラム」という意味で使っているのか「知的障害を伴うカナータイプの『いわゆる』自閉症」という意味で使っているのかがわからない。世間一般の人は当然後者だと取るだろうけど、もし事実が前者の方だったらこの記事はかなりミスリーディングですね。


__ メモメモ。色盲の有症率は20人に1人、アスペルガーの有症率は客観的な診断方法がない為か、250人に1人~16人に1人とばらつきがある。


__ 食後に挑戦するんじゃなかった。IQテスト。最後の数問が熾烈に難しくて、考えているうちに眠くなって適当に答えてしまいました。結果は140。まぐれ当たり?だれか34と38と39の答えを教えてください。

2006年07月15日

日記

雷ごろごろ。そろそろ梅雨も終わりですかねぇ。

西尾泰和のブログ: PythonとXML-RPCとグラフ可視化ソフトGRINEditを使ったCollatz角谷問題の計算ステップが最大になる数の求め方を作ってみました。やっぱり普通の動画よりもFlashの方が説明と動きの実演をつなげるのが楽ですねぇ。

週に1回は手帳の整理。


__ あついー。 冷蔵庫の中がほとんど空っぽだったので買い出しに行ってきました。まず家の前で自転車が行方不明で大あわて。よく考えたら昨日南船橋から帰ってきたので自転車は駅前ですね。仕方がないので歩いていきました。

駅までの道の一カ所、いつも涼しい風が出ているところがあります。今まではコンビニの冷房が出ているのだと思っていましたが、今日は歩きだったのでどこから出ているのかを特定できました。なんと道路に開いた下水道への入り口?から吹き上がってきていました。どこから来た風なんでしょうか。


__ ふと思ったのですが、コーヒーを作った後のコーヒー豆にカフェインが残っているなら、普段捨てられるその豆からカフェインを抽出してカフェイン増量コーヒーを作れるのでしょうかね。手軽なカフェイン抽出法。カフェインは熱に強く昇華を起こすので加熱するだけで抽出できるそうです。


__ 「ゲド戦記1 影との戦い」読了。面白かった。第二巻も注文しようっと。

ちなみに第一巻で影と戦うゲドは19歳。若気の至りでの過ちとそこから始まるゲドの成長物語でした。映画は3巻相当らしいですねぇ。


__ やっぱりレオパレスに最初からついてきた椅子は悪すぎる。背中を支えるのが直径2センチくらいの1本のパイプだけなので、うっかりもたれると腰の血流を妨げる。やっぱバランスチェア買おうかなぁ。これ。小学校の時からずっとこれを使っているし、意外と安いし。

買いました。

PythonとXML-RPCとグラフ可視化ソフトGRINEditを使ったCollatz角谷問題の計算ステップが最大になる数の求め方

GRINEditを使って解いてみました。 Flashで動画にしたのでこちらをご覧ください。

なお、ここで使っているGRINEdit-alpha 0.20はまだリリースされていませんが、需要があれば早めにリリースするのでご連絡ください。


__ 2006/07/25 わかりにくいという意見があったのでステップ実行バージョンを作りました。グラフ可視化ソフトGRINEditを使ったCollatz角谷問題の可視化その2

2006年07月14日

マウス操作のメタキーサポート

マウスとメタキーの組み合わせについて、それぞれMouseOperationを割り当てられるようにと思い、 「マウスとメタキーの組み合わせ」をキーにしてハッシュにMouseOperationを入れることを考えたのだけども、 ユーザーとしてはそんなに粒度の細かいカスタマイズは欲しくないのかも知れませんね。 この方法だと「左ドラッグに範囲選択」「左Ctrlドラッグに範囲を追加する範囲選択」…と似た機能でもそれぞれ別個の機能になるので、例えば範囲選択は範囲を追加しない物をCtrlの方にして…なんてカスタマイズもできますが、そんなことより左ドラッグの操作を移動から範囲選択に切り替えたときにCtrl+左ドラッグが勝手には変わらないと言うデメリットの方が大きそうです。

現在、固定しない頂点移動と固定する頂点移動が別の物としてメニューに登録されているのはそれが原因です。 このマウス周りの操作を行うクラスがSWTとAWTの両方をサポートする必要があるのかないのか。いや、ないということに決めたんでしたっけ。結局両方を1つのクラスでサポートすると、AWTしか使わないソフトでそのクラスを使う場合にswt.jarなどが必要になって良くないという結論でした。

日記

駅のパン屋で売っていたハバネロカレーパンが辛くて辛くて。

Kazuho@Cybozu Labs: Movable Type をコマンドラインから操作する (トラックバックスパム一括削除)を読んで、スパムトラックバックがどれくらい溜まっているのかをチェックしてみると、スパムの中に人間のトラックバックが発見されました。 うーん、トラックバックの便利さはちょっとわかったような気がしますが、スパムに分類されてしまうとつらいですね。他に埋もれているトラックバックがないか目で探すのも大変ですし。

「東京工業大学のうた」。うわー。なんか絶叫してるー。なんでゲートボールなんだー!


__ Winkを使うとこんなのが簡単に作れました。 本来60FPSで動いている物が30FPSになってしまっていますし、マウスの動きはなめらかですけど範囲選択の箱の描かれ方を見ると実はあまりキャプチャ頻度は高くないみたいですけども。


__ 研究室内の飲み会で終電がなくなりました。南船橋から家まではタクシーの深夜料金だと1600円くらいということがわかりました。


__ LL Ringのチケットがまた発売になるそうなので早速楽天チケットに行ったのですが、もうなかったですorz

実はGRINEditにPythonからXML-RPCしてコラッツ計算のステップが最長になる数を求める(っていうか可視化したらたぶん最長になるのが一番下に垂れ下がる)スクリプトを書いたので明日エントリーを作ることにします(ぇ)

どうせならPythonからクエリを投げるんじゃなくてRubyから投げる方が受ける?受ける?

しかし「LL Ring まだまだいくよ~」を見て「生麦生米 LL Ring」とか連想するのはやっぱダメ人間でしょうか。


__ 暑い死ぬ。

アルコールのせいだ。


__ Lightweight Language RingがLightweight Languageに限らず何でもアリになりつつあるという意見について。 LLをLess-popular Language/Libraryに変えればとりあえずつじつまは合うとか思いました。 あー、でもPHPやPerlはそれほどlessでもないのかな…。


__ 土日遊ぶためにMac miniを持って帰ろうかと思ってたのだけど、みんなが待っているので断念。でもLinkStationは持って帰れば良かったかなぁ。

あー。自宅用にPS2キーボードをUSBに変換するアダプターをもう1個欲しい。でもそれを買うためダメに秋葉原に行くのは何か電車賃が…。


__

2006年07月13日

log

  • 物理演算をXML-RPCで追加してみる
    • クラス名に"org.nishiohirokazu.layout"をつけるのは面倒なのでクラスの検索パスを配列で持たせる
    • anchoredの処理
      • anchoredをセットすると、それがvertexのpropertyに入るという仕組みを考えていたが、vertexにanchoredをセットしたときにanchoredVertexにそのVertexが入る、という処理の方が楽で高速でシンプルな気がする。汎用性を損ねないか?
    • java.lang.reflect.InvocationTargetException
      • anchorをセットしようとする段階でname == null
      • nameの初期化がパラメータのセットより後であるせい。nameを先に持ってくるのは難しいのでparamsのセットを後に持ってくる。
        • XML-RPCの現状「オブジェクト作成→パラメータ設定→ハッシュに追加する際に名前が未定なら生成して追加」 名前は真っ先に決まるべきなので「名前をパラメータから取得・なければ生成→オブジェクト生成→パラメータ設定→追加」に変更
        • いいタイミングだったのでobsoleteだったgraph#addVertexなどを一掃
        • XML-RPCで固定する頂点を指定できるようになった。
      • InvocationTargetExceptionは例外をラップしている為、本当はぬるぽなのにXMLを投げただけのPythonにはそれが伝わっていない。例外の詳しい内容を取得するメソッドが欲しい。
        • XML-RPCのクライアントはエラーが起きていないと思っているので、エラーが起きたことを能動的に知らせなきゃいけない。受動的に問い合わせを受けて答えるのではなく、能動的に例外を投げるべき。
        • catchしてthrow e.getCause();
  • 完了:*1 addLawのtargetとして文字列を渡すことができるようにする。"SelectedEdges"や"AnchoredVertex"など。 45min

Pythonでカリー化

帰りの電車でHaskellの勉強をしていたはずが、なぜかPythonでカリー化を実装してしまいました。 型チェックも入っていますけど、これは実行時の型チェックですね。「型XはYまたはXとXのForkである」などの定義の仕方は僕の発想の斜め上を行っていたのでしばらく寝かせないと理解が進みません…。

def curry(argsType, resultType):
    def _curry(f):
        args = []
        restArgsType = argsType

        def foo(x):
            argType = argsType.pop(0)
            assert isinstance(x, argType)
            args.append(x)

            if argsType == []:
                result = apply(f, args)
                assert isinstance(result, resultType)
                return result

            def bar(y):
                return foo(y)
            return bar

        return foo

    return _curry


@curry([str], str)
def f(x):
    return x

print f("hello") #-> hello

@curry([str, str], str)
def f(x, y):
    return x + " " + y + "!"

print f("Hello")("Haskell") #-> Hello Haskell!

@curry([int, int, int], int)
def add(x, y, z):
    return x + y + z

print add(1)(2)(3) #-> 6

日記

色即是空 空即是色というのは、空がjava.lang.Objectみたいな基底クラスであり、Pythonみたいにクラス定義自体もオブジェクトであるような言語であれば「すべてのインスタンスは空のインスタンスであり、空自体もまたインスタンス」という方法で自然に実現できるのですけど、関係の対象性を求めるととたんに難しくなります。両方を同一のものにしてしまうというのがトリビアルな解なのですけど、それじゃ面白くないですし。

そんなことを考えていたら電車を乗り過ごしかけました。


__ Pythonで75文字でCollatz角谷問題の(以下略にSchemeの解を書き足したのは別のエントリーに分けるべきだったかも。

Pythonで87文字でCollatz角谷問題の(以下略

f = lambda x: x == 2 and 1 or f(x % 2 and x * 3 + 1 or x / 2) + 1; max(map(f, range(2, 101)))

上の行は読みやすいように不要な空白文字を削っていませんが、削れば75文字です。 問題についての詳しい内容はキミならどう書く 2.0 - ROUND 2 - — Lightweight Language Ringをお読みください。


キャッシュを追加してみました。n = 100000で20倍程度速いみたいですね。

c = {}; f = lambda x: c.get(x,0) or c.__setitem__(x, x == 2 and 1 or f(x % 2 and x * 3 + 1 or x / 2) + 1) or c[x]; max(map(f, range(2, 100001)))

こちらも100までにして空白文字を取り除くと119文字です。


__ 関数型言語にも挑戦してみました。Schemeです。

(define (mod x y)
  (if (> x y)
      (mod (- x y) y)
      x))

(define (step x)
  (if (= (mod x 2) 1)
      (+ 1 (* x 3))
      (/ x 2)))

(define (numStep x)
  (if (= 1 x)
      0
      (+ 1 (numStep (step x)))))

(define (maxStep x)
  (if (= x 1)
      0
      (max (numStep x) (maxStep (- x 1)))))

素直な書き方をしてみました。


__ 上のSchemeコードはシンプルすぎて面白くないのでこっちもワンライナーにしてみました。といってもSchemeですから、単に改行を取り除くだけでもワンライナーになってしまって面白くないですね。そこでdefineを取り除いてみました。

(((lambda(f)(lambda(x)(f f x)))(lambda(f x)(if(= x 1)0(max(((lambda(f)(lambda(x)(f f x)))(lambda(f x)(if(= 1 x)0(+ 1(f f((lambda(x)(if(=(modulo x 2)1)(+ 1(* x 3))(/ x 2)))x))))))x)(f f (- x 1))))))100)

lambdaを一文字にする方法ってどうするんでしたっけ。それを使えば上のコードは下のようになるはずです。

(((λ(f)(λ(x)(f f x)))(λ(f x)(if(= x 1)0(max(((λ(f)(λ(x)(f f x)))(λ(f x)(if(= 1 x)0(+ 1(f f((λ(x)(if(=(modulo x 2)1)(+ 1(* x 3))(/ x 2)))x))))))x)(f f (- x 1))))))100)

こちらはλを一文字と見なせば166文字です。λは7つあるので一文字と見なしたくない人は+35してください。


__ 「f f」というあたりがYコンビネータみたいなので、Yコンビネータについて勉強してきました。参考文献はY Combinator。なるほど、上のコードでは元の関数maxStepがmaxStepを呼んでいる部分をf fで置き換えているわけですが、それをf fではなくfで置き換えることを可能にするのがYコンビネータのようです。というわけでYコンビネータを使ったバージョン。

(((λ(Y)(Y(λ(f)(λ(x)(if(= 1 x)0(max((Y(λ(f)(λ(x)(if(= 1 x)0(+ 1(f((λ(x)(if(=(modulo x 2)0)(/ x 2)(+ 1(* x 3))))x)))))))x)(f(- x 1))))))))(λ(g)((λ(f)(g(λ(x)((f f)x))))(λ(f)(g(λ(x)((f f)x)))))))100)

λを1文字として195文字ですね。Yコンビネータのせいでかえって文字数が増えています。


__ Schemeって面白いですね…。

(((lambda(▽^)((lambda(>_<)(>_<(lambda(f)(lambda(^x^)
(▽^ ^x^ 0 (lambda () (max((>_<(lambda(f)(lambda(^x^)                          
(▽^ ^x^ 0 (lambda () (+ 1(f((lambda(^x^)(▽^ (modulo
^x^ 2)(+ 1(* ^x^ 3))(lambda()(/ ^x^ 2))))^x^))))))))^x^)
(f(- ^x^ 1)))))))))
(lambda(-^)((lambda(^)(-^(lambda(b)((^ ^)b))))
            (lambda(^)(-^(lambda(b)((^ ^)b))))))))
(lambda (a b c) (if (= a 1) b (c))))100)

なんか癒されます。λを^で代用する書き方もあるそうですけど、^^にすると顔文字が作りやすそうです。(lambda (x) (+ x 1))が(^^(^x^) (+ ^x^ 1))になります(笑)


__ 404 Blog Not Found:LLR2006 - Round 2, まだまだいくよ~

これなのだが、h(100)ではなくg(h(100))を解いてしまう。

最大のステップ長を求めるんではなくてステップ長が最大になる値を探すんでしたね。勘違いしていました。修正すると以下のようになります。

f = lambda x: x == 2 and 1 or f(x % 2 and x * 3 + 1 or x / 2) + 1; max(((f(x),x) for x in range(2, 101)))

これで最大の値とその位置が(118, 97)と出力されます。空白を削ると87文字ですね。もし「g(h(100))を出力せずにh(100)だけを出力しろ」という場合には末尾に[1]をつけてください。

キミならどう書く 2.0 - ROUND 2に食指が動かない件。

キミならどう書く 2.0 - ROUND 2 - — Lightweight Language Ring

def collatz(x):
    if x % 2:
        return x * 3 + 1
    else:
        return x / 2

def numStep(x):
    count = 0
    while True:
        x = collatz(x)
        count += 1
        if x == 1:
            break

    return count

def bruteForce(x):
    return max(map(numStep, range(2, x + 1)))

from time import clock
startTime = clock()
print bruteForce(100) #-> 118
print clock() - startTime #-> 0.016sec

startTime = clock()
print bruteForce(10000) #-> 261
print clock() - startTime #-> 1.9sec

えー。とりあえずプロトタイプを作ってみたのですけど、特に高速化したいという欲求が起きないです。 かといってこんなコードじゃエントリーする気もわきません。

任意の正数 N = 2 ** n - 1 について とりあえず g(k) = h(N) たる k は必ず [x ^ N for x in range(2 ** (n - 1))] の中に存在する。 でもこれじゃぁ大してクールでもなんでもないしなぁ。うーん、萌えない。 PythonでweaveしてみるとかもぜんぜんLLじゃないしなぁ…。Brainf*ckで作るのは二番煎じだし…。


__ とりあえず高速化には萌えなかったので短いコードにチャレンジしてみたら75文字で書けました。でトラックバックをしたのですけど、また2回トラックバックしてしまった…orz

2006年07月11日

日記

体調不良。

頭が重くて痛くて、どうしたんだろうなぁ、と思っていたのですが、 原因はおそらく冷えによる緊張性頭痛です。

自分の体調不良とその解決法を整理してみます。

  • 酸欠
    • 窓を閉めたまま長期間作業をしていないか?
    • 症状:だるさ、倦怠感、やる気がでない
    • 対処:換気、散歩
  • 脱水
    • 十分な水分補給を行っているか?
    • 炎天下で長時間歩いた場合、熱のある場合、寒気がしたので暖かくして寝た場合
    • 何も出ない吐き気、めまい
  • 脱塩
    • 水分補給が過剰ではないか?
    • 症状:食欲不振
  • 冷え
    • 暑い、汗をいっぱいかく、汗が乾かなくてじっとりしている
    • 暑いのに寒い、寒いのに汗が出る
    • 手足がほてっているけど二の腕などが冷たくなっている
    • お風呂やシャワーでお湯に触れた瞬間寒気が走る、鳥肌が立つ。
  • 緊張性頭痛
    • 冷房で冷えていないか?カバンが重すぎないか?
    • 頭が重い、痛い、立ち上がるとめまいを感じる
    • シャワーを浴びる
    • 経皮消炎鎮痛剤を使う
  • エネルギー切れ
    • 症状:吐き気、倦怠感、頭痛
    • 最後に糖質を取ったのはいつか?
  • ぷち過食症
    • 症状:パソコンをしながらお菓子をむさぼり食い始める
    • 対処:とりあえずガムを口に入れる。出さない。
  • ビタミンB群不足
    • だるさ、倦怠感、食欲不振
  • 眼疲労
    • 目が疲れる。頭の前半が痛い。
    • モニターの明るさと周りの明るさがアンバランスでないか?
    • 特に人と共用のモニタの場合、モニタが明るすぎないか?
    • 特に慣れない場所での作業の場合、視界に窓など明るい物が入っていないか?
    • CRTの場合は目を保護するためにめがねをかける。
    • 冷房による乾燥も一因
    • 冷房や送風機の風が顔に当たる環境も良くない

まぁ、最後の方はおまけですけど、前半に関してはこのそれぞれがお互いに絡み合っているから複雑ですね。暑いのを放置しすぎると脱水を起こしてしまい、冷房をかけすぎると今度は冷えてしまいます。水分もないと脱水を起こす(これは頻度高い)けども、取りすぎると食欲がなくなります。大学生時代に一度1日にペットボトルのお茶を4本飲むのを数日続けたことがあって、その時は塩分が不足して大変でした。逆に言うとそこまで変なことをしない限り塩分不足にはならないんですけども。

もう一つ思いつきました。

  • カフェイン摂取過剰
    • 作業しながらカフェインを摂取した場合に陥ることが多い
    • うまく行っている間は仕事がはかどる
    • ひとたび歯車が食い違ったら猛烈な勢いで空回りが始まる。
    • 予防:カフェインを取りすぎないことが重要。
    • 対処:鎮静剤か、テアニンの豊富な雁がね茶or玉露を飲む

ドライアイの予防にはモイスチャーエイドというめがねに取り付けて乾燥を防ぐ物があるそうな。これなら風が目に入る環境でも大丈夫ですし、よさそうです。

サンバイザーを買おうかなぁ。

サンバイザー/ 綿ツイル生地には刺繍を入れられると書いてあったので、僕だったら何を入れると面白いかとしばらく考えたあげく「Just Another Python Hacker,」にしようと思ったのに、字数制限オーバーでした。うぐぅ。

そして頭はまだ痛い。


__ 写真を撮ってみました。

顔修正後
posted from フォト蔵

これは顔写真です。

顔修正前
posted from フォト蔵

これは無修正の顔写真です。

mixiで写真修正の仕方が書いてあったのでGIMPで試してみました。とりあえず消したいシミとかはないのでほくろとにきびを消してみたのですけど、上の方が若く見えるかな?どちらかをプロフィールの画像に使えと言われるとやっぱり上の方を選ぶかなぁ。

方法としては、写真をぼかした物を半透明で上に重ねて、目などの輪郭がはっきりしているべき所だけを切り抜くものです。ということは、この方法で修整された写真かどうかは次の2点に注目すれば見抜けるかも知れませんね。一つめは「ぼけているはずのない物がぼけていないか」。上の例ならば、目の輪郭がぼけていないのに額にかかる前髪がぼけているのはおかしいわけです。面倒だったので髪の毛は切り抜きませんでした。もう1点は「ぼけている物が顔の周辺だけクリアになっていないか」。もし髪の毛もきちんと切り抜いたとすると、髪の毛に交差している背景の線が髪の毛の付近だけクリアになるはず。

あ、でもお見合い写真とかは普通背景に物が写らないからこれじゃ判別できないのか!一色の背景で撮影して、服や髪の毛まで全部切り抜けば判別はできないんでしょうか…。

高周波成分だけ通すフィルタをかけたら修正された部分と修正されていない部分の間にわかりやすい境界が出ないかなぁと思ったのですが、でないですね。そんなことよりそのフィルタの結果がタブレットでなぞってくれと言わんばかりだったので久しぶりにArtRageを使ってみました。

sketch1.jpg

普通にトレスしてみたけど面白くなかったので目を3倍にして鼻を10分の1にしました(笑)

ついでにAlias Sketchbookで色を塗ってみたのが下。

sketch2.jpg

わはは。なんで瞳が緑なんだとかつっこむのは禁止!(笑)


__ 意外。最近しばらくJavaとPythonばっかり使っていて、多くの人に「JavaとPythonを使う人(っていうかJython使い)」と思われているのですが、その「最近」ってのは意外と短いようです。2004/09/03 13:24:52に書かれた日記には

あー、やっぱJavaを勉強しようかな(こうしてRubyの勉強がどんどん後回しになる)

そうか、しばらくDelphiを封印して、今までのDelphi+Pythonでの開発をJava+Pythonでやるようにしてみればいいのかな、Jythonもあるし。

なんて書いてあるので、Jython歴はまだ2年に達していないようです。意外意外。つまり今から2年後に僕がC#とかIronPythonとか使っていても何もおかしくないと言うことですね。っていうか2年前から「Ruby勉強しなきゃ」って言い続けてるのか自分…。

2006年07月10日

Schemeで双方向リスト

今日の帰宅車内ハック。といっても武蔵野線は混んでいて座れなかったのでりんかい線の中だけなのですけど。先日作った双方向リストに見やすい表示機能をつけて、Dancing Linksのremoveとrestoreを実装しました。 肝心の双方向リストのソースコードがなくなっていてうちひしがれかけたのですけど、改めて書いてみるとすんなり書けてしまいました。やっぱり最初に作るときが一番大変ですが、一度できるとできたときの「Aha!」によって重要なところは脳に刻み込まれるのでソースがなくなってももう一度作ることができるわけです。そんなことはどうでもいいか。

(define (doublyLinkedList x prev)
  (if (null? x)
      ()
      (let ((c (cons (car x) (cons () prev))))
        (set-car! (cdr c) (doublyLinkedList (cdr x) c))
        c)))

(define dl (doublyLinkedList '(1 2 3 4 5) ()))
  
(define (getPrev x)
  (cdr (cdr x)))

(define (getNext x)
  (car (cdr x)))

(define (print x)
  (define (_print x)
    (if (null? x)
        (display ")")
        (begin
          (display " ")
          (display (car x))
          (_print (getNext x)))))
  (display "(")
  (display (car x))
  (_print (getNext x)))

(print dl) ;-> (1 2 3 4 5)
(print (getNext dl)) ;-> (2 3 4 5)

(define (getNth x i)
  (if (= i 0)
      x
      (getNth (getNext x) (- i 1))))

(define three (getNth dl 2))
(print three) ; -> (3 4 5)

(define (setRight x y)
  (set-car! (cdr x) y))

(define (setLeft x y)
  (set-cdr! (cdr x) y))

(define (remove x)
  (let 
      ((right (getNext x))
       (left (getPrev x)))
    (setRight left right)
    (setLeft right left)))

(remove three)
(print dl) ;-> (1 2 4 5)

(define (restore x)
  (let
      ((right (getNext x))
       (left (getPrev x)))
    (setRight left x)
    (setLeft right x)))

(restore three)
(print dl) ;-> (1 2 3 4 5)

log

だいぶマルチスレッドがわかってきた気がします。 とりあえずは描画部分とXML-RPCでの追加・修正部分に同じmutexを使ってロックをかければ問題は起きなくなるはずです。で、問題を起こさなくするだけならこれで構わないはずですけど、もう一歩進めるとレンダリングを止めずにXML-RPCを使ったときに頂点の追加がゆっくりなのを解決することができそうです。現状では、クエリーを投げる側もシングルスレッド、受ける側もシングルスレッドなので「一つクエリーを投げる→整形orレンダリングエンジンがlockしているのでしばらく待つ→unlockされたので頂点を追加する→もどる→次のクエリーを投げる→またlockされているので待つ…」となっていたわけです。間にもう一つバッファになるスレッドを作ってやり、それがレンダリングの終了をwaitすればいいわけです。

結論から言うと、先日XML-RPCのバッチ処理をサポートしたのはネットワークが律速段階である場合の解決だったということですね。


__ JAVAで自前で動画をBMPで出力すると、フレームレートが1.5位になってしまって実用的でないという結論になってしまいました。この機能にそんなに時間をかけるのもアレなので、モニターの前にカメラを置いて撮影とかでいいかなぁ、とも思っています。

[Jython]Javaで定義されたフィールドを名前の文字列で取得する方法

SWTでは、たとえばSHIFT+CTRL+F5をメニューのアクセラレータに指定するには

from org.eclipse.swt import SWT
menu.setAccelerator(SWT.SHIFT + SWT.CTRL + SWT.F5)

というようにおのおのの値を足しあわせてやる必要があります。しかしいちいちSWTと書くのは面倒ですし、 from org.eclipse.swt.SWT import * とやってSWTパッケージの中身を全部取得してしまうのはスマートではありません。そこで "SHIFT+CTRL+F5" という文字列を"+"でsplitして、"SHIFT"という文字列からSWT.SHIFTの値を取得しようと思いました。

Pythonでは、あるパッケージ X の中にある name という名前のオブジェクトは X.__dict__[name] で取得することができます。しかしJythonでこれをやると、オブジェクトは取得されますが、フィールドが整数であっても取得されたオブジェクトはPyIntegerではなくPyReflectedFieldです。_dogetを呼んでPyIntegerを取得してやる必要があります。

下のコードでは、"CTRL+SHIFT+O"などという文字列がaccelに入っている場合に、 SWT.CTRL + SWT.SHIFT + ord("O") をメニューmenuのアクセラレータに指定し、与えられた文字列自身もメニューに表示します。

	if accel != "":
		from org.eclipse.swt import SWT
		intAccel = 0
		for key in accel.split("+"):
			if SWT.__dict__.has_key(key):
				v = SWT.__dict__[key]._doget(SWT)
				intAccel += v
			else:
				intAccel += ord(key)
		
		menu.setAccelerator(intAccel)
		menu.setText(text + " " + accel)

日記

ソースコードが行方不明。やっぱり公開しても問題のないソースコードは公開しておくのがいいのかなぁ。 DLLDLLstdcallつけるの忘れてたとりあえず @ NISHIO HIROKAZU # Archived COREBlog。記事はググればすぐに見つかったのだけど、肝心のシステムフック部分のコードがない。家に帰って外付けHDDの中を探せばどこかにあるかも知れない。

Mac miniにはキーボードとトラックボールとモニタを繋いで一応使える状態にはしました、が、いったい何をしていいやら。繁体字中国語入力モード(pinyin)にして中国語を入力できることを確認しました。中国語を勉強するのには便利ですね。ピンインを打って、正しくなければ候補に目的の漢字が出てこないですから。中国語の文章を書くのにも(あたりまえだけど)日本語で「われ、ある、いち、こ、いもうと、いもうと」なんて書くのに比べて圧倒的にスムーズ。妹はmaiじゃなくてmeiですね、今書いていて気づきました。

この方法では四声がわからないじゃないか、と日本の中国語学習者は思うのかも知れないですけど、実際問題として向こうの人は四声を意識していないみたいですし、まぁいいかと。あ、Show Input Keysにチェックを入れると四声も表示されるようです。解決。

ああ、入力の入のピンインがわからない…。漢字を入れるとピンインが出てくる辞書ソフトを探すことにします。


__ スレッドまわりを勉強中。 ConcurrentHashMap (Java 2 Platform SE 5.0)の「putAll や clear などの集計操作では、同時取得は一部のエントリの挿入や削除だけを反映します。」はおかしいですね。原文をチェックしてみると「For aggregate operations such as putAll and clear, concurrent retrievals may reflect insertion or removal of only some entries.」と書かれているのに、mayのニュアンスがまるっきり無視されています。「putAll や clear などの複数個一括操作と同時に取得を行った場合、一部のエントリの挿入や削除だけが反映されている状態を返すことがあります。」ですかな。

これはまだしも「また、構築後の変更を反映することも可能です (ただし保証されてはいない)。」はまずいように思う。「and may (but is not guaranteed to) reflect any modifications subsequent to construction.」なので「構築後の変更を反映することがあります(ただし保証はされていません)」でしょう。僕なら「だから構築後に行った変更が反映されていることを期待してコーディングをしてはいけません」と続けます。

EclipseでHashtableとかのソースを見られるようにするのは意外と簡単でした。System.out.printlnなんかをCtrl+Clickして表示される「ソースコードが添付されていません」というエラー画面で添付ボタンを押し、JDKの中にあるsrc.zipを指定するだけ。なるほど、確かにVector#addはsynchronizedだけどArrayListはそうではない。でaddとgetの両方のメソッドにsynchronizedをつけているのでmutexをインスタンス自体にしてロックをかけてしまい、get同士でもロックが発生してしまうというわけですな。

2006年07月09日

日記

あー。ダメだ。アルマジロは禁止!

この前YouTubeに乗せたアルマジロ動画にコメントがついている。日本語で言えば「ちょっと予算オーバーしてるんじゃない?」という感じのコメントなので「予算を超えてないのをアップすると他の人の解く楽しみをスポイルするじゃん?」は「ネタにマジレス」っぽい。ユーモアにユーモアで返すには何がユーモアとして取られるかという相手のメンタルモデルを推測する必要がある。難しい。「Can I refuse the payment?」と「I refuse the payment.」のどっちがユーモラスなんだろうか、とか、そもそもこれってユーモアだと理解してもらえるんだろうか、とか、難しい。あー、相手がbudgetを使っているんだからこっちがpaymentを使うのはおかしいのかも。じゃぁ「It's not the budget of my company.」かなぁ。

対人コミュニケーションがプログラミングより難しいところは、うまく行ったかどうかがわかりにくいところだと思う。プログラムならおかしいことをすればちゃんとエラーメッセージが帰ってくるけど、対人の場合はおかしいことをするといつの間にか対人関係が壊れている。プログラムで言うなら、間違ったプログラムを実行するとコンピューターが壊れるようなもの。


__ もう日曜日の午後5時…。なにやってんだ自分。


__ 首輪型クーラー - Engadget Japanese 首を冷やすといいのか…。凍らせた保冷剤とかで…。


__ 部屋の写真を撮ってはてなで「部屋を片付けたいのだけど何から始めるべきでしょうか」とか質問してみようかと思ったのに、USBカメラの土台が行方不明で探しているうちに結局やりそこね。 部屋が散らかっていると「部屋を片付けなきゃ」というプレッシャーで土日に有益なプログラムを書くことができない。これは大問題だ。至急メイドさんに片付けて貰わねば!(結論おかしい)

神奈川県の別荘のお掃除・片付け・洗濯・庭仕事などの家事代行・ハウスクリーニングサービス、2時間5000円。家事代行サービス メイドサービスのサマンサ 「料金体系」3時間9000円。

逃避とは何なのか。より優先度の高いタスクがあるにもかかわらず、優先度の低いタスクを先にしてしまう行為。なぜ逃避が起きる?「ゴールへ到達する方法」がはっきり見えているタスクの方が「ゴールへ到達する方法」の不明瞭なタスクより開始しやすい?複数のタスクが「こっちを先にやれ」と主張している場合に、どちらから始めるかの決断ができない場合に別のことをしてしまうケースがある。

TODOは実行可能な物を書くもの。 実行可能って何? 実行時間を見積もることのできるもの? 例えば「英語を話せるようになる」はTODOではない。 「どうすれば解決できるか考える」もTODOではない。 「話せるようになる」の定義は?「解決」の定義は? その定義が終了条件。 話せるようになるには「何をする?」これが真のTODO。

「思いつく」は実行可能じゃない。じゃぁ何か。 結果がいつ帰ってくるかわからない人に仕事を依頼したようなものか。 脳の中のコビトさんに任せる。 人に何かを任せた場合、誰に何を任せたかということはきちんと記録しておいて、時々進捗を確認する必要がある。

たくさんのTODOの中で何を優先するか 優先しないでいい「空き時間でやることリスト」を作ることが、 細かな空き時間を有効活用するコツだと述べている本は複数ある。 ただ、どれくらいの粒度の物をそのリストに入れるのが効率的かは、 それぞれの人のライフスタイルによって異なるだろう。


__ 明日はMac mini。でもMacは初めてだから何をしたらいいかわからないかもな。

2006年07月08日

日記

昨日はポータブルプレイヤーを忘れました。

奈良のジョーシンは注文して1ヶ月半後に「入荷しました」と電話を受けて取りに行っていたのですが、こっちでは昨日ラボに行ったら机の上にあったのでびっくり。そんなにすぐにくるとは思っていなかったのでMac miniがきたのにUSB接続のキーボードがなくて使えない…。とりあえず今日キーボードを買いに行くとしましょうかね。


__ キーボード買ってきました。ついついよけないアイテムもいくつか買ってきたのですが、その話はアイテム行使時に。

最近豚丼にはまってまして、でも外食の豚丼は野菜が少なく、ちょっと野そ菜を足したりボリュームを増やしたりするとすぐに値段が跳ね上がるので自分で作ることにしました。 レシピ集 タマネギ1/2個って書いてあるのに、4つ入りしか売ってなくてそれを買ってきたのですが、よく考えたらネギが丸1本残っているのでこれで良かった気もします。両方使ってみます。


__ ちょっと甘すぎたかな。あとつゆだくにしたかったのにつゆが5ccほどしか残らなかった。


__ いま、「ズボンイン」がアツい! と言いたい | エキサイトニュース そんなこと言われてもなぁ。僕がシャツをズボンに入れてもファッショナブルじゃないし。


__ 半田ごてがない。実家から送ってもらおうにもどこにあるかわからないし。


__ 噂は噂ですが、ゲド戦記はこの機会に原作を読むことにします。


__ TODOを手帳(紙)にまとめるかデジタルにまとめるか、それが問題だ…。


__ 掃除機を買いました。だいぶ前にヨドバシでパンフレットを貰って、今日ヨドバシで実物と値段を確認してきて、いま検索して楽天のPC-Successで3600円ほど安く売っているのを見つけてぽちっと。 スーパーポイントで掃除機が買えてしまうけど…うーん。なんかポイントを使うのがもったいないとか思ってしまうのはなぜだろう。

楽天カードを切り替えただけで2000ポイントもらえたという話の続編で、2000ポイントを獲得したので「過去6ヶ月で2,000ポイント以上、かつ15回以上ポイントを獲得するとプラチナ会員」という条件に後5回ポイント獲得をするだけで到達するとのことです。プラチナだとどういう特典があるのかよくわかってませんが…。 あ、ゴールドなだけで誕生日に500ポイントもらえるんですねぇ。

【楽天市場】新6月2種類のサンプル珈琲サンプルコーヒーの楽しみ方0529祭10 お試しセット 【父の日2006】:生豆自家焙煎珈琲工房アロマージュは6月30日までか…。まぁ、あわてなくても今月中にあと3回くらいは使うことでしょう。

あ、例の物理演算ゲーム「Armadillo Run」は、日本円の価格表示があってPaypalで買うときに住所を入れさせられたから、てっきり日本のどこかに営業所があってそこからパッケージが送られてくるんだと思ってました。メールでダウンロードURLが送られてきていたとは。今気づきました。

「今気づきました」と言えば、今済んでいるレオパレスは光熱費が込みの家賃なんですけど、今後のために自分がどの程度の電力を使っているのか調べようと思うんです。で、引っ越してきたときに電力を測るくるくる回るやつを見ようとドアの横の物置みたいな所をあけようとして、開かなかったので「ああ、電力計を見るには電力屋さんが持っている鍵がないといけないんだな」と納得していたんですが、今日ドアの斜め上に電力計が出っ張っているのに気がつきましたよ!引っ越してから2ヶ月経って、ついにドアの斜め上に電力計があることに気がつきました!なんで気づかないんだ自分!ちなみに1階に郵便受けがあるのは1ヶ月くらいで気がついたんですけどね。あふれてました。

アルマジロは製品版にはセーブ機能があるようですね。そして製品版のレベルは結構難しい。製品版の一番最初のレベルは自重で崩壊する橋なんですけど、ロープで吊って崩れなくしただけではアルマジロが渡れません。傾きが少なすぎて途中で止まってしまいます。どうやれば渡らせられるか…と。

眠いのに熱中して眠いのにもう朝だ!

JavaでSuffixArray

書いてしまったので一応載せておきます。勉強用のコードなので入力文字列が巨大になったときにどういう挙動を示すかは考えていません。

import java.util.Iterator;
import java.util.Vector;

public class Test {
	static char[] buffer;
	public static void main(String[] args) {
		String input = "abracadabra$";
		Vector<Integer> vec = new Vector<Integer>(input.length());
		for(int i = 0; i < input.length() - 1; i++){
			vec.add(i);
		}
		buffer = input.toCharArray();
		vec = sort(vec);
		for (Iterator<Integer> iter = vec.iterator(); iter.hasNext();) {
			Integer i = iter.next();
			System.out.println(input.substring(i));
		}
	}

	static boolean compare(Integer i, Integer j){
		int w = 0;
		while(true){
			if(buffer[i + w] < buffer[j + w]){
				return true;
			}else if(buffer[i + w] > buffer[j + w]){
				return false;
			}
			w++;
		}
	}

	static Vector<Integer> sort(Vector<Integer> vec) {
		if(vec.size() < 2){
			return vec;
		}
		Integer pivot = vec.get(0);
		Vector<Integer> less = new Vector<Integer>();
		Vector<Integer> more = new Vector<Integer>();
		
		for(int i = 1; i < vec.size(); i++){
			Integer v = vec.get(i);
			if(compare(v, pivot)){
				less.add(v);
			}else{
				more.add(v);
			}
		}
		Vector<Integer> result;
		result = sort(less);
		result.add(pivot);
		result.addAll(sort(more));
		return result;
	}
}

日記

ありゃ、昨日書いたはずの日記がない。保存する前に閉じちゃったかな。

アルゴリズムの授業は難しいですねぇ。課題を出す側は自分で実装することで理解することを求めているはずなのですが、実際は誰か「グループ内でちょっとプログラムが書ける人」がさらっと書いてしまって、多くの人はそのコードを解読して改造して提出するわけです。それを前提に考えると、この「さらっと書かれたコード」がすさまじく可読性が低かったり、いらない変数やねじれた制御構造があったり、SuffixArrayを作るのに、与えられたStringをまずchar[]に変換した上で、部分文字列の比較はもう一度Stringを作ってcompareToを使っていたりとかするわけです。あんまりひどいんでリファクタリングしたくなってそのソースコードを送ってもらったのですが、これをリファクタリングして公開してしまうと僕がレポートを解いたことになるような気が。

うーん。やっぱリファクタリングするのはやめよう。なんか頭が痛くなるくらいすさまじいコードなので、これをきれいにするのも0から自分で書くのも大して変わらない。


__ そうそう、楽天カードを切り替えたら、2000ポイントもらえちゃいました。2000円分。太っ腹。年会費を取らないのにいったいどこからこのお金が沸いてくるんでしょう。


__ 最近、積ん読だった「珠玉のプログラミング」を読んでいるのですが、たとえ話や実話がなかなかいいですね。divide and conquerは一般的になぜか「分割統治法」というイメージの沸かない訳され方をしていますが、この本は「分割して征服する」と書いてあってイメージしやすいですね。大きな集団と戦うより、小さい敵と戦って少しずつ征服していった方が楽と。

2006年07月07日

Javaで破壊的クイックソート

後輩のレポートを僕が解いてしまうと勉強にならないと思って我慢していましたが、レポート内容はクイックソートではなくてそれを利用してSuffixArrayを作ることらしいです。帰りの電車で作ったのでとりあえず貼っておきます。皮の部分は「QuickSort祭り(一人)」を参照。

後輩のレポートにはin placeでvec[i]をvec[pivotPos]の手前に持ってくるためにpivotPos~i-1のすべてを一つ右にずらしていたのですけど、単に「iをバックアップし、pivotPos+1をiに書き、pivotPosをpivotPos+1に書いてpivotPosにバックアップしたiを戻す」でもいいような気がします。

むう、10000件のソートで、非破壊的ソートが32ミリ秒なのに、この破壊的ソートは3515ミリ秒かかって100倍遅い。Vectorである必要性がないので最初に配列に変換してみたけども、それでも351ミリ秒なので10倍遅い。上の段落で書いた高速化を入れて47ミリ秒なので1.5倍遅い。どういうことかな…。

非破壊的ソートではNlogNのメモリを消費して1回の分割でN回読んでN回書いているけど、破壊的ソートではNのメモリを消費して、約1/2の確率で起きる値の移動で3回ずつ読み書きするのでだいたい1.5N回の読み書きを行うと。ソートの対象が十分に小さければ、メモリの確保が大した問題にならないので破壊的ソートに約1.5倍の時間がかかるというわけですかな。で、メモリの確保に苦労するような巨大なリストをソートする場合には破壊的ソートの方が早いかというと…うーん、ひとかたまりの配列として保持しづらいし、何度も同じ所を読むからキャッシュに期待できないし…。

いや、待てよ、上の計算は正しくないか。非破壊的ソートの方はVectorを使っているから、Vectorを使った破壊的ソートと使わない破壊的ソートの比程度のオーバーヘッドがあるはず。だから非破壊的ソートと破壊的ソートの比は1.5倍どころじゃない。

	private static Vector sort(Vector vec) {
		partialSort(vec, 0, vec.size());
		return vec;
	}
	private static void partialSort(Vector vec, int start, int end){
		if(end - start < 2){
			return;
		}
		Integer pivot = vec.get(start);
		int pivotPos = start;
		for(int i = start + 1; i < end; i++){
			Integer v = vec.get(i);
			if(v < pivot){
				// vをpivotの前に移動
				for(int j = i; j > pivotPos; j--){
					vec.set(j, vec.get(j - 1));
				}
				vec.set(pivotPos, v);
				pivotPos++;
			}
		}
		partialSort(vec, start, pivotPos);
		partialSort(vec, pivotPos + 1, end);
	}

log

XML-RPCで投げたマップをMapで受けようとしたら「そんなメソッドはない」と怒られました。 メソッドの引数がHashtableであるようなものをリフレクションで取得しようとするのでシグニチャが異なるとダメなのでしょう。

Schemeで破壊的クイックソート

一応できました。後は非破壊的クイックソートとのパフォーマンスの差を調べてみたいところです。

(define (_move_shift_one head tail)
  (if (eq? (cdr head) tail)
      (begin
        (set-car! (cdr head) (car head)) ; shift one
        head)
      (_move_shift_one (cdr head) tail)))

(define (_move_shift head tail)
  (if (eq? head tail)
      head
      (_move_shift head (_move_shift_one head tail))))
  
(define (moveBack src dst)
  (let ((tmp (car src)))
    (_move_shift dst src)
    (set-car! dst tmp)
    dst))

(define (sort! x)
  (partial_sort! x ())
  x)

(define (partial_sort! head tail)
  (let ((pivot (split head (cdr head) tail)))
    (if (eq? head pivot)
        ()
        (partial_sort! head pivot))
    (if (eq? (cdr pivot) tail)
        ()
        (partial_sort! (cdr pivot) tail))))
  
(define (split pivot cur tail)
  (if (eq? cur tail)
      pivot
      (if (< (car cur) (car pivot))
          (begin
            (moveBack cur pivot)
            (split (cdr pivot) (cdr cur) tail))
          (split pivot (cdr cur) tail))))

(define a '(3 2 4 1 5))
(sort! a) ;-> (1 2 3 4 5)

2006年07月06日

日記

INCREDIBLE! 物理演算パズルArmadillo Run:ピタゴラ装置も作れます - Engadget Japanese THE INCREDIBLE MACHINE系のゲームが好きだった僕にはヤバイくらいはまりそうなソフトが出たそうです。最初は「見かけだけ3Dになったのかな」と思ったのですが、用意されているのは基本的な素材だけで、動きは物理シミュレーションで記述されているというインクレディブルなソフトだそうです。THE INCREDIBLE MACHINEとパネキットのいいところ取りみたいな感じかとも思ったのですが、なんと「橋脚が端の重みに耐えかねて破断」なんてことまで起きるんだそうで。

予算を超えて変な物を建築することもできるのがいいですね。で、予算より安く仕上げるとその残額がステージ選択画面に表示され、トータルでいくら安くあげたかがわかります。体験版のLevel1からLevel6まででそれぞれ$18, $130, $102, $70 $124 $112浮かせて合計$556の節約になりました。布が実はさほど安くないというのがちょっと引っかけですね。最小単位は安いんですけど、1単位の鉄板の最長の長さと同じだけ布を設置すると逆に布の方が高くなります。コスト削減のつもりで布で作ったところを鉄板に変えるだけでだいぶ削減できました。

体験版では「ゴム紐のような物」と「バネのような物」、「ロケット」が使えません。値段が高いのであまり使う機会のない「一定時間が経つと設置した素材を破壊するタイマー」と「布やロープを強く引っ張るって設置する機能」などとあわせて使うと動力源が重力だけではない装置を作れるので楽しいでしょうね。

お、Level1の残額が$18から$44に増えてトータルで$582になった。まだまだ効率化ができますねぇ。600の大台に乗せられないかなぁ。

Level5が$170になって、トータル$628になりました。大台に乗りましたし、きりがないのでここらで終わりにしましょう。


__ 夢見がちな解法。

armadillo_run.png

動画@YouTube

予算がふんだんにある建築家って楽しいんだろうなぁと思いました(笑)

パイプはパイプに衝突する、鉄板、布、ロープは通り抜けるが、ロープと他の物のつなぎ目だけは通り抜けない。 ロープは布を通り抜ける、他の物は衝突する。

48, 138, 110, 80, 188, 138で合計$702。ここまで使う資材が少ないと組み合わせ方にも限界があるので点数から解き方を逆算できそうです。使った費用は$52、$62、$90、$20、$12、$112なのでレベル4と5は何をしたか明らかですね。$20が鉄板1枚の値段で、$12が一番小さな布の値段です。


__ 秋元@サイボウズ研究所プログラマーBlog: ギークのためのバーカウンター。 コップが反応しているから赤外線じゃないし、触る前から反応をしているから感圧センサでもないですね。おそらくカウンターの上にカメラがあるんでしょうねぇ。しかし面白いなぁ。

QuickSort祭り(一人)

後輩のQuickSortの課題を見ていて思ったのですけど、QuickSortは分割したリストのために新たに領域を確保していいかどうかによって難易度がだいぶ異なりますよね。高級言語は「QuickSortがこんなに簡単に書ける」なんてことを主張することがありますが、与えられた配列をその配列(+定数サイズ)の領域だけでソートするCとかで書かれたアルゴリズムを「真・クイックソート」だとすれば、新たな領域の確保を伴うQuickSortはちっとも早くないので「似非クイックソート」かもしれません。

で「似非クイックソート」なら簡単に書けるという話題で、ラボから赤坂某所への電車で書いたJavaのコード。

import java.util.Iterator;
import java.util.Vector;

public class Test {
	public static void main(String[] args) {
		Vector<Integer> vec = new Vector<Integer>();
		vec.add(5);
		vec.add(1);
		vec.add(2);
		vec.add(4);
		vec.add(3);
		
		print(vec);
		vec = sort(vec);
		print(vec);
	}
	
	private static void print(Vector<Integer> vec){
		System.out.print("{");
		for (Iterator<Integer> iter = vec.iterator(); iter.hasNext();) {
			Integer element = iter.next();
			System.out.print(element);
			if(iter.hasNext()){
				System.out.print(", ");
			}
		}
		System.out.print("}");
	}

	private static Vector<Integer> sort(Vector<Integer> vec) {
		if(vec.size() < 2){
			return vec;
		}
		Integer pivot = vec.get(0);
		Vector<Integer> less = new Vector<Integer>();
		Vector<Integer> more = new Vector<Integer>();
		
		for(int i = 1; i < vec.size(); i++){
			Integer v = vec.get(i);
			if(v < pivot){
				less.add(v);
			}else{
				more.add(v);
			}
		}
		Vector<Integer> result;
		result = sort(less);
		result.add(pivot);
		result.addAll(more);
		return result;
	}
}

この通り非常に簡単(?) 似非クイックソートは高級言語だとかなり短く書けるのですけど、まぁJavaはそれほど高級じゃないということでしょう。Pythonなら4行で実装できますし。

def sort(a):
    if len(a) > 1:
        return sort([x for x in a[1:] if x < a[0]]) + a[:1] + sort([x for x in a[1:] if x >= a[0]])
    return a

print sort([5,4,1,3,2])

まぁ、冗談はさておきまともに書いても15行程度でしょうか。

def sort(aList):
    if len(aList) < 2: return aList
    pivot = aList.pop()
    less = []
    more = []
    for item in aList:
        if item < pivot:
            less.append(item)
        else:
            more.append(item)

    less = sort(less)
    more = sort(more)
    less.append(pivot)
    return less + more

Schemeだと「リストを結合する関数」と「条件を満たす要素だけを取り出す関数(filter?)」を「車輪の再開発」してもこんな感じでしょうか。

(define (get less aList pivot)
  (if (null? aList)
      ()
      (if (less (car aList) pivot)
          (cons (car aList) (get less (cdr aList) pivot))
          (get less (cdr aList) pivot))))

(define (join list1 list2)
  (if (null? list1)
      list2
      (cons (car list1) (join (cdr list1) list2))))

(define (sort aList)
  (let
      ((less (lambda (x y) (< x y)))
       (more (lambda (x y) (>= x y))))
    
    (if (null? aList)
        ()
        (join (sort (get less (cdr aList) (car aList)))
              (cons (car aList) 
                    (sort (get more (cdr aList) (car aList))))))))

この後、「真・クイックソート」をJavaやPythonで実装すると後輩の目標を奪ってしまうのでSchemeでやろうとしてかなり苦しみました。 一度「一方向の連結リストじゃダメなんじゃないか」と考えて双方向リストを実装してみたり。

(define (makeDoublyLinkedList aList prev)
  (if (null? aList)
      ()
      (if (null? (cdr aList))
          (cons (car aList) (cons () prev))
          (let ((c (cons (car aList) ())))
            
            (set-cdr! c
                      (cons
                       (makeDoublyLinkedList (cdr aList) c)
                       prev))
            c))))



      
(define (getNext dList)
  (car (cdr dList)))

(define (getPrev dList)
  (cdr (cdr dList)))

(define dl (makeDoublyLinkedList '(1 2 3) ()))
(car dl) ;-> 1
(car (getNext dl)) ;-> 2
(car (getPrev (getNext dl))) ;-> 1

僕にとって関数型言語はパズル用言語なので、letやsetを使うのは自分的に禁止だったのですが、この手のモノをやるのには必要不可欠ですね。あと、LispやSchemeは確かにツリー状のモノを扱うのには適していますが、双方向リストのような本質的にループだらけの構造は逆に書きづらいかもしれません。

で、とりあえず破壊的ソートは「与えられたリストのcarをピボットにしてピボットより小さいモノをピボットの前に移動する」って所までできました。あとはピボットの前と後ろとを再帰的にソートしていけばいいのですけど…ここまで書いて設計がまずい気がしてきました。

(define (sort! head tail)
  (if (null? head)
      ()
      (find head (cdr head) tail (lambda (x) (< x (car head))))))

(define (shiftOne head tail)
  (display "shiftOne")
  (display tail)
  (display "\n")
  (if (null? tail)
      tail
      (if (null? (car (cdr tail)))
          (begin
            (set-car! (cdr tail) (car tail))
            (set-car! tail ())
            head)
          (shiftOne head (cdr tail)))))
  
(define (shift wholeList)
  (display "shift")
  (if (null? (car wholeList))
      wholeList
      (shift (shiftOne wholeList wholeList))))
      
(define (find aList start end condition)
  (if (equal? start end)
      ()
      (if (condition (car start))
          (begin
            ; rotation
            (let ((x (car start))) 
              (set-car! start ())
              (set-car! (shift aList) x))
            ; partial sort required
            (find aList (cdr start) end condition))
          (find aList (cdr start) end condition))
      ))

うーん。「リストのこの範囲にこの処理を行う」だとか「この値を手前のこの位置に移動して間の物はずらす」だとかを定義して、それを組み合わせるほうがよさそうです。でももう26時半だしなぁ。

2006年07月05日

RubyのyieldとPythonのyieldの違い

RubyのyieldとPythonのyieldは実は全然違うような気がしてきたので、整理のために書いてみます。 まず、Rubyでeachに相当する物を自分で実装してみました。

# Ruby 1
class Array
  def my_each
    self.each{|x|
      yield x
    }
  end
end

[1, 2, 3, 4, 5].my_each{|x|
  puts x
}

これに相当する物をPythonで書くと、実はyieldを使いません。

# Python 1
class Array(list):
    def each(self, f):
        for i in self:
            f(i)

def myprint(x):
    print x

Array([1, 2, 3, 4, 5]).each(
    myprint
)

これをもっとRuby 1のコードに近づけて書くと以下のようになります。Pythonにはputsに相当する関数がsys.stdout.writeという長ったらしい物なのでputsは自分で定義していますがそこは本質ではありません。重要なのは「引数xを取ってputs(x)を評価せよ」というモノ(Python流に言うと無名関数、Ruby流に言うとブロック)を渡しているということだと思います。

# Python 2
class Array(list):
    def each(self, f):
        for i in self:
            f(i)

def puts(x):
    print x

Array([1, 2, 3, 4, 5]).each(lambda x:
    puts(x)
)

逆にRuby 1の方をPython 1に近づけて書くと次のようになるようです。

# Ruby 2
class Array
  def my_each
    self.each{|x|
      yield x
    }
  end
end

myprint = proc {|x|
  puts x
}

[1, 2, 3, 4, 5].my_each(
  &myprint
)

Python 1 では関数オブジェクトを引数に渡していましたが、Ruby 2ではProcオブジェクトを渡すようです。

さて、ではPythonでyieldを使うとどうなるでしょう。

# Python 3
class Array(list):
    def each(self):
        for i in self:
            yield i

for i in Array([1, 2, 3, 4, 5]).each():
    print i

Rubyと大きく異なる点は、forが必要である点と、eachが引数を取らない点です。Rubyの「yieldを使っているメソッド」は「Procオブジェクトを受け取ってyieldの場所でyieldの後に続いているモノを引数としてそのProcオブジェクトを呼び出す」という働きでしたが、Pythonの「yieldを使っているメソッド」は「なにも受け取らず、ジェネレータを返す」という働きをします。ジェネレータはnextメソッドを持ち、nextが呼ばれるとyieldまでを実行してyieldの後に続いているモノを返り値として返します。ですので、ループを途中で中断することもできますし、中断したループを後で継続することもできます。

# Python 4
class Array(list):
    def each(self):
        for i in self:
            yield i

gen = Array([1, 2, 3, 4, 5]).each()
for i in gen:
    print i
    if i == 3:
        break

print gen.next() # -> 4

Rubyで同じことをやろうとすると、明示的にジェネレータを使って以下のようになります。

# Ruby 3
require 'generator'

g = Generator.new([1, 2, 3, 4, 5])

while g.next?
  i = g.next
  puts i
  if i == 3
    break
  end
end

puts g.next

Generator.newの引数にはProcオブジェクトを渡せるようですので、無限リストはこんな感じに実装できますね。

# Ruby 4
require 'generator'

def makeList
  Generator.new{|g|
    i = 0
    while true 
      i += 1
      g.yield i
    end
  }
end

g = makeList

while g.next?
  i = g.next
  puts i
  if i == 3
    break
  end
end

puts g.next

PythonでRuby 4に相当するコードを書くとこうです。

# Python 5
def makeList():
    i = 0
    while True:
        i += 1
        yield i

gen = makeList()
for i in gen:
    print i
    if i == 3:
        break

print gen.next() # -> 4

Rubyでは引数gにProcオブジェクト?を受け取っているようですね。Pythonではジェネレータの時には省略できて、Ruby風のループ抽象(イテレータ?)を行うときには省略せずに引数fに関数オブジェクトを受け取っていました。Rubyではちょうど逆ですね。面白いです。

2006年07月04日

log

頂点と辺のリストが分かれている必要があるか、という物理演算の対象での疑問点について。 一つのリストにまとめる必要はないが、別々のVectorとして実装されているのには問題がある。 例えば今、modVertex, modEdge, modLawという3種類のよく似たインターフェイスがあるが、これはVertex, Edge, Lawがそれぞれ別個のVectorとして宣言されているからに他ならない。これらが一つの「名前をキーとしリストを値とするマッピングオブジェクト」に入っていればmodify("Vertex", vertexID, params)というように一つの窓口に集約できる。

「一つの窓口に集約できる」のはいいが、集約する必要はあるのか?これはYesだ。ここで修正しておかなかった場合、物理演算の引数として渡される名前付きリストの作成の実装をするのにも3つのコードクローンが発生する。将来的に他の場所で問題を発生させないとも限らない。設計の不備は早めに直しておくべきだ。

現状で、Vertexだけ名前と頂点のマッピングであり、EdgeとLawはただのリストだが、これは全部マッピングにすべきか。少なくともそうすれば「デフォルトの物理演算で3番目に設定されているバネの力の係数をいじるためにget(2)する」なんてバッドノウハウはなくなる。名前で取得できるから。

LawをVertexやEdgeと同格にしたら、Aggregatorクラスが持つフィールドがなくなったのでaggregateメソッドをGraphクラスに移動してAggregatorクラスは削除。

gettextって、同綴異義語があったらどうするんだろうね。

剛体制約は問題なく動いていますな。回転速度の係数くらいいじる必要があってもおかしくないのに一発で動いてむしろびっくり。でもこれは画像を貼っても面白くないので撮るなら動画ですねぇ…。やっぱり動画か…。

HashMapは同期化されない、と書いてあるからHashtableは同期化されるんだと思っていたのですが、ConcurrentModificationExceptionが送出されるケースはあるようですね。synchronizedしないといけないんですかねぇ。そういう手間がないんだろうと思ってHashtableを使ったんですが…。

剛体制約と壁張り付き制約を両方入れると粘っこい壁にスポンジをこすっているような気分。やっぱ動画か…。

画面外に頂点が出ないようにする制約も作りました。

JSONとXML-RPCの出入り口を共通にするのはどちらもJavaオブジェクトを直接触ることができないからいいのだけど、Jythonまで共通にしてしまうとせっかくのJavaオブジェクトを生で触れるメリットが失われてしまいますね。三層構造。

物理演算の対象になる頂点を保存する場合にどうするか。名前のリストで保存するのはてっとりばやいが、とりあえず辺や頂点などで重複する名前がないように保証する必要がある。あと、そういう形で保存した物をロードして新しい頂点を追加したら、新しい頂点に物理演算が働かないのが自然ですな。それは使い勝手が悪い。SpringEdge("allEdge")というように名前付きリストの名前で参照する方法なら、後からリストの内容が変化しても問題はなさそう。数の少ないハッシュから引いてくるだけだから大したオーバーヘッドにもならない。この場合、物理演算が対象の名前を覚えておくか、対象から名前が引けるか、どちらかが必要になると思う。名前付きリストを文字通り「名前とリストがくっついたオブジェクト」にしてしまえば後者の条件が満たされるが…。

各頂点を名前付きで作成した後でanchoredListにその名前を入れていくよりは、各頂点にanchoredという属性をつける方が自然。Vertexなどに「存在しないプロパティ」をセットした場合にはHashtable Vertex#propertiesに値が入るとか。それならanchoredも頂点作成時にparams = {"anchoredPos": (0, 0)}と自然に書ける。うむ。これがよさそう。

TODO

自分宛のメッセージ

  • TODOは「実行可能なこと」を書くもの。
  • 凡例
    • \*+\d+: 優先すべきタスク。優先度は星の数、\d+は一意な数値
    • d\d+: タスク\d+に依存している。タスク\d+を優先して片付けるべき。
    • s: 何らかの理由で延期中。(おそらくdなのに依存しているタスクがTODOに書かれていない、がやらないことに決めているタスクを詳細に記述することに時間を割く必要性はない。sは「今はこれに時間を割く必要がない」という意味)
  • 忘れずにいるべきこと
    • CommonGatewayクラスはXML-RPCやJythonなどから叩くことの出来る共通のインターフェイス
    • MediatorクラスはJythonやJavaなどの直接POJOを扱えるものから、よりダイレクトに(Javaの型の情報などを利用して)操作するためのインターフェイス
    • ユーティリティ的なメソッドはユーティリティクラスにまとめるべき
    • InvocationTargetExceptionはgetCauseする。XML-RPCで何か失敗して例外が起きたときに、例外を見て何が起きたか推測できるように、なるべく情報を出すべき。
    • XML-RPCのライブラリがリフレクションで引数がHashtableのメソッドを探すので、CommonGatewayの引数の型がHashtableのところをObjectに変えるとXML-RPCが動かなくなる。
    • FLASHを作るときはnon-stopバージョンとstep-by-stepバージョンの両方を作る。non-stopはぼんやりどんなことが出来るのかを眺められるように、step-by-stepは試しながら1歩1歩進めるように。
    • あちこちに書き散らすと後で大変なので、新しく思いついたアイデアは必ずここのinboxに書く。

TODO

INBOX: 未整理のタスク

  • レンダリングエンジンを切り替え可能にする
    • CommonGatewayからそれを変更できるようにする
    • init.pyでそれを設定
  • Zオーダーのあるレンダリングエンジン(デフォルトEdge:0 Vertex:1)
    • makeDictとsetZOrder, getZOrderをつける
  • http://www.genpaku.org/other/eclipse/plugin_architecturej/plugin_architecture.html 読む
  • http://pyunit.sourceforge.net/pyunit_ja.html 読む
  • json.simpleのライセンスを調査。使い続けるかやめるか検討する。
  • ローカルのGRINEditで保存した物をFTPでサーバにアップロードしたら、ウェブページ上のアプレットでも同じ物が見える
  • http://wiki.python.org/jython/ReadlineSetup
  • 現在のgetParamsは値がデフォルトかどうかにかかわらず全部の値を返しているので、それを保存や通信に使うと量が多い。
    • デフォルトと異なる量だけを返すgetParamsSimpleをつける?
    • JSONを圧縮した状態でも読み書きできるようにする?
  • 出力されたJSONを人間に読み書きしやすい形に変えるPythonスクリプト
    • positionとかを削除するオプション?
  • drag & drop されたファイルの拡張子がpyの時はスクリプトとして実行する?
  • XML-RPCでのaddやdel、modのクエリーを即座に実行しようとするとレンダリングや描画のスレッドがロックしているので応答性が悪くなる。
    • 変更を伴うクエリーをためておくスレッドを1つ作る。このスレッドはwaitし、レンダリングの終了時点でnotifyされる。
  • PythonのxmlrpclibでGRINEditから文字列を取得するとUnicodeで返ってくるのに、GRINEditにUnicode文字列を投げると化けてSJISならOK。xmlrpclibが余計なことをしているのかな??投げるときに....encode("sjis")とやればいいだけではあるけど。
    • Jythonコンソールで日本語を打つこと自体は出来るけど、頂点のラベルに日本語を指定すると化けるのも同じ現象か?
    • 調べる
  • 名前空間をフラットにする必要はないが、全部のオブジェクトが入っている名前空間があるべき。
    • grinedit.addObject("Vertex", "vertex1")みたいに名前で参照して追加できるように。
    • 現在は選択された頂点はSelectionというレガシーなものに入っているけど、これをVertexやEdgeやLaw同様にHashtableに入れてXML-RPCからアクセスできるようにすべき。
      • 今はJavaとJythonからしかアクセスできない。
    • この両方をやったら grinedit.addObject("SelectedVertex", "vertex1")みたいな方法でXML-RPCから頂点の選択が出来る。
    • grinedit.newTable("Hoge")してgrinedit.addObjects("Hoge", ["v1", "v2", "v3", ... ])する?
  • グラフをシリアライズして復元したときに、内部でオブジェクトの管理のために振られている一意なnameフィールドの値が変化する。これでいいのだろうか?将来的に何か問題を起こしそうな気はするけど、逆にこれでいいのかも知れないという気もする。一意でないと行けないnameフィールドを元通りに復元するなら、グラフのマージとかはできないわけで、元通りに復元しないことを前提として頂点のnameがどう変わったかの対応付けをするようにしたほうが結果的に色々いいかもしれない。
  • 入れ子頂点
    • 入れ子頂点は親と子の位置がかっちり固定されているよりも、子供の頂点が動けるほうがいい。まるくて、中にはいるべき頂点の重心が自分の中心であり、最も遠い頂点までの距離*1.1くらいが半径であり、中に入るべき頂点には中心からの距離に比例した引力を持ち、中にはいるべきでない頂点には半径*1.1以内に入らない制約。つつむ頂点の中に入っている普通の頂点は引力で緩やかに拘束されつつ外の頂点との辺による引力で位置を変えたりする。いくつかの頂点が複数の親に属しているとベン図みたいになりそう。これはそういう構造にするためのUIがちょっと難しそう。
    • 中に入らない制約の反作用を親の頂点が受けるべきか。たぶん基本的に全ての力は反作用を持つべき。でももし持たないならドラッグドロップが簡単にできるかも。
  • 頂点は物理演算になれないが、でも描画したい物理演算もある。頂点と呼んでいた物は実は「インターフェイスIRenderableを実装したクラス」であるべきなのではないか。辺もIRenderable。でも辺の接続する頂点として辺を指定されるとイヤ…でもないのか…うーん。追加できないのがイヤという可能性もある。
    • グラフの要約機能や動的に開いたり閉じたりは需要がある。
  • たかだか300頂点で15FPSまで落ちてしまうことがある。長い紐状のグラフがぐるぐる巻きの状態になってしまったときに、外側の頂点の拡散を辺の引っ張る力が邪魔をするために、頂点が密集した負荷の高い状態が持続してしまう現象。
    • デフォルトの物理演算は、イヤならはがせるわけだから、機能てんこ盛り路線でいいのかも。それなら「反発力がなかなか減らないときには拡散を加速する」という物理法則を入れる手がある。
  • setter/getter生成スクリプト
    • PythonをインストールしなくてもいいようにJythonで動かす?
      • Developer向けプラグイン?
  • ActionScript?
  • GRINEdit よくある失敗 をFAQに変える
  • 西尾泰和のブログ: オフラインミーティングのログ
  • 西尾泰和のブログ: log入れ子頂点の考察
  • ニーズ:FreeMindみたいにInsやEnterで頂点追加するため
    • キーイベントのリスナをプラグインから登録
    • リスナはフラット?
      • もし衝突が起こったら?
    • 特定の条件の時だけアクティブなリスナ
      • リスナ自体は常にアクティブで、特定の条件ではないときにはイベントをドロップするほうが適切な設計かも知れない
  • 辺や頂点を作成するときのためのテンプレート?
    • チュートリアルがあればテンプレートはいらない?
  • ツリーを見栄えよく表示するための初期配置
  • ツリーの兄弟の順序を保つための制約
  • ツリーの兄弟の深さを保つための制約
  • 「それGRINEditで(ry」
    • sodaplayをGRINEditで
      • 位相と振幅をパラメータに持つ「周期的に自然長を変える辺」
      • 自然長タイプのバネの力(既存)
      • 壁制約(既存)
      • 壁に当たったときに振動を逆方向にするもの
    • sodaconstructorをGRINEditで
      • 編集モードと実行モード(物理演算セットの切り替え)
        • pauseしてdelLaw、addLawで一応出来る
      • クリック、ドラッグで頂点や辺を作成するMouseOperation
      • 辺の選択
      • サイドパネル
        • サイドパネルの操作で選択されている辺のパラメータを変更
    • 音声認識でタグクラウド
      • リンクは少なめに張った方がいい。
      • しゃべった後、散らばった頂点を眺めてリンクを張る。発散と収束のプロセス。
    • NarVisualizer
      • Listlike、DictLikeの頂点
        • 親頂点から子頂点への矢印の接続点が、中心を指さないことがちょっと違う。
        • 「複数の頂点が貼り付いている」という実装では矢印が箱の間の壁を指したりして都合が悪そう。やはり「接続位置が指定されている頂点」という実装が正しそう。
      • 根からたどれなくなった&画面外に出た頂点の消去
    • TouchGraph
  • プラグインからSWTのGUIを出す際にswt.jarやswt.dllがどういう扱いになるか?
    • デフォルトのGUI自体をプラグインにしてしまえば、追加のGUIとswt.jar、swt.dllの関係を悩む必要はなくなる
  • 操作マニュアルの自動生成
    • MouseOperationインスタンスはメニューに表示する文字列を持っている
      • メタキーによる修飾をサポートしたので機能がメニューに書ききれない
        • 機能説明の文字列も持たせる
  • 頂点の中の文字列も動的に書き換えたい
  • グラフをネットワーク越しに共有して複数人で同時に編集できるようにしたい
    • サーバで物理演算をやって、クライアントはその結果を受け取って表示するだけにするか。
    • JythonやXML-RPCではない操作も全部CommonGatewayを通すことにして、そこでサーバと通信する?
      • 全部まとまっていて楽そうだけど、パフォーマンスはうなるだろうか?
  • plugin関連
    • 「無視するプラグイン」ファイルをpluginsフォルダに?
    • 能動的プラグインのロード
      • 「あるプラグインがすでにロードされている必要性のあるプラグイン」ってあり得るかな?問題になりうるかな?
      • 最悪Pythonスクリプトで「起動に必要な条件が整っていなければ自分自身をwaitsetに入れる」とやって、プラグインのロードが完了するたびにnotifyAllすればいい。
        • 全部終了しても起動条件が満たされないプラグインがあったらユーザに知らせるべき。
      • 実際問題として実行時にPluginsフォルダ内のPythonスクリプトが呼ばれるだけ。
        • 呼ばれるのはinit.pyだけ
          • こうしておけば他のスクリプトを呼び出す順序はプラグイン作者の管理下に置かれる。
          • サブディレクトリ内にもinit.pyがある場合、常に親が先に呼ばれる
            • それが自然だと思う。共通して使われるリソースを先にどうこうしておくとか。
          • グローバル名前空間を汚染しないように、グローバル名前空間を引き継いだexecは使わない。空の名前空間を使うか、importを使う。
        • 実はうまく配置を考えると、Jythonライブラリとしても働くかも。Jarが全くないプラグイン
          • それならpluginsって名前じゃなくてdependencyのがいいかも。現状でswt.jarなどが入っているフォルダがそれ。
    • GRINEditにコマンドライン引数でPythonスクリプトを渡した場合に、それを実行
      • 全てのプラグインの初期化が住んだタイミングで?
      • 一番最初に?
        • 一番最初に実行されて「初期化が済んだら実行するリスト」に初期化が済んでから実行して欲しいものを入れればよい。
        • 一番最初に実行されて、いらないプラグインを無視リストを書き換える。
          • あ、それだと無視リストを設定するスクリプトが走った後に呼び出される必要があるのか。
          • わかった、最初に実行されるスクリプトの代わりに走るんだ。指定されなかったらdependency/init.pyが走る、と。
      • これのメリット:GRINEdit test.pyでテストが起動され、 GRINEdit narVisualizer.pyでNarVisualizerモードで起動し、何も指定しなければプレーンなGRINEditが起動する、なんてことができる。
  • タブレットでスケッチっぽく頂点や辺の追加がしたい。
  • Java 2D による半透明描画で半透明頂点。
  • いまはグラフのインスタンスが1アプリに1個だけど、複数個になる可能性を考えるべき?必要になったときでいい?
  • 本体を起動する実行可能Jar
    • スプラッシュウィンドウを出して、出力された情報をそこに出す。
    • 本体画面が表示された後で、"HIDE_SPLASH"とか出力して、ランチャー側はその文字列を見たら隠れる。
    • エラーが起きた場合にはそのメッセージを出せばいい。
  • LibreSource - JyConsole
  • applyのパターンをパラメトライズ
  • Jython Course Outline
  • Jython Consoleのデモ
    • vs = med.getVertexList()してからvs[0]した場合の挙動がどうなのか確認
    • v = med.getVertexDict()["Vertex0"]できた。これを使ったデモ。
    • edgeのデフォルト時の値が-1なのはバッドノウハウ。getParamsして見せたときにかっこわるい。
    • med.getMarginalEdges色をつけてからlengthを伸ばす
  • XML-RPCのデモはPL_Wallを外した後つり上げてPL_Cohesionでいきなり貼り付かないようにする。その後ぶら下げて貼り付ける。
  • 物理演算クラスはレンダリングエンジンクラスが持つべき?
  • 「何に使えるの?」という質問にはウェブサイトのグラフによる可視化をやって見せて「これがたったの~行で書ける」というのがいいのだろうか。
  • 利用できる頂点・辺・物理演算の一覧が得られれば、それ全部を追加するテストも簡単だが…。

日記

大井町と大手町とか青梅と青海とか紛らわしすぎる。

今日はお弁当を作る気があまり起きない。まぁいっか。


__ FreeMindはやっぱりマインドマップなんかじゃない。これじゃただの「きれいな箇条書き」です。

こういう通常の文章という1次元的なフォーマットがあり、箇条書き文書というツリー状のフォーマットがあり、そしてマインドマップという右脳を大いに使ったフォーマットがあって、3つそれぞれ特色が異なっているから価値があると思うのです。マインドマップも基本はツリー状に発展していきますが、ツリー状に制約されてしまうと自由な発想を妨げます。頭の中にツリー状に整理された状態でイメージがあるのなら箇条書きで十分なわけで、そうではないからマインドマップが重要なわけです。脳の中のネットワーク状のアイデアをネットワーク状のまま紙に書き出して全体を観察できるようにした上で、それを整理することで初めてツリー状になるんです。

絵を描いたり変なところから線を繋いだりできないマインドマップなんてマインドマップじゃない。


__ もうすぐ9時。 明日は研究室のミーティングのはずだったけどキャンセルになったので赤坂某所のSICP勉強会に行ってきます。かなり久しぶりな気がします。


__ 渡辺さんの日記より

おそらく10年(早ければ5年)以内にローカルディスクというものは絶滅し、すべてどこかサーバ上のデータを扱うことになるだろうと思うわけだ。

HDDが1GBあたり31円のこの時代でも1GBあたり7000円のメモリは売れてますよね。10年後でもローカルディスクの方がネット接続より早いでしょうから絶滅はしないでしょう。「ベストエフォートで100Mbps」と言っている回線が、本当に100Mbps出るようになったらだいたいUSB1.1くらいの速度ですかね。その頃にはUSB1.1は絶滅しているかも知れません。

でもファイルをオンラインに置く流れはもうかなり強い物になってきているようです。今日聞いていたBootcamp: Reportによれば25GBのオンラインストレージが無料で使えたりするそうですし、以前はてなでバックアップの取り方をサーベイしたときも「Yahooブリーフケースを使う」とか「GMail宛にファイル添付で送る」とかのオンライン保存をしている人が結構多くて驚きました。


__ IBMには近藤科学、実売9万円のホビーロボット「KHR-2HV」があってみんなで側転させて遊んでるんだってさ(誇張)


__ K&Rがバフェットの1000分の1の価値であることに皆さん不満げな様子ですな(笑)


__ 朝日新聞のasahi.com: ウィニー開発者に懲役1年求刑 京都地裁。 とりあえず「『懲役1年』って執行猶予はつかないの?」とか「なんで最終弁論(9月)の前に『懲役1年』とかニュースになってるの?」とか悩んでたのですけど、 「『ウィニー開発者に懲役1年求刑 京都地裁』ってタイトルなのに中身は『検察側は(中略)懲役1年を求刑した。』じゃん!釣り?」という結論に。 求刑とかそういう法律用語には詳しくないのでこういうことをされると困るなぁ。


__ なんかささださんが面白そうなことをやっているのでPythonで似たようなことをしてみました。

# -*- coding: cp932 -*-
import re, sets, copy

data = """
  ONE
  TWO
+FOUR
-----
SEVEN
"""

chars = re.findall("\w", data) # 文字だけ取り出す
chars = list(sets.Set(chars)) # uniq代わり

class Array(list):
    def perm(self):
        done = []
        while self:
            e = self.pop()
            yield e, done + self
            done.append(e)

def foo(data, candi = range(10), i = 0):
    if candi == []:
        try:
            if eval(data.strip().replace("\n", "+")) == 0:
                print data
        except:
            pass
    else:
        for (value, rest) in Array(candi).perm():
            foo(data.replace(chars[i], str(value)), rest, i + 1)


from time import clock
start = clock()
chars.remove("E")
chars.remove("S")
data = data.replace("E", "0")
data = data.replace("S", "1")
foo(data, range(2, 10))
print clock() - start

#foo(data)

理論的にはfoo(data)だけで答えが出るはずなのだけども、時間がかかってしょうがないので枝刈りをせざるを得なくてchars.removeなんかをするハメに。でもこの枝刈りバージョンは6.3秒で答えが出ましたよ。枝刈り無しだとどれだけかかるんでしょうかねぇ。

それはさておきこのアルゴリズムのいやらしいところはpermutationとかそんな所じゃなくてもちろん

            if eval(data.strip().replace("\n", "+")) == 0:
                print data

なのです。筆算の横棒がハイフン5つでできているので正しい筆算、例えば

  940
  739
+8925
-----
10604

の時に、eval(data.strip().replace("\n", "+"))である「940+ 739++8925+-----+10604」は0になるわけです。いやはや。

2006年07月03日

日記

AC になる方法 (簡単!)によれば、日記に 我AC と書くと1週間以内にとても AC になれるそうです。試してみました(笑)

それはそうとSJISの「変形」をEUCで読むと「ハムキチ」になるという話はこういうことですよね。

>>> print unicode("変形", "sjis").encode("euc-jp")
ハムキチ
>>> print unicode("ハムキチ", "euc-jp").encode("sjis")
変形

「儲安」は「フルーツ」になるのだけど漢字でもカタカナでも意味が通じる物を探すって言うのは難しいですねぇ。 いろんな単語の読みが入っているような辞書を取ってきて、全部漢字に変換した上でそこから改めて意味のある熟語を探索…というのが一番原始的な方法かと思いますが、それでは「ハムキチ」を見つけることは出来なかったでしょうし…。


__ ふぅ。なんだか頭の中に脱脂綿が詰まったような感じ。


__ ちょっと脳神経系に作用する薬物を摂取してみます。Wikipediaによればアデノシンの働きを阻害する薬物らしいです。なんて書くと大げさですが、緑茶です。緑茶は中枢覚醒効果のあるカフェインと鎮静作用のあるテアニンを両方含んでいて、過度の興奮を押さえてくれるのです。たぶん。あとチョコレートも買ってきました。これも中枢覚醒効果のあるテオブロミンを含んでいます。カフェインからメチル基が1個取れただけなんですねぇ。


__ 生まれた時からプログラマ☆興味と感性で世界を驚かす/Tech総研 どうやってたどり着いたか忘れたので、タブを閉じるともう一度開けなくなりそうだからリンクしておくことにします。こういう時にはてなブックマークとか使うべきなのかなぁ。


__ 512MBのポータブルMP3プレイヤーって、大した曲数入りませんね。たくさん入れて聞くのかと言われるとそうでもないのだけども、たくさんの曲からいくつか選ばないと行けないと言われるとそれはそれで悩みます。そして高速再生が期待していたような機能ではなかったので高速再生したMP3も別途用意するので普通より入る曲数が少ないです。

MP3プレイヤーのために作った高速再生MP3ですけど、ノートパソコンでも有益ですね。高速再生に使っているWinampのPaceMakerプラグインは200%までしか高速再生が出来ないのですけど、高速再生MP3をさらに高速再生することができますから。200%再生MP3を作ったので400%までは行けるわけです。

Bootcampの最新記事とMP3を保存するPythonスクリプト

実行するとカレントフォルダに例えば「StoringYourDigitalMediaOnline_30-Jun-2006_2049.html」と「StoringYourDigitalMediaOnline_30-Jun-2006_2049.mp3」というファイルが生成されます。 もちろんlinks[0]と最初のリンクだけ取得して実行しているのをすべてのリンクについてforで回すようにすれば一気に全部取得できますが、全部聞きもしないのに全部取得するのは迷惑がかかるのでおすすめしません。だいたい1日1個ずつ増えるので、毎日1個ずつ取得して聞いていくつもりで作ったスクリプトですので。

技術的にはurlopenで開いて正規表現で切り出しているだけなのでさほど目新しいことはしていませんね。findallを使わなくてもいいのでは?という疑問を持たれた方には、もちろんsearchしてgroupsを使う方法でも何ら問題ない、と答えておきましょう。

#
# get bootcamp
#

from urllib import urlopen
from re import findall

ROOT_URL = "http://www.bootcamp.com/"
data = urlopen(ROOT_URL + "archives.jsp").read()

PAT_LINK = r"""
<a\shref='(report\.jsp\?reportId=(.+?))'>
<span\sclass='reportitem'>([^<>]+?)</span></a>
"""

links = findall(PAT_LINK, data, re.VERBOSE)

(url, index, date) = links[2]

data = urlopen(ROOT_URL + url).read()

PAT_TITLE = "<span class='reporttitle'>(.+?)</span>"
PAT_MP3 = "<a href='(sendAudio.jsp\?reportAudioFileId=\d+)'>in MP3 format</a>"
PAT_CONTENTS = "<span class='reporttext'>(.*?)</span>"

title = findall(PAT_TITLE, data)[0]
mp3url = findall(PAT_MP3, data)[0]
contents = findall(PAT_CONTENTS, data, re.DOTALL)[0]

filename = title.replace(" ", "").replace(".", "") + "_" + date + "_" + index
contents = "<h1>" + title + "</h1>" + contents

data = urlopen(ROOT_URL + mp3url).read()
data = urlopen(data.strip()).read()
file(filename + ".mp3", "wb").write(data)
file(filename + ".html", "w").write(contents)

2006年07月02日

Pythonでmixiにアクセス

MIXI Pythonライブラリ — Emerge Technologyを参考にしましたが、リンク先はログイン処理に問題があってきちんとログインが出来ていないように思われます。

import urllib
import re

class MixiOpener(urllib.FancyURLopener):
    def login(self, email, password):
        LOGIN_URL = "http://mixi.jp/login.pl"
        params = urllib.urlencode({
            "email": email,
            "password": password,
            "next_url":"home.pl"})
        r = self.open(LOGIN_URL, params)
        cookie = []
        for c in r.headers.getheaders("Set-Cookie"):
            m = re.match("(.+=.+);.*", c)
            if m:
                cookie.append(m.groups()[0])

        self.addheader("Cookie", ";".join(cookie))
        r = self.open("http://mixi.jp/check.pl?n=home.pl")
        return r.read()

    def searchDiary(self, keyword):
        SEARCH_URL = "http://mixi.jp/search_diary.pl"
        params = urllib.urlencode({
            "submit": "search",
            "type": "dia",
            "keyword": keyword})
        r = self.open(SEARCH_URL, params)
        return r.read()

m = MixiOpener()
m.login("あなたのメールアドレス", "パスワード")
data = m.searchDiary("(*゚▽゚)")

これで日記検索画面のデータを取得できます。他のURLを開くのもm.open(URL)とやるだけなので簡単ですね。

日記

SPAM SPAM SPAM Spam (Monty Python) - Google Video。SPAMの語源になったMonty PythonのスケッチがGoogleVideoにありました。「繰り返し繰り返しウザイ=SPAM」というのがわかるかと思います。日本で言えば「やたら長ったらしい=寿限無」に相当するのでしょうか。でもこれ、前のスケッチを見ていないと、そもそもなんでバイキングなのかとか、途中で現れて変なことを言う紳士が何なのかわからないかも知れないですね。紳士は旅行者用の辞書を見ながら会話しているのですけど、これがエロ単語だらけのデタラメ辞書なので本人は大まじめに会話しようとしているのに変なことを言ってしまうのです。なぜバイキングが出てくるのかは忘れました。


__ 今気づきました。僕って18歳ですね、16進数で。プログラミングシンポジウムとかでは20歳未満が若手とされるので、僕が若手でいられるのもあと2年ですね(違)


__ やっぱり冷房は体に良くないですね。奈良にいる3年間は夏場も窓を開ければ涼しかったので冷房無しで過ごせたのですけど、こっちはそうも行きません。しかもレオパレスの作り付けの机は作り付けのエアコンの風が直撃する場所にあるので冷えてしまいます。昨日も暑いから冷房をつけ、寒いから止め、を繰り返したのですが、布団に入ったら寒気がして布団を首までかぶって寝たので起きたら汗でぐっしょり。軽い脱水症状を起こして吐き気まで催しました。やれやれ。扇風機を買うのと冷房の当たらない位置に机を作るのとどちらがいいでしょうかねぇ…。


__ MovableTypeはタグのidにいろいろな物がセットしてあるのでハックしやすかったですが、mixiはそうではないので面倒。class=h12っていうのは日記の本文を意味していると考えていいのでしょうか。


__ 痛いニュース(ノ∀`):プレスリーの物真似をサングラス姿でする小泉首相 本題よりも「公の場で服をつまんで引き回される胡錦涛国家主席」が面白かった。


__ やっぱりBaum-Welchを使うか…とググっていたらSourceForge.net: General Hidden Markov Model LibraryというCで書かれたライブラリがありました。Pythonバインディングもついているようなので試してみるのも悪くないかも知れませんね。


__ うはー、もう22時。雨がやんで日が落ちて涼しくなったのでお玉とスポンジを買いに船橋まで自転車で行ってきました。行きは4分半のニュースが3回弱再生されたので13分くらいでついたのですけど、帰りに遭難してえらいめに会いました。船橋駅から線路の北側に沿って進もうとしたのですが。線路に沿った道がなくて遠回りしたりしているうちに見失い大変なことに。途中に船橋健康センター ゆとろぎの湯がありましたよ。西に進んでたはずだったのに真北じゃん!しかもこの地図だと近そうだけど船橋駅から2キロ離れていてしかも起伏があります。今日の教訓は「線路に沿って行けばたどりつける」と思ってはいけないと言うことですね。結局船橋駅まで戻って南に行って国道14号まで出てから帰ってきました。


__ せいきさんのコメントより。

graphviz は個人的にはフローグラフを上からぶら下げて表示させたときに、連結線が綺麗な曲線で繋がってくれるのが嬉しかったのでした。世の中、グラフの可視化ツールというとバネモデルばかりで、なかなかフローグラフを綺麗に配置をしてくれるものがみあたらないですよね……。不勉強なだけだとは思うんですけど。

なるほど。graphvizから何かよさそうな機能を一つプラグインで取り込もうと思っていたのですが「きれいな曲線」はなかなかいいですね。それは確かに欲しい機能です。物理演算で曲がった辺を実現する方法もアイデアはあるのですけど、graphvizがどうやっているのかをちょっと調べてみるのも悪くないですね。GRINEditのTODOに足しておきます。


__ 先日作ったCGIがFirefoxではtext/plainになってしまう問題が解決しました。CGIで出力する文字列をだらだらとスクリプト内に書くのを嫌って、UTF-8のファイルからテンプレートを読んでコンテンツを埋め込んで出力するようにしたのですが、そのテンプレートの頭にBOMがついていたため出力されたContent-typeの前にも余計な文字がつき、Content-type: text/htmlという指定がうまく働かなかったのが原因でした。保存時にBOMと書いてあるチェックボックスをオフにして見たら解決しました。BOMに関する話をUTF-8 - Wikipediaで読んでおいて良かったです。


__ 隠れマルコフモデルを用いた顔文字抽出。英文字をあまり学習していないせいで英文字の羅列を顔文字と勘違いするケースがあります。その辺はちまちま学習させれば直ると思うのですけど、基本的にそういう面倒くさいことは嫌いなのです。

とりあえず過去1週間の日記に指定した顔文字が何回出現するかはカウントできるようになったのですけど、さて、これからどうしようかな。休日は終わったから塩漬けかな。

・゜゜(>д<)゜゜・ 92
(๑→ܫ←๑) 29
_| ̄|○ 22422
(´ω`)b 92
(*゚ー゚) 1328
(*‘ω‘ *) 376
(*´ω`*) 3302
( ゚∀゚)o彡° 38
(。・ω・。)ノ" 755

__ X-Barが届いた話は書いてないですね…。まず150%高速再生は音程の変化を伴う高速再生でがっかりしました。A-B再生は通常の再生中にジョイスティック(?)を上に倒すだけですぐに使えるので便利です。でも通り過ぎてしまってから「あ、今のをもう一度」って訳にはいかないのが問題です。早送りや巻き戻しは長押しなのでなかなか期待した位置に戻れません。ファイルの出し入れに関してはUSBポートにさして読み書きするだけなので「少し大きいUSBメモリ」の感覚ですね。充電もUSBポートから出来て便利です。Voice of Americaのニュースをダウンロードして聞いていたのですけど、やっぱりほとんどわからないですねぇ。繰り返し聞いているうちにだんだんわかるようになってくるので耳が英語に慣れていないんだと思います。電車の中とかで繰り返し聞いて、目的地に着いてから文章を見て確認するのがいいですかねぇ。Bootcamp: Reportの文章とMP3をワンタッチでダウンロードしてくれるスクリプトでも作ろうかな…。


__ Bootcampの最新記事とMP3を保存するPythonスクリプト。さて、寝よう。

2006年07月01日

西尾泰和のプロフィール

Here is English version. このページは研究者としてのプロフィールです。広い意味で「やっていること」について知りたい場合は 西尾泰和の活動ダイジェストをご覧ください。

メールアドレス

「nishio どっと hirokazu あっと gmail どっと com」

経歴など

  • 1981/07/23 誕生
  • 1994/04-1997/03 灘中学 入学 → 卒業
  • 1997/04-2000/03 灘高等学校 進学 → 卒業
  • 2000/04-2003/03 京都大学工学部情報学科 入学 → 退学
  • 2001/07-2002/02 独立行政法人 情報処理振興事業協会(IPA) 未踏ソフトウェア事業
  • 2002/11-2003/03 IPA 未踏ソフトウェア創造事業(未踏ユース)
  • 2003/04-2004/03 奈良先端科学技術大学院大学(NAIST) 情報科学研究科博士前期過程 入学 → 短期修了
  • 2004/04-2006/03 NAIST 情報科学研究科博士後期過程 進学 → 短期修了(24歳。たぶん日本最年少博士)学位記(PDF)
  • 2004/05-2005/02 NAIST 情報科学研究科 ティーチングアシスタント
  • 2004/08 文部科学省 IT人材養成プロジェクト ITスクール2004 チューター
  • 2005/04-2006/03 独立行政法人 日本学術振興会 特別研究員(DC2)
  • 2005/08 文部科学省 IT人材養成プロジェクト ITスクール2005 チューター
  • 2006/04-2007/03 独立行政法人 日本学術振興会 特別研究員(PD)
  • 2006/05-2007/03 東京大学大学院 新領域創成科学研究科 学振特別研究員
  • 2006/08 文部科学省 IT人材養成プロジェクト ICTスクール2006 チューター
  • 2007/04- 株式会社サイボウズ・ラボ ソフトウェアエンジニア

所属など

論文・発表など

主著

  • GIW ポスター発表 "Genome Visualization by Isometric Projection Focused on Replication Origins and Termini, and Genome Instability" Nishio, H., Wada, K., Wada, Y., Fukushima, A., Ikemura, T., Mori, H., Oshima, T., Kanaya, S. Genome Visualization by Isometric Projection Focused on Replication Origins and Termini, and Genome Instability. Genome Informatics 13: 449-450 (2002)
  • プログラミングシンポジウム2003冬 オーラル発表 "ゲノム丸ごと可視化"(和文)
  • 平成14年度未踏ユース事業"4次元グラフによるゲノムの可視化"
  • WSOM2003 オーラル発表 "Visualization of Gene Classification Based on Expression Profile Using BL-SOM" Nishio, H., Amin, M., Sato, T., Wada, K., Wada, Y., Minato, K., Kobayashi, K., Ogasawara, N., and Kanaya, S. (2003) Visualization of gene classification based on expression profile using BL-SOM., Proc. of WSOM03, 101-106.
  • RECOMB2004 ポスター発表 "Suitability of Spherical SOM for Gene Expression Analysis" Nishio, H., Wada, K., Wada, Y., Amin, M., Kanaya, S. Suitability of Spherical SOM for Gene Expression Analysis. Proc. of RECOMB2004
  • SCI2004 オーラル発表 "Gene classification Based on Expression Profile using BL-SOM: Suitability assessment of multivariate gene expression data to Spherical and Plain SOM by N-measure"Nishio, H., Altaf-Ul-Amin, M., Nakamura, Y., Abe, T., Kinouchi, M., Ikemura, T., Kobayashi, K., Ogasawara, N., Kanaya, S. Gene classification Based on Expression Profile using BL-SOM: Suitability assessment of multivariate gene expression data to Spherical and Plain SOM by N-measure. SCI2004
  • WSOM2005 ポスター発表 "Spherical SOM with arbitrary number of neurons and measure of suitability"
  • プログラミングシンポジウム2005夏 オーラル発表 「プログラミング初学者のための名前空間の可視化」
  • 情報処理学会論文誌「数理モデル化と応用」 "Spherical SOM and arrangement of neurons using helix on sphere"

その他

受賞など

研究費助成など

日記

7月ですね。暑い暑い。

「レールの上を走れないのなら、レールの外を2倍走れ」というのも悪くない。


__ 文科省の調査によれば、小学五年生について、水泳の授業での着替えを男女同室で行う学校が0.1%、林間学校などの校外宿泊で宿泊部屋が男女混合なのが1.1%だそうです。そういうのって男女平等とは違うように思うんですけどねぇ。

一律の扱いをすることはむしろ平等とは逆なんじゃないでしょうか。僕の頭の中のイメージは2次元平面上に点が散らばっている風景です。ある位置に標準点を定めるとそれに近い点と遠い点ができるわけです。近い点の方が有利で遠い点が不利益なのだから、一律の扱いは平等ではありません。ごく一部の点の分布以外では、どこに標準点を定めても距離が一定にならないのですから、本質的に「平等な扱い」が存在しないケースの方が多いわけです。

それはそうと「文科省の調査」とだけ書かれてもソースに当たるのが大変だからせめて調査の名前くらい書いて欲しいと思うのですが、そういうニーズは少ないんでしょうかねぇ。


__ ☬ฺこの文字なんでしょう。一瞬ガンダムかと思いました(そんなのがUnicodeにあるはずない) (‘ủ‘) 特殊文字コード表を参考にして作ってみましたが、これだけ部品がたくさんあるとちょっと楽しいですね。

昨日は夜中になってから隠れマルコフモデルを使った顔文字の抽出を実装し始めてしまいました。 でも隠れマルコフモデルの勉強になったからいいとしましょう。2状態で、 1状態が必ず1つの出力を伴うという仮定の下では、結局のところ間にギャップを入れるか入れないか考えているに過ぎないわけです。たとえば(→へ←)の様な顔文字であれば、真ん中の「へ」は顔文字でない場合にもよく出現する文字(つまり「顔文字と見なすコスト」が高い)なのですが、両脇の文字が「顔文字でないと見なすコスト」の高いものなので、間にコストの高い「異なる状態への遷移」を入れるよりはちょっと高いけど「へ」を顔文字だと見なす方がマシ、という判断が起きるわけです。結局のところ、これでは1文字1文字の出現確率というパラメータを繰り返し繰り返し学習させることでいい値に収束させるだけのことです。

♡→ܫ←♡のハートは顔文字に含めるけども♥。・゚♡゚・。♥。・゚♡゚・。♥。・゚♡゚・。♥。・゚♡゚・。゜♥。゚♡゚・。♥。・゚♡゚・。♥。は顔文字に含めない、というルールを個々の文字の出現頻度だけで記述できるんでしょうか。 状態数を増やしたりBaum-Welchを使うことで解決になるのかどうかは微妙な気がします。

㍰㏾、そんな物を一文字にして文字コードを割り当てる必要性があったのかと…。そんなのより最近滅びつつある変体仮名を入れてくれればよかったのに。