sheaf, category and topos

訳あって「層・圏・トポス」を読んでいて, せっかくなので何考えながら読んでるかを晒してみる. 以下の地の文は俺の心の中のつぶやきである.

第1章 層

2. 前層

ここで前層の第一の定義が出てくるのだが, 与え方が形式的すぎてすぐには分からん. ただ, どうも集合 \(A\) で位相 \(\mathcal{O}(X)\) の元 (すなわち開集合) を関数 \(E\) によって parametorize しているっぽい雰囲気だ. \(\rceil\) は集合 \(A\) の元に開集合が右から作用してるのかなぁ. 3) の式を見るとそんな感じ. 集合の共通部分を取るのは集合の積と看做せるし.

とするとなんかどうも \(\rceil\) は集合の共通部分を取る操作に似ている. じゃあ \(E\) として恒等関数を取って, \(\rceil\) = \(\cap\) と見てみよう. 公理を全部満たしているので, \(X\) の位相は \(X\) の前層でもある.

1つ目の定義はなんとなく分かった.

MathJax test

inline -> \(x^2 + y^2\) <- inline

displayed $$ \sum $$

jvm backend in PyPy

PyPy (正確には RPython toolchain) の jvm backend への翻訳処理の設計を知りたくてソースコードを追い掛けてみた.

ややメモ書きっぽい感じだが, ほぼ自分用メモということで許してください.

(以下, パスは全て pypy のルートディレクトリを起点としている.)

入口

pypy/translator/jvm/genjvm.py の GenJvm クラス. たぶんだけど. pydoc はこんな感じ.

""" Master object which guides the JVM backend along.  To use,
create with appropriate parameters and then invoke
generate_source().  *You can not use one of these objects more than
once.* """

バイトコード吐いてるのが pypy/translator/jvm/generator.py の JVMGenerator. 既存の何かを使ってたわけではなく, 自作していたのか…… しかも raise NotImplementedError がそこかしこに見える……

これ作った人すごいなぁ. javac 相当のものを RPython で実装しているし. Antonio Cuni さんの仕事はどこまでなんだろうか?

GenJvm#generate_source

これを呼ぶと処理をしてくれるらしいのでここから読む.

メソッドの実装はこんな感じ.

def generate_source(self):
    """ Creates the sources, and returns a JvmGeneratedSource object
    for manipulating them """
    GenOO.generate_source(self)
    self.jvmsrc.set_jasmin_files(self.db.jasmin_files())
    return self.jvmsrc

Jasmin という jvm アセンブラを使っているようだ. Jasmin home page 処理は, 親クラスである GenOO の generate_source メソッドに処理を投げて, 出来上がった jasmin ファイルを jvmsrc 属性に格納して返しているようだ.

さてこのメインの処理を行っていそうなメソッドを覗いてみよう.

pypy/translator/oosupport/genoo.py を開く.

GenOO#generate_source

def generate_source(self):
    self.ilasm = self.create_assembler()
    self.fix_names()
    self.gen_entrypoint()
    self.gen_pendings()
    self.db.gen_constants(self.ilasm)
    self.ilasm.close()

う〜む, 綺麗だ. 文句の付けようが無い. だいたいどんな処理をやっているのか分かりやすくて良い.

GenJvm#create_assembler

まず処理の主体となるであろうアセンブラを用意しているところから見る. デフォルト実装は raise NotImplementedError となっていて, GenJvm クラスでは以下の実装になっていた.

def create_assembler(self):
    """ Creates and returns a Generator object according to the
    configuration.  Right now, however, there is only one kind of
    generator: JasminGenerator """
    return JasminGenerator(self.db, self.jvmsrc.javadir)

JasminGenerator クラスは pypy/translator/jvm/generator.py にある.

JasminGenerator のコンストラクタはいったん置いといて, 次の処理の中身を見てみる.

GenOO#fix_names

def fix_names(self):
    # it could happen that two distinct graph have the same name;
    # here we assign an unique name to each graph.
    names = set()
    for graph in self.translator.graphs:
        base_name = graph.name
        i = 0 ...

Mac で PyGame のインストール

PyPy の translationshell.py で遊んでいると, Flow Graph の表示に PyGame が必要になってくるので, それをインストールした記録.

homebrew と pip は入っているものとする.

$ brew install sdl sdl_image sdl_mixer sdl_ttf smpeg portmidi
$ pip install hg+http://bitbucket.org/pygame/pygame

"Warning: m4 macros were installed to "share/aclocal"." という警告が出たけど無視しても大丈夫でした.

smpeg のインストールで失敗したけど "Error: This is a head-only formula; install with brew install --HEAD smpeg" と出たので, 指示どおりに

$ brew install --HEAD smpeg

とやったら無事インストールできました.

きちんと手順をまとめておくと, こんなふうになります.

$ brew install sdl sdl_image sdl_mixer sdl_ttf portmidi
$ brew install --HEAD smpeg
$ pip install hg+http://bitbucket.org/pygame/pygame

参考資料: https://bitbucket.org/pygame/pygame/issue/82/homebrew-on-leopard-fails-to-install#comment-627494

syntax highlighting in bloggart

Elliptium は bloggart というブログエンジンをちょっと改造したもので動いています. 長らく syntax highlight の方法が分からなかったのですが, やっと分かりました.

bloggart には docutils と pygments がライブラリとして入っているので,

.. sourcecode:: <syntax type>

   hoge
   fuga

とやるだけでした.

docutils から pygments の syntax highlight 機能を利用するには http://www.deffbeff.com/blog/2009/06/using-pygments-with-docutils/ にある方法が標準的です. bloggart では rst_directive.py をモジュールが読み込まれる位置に持ってきて対応しています.

<syntax type> が取り得る文法を調べると, pygments.lexers._mapping.LEXERS という辞書を見ると良いようです. この辞書の値はタプルになっていて, 第3要素にある文字列が <syntax type> に来ることができます.

以上, ほぼ自分用のメモでした.

初めての RPython Toolchain

タイトルは釣りっぽく見えるかもしれませんが, 理論にばっかり興味あったので, RPython をちゃんと触るのは初めてです.

発端

理論派で手を動かすのが億劫な俺が実装書いてみようと思った動機は, PyPy Sudden Death Calendar 27日目 - JVM Backend に完敗した件を受けて にある話にあります. ここでは ootype によって JVM 用に変換されたクラスがしっちゃかめっちゃかだ, ということを追っています. なんでこんなことになっているのか分からないので, まずは簡単なインタプリタを例に RPython Toolchain の動きを追っていく計画です.

プログラム仕様

このプログラムの仕様はすごく簡単で, 各行の先頭に暗黙の echo があるものとして動作します. プログラミング言語 ECHO とでも呼びましょうか.

実装

さっきのブログエントリの筆者でもある shoma さんが翻訳されている PyPy を使ってインタプリタを書く を参考に作りました.

"""
echo.py

programming language ECHO
implemented on top of PyPy

by cocoatomo
"""

import sys
import os

try:
    from pypy.rlib.jit import JitDriver
except ImportError:
    class JitDriver(object):
        def __init__(self, **kw): pass
        def jit_merge_point(self, **kw): pass
        def can_enter_jit(self, **kw): pass

jitdriver = JitDriver(greens=['pc', 'program'], reds=[])

def mainloop(program):
    pc = 0

    while pc < len(program):
        jitdriver.jit_merge_point(program=program, pc=pc)

        line = program[pc]

        # instead of print
        os.write(1, line)
        os.write(1, '\n')

        pc += 1

def parse(program):
    return program.split('\n')

def run(fp):
    program_contents = ''
    while True:
        read = os.read(fp, 4096)
        if len(read) == 0:
            break
        program_contents += read
    os.close(fp)

    program = parse(program_contents)
    mainloop(program)

def entry_point(argv):
    if len(argv) < 2:
        print("too few arguments. program file name needed.")
        return 1

    run(os.open(argv[1], os.O_RDONLY, 0777))
    return 0

def target(*args):
    return entry_point, None

def jitpolicy(driver):
    from pypy.jit.codewriter.policy import JitPolicy
    return JitPolicy()

if __name__ == "__main__":
    entry_point(sys.argv)

なんの変哲も無い処理系です.

PyPy は pypy-ja で fork している レポジトリ から取ってきました.

$ python ./pypyja/pypy/translator/goal/translate.py --opt=jit echo.py

とすると長々とビルドが走り, MBA によって俺の腿が温まりました.

$ cat input.echo
begin
1 ...

Licenses