« 2006年05月 | メイン | 2006年07月 »

2006年06月29日

log

MenuActionを継承した具体的なクラスは全部MA_で始まり、 MouseOperationを継承した具体的なクラスは全部MO_で始まるので、 PhysicalLawを継承した具体的なクラスは全部PL_で始めることにしました。

剛体の実装に着手。剛体のような「めったに構成する頂点が変わらないようなもの」に関してはVectorではなく配列にしてしまった方がいいのかも知れないと思ってそういう実装にしてみました。しかし、この設計が必ずしも正しいとは言えないので時間が経ってから考え直す必要があるでしょう。

実装は出来たので次はそれをテストするための仕組み。メニューに「選択範囲をグループ化」をつける。

慣性がないのがなぜ自然か

物理学としては「力が働かないものは動き続ける」というのが自然であり、加速度が与えられないものは速度を維持するというのが自然です。しかしユーザーインターフェースとしては自然ではありません。それはなぜでしょうか。

それは人間の素朴物理学(naïve physics)と正しい物理学との間には乖離があるからです。いい参考資料があったのでリンクしておきます(認知学習論(ppt)

結局のところ人間が素朴に持っている物理学が正しい物理学に一致していない以上、物理学的に正しいことよりも素朴物理学的に正しいことを重視しないと行けません。多くの人は静止している物を見たときに「無重力空間で空中に浮かんでいる物体」をイメージしません。「机の上に乗っているコイン」の様なイメージを持ちます。力をかけている間は動きますが、力がなくなると止まるのが自然なのです。

日記

新幹線でLANが使えると幸せですね。2009年の予定ですけど。

人力検索はてな - ライセンスの問題です。CPL(Common Public License)で配布されているソフトウェアのソースコードを参考にして自分のLGPLで配布しているソフトウェアに機能を追加したいので..によれば、CPLのコードをプラグインという形でLGPLのプログラムに組み込むことは問題なさそうです。つまり、graphvizのコードをプラグインという形でGRINEditから使えるようにすることには法的な問題はないということです。

サーベイ能力弱いなぁ、僕。GraphvizのJavaによるラッパーがありますね、Grappaっていうのが。no longer activeですけど。これもCPLならこっちのコードを使う方がいいかもしれませんね。no longer activeだからこっちでいじっている最中に向こうがガシガシ書き換わることもないでしょうし、向こうにとってももうメンテナンスする気がないのですからこっちが引き継いでも損にはならないですし。

昨日のカレーみたいなポトフは、冷蔵庫から出してみるとゼリーみたないなものに変わっていました。骨のついている鶏肉をぐつぐつやったからかな?まだ2食分くらいあるので今日はこれにカレールーを入れることにします。

コラーゲンは骨から出たのか軟骨から出たのかどっちだろう。

JUNG - Java Universal Network/Graph FrameworkのFAQを参考にしよう。英文の。


__ 暑い。 さすがに冷房を効かせれば暑くはないんだけど、出勤過程が暑いので涼しくなっても汗臭い。


__ グラフの可視化を簡単に説明するサイトを探そうと「グラフ 可視化」で検索したら秋元@サイボウズ研究所プログラマーBlog: HTML構造のグラフによる可視化が一番上に来ました。


__ ダメだダメだダメだ、GRINEditリリース後しばらく遠ざかっていたせいで何をしたらいいのかが頭から消えていた。 消えないようにTODOとか作業ログとか書いていたのに、書き方が悪くてダメだ。

頭の中にあることを単に全部吐き出してしまうだけではなく(もちろんそれも書き忘れたことを後で探す必要が出来たときには重要だが)簡潔・最小限の「未来の自分への手紙」を書いておかないといけない。 やろうと思ったことを忘れないためには「Aをやろう」「Bをやろう」「Cをやろう」と全部書き留める必要があるが、次に再開した時に自分がタスクに押しつぶされたり道に迷ったりしないためには「次はアレをやろう」をわかりやすいところに書いておく必要がある。

角運動量の計算で外積が出てきたので結局「3次元だけども2次元に拘束されている世界」になってしまった。美しくない。いっそ3次元にしてしまった方がいいのだろうか。ほとんどの人にとって3次元は必要ないと思えるし、3次元にすると必然的に今の「平行移動」の他に「回転」が必要になる。別に出来なくはない、というか実は過去に3次元のバネモデルは 作りかけアプレットで使っているので目新しい問題点はないのですけども。うーん。ニーズがないと思うしなぁ…。

もう9時?!


__ だいぶ家事がうまくなったかも知れません(あくまで過去の自分と比べて)。 帰ってきて、薬罐に麦茶のパックと水を入れてお茶を沸かしている間に、 冷蔵庫から昨日のポトフの鍋を取り出し、チンして冷凍して置いたニンジンを入れて、タマネギの残りを入れ、沸いた薬罐と取替え、炊飯器にお米と水を入れてスイッチを入れて、今ぐつぐつと鍋が煮えているところです。 炊飯器は一番最初につければ良かったってのと、鍋に水を入れすぎてちょっとこぼれ気味なのが反省点ですね。あと時々新聞と一緒に入っている茶色の袋が、実はかなりマチが広くて読み終わった新聞を入れられると言うことに気がつきました。(っていうか古新聞を入れるための袋ですね、これ)。縛らなくていいので楽です。

お茶はいつも2リットルの水を入れて沸かしていたのですが、水出し麦茶のパックで出すとかなり濃く出るので2リットル沸かしても4リットルに薄めて飲んで大丈夫です。そこで「1リットル沸かして2リットルに薄めればいいじゃん」と気がついてお茶が沸くまでの時間を節約できました。

家事もハックですね。しかもマルチスレッド。


__ Grappaはおそらくレイアウトの機能を全く持っていないですね。dotファイル自体が頂点の位置などの指定された物に指し変わっています。とりあえずJavaで書かれたdotパーサは再利用できそうです。Cで書かれたgraphvizのコードを読むのと、graphvizのコードにコメントとして書かれていた論文を読むのとどっちが手っ取り早いかな。

graphvizを読めば読むほど、たいしたことがないように見えてきます。とりあえずレイアウト方法は6通りあって、そのうち2つはGRINEditと同じバネモデル。残りは階層的レイアウトと円形レイアウトと放射状レイアウトですね。円形レイアウトはJ. M. Six and I. G. Tollis, A Framework for Circular Drawings of Networks, Proc. of GD 99, LNCS 1731, Springer-Verlag, pp. 107–116, 1999に載ってそうです。ググって見つけたSymeonidis and Ioannis G. TollisのVisualization of Biological Information with Circular Drawings Alkiviadisが数ページを割いて解説しているのでまずはこれを読んで、原典に当たる必要があればそうしましょう。

2006年06月28日

日記

今朝夢の中で阪神大震災の予震が3倍くらいの長さになったような地震を感じたのだけど、実際に地震があったらしい9時45分には起きていたと思うんだけどな。シャワーを浴びて地震情報を検索している今が9時55分だもの。でも起きているときに地震を感じていないのも考えると…やっぱり寝てたんだろうか?

また洗濯物を干すの忘れて放置してる…。 あと一昨日買った鶏肉のことも忘れてた…。傷むと困るから冷凍庫にいれとこうかな。 今日は早めに帰って一昨日買った野菜を調理しないと。


__ 論文提出完了。


__ Brainf*ckが一部で流行っているみたいなので An introduction to programming in BF へのリンクを張っておきます。


__ 今年度の若手の会(第39回情報科学苔手の会) の申し込み。GRINEdit発表するのも悪くないかもなぁ。


__ 下期の未踏って終わるのが来年の9月末なんですねぇ。思っていたよりも長いです。


__ Boost勉強中、と言ってもC++のBoostではなくAdaBoostですが。


__ 書かないと気になって集中すべきことに集中できないので書いておきます。 PythonBrainf*ckコンパイラの話ですが、一応周囲のコマンドの情報から適切なGoやKillを挟むようにはなったので次はコード内で領域の確保が出来るようにしたいわけです。その為にはどこが破壊していい領域でどこが破壊しては行けない領域かを知る必要性があるわけです。それと、現在は [ ] を使ったジャンプが生で直接操作されるようになっていますが、これはp回繰り返すTimes命令 [- (command) (go p)] やIf命令(Kazuho@Cybozu Labs: brainf*ck で計算機を参照)を作っておいてそれを使うようにし、生の [ ] はなるべく使わないようにすることで1カ所のミスが全体に波及して困難なバグを生み出す可能性を減らすことが出来ます。 そうすれば、Times命令が使う領域に「破壊禁止」のマークをつけた上でその中身のコマンドをコンパイルすることで中身のコマンドが新しい領域を確保しようとした場合にTimesの作業領域を破壊することが防げます。

デジャヴですね。これぞ構造化プログラミングの誕生です。

必要な変数は最初に全部宣言してしまうタイプの方が、whileやifが現れるたびにその場であいている領域から作業領域を確保する今作っているようなタイプよりも楽でしたね…。

それはさておき、Brainf*ckで特定の数を作るための最小のコマンドは何か、という問題は作業領域として使っていいセルがどこにあるかによって異なりますね。[0]以外は全部使っていいとするのが問題としては一番簡単ですが、コンパイラを作る側としてはそれでは実用性がないわけです。Brainf*ckには元から実用性がないじゃないかというつっこみは禁止。

Cを機械語にするのは機械語コンパイラじゃなくてCコンパイラで、JavaをバイトコードにするのもJavaコンパイラだから、PythonをBrainf*ckにするのはPythonコンパイラ(違う) 任意のPython言語がBrainf*ckになるわけではないので、あくまで「Pythonで実装された小さな言語」のコンパイラなのですね。じゃぁPyBrainf*ckコンパイラって呼ぶことにします。


__ Pythonは2.4あたりから複数同時に起動しようとすると怒るようになったので、 何かプログラムを書いていて時間のかかる処理を実行した後、待ってる間に別のプログラムを書こうとすると対話的に短いコードのテストとかが出来なくて不便です。何とかならないんですかね。 しばらく考えてCygwinのPythonを起動しましたがコピペ出来ないから不便…。


__ おなかすいたなぁ。


__ 腰が痛いなぁ。 いい椅子のはずなのに何故だろう。


__ ふう。そろそろ帰ろうと思ったのでBrainf*ck(ぇ)

もっと完成してからまとめて公開するので今日はクラス定義は全部省きます。

e = Environ()
e.nameSpace.update({"A":0, "B":1, "C":2})
print "".join([x.make() for x in [
	Copy("A", "tmp1", "tmp2"),
	Copy("B", "C", "tmp2"),
	AddTo("tmp1", "C")]])

name tmp1 not found alloc. at 3 name tmp2 not found alloc. at 4 [>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<[>+>>+<<<-]>>>[<<<+>>>-]<[<+>-]
bf = BFInterpreter()
bf.simplify("""
+++>++++< # [0] = 3, [1] = 4
[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<[>+>>+<<<-]>>>[<<<+>>>-]<[<+>-]
(showMem)
""")
bf.runCode()

0 3 1 4 2 7 3 0 4 0

Brainf*ckインタプリタはコードの中に括弧で囲ってデバッグ用のコマンド(メモリダンプやassert, 任意文字列のprintなど)を入れられるようにしました。PyBrainf*ckコンパイラの方は、名前空間を処理系が1つだけ持つ(原始的な)形に変えました。実装がすごく楽でした。

あ、もう8時だ。晩ご飯食べて帰っちゃダメなんだった。野菜と鶏肉が僕を待っている…。


__ ポトフ作りは暑くて大変です。

スープは悪くない味だと思うのだけど(っていうかコンソメだし)タマネギを食べてみると味がしみてないのはなぜでしょうねぇ。もっと煮ないといけないのかなぁ。

そういうわけでさっきからずっとぐつぐつやっています。


__ 出来ました。 これポトフなんでしょうか。 なんか、カレーみたいなにおいがします。カレー粉とかは使っていないのでもちろんそういうにおいではないのですけど「タマネギやニンジンを煮詰めました」というにおいがします。それから何か予想と違ってかなり茶色いです。いわゆるカレーほどではないですけど、こういう色のスープカレーはありそうです。最後に、割と辛いです。コンソメだけではぼんやりした味だったのでこしょうを瓶のふたに半分くらい入れたからだと思います。食べると汗が出ます。


__ Kazuho@Cybozu Labs: brainf*ck でマジメに素数探索

ひゃー。もう解かれちゃいましたか。

こちらの現状は「[1]が[0]で割り切れるかどうかを判定するBrainf*ckコード」を生成するプログラムが出来たところでした。素数への道のりはまだ遠い…。

e = Environ()
e.nameSpace.update({"A":0, "B":1, "Result":2})
print Seq([
    Create("A", 3),
    Create("B", 6),
    Create("toLoop", 1), # True
    While("toLoop", [
        Copy("A", "tmp1", "tmp2"), # free tmp2
        Times("tmp1", [
            If0("B", Dec("toLoop"), "tmp2", "tmp3"),
            Dec("B")]),
        If0("B", Seq([
            Dec("toLoop"),
            Inc("Result")]), "tmp2", "tmp3"),
        ]),
    ]).make()

name toLoop not found alloc. at 3 name tmp1 not found alloc. at 4 name tmp2 not found alloc. at 5 name tmp3 not found alloc. at 6 (start_Seq) +++>++++++>>+[ (start_Copy) <<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] (end_Copy) <[ (start_If0) (start_Copy) <<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] (end_Copy) +<[[-]>-<]>[[-]<<<->>>] (end_If0) <<<<<->>>-] (start_If0) (start_Copy) <<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] (end_Copy) +<[[-]>-<]>[[-] (start_Seq) <<<-<+ (end_Seq) >>>>] (end_If0) <<<] (end_Seq)

If0("B", Dec("toLoop"), "tmp2", "tmp3"), とかを見ると、どこを作業領域に使うかを人間が指定するのはやっぱり嫌な感じですね。 この「割り切れるかどうか判定」を一つのコマンドにまとめると IsDividable("A", "B", "Result", "tmpToLoop", "tmp1", "tmp2", "tmp3") になります。おぞましい。 作業領域の指定は省略できるようにして、省略した場合は適当に確保することにしましょうかねぇ。 必要になったときにメモリに「使用していますマーク」をつけて、いらなくなったときに「使用していますマーク」を消せばいいんですよね…。

AB間の移動が5回、BC間の移動が4回、CA間の移動が3回ある場合に、移動距離が最短になるようにABCを並べる方法は、っていうとまず一番大きいABを隣接させ、次にCをA側につけるのとB側につけるののどちらがいいかを調べてABCという順に決定されるわけですけど、もっと要素が多くなった場合もそれでいいのかなぁ。いや、違うなぁ。仮にA1からA100までがそれぞれ隣の数と太さ100の辺で繋がっているとして、A100とCが太さ99の辺で繋がっているとするとCはA100の側につけたくなるけど、CがA1,A2,A3のそれぞれと太さ50の辺で繋がっているならCはA1の側に行くべきだもの。難しい問題かも知れない。

PythonによるBrainf*ckインタプリタ 1.01

PythonによるBrainf*ckインタプリタ @ NISHIO HIROKAZU # Archived COREBlogの改良版です。 便利な機能としては「入出力を数字にするモード(7を入力したいときに文字コード7のものを入れるとか、7の文字コードから0の文字コードを引くコードにしておく等の面倒なことが不要)」「ステップ実行」「メモリの内容表示」「#以降行末まではコメントになる」「コメント以外でもコードに使われる種類以外の文字は無視される」などです。

## 掛け算
,>,< # 2つ値を読み込む
[-  # [0]の回数だけブロック内を繰り返し
    >
    [->+>+<<]  # [1]の内容を[2], [3]に加算、[1]は0になる
    >>[-<<+>>] # [3]の内容を[1]に加算(移動)、[3]は0になる
    <<<
]
# -*- coding: cp932 -*-
#
# Brainf*ck Interpreter
#
import sys
IO_ORD = True

class BFInterpreter:
    pointer = 0
    caret = 0
    code = ""
    def __init__(self):
        self.command = {
            ">": self.incPtr,
            "<": self.decPtr,
            "+": self.incValue,
            "-": self.decValue,
            ".": self.putValue,
            ",": self.getValue,
            "[": self.jumpIfZero,
            "]": self.backJump
        }
        self.memSpace = {}

    def incPtr(self):
        self.pointer += 1
        self.caret += 1

    def decPtr(self):
        self.pointer -= 1
        self.caret += 1

    def incValue(self):
        ptr = self.pointer
        v = self.memSpace.get(ptr, 0)
        self.memSpace[ptr] = (v + 1) % 256
        self.caret += 1

    def decValue(self):
        ptr = self.pointer
        v = self.memSpace.get(ptr, 0)
        self.memSpace[ptr] = (v + 255) % 256
        self.caret += 1

    def putValue(self):
        value = self.memSpace.get(self.pointer, 0)
        if IO_ORD:
            print value,
        else:
            sys.stdout.write(chr(value))
        self.caret += 1

    def getValue(self):
        data = raw_input("bf>")
        if IO_ORD:
            self.memSpace[self.pointer] = int(data) % 256
        else:
            self.memSpace[self.pointer] = ord(data[0]) % 256
        self.caret += 1

    def jumpIfZero(self):
        if self.memSpace.get(self.pointer, 0) == 0:
            c = self.caret + 1
            depth = 1
            while c < len(self.code):
                cod = self.code[c]
                if cod == "]":
                    depth -= 1
                elif cod == "[":
                    depth += 1
                if depth == 0:
                    break
                c += 1
            else:
                raise RuntimeError
            self.caret = c + 1
        else:
            self.caret += 1

    def backJump(self):
        if self.memSpace.get(self.pointer, 0) != 0:
            c = self.caret - 1
            depth = 1
            while c != 0:
                cod = self.code[c]
                if cod == "]":
                    depth += 1
                elif cod == "[":
                    depth -= 1
                if depth == 0:
                    break
                c -= 1
            self.caret = c + 1
        else:
            self.caret += 1

    def stepCode(self):
        c = self.code[self.caret]
        self.command[c]()

    def runCode(self):
        while self.caret < len(self.code):
            self.stepCode()

    # util
    def showMem(self):
        ks = self.memSpace.keys()
        ks.sort()
        for k in ks:
            print k, self.memSpace[k]
            
    def simplify(self, source):
        code = ""
        for line in source.split("\n"):
            for c in line:
                if c == "#":
                    break
                elif c in "><+-,.[]":
                    code += c

        self.code = code

    def removeOpposite(self, source):
        code = ""
        code = self.simplify(source)
        while True:
            prev = code
            for p in ">< <> +- -+".split():
                code = code.replace(p, "")
            if prev == code:
                break

        self.code = code



bf = BFInterpreter()

bf.simplify("""
++++++++++
[                   # The initial loop to set up useful values in the array
   >+++++++>++++++++++>+++>+<<<<-
]
>++.                #print 'H'
>+.                 #print 'e'
+++++++.            #      'l'
.                   #      'l'
+++.                #      'o'
>++.                #      space
<<+++++++++++++++.  #      'W'
>.                  #      'o'
+++.                #      'r'
------.             #      'l'
--------.           #      'd'
>+.                 #      '!'
>.                  #      newline
""")

bf.runCode()

2006年06月27日

日記

今朝ナカバヤシから製本された論文が届きました。昨日送ったメールにはまだ返事が来ていません。見事なまでのすれ違いです。(というか発送した時点で連絡くれればよかったのに)

Brainf*ckは、破壊しても構わないtemporary memoryをどこに置くのかの調整が重要ですね。使用期間が重ならない処理は同じ場所をテンポラリに使って構わないですし、テンポラリメモリの位置が離れているとステップ数も増えるのできれいに分けるよりも混ざっていた方が実行効率は高いですし。どのメモリがどの期間で使用されているかを理解して適切な位置にテンポラリを作ってくれるといいですね。

PythonによるBrainf*ckインタプリタ @ NISHIO HIROKAZU # Archived COREBlog。アーカイブのpreタグがもれなく1行とばしになってますね。やっかいだなぁ。そしてバグいりのインタプリタなので直したくなってきた、やばい、そんなことをしている場合ではない。


__ @柏

携帯の充電ケーブルを忘れてしまいました。まぁ、電話は明日すればいいか。

暑いですね。暑いけども、夜に冷房で体をこわさないように長袖を持ち歩かないと行けないのが面倒です。3年間通学をしてなかったので忘れてました。


__ 行きの電車の中で考えたことをメモしときます。 Brainf*ckは、本当の機械語よりも遙かにシンプルで、チューリングマシンよりは高級なので、名前さえ別のものだったら高校や大学の情報系の授業で使われていたかも知れませんね。「Brainf*ckのコードをいかにして生成するか」と考えていくと、過去のプログラミング言語の進化を追体験することが出来て興味深いです。

まず真っ先に考えたのは、アドレス位置の抽象化です。同じ「足し算をする」というコードでも、入力セルがどこで出力セルがどこかによって、コード中の「移動命令(「>」や「<」)」の個数が変わります。でもこれは本質的ではなく、アドレス位置に名前をつけて(add A B)と言うような表現をしても内部でAとBの位置関係から適切な個数の移動命令を生成することが容易に出来ます。擬似コードで書くとこう。

def move(A, B):
  "AからBへカーソルを移動する"
  before:
    assert cur == A
  do: (略)
  after:
    assert cur == B

次に、オブジェクトの生成と消滅に関して。create(A, n) と kill(A) が必要だと思います。

def create(A, n):
  "セルAの値をnにする。"
  destructive: [A] # 破壊されるセルのリスト
  before:
    assert A == 0
    assert cur == A
  do:
    return "+" * n  # 将来的にはもっと効率的な実装に変えることも可能だがとりあえずこれでOK
  after:
    assert A == n
    assert cur == A


def kill(A):
  "セルAを0にする。"
  destructive: [A]
  before:
    assert cur == A
  do:
    return "[-]"
  after:
    assert A == 0
    assert cur == A

説明が遅れましたが、before節の中でのassertはそのコードが実行される前に満たされているべき条件、after節の中でのassertはそのコードが実行された後に満たしているべき条件です。たとえばある命令のafterでcur == Aと宣言されており、その次の命令のbeforeでcur == Bが宣言されているなら、間に(move A B)を挟む必要があります。これは人間の頭を患わせなくても機械的に判断できますし、機械的に解決できる作業です。他にassert A == 0 というのもありますが、これが満たされていない場合には(kill A)を呼べばいいわけです。各命令は破壊するセルのリストを持っていますが、これは「その命令を包む命令」がセルを確保する場合には破壊されないセルを確保する必要があるからです。

さて、破壊の話が出ましたけど、Brainf*ckでの演算は基本的に破壊的です。関数型言語が副作用のない演算を追い求めたり、他の言語でもスコープを限定したりカプセル化したりして破壊を防ごうという努力がされてきたりしたのですが、基本はやっぱり破壊なのです。世界は破壊の中から生まれた(ぇ)

冗談はさておき、生成されたオブジェクトが演算のたびに破壊されるとなると、「破壊されたくないシチュエーション」で困るわけです。そういう場合に必要なのがcloneによるオブジェクトの複製です。

def clone(A, B, C):
  "セルAの内容をBとCに複製する"
  destructive: [A, B, C]
  before:
    assert cur == A
    assert B == 0
    assert C == 0
  do:
    return "[- (move A B) + (move B A) + (move C A)]"
  after:
    assert cur == A
    assert A == 0

たとえば足し算addは

def add(A B):
  "A+Bの結果をBに入れる"
  destractive: [A, B]
  before:
    assert cur == A
  do:
    return "[- (move A B) + (move B A)]"
  after:
    assert cur == A
    assert A == 0
と書けるわけです。ただ、この時点ではまだ「変数」はアドレスの別名でしかありません。しかも変数が指すアドレスが変化することはありません。掛け算のコードを書く際にこれでは不便で、それを解決するためにポインタの概念が誕生する瞬間を目撃してちょっと興奮していたのですが、言葉で説明しにくいですな。

とりあえず出勤途中の電車でメモ帳に手書きした内容はデジタル化出来たので続きは帰りの電車ででも考えることにしましょう。とりあえずアドレスのエイリアスとして生まれた変数はポインタへと進化する必要があるのが1点と、他のコードに副作用を及ぼさずに使うことの出来るテンポラリ領域を取得するための関数allocateが必要です。


__ 遅めの昼ご飯食べながら考えたのですが、Brainf*ckでエラトステネスの篩を実装するくらいはわざわざBrainf*ckを出力するプログラムを作らなくても作れそうな気がしますね。 どっちが大変なのかはよくわからないですけど、でも一度Brainf*ckジェネレータを作っておけばネタとして何度も使い回せそうです。Don't Repeat Yourselfですね。


__ 今日は携帯の充電器を忘れただけにとどまらず、上着も持ってくるのを忘れたようです。

はさみも持ってくるのを忘れました…。


__ 暑いけど席が冷房の直撃する場所なので冷房をつけると寒い。

帰りの電車の中で考えたBrainf*ckの続き。 とりあえず(move A B)は(move B)だけでいいですね。あと、セルが持ちうる値を「正の整数」とすると演算が閉じていないです。つまり0をデクリメントしたときに問題が起きます。そこで「整数」にすると今度はkillの実装が"[-]"ではダメになります。元の数が負の数の場合に問題が起きますから。でもそれでも別に頑張れば実装は出来るからいいのか…とか思ったのですが、WikipediaのBrainfuckの記事が正しければbyte型なので255をインクリメントすると0になる仕様だと考えるべきかも知れませんね。

Index of /brainfuck/compiled/winの実装では確かに255を超えた場合に0にリセットされてますね。でもこれメモリの内容を見る機能がないんですね、使いにくいです。

とりあえず今ちょっと昔書いたインタプリタをいじって、byteとかループのネストとかがきちんと動くバージョンを作ってみました。[]の仕様を誤解してましたね。英語版Wikipediaのプログラムが動いたので今回は正しいと思います。


__

>>> Move(frm = 3, to = 1).make()
'>>>[-<<+>>]'
>>> Move(frm = 1, to = 2).make()
'<<[->+<]'

class Move(Command): "Move(frm, to)" beforeCur = "frm" afterCur = "frm" destructive = "frm to" beforeZero = "to" afterZero = "frm" def do(self): result = "".join(["[-", Go(to = self.args["to"]).make(), "+", Go(to = self.args["frm"]).make(), "]"]) return result

寝ようっと。

2006年06月26日

キミならどう書く 2.0 - ROUND 1

100までの素数をエラトステネスの篩を使って列挙するプログラムを、Pythonで、defもifもwhileもforも使わずに1行(66文字)で作りました。以下はその作成過程のログです。


__ おおっと、今知りました。(via 竹迫さんの記事) キミならどう書く 2.0 - ROUND 1 - — Lightweight Language Ring 締め切りまであと30分しかないですね。うわー、もっと早く気づいていれば…。30分でPythonでdefもifも使わずに1行で素数を求めるなんて(勝手に問題を難しくしすぎ)

def foo(x): return [x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] > 0]]

あと29分!

>>> i = [[],range(2,100)]
>>> while (i[1] != []): i = foo(i)

>>> i
[[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97], []]

とりあえず素数出た!ボーダーラインはギリ越えた! あと24分!whileを使わずにwhileを作るには…

>>> def foo(x):
	if x[1] == []:
		return x[0]
	else:
		return foo([x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] > 0]])

	
>>> foo([[],range(2,100)])
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

あと22分! ifを使わずに分岐をするには…

>>> def foo(x): return (x[1] == []) and x[0] or (foo([x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] > 0]]))

>>> foo([[],range(2,100)])
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

あと20分。うーん、再起を使ってしまうと関数定義で確実に1行使うので1行にまとめることが出来ない…。とりあえず時間がないから現状でコミットしてから考えるか…。

foo = lambda x:(x[1] == []) and x[0] or (foo([x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] >
 0]]));foo([[],range(2,100)])

関数定義をラムダ構文にして解決。


__ 改めてすでに投稿されているものを見てみると…ああ、Pythonでもっと短く作っている人が複数いる…orz。 時間がなくてじっくり既出コメントを読む暇がなかったのですよ、とイイワケ。 4つ目くらいの「圧倒的にPythonに不利な設定ですね!」を見て「そんなわけない!」と奮起したもので。

まぁ、負けてしまったのは仕方がないのでcoolな回答をピックアップしてみるとしますか。

[p for p in range(2,100) if 0 not in [p%d for d in range(2,p)]]

一つ目、なぜこれを思いつかなかったのかちょっと悔しいです。range(2,p)が「2以上p未満の整数」のリストなので[p%d for d in range(2,p)]が「「2以上p未満の整数すべて」でpを割ったあまり」のリストになります。その中に一つでも0があるなら、「2以上p未満の整数の中にpを割り切るものがある」、つまり素数でないということになります。 どれでも割り切れないものだけを残せば残るのは素数っていうわけです。シンプルかつ完璧。

filter(lambda i:reduce(lambda x,y: x*(i%y), range(2,i), 1), range(2, 100))

これも原理は一緒ですね。「2以上i未満の整数」のリストを作って、初期値1であまりを次々とかけていくと、もし0があるなら結果は0になるし、0がないなら結果は0にならない、というわけです。


__ まぁ、初戦は惨敗しましたが、二回戦以降があるならぜひ参加したいところであります。今度トラックバックする時はタイトルにPythonって入れます…。大あわてでトラックバックしたので割と見苦しいですね(´・ω・`)すみません。


__ せめてもの罪滅ぼし(?)に僕が書いたコードの「途中結果を関数への引数として渡す」という設計を見直して72行に縮めてみました。あとPythonインタプリタの直前に評価したものが「_」という名前の変数に入る仕組みを利用して代入も削ってみました。

lambda x:x and([x[0]]+_([y for y in x if y%x[0]]));_(range(2,100))

これでも66文字で、上で取り上げたcoolな解には3文字ほど負けているんですよね…。

自分が負けを認めたくないだけなのだと気がついたので勝ってそうな所で勝負してみよう。所要時間をチェック。

0.00555266102256
0.000577168327259

やった10倍速い。 これで満足して眠れます(笑)

バージョン管理

次のバージョンがbeta1.00なので、beta1.01、beta1.02…と上がっていって、安定版は2.0でbetaを外してリリースにするのはどうだろう。それ以降は安定版は2.01、2.02と上がっていき、開発版は常にbetaをつけてbeta3.00、beta3.01としよう。そうすれば「どれをダウンロードしたらいい?」という質問に「不安定でも機能がたくさんある方がいいのなら数字の一番大きいのを、ある程度安定したものがいいのならbetaのついていないものを」と説明するだけですむし。

参考文献: Open Tech Press | バージョン番号の衰亡

日記

おおっと、うかうかしていたら夏のプロシンの発表申し込みが終わっちゃってるじゃん。参加の申し込みは始まったところなので忘れないうちに申し込まないと。

前回、夜の懇親会でライフゲームの話題が出た際に多人数ライフゲームβなんてのを作ってましたとデモしたのだけど、結局1年間発展無しに放置していましたね。西尾泰和の日記(2006-03-09)でマップを大きくしたらどうだろう、と言っていますけど、やっぱこれ無理にAjaxを使うよりJavaアプレット使う方が素直な気がしますね…。

これのルールに関する考察は昔非公開のPukiwikiに書いたのだけど、どこにバックアップ取ったのやら…。公開していないとこういうときにググれないから不便です。

「ググる」を「ラ行五段活用」で単語登録したけど、「ググれない」はら抜き言葉で変換できない罠。


__ 何をどう間違えたのかカテゴリがGRINEditになっていました。

明日LL Ringのチケットを買わなきゃ。

博士論文がまだ出ていないと事務から電話がありました。博士論文の製本業者の手元にこちらから送った原稿が届いたのは1ヶ月以上前です。やれやれ。製本ができあがったら連絡が入るだろうと思って一時記憶から削除したのが間違いだったのでしょうか。毎週1回くらい進捗状況の問い合わせメールでも投げるべきだったんでしょうか。

とりあえず業者への問い合わせメールは出しました。事務への連絡は業者からの連絡が帰ってくるのを待つよりも、明日すぐ連絡して「業者に問い合わせています」と報告した方がいいだろうなぁ。


__ 区切り線の下についているアンカーはその区切り線から下の文章がその時刻以降に書かれたことを意味しないものとします、とどこかで宣言したい。ネット接続が出来ない環境で書いた文章を貼り付けるケースもありますから。


__ 「売りつくし」ののぼりが「つくし売り」に見えました。

「ツクシ売りの少女」というお話は、 貧しい少女が生活費を稼ぐためにツクシを売るのだけど誰も買ってくれなくて、 飢えに耐えかねて売り物のツクシを生のまま食べているうちに 生のツクシがもつ有害なアルカロイドの影響で幻覚が見え、急性中毒で死んでしまう、 というお話です。(捏造)

ツクシに幻覚作用があるかどうかは知りませんが、きっとこのお話の教訓は「食べられるものでも生で食べられるとはかぎりません」なのでしょう。ドングリ(シイの実)が食べられると聞いて、そこら辺のどんぐりを食べてしまった小学生の僕に聞かせてあげたい話ですね。


__ 木曜日に修理に出したデジカメは土曜日に修理完了の知らせが入り、日曜日はサポートセンターがお休みで、今日引き取ってきました。修理には1週間から10日程度見てくださいと言われていたのに仕事が早い。さすが松下。ナカバヤシとはえらい違いです。

1GBのSDカードって安いものは3000円しないんですねぇ。 高いものはすごく高いので512MBにしようかと思っていたんですが、 デジカメを修理に出した帰りにちょうど安い店を見つけたので そこで買ってしまいました。16MBから1GBになって撮影可能枚数が格段に増えました。 今までは容量節約のために800x600で撮っていたのですけど、 今度からは一番画素数の多いモードで撮影しても300枚も入っちゃいます。 動画も一番クオリティの高いので11分、 今まで通りのクオリティだと1時間以上撮れちゃいます。 そんなにバッテリーが持つのかどうかは知りませんが。

これで今までよりもっといい写真を作れるだろうと期待しています。 たとえば高感度モードにするとノイズが多くなりますけど、 基本的にモニターでしか見ないので縮小しますから、 そこで平均ではなくメジアンをとるアルゴリズムにしてみるとノイズが取り除けるんじゃないかとか。夢がふくらみます。


__ 論文書き。もうワードなんて大嫌いだー! TeXで書きたい! TeXに比べてワードはWYSIWYGなのがいいとする主張もあるけど、 10ptで印刷される文字は画面上では小さすぎます。 拡大すればいいんだろうけど面倒だなぁ。

ワードが嫌いだからといって、じゃぁTeXを他人に勧められるかというと それも微妙なところ。両方のいいところを兼ね備えたソフトが生まれてくれないかなぁ。

だいたい、Microsoft Officeみたいなバージョン感での互換性の低いもので原稿を提出させて大丈夫なのかなぁ。うまく行っているってことは大丈夫なのかなぁ。それともやっぱりうまく行ってなくて、中の人がいっしょうけんめい修正しているのかなぁ。


__ 明日は気分転換で柏に行こうかな。


__ 科研費で買えるものが、学校によってかなり違うことに衝撃を受けました。 たとえば、昨年度いっぱいで前の研究室から借りていたノートパソコンを返却するので新しいマシンを買う必要があり、 昨年度にいた大学では「10万を超えるものは備品」だったので 自費で今使っているノートパソコンを買ったのですが、今の大学では 「20万を超えるものが備品」なのでパソコンが買えてしまう、とか。もっともノートパソコンが2台あっても困るので買いませんが。

そしてさらに驚きなのが、今いる大学では「OfficeやWindowsは科研費で買えません(通常オフィスに備えてあるはずだから)」という決まりらしいです。いやはや。よくわからないけどOfficeを去年の予算で買っておいて良かったです。研究室のライセンスは卒業するときに返すべきだと思ったので自分用に買ったのです。どうせならWindowsXPのライセンスも買っておけば良かったかも知れませんね。

そしてどちらにしても「年度末までに1円残さず使い切ってください」というのは同じ。 まずこの制度を何とかしないと財政赤字削減とか議論しても意味がないよねぇ。 日本国中の、小は僕みたいな年間50万の小規模な予算から、大は省庁の予算まで、ありとあらゆる予算が、年度末になると予算を1円残さず使い切る為に無駄遣いを始めるわけですから。


__ 卵に黄身が2つ入っている確率がいくらぐらいなのか知りたい。 人間の場合は排卵誘発剤を使うと双子や三つ子が生まれやすくなるけど、 同じように鶏に排卵誘発剤を使うと黄身の複数入った卵が出来やすくなるのだろうか。


__ ATOKは使いこなすとすごく便利ですね。住所を打つのに「ちば[Tab][Enter]1ちょTAB[Tab][Enter]」であっさり入力できてとても幸せ。ただしいつまで経っても住所が覚えられないという罠w


__ おおっと、今知りました。 キミならどう書く 2.0 - ROUND 1 - — Lightweight Language Ring。頑張った結果: 西尾泰和のブログ: キミならどう書く 2.0 - ROUND 1

ふぅ。一応完敗ではない(苦しいいいわけ)


__ Brainf*ckでlookup tableではなくまじめに素数を計算したらどうなるんでしょうねぇ。 それをやるためにまず「Python→Brainf*ckコンパイラ」を作ってしまいそうです。睡眠時間がなくなってしまうので見なかったことにして寝ます。

2006年06月25日

日記

今日はだらけてるなぁ。


__ 新宿のジュンク堂に行ってきます。


__ 後輩と飲み。 やはりお酒を飲むと眠れなくなる傾向が強い。 もう28時だ。

2006年06月24日

Pythonでタブ区切りデータを出力する方法

毎回実装するのがさほど苦にならないので、ついつい毎回実装してしまったりするタブ区切りデータの出力ですが、やっぱりたまに改行をつけ忘れたりstrで文字列にするのを忘れたりすることがあるので、まとめてみることにしました。

class TSVFile(file):
	def write(self, v):
		file.write(self, "\t".join(map(str, v)) + "\n")

これは普通のfileを継承して、writeだけ独自のものに差し替えたクラスです。こうすると、以下のように普通のファイルを扱っている気分で、タブ区切りでの出力が出来ます。

fo = TSVFile("c:\\test.txt", "w")
fo.write((1,2,3))
fo.write((4,5,6))
fo.close()

ただし、タブ区切りじゃなくてカンマ区切りでもよくて、数字やアルファベットしか使わないというケースなら20 csv -- CSV ファイルの読み書きライブラリの利用も検討してみた方がいいでしょう。


__ 追記:writeを上書きしてしまわないで、writeListなどといった名前のメソッドを作るのがいいかもしれませんね。

Rで歪度や尖度を計算するには

Rで歪度や尖度を計算するにはe1071というパッケージをインストールすると楽。 インストール方法はRを立ち上げてinstall.packages("e1071")と入力すると パッケージをどこからダウンロードするかの選択ウィンドウが出るので(Windowsの場合)、 近そうな日本のサーバーを選択する。 library("e1071")とやってインストールされたライブラリをロードし、kurtosis(data)というコマンドでデータの尖度を計算することが出来る。歪度はskewness。

日記

エレキギターのピックアップ(弦の振動を感知する部分)って電磁誘導を使ってるんですね。鳴るほど♪楽器解体全書 エレキギターの音の原理。NHKで弦の端にピックアップがある場合と真ん中にピックアップがある場合の音の違いを実験していました。端にある方が倍音成分が多い音になるそうです。エレキギターも面白そう。 名前のわからなかった曲がパイプライン(音が出ます)という名前だと知りました。


_ _ 「学びてプログラミングせざれば則ち罔く、プログラミングして学ばざれば則ち殆し」と孔子も言っているわけですが(嘘)

SQLのクエリーは投げたことがあったけども、テーブル自体を自分で作ったことはなかったので、やっぱり作ってみて色々失敗に気づくことも。年月日ぞれぞれ「年」「月」「日」のカラムにしてしまった(元のデータがそうなっていたから)のだけど、これだと最新のデータを取得するのに"select foo from bar order by year desc, month desc, day desc"なんていう面倒なクエリーを投げないと行けない。投げる僕の方はさておき投げられるSQLiteの中の人は大変だろうな。「年や月に関係なく15日のデータを取得したい」なんてユースケースがあり得ないんだから、年月日まとめてcomparableなカラムを1個作っておいて、ついでにそれにインデックスをつけておけば中の人も楽ちんだっただろうに。

學而不編寫程序則罔 編寫程序而不學則殆。プログラミングってのは「程序(プログラム)」を編んだり寫(写)したりすることなのですか。程序は日程の程に順序の序と。なるほどねぇ。


__ Rで歪度や尖度を計算するには


__ てすと。 ふむふむ、spanでも十分ボタンっぽさをアピール出来ますね。凹んだりはしないけど。


__ Pythonでタブ区切りデータを出力する方法


__ 「暑くてしめっぽくて汗をかいたから」と思ってお風呂に入ると、体の表面が実は冷え切っていることに気がつきます。汗が蒸発せず、熱がこもってしまうのは、実は冷えて毛細血管が縮まっているせいなのかもしれません。梅雨や夏場に「暑くてしめっぽくて気分が悪い」という人はたくさんいても、温泉の洗い場で「暑くてしめっぽくて気分が悪い」って人はあまりいません。どちらかというと温泉の洗い場の方が湿度は高いのに。

防水ノートパソコンは高いのですけど、防水性と排熱を両立させるのが難しいのがなかなか商品化されない理由の一つなので、じゃぁ本体は外に置けばいいじゃないか、と思うのですよ。見える範囲にモニターがあって、手元に濡れても大丈夫なキーボードとマウスがあればプログラミングに支障はないかと。光る“ふにゃふにゃキーボード”が発売、英語版で2,000円とか、光る必要はないですけど手頃な値段で防水ですね。モニターは水のかからない程度に離れた場所で、一応ビニール袋にでも入れて口を縛っておけば大丈夫でしょう。


__ 逆もありかも。 つまり、 「プログラミングして思はざればすなわち罔し、思ひてプログラミングせざればすなわち殆し。」 3週間も前に「これで行けるはず」と思ったアルゴリズムを今やっと実装して試してみていて、 予想通りの結果も出るけども、入力データによっては予想外の値も出ることを知りました。 何か見落としがあったに違いない。 孔子 - Wikiquote


__ 運動がてら自転車に乗ってまだ行っていない方向に走ってきたのですけど、 大阪と違って隣の駅が遠いですね。1~2キロもあったので隣の駅に行って帰ってきただけで結構時間がかかってしまいました。


__ 2005年4月例会@物理教育実践交流会

プラスに帯電したシャボン玉と、マイナスに帯電したシャボン玉を浮かばせて近づけると、互いに激しく回転しながら引き合い、衝突して消滅します。

見たい。


__ デジタル一眼レフのレンズの部分をピンホールに変えるという手もあるようですね…。うーん。デジタル一眼レフを買うか…。その前に、とりあえず故障したデジカメは修理完了したらしいので、それを使って色々試してみてからにしたいと思います。今日、トレーシングペーパーに油を塗り込んで透明度を上げてたところですし。

そうそう、書き忘れてました。今までアルコールと油は混ざると思っていたのですけど、少なくとも飲めるアルコールと食用の油は混ざらないですね。もっと炭素の多いアルコールなら混ざるのかも知れないですけど。油を薄めようと思ってアルコールを入れたのに混ざってくれなくてがっかりでした。

地図を見て、職場のある島の西側は公園だと言うことを知ったので、今度は夕方の海を撮影してきます。


__ 自作ピンホールカメラ1号の内部を黒く塗装したり、光漏れが起きる部分をアルミ箔でふさいでいったり、いろいろな改良を加えています。問題はスクリーンの位置なんですけど、前回の写真を見る限りではピンホールからの光は十分スクリーンの端まで到達していますよね。あ、説明が遅れましたが、僕のピンホールカメラはピンホールからスクリーンに投影されたものをスクリーン背後からデジタルカメラで撮影する構造になっています。スクリーンをもっとピンホールに近づければより広い範囲がスクリーンに映るようになるのですけど、逆にデジカメの画面に移る映像は小さくなります。難しいところです。うーん。高画質モードで取って周りをトリミングするしかないかな。

デジタル一眼レフカメラは「デジタル一眼レフカメラレンタル」を使うという手もありますね。高いものだから色々試してみてどれを買うか決めるってのもいいかもしれません。


__ 部屋が全然片付きませんが、ハウスメイドのキャンディフルーツが20%割引キャンペーンをやっているのを発見してしまいました。うわー。悩む。


__ QRコードBlogを見て 「塗ると絵の出るQRコードって出来るのかなぁ」とか思ってしまった。


__ おおっ。ピンホールカメラのスクリーンを今までの半分くらいの距離までピンホールに近づけてみたのですが、 自分の部屋の照明を見ると肉眼でくっきり輪郭がわかるくらい明るくなっています。スクリーンまでの距離が半分になったのだから像の明るさは4倍になるわけですね。画角は大体40度くらいになったかと思います。一つの照明しか見えない状態では測りづらいですけど、目測で30度くらいには像が写りそうです。早くデジカメが帰ってこないかな。


__ アスペルガー症候群 - Wikipediaは割と充実してますね。ただ過度に賛美している意見がありますね。 多少公平性を欠くかも知れませんが、でも世間一般の認識はかなりお粗末なものですから、多少賛美されているくらいでもいいのかも知れませんね。難しいところです。3カ所ほど修正しました。

ADHD - Wikipediaはまだちょっと物足りないですね。


__ わお、もう26時。

2006年06月23日

日記

今日は調子が悪い。金曜日なので古新聞古チラシを収集場所に持って行き、燃えるゴミを出して、なぜかぼんやりしてしまいました。洗濯して干したはずの服はいったいどこへ行ったのだろう…とか。思いつくところを全部さがしてみたつもりなのにどこにもないし。謎。あと新聞をカバンに入れてくるのを忘れました。

JRの定期券を買いました。ややこしかったですけど。あとりんかい線の回数券を買おうと思ったのですが、財布の中にお札がないことが判明したので買えませんでした。今日の晩ご飯はsuicaの使えるところで食べないと行けませんね。

今月の前半はかなり論文を書く気をなくしていたのですが、やっぱり書いた方がいい気がしてきました。6月末締め切りですけど。Word指定ですけど。

「ICTスクール2006」のチューターをやるのですけど、学振の専念義務とのかねあいでややこしいです。週5時間のTAがOKなんだから単発6日間のTAもOKだと思うのですけど、後で怒られても嫌なので確認しないと行けないですし。去年まではTAは無条件でOKだったのですけど、今年から厳しくなった上に受け入れ研究者の承諾が必要になったので、万が一もめると先生に迷惑がかかります。最悪の場合でも、チューターの方をボランティアにするか、学振の方を1ヶ月中断するかすればいいと思うのだけどもね。


__ あー、論文書きたくない。正確に言えばどうせ書くのなら新しいGRINEditのことを書きたい。でもそれじゃ仕事とは認められないので仕方なく球面自己組織化写像による可視化の話を書く。


__ 【楽天市場】シーグランド クロスバー 800 の検索結果。同じ機種でも色が違うだけで40%以上値段に差が出るとは恐ろしい業界ですね。安いところは黒だけ売り切れています。

論文を書いたら自分へのご褒美で買おうと思っていたはずなのに、いざ安いのを見つけると在庫がなくなる前に買ってしまおうと思ってしまう罠。買いました。


__ 楽天ブックスの大見出し。コミック、写真集、雑誌、小説・エッセイ、ボーイズラブ。そ、そんな分類の仕方って…。


__ Polycomのリモート会議システムはカメラだけで128万もするようです。参考資料


__ 楽天ポイントの履歴によると、楽天市場での購入はポイントで買った場合でもポイントがつくようです。そして楽天カードで支払っているのでそちらにもポイントがつきます。つまり今のところ「楽天市場での買い物2%」>「Suicaでの買い物1.5%」>「楽天カードでの買い物1%」という状態ですね。後はEdyか。

Edyはさておき、楽天のポンカンシステムをまだ使ったことがないことに気がつきました。2ヶ月の間に楽天のシステムを3種類使うと、その2ヶ月に得られるポイントが2倍になる、などのシステムです。これで楽天カードのポイントまで2倍になると楽しいですよね。試してみる価値はあるかも知れません。

さすがにそこまで世の中甘くないようで「ポンカンキャンペーンの対象サービス以外は倍付け対象にはなりません」と明記されていました。カードのポイントが倍にならないのなら、特に必要ない安いものを買ってポイントを倍に増やす戦略も現実的じゃないですね。対象ポイントだけしか倍にならないということは仮に1万円のものを楽天市場で買ったとして楽天市場のポイントが100ポイント、楽天カードのポイントが100ポイントついている状態で倍付け達成しても+100ポイントになるだけ。楽天市場などで10万円使った場合は検討の余地もありますけど、楽天市場で10万円使うかなぁ…。

結局、ポンカンシステムは狙って達成しに行く必要はなさそうですね。

本を買うときは無批判にアマゾンを使っていたのですけど、楽天ブックスの方がいい場合もありますね。1500円以上の場合はどちらも送料が無料になるので、つくポイントの差で楽天の方が上ですし。安い場合も7月末までは楽天が送料無料キャンペーン中なのでやっぱり楽天の勝ちです。8月以降も楽天は250円でアマゾンは300円なのでやっぱり楽天の勝ち。アマゾンは古本が安い場合に有利ですね。

こうやってたいした額ではない金額を削り落としていく作業は、プログラムから余計な部分を削り落として高速化する作業に通じるところがあるから楽しいのかも知れません。


__ 今日発見した顔文字: (๑→ܫ←)。 各種顔文字の変遷をたどると進化系統樹が書けるかも知れません。

いや、違う。細菌同様、水平伝播が頻繁に起こるからツリーにならないに違いない。

文章中での出現頻度が低い文字でほとんどが構成されているような顔文字に関してはこの前作った隠れマルコフモデルのViterbiアルゴリズムで切り出せるはずですな。mixiの日記をいくつかの顔文字で検索して、ヒットした日記から過去にさかのぼりながら切り出していけば、特定宿主内でそれぞれの顔文字が占める割合がわかるはずですね。

あ、これは今はやりのメタゲノムじゃないか!(んなわけない)

とりあえず今はそんなことしている場合ではないのでこのネタは塩漬け。


__ 学振とチューターの話はやっぱりややこしそう。「アルバイトは週あたり5時間を上限とする」という文章が今年から規約(?)に導入されたのでダメみたいですね。でもいくら専念義務とは言っても1週間の休暇くらい取れるはずですし、休暇中のボランティア活動を禁止するような条項はどこにもない。アルバイトじゃないかと疑いをかけられた場合のことを考えてしかるべき立場の人に「アルバイトではなくてボランティア活動である」と書いてもらえばいいんだと思います。


__ 迷惑トラックバックが2件来ていた、という先日の話は事実誤認で、通算427件の迷惑トラックバックのうちMovableTypeのスパムフィルタが自信を持てなかったものが2件あると言うだけでした。いやはや、スパムフィルタのないブログなんか運営したら死にますね。


__ おなかすいたなぁ。土日はどうしようか。家の机は集中して長時間の作業すると腰が痛くなる椅子だけど、土日に集中して作業が出来てネットも出来るところってのもあんまりないよね。


__ バランスチェア 意外と安いですね。ちなみにこれは楽天アフィリエイトで生成したリンクなんですが、リンクの脇にサイズ1x1の小さな画像があります。これがクッキーを仕込むんでしょうかね。


__ 楽天カードが三井住友から楽天KCに変更になったようですね。最初からこういう戦略だったのでしょうか。巧妙ですね。三井住友の信用力を利用して囲い込んでおいて「8月1日以降の利用には楽天ポイントがつかないので楽天KCのカードに変更してください」とやってその囲い込んだ会員をごっそり引き抜くわけですね。うーむ。巧妙だ…。市場自体を手中に収めて売り手から手数料を取りつつ、カードローンで買い手からもお金を取るって訳ですな。僕はクレジットカードでお金は借りないので別に構わないのだけど。

ガーン。楽天KC発行の楽天カード限定で楽天市場での購入ポイントが2倍になるキャンペーンをやってる!今日買った分は三井住友だからポイントが倍にならない!ひどい!注文決定前に教えてよ!

カードの与信調査のフォームっていつも困ります。なんでこう、網羅されていない質問文なんだろう。仕事の種類が「お勤めの方、学生の方、主婦の方、年金の方」で「お勤めの方」を選ぶと「資本金の額」が必須です。おかしい…。こういうところに限って「その他」の欄がないし。勤務先の種類も、選択肢に宗教法人はあるけど独立行政法人はない。誰がこの選択肢を考えたんでしょう。この選択肢に答えることにいったいどういう必要性があったんでしょう。

2006年06月22日

日記

今日はいつもより1時間ほど早く朝の作業が済みました。何か忘れてるんじゃないでしょうか。

お弁当とお茶の用意をしたらいつも通りの時間ですね。 りんかい線は大手町を通っていることが判明。


__ デジカメは一応修理に出しましたが、有償になる可能性もあると釘を刺されました。まぁ、仕方ないですね。

秋葉原で見かけたX-CUTE クロスキュート - USBデジタルオーディオプレーヤーはあまりの小ささに笑ってしまいそうになりました。これで録音もできてしまうんだから怖い世の中になったものです(笑)

買おうかと迷っていたX-Bar XB800 クロスバーは店頭にはなくて代わりにXM002 X-mate クロスメイトが並んでいました。写真よりはキュートでしたが、150%高速再生の機能はなさそうです。

当初はボイスレコーダーを買おうと思って調べはじめたのですが「講演や議論を録音して後で聞き直す」なんてまめなことを僕がするのかどうかはなはだ怪しいと思うようになってきました。歩いているとかのメモが取りにくい状況でアイデアを記録するのにはこういうポータブルプレーヤーについているプアなマイクで十分そうですし、そう考えると「講演がしっかり取れるマイク」と「150%高速再生機能とデザインの良さと安さ」を天秤にかけると…うーむ。


__ そうそう、前に日記に書いた「はてなの広告はなぜ飲み物でもないのに『スポンサー ドリンク』なんだ?」という疑問は今「スポンサード リンク」だと言うことに気がついたので見なかったことにしてください(笑)


__ コメントで < を使うと、たとえ前後に空白文字を入れておいてもタグだと見なされて削除されているようです。そして&lt;にしてプレビューするとうまく行ったように見えるけどもテキストエリアの中はエスケープしていない < に戻っているのでうまく行ったと思って保存するとうまく行っていない罠。うーん。 今日はMovableTypeハックはしない。


__ 研究室に僕一人しかいなくてだいぶ寂しいんですけど。


__ M1の時の同期と飲み会。酔っぱらい。ビール1~2杯と日本酒2杯で酔っぱらうようになりました。かなり弱い。


__ 酔っぱらいごっこは楽しいです。具体的には、演歌っぽい鼻歌を歌いながら自転車で蛇行運転したりすることなのですが、でもよろめいて壁に膝をこすったのは事実なので実は「ごっこ」ではないのかも知れません。

2006年06月21日

物理演算の対象

剛体を実装しようかと思ったのですが、その前に物理法則をCommonGateway経由で操作できるようにした方がテストが楽ですね。

物理法則は「対象」を引数に取ります。たとえば「全頂点」であったり「全辺」であったり「anchoredな頂点」であったりします。これの「対象」の表現には「名前付きリスト」を使うとよさそうです。1つの「名前付きリスト」は1つの名前と複数のオブジェクトを持ちます。

頂点と辺の区別は重要ではないのかも知れません。現状で頂点リストと辺リストを分けて管理していること自体が不必要に具体的であるとも考えられます。でもそこまで抽象化するのは、抽象化するニーズが生じてからにした方がいいかと思います。過度の抽象化によってパフォーマンスが劣化しても仕方がないですし。

地球シミュレータが排出するCO2の量

地球シミュレータがどの程度の量のCO2を排出しているのか気になったので計算してみました。

地球シミュレータ開発の現状(PDF)によれば1つのノードで8kVAだそうだから、640台で5120kVAです。ほとんどの電力はCPUで消費されるだろうからこれはほぼ5120kWと見なして良い、という考えで正しいのでしょうか。24時間稼働しているので1日の消費電力は24倍して122880kWh。中部電力 | 新エネルギーデータ - 発電方式別CO2排出量によれば1kWhを石油火力で発電すると742gのCO2が発生するようなので一日あたり91176960gのCO2が発生する。つまりおよそ91.1トン。えー、そんなに多いの?計算間違ってない?日本のCO2排出量 によれば2000年度の日本のCO2排出量は12.7億トンなので地球シミュレータは日本の全CO2排出量の0.0026%を占める。仮にCO2排出量を1億人に均等に割り当てたとしたら地球シミュレータだけで26万人分を排出する計算に。これでもまだノードの消費電力だけで、それによる発熱を冷やすための空調や、照明や、その他もろもろは計算に入っていないのだけど…。えっと、1日あたり91.1トンのCO2が排出されるという計算が正しいとして、91.1トンとはどれくらいなのか、というのも計算してみましょう。排出権取引を活用したCO2フリーガソリン企画によれば「クルマ1台で1か月に120リットルから130リットルのガソリンを使います。ガソリン1キロリットルあたりの二酸化炭素排出量は2.3トンです。」とのことなので91.1トンのCO2を出すガソリンの量は39.6キロリットルです。それは月に125リットルのガソリンを消費する車で317台分。と言うことは30倍して、9510台の車が1日に排出するCO2と地球シミュレータが1日に排出するCO2の量が大体同じ、ということですかな。

日記

雨なのであまり光が強くないですけど、夜の電灯よりは明るいことを期待してピンホールカメラで撮影。

pinhole
pinhole posted from フォト蔵

一応、絵にはなるようです。

pinhole2
pinhole2 posted from フォト蔵

しかし、ここで悲しいお知らせがあります。 この写真を撮った後、手を滑らせてデジカメを落としてしまったのですが、30センチ程度の高さからだったにもかかわらず打ち所が悪かったようで、動かなくなってしまいました。エラーメッセージを調べてみるとレンズ駆動系に異常が起きている模様。これは修理するしかなさそうですね。当分写真は撮れません…。


日記ページに過去の日記すべてが表示されていて膨大な量になってきたので、最新5件のみ表示にして、残りはページ待つ二タイトルの一覧を載せる形にしてみました。


うーん、シャワーを浴びてお弁当を作ったら乗る予定の電車にぎりぎり間に合いませんでした。 もっと早く作り始めるべきでした。朝起きた後にすぐご飯を炊き始めるべきでしたね。 あとお弁当箱にご飯が1合入らないのでもうちょっと大きい入れ物を探さないと。 箸箱も必要。 余ったご飯は小さいおにぎり1個分くらいだったのでおにぎりにしました。

今日のお弁当は写真を撮れないので言葉で記録しておきます。ご飯とソーセージ2本と冷凍ほうれん草とキムチ。今日は野菜が少なめなので駅前のスーパーでプチトマトを買って持って行くことにしましょう。

しなきゃいけないことの把握や優先順位をつけることがまだ下手なんでしょうね。MovableTypeのテンプレートをいじる必要はなかったはず。


オオムラサキのサナギは脅かすと暴れるらしい。うねうねと。気持ち悪い。


「新しい方から6件目の記事~一番古い記事」を<MTEntries lastn="5">で取得できたつもりになっていたけども、これでは「一番新しい記事~古い方から6番目の記事」になっていた。謎。古い方から削られる原因はContextHandler.pmの828行目付近で「lastnが指定されている場合だけ作成日時でソート」になっているせい。 直後の my $off = $args->{offset} || 0; と位置を交換して、 if ($n) と書かれているところを if ($n || $off) に変えるだけで「offset使用時にlastnの指定が必須」という謎仕様は解決できそうに思う。でもそれは僕の仕事じゃないし lastn = "999999" で用は足りたので別にどっちでもいいや。


スラッシュドット ジャパン | 理研が 1ペタフロップスのスパコン「MDGRAPE-3」を構築

じゃあ、もう少し単位を工夫しよう。基礎研究の意義は科学的好奇心っていうことだから、

おもしろおかしい(ワロス)/秒

というのはどうか。「こんどのスパコンは2ペタワロス/秒を稼いだ」とか。

「ワロス/排出CO2量」がいいな。地球シミュレータが排出するCO2量ってどれくらいなんでしょう。 計算してみた結果は「地球シミュレータが排出するCO2の量」に書きました。


GRINEdit系のページにスパムトラックバックが2つ来てました。少なくともbotには知名度が上がりつつあると言うことでしょうか(苦笑)


なんとなく正規表現オプションにigとつけたせいで、ソースコード中のgrinedit.addVertexのgrineditもリンクに置き換えられてしまっていました。修正。 それはそうとPerlのeオプションは便利ですね。Pythonにはないのかな。あ、あるね。Perl-likeなのじゃなくてJavaScript-likeなのが。

>>> import re
>>> def foo(x):
	return str(int(x.group()) + 1)

>>> re.sub("\d+", foo, "aaa66aaa")
'aaa67aaa'

書き忘れ。 日経新聞より。はてなでは「50%ルール」と言うと「完成度50%の試作段階でサービスを提供する」ということを意味するらしい。


昨日は御茶ノ水駅かと思ったら新御茶ノ水駅だったり、有楽町線と有楽町新線があったり、東京の不親切さを改めて思い知ったのでした。


VIEWカードの申込書が届きました。Suicaに67000円チャージするとたまったポイントで1000円Suicaにチャージできるようです。1.5%。普通の買い物では0.5%。つまり僕は可及的速やかにVIEWカードを作って、電車賃とSuicaの使える店での支払いをこっちのカードでやればいいわけですな。

ガーン。申込書が届いたのだと思ったらカードが届いたのでした。今朝3000円分チャージしたのに。45円損した。まぁいっか、45円だから。

定期券の計算。りんかい線の定期は、月に20往復しないと採算が取れません。ひどい。 そして今日初めて回数券があることを知りました。五月頭から今までのりんかい線の運賃が1割引になると計算すると…わっ、2000円ほど損してる!今日の帰りに回数券を買うことにします。JRの方の定期は1ヶ月定期でも採算ラインが15往復。三ヶ月定期で14往復、6ヶ月定期で12往復。やっぱり定期はこれくらいのところが採算ラインじゃないとね。20往復が採算ラインだったら土日休みの人にほとんどメリットがないもの。

月に15往復以上する場合に1ヶ月定期を6回買うと、18往復分5220円の損になります。逆に1ヶ月定期を買っていた方が得をするケースは「定期が切れた時点で次の1ヶ月の利用回数が0だと予想できる場合」かな。ふむ…6ヶ月定期を買おうか。 いつも帰りの新木場での乗り換えで待たされるのでそこで買おう。


「eBayで自分の時間をオークションにかける」なんて人もいるのですか…。僕が仮に自分の時間をヤフオクに出したらいくらくらいの値がつくんでしょうかね。誰も入札しないと悲しいので出しませんが。


壊れたデジカメの件、今日電話しなくても先延ばしになるだけで何も解決しないのでサポートセンターに電話をかけてみました。出た人が聞き取りやすい声の女性だったので助かりました。土曜日に秋葉原に持って行って預ければ7~10日くらいで戻ってくるそうです。土曜日はららぽーとに行ってこの前もらった福引き券を使おうと思ったのだけど、確か前回も休日で混んでいたことですし、平日のいつかに早めに帰ってやる方がいいかもしれませんね。平日は20時までみたいですし。ここを19時に出れば一応間に合うのかな?


ふぅ、ただいま。 帰りに南船橋に行って福引きしてきましたが、期待したぐるぐる回すやつじゃなくてただの紙切れで、しかも自分で選べずに渡されるだけだったのでちっとも面白くありませんでした。ポケットティッシュ2つ貰っただけですし。電車賃を考えると高いポケットティッシュですな…。


だいぶこっちで日記を書くのにも慣れてきて、特にタイトルをつけるまでもない雑記は区切り線だけ書いてつらつら書き、ある程度の粒度を持っていてリンクを貼ったりコメントを書いたりする人がいそうなものは書いた後とかでも個別のエントリーに切り出したりしているのですが、それでも本人が予期しないところにリンクを張りたい人もやっぱりいるのかも、とも思うわけです。で、今区切り線はMovableTypeのグローバルフィルタを使って<split>というタグではいるようにしているので、なんだったらこれをいじって適当なアンカータグが入るようにしようかな、と思うわけです。

んー。save時に呼び出されるようなフックをかけることができるようなので 保存テキスト中に適当な文字列があればそれを<split><a name="時分秒">_</a>に置換するなんてのがいいかもしれないですね…。

あ、編集画面についている「strongタグで挟むボタン」に仲間を追加するのもいいかも。


問題のデジカメは今よく見てみるとレンズが少し斜めになっています。あちゃー。土曜日に修理に出そうかと思っていましたが、土曜日に出しても工場に届くのが月曜だったりしそうなので、明日秋葉原に寄ってから出勤することにします。


tmpl\cms\edit_entry.tmplはHTMLとMTタグとJavaスクリプト(による分岐とwriteの嵐)が入り交じっていて、なんともはや。む、編集用ボタンを表示するためのボタンを記述しているコードにそっくりなものがもう一カ所あるぞ?あ、本文用のボタンと追記用のボタンか…。ってdon't repeat yourself…。

そして肝心のボタンが押されたときのロジックはこのテンプレートの中にはありません。ロジックはmt-static\mt_ja.jsの中。えっと。MovableTypeの中の人はすごいなぁ、この設計でこれだけのクオリティのものをリリースできるなんて。僕だったら絶対「上だけにしかstrongボタンがないぞ」なんて事態になりそうです。ビューとロジックを分離したかったのはわかるんですけど、このJavaScriptと独自タグまみれのビューじゃデザイナはいじれないわけですし、なにより「ビューとロジックの分離」と「Don't Repeat Yourselfの原理」では後者の方が圧倒的に強いと僕は思っているんですけどもね。後者はJavaで可視化ソフトを作るときにもPostScript手書きで図を作るときにも通用する「原理」であるのに対して、前者ははるかに狭いドメインの「ローカルルール」な訳で。

っていうか*.tmplの中に「Ctrl+Shift+Pで非公開にする」ロジックがあり、*.jsの中に「Ctrl+Shift+Bでstrongにする」ロジックがありました。分離できてないじゃん!


そうか、わかった。僕は病的にコードクローンを嫌っているのかもしれない。 JavaScriptのサンプルを探していて下のようなコードを見かけたら

if ( hour < 10 ) { hour = "0" + hour }
if ( min < 10 ) { min = "0" + min }
if ( sec < 10 ) { sec = "0" + sec }
result = "" + hour + min + sec;

Pythonでならこう書けるのに、もしくはこう書けるのに、JavaScriptで同じようなことはできないのか、というのをまず考えてしまう。上の4行をコピペすれば用は足りるのに。

result = ""
for v in (hour, minute, second):
	if v < 10:
		result += "0" + str(v)
	else:
		result += str(v)
"".join(((v < 10) and "0" + str(v) or str(v) for v in (hour, minute, second)))

__ 一応できました。MovableTypeの元からの仕様でボタンを押すとテキストエリアが一番上までスクロールしてしまうので、今度web-conte.com | MTの編集ボタンを追加・改造するを参考にして直してみるとしましょう。それに今日はMovableTypeの改造をする予定ではなかったはずなのに。もう今日は残り9分だし。うむむ。


__ とりあえず食器を洗わないと…。 お弁当を作るのは冷凍しておいてレンジでチンすれば割と楽だけども、その分汚れた容器がたくさんできるので洗うのが大変。

一応洗い終わり。えっと。次は。そうそう、デジカメを修理に出すので保証書を探さないと行けないんですな。


__ ううむ。電化製品などの保証書は全部まとめて一つの箱につっこんであるので、デジカメの保証書もそこを探せばすぐに見つかったのですが、普通こういうのって店の名前や購入日時が書き込んであるorシールが貼ってあるor判子が押してあるもんじゃないですか?何も書かれていない保証書って購入日時を証明できないじゃないですか…。確かクレジットカードを使えない店だったからカードの仕様履歴には載ってないし…Google先生に聞いて僕がデジカメを買った日時を特定(西尾泰和の日記(2006-04-15))し、その周辺のレシートが入っているバインダーを探しました。見つかりました。やれやれ。やっぱり検索できることは重要ですね。レシートも月ごとに分けて分類していなかったら見つけ出せなかったでしょうし。後は明日忘れずにこれを持って行くこと、と。

あ、これ手書きで僕の名前が入っているからわざわざ書かせた領収書ですな。収入印紙が貼ってあるし。高額な買い物の時は領収書を書かせる、というのも重要なわけですね。


__ あ、a nameだけじゃリンク貼りづらいですね。でもhrefも埋めるとなると、現在編集中の記事がどういうURLで公開されるかを知る必要があります。今度考えておきましょう。

あー、あった。簡単でした。

<TMPL_IF NAME=ENTRY_PERMALINK><a href="<TMPL_VAR NAME=ENTRY_PERMALINK>"><MT_TRANS phrase="View Entry"></a></TMPL_IF>

これが「エントリーを確認」リンクのテンプレートなのでこのパーマリンクのURLをタグを生成している関数に渡してやればよい。


__できた?できたっぽい。 テキストエリアがスクロールしてしまうのを防ぐ件は、僕のユースケースではこのタグは末尾に追加しかしない(時分秒を入れるのはその時刻にその区切り文字以降を書き始めたことの記録のためだ)から、 e.scrollTop = e.scrollHeight; で末尾までスクロールさせるだけで解決。これで自分には十分。さぁ結局、今日の夜はMTHackで終わってしまった。カブロボ作ろうと思ったのに。

2006年06月20日

日記

口内炎がもう1週間くらい続いているので、きっとスタミナが足りないんだと思って、ニンニクを無料で追加できるラーメン屋に行ってたっぷりニンニクを取ったら、体が負けました。

就職3年以内に離職する人の割合は大卒で35%だそうです。3人に1人を超えてるんですね。

NHKがスタジオパークを略して「スタパ」と表示するたびに、スタパ - Google イメージ検索の方を連想します。

14時半。おなかすいてきたので朝ご飯を…。 冷凍ご飯を解凍するのも初めて。

夕張市が財政破綻ですか。

はっ、プロフィールのページ変えないと…。


ふー、はー。

せっかく晴れているのに家に引きこもっていると良くないと思って、池袋のジュンク堂と東急ハンズに行ってきました。池袋の地理は比較的わかりやすいですね。ジュンク堂とハンズは結構離れていますが迷わずに行けました。池袋のジュンク堂は梅田のジュンク堂が8階建てになったような感じで結構本が多いですね。22時までやっているようなので仕事帰りによるのも悪くないかも知れませんね。今調べてみたら東京テレポートから1本で池袋まで行けるようですし。31分だそうな。

しかし今日は、暑いだろうと思って半袖Tシャツだけで出かけたものだから帰りの電車で冷房の真下に立ってしまったせいで全身鳥肌立ってしまい、やむなく途中下車をするハメになりました。侮りがたし。

ジュンク堂ではどんな本がどれくらいあるかの視察ついでにPHaT PHOTOの2005年11-12月号の取り寄せを頼んできました。ピンホールカメラが付録についているらしいので。

それはさておき今日は東急ハンズでピンホールカメラの材料を買ってきたのです。

P1000732
P1000732 posted from フォト蔵

初ピンホール写真。天井から下がっている丸い照明です。暗すぎてきちんと写っているのかどうかすらよくわかりませんね。明日の朝まで待って風景を撮ってみます。

ちょっと調べてみたのですが、竹中大臣が「ETFは絶対儲かる」と言ったときに日経平均連動型のETFを買っていれば3年で2倍に増えていたんですね…。年利に直して25%です。もちろん買ってなかったのですが。それと比べると「村上ファンドに1000万円を拠出していた日銀の福井俊彦総裁が2005年末までの6年間余りで約1200万円の累計運用益を上げていたこと」(出典:NIKKEI NET、年利14%)って実はそんなに騒ぐほどの利益ではないような気がします。僕を含め多くの人間は、竹中大臣の言うとおりにETFを買っていれば得られたであろう年利25%の利益を、愚かにも銀行預金をすることによってドブに捨てたと言うだけのことなのかも知れませんね。ドブに捨てた人がドブに捨てなかった人を責めるのはおかしいです。

というか年利14%ってほのぼのレイクとかよりも安いんですね。

あっ、もう25時。眠い。部屋が片付いていない。っていうか工作したせいでかなり散らかってる…。さすがに床にはもの置いていると明日の朝悲劇が起きるかも知れないから片付けるか…。今日は結局ほとんど作業が進んでいない。

寝るべきなんだろうな。今から作業をはじめると確実に明日に影響が出る。 今までだと朝の五時頃に眠くてたまらなくなっていたような状態に、夜の二十五時頃になるようになりました。健康的?朝の五時だと「今から寝ると午前中に起きられないから起きていた方がいいんだけど眠い…」という葛藤があったけども夜の二十五時なら「今寝ないと明日の朝に起きられないし眠いから寝よう」になって問題なく眠れる…かと思いきや「あー、あれもこれもやるつもりだったのにできてないー」と思ってやっぱり眠れない罠。

っていうか明日の朝ご飯何にしよう。冷凍ご飯を解凍して卵を書けるくらいしか作れるものがないぞ…。

電源の入ったマシンが目の前にあるとキーボードを叩いてしまう習性があるのでとりあえず電源を落としてみよう。

2006年06月19日

log

今までの修正をコミット。

XMLRPCHandlerクラスは、JSONやJythonなどからも共通して使うようにするので、CommonGatewayという名前に変えました。GraphVisualizerTestっていうメインクラスもGRINEditにしました。次回リリース時にはデフォルトのフォーマットをJSONにし、バージョンはbeta-1.00にすると思います。

次期リリース時にはドキュメントも最低限「きちんとしたJavadoc出力」くらいはつけるようにしましょう。

軽く試しにJythonからCommonGatewayのメソッドを呼んでみましたが、案の定「TypeError: addVertex(): 2nd arg can't be coerced to java.util.Hashtable」と言われました。JSONで同じ現象が起きたときは、JSONのライブラリがソースコード付きで小さかったのでJSON側をHashtableを使うように書き換えたのですが…Jythonのライブラリも書き換えるのはあんまり現実的じゃないソリューションですよね。 CommonGatewayのメソッドの引数をObjectにしておいて、中でリフレクションで適切な型にするのが妥当でしょうかね。「上位クラスで受ける」という所で気がついたのだけどもJSONの「Hashtableが欲しいところにHashMapが渡される」という問題はMapで受ければいいだけでしたね。たぶん。

英語のページをエキサイト翻訳にかけてみる。layoutは名詞だからlayoutedにしちゃいけないのか。

Javadoc用のコメントがついていないところを警告するようにしたら警告だらけ。コンパイラを変えてGenericsを使っていないところを警告するようにしたらまた警告だらけ。っていうかJSONObjectがHashtableを継承していて、警告が出るのだけども、JSONObjectは総称型ではないからパラメタライズできないと怒られる。そんなこと言われてもなぁ。

Jar中のクラスをロード

一応、Jarファイル名とクラスの名前を決めうちでロードすることに成功しました。実際のクラス名はorg.nishiohirokazu.sample_grinedit_plugin.SamplePluginVertexですが、Jarファイルのエントリー名としてはorg/nishiohirokazu/sample_grinedit_plugin/SamplePluginVertex.classであるのが注意点ですね。かといってユーザーにデフォルトパッケージでプラグインを作られるとプラグイン同士で衝突する可能性が出てくるので好ましくないですね。変換はピリオドを置換してから末尾に".class"をつければいいんでしょうか。

異なるクラスローダで読んだクラスはキャスト互換性がなくなるようなことを書いてあるページがあったので、クラスローダを自作してしまうと根っこから全部そのクラスローダを使うように書き換えないといけないのじゃないかと不安に思ったり、クラスローダを作成せずに済む方法はないかと模索したりしていましたが、そんなに難しく考える必要はなかったようです。

セカンダリモニタにアイコンが移動する問題

Windowsでプライマリモニタの左側にセカンダリモニタを接続する場合に、普通に「画面のプロパティで左側にセカンダリモニタを配置して『Windowsデスクトップをこのモニタ上で移動できるようにする』オプションをONにしてOKを押す」という方法ではデスクトップのアイコンの自動整列がOFFであっても移動してしまう。 しかし「右側にセカンダリモニタを配置して『移動できるようにする』をONにしてOKを押す」をした後、改めて「セカンダリモニタを左側に配置変更」ならばアイコンの自動整列がONであってもアイコンは移動しない。

夜景

金曜日に撮影した夜景の写真。「夜景」というと人工的な建築物からの光を直接撮ることを考える人が多いですけど、「夜の景色」はそれだけに限らないなぁ、と撮っていて思いました。我々の目には黒にしか見えない夜の空がこんなにも表情豊かだったとは…。

P1000642
P1000642 posted from フォト蔵
P1000641
P1000641 posted from フォト蔵
P1000670
P1000670 posted from フォト蔵
P1000681
P1000681 posted from フォト蔵
P1000712
P1000712 posted from フォト蔵
P1000711
P1000711 posted from フォト蔵
P1000713
P1000713 posted from フォト蔵
P1000698
P1000698 posted from フォト蔵

日記

昨日は晩ご飯を20時くらいに食べて、そのまま寝てしまい、そして4時半起床。

お茶でも沸かそう。

8時間寝ているから十分なはずなのに、結局二度寝をして時間がなくなる罠。 今日は人生初のお弁当を作ったのだけど野菜とご飯しかない…。

ソーセージをレンジで加熱してたらまた遅刻だ!


日経新聞より。はてなはフリーアドレス制で、しかも「昨日座った席には座ってはいけない」というルールなんだそうです。コミュニケーションを盛んにするのには賛成です。イノベーションは雑談から生まれる場合も多いとは思います。ただ、人に話しかけるて作業を中断させることによるコストをどうやって減らしているのかが疑問です。世の中には、集中しているときに話しかけられると生産性ががた落ちになってしまうタイプの人もいるわけですから。個々人が「話しかけてもいい状態」か「集中して作業しているので中断しない方がいい状態」かを可視化するとか、個々人のインタラプトに対する耐性を測定するとか、そういう研究が必要かも知れません。

金曜日に撮影した夜景。撮影するために立ったりしゃがんだりを繰り返していたらめまいが…。血液が足りない?鉄分豊富な小松菜を食べる?献血に行ってみる?秋葉原で?(ぇ)

「めまい」で変換すると「眩暈」と「目眩」が出るけど、どう違うのでしょう。gooる。「目眩」は「目眩い」と書けば「めまい」とも読むけれども、「目眩し」と書けば「めくらまし」、「目眩く」と書けば「めくるめく」と読むようです。一方「眩暈」は「めまい」とも読むけれど「げんうん」とも読み、「実際には静止しているのに、自分の周囲や自分自身が回転しているように感じたり身体が浮き上がるように感じること。」と説明されています。たぶん、同じ脳虚血(いわゆる貧血)でも目の前が真っ白に光る症状の方は「目眩」で、世界がぐるぐるまわったり壁や床が波打ったりする方は「眩暈」なんでしょう。金曜日のめまいは眩暈の方でした。目眩は満員電車で長時間揺すられたときに一度なったことがあります。

Javadocの説明を読んでいたはずなのになぜかJarでプラグインを作るほうを…あ、そうかJavadocを試してみようとEclipseを立ち上げたら前回コンパイルエラーの状態で終了していたのを見て直し始めてしまったのか…。一応Jarからクラスを読み込んで使うところは動いたのでメモ。

はてなの回答のおかげで、一人で悩んでいたら解決までにもっと時間がかかっていたであろう問題が解決したら、「え、これで60ポイント?安いな。もっとあげちゃおう!」となるのは割と自然なことだと思う。 日本に寄付の文化がないから云々とか議論されることもあるようだけど、問題はそこではなく、日本に「サービスの対価として自分で金額を決めてお金を払う」チップの習慣がないことなのではないだろうか。 Wikimediaに対する寄付なんかと、日本の小学校でやったりする「赤十字の募金」とは別物だと思う。後者は見返りを期待しない「喜捨」だけども、前者はWikimediaの喜捨によって僕が得た利益に対する対価を自分の払える/払いたい範囲内で支払っているだけだもの。

はてなには「ポイントを必要としない回答」をサポートして欲しいな。たまに「その質問文じゃ答えるのに必要な情報がだいぶ抜けてるから答えようがないじゃん…」という質問文もあるのだけど、「それじゃ答えられない」って回答でも質問者は10ポイント負担が増えるので嫌がるかも知れない。質問者もお金を出すからにはいい回答が欲しいわけで、そういう「質問スキル」を学ぶチャンスを与えることで質問の質を改善し、質問者の満足度を高めることが必要なのではないかと思う。

あと、回答に対して最低配布しないといけないポイントが質問1個50pt+回答1つあたり10ptに固定なのはおかしい。倍払ってもいいから回答が欲しい人もいるわけだからそこは質問後にもつり上げられるようにするといいと思う。配布ポイントをつり上げるたびに質問一覧のトップに上がってくるとか、「現在もっとも配布ポイントの高い質問一覧」のページを設けるかするといいと思う。でももらえるポイントが多くなってくると、ポイント目当てで適当な回答をする人も出てくると思うので、なんらかの方法で「その回答にはポイントを払わない」とする方法が必要。そうなるとその方法を悪用する人も出てくるかも知れない。その辺が難しいのか…。

質問者は回答を却下することができて、却下された回答者は不服を訴えることができるというシステムはどうだろう。不服が訴えられた場合は、回答者の希望額が質問者に伝えられ、払うかどうか質問者が判断できる。払わないと判断した場合(示談決裂)は、はてなアンケートで二人以外のユーザーに判断がゆだねられ、そのアンケートの費用100ptは敗訴した側の負担になる。現状で回答に与えられるポイントはたいがい100ptより少ないのでポイントの額よりもプライドを満たすための戦いになりそうです。

GRINEditのプラグイン機能を今日実装する気はあまりなかったのに、9割方できてしまった。pluginsフォルダの中を再帰的に検索してjarファイルを探すので、readme.txtやjavadocの結果を添付することもできるような感じ。

javadoc - Java API ドキュメンテーションジェネレータに書かれている

最初の文 - 各 doc コメントの最初の文は、宣言されているエンティティに関する簡潔かつ完全な要約文である必要があります。この文は、後に空白、タブ、または行末記号が続く最初のピリオドに遭遇した時点、あるいは最初のタグに遭遇した時点で終了します。最初の文は、Javadoc によって HTML ページ上部のメンバの概要の部分にコピーされます。
が本当なら、「日本語の説明。\n英語の説明.\n」は日本語と英語の両方の説明が出るはずだが、そうはなっていないようだ。改行が区切り文字になるのは嫌いだ。

うわー。1行目かそうでないかに意味を持たせているのに、Ctrl+Shift+Fでフォーマットすると勝手に1行目をつなげたりするぞ。

もうJavadocに期待しすぎるのはやめよう。最初に英語を書いて後に日本語を書こう。最初の1文がきちんとようやくになるようにだけ気をつけて書こう。将来的にはドックレットをいじって日本語部分を出力しないことも可能にしよう。

おなかすいた。もう20時か。

25時。

あー。Jarの中にmainメソッドがあるってのもアリなんですな。いわれてみれば当たり前ですけど。

2006年06月18日

日記

だいぶ朝型に変わりました。休日なので目覚ましをかけずに寝て「昼過ぎかな」と思いつつ起きたらまだ10時半。

アタック25を録画してみよう。マウスカーソルを一時停止の所に置いておけば早押しクイズっぽくなるはず。

朝起きて真っ先にパソコンの電源を入れるのはおかしい。ご飯を炊かないと朝ご飯がないじゃないか…。今から炊いても昼ご飯だし。っていうかタイマーで炊いておくべきだったか。

5月2日から比べてウェスト3cm減。でもまだまだ博士論文を書く前に戻っていない。

小松菜を買ってみたらすぐにしなしなになってしまった…。調理して冷凍しとくか…。

山瀬まみはすごいなぁ。野菜はアブラナ科やナス科など、違う科のものをバリエーション豊かに取るようにしているんだそうな。小松菜はアブラナ科で昨日食べたピーマンはナス科だなぁ。キャベツはアブラナ科だけどレタスはキク科なのか…。ウリ科のものを全然食べてないなぁ。

録画したアタック25で早押しクイズをしてみたけども、3問しか答えられない。やっぱりテレビを見て答えるのと早押しボタンを押すのとではだいぶ違う。台形の面積や六角形の内角の和や大森貝塚なんか、今までだったら「答えられた回数」にカウントしていたと思うけども、実際に早押しで勝負してみると番組の出場者に押し負けてるので無効だし、ボタンを押すのに勇気がいるのでスタンダールの赤と黒とか火星のオリンポス山とか正解なのに自信がなくて答えられない問題もあるし、これじゃ勝ち目がないですな。

眩暈がする…。

2006年06月17日

日記

GRINEditプロジェクトが始まったのはいつか気になったので調べてみました。2004-12-18の時点では下のようなことを書いているのでまだJava版を作っていなかったようです。

手元にDelphiで書かれた可視化ソフトがあり、 最近蛋白質相互作用の可視化などの目的で人に使われているのですが、 これはかなりアドホックに書かれたものなので拡張がしにくく、 ユーザのニーズに答えられません。

2005-02-25の時点でCVSに.projectファイルをコミットしているので、この時点でプロジェクトは開始していたということですね。想像以上に簡単に絞り込めました。

IBM dW : クラス・ローディング問題の神秘を解く 第1回 - Japan IBM dW : Java : クラス・ローディング問題の神秘を解く 第2回 - Japan

今日の晩ご飯は鶏肉のカシューナッツ炒め。超ウマイ!鶏肉とアスパラのカシューナッツ炒めの作り方 :: Drk7jpを参考にしつつ、日本酒や紹興酒がないからジンで、オイスターソースがないからオタフクソースで、野菜はピーマンと赤ピーマンで作りました。中華料理は大変ですね、容器や周りの壁が油だらけ…。あと今日は炊飯器が届いたので初めてご飯を炊いてみたのでした。もっと早く炊飯器を買えば良かった。お米と水を入れてスイッチを入れて待つだけだからスパゲッティより簡単ですね。

うわー、すごい雨。

2006年06月16日

log

  • 14:10-15:48
    • プラグインのサンプルを作成
      • 新しいプロジェクトを作ってSamplePluginVertexというクラスを作成。
      • GRINEdit-alpha0.10.jarをビルドパスに追加
      • プラグインの中身を適当に作る
      • Eclipseのエクスポート機能でJarに出力。出力ファイル名以外特にいじるところはない。
      • うーん。うまく行かない。
        • 絶対パスでjarファイルをjava.class.pathにセットすると、新しいjarが使われたときに表示される「*sys-package-mgr*: processing new jar,…」というメッセージが出るので、パスを通すのは成功しているはず。
        • 何が原因だろう…。
  • -17:00
    • XML-RPCのバッチ処理完成。
      • import xmlrpclib
        server = xmlrpclib.Server('http://localhost:8080/RPC2')
        print server.grinedit.batch([
            {"method": "addVertex", "params": ["CircleVertex", {}]},
            {"method": "addVertex", "params": ["CircleVertex", {}]},
            {"method": "addVertex", "params": ["CircleVertex", {}]}]
      • フォーマットは予定とちょっと代わったけどJavaの引数は名前付き引数ではないからこれが自然かと。あと同じ名前のメソッドで引数が異なるものがあるとリフレクションがやっかい。このクラスをいじるのは自分なので自分で気をつけておこう。
  • -18:05
    • Pluginがうまく動かないからぐだぐだになっちゃった
    • お菓子を食べたりしゃべったり
    • 慣性と重力を実装。重力は単なる特定方向に均一な力をかける物理法則なのでパラメータ次第でいろんな方向に向けられます。この二つは非常に簡単。
    • 眠い…。
  • -18:47
    • 画面端への吸着(Cohesion)がX=0部分のみだけど完成。ぺとぺとくっつくのが面白い。一般化としては、スクリーン座標系での上下左右のどの端への吸着をONにするかでbooleanを4つ持つバージョンと、ワールド座標系での特定の形状(円とか?)への吸着をするバージョンとに分かれるだろうか。

日記

デュアルモニタをする際に、実世界でモニタが左手にあるからと思って左側に2つ目の画面がつながる設定にすると、デスクトップのアイコンが勝手にそっちに行ってしまって困りました。で昨日は右側に画面をつなげたのだけど、それはそれで左の画面に移るときに右にマウスを持って行くのは不自然。今日、右側につなげた後、やっぱり気が変わって左側に変更したら…あれ、アイコンがちゃんと残ってるじゃん!Windowsは謎が多い。

IBM dW : Java technology : One-JARでアプリケーションの配布を単純化 - Japan。s/拡張/展開/gかな。

Don't touch the label [ ] the bottle. と Don't touch the bottom [ ] the bottle. に入る前置詞は違う、というNHKの番組を見て目から鱗。たしかにGoogleでの検索結果もNHKの説明通り。自分で解いてみたい人のために続きは背景色で。

  • "the label on the bottle": 33,100件
  • "the label of the bottle": 955件
  • "the bottom of the bottle": 188,000件
  • "the bottom on the bottle": 20件
「of」は日本語の「の」より広い意味を持っています、とよく英語の授業では説明されていますが、この説明では「の」で表現できるものは全部「of」と言っていいみたいに思わせるので正しくありません。実際は「of」の持つ意味の範囲と「の」の持つ意味の範囲が食い違っているだけで、包含関係はありません。英語の「of」には「the top of the mountain」のように「頂は山の一部であり、頂なしで山は存在し得ない」関係を意味するものだそうです。「How kind of you!」も「親切さはあなたの一部で、親切さを取ってしまうとあなたじゃなくなる」ってことだそうで。で、問題文に戻ると、「ラベルは瓶に張り付いているだけで、ラベルをとっても瓶は瓶のまま」だから「the label on the bottle」、「底は瓶の一部で、底を取ると瓶じゃなくなる」から「the bottom of the bottle」なんだそうです。

英語勉強しないとなぁ…。

スラッシュドット経由で、金子さんの出たテレビの動画

今、企業でP2Pを使った配信ソフトウェアを作ってらっしゃるとは知らなかったですねぇ。不正使用をできなくする機能も積んでいるとのことで、もしWinnyの改良を警察に禁止されてなければそういう機能がWinnyについていたかも知れないですね。

まじめな話はさておき、なんか僕も2秒ほど写ってるじゃん、そんな話は聞いていないぞ、肖像権の侵害だ!(もちろん冗談)

2006年06月15日

「MovableTypeで箇条書きを楽に入力するプラグイン」の改良

MovableTypeで箇条書きを楽に入力するプラグインで箇条書きの中にpreタグを使うと改行や空白が全部取り除かれてしまいます。

        if($2 eq ""){
            $result .= $3;
            next;
        }

の部分を

        if($2 eq ""){
            $result .= $1 . $3;
            next;
        }

に変更すれば、箇条書き内でpreタグを使ったときに改行や空白が取られてしまうこともなくなります。

日記

目の健康を考えると、正面がノートパソコンで横にモニタがあり、前で作業をして目を上げると遠くが見える、という現在の環境はけっこういい。でも近々新しい人が来て向かいに座るのでパーティションが入ってしまう。

個人的にはプロジェクターで巨大なスクリーンに投影して、5メートルくらい離れて作業したいのだけど、そんなスペースもお金もないので。

まつげいじりながらプログラム書いていたせいで目がごろごろする…。

JSONはいいなぁ。JSON形式で出力した内容をPythonでimport pprintしてからpprint.pprint(JSONで出力された内容)ってやるだけできれいに整形して表示される。JSONは99%Pythonだから。

TeXに代わるものを作りたいという野望は多くの人が抱くが、結局のところあれだけのものを再生産するのは大変なので、いいラッパーをかぶせて使うとか、TeXを出力する高級言語を作るとかに落ち着くのかも知れない。

明日すべきことを付箋に書いてみる。今、お風呂の照明スイッチに「お風呂にはいるときはタオルがあるか確認する」と書いて貼ったりして、よく起きる忘れ物を防止できるか試してみています。明日は新聞を出さないといけないのでメモ。

人力検索はてな - javascriptの正規表現。いいパズルだ。考えとこう。特定の文字列で挟まれていない特定の文字列だけを抽出する、と。もちろん1行の正規表現で、ってのが条件だから、whileで頭に近い方から順番に置換するのも禁止、と。…できるのかなぁ、それ。

おおっ。hail2u.net - Weblog - 正規表現のeオプションをJavaScriptでエミュレートができるのならワンライナーはできそうだ(チャレンジの内容が変わってるし)

ねむいからもうやめた。

スラド経由で 大人には聞こえない着信音 - Engadget Japanese。 耳障りなキンキン音が聞こえる…。耳の奥というか耳たぶの下の凹んでるあたりというか、何か普段使われない奥の方がいじられている気分。

洗口液で口をすすいだ後、流しの生ゴミに吐きかけたら、雑菌が死んでくれたりしないかな。

log

つらつら考えながら書くだけではなく、きちんと作業日誌っぽくしよう。

  • 13:19-14:11 
    • 制約と物理法則が微妙に分かれていたが、この2つは「どのタイミングでsatisfyするか」が異なるだけなので整理してcode cloneを削った。またMaxxPointクラスのvelocityフィールドは使用されていなかったので、きちんと正しい値が入るようにした。物理法則によって頂点に与えられる加速度をvelocityListという名前のメソッドに入れていたが、これは実際には加速度なので名前が正しくない。accelerationListは長いのでdVelListにした。
    • 制約は繰り返し回数の上限までの範囲で満たされるまで繰り返し実行されるので、ステップの最初と最後では満たされている。その為、その他の物理法則とまとめた際に0ステップ目で「satisfied = true」を返してしまい、物理法則は常に「satisfied = true」であるので、すべての条件が満たされたと判定されて繰り返しを終了してしまう。これが原因でバネを引っ張りAnchorした場合に「Anchorが働くフレーム」と「働かないフレーム」が交互に現れ振動して見える現象が起きる。制約は0ステップ目でfalseを返さなければいけないことに注意。これをライブラリのユーザに対する注意にするか、こういうミスが発生し得ないフレームワークにするかは難しいところだ。
    • 頭ではうまく動くつもりの設計だけども、慣性力と剛体制約を入れて本当にうまく動くのか早めに確認する必要がある。
    • 次はVertexListをHashtableに変えるあたりの修正。
    • ここまでの作業はコミット済み
  • 14:23 - 15:43
    • vertexList を Vector から Hashtable に変更。
      • for (int i = 0; i < numVtx; i++) {
        	RenderableVertex v = (RenderableVertex) vertexList.get(i);
        	(中略)
        }
        
        の部分を
        for(Enumeration e = vertexList.elements(); e.hasMoreElements();){
        	RenderableVertex v = (RenderableVertex) e.nextElement(i);
        	(中略)
        }
        
        に変更する。
      • 反発力の計算ではすべての頂点の対に対して計算するけども、i < jに限定しておいて作用反作用の法則を使って計算量を半分に減らしている。だからEnumerationではやりづらい。values()でjava.uitl.Correctionを取得してtoArray()で配列にしてしまえばいい。
      • IteratorとEnumerationはどう違うのか。Enumeration (Java 2 Platform SE 5.0)によれば
        このインタフェースの機能は、Iterator インタフェースにもあります。Iterator インタフェースの方には、任意指定の削除のオペレーションが追加されており、メソッドの名前も短くなっています。新しく実装する場合は、 Enumeration ではなく Iterator を使うようにしてください。
        がーん。修正やり直し。
      • 一意なキーと頂点の対応付けに関して、XML-RPCでintを受け渡しして、いちいちIntegerに変換してキーにするより、キーを一意なStringにしてしまう方が手っ取り早い。int indexの代わりにString nameをつける。
      • Graphが持っていたAddVertexやAddEdgeを除去。ad hocなもの(引数がなかったらCircleVertexを作って、1つ文字列があったらBoxVertexのlabelだと見なして…という感じ)だし、頂点オブジェクト自体や、辺オブジェクト自体を返しているので。しかし当然のようにLegacyLoaderが動かなくなった。うーん。メソッドは一応復活させておいて、LegacyLoaderを捨てるときに一緒に捨てよう。
  • 15:49 - 16:19
    • コメントアウトしたGraph#AddVertexの復元。結局、XMLRPCHandlerに持たせたgetUniqNameをMediatorに移しておけばいいのだろう。
    • そうだ、忘れてた。Vertexに自分のnameを持たせるんだった。そうすればインスタンスから名前も取れるし、名前からインスタンスも取れるんだった。
    • 以降、vertexListに頂点を追加する際はString graph.addVertex(RenderableVertex)を呼べば自動的に一意な名前をつけて頂点を追加し、その名前を返してくれます。
  • 17:30 - 18:37
    • 現状でXML-RPCでのAddEdgeはクラス名と頂点のインデックスが必須の引数になっているけども、頂点のインデックスもparamsに含めてしまった方がいいのかも…。省略不可であることを表現したつもりだったけどもJSONでの保存時に特別扱いが必要になるし、現状で作成した辺の頂点を変更することはできないし(これは別にできないという仕様にしても構わないと思うのだが)
    • 一気呵成にedgListもHashtableにした。とりあえず表示は問題なく動いている。
    • nameもparamsに含めるべきなのだろうか…。
      • 含めてみた。
    • 頂点や辺の種類(クラスの名前)もname, 頂点や辺を識別するための一意な文字列もname…、使われる場所が違うから衝突はしないが、ユーザが混乱しそうではある。
    • おおっ、JSONで保存したファイルを読み込むのがうまく行った。
      • ただしまだ辺と頂点だけしか保存していないので、固定した頂点もまた動くようになってしまう。

先に根本に近い方をいじろうと思って作業していたので、変化がいまいちわかりにくい。この一連の修正で、JSONでの保存ができるようになったのはもちろんだけど、それだけではなくて、「選択範囲をグループ化」「選択範囲だけこの手法で整形」「選択した頂点にこういう物理法則を適用」ということができるようになるはず。

あと、しばらくぶりに自分のコードを見て、やはり「一つのクラスでSWTにもAWTにも対応」というのは良くないと思った。美しくない。アプレットなのにswt.jarが必要になるのもばかげている。

LinearEdgeだけAWT用とSWT用を分離した。ColorHolderもAWT用のを作成した。

坂を上るタイヤの謎

アコードのピタゴラ装置動画はあまりにもうまく行き過ぎなので一部合成なんじゃないかと疑っていたのですが、そのうちの一つ、坂を上がるタイヤの謎はおびなたのはてな日記 - 上るタイヤの説明で正しいと思います。

試してみた動画はこちら(3.44MB)。確かに、坂を加速しながら上がりますね、わかりにくいですが。ガラスだとこれ以上坂を傾けると滑ってしまうのですが、ゴムのタイヤならその心配もないでしょうね。誰か僕にゴムのタイヤをください(なお使った後の引き取りもお願いします(笑))

2006年06月14日

新機能案2つ

現在右ボタンと左ボタンの機能を切り替えられるようにMouseMediatorがMouseOperationクラスのインスタンスを持って、適当な子にイベントを抽象化して中継するようになっている部分を、ShiftやCtrlやAltキーで修飾されたマウス操作が行われた場合に対応できるように拡張する、というもの。Macに対応することを考えるとボタンが一個しかなくて修飾機能がないと不便だろうから。もちろんこれはPythonスクリプト上で設定されるので、自分の好きな設定に切り替えることもできます。あ、それを考えると「Sキーで選択モードに変更」なんてものできた方がいいのかな。

もう一つはpauseの扱いの変更。setPauseが直前のpauseの値を返し、ユーザーがそれを保管して後でそれに戻す用になっていましたが、そうではなくpushPauseとpopPauseにしましょう。

XML-RPCのサンプルは頂点数が多くなると格段に遅くなりますが、それは物理演算とXML-RPCを同時に動かしているからで、別に物理演算が遅いからではないと思います。物理演算と描画が1秒間に20フレームの速度で動くとすれば、まぁ人間にはそれなりにスムーズに動いているように見える訳なのですが、XML-RPCでクエリを投げている側のプログラムは1つクエリを投げて帰ってきた後次のクエリを投げてもGRINEditが物理演算のためにVectorをロックしているので追加処理ができずに待たされるわけです。最初に物理演算をpauseしてからクエリを投げればもっと速いはず。でもそれだとかっこよくないので、ツカミを重視して頂点数の少ないサイトをpauseしないで表示させています。これはきちんと測定する必要がありそう。

あと、そもそもXML-RPCで1つずつクエリを投げるのが遅いのだから、複数個をまとめて投げられるようにすればいいだけですね。

日記

行きの電車の中でGRINEditに追加する機能を二つ思いつきました。一つめは現在右ボタンと左ボタンの機能を切り替えられるようになっている部分を、ShiftやCtrlやAltキーで修飾されたマウス操作に対応できるように拡張する、というもの。Macに対応することを考えるとボタンが一個しかなくて修飾機能がないと不便だろうから。もちろんこれはPythonスクリプト上で設定されるので、自分の好きな設定に切り替えることもできます。あ、それを考えると「Sキーで選択モードに変更」なんてものできた方がいいのかな。

というかこういうことはGRINEditのlogの方に書くべきなのか…。


今日は後輩にじっくりプログラミングを教えてみました。今までなぜか自分の研究室の後輩じゃない方にばかり教えていたのでいつか教えようと機会をうかがっていたのです。

あと今さっきふと思いついたので今までのエントリーで、リンクを貼らずにGRINEditに言及しているところからGRINEditのホームページへリンクが貼られるようなフィルタをMovableTypeに追加してみました。プロジェクト名で検索したときにプロジェクトのホームが表示されるようにならないと弱いし。

忘れてたけどもEnumerate graphesなんてのもやったことがあったのだった。これもGRINEditのサンプルデータに入れようかな。


ただいま帰りました。正確に言うと今日は「帰るなりパソコンをつける」という習慣を変えて、とりあえず30分タイマーが鳴るまでは家事をすることにしてみたのでした。30分家事をすることに決めても、先にパソコンをつけるとkがついたら夜遅くなっていたりするので。これを毎日やるだけでだいぶ家事がはかどりそうです。やっぱり30分タイマーは重要ですな。ラボでも使える音の鳴らないアラームが欲しい。それを目指してバイブレーション式の腕時計を買ったのだけど、30分のセットが「分のところでボタンを長押しして30分で止める」という方法でしかできないので不便。1時間ならすぐなのだけどね。60進数の弊害。はてなでもっといい時計がないか聞いてみるか(ぉ)

目にも紫外線対策を~白内障と紫外線。僕が視力は悪くないのに外に出るときだけめがねをかけているのはこれが理由です。色がついているものは瞳孔が広がるので網膜に当たる紫外線量は増える、細身のレンズは斜め上から降り注ぐ紫外線から瞳を守るのには無意味、というわけで今のめがねを選んだわけですが、まぁ縁はなくてもいいかなぁとも思うので買い換えるときには縁なしのにしようかな。

はてなの英語版があるといいのに。「この英文を読んで変に感じるところやわかりにくいところを教えてください。」が1回答10ポイントでできるのなら喜んで使うのに。いまのはてなでやっても英語のネイティブはきっと少ないからダメだろうしなぁ。「日本語を学びたい英語圏の人」はパラオやニュージーランドなんかの親日国にはいっぱいいるだろうし。

西尾泰和のブログ: 坂を上るタイヤの謎

電車と結びついているSuicaはやっぱり強いかと思いきや、Edyがマイクロソフトやインテルと組んでPC標準搭載を目指すとは、なかなか面白いですね。そんなことよりQuoカードが13000円分あるのですけど、使えるコンビニが近くに見あたりません。悲しい。って今調べたらセブンイレブンで使えるって書いてあるじゃん!「使えません」って断言したあの店員が嘘つきだっただけか!

How it works? Physics?

Simply stated there is a repulsion force between any two vertexes, and there is a attraction force between vertexes connected with an edge.

All force in GRINEdit's physical layout engine are represented as an instance of class "PhysicalLaw". The layout engine can have several number of the instances and applys all instances iteratively.

2006年06月13日

可遊化とは

GRINEditの解説文を書きながら、「可遊化」でググってみたところ【ESPer2006】未踏ソフトウェア創造事業のOB/現役“超能力者”プログラマが大集合:ITproで「西尾泰和氏は「直感的にいじって遊べる」ことを意味する「可遊化」の概念を提唱。」と書かれているのを発見しました。ひゃー、恥ずかしー。

しかし可遊化でググってヒットする本人の文章が2004/09/04の「解くべき問題を面白いゲームにマッピングする技術」としての言及だけなのはちょっと誤解を招きますね。確かに、僕が可遊化という言葉を使い始めたのはこの時です。でも当時の僕はまだ視野が狭かったため、遊ぶという行為を「面白いゲームをプレイすること」に限定してしまっていたわけです。 しかし、それから「どうすれば現実世界の問題をゲームにマッピングすることができるか」を考え続け、そして間違いに気づいたわけです。ゲームだけが遊びではない、と。

「生産性のないゲームではなく、生産性のあるゲームを作ることで、 ゲームでの遊びに浪費されている人間の思考リソースを有効活用しよう」というのが花田さんがグリゲーでやろうとしたことなのだと思います。 それに触発されて「可遊化」と言い出したのですが、 遊びはゲームだけではなかったのです。

「遊びとは何か」という問題の答えはまだ見つかっていませんが、 プログラマが休日に何かをハックしているとき、 それは「遊び」なのではないかと思います。 「やっていて楽しいこと」は「遊び」なのでしょう。

今では、生産的なことを「やっていて楽しいこと」にすることができれば、 それは「可遊化」なのかもしれないな、と思っています。 直感的に操作できるツールは、バッドノウハウだらけのデータファイルをいじってコンパイルしないと結果を見ることができないツールより「やっていて楽しい」です。 だから「直感的に操作できるようにすること」は「可遊化」ですが、 それだけが可遊化なのではないと思います。

GRINEdit applet

A sample applet using the layout engine of GRINEdit. It scales with right-drag and a vertex move (and anchor) with left-drag.

MTでクリックしたエントリを編集するBookmarklet

ブックマークレットを実行すると<div class="entry" id="entry-<$MTEntryID$>">で囲われている領域をマウスオーバーでハイライト表示し、それをクリックすると編集画面を開く、というブックマークレットです。

フルバージョンは35行あって結構長いので、「川o・-・)<2nd life - bookmarkletの文字数制限を無くす」で紹介されている方法を使うといいと思います。 でもハイライトが静的なもので良ければ短くすることもできます。

javascript: (function(){baseurl = "http://YOUR_MT_POS/mt.cgi?__mode=view&_type=entry&blog_id=1&id=";tags = document.getElementsByTagName('div');for(i = 0; i < tags.length; i++){tag = tags[i];if(tag.className == "entry"){tag.style.background='#DAFADA';tag.style.border='solid';tag.onclick = function(){t = this;id = t.id.substr(6);window.open(baseurl + id);}};}})();

なおいつものようにFirefoxでしか動作確認をしていません。

colorArray=new Array();
borderArray=new Array();
currentTag = undefined;
baseurl = "http://YOUR_SERVER/LOCATION_OF_YOUR_MT/mt.cgi?__mode=view&_type=entry&blog_id=1&id=";

tags = document.getElementsByTagName('div');
for(i = 0; i < tags.length; i++){
  tag = tags[i];
  
  if(tag.className == "entry"){
    tag.onmouseover=function(){
      if(currentTag){
        return;
      }
      currentTag = this;
      t=this;
      colorArray[t]=t.style.background;
      borderArray[t]=t.style.border;
      t.style.background='#DAFADA';
      t.style.border='solid';
    };
    tag.onmouseout = function(){
      t=this;
      t.style.background=colorArray[t];
      t.style.border=borderArray[t];
      currentTag = undefined;
    };
    tag.onclick = function(){
      t = this;
      id = t.id.substr(6);
      window.open(baseurl + id);
    }
  };
}
baseurl = "http://YOUR_SERVER/LOCATION_OF_YOUR_MT/mt.cgi?__mode=view&_type=entry&blog_id=1&id=";

tags = document.getElementsByTagName('div');
for(i = 0; i < tags.length; i++){
  tag = tags[i];

  if(tag.className == "entry"){
    t.style.background='#DAFADA';
    t.style.border='solid';
    tag.onclick = function(){
      t = this;
      id = t.id.substr(6);
      window.open(baseurl + id);
    }
  };
}

GRINEdit

There are more contents in Japanese(日本語) than that in English...

What is GRINEdit?

GRINEdit is an open source visualization/"KAYUKA" (interactivation) software for Graph, Relation, Interaction and Network. It is customizable, scriptable, pluggable and also communicatable via XML-RPC.

Feature

  • You can visualize a graph. The graph changes its layout automatically using a physical model. Because the layout engine has a basis on physics, you can easily understand its behavior.
  • You can change the physical model of the layout engine. It's not only changing parameter, you can modify with plugin system. (It is to be supported at beta1.0.)
  • You can change the layout of a graph with dragging a vertex. And it doesn't mean to stop the layout engine. The engine continues calculation of layout considering your judgment.
  • You can edit a graph using XML-RPC from another process.
  • You can edit a graph with Jython script.
  • You can execute Jython code interactively, using Jython console. (Thanks to Don Coleman. I owe the feature to "Jython Console with Code Completion".)

Screen shot

See screenshots. Sorry for it is written in Japanese. I'll soon make English version.

Demo as applet

GRINEdit applet

Download

Please download this from SourceForge.net.

Document

Sorry, there is no good document.

Short guidance

  • The zip archive includes 3 files and 2 folders as below.
    • config.py: Configuration file
      • You can modify the language for GUIs (English/Japanese).
      • You can set ON/OFF of XML-RPC server (default ON).
      • If you have installed Jython, you can get extra power by setting library path.
    • GRINEdit-alpha0.10.jar: Executable JAR.
      • Double click it to run.
    • pythonScripts: Folder for scripts and demos
      • Many feature, for example the construction of menu, is customizable.
      • In sample folder, there is a demo to visualize HTML using XML-RPC. See original at Aharef: Websites as graphs. It is Python script. If you doesn't have installed Python, please try "website_as_graph.exe" in "dist" folder.
    • sampleData: Sample data
      • But please notice this 'legacy' format will become 'obsolete' at beta1.00. New formats based on JSON and XML are coming soon.
    • swt-win32-3139.dll
      • The library to connect the Standard Widget Kit(SWT) of Java and Windows. The software will run on other OS (for example Mac), but because I don't have Mac, I can't support it.
  • Please try to open sample data. Use menu 'File', 'Load LegacyFormat data' or drag and drop a file to the GRINEdit window.

Contact us

A mail sent to "grinedit(at mark)nishiohirokazu(dot)org" is forwarded to the account I frequently use. Please don't be shy to contact me, your mail will progress my project.

Acknowledgement

Other projects on graph visualization

日記

このあたりをいじっています。

MTをCMSとして使うのは十分可能(GRINEdit関連ページの共通部分をモジュールにしたりして)だけども、テンプレートの名前空間がフラットだから衝突を避けるために「GRINEdit_index_ja」と長い名前を使う必要があります。まぁ、別に今のフラットなままでも十分かとは思いますが。

MT自体は国際化されていますが、日本語ユーザが目にするテンプレートには「続きを読む」などの文字列がリテラルとして挿入されているわけでコマッタ。English contentsとJapanese contentsのリンクが並んでいるときにEnglishの方をクリックする人の為には、そういうところも英語化したいところだけども、すべてのテンプレートを日英両方作るのも微妙ですねぇ。今はテンプレートの数が少ないからまぁ問題ないけども、将来的には何とかしたいところです。どうするのがいいのかなぁ。読者が英語を好むか日本語を好むかをCookieとして保存する?

現在、個々のエントリーアーカイブのページで手元のブックマークレットを実行するとそのエントリーの編集画面が出るようにしているのですが、それでは一覧ページからは直接編集ページに飛ぶことができません。ちょっと不便だけどもパーマネントリンクをクリックしてエントリーアーカイブのページに写ってから編集画面に行っていました。しかし、この方法も今回のようにパーマネントリンクを表示しなくすると使えません。<div class="entry" id="entry-<$MTEntryID$>">というDIVタグで囲われているようなので、ここは「クリックされたエントリの編集画面を開く」という方法が使えそうです。…。使えました。MTでクリックしたエントリを編集するBookmarklet


クラスを実行時にロードする方法がわからなくてはてなで聞いて、ClassLoaderをいうキーワードを教えてもらって、ClassLoaderとNISHIO Hirokazuで検索をかけて、クラスを実行時にロードするには @ NISHIO HIROKAZU # Archived COREBlogを見つけ出しました(ぇ)

フォーマット崩れてるし、せっかくだからこっちに転載しときますか。いや、単なる転載じゃなくて、今回これを使って実装した内容でやりましょう。前回はJythonを使ってPythonコードから作成した*.classファイルを実行時に動的に読むというものでしたが、今回はGRINEditの物理法則をプラグインで追加できるようにする予定。


帰りの電車で気がついたのだけど、GRINEditに加速度を入れなくても、慣性力を入れれば同じ現象が引き起こせるような気がします。慣性力を入れるのの方がよいかも知れません。

どうして研究に必要な洋書を読んでいるときにそんなことを思いつくのか謎ですがね。

2006年06月12日

日記

電子レンジの中にいつかチンしたニンジンが発見されました。なんか白くてとろりとした液体ができているので容器ごと処分…。100円で4個の容器だったのがせめてもの救いでしょうか…。

メカニカルのタイマーを30分にセットして家事をしました。爆弾のような「チッチッチッチ」という音が鳴るので「今家事をしている」ということを忘れずに家事に専念できます。でも2回もパソコンの前に座りそうになったので、やっぱりこういう「注意がそれない仕組み」は重要なのかも知れません。

30分あれば洗濯物を干して玄関に堆積していたチラシと新聞を整理することも十分できますね。うかうかネットしているだけで1~2時間が経ってしまうことを考えると、タイマーは重要です。

今日の日経新聞から。松下がニッケル水素電池を使った非常用電源を開発。この手のものは鉛蓄電池を使う印象があって、しかも僕は使ったことがないので間違っているかも知らないけれども鉛蓄電池はメンテナンスを怠ると爆発して硫酸をまき散らす怖いものというイメージがある。鉛蓄電池に比べて重さ半分で2倍長持ちだそうで、これが実用化されたら結構便利そう。価格が高いのが難点だけども。

サイバーステップ | CyberStep。日経の記事だけでは詳しいことがわからないが、「P2P接続のネットゲームで、格闘ゲームなどの動きの速いものが可能」だそうだ。しかもOSを問わないそうな。

タッチパネル用なのに緊張感あるアクション性を持ったフル3D卓球ゲーム。 (snip) Java言語を用いて開発されており、Windows, MacOS Xの両方に対応 (snip) サイバーステップが二ヶ月、二名のみという短期間で開発し、 JavaNightsContest2003に入賞

なんかすさまじいですな。二ヶ月、二名でそれができると言うことは、かなり質のいいライブラリを持っているということでしょうね。


柏にて。

P1000621
P1000621 posted from フォト蔵

乗ってから気がついた。というか行きは気づかず、帰りに一緒に乗った人の話で気がついた。

P1000620
P1000620 posted from フォト蔵

大腸ハウスだと思った。

毎日少しずつでもISBN打ち込み作業をしないと本が片付かないなー。

寝床のロフトで打ち込もうかと思ったが、ロフトにネットが繋がってないのだった。でもまぁ、一箱済んだ。毎日一箱打ち込もう。あと今は打ち込み欄が省略記法で登録ボタンを押されてから省略前の形に戻しているけど、編集時に変わってくれた方がよさそう。

2006年06月11日

人力検索はてなでのアンケートの信憑性に関する実験

人力検索はてな - 人間には簡単なアンケートです。はてなのアンケートにどの程度botがいるのか気になったので実験してみます。

この質問の重要な点は、人間にとって意味のある選択肢が1つしかないという点です。つまり、アンケートで「私はポイントが欲しいだけです」といった「ポイントゲッター用選択肢」を用意したときに、選択肢を読んでそれを選ぶような人ならこのアンケートで正解の選択肢を選ぶと考えられる点です。ポイントゲッター用選択肢を選ぶ人がたとえ50%居たとしても、それ自体はアンケートの結果にはノイズを与えません。単に1回答あたりの出費が2ポイントに増えたと言うだけのことです。一方、人間であるか機械であるかに関わらず「選択肢を適当に選ぶ回答者」は結果にノイズを与えます。こういう回答者をこの記事ではbotと呼ぶことにします。

さて、アンケートの結果、「はてなアンケートに対する回答の約16%はbotだ」と結論できます。回答の精度から考えると四捨五入して「約20%」とする方が適切だと思うのですが、根拠無く不安をあおっていると取られかねないのであえて「約16%」にしています。

botの回答が最初と最後に偏るのは想像の範囲内ですけども、選択肢6に3つも回答が集中しているのは謎ですね。偶然なのか、それともそこに集中する未知の要因があるのか、このデータからでは何とも言えません。 同じ内容のアンケートを繰り返して、やはり選択肢6に偏りが出るのかどうかを観察する必要があるでしょう。 もしかすると人間が適当に選ぼうとしたときに真ん中周辺を選んでしまう傾向が出ているのかも知れません。

最初と最後の選択肢以外は「ランダムに回答する」というタイプの回答だと仮定すると、「ランダムに回答するbotが全回答の10%程度を占める」ということになりますね。正解や最初と最後の選択肢にもランダムな回答が混ざっている可能性があるので10%以上の可能性の方が高いですが。想像以上に高かったです。

とりあえず、はてなアンケートで多少でも有益な結果を得ようと思うなら、botによるノイズを減らすために「最初と最後に聞きたい内容の選択肢を置くのは避けて、選択肢の上限まで無意味な選択肢を追加してランダムに選ぶタイプを拡散させる」などの方法が有効でしょう。その上で、解釈時に「ある程度のランダムな回答が存在する」ということを忘れないように気をつける必要があるでしょう。たとえばある選択肢に100票中3票入っていたとしても、それを根拠に「こういう考え方をする人も多少は存在する」や「日本全体でこういう考え方の人がおよそ300万人いる」といった結論を導くのは明らかに誤りです。

なお、はてなを不当におとしめることがないように一言付け加えますと、 この記事は「はてなのシステムを用いたアンケートには他のアンケートに比べて精度が低い」ということを主張するものはありません。アンケートの設定によっては選択肢を読んでいない回答がはてなより多いケースもあると思われます。たとえば最高裁判所裁判官国民審査の投票の86%以上がきちんと設問条件(白紙で出すと積極的に信任されたことになること)と選択肢(どの裁判官がどんな人間か)を理解して回答されているかどうか…。

日記

朝8時ちょい前に目が覚めました。

成分無調整豆乳を買ってみたけれど、液体豆腐ですね、これ。

秋葉原に炊飯器を買いに行こうかと思っていたのですが、雨なのでネットで料金を調べているうちにネットで買ってしまった方がいいような気がしてきました。秋葉原のヨドバシカメラに目当てのものがあるかどうかわからないし、そこでの値段が安いかどうかわからないし。Amazon.co.jp:EUPA マイコン炊飯ジャー 3.5合炊き ホワイト TSI-MRC06なら送料0円で3180円だから、秋葉原に買いに行くなら往復580円を引いて2600円以下じゃないと得にならないし。これに決めようっと。


最近はてなにいいカモにされている気がします。でも、駅の売店で目についた500円の雑誌を買うのにくらべて費用対効果がかなりいい。と言いながらしなくていい質問までしている(苦笑)

まだ、通常の質問とイワシの使い分けはうまくできていない。質問が漠然としていたり「おすすめは?」とか「~ってどう思います?」とかならイワシの方がいいのかも知れないですね。普通の質問をしてから、自分の知識不足のせいで質問が適切でないことに気づくとちょっと悔しいです。

今日は初めてアンケートってのをやってみたのだけど、自分の質問に続々と回答が集まってくるのは面白いですね。

あーあ、ポイント使い切っちゃった。遊んでないで部屋の片付けをしよう。

はてなポイント自動引き落としにしちゃった。


今日は豚の生姜焼きリベンジ。


ボイスレコーダーを買おうと思っていろいろ調べていたのですが X-Bar XB800 クロスバー - USBデジタルオーディオプレーヤー とか、なかなかかっこいいですよね。というかICR-S270RM/S260RMが21000円超なのと比較して、こっちは1GBが14980円から。おおっと。たしかにICR-S270RMの指向性マイクにはちょっと萌えるけど、容量が倍なのに5000円安いってのは…。

…。

…こっちの方が魅力的だけど、品名が「デジタルオーディオプレーヤー」なんですね…。仮に録音するのも聞くのも同じ機能でできたとしても、「ボイスレコーダーが研究に必要です」と「デジタルオーディオプレーヤーが研究に必要です」では説得力が違いすぎます。経費でICR-S270RMを買うか自費でX-Barを買うか、って言われると悩みどころですなぁ。X-Barは150%までの高速再生が可能(ICR-S270RMは120%まで)のとデザインと容量が魅力的なのだけど…。っていうか単純に言えばX-Barの方がICR-S270RMより萌えるんだけど…。どうしようかなぁ。

まぁ、しばらく放置して考えよう。


豚の生姜焼きリベンジ。 前回はレシピの通りに作ったらなんだか白っぽくて全然僕の中の生姜焼きとマッチしない「ちょっと生姜の香りがする焼いた豚肉」ができてしまったのでした。とろみが足りない。今回は、タレをレシピの10倍以上(レシピ通りだとみりん小さじ2杯、醤油小さじ2杯なんだけど、今回は小鉢にそこが見えないくらい)の量を作り、生姜もチューブから10センチくらいひねりだし、ついでに片栗粉を少々入れてみたのでした。できあがり。そうそう、これこそ僕が求めてた生姜焼きだ!茶色いつややかな衣をまとった豚肉!立ちこめる生姜の香り!VIVA生姜焼き!

結局のところ、同じ言葉で呼ばれるものが同じ料理を指しているとは限らないわけですね。ほら、「日本のキムチは発酵してないからキムチじゃない!」とか「揚げ玉が入っているのはたぬきうどんであって素うどんではない!」とか「俺の料理はしなそばであってラーメンではない!」とか色々意見の食い違いはあるわけですよ。僕はレシピに載っていた豚の生姜焼きを豚の生姜焼きとは認めません(笑)

液体がすぐになくなって豚を本当に焼いちゃうレシピ通りの作り方に比べて、こっちは常時液体が残ってそれを絡めながら加熱するので肉が軟らかいと思う。食べ比べてはいないからわからないけど。


なんかVectorから「Vector maglogプログラマー募集!!」ってタイトルのメールが来たので知ったのだけど、会員制のBlogってうまく行くのでしょうかねぇ。しかも課金もできるそうですが…。あ、でも「もっと読む」の先だけ有料会員しか読めなかったりすると、内容によっては会員になっちゃうかもなぁ。問題の解決方法を検索してて、ずばりの内容の記事を見つけたけども有料だ、って言われたら払ってしまうでしょうか…。なんか僕は払わないような気もするのだけど、期待してそういう有料Blogをやろうと思う人はたくさんいるかもしれないですね。

ああ、なるほど、Vectorはシェアウェアのダウンロード販売のノウハウがあるから、それをソフトウェアから文章に広げようというわけですね。プログラムを書ける人間より文章を書ける人間の方が多いから顧客の層が広がるってわけですね。なるほど、なるほど。うまいこと考えましたねぇ。

でもMMORPGまで作っているのは謎です。


ほのかに眠い。24時。豆乳飲んでリラックスして寝よう。あれ飲んでリラックスできるのかどうか自信がないけど。

人力検索はてな - このアンケートには答えないでください。を作って2分で選択肢1に4件も回答がある。あと、現時点で大まかに「一番上と一番下が多いが、他は真ん中に近いほど多くなる分布」になっている。ただ2番と6番だけ回答が0個なのはなぜだろう。偶然かなぁ。

明日は12時には柏にいないといけない。月曜日が研究室ミーティングの日に決まったので赤坂に遊びに行く曜日を考え直さないといけないなぁ…

はてなにいっぱい質問を投げると、はてなから大量に送られてくる通知メールがうざいねぇ。なんかいい方法ないかなぁ。GMailが適当にまとめてくれるからかえってややこしいことになってるし 。これplagger?

結局、30分で100回答集まったので、「答えないでください」と書いてあっても答える人は20秒に1人くらい現れるということがわかった。そこでまともに答える気のある人間のほとんどが開こうとすら思わないような質問文を作ってみた。人力検索はてな - DRD4遺伝子のVNTR(Variable number of tandem repeat)多型がカラビ=ヤウ多様体の辺彩色数に与える影響を調べているのですが、リアプノフ数をショケ積分した際に出てくるフ..。作成完了画面が出て即アンケート画面に戻った時点ですでに1件の回答があった。やっぱりbotは居るのじゃないかなぁ。アンケート自体1日に10件もないので自動的に全部答えてもたかだか10円にしかならないのだが…。ああ、それでも10分に29件とか集まってくるなぁ。でも、上の「答えないでください」の方は29件の時点でも両端の高い分布の形が割とはっきりと出ていたのに、こっちは結構平たいぞ…まだ判断するには速いが選択肢をランダムに選ぶbotの比率が多いのかも知れないな。

ってもう25時じゃん。寝ないと。

最初は平たかったのにやっぱりピークができてきてしまいました。がっかり。でも、早い時期に投票したのがbotだと仮定するなら、それの挙動を利用して10回答くらいで締め切るアンケートを10本ばらついた時間帯に出せばbot特有の回答パターンを得られるかも知れませんね。100回答受け付けたアンケートと10回答ずつ受け付けたアンケートの結果の分布が有意に異なっていることを示せれば、(特に10回答ずつの方が見るからに平たいなら)botが回答している証拠になりますね。

ダメだ、試してみたけど50回答未満には指定できないようだ。

人力検索はてな - @;*!@、。;;@」」:;、。:??。 10件で止めたけども、やはり2割がbot(かランダム回答者)という結果。質問文を思いつかなくて適当な記号列にしたのが逆に人間の目を引いてしまったんだな、「答えないでください」と同じように。一見自分に興味のない分野の普通の質問に見えるような質問文で、朝の5時とかの人間が少なそうな時間帯に10件だけ受け付けるor10分だけ受け付ける、という戦略ならどうだろう。でもどっちにしてもサンプル数が少なくなるから、偶然ではなく有意差が出ていると示すには繰り返し実験が必要だ。めんどくさー。っていうかそこまでしてbotの存在を示さなきゃいけない筋合いはないしなぁ。単に好奇心からbotの比率を調べてみただけなのにbotなのか人間なのかの識別をしたくなったあたりからずるずると深みにはまっている気がする。

でも、人力検索はてな - @;*!@、。;;@」」:;、。:??の10件の回答のうち、最初の2個は「私はbotです。」だったのだよ。やっぱり大半の人間よりも素早くでたらめな回答をするナニモノカが居るのは間違いない。そしてそれはおそらくbotなんだけども、まだそれを証明することはできない。物証がないけど状況証拠だけ集まってきているような状況。

26時だよ、もう。本当に寝ます。

alpha-0.10 リリース

http://sourceforge.jp/projects/rel-visualizer/files/ から、現在最新のGRINEditをダウンロードできます。

zipファイルを解凍して、jarファイルをダブルクリックすれば動くはずです。こちらのマシンと、Jythonの入っていないマシン(両方WinXP)で動作確認が取れています。

動いた方はFileメニューのLoad legacy fileからSampleDataフォルダ内にあるデータを開いてみてください。 また、pythonScript/sample/の中にXML-RPCでウェブサイトを可視化するスクリプトが入っています。py2exeで実行形式にしたのがdist/website_as_graph.exeですので、Pythonを持っていない人も試しに実行してみてください。

なお、Java+Jython+SWTなので、swt*.dllをMac用のランタイムライブラリに置き換えればMacでも動くと思うのですが、手近に動作チェックに使えるMacがないので確認はできていません。

2006年06月10日

日記

今日は6時に目が覚めた。

本郷には行ったことがないのでどれくらいのタイミングで家を出たらいいかがわからないなぁ。 そろそろ行こうかな。


何から書こうかな。一昨日くらいに、アパートの1階に郵便受けがあることに気がついたんですよ。もちろん僕の箱は1ヶ月分の郵便物であふれていました。なぜ郵便局から「住んでいることが確認できなかったので住んでいるならこのはがきに判子を押して提出しなさい」なんて書類が来たのか理解しました。 で、まぁ、そのあふれんばかりの郵便物の中に埋もれていたのが、いつなぜ購入したか忘れた2冊の文庫本。

Amazon.co.jp:BRAIN VALLEY〈上〉角川文庫: 本 Amazon.co.jp:BRAIN VALLEY〈下〉新潮文庫: 本

いま読了したのですが、すごくよかったです。 僕の価値観はあまり一般ウケしないものを好むと言うことは自覚していますが、どうせ小説の感想なんて主観的なものなんだから客観性は求めなくていいでしょう。未知の単語に免疫があり星を継ぐものに興奮した人ならきっと面白いはず。パラサイト・イヴで有名になった瀬名秀明の9年前の作品です。

脳科学、それもレセプターレベルの話や、てんかんと幻覚の関連性、人工生命、ニューラルネット、などの萌え要素が絡み合って想像だにしない内容に進んでいくところは非常に面白いです。ニューラルネットを積んだ人工生命とか未踏で作った経験がありますし、ゲノムとレセプターレベルの話も最近興味を持って(DRD4遺伝子はVNTRが原因で変異しやすいので機会があれば僕のDRD4遺伝子がどういう状態になっているか調べて欲しいなと思う程度に)調べていたので、ストライクゾーンど真ん中でした。 以下ネタバレ:

今考えると、未踏で作ったニューラルネットを積んだカモが時々ぷるぷる振るえて動けなくなったりしていたのは「てんかん」だったのですな。当時はそのてんかんを押さえるために「ニューロンの発火が多いほど消耗するエネルギーも多い」と規定してエネルギー切れによる餓死で淘汰されることを期待したのでした。今もう一度試すのなら、「ニューロンの発火があまりに多いと、そのニューロンが壊れる」というルールを入れるでしょうね。よりスピーディな進化が期待できると思います。まぁ、そのチャンスはないでしょうが。

バーチャルな空間にバーチャルな物体を作りだし、スクリプトという魔法をかけ、魂を吹き込み、思いのままの世界を創造していた、あの時代こそが僕の青春だったのかもしれない。


なんかITスクールで教えてた高校生が、大学に入ってから始めたルービックキューブで自己ベスト30.97秒とか出してるよー。若い力が怖いよー。

僕もまだ若いうちに頑張らないと。(ルービックキューブをじゃないよ。買ってきて挑戦しようかと考えていたけど30.97秒を見て挑戦する前に挫折w)


Matrox Graphics - TripleHead2Goを使えば一つのビデオ出力端子から出た情報を3枚のモニタに映すことができるそうです。現時点で実売3万5千円程度らしいです。安いと思ってしまいました。僕のThinkpadTabletが対応しているかどうかはまだサーベイしてませんが、使えるとなったら…むむむ。

そうそう、この前「揺れる電車に長時間乗ることが少なくなったからHMDはいらないや」と書いたばっかりですが、やっぱり欲しいです。体内リズムの正常化のためには昼間に外で光を浴びるべきなのですが、外は明るすぎてモニタが見づらいので長居できません。HMDがあればすべて解決!

ちなみに今日、松蔭の前でUSB電力で携帯を充電しつつPHS接続でGoogleMapを見ながら道に迷って行ったり来たりしていたのは僕です。さらにHMDを装着したりするときっと警察を呼ばれることでしょう。

なお、本郷リサーチキャンパス?の西門は土曜日のため閉まっていましたが、柵を乗り越えようかどうか迷っている間に人が来たのでついて入れました。自分でもそのうち警察に捕まりそうな気がします。


はてな人力検索についている広告が「スポンサードリンク」という名前なのはなぜなのか疑問だけど、それを質問するのは罠にはまっている気がするので質問しない。


お台場ではOkamuraのContessaに座り、赤坂では同じくOkamuraのCruise & Atlasに座っているのだけど、違いがよくわかりません…。あ、でも自宅の備え付けのパイプ椅子は背もたれもパイプなので腰が痛いです。一応、ダメな椅子と言い椅子の違いは識別できているわけですか…。実家では小学校の時からずっと背もたれのないバランスチェアを使っていたので、実は後ろにもたれて作業する習慣はあまりないのですけどね。今も椅子の上に結跏趺坐で座って背もたれを使わずに作業していますし。


Matrox TripleHead2Go システム互換性確認ツールで試したら、TripleHead2Goの動作は保証できないと言われました。DualHead2Goなら動くそうです。ラボのモニタと同じサイズのをもう一枚買って、自宅用にMac miniと同じサイズのモニタをもう一枚買って、来年になったらラボに置いていたモニタを持って帰って自宅でデュアルモニタとか…(妄想)

少し眠い。24:50か…寝て、明日8時に目覚ましをならそう。体を健康なリズムに誘導。

2006年06月09日

リリース作業

今まで med.defaultSpringStrength = 0.5 と簡単に変更できていたバネの強さが、まず物理法則を取得してからごにょごにょしないと変更できなくなって面倒。g.aggregator.getLaw(0).defaultSpringStrengthって。0って。graphにprivate boolean isDefaultSettingとgetterをつけて、med.setDefaultSpringStrength内でこれがtrueかどうか判定して操作するようにします。

NEEDS: 選択範囲をまとめて平行移動

頂点リストをハッシュに変える大手術を今やると満身創痍になりそうだから我慢我慢。

pygettext.pyを入手して翻訳作業。 pygettext.pyは自分のものじゃないのでCVSに入れるのはどうかと思ってコミットしてなかったのだけど、 おかげで自分でもどこから入手したらいいかわからない事態に。 前のマシンはもう出荷時の状態に戻して前のラボに置いてきたので、 ソースコードを丸ごと渡した後輩の所にないか問い合わせてみました。無事発掘完了。 しかし、プロジェクトをCVSに入れているからと言って安心しちゃダメだと言うことがよくわかりました。 やっぱりプライベートなリポジトリは必要ですね…。

日記

きちんとまともな時間に起きたのに、急におなかが痛くなって、トイレに入って出てきたら1時間も経っていた…。うー。立ち上がると少しめまいがする…。

今日は家でおとなしく開発します。

とりあえずAntで実行可能ファイルを作るところまではできたので、安心してテスト。 この手のプログラムは、たとえば何らかのバグによってバネ係数がおかしくなっていとしたら「位数の高い頂点を含んだグラフをロードして0.5秒で計算が発散」というような症状が出るわけです。重要なのは「0.5秒」というところ。つまりロードの処理をしただけではエラーにならないのでsleepする必要があります。でもsleepしている間に本体が止まってしまっては意味がないのでテストは本体とは別スレッドで動く必要があり、かつsleepしている間に次のテストが始まっては困るのでテストスイート自体は単一のスレッドでなければいけません。ってそんなテスティングフレームワークがあるのかどうか探すのが面倒だったので作っちゃいました。

あー、でも、「特定のグラフをロードして、メニューの○○を選んでダイアログに25と打ち込んでOKを押して少し待つ」なんてテストを記述するためにはどうしたらいいのだ?

EclipseでVectorとArrayListを両方使い、ファイル内の名前変更でArrayListをVectorに変えると、インポート部分にVectorが重複する形になる。その状態でインポートの編成を行うと、あまり見たことのない現象にお目にかかれる。Undoで戻れたので助かった。


ううう、おかしい。急にめまいがして足下がふわふわするので横になったらもう20時です。 今日は体調が悪いからと在宅勤務にしておいてよかった、おかしくなったときにすぐに休めるし、と思ったのですが…冷静に原因を問いただしてみるとそうとも言えないような。眩暈、起立性貧血、下痢、吐き気、はしごを上がっただけで心拍が120ぐらいに跳ね上がるetc…こんなよくわからない症状が体のあちこちに出るなんて、自律神経失調症の可能性が高いんじゃないかと思います。じゃぁ、失調した原因は何か、というとこれは「概日リズムがずれているのに無理矢理気合いでいつもの時間に起きたこと」の可能性が高いと思います。卵が先か鶏が先かは難しいところですが、ラボで作業するときは合計1時間歩いて、昼間に僕が好む明るさより明るい部屋で作業をするけど、家で作業をするときは動かず多少暗めの照明で作業をするので、リズムを崩しやすそうです。リズムが崩れたので眠れなくなって、眠れなくなったから出勤時間に起きられなくなって、これではイカンと気合いで起きたら次の日寝込むなんて…うー。少なくとも今日の選択は結局光を浴びてリズムを元に戻す機会を失ったわけだから根本的な解決が先送りになってしまっていますね。

明日はいつもと同じ時間に起きて、自転車でまだ行っていないところへ行ってみよう。日中光を浴びて運動して、疲れて眠れば治るはず。あ、ダメだ、明日は昼間に用事があるや。

sourceforge.netはなんかつながりが悪いなぁ。よくタイムアウトになる。

おなかすいた。おなかがすくと言うことはだいぶ回復してきたと言うことか(結局昼ご飯は食べていないし)

すきやでオクラの乗っている豚丼を食べて、帰ってくる数分の間にまたおなかが痛くなったり。

わかりやすい言葉で言い換えるのはいいことだと思うけども、 破堤を決壊で言い換えるのはわかりやすくなったのかどうか微妙。破堤という言葉は知らなかったが、 つつみがやぶれるから破堤、と、文字に分解したら至極わかりやすい。 一方、決壊になんで決の字が使われているかは、わかる人の方が少ないと思う。僕自身も「決る」を「さくる」と読むとは今ググるまで知らなかった。「えぐる」だと思ってた。「えぐる」は「抉る」。

決壊の方が破堤よりわかりやすいと思う人の方が多数派だと言うことは、 それだけ熟語を個々の漢字に還元して理解している人が少ないと言うことだろうか。 日本語は表意文字を使っている数少ない先進国の一つなのに、自らそのメリットを放棄しているように思える。

もう3時間ほど経つのにまだおなかが痛いのは収まらない…。

SourceForge.net: Filesにリリースしたのにまだ表示されない。何か間違えたのだろうか。管理者画面ではちゃんと見えてるのになぁ…。

とりあえずhttp://sourceforge.jp/projects/rel-visualizer/files/ に置いてみた。解説はまた今度。pythonScript/sample/の中にXML-RPCでウェブサイトを可視化するスクリプトが入っています。py2exeで実行形式にしたのも入っているので、Pythonを持っていない人もぜひ一度試してみてください。

SourceForge.netの方のリリースの仕方を理解した。でもソースコードのリリースとバイナリのリリースを別々に登録したらrecentなのがソースコードの方だけになっちゃったな。一つのリリースに複数のファイルが入れられるのか…なるほど。

2006年06月08日

日記

自転車は買ったものの、駐輪場がいっぱいで駐められない罠。6月15日にキャンセル分の追加募集があるらしいけど、どうなることやら。駅から遠い9番駐車所で妥協するしかないのかもしれませんね。別にそれでもいいけど。

明日はGRINEditのいまいち完成していないテストシステムを改良しつつパッケージを仕上げて公開して、ついでにサイトもきちんとする。っていうかなんでGRINEditのトップページはGoogleに補足されないんだろうね。その辺も含めて。それじゃおやすみなさい。26時前か。悪くないライン。

JSONそんなに甘くない

世の中そんなに甘くない。JSON形式で保存したグラフをJSON形式で読み込んでJSONObjectになったものをそのままXML-RPCのインターフェイスに投げつければグラフが復元できるかと思いきや、JSONObjectとHashtableに互換性がないせいで、あちらこちらで型キャストに失敗する。JSONObjectとJSONArrayを全部再帰的にHashtableとVectorに変換してから投げないといけない。

あと、EdgeオブジェクトはVertexオブジェクトへの参照を持っていて、今まではそれで何の支障も感じなかったのだけど、XML-RPCやJSONのことを考えると、参照をそのままシリアライズできないため、何らかの方法でEdgeがどのVertexを持っているのかをシリアライズ可能な形式で取得できるようにする必要がある。むにゃむにゃ。

今日はあまり眠れていないのでもう活動限界。明日のリリースに関してはJSONでの保存は諦めてとりあえずXML-RPCを試してもらえるようにし、それがあっさり終わったらその次のリリースに向けて改めてJSONでの保存を考えることにしよう。


結局、org.json.simpleの方はHashMapやArrayListを継承してJSONObjectとJSONArrayを作っていたので、これをHashtableとVectorに変更して、あとXML-RPCからやってくる整数はIntegerなのにJSONからやってくる整数はLongだったのでリフレクションで適当にキャストして値を取り出すユーティリティ関数を一つ作って、一応JSONの読み書きができるようになりました。

あ、誤解を招く表現。頂点への参照をどうやってシリアライズするかが解決されていないので読み込めるのは頂点だけ。まぁ、単に頂点クラスにidを振るだけでは、途中に削除された頂点がある場合に指定したIDで取得できる頂点がずれてしまうので、まともに解決しようと思えば今VectorであるvertexListがHashtableになるより他にない気がします。削除のたびに頂点IDを振り直すとかどう考えても危険だし。

頂点リストのハッシュ化に取りかかりたい気分だけど、明日きちんと当分リリースし直さなくていいような安定版をリリースすることを考えよう。

リファクタリング

現状ではMediatorがデフォルトでのバネの長さや反発力の強さなどを持っていますが、これは本来個々の物理法則が持つべきものです。今までなぜMediatorが持っていたかというと、個々の物理法則にアクセスする手段がなかったからで、本来なら個々の物理法則にアクセスしてそこから取得すべき。

大幅なリファクタリングなので一度今までの結果をCVSにコミットしてから。website visualizetion as *interactive* graphはできたのだけど、そこで「反発力をもうちょっと強くしておいたら見栄えがいいなぁ」と思ったのです。でそれを変更するためにそれ専用のAPIを作るのは設計がよろしくない、と。

自分のためのメモ書き。頂点、辺、物理法則などのフィールドをXML-RPCで操作できるようにするには。

  • setter
    • public void rpc_****(Object o) を作る。引数の型やrpc_で始まるあたりはリフレクションで必要になるので変えちゃいけない。なんとなく****部分は小文字とアンダーバーで構成されているけど必要性は微妙。
      • やっぱりフィールド名と一本化した方がいろいろ自動生成できていいかもしれない。Eclipseのコードアシストとかドキュメントとか。javadocの出力にさらにフィルタを書けてXML-RPC用ドキュメントを生成とか。
      • なんでコードスタイルが変わったんだろう。rpc_にアンダーバーがついているからその後ろにキャメルケースを続けるのを無意識にためらったんだろうか。他の所は全部キャメルケースなのに。
    • 再利用できそうな型変換はUtilXMLRPCにstaticな関数として入れて再利用する。
      • ((Double) o).doubleValue() ですら UtilXMLRPC.ToDouble(o) に置き換えるのはやりすぎか??
  • getter
    • getterは何も受け取らずにハッシュを返す設計になっている。名前はrpc_getParams(ってアンダーバーにキャメルケースを続けてるじゃん!)
    • public Hashtable rpc_getParams()
    • 1行目はHashtable result = new Hashtable();かHashtable result = super.rpc_getParams();
	public void rpc_defaultNormalLength(Object o){
		defaultNormalLength = UtilXMLRPC.ToDouble(o); 
	}
	public void rpc_defaultSpringStrength(Object o){
		defaultSpringStrength = UtilXMLRPC.ToDouble(o); 
	}
	public Hashtable rpc_getParams(){
		Hashtable result = new Hashtable();
		result.put("defaultNormalLength", Double.valueOf(defaultNormalLength));
		result.put("defaultSpringStrength", Double.valueOf(defaultSpringStrength));
		return result;
	}

Javadocの結果からAPIリファレンスを作るスクリプトか…。来週の課題にしよう。

API整備

各頂点クラスや辺クラスのアクセス可能にすべき属性にはそれぞれXML-RPCでアクセスできるようなアクセッサをつけないといけませんね。結構面倒。

  • 凡例
    • s: 文字列
    • i: 整数
    • b: 真偽値
    • f: 浮動小数点数
    • (iii): 整数3つからなる配列
    • H: ハッシュ、連想配列、辞書、など
  • BoxVertex
    • 四角い箱状の頂点。中に文字列(label)が表示される。
    • 備考:文字列が空の場合は小さな四角になる。
    • 属性
      • label(s): 箱の中に表示される文字列(ラベル)
      • bgcolor((iii)): 背景色
      • frame_color((iii)): 縁の色
      • letter_color((iii)): 文字の色
      • self_link(b): 「自己リンクがある」マークの表示・非表示(ad hoc)
      • bound((ii)): 縁のサイズ。ラベルを変更した場合には再計算される。
  • CircleVertex
    • 丸い頂点
    • 属性
      • bgcolor((iii)): 背景色
      • frame_color((iii)): 縁の色
      • diameter(i): 円の直径
  • LinearEdge
    • 直線の辺
    • 属性
      • color((iii)): 線の色
  • RenderableEdge
    • 辺の基底クラス
    • 属性
      • k: バネ係数(負の場合Mediatorが持つrepulsionKの値0.02が採用される)
      • length: バネの自然長(負の場合Mediatorが持つdefaultNormalLengthの値1.0が採用される)
  • XMLRPC
    • pause(b): 自動整形のON/OFFを切り替える。 直前の値を返すので
          isPaused = pause(True)
          // do something
          pause(isPaused)
          
      で安全に「一時停止」ができる。
    • initGraph(): グラフを新しい物にする。 具体的には、頂点リスト・辺リストを空にし、 物理演算を初期設定に戻すことを意味する。
    • addVertex(s typeName, H params): 頂点を追加する。 typeNameには頂点クラスの名前(たとえばBoxVertex)、 paramsには設定したい属性の名前と値(たとえば{"bgcolor": (255, 0, 0)})を指定する。整数値を返す。
    • addEdge(s typeName, i v1, i v2, H params): 辺を追加する。 addVertexに同じ。v1, v2には頂点を追加した際に返ってきた整数値を指定する。
    • modVertex(i, H params): 頂点の属性を変更する。 addVertex内でも呼ばれている。
    • modEdge(i, H params): 辺の属性を変更する。 modVertexとほぼ同じ。
    • delVertex(i): 頂点を削除する。
    • delEdge(i): 辺を削除する。

add系に共通の注意点。 XML-RPCでは生成されたオブジェクト自体を返すことができないので、 vertexListやedgeListの中で何番目にいるかを返しています。 そのため削除をした場合には後ろの物のindexが繰り上がり、以前の値ではアクセスできなくなります。 この挙動はidとインスタンスをマッピングするHashtableを用意すれば取り除くことができますが、その必要性があるかどうか疑問なので保留状態です。

今は位置や速度がXML-RPCでgetParamsしたときに返ってこないのだけど、やっぱそれもいじれるようにした方が面白い応用ができるかも知れませんね…。

とりあえず、やりたいことはいっぱいあるけど全部やるわけにもいかないので、今週末にGRINEdit-alpha 0.1を公開するという目標に向けて何をすべきか考えないと。

よし、PythonからXML-RPCで「ウェブサイトの可視化」をするサンプルスクリプトを作るとしましょう。その過程で足りない物にも気づくだろうし、漠然と「いろいろできます」より「こんなことができます」の方が訴求力が高い。

(add|mod|get|del)(Vertex|Edge|PhysycalLaw)

addで追加、modで各種属性を変更、getで各種属性を取得、delで削除、っと。 modとgetが対になると考えるとset/getがいいのではないかと思われるかも知れないけど、 setVertexではvertexをsetするみたいだし、modVertexはあくまで既存のVertexインスタンスに対してハッシュを投げて属性を変化させるメソッドなのでこれでよい。getは可視化のためにはあまり必要ないのだけど、これを作っておけばグラフのセーブがXML-RPCでできるようになるので、誰でも自分の使いたいフォーマットを使うことができる。もちろん自分の好きな言語でXMLをやりとりするプログラムを書く必要はあるけど。

インスタンスの種類の差し替えについて。他の属性(色やラベル)の変更と、種類の変更は大きく異なる。それは設定することのできる属性自体が変わるから。どの属性を新しいインスタンスのどの属性に引き継ぐかってのは自明ではないし、種類が増えるに従って2乗のオーダーで「引き継ぎ方」が増えるのでこれをサポートするのは得策ではない。やりたければgetで属性を取得し、delで現在のを削除してから、新しいのをaddすればいいだけなので別に本体側でサポートする必要もないと思う。

Vertexを削除しても、それに繋がっているEdgeが残っていれば、表示されない&移動もしない幽霊が残ってしまうね。それは当たり前の挙動だと思うのだけど、どうだろう。頂点を削除する際に繋がっている頂点を削除するようにすべきだろうか?

メモ。med.pauseも制御できるといいね。

PhysicalLawに関しては、targetを省略できるようにしておいて、たとえばRepulsionなら省略時には全頂点が対象だしSpringEdgeなら全辺が対象。

2006年06月07日

日記

扁桃腺の軽い腫れ。

明日からは復帰する予定。

酸欠?

体調不良で何もできずに部屋にこもったのが引き金で、軽くエアーポケットに落ち込んだようですな。

部屋の窓を全開にして換気しつつ、MINTIA DRY HARDを食べたら少し気分がよくなってきました。ミントの刺激でくしゃみをたくさんしたおかげで肺の換気が進んだのが原因か、カフェインの効果か。でもカフェインってそんなにスピーディに吸収されるのでしょうか。

経口投与したカフェインの作用は15分後にピークを迎えるそうです。


破傷風の予防。ほほう、僕は小さいときに予防接種を受けているはずなのですね。でももう効果が切れている、と。


ふーぅ。

シャワーを浴びてみたら、体が想像以上に冷えていたことが判明。

エンジンがかかりだしたみたい。おなかがすいてきたのでとりあえずヨーグルトを食べてみます。


晩ご飯にカシューナッツとキャベツと魚肉ソーセージとニンジンを炒めてみる。 まだ慣れていないせいか、カシューナッツをロースト中に、鍋の温度がかなり高くなっているにもかかわらず醤油を入れて瞬時に焦げ付かせてしまいました。油と水気の少ない物だけで調理している時は温度が想像以上に上がっているから液体の調味料を入れちゃダメですね。火をゆるめてキャベツを入れてから醤油を入れるべきでした。

VIEWスイカカードを作ろうと思ったのですが、こういうのをやるときにいつも困ることは「会社員」とか「公務員」とか選ぶところ。会社員じゃないし、公務員じゃないし、学生じゃないし…。お、「その他」の欄がある。

Subversion によるバージョン管理は長いなぁ…。

防水パソコンを調べてみたけどやっぱり難しいですねぇ。モニターとキーボードだけ袋で包んで浴室内に入れて、本体は外に置くのがいいのかも知れません。mac miniと安いモニタとキーボードを買って…。

明日は木曜日、GRINEditの日ですな。ふむ…。何をするか…。 XML-RPCによる物理法則の変更、JSONでのグラフの入出力、そしてリリースですかね。そろそろ使ってみたい人もいらっしゃることでしょうし。うー、そうなるとドキュメントもしっかり書かないとねぇ。

今年の夏のプロシンは大分なのか。申し込みの締め切りは6月23日。


眠れない。布団に入っても眠れないが、起きてパソコンの電源を入れると眠い。

脳の消火剤がないと、燃えている火を消すことができない。

パソコンが起動するのを待つ間に何度もあくびをするくらい眠いのに、布団にはいって目を閉じても目の前に画面があってそこにいろいろ書いていってしまう。ある程度溜まると保存したくなるのだけど保存できないのでプレッシャーがどんどん溜まっていく。

「プログラミングを学ぶのに、Cを学ぶ」なんてのは「料理を学ぶのに、火のおこし方を学ぶ」に近い印象を僕に与える。確かに昔はそれが必要だったし、火加減は料理の基礎かも知れないけど、でもカセットコンロ買ってくればいいじゃん、と。研究室の後輩がCとJavaを勉強していて、個人的にはPythonを教えたいのだけど、僕も昔に比べて年を取り分別を知ったので教えない。

重要なキーワードはsustainabilityだ。僕がこの職場にいるのは1年間だけだ。僕がいなくなればPythonの質問をできる人は周りにいなくなるが、JavaやCならいるだろう。こうしてメジャーな言語は実力以上にメジャーであり続ける圧力がかかり、古くて難しい言語を学ばされる人は生まれ続け、出せば売れるので解説書を出す圧力がかかり、間違った内容の書籍が増える。

基本情報技術者か何かの教科書で、10を2進数表記した物が110になっていたのにも唖然としたが、「int mainとvoid mainとmainだけの3通りの書き方の本があるけどどう違うんですか」なんて質問されるのもそれはそれで困る。僕はC言語は詳しくないので自分の言葉で語るのは避けるがC FAQ 11によれば

11.15:
僕がいつも使っている『ほんとおの馬鹿向けのC』には、いつもvoid main()と書いてる。
A:
たぶんその本の著者は自分も対象読者の一人に数えているのだろう。 不思議なことに、例題のコードでvoid main()と書いてる本は多い。 そういう本は間違っている。

ということらしい。まぁ「間違っている」というとちょっと言い過ぎの感があるけど、「正しく規格に従っていないためそこでたまたま動いたとしても他の機械では動かない可能性がある…けどどうせそこでしかプログラム書かないんだからどっちゃでもいいんじゃない?」というのを省略するとやっぱり「間違っている」になるのかなぁ、とも思う。


svn-1.3.1-setup.exeをDLしにいったらsvn-win32-1.3.2_py.zipがあったので名前に惹かれて一緒にDL。APIの利用。Python他いろんな言語からSubversionのAPIを叩くことができるようだ。

もうすごく眠くて目がしょぼしょぼする。でも外は明るい(28:41)

CVSではファイルを移動したり名前を変更したりすると履歴が取れなくなってしまったのだけど、Subversionなら移動先のファイルに引き継げる。しかしSubversionのコマンドで移動しないと引き継げないのだと面倒だ。Eclipseのリファクタリング機能で名前変更したときにちゃんと履歴情報を引き継いでくれるといいのだけど。SubclipseっていうEclipse用のプラグインはあるみたい。

2006年06月06日

日記

頭痛。

今やソフトウェアもそれ一つで完結してサービスを提供するのではなく、他のソフトウェアなどから利用されることを考えるべき時代なのでは、とGRINEditをいじりながら考えていたのだけど、それって一言で言うとソフトウェア2.0?(笑)

動かなくなっていた球面SOMのデモを直す。原因は明確ではないけども、Eclipseのバージョンを変えたりソースコードを移動したりした過程でJavaのバージョンが変わったことが原因じゃないかなぁ。

日本人も打てない中国語を適当な日本語の漢字で置き換えたりするけど、逆に台湾の友達が日本語の漢字を出せないからといって書いた「版叮隆史」って誰のことでしょう。反町なんだけど…わかるわけないよね。 町って中国語にはない漢字なのか…。


同じ型のエレベータで異常が相次いでいる、と聞いて「ここ数日で一斉に異常が発生」と勝手に誤解して「エレベータのファームウェアに感染するコンピュータウイルス?!サイバーテロ?!」と思ったけど、さすがにそれは時代を先取りしすぎだったようです。

豚肉の生姜焼きを作ったのだけど、期待したのと違う。実家の生姜焼きはもっととろりと茶色かった気がするのだが…。片栗粉でもはたいてから焼けばいいのかな…。

どうやら、レシピ通りに作ったのではタレが足りないような。肉を漬け込んだ時点でほとんど液体が無くなってしまったのだけど、そうじゃなくて、肉をつけてもたくさん余るくらいのタレを作って、肉を焼いた後その液体を煮詰めながら肉に絡めれば期待通りの物になりそう。

人力検索で「どうしてみりんを入れるときにも料理酒を入れないといけないのか」と聞いたらこんなサイトを教えてもらいました。 ミツカンのみりんと料理酒で(以下略)

ダメだなぁ、力が出ない。まぁ、小さな一歩でも進んだのだからいいとするべきなのかもしれない。

ブードゥー人形ストラップ。 ブラック怖い。

29時だ。不眠。

MovableTypeで箇条書きを楽に入力するプラグイン

詳しい記法などはPythonで箇条書きをHTMLに変換をご覧ください。コンテナタグで実装してみたところエントリーの本文の中で使うことができなさそうでしたので、グローバルフィルタを使って実装しました。

package MT::Plugin::MyPlugins;
use strict;
use MT::Template::Context;

MT::Template::Context->add_global_filter(MyTag=>\&myTag);

sub closeTags{
    my($ref_indent_stack, $indent) = @_;
    my(@indent_stack) = @$ref_indent_stack;
    my($result) = "";
    while ($indent < $indent_stack[-1]){
        $result .= "</li></ul>";
        pop(@indent_stack);
    }
    return $result, \@indent_stack;
}

sub itemize{
    my($contents) = @_;
    my @indent_stack = (-1);
    my $result = "";
    foreach my $line (split(/\n/, $contents)){
        $line =~ /^(\s*)(-?)(.*)/;
        if($3 eq ""){
            next;
        }
        if($2 eq ""){
            $result .= $3;
            next;
        }
        my $indent = length($1);
        if($indent > $indent_stack[-1]){
            $result .= "<ul><li>" . $3;
            push(@indent_stack, $indent);
        }else{
            my($closing, $ref_indent_stack) = &closeTags(\@indent_stack, $indent);
            @indent_stack = @$ref_indent_stack;
            $result .= $closing;
            $result .= "</li><li>" . $3;
        }
    }
    my($closing) = &closeTags(\@indent_stack, -1);
    $result .= $closing;
    return $result;
}

sub myTag {
    my($text, $arg, $ctx) = @_;
    $text=~s#<itemize>((?:[^<]|<(?!itemize>))*)</itemize>#&itemize($1)#ieg;
    
    $text;
}

1;

2006年06月05日

日記

体調不良。

6月に入るやいなや1ヶ月遅れの5月病でしょうか。

何も生産せずに一日が終わるとそれはそれで憂鬱になるので、 MovableTypeのコンテナタグで箇条書き化プラグインを作ってみました。でも、本文部分ではタグが聞かないみたいですね。グローバルフィルタを使うしかなさそう。

らくがきこども せっけんを使えば、お風呂で物書きができるかな。


subversionを入れようと調査。tortoisesvnってWinCVSみたいなのをイメージしていたのだけどスクリーンショットを見た限りでもだいぶ使い勝手が違いそう。Explorerと統合されていて便利そう。

  • グローバルフィルタを使って箇条書き化プラグインを作成
    • Perlの正規表現でマッチした部分を関数呼び出しの結果で置き換えるにはeオプションを使う
      • $text=~s#<itemize>((?:[^<]|<(?!itemize>))*)</itemize>#&itemize($1)#ieg;
    • Perlの関数呼び出しで、@_を書き換えると関数の外の変数に干渉する可能性がある。
      • それを使って複数の値を返すのかと思ったけど、普通にreturn $a, $b;って感じに返すことができる。
        • この挙動はPythonと同じ。
    • $" という変数が配列を表示する際の区切り文字

Perlのリファレンス、デリファレンスは理解できたような気がします。いやはや、やっぱりPerlを使ってプログラミングの経験のない人にプログラミングを教える自信は僕にはありません。結局のところ、Pythonのリストにはすべてのオブジェクトが入るけど、Perlの配列にはスカラーしか入らないので配列を入れたければリファレンスを入れないといけない、ということなのですが…タブ区切りのデータを読み込む演習課題ってプログラミング演習の割と最初の方で使っているわけで、これの前にリファレンス/デリファレンスを教えるなんて考えただけでも恐ろしい。(もちろん平たい配列に入れて $data[$x + $y * $WIDTH] ってやるのもアリですが…)

lethevert is a programmerより引用。

このサイトに存在するすべての間違いは、意図されていたかいなかったかに関わらず、読者のための練習問題もしくは冗談です。:p

いいなぁ、その主張(笑)

2006年06月04日

日記

タスクが衝突すると格段に生産性が落ちる。 土日の作業がはかどらないのは、手帳に書いてある「土日にやろうと思っているプロジェクト」と心の中にある「土日に家にいるうちに部屋を片付けたり洗濯したりしないとという思い」が衝突しているからに他ならない。洗濯とか片付けを手帳のプロジェクト欄に書いてみる。片付けは完了するまでやったらきりがないので30分間だけやる。

まぁ、実践は来週からです。

自転車を引き取りに行ってきます。自転車の鍵も買わなきゃね。


残り物の野菜とかを片付けないとね。って万能ネギ一束だけで何を作るのか…。あ、小麦粉と卵があるからネギ焼きを作ろう。ネギ焼きの作り方がわからないので適当に卵2個割って、何となく木綿豆腐を1丁入れて、粉を適当に入れて混ぜたらそれっぽい生地になりました。ネギもざくざく切って入れました。いま冷凍シーフードをレンジで解凍しているところです。後何を入れると面白いかなぁ。キムチを入れていい物かどうか悩みどころです。

今日もまたサラダ用レタスを買おうかと思ったら見あたらなかったので、なんとなく水菜を買ってきました。 ネギ焼きに水菜を入れてみました。これはネギ焼きではない…どう見ても水菜焼きだ…。 大きく作りすぎてひっくり返すのに失敗。そして少し焦げ気味。 ひっくり返してからお好み焼きに必須のソースもマヨネーズも無いことに気がつきました。ううむ。どうやって食べよう。

ソースとマヨネーズを買ってきました。自転車で片道6分くらいでした。


OCRがうまく行かなかったので1時間くらいかけて手で打ち込んだデータが整合性エラーorz

アメリカのハリケーンが直撃した町がカビだらけになっている映像を見て、ナウシカを連想した。

JSON

JSON in Javaを使って新しいデータフォーマットを作ります。

Simpleな説明でほぼ語り尽くされていますね。

{
  "version": "0.00.planning",
  "vertexList": [
    {"type": "CircleVertex", "params": {}},
    {"type": "BoxVertex", "params": {"label": "Hello"}}],
  "edgeList": [
    {"type": "LinearEdge", "params": {}}]}

という感じでしょうか。物理法則をいじらないならこれで十分そう。anchoredはparamsに指定したくなるけども、特定の物理法則が持つ情報だから…XML-RPCの方にも物理演算を追加するべきですな。ふむふむ。

2006年06月03日

日記

NHK大河ドラマを見て、山内一豊が本能寺の変の後どうなるのか気になって調べてみました。土佐藩 - Wikipedia。なるほど、土佐に行って山内容堂に繋がるのか!(百科事典に口がくさいとかかれる山内容堂ってかわいそう。)

「無印DB」という文字を見て「どんなデータベースだろう」と思ったら「ドラゴンボール」だった。

mixiの日記は前の前の日記とリンクされている。こっちにリンクし直そうと思ったけど、全体のRSSなんかにしたらかなりウザイことになりそうな気がする…。zakkiカテゴリーだけのRSSを出せばいいんだな。簡単にできそうな気がする。

あと箇条書き化プラグインも作らないとね。

チャーチ数で引き算をするにはpairとpairの1番目、2番目を取得する関数を作り(0, 0) ->(1,0) -> (2,1) -> (3,2) ・・・->(n, n-1)とやって1引き算する関数を作ればいい、と言われて「なるほど」と思ったのですが、もちろんconsとか使うのは禁止なんですよね…。むずかしいな。

クレジットカードの引き落とし日は6/12日で、もしまだ給料が入っていなければ今週中に何とかしないとブラックリストに入れられてしまうかも知れないな、と残高照会をしてみたら無事2ヶ月分の給料が入っていました。 早速自転車を買いにららぽーとへ行ったのですが、せっかく来たのでいろいろ見て回って帰り際に自転車を買おうとしたら「点検整備で一時間待ちです」とのこと。自転車を買うのに時間がかかるとは知りませんでした。混んでなくても20分待ちだそうで、それを知っていたら最初に買ってから見て回ったんですがね…。明日引き取りに行くことにします。

ちなみにららぽーとは巨大で、前に見たときに「大きいなぁ」と思ったのは長方形の短辺でした。そして地図がわかりにくいことこの上ありません。地図と床の両方に方位を書いて欲しいと思いました。広場とかに出るとどっちが目的方向かわからなくて大変。

お金が入ったので炊飯器を買おうかとも思ったけども、炊飯器を買う前に「たくさん作って冷凍保存」というスキルを習得すべきだと思ったのでとりあえず明日はパスタをゆでて冷凍保存してみます。

Googleマップは重要ですねぇ。船橋周辺ではJRが北で京成が南にあり、ららぽーと周辺ではJRが南で京成が北になっているので、自転車を買った後はとりあえず西に走ればどちらかに当たるはずだ、とGoogleマップのサテライトでシミュレーションしたら全然違うところに行ってしまいました。南船橋を通るJRと船橋を通るJRは別の線でした。うーん、僕は明日自転車を買った後どうやって帰ってくればいいんだ?県道14号を走ればいいのかな?京成電鉄の駅周辺まで行って曲がればそれが県道14号で、途中で大きい道と小さい道に分かれたときに小さい方に入ることだけ気をつければ、後はJRが見えたころには家の近くだから目印のラブホテルの看板が見えるはず…。広き道は滅びに至る道、狭き道を進め、とな。

「はてな人力検索」で「他人の脳を使う」ことに味を占めたので、「教えてgoo」がどんな感じなのかをチェックしてみました。ほほー、こっちは質問のカテゴリ分けがかなり細かいですね、プログラミング言語ごとにカテゴリー分けが…ってPythonないじゃん!やっぱりマイナー言語はつらいですなw

gooの会員登録は例の画像から文字を読んで入力する認証がありますが、出てくる文字が数字だけで、左上にgooの文字があり、色のついたうねうねした領域があり、端から端までの太さ1の直線が走っているだけ。うーん、これってその気になれば簡単に突破できそうな気が。さすがに面倒なのでやりませんが「7割くらいの確率で突破できるシステムを作ったら30万あげます」って言われたらさくっと作ってしまいそうです。OCR興味あるし。っていううかこの前、表に数字が入っているのをOCRで認識させようと思っていろいろ体験版を試してみたのにいまいちうまく行かなかったから自分で作ろうかと考えていたところでした。

でもどっちみちスキャナがないとどうしようもないんですけどねー。デジカメで撮っても想像以上にひずんでいるので。

そうそう、長袖のシャツも2枚買ってきたのでした。だって、すぐ夏になるからいらないと思って2着しか持ってきてないのに、夜とか寒いので毎日着る羽目になって洗濯が大変なんだもの。しまった、もう1着買えば週に1回の洗濯でよかったのか…。

ららぽーとから家までは4キロ前後みたいです。遠いのか近いのかよくわからないので自転車の時速を調べてみたら時速16~40kmだそうで、15分~6分ってとこですか。近いですな。徒歩が時速4~5キロか。それなら1時間。歩けない距離ではないですね。

TABLEタグの代わりにスタイルシートでレイアウトする練習。

P1000422
P1000422 posted from フォト蔵
P1000439
P1000439 posted from フォト蔵
P1000574
P1000574 posted from フォト蔵
P1000551
P1000551 posted from フォト蔵

要素を下の端でそろえる方法はよくわからなかったけど、まぁいいや。横にいくつまではいるかとか考えなくても適当に並んでくれるから写真連貼り用には楽でいいですね。

マシンの調子がおかしくなってしまったので、USBカメラを使って「時間を縮めて見る」のはしばらくやっていないのですが、普段見えるのと違うものが見えるのは面白いです。そういうわけで最近は「明るくして見る」のにはまっています。露出を長くするだけなのですけどね。

ATOKは賢いなぁ。「取った」を打って確定した後で「写真」と打ったら「『撮った』じゃないの?」と聞いてくれました。しかもShift+Enterで修正まで。JavaとEclipse、日本語とATOK、って感じ。後は文章のアウトライン表示とリファクタリングの機能があれば(ぇー)

「散らかっていく過程を録画し続ける」という当初のプロジェクトは、1台しかないメインマシンをそれに専属させるわけにはいかなくて断念しましたが、現在の部屋の状況はこんな感じです。

P1000581
P1000581 posted from フォト蔵

テレビの上の目覚ましを止めるには荷物を2回またがねばなりません。

P1000584
P1000584 posted from フォト蔵

このスペースを有効活用すれば片付くはずなのだけど。

先日の日記で「たかだか2GBのデータファイルを圧縮するために工数をかけるより、そのデータの解析の方を優先すべきかも知れないですねぇ。」とか書いていますが、いまざっと計算してみたところ1185KBのデータファイルに書いてある内容を単純にただの配列に入れた場合でも189KBぐらいになり、全体では330MBくらいにはなりそうな雰囲気です。うーん。メモリに乗るようになれば処理は高速になりますよね…。まぁ、まずはSQLiteにでも入れておいて、使ってみて速度に不満が出るようであれば高速化するとしますか。

Pythonでウィンドウをずらしながら平均、分散、回帰直線の傾き、相関係数を求める。

有名な方の分散を求める(平均を中に含んでいる)式を素直に使って計算すると、ループを2回なめないといけませんが、式をいじると1回のループで平均と分散が同時に出る、というのはたぶん有名な話だと思います。今回はそれに似ていて、n個のデータからサイズmの連続している部分を切り出して、そのそれぞれの統計を行う方法のハックです。普通にやるとO(mn - m^2)くらいかかるわけですが、これがO(n - m)になっていると思います。たぶん。

水曜日に始めたC言語の勉強で、せっかくだからパフォーマンスが要求されるようなプログラムを作ろうと思って考えたのがこれです。ってアルゴリズムの部分で高速化しても「Cで書いてよかった」という満足感は味わえないんですがね…。

class RingCalc:
    def __init__(self, size):
        self.size = size
        self.Sx = size * (size - 1) / 2
        self.Sx2 = sum([x * x for x in range(size)])

    def setValues(self, values):
        self.values = values[:self.size]
        self.index = 0
        self.initCalc()
        for v in values[self.size:]:
            self.append(v)

    def append(self, value):
        oldValue = self.values[self.index]
        self.values[self.index] = value
        self.index += 1
        self.index %= self.size
        
        self.stepCalc(oldValue, value)

    def initCalc(self):
        self.sumY = sum(self.values)
        self.sumY2 = sum([y * y for y in self.values])
        self.sumXY = sum([x * y for (x, y) in enumerate(self.values)])
        
        self.calced()

    def stepCalc(self, oldValue, value):
        self.sumY = self.sumY - oldValue + value
        self.sumY2 = self.sumY2 - oldValue ** 2 + value ** 2
        self.sumXY = self.sumXY - self.sumY + self.size * value

        self.calced()
        
    def calced(self):
        from math import sqrt
        n = self.size
        Sy2 = self.sumY2
        Sy = self.sumY
        Sxy = self.sumXY
        Sx = self.Sx
        Sx2 = self.Sx2
        SySy = float(Sy * Sy)
        SxSy = float(Sx * Sy)
        SxSx = float(Sx * Sx)
        Vxy = Sxy * n - SxSy
        Vxx = Sx2 * n - SxSx
        Vyy = Sy2 * n - SySy
        print "ave:", Sy / n
        print "var:", Vyy / n / (n - 1)
        print "katamuki:", Vxy / Vxx
        print "cor:", Vxy / sqrt (Vyy * Vxx)

Schemeでチャーチ数

この前の数のない世界を見た友達に「チャーチ数を勉強しろ」と言われたので勉強してみました。(ソースコード参照)

僕が前にやったのは括弧の深さで自然数を表現するのでしたが、こっちは関数適用の深さで自然数を表現するのですね。引き算をどうやって実現するのかが謎です。イコールが実装できればがんばって引き算できるんですが、それもどうしたものやら。(lambda (x) (+ x 1))なんかの同じ値が現れないことが自明な関数を使えば簡単ですけど、それはズルっぽいですし。

はてな - λ計算とはを見ながらYコンビネータを使った階上計算をやってみたけどうまく行かないなぁ。

(define zero (lambda (f) (lambda (x) x)))
(define one (lambda (f) (lambda (x) (f x))))
(define two (lambda (f) (lambda (x) (f (f x)))))
(define three (lambda (f) (lambda (x) (f (f (f x))))))

(define add 
  (lambda (m) 
    (lambda (n)
      (lambda (f)
        (lambda (x)
          ((m f) ((n f) x)))))))

(define mul
  (lambda (m)
    (lambda (n)
      (lambda (f)
        (m (n f))))))

(define (inc x) (+ x 1))
(define (test m) ((m inc) 0))

(test ((add two) three)) ;-> 5
(test ((mul two) three)) ;-> 6

(define (Y f)
  ((lambda (x)
     (f (x x)))
   (lambda (x)
     (f (x x)))))

(define (zuruEq x y)
  (= (test x) (test y)))

(define (fact n)
  (define (foo start end value)
    (if (zuruEq start end)
        ((mul value) end)
        (foo ((add start) one) end ((mul start) value))))
  (foo one n one))

(define (fact2 n)
  ((Y
   (lambda (f)
     (lambda (start end value)
       (if (zuruEq start end)
           ((mul value) end)
           (f ((add start) one) end ((mul start) value))))))
   foo one n one))

(test (fact three)) ;-> 6
(test (fact ((add three) two))) ;-> 120

(test (fact2 three)) ;-> hung up!

2006年06月02日

要望と展望

GRINEditが目指すもの

  • 世界に通用するソフトウェア
    • graphvizを超える
  • インタラクティブであること
    • 得たいレイアウトを得るために 「データをいじる」 「可視化する」 「またデータをいじる」 を繰り返すのは非効率
    • 直感的に操作できること
    • 操作の結果も即座に確認できる
    • 思考を妨げない
  • 拡張性の高さ
    • クリエイティブなユーザの思いつき
      • どんなに完成度が高くてもすべてカバーは出来ない
      • どんなに完成度が高くても「こんな機能はないのか」と言われる
      • 拡張性がないとユーザは0から実装しないといけない
      • ユーザがせっかくの思いつきを公開する前に挫折してしまう
    • ニーズに応じて拡張することが容易でなければならない
    • 外部JARファイルからクラスをロード(サポート済)
    • Jythonスクリプトの実行(サポート済)
      • 再コンパイルの必要がない
      • メニューなどのGUIもJython
        • 依存性の注入
        • インスタンス化をJavaでハードコーディングしない
        • メニューを自由に変更可能
  • 他のプログラムとの連携
    • ソフトウェアを使うのは人間だけではない
      • 他のプログラムとの連携が重要
      • 他のプログラムが出力した結果を可視化
      • 独自フォーマットのデータは余計な手間を増やす
      • 多くの言語でパーサが実装されているデータ交換用言語を使うべき
        • XML, YAML, JSONなど
    • データファイル形式はJSON
    • XML-RPCで他のプロセスから操作が可能(サポート済)
  • 再利用性の高さ
    • 容易に利用できるライブラリ
    • 物理法則ベースのレイアウトエンジンを再利用できるようにする。
    • GRINEditを「ライブラリ化する部分」と「それ以外」に分離する。
    • いろいろな応用アプリを作ることで不足している機能をあぶりだす
  • ユーザ層の厚さ
    • 高い移植性
      • Java
        • OS非依存
      • Standard Widget Kit(SWT)
        • 高いパフォーマンス
    • 多言語対応
      • 日本語と英語に対応済
      • 切り替えも容易
      • 他の言語への対応も簡単
    • 豊富なドキュメント
      • 日本語と英語の両方
      • ある程度は自動生成
      • 英語サイトの充実
      • コンパクトで読みやすいサンプル
  • 余裕があれば試してみる
    • XSLTでグラフ変換
    • プラグイン中でJNIを使う(高速化)

目指さないもの

  • 1000頂点、10000頂点などの巨大グラフの表示
    • 巨大なネットワークはどう表示させてもわかりやすくないと思う
    • 表示だけはいちおう出来る
  • 収束状態へ落ち着くまでの時間の短さ
    • 描画を止めて計算する方が高速だが、操作に応じてグラフが連続的に変化することを重視
    • 連続的でない整形アルゴリズムは必要に応じてメニューから選ぶ(それなら非連続的でも不自然ではないので)
  • 論文になるような新しい整形アルゴリズム
    • 学術的に新しいアルゴリズムでも使いやすいライブラリやツールがなくては使える人が限られる。
    • 既存の力学的整形方法にも、実装上ではいろいろなノウハウがある。論文にならないノウハウを再利用可能なライブラリにすることにも価値がある。

XML-RPCできあがり

下記のソースコードで赤い丸い頂点や"Hello"と書かれた箱を作成したり、0.5秒に1個ずつ頂点を追加したり、ということができます。

import xmlrpclib
s = xmlrpclib.Server("http://localhost:8080/RPC2")

v1 = s.grinedit.addVertex(
        "CircleVertex",
        {"bgcolor": (255, 0, 0),
         "diameter": 20})

v2 = s.grinedit.addVertex(
        "BoxVertex",
        {"label": "Hello"})

s.grinedit.addEdge(
    "LinearEdge", v1, v2, {})


from time import sleep
prev = v2
while True:
    v = s.grinedit.addVertex(
        "BoxVertex",
        {"label": str(prev)})
    s.grinedit.addEdge(
        "LinearEdge", prev, v, {})
    prev = v
    sleep(0.5)

XML-RPC→リフレクション

当初、Jythonでやろうと思っていたことが、Javaだけでもリフレクションを使えばできると気がついたのでJavaだけでやる方針に変更しました。

あー、追加した頂点にいろんなパラメータをセットするために、その頂点のメソッドを呼び出すところでつまずきました。そうか、Javaは名前だけでメソッドをゲットできないんですな。シグネチャが違えば同じ名前で複数のメソッドを作れるから。Pythonとはそこがちょっと違う。XML-RPCの引数にシグネチャまで指定するのは変なので、ここの頂点が持つメソッドの引数はObject1個に固定してしまいましょう。たくさん渡したければ配列なりハッシュなりを渡せばいいだけですから。

ははーん。InvocationTargetExceptionが起きると思ったら、XML-RPCで配列を投げるとJava側で受け取るのはVectorなのか。int[]にキャストしようとして怒られた。まぁ、そりゃそうか、要素にObjectじゃないものが混ざっているとやっかいだろうしな。ということはintもIntegerオブジェクトになっているんだろうな。

結局ColorHolderにVectorを引数に取るgetメソッドを追加。括弧だらけ。Jythonを使っていればもっと楽ちんだったのですが…まぁ、そんなに大変でもないからいいや。でもとりあえずXML-RPCで好きな色の丸い頂点を追加することはできるようになりました。setBackgroundってメソッド名にしてあるけども、引数がObjectとかいろいろ制約があるので一般的なsetterみたいな名前じゃなくてrpc_bgcolorとかにしましょうかね。

    public static Color get(Vector rgb){
    	return get(
    			((Integer)rgb.get(0)).intValue(),
    			((Integer)rgb.get(1)).intValue(),
    			((Integer)rgb.get(2)).intValue());
    }

directed

メモ。Vertexまわりの構造を変えたのでdirectedのON/OFFがうまく動かなくなっているけども、そもそも「無向辺が実は有向辺で、directedのON/OFFで矢印を表示するかどうかが変わる」という設計が変なのでそこはまとめて整理するまで放置。

アプレット動く

GRINEditアプレットは一応動くようになりました。

現在は頂点の色が固定だったり、アプレットとしてデータファイルを読む機能がなかったりします。

頂点の色に関しては、SWTのColorがガベージコレクトの対象外で、不用意にインスタンスを作るとどんどんメモリ消費量が増えてしまうと思って一括管理をするColorHolderというクラスがあるのですが、これをまだAWTに対応させていないためです。AWTのColorはただ値を持っているだけのクラスだと思うのであまり大げさなものは必要なさそうですが。Color (Java 2 プラットフォーム SE v1.4.0)

後者のデータファイルを読む機能に関しては、まぁアプレットがサーバからHTTPでデータを取る形にするのが一番簡単そうですが、問題はこのファイルのフォーマットです。legacy formatのパーサをJavaで書きたくありません。というわけでXMLかYAMLかJSONをサポートするまでこちらは保留にします。 目標を増やしすぎるのもよくないかと思いますし。 現在の目標はGRINEdit本体がXML-RPCで他の言語からも使えるようにすることと、GRINEditの整形ライブラリが他のJavaプログラムから使いやすい設計になることの2つ。

今回アプレットを作ったことで、だいぶリファクタリングが進みましたけど、もう一押ししたいですね。現状で53KBの本体のJarの他に「使わないはずのswt.jar」1128KBが必要なのが少し嫌です。そうなると、やっぱりVertexなどはレンダリングが何に対してかによってBoxVertex_SWT、BoxVertex_AWTに分かれるべきなのかも知れないですね。BoxVertexが適切に判断してBoxVertex_SWTかBoxVertex_AWTかどちらかのインスタンスを返すというのもアリかな…。コンストラクタをprivateにしてmakeInstanceメソッドを呼ばせるようにすればそういうことも可能ですね。

クラスがたくさんあるJavaアプレットのappletタグの書き方

たくさんのクラスがあってきちんとパッケージを掘っている場合には 必要なクラスをjarにまとめ、他の必要なjarと一緒にアップロードし、 archive属性で「archive = "sampleApplet.jar, swt.jar"」というように指定する。

指定されたjarがカレントディレクトリにない場合はcodobase属性を用いて 「codebase = "http://www.nishiohirokazu.org/blog/files"」という様に指定する。

起動すべきAppletクラスがどれなのかは、code属性で 「code = "org/nishiohirokazu/dummy_package/sample_impl/SampleApplet.class"」 と指定する。

GRINEditアプレット

GRINEditの整形ライブラリを用いたアプレットのサンプルです。右ドラッグで拡大縮小、左ドラッグで頂点の移動(固定)ができます。

日記

「村上ファンドを捜査」がトップニュースです。逮捕ならまだしも捜査の段階で1面記事ってのはどうなんでしょう。この記事を見て快哉を叫ぶ人が多いんでしょうかねぇ。

今まで快哉を「かいや」だと思っていましたが、変換で出ないので調べてみたら「かいさい」でした。

GRINEditアプレット。動きました!右ドラッグで拡大縮小、左ドラッグで頂点の移動です。はてな人力検索に質問を投げて、一晩寝たら解決しちゃいました。80円で。「1000円払ったらアプレットが動くようにしてあげる」と言われたらたぶん払ってしまうと思うので、これはものすごーくお得な買い物でした。

表示するのはちょっと待って!IEでは動作したけどFirefoxはハングアップするみたい! Firefoxってappletタグで指定されたjarファイルが存在しないだけでハングアップするみたいですね。きちんとファイルのある位置をcodebaseに指定してやったら表示されるようになりました。

できあがり。 そろそろドキュメントの生成も考えていかないといけませんね。

研究室での雑談で気がついたのだけど、GRINEditを未踏ソフトに応募して、受かったら学振研究員をやめてしまうというパスもありえますね。今まで「学振は兼業禁止だから未踏には応募できない」と思いこんでいたせいで、やめるという選択肢に気がつきませんでした。未踏ソフトの方に受かったら人を雇えていいかもしれませんね。それなりのスキルの人を雇うのにどれくらいのお金がかかるのかさっぱり見当がつきませんが、C++が読めてJavaが書ける人とか、Javaが読めてわかりやすい文章を英語で書ける人とかがいると、GRINEditを世界に通用するソフトにする上で心強いですよねぇ。

でも人を探してきたり仕事割り振ったりするのは苦手かも知れないなぁ。

せめてドキュメントを自動生成することを考えてみる。


今日は例のゲーム(ITmedia News:“IT研究者人生ゲーム”を研究者が開発)を4人でプレイして、全員初挑戦だったのでやけに時間がかかって4時間も費やしてしまったのでした。

2006年06月01日

XML-RPCを考える

とりあえず(本当は物理法則の変更や動的なスクリプト実行なんかが売りだけども)頂点と辺の追加ができればいろいろなグラフの可視化に使ってもらえそうなのでそれを早急に詰めましょう。

将来的にやっぱりいろいろな種類の頂点をサポートすることになると思うので、int addVertex(String vertexType, struct params)が一番現実的かなぁと思っています。返り値のintはvertexListの中での追加された頂点の位置で、これをint addEdge(String edgeType, int vertex1, int vertex2, struct params)で辺を追加するのに使います。

この仕様でとりあえず問題なかろうと思っています。また、このインターフェイスがあればXMLやJSON、YAMLでデータファイルを作成し、それを読み込むパーサを作るのも簡単になりそうだと思っています。すくなくともdotファイルよりは見通しのいいものにしたいですね。

物理演算の追加はint addPhysicalLaw(String lawName, array target, struct params)とかかな。削除や変更のことも考えておかなくてはいけないだろうけど、明日はとりあえず追加とクリア(全消去)だけにします。

Applet作成

GRINEditアプレット作成中。元のGRINEditはSWTなので org.eclipse.swt.graphics.GC に対して描画を行っています。しかしアプレットはSwingで作ることにしたので、java.awt.Graphics に対して描画を行います。renderという関数を作ったとしても受け取る引数が異なるからSWTとSwingの両方をサポートするのは無理だ…と思っていたのですが、描画を担当するオブジェクトをVertexに持たせてデリゲーションすればいいだけのような気がしてきました。今はRenderableVertexのサブクラス化で描画のタイプの異なる頂点を作っていますが、RenderableVertexにaddRendererって感じのメソッドがあればいいだけかもしれませんね。

addRendererじゃなくてsetRendererにしとこう。一つの頂点が複数のレンダラーを持つなんて機能は必要なかろう。

あー、そうか、CircleVertexはdiameterを持ち、BoxVertexはtextを持つのか。頂点の種類によって必要とする値が異なるわけですね。全部を親のRenderableVertexに持たせるのはきなくさい。解決方法は簡単なのが一つあるけど、それを選択する前にちょっと考えてみよう。そもそも継承ではなく委譲でポリモルフィズムするメリットはなんなのでしょうか。

継承ならフィールドを追加するのも自然にできます。自分のrenderメソッドが自分のフィールドを読むだけだから自然です。委譲なら、Rendererが個別のVertexの属性を持つのはおかしいし、抽象的なVertexクラスに具体的なフィールドをつけるのもおかしいので、僕が思いつく一番まっとうな解決法はVertexクラスにpublic Hashtable propertiesをつけるなんてのになります。プロパティへのアクセスのたびに型キャストが必要です。

renderメソッドの引数をObjectにしておいてSWTのGCでもAWTのGraphicsでも受け取れるようにした上で、リフレクションで分岐すればいいだけですし。

まぁ、RenderableVertexのrenderメソッドはObjectを受け取ってthis.rendererに委譲する用にしておいても、継承したらどうせrenderを上書きしてしまうんだから支障はないですね。

RenderableGraphのdrawOnBackgroundはダブルバッファリングを管理しているオブジェクトを受け取っているけど、呼び出しているところは1カ所なのでそこで描画対象を取り出して渡してやればRenderableGraphは単にVertexとEdgeに中継するだけになりますね。


後輩にEclipseの設定の仕方を教えたりしつつ、とりあえずアプレット上で頂点が100個あるグラフの表示はできました。ダブルバッファリングつき。後は肝心のマウス周りですね。

マウスイベントのハンドリングは基本的には、MouseListenerとMouseMoveListenerをimplementsしたMouseMediatorが、受け取ったイベントを具体的なクラスに渡す設計になっています。その渡す対象がどれか、というのをMouseMediatorが持つことで「右や左のボタンの意味」を簡単に切り替えられるようになっています。さて…、今はorg.eclipse.swt.events.MouseEventを投げ渡していますけど、これをx,yの座標だけ渡すように抽象化してしまえばいいですね。MouseMediatorだけがSWTとAWTの両方に対応し、具体的なMouseOperationクラスには座標の値だけが渡る、と。

MouseOperationのdrawメソッド内でシングルトンのDoubleBuffererにアクセスしていますねぇ。これは範囲選択のドラッグ時の枠を書くためなのですが…。ダブルバッファリングを使いたくないシチュエーションってあるかなぁ…。ああ、すでに自前のダブルバッファリングを持っている場合とかはこちらが用意したDoubleBuffererを使いたくないかも知れないですね。じゃぁ、ここもやっぱり描画対象をObject型で取得してリフレクションで分岐する方針で。

10KBのソースコードが8KBに縮みました(笑)

とりあえずマウス操作周りをSWTから切り離したところでCVSにコミットしておくとしますか。

さてと、次はMouseMediatorをAWTにも対応させる必要がありますね。

できました。でもアプレットビューワーでは動くけどブラウザで見るにはどうしたらいいのだっけ…。

うーん。

if(target.getClass() == Graphics.class ||
    target.getClass() == SunGraphics2D.class){

このコードが「java.security.AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.sun.java2d)」って感じにセキュリティモデルに引っかかるみたいで動きません。アプレットビューワーでなら動くんだけどなぁ…。やっぱりリフレクションで分岐するんじゃなくて委譲するようにするべきだったのかな…。いや委譲しないにしてもせめてSWT用とAWT用のクラスを分離すべきなのか。 SWTまわりのクラスがインポート宣言に含まれているせいで、実際には使われないのに「クラスがロードできない!」と怒られ、結局アプレットにswt.jarもつけてサイズがふくれあがってしまったり。やっぱりアプレットは何かと難しいなぁ。

カテゴリの説明がないときはラベルを表示するMovableTypeプラグイン

MovableTypeで「GRINEdit」カテゴリの下に「開発日誌(log)」というサブカテゴリを作ると、URLは「http://www.nishiohirokazu.org/blog/projects/grinedit/log/」になっていい感じだけど上のナビゲータに「開発日誌(log)」とだけ出るのでGRINEditの開発日誌だと言うことが伝わりません。ラベルを「GRINEdit開発日誌(log)」に変えて満足していたらURLも「http://www.nishiohirokazu.org/blog/projects/grinedit/grineditlog/」に変わってリンク切れ(正確に言うと更新されない残骸へのリンク)になってしまいました。勝手にURL変わらないで欲しいです。そこで、「カテゴリの説明があれば(そして空白文字列でなければ)それを表示し、なければカテゴリのラベルを表示する」というタグを作って、ラベルにはURLに入れたい文字列を使い、説明文に表示したい文字列を入れようと思いました。が、説明文をつけてもラベルしか表示してくれません…何がいけないのやら。

結局、文字列を != で比較したのがいけなかったようです。うまく動くようになった修正版に差し替えておきます。

MT::Template::Context->add_tag(CategoryDescOrLabel => sub {
    my ($ctx, $args) = @_;
    my $e = $ctx->stash('entry');
    my $cat = ($ctx->stash('category')
        || $ctx->stash('archive_category'))
        || ($e && $e->category)
        or return (defined($args->{default}) ? $args->{default} : 
                    $ctx->error(MT->translate(
                           "You used an [_1] tag outside of the proper context.",
                           '<$MTCategoryDescOrName$>' )));
    
    $cat->description || $cat->label;
});


日記

眠りたいけど眠たくない。朝4時半。


MovableTypeで「GRINEdit」カテゴリの下に「開発日誌(log)」というサブカテゴリを作ると、URLは「http://www.nishiohirokazu.org/blog/projects/grinedit/log/」になっていい感じだけど上のナビゲータに「開発日誌(log)」とだけ出るのでGRINEditの開発日誌だと言うことが伝わりません。名前を「GRINEdit開発日誌(log)」に変えて満足していたらURLも「http://www.nishiohirokazu.org/blog/projects/grinedit/grineditlog/」に変わってリンク切れ(正確に言うと更新されない残骸へのリンク)になってしまいました。個別のエントリーにはファイル名指定欄があり、変更しようとすると丁寧に「変更するとリンクが切れるおそれがあります」とか警告してくれるのに…。

CategoryをCategiryと打ってしまい、Catagiryとか思ってしまった(ラーメンズネタ)

カテゴリの説明がないときはラベルを表示するMovableTypeプラグインを作ったけど動かない…

わかった。Perlでは「'a' != ''」がFalseだというのが原因だったようだ。その為「カテゴリの説明 != ""」がたとえカテゴリに説明文が指定されていてもTrueにならない。文字列の比較にはeqを使うのですな。

ああっ、こんなつまらないことに2時間も使ってしまった!GRINEditの開発に入ろうとして、今までの日誌を見ようとしたら最近書いたはずの記事が見つからなくてなぜだろうと思ったことからこれをいじりだしたんだった。


できあがったものが自分の所では動くのに人に見せられないのってつらいねぇ。 ダウンロードが必要なソフトウェアよりアプレットの方がやっぱり気軽に試せると思うので、 広報的な観点からもアプレットをさくさく作れるようなライブラリにしておきたい。

でもまぁ、とりあえず一時休憩で、次はXML-RPCでどういうクエリを投げてもらうかってところを考えよう。

もう22時か。ぼちぼち帰ろう。おなかもすいたし喉が渇いたし。


やってしまった。廊下に置いていたお茶の入った薬罐を蹴り飛ばしてカーペット浸水。さいわい、大事な本はぬれなかったけど。

帰ってくるのが遅かったので店が閉まっていたのはまだいいとして、家に牛乳もパンもないことを忘れていたのは痛い。明日の朝食べるものがない。

Pythonで箇条書きをHTMLに変換

COREBlog使用時も生DTMLでエントリーを書き、tDiaryの勝手な整形よりMovableTypeでタグを手打ちする道を選んだ僕ですが、それでも箇条書きをHTMLで書くのは直感的でなさ過ぎるので嫌いです。 そこで、MovableTypeに「Wikiっぽい記法で書いた箇条書きをHTMLに変換してくれるタグ」を追加しようと思い、とりあえずそのアルゴリズムをPythonで書いてみました。(Perlでいきなり書く自信がなかったので)

あ、誤解を避けるために書いておくと、もちろんPythonで構造化テキストを扱いたいだけならStructuredTextとかreStructuredTextで検索して適切なライブラリを使う方が楽だと思います。今回はあくまで自分好みの箇条書きフォーマットをHTMLに変換するPerlのプログラムを作るためのプロトタイプってことです。

  • 特徴
    • インデントの深さで階層構造を表現
      • オートインデント機能のあるエディタと親和性が高い
      • Pythonの制御構造は別に意識していません
        • でもPythonの構文に親しんだせいでこれが自然な表現方法と感じるのかも
      • 箇条書きの点がハイフンと1対1対応するので直感的にわかりやすい?
      • 点のついていない行は前の項目の続きになる
        • つまり一項目を無理矢理1行にまとめる必要はない
      • 箇条書き中に空行や空白文字だけの行を含めることができる
  • 文法
    • 空白文字だけの行は無視される
    • 行頭に最初に現れる空白文字以外の文字がハイフンでない場合直前の項目の続きだと見なされる。
    • 行頭に最初に現れる空白文字以外の文字がハイフンの時、新しいliタグが作成される。
      • その際、インデントが深くなっていればulタグを1つ挿入する。
      • インデントが浅くなっていれば、適切な個数の閉じulタグを挿入する。

上の箇条書きは下のソースから生成されました。 僕はたまたまスペース1個のインデントで統一していますけど、Python同様インデントの幅に制約はありません。スペース2個でインデントした方が子の頭が親の文章の始まりにそろって美しいかも知れませんね。

追記:ハイフンを取り除くのを忘れていたので修正しました。@2006-06-01 05:06

# -*- coding: cp932 -*-
#
# 箇条書きジェネレータ
#

data = """
- 特徴
 - インデントの深さで階層構造を表現
  - オートインデント機能のあるエディタと親和性が高い
  - Pythonの制御構造は別に意識していません
   - でもPythonの構文に親しんだせいで
     これが自然な表現方法と感じるのかも
  - 箇条書きの点がハイフンと1対1対応するので直感的にわかりやすい?
  - 点のついていない行は前の項目の続きになる
   - つまり一項目を無理矢理1行にまとめる必要はない
  - 箇条書き中に空行や空白文字だけの行を含めることができる

- 文法
 - 空白文字だけの行は無視される
 - 行頭に最初に現れる空白文字以外の文字がハイフンでない場合
   直前の項目の続きだと見なされる。
 - 行頭に最初に現れる空白文字以外の文字がハイフンの時、
   新しいliタグが作成される。
  - その際、インデントが深くなっていればulタグを1つ挿入する。
  - インデントが浅くなっていれば、適切な個数の閉じulタグを挿入する。
"""

MARK = "-"
import re
pat = re.compile("^(\s*).*")
indent_stack = [-1]
result = ""
for line in data.split("\n"):
    sline = line.strip()
    if sline == "":
        continue
    if sline[0] != MARK:
        result += sline
        continue
    r = pat.match(line)
    indent = len(r.groups()[0])
    body = sline.lstrip(MARK)
    if indent > indent_stack[-1]:
        result += "<ul><li>" + body
        indent_stack.append(indent)
    else:
        while indent < indent_stack[-1]:
            result += "</li></ul>"
            indent_stack.pop()
        result += "</li><li>" + body

while -1 < indent_stack[-1]:
    result += "</li></ul>"
    indent_stack.pop()
        
print result

すこしPerlっぽく書いたのが下。(部分文字列より正規表現を選んだあたりがPerlっぽいつもり)

import re
pat = re.compile("^(\s*)(-?)(.*)")
indent_stack = [-1]
result = ""

def closeTags(indent):
    global result
    while indent < indent_stack[-1]:
        result += "</li></ul>"
        indent_stack.pop()
    
for line in data.split("\n"):
    (_1, _2, _3) = pat.match(line).groups()
    if _3 == "":
        continue
    if _2 == "":
        result += _3
        continue

    indent = len(_1)
    if indent > indent_stack[-1]:
        result += "<ul><li>" + _3
        indent_stack.append(indent)
    else:
        closeTags(indent)
        result += "</li><li>" + _3

closeTags(-1)
        
print result