2010/12/23

2011年賀状

年賀状書いた。
%!
<< /PageSize [285 420] >> setpagedevice

/ellipse { % def
/c 2 index def
{ % for
/t exch def
/r1 {rand 4 mod 2 div} def
/r2 {rand 2 mod 2 div} def
/r3 {rand 2 mod 2 div} def

newpath
gsave
65 190 moveto
/x 70 t cos mul def
/y 220 t sin mul def
x y rmoveto
/xscale 2.0 t cos add 20 mul def
/yscale 1.0 t cos add 30 mul def
/FireFightBB findfont [xscale 20 20 yscale 0 0] makefont setfont
(2011) true charpath clip

newpath
0 70 490 { % for
/i exch def
gsave
100 190 translate
70 setlinewidth
r1 r2 r3 setrgbcolor
.5 1 scale 0 0 i 70 add 0 360 arc stroke
grestore
} for
grestore
} for
} def

1 1 20 {
/n exch def

0 12 360 ellipse
102 6 258 ellipse % for dense farside

240 25 moveto
/Georgia-Bold findfont 10 scalefont setfont
n =string cvs show
(/20) show
showpage
} for
書いたものの、肝心の年賀状がなかったので、とりあえずテスト印刷だけ。

IMAG0145.jpg

今年はFire Fightというフォントを使わせていただきました。文字のレイアウトはあっさり決定したけど、色づけとフォント選びが悩ましかった。

2010/12/20

プログラミングのための確率統計 in Haskell

まっとうなサイコロをふったときに出る目の確率は、こんな表にまとめられます。

目の値123456
確率1/61/61/61/61/61/6

こんな表のことを確率分布といいます。サイコロをふったときに起こるイベントの確率、たとえば「偶数の目が出る」確率を調べることは、この確率分布からこんな別の確率分布への変換だと考えられます。

目の値2,4,6(偶数)1,3,5(奇数)
確率1/21/2

この変換は、具体的にはこんな対応です。
P(偶数) = P(2) + P(4) + P(6)
P(奇数) = P(1) + P(3) + P(5)
P(X)がイベントXに対する確率を表しているわけですが、Pを「イベントの集合から[0,1]区間の実数への関数」だとみなすこともできます。確率分布から確率分布への変換は、関数に対する演算でもあるわけです。確率分布を連想リストで表せば、高階関数や代数型を使って、この変換をモデル化できそうです。

以前、このアイデアをSchemeで試してみたことがありました。当時は、そもそも確率についての理解が今よりもいっそうあやしかったし、実装もちゃちでしたが、このアイデアが特別なものでなかったことを最近になって知りました。その名も確率的関数プログラミング(Probabilistic Functional Programming)。PFPと呼ばれているようです。Haskellのライブラリが公開されているので、これで遊んでみます。



PFPでは、確率と確率分布をだいたいこんな感じに定義しています。
newtype Probabillity = P Float
Dist a = D [(a, Probability)]
確率分布(Probabilistic Distribution)は連想リスト以外のなにものでもありません。

さっそく例題をといてみましょう。次のような確率の問題を考えます。どこかで見たことがあるような問題ですね :)
とあるロールプレイングゲームではモンスターを倒すと宝箱が得られます。その宝箱には確率 2/3 で罠がかかっています。罠の気配は魔法で判定できますが、この判定は完璧ではなく、確率 1/10 で間違った判定結果がでてしまいます。
  • 問題1. モンスターを倒して得た宝箱に魔法をかけたとき気配なしと判定される確率は?
  • 問題2. 魔法をかけたら気配なしと判定された。このとき本当は罠がかかっている確率は?
なにはともあれ、宝箱をあらわす型を用意します。宝箱は、罠がかかっているか、安全か。
data TreasureBox = Trap | Safe
問題文を読むと、2つの確率分布があたえられていることがわかります。罠がかかっている確率をあらわす分布と、判定魔法の結果をあらわす確率分布です。PFPには、イベントを列挙したリストと、それに対応する確率を列挙したリストとから確率分布を生成するための関数enumが用意されているので、これを使います。
treasureOfMonster   :: TreasureBox -> Dist TreasureBox
treasureOfMonster _ = enum [2/3, 1/3] [Trap, Safe]

magicSpell :: TreasureBox -> Dist TreasureBox
magicSpell Safe = enum [1/10, 9/10] [Trap, Safe]
magicSpell Trap = enum [1/10, 9/10] [Safe, Trap]
いずれの関数も、引数として受け取るのは目の前にある宝箱です。目の前にある宝箱は、それがモンスターから得たtreasureOfMonsterであれば、とにかく 2/3 で罠がかかっています。その宝箱にmagicSpellをかけると、罠がかかっていなくても 10回に 1回は罠がかかっていると判定してしまうし、逆に 10回に 1回は罠がかかっているのに安全だと判定してしまいます。

では、目の前にあるtreasureOfMonsterな宝箱にmagicSpellをかけてみましょう。2つの確率分布を組み合わせればいいのですが、magicSpellの結果は、とうぜん、treasureOfMonsterな宝箱に罠がかかっているかどうかで変化します。分布Bが分布Aに依存するというなら、分布Bそのものではなく、Aから分布Bへの関数を組み合わせればいい。つまり、Distがモナドであればいいということです。実際、PFPではそのように実装されています。だから、こんなふうにすれば、モンスターの宝箱を魔法で調べた結果の確率分布が得られます。
check     :: TreasureBox -> Dist TreasureBox
check box = treasureOfMonster box >>= magicSpell
試してみましょう。宝箱はなんでもいいので、undefinedを与えておきます。
*RPG> check undefined
Trap 63.3%
Safe 36.7%
問題1の答は 36.7% だとわかりました。本来の安全な確率である 1/3 より若干多い値であることから、誤判定で罠を見抜けない危険性のほうが、罠がないのに罠があると間違えてしまう可能性よりも影響が大きいようです。

問題2に答えるために、罠がかかっているのに罠がないと判定してしまって死に至る確率を考えてみましょう。そのような事態はこんな演算として表せます。
death           :: TreasureBox -> TreasureBox -> TreasureBox
death Safe Trap = Trap
death _ _ = Safe
magicSpellの結果とtreasureOfMonsterの結果のそれぞれに対して、このdeath演算を適用すれば、その一覧から死に至る確率がわかるでしょう。PFPでは、このような操作のために、joinWith :: (a -> b -> c) -> Dist a -> Dist b -> Dist cという関数が用意されています。
dead     :: TreasureBox -> Dist TreasureBox
dead box = joinWith death (magicSpell Trap) (treasureOfMonster box)
magicSpellに与えている引数がTrapなのは、ここで気にしている状況が「目の前にある宝箱に実際には罠がかかっている」場合だからです。ただ、魔法をかけるほうからすると、目の前にある宝箱がdeadか否かはわかりません。deadで評価する宝箱はundefinedです。
*RPG> dead undefined
Safe 93.3%
Trap 6.7%
宝箱を前にしてmagicSpellによる判定結果を盲信するというポリシーをつらぬくと、6.7%の確率で死んでしまうようです。

さて、問題2に戻りましょう。知りたいのは、magicSpellの判定結果で安全と出たときに、実際には罠がかかっていて死を招いてしまう確率です。これは、いわゆる条件つき確率の問題なので、教科書的には Bayesの公式で解く場面です。しかし、すでに「判定結果で安全と出る確率」も「死に至る確率」もわかっているので、これらの比率を求めれば答が得られます。
guessedSafeButTrap :: Probability
guessedSafeButTrap = (==Trap) ?? dead undefined |/ (==Safe) ?? check undefined

infix 7 |/
(|/) :: Probability -> Probability -> Probability
(|/) (P p) (P p') = P $ p/p'
(??)は、PFPに用意されている「確率分布からイベントの確率を求める」関数で、Event a -> Dist a -> Probabilityという型を持ちます。(|/)は、Probability型同士の確率の値について割り算をするために定義しました。infixを7にしたのは、??infixが8だからです。

コンパイルして評価すれば問題2の答がわかります。
*RPG> guessedSafeButTrap
18.2%
安全だという判定が出ても、誤判定が 1/10 もあると、まだまだ気を抜けないようです。

(PFPのソースをのぞくと conditional probability というコメントのついた関数(|||) :: Dist a -> Event a -> Dist aがあって、いかにも条件つき確率の計算に使えそうだけど、確率分布からイベントの確率をfilterするようにしか見えない。そんな型で大丈夫か?)



まとめ

HaskellとPFPを使うことで、確率の問題をうまく抽象化してエレガントに回答を導くことができます。そしてこの抽象化は、Haskellという言語の機能によるものではなく、確率論という数学によるものです。PFPにしても、特別なHaskellの機能はほとんど使っていないように思います(PFPには確率過程をシミュレーションする機能もあって、そちらはもしかしたら高度なHaskellの機能が満載かも)。そんな数学における抽象化をダイレクトにコードで使えることがHaskellの魅力のひとつなのはいわずもがな。

数学では、抽象化が漏れて台無しにならないように、厳密な論証や独特の表記を使います。そのため、数学による問題の抽象化を利用するには、少し勉強や訓練が必要です。とくに確率論は、漏れがないように抽象化された理論(公理的確率論とか呼ばれます)を勉強しようと思うと、高校までの数学経験だけではつまずいてしまう教材が多い。多少の漏れを棚に上げた感覚的な確率の話をもって「確率論」という教材もあって、それはそれでおもしろいとは思うのですが、抽象化の道具として使うにはちょっとねえ。

そこでおすすめの教科書はこれ。



『プログラミングのための確率統計』
PDFでも買えます

ここまで読んだ貴徳な方なら、この記事の例題が『プログラミングのための確率統計』のものであることに気がついているかもしれません。具体的には53ページの例題2.7。この本に書いてある図を見れば、条件付き確率は一目瞭然です。確率分布や確率変数がとてもよくできた確率の問題の抽象化であることを実感できると思います。

なお、この記事は Haskell Advent Calendar jp 2010 のために書いたものです。宣伝いうな。

2010/12/08

Kindleはメディアそのものだった

もう紙の本はbook、電子の本はkindleという一般名詞でいいとさえ思う。Kindle for the Webの正式リリースが数ヵ月後だと発表されて、あらためてそう感じた。Amazon.comも一企業でしかないので、あんまり妄信するつもりはない。けれども、今年の初めにKindle DXを買ってから12冊ばかし読んでみて、Kindleが自分の読書空間の一部になってしまったなと実感している。つまり、Kindleというのはデバイスとかデータ形式ではなく、紙の「本」が書店や読書の場所(自宅とか電車とかスタバとか)なんかを含めた大きなメディアであったのと同じ意味で、メディアそのものだった。

たぶん、Kindleが自分にとってメディアそのものになってしまった背景には、こんな理由がある。
  1. 本当に読みたいと思える本がいつでも買える
  2. リフローするページメディアである
  3. さまざまな環境でシームレスに読めてしまう

1の要因は本当に大きい。この1年でいろんな本がEPUBやPDFで配布されるようになったけど、Kindleにはすでにほとんどそろってる。紙の本ならジュンク堂に行くように、品揃えのよい本屋はそれだけで足を運ぶ価値がある。Kindleは足を運ぶ必要もない。

2は、Kindleに限らず、革命だと思う。むかしはわたしもスクロールメディア対ページメディアとか考えてました。読書におけるページというインターフェースの利点は、情報の位置が固定されることやインデックスとしてノンブルがあることじゃなかったのですね。この革命感は、実際にKindleやEPUBリーダーで本を読みまくらないと実感できないかも。3だって、クラウドとかいう前に、2があるからこそ違和感なく実現できるわけで、リフローするページメディアは偉大だと思う。スクロールして読むEPUBリーダーとか意味わからん。

「こうじゃない」式の言い方をするなら、たとえば、EPUBやPDFで配布されているものをデバイスのKindleで読むことは、ここで絶賛したいKindleのうれしさではない。あるいは、EPUBで配布されている電子書籍をAndroid端末のEPUBリーダーで読むことだって、Kindleストアで購入した電子書籍をKindle for Androidで読むのと同じくらいに快適だけど、プラットフォームとしての魅力があるのはKindleのほう。もしくは、購入した書籍を自炊したPDFをiPadで読むのはすばらしいけれど、それはやっぱり「電子書籍の代替」なんだろうなと思う。

2010/11/29

多値で簡単パーサーコンビネーター(Shibuya.lisp TT#6)

Shibuya.lispのテクニカルトーク#6に参加しました。仕事半分以下、趣味半分以上です。

まず仕事の部分について、直売で書籍を購入いただいた皆さん、本当にありがとうございました。Lispそのものの本よりも『鉄道ダイヤの回復技術』や『日本のコンピュータ史』のような本が想定以上に売れてしまうあたり、さすがShibuya.lispだと思った。

ただ、前回も直販をしたのだけど、そのときの反省として、販売員をやるとどうも外野っぽくなってしまう。自分としては、普段からSchemeを使っているので、いちLispユーザーとしてもShibuya.lispに参加したい。それで今回はLTに応募した。LTのトピックはなんでもよかったのだけど、具体的にコードが見えるもののほうが面白かろうということで、個人プロジェクトの中で利用したアイデアを切り出して、多値を使って自分の目的にあったパーサーコンビネーターを簡単に作れるよ、という発表をさせてもらった。誤解を招くようにしたわけだけど、本の宣伝広告のほうはネタです。



Gaucheで実行できるコードもgithubにあげておきます。実質的には100行くらいの短いコードです。

k16shikano/tinypeg

肝心の発表では、思わずTeXについて語ってしまったおかげで時間がなくなってしまったけど、本当はスライド26枚目でParsecが出てくるあたりから面白くなるはずだった! でも@khibinoさんに喜んでもらえたので本望です。なおかつフィードバックもたくさんもらえた。ありがとうございます。これについてはそのうちまとめてもうちょっと役に立ちそうな記事を書くつもり。

ちなみに、実際にこのアイデアを実装していたのは去年のいまごろの話。この原理を利用したパーサーコンビネーターを作ったおかげで、本来の開発対象であるTeX modokiがずいぶん前進した。

k16shikano/tex-modoki

TeX modokiはGaucheによるTeXの簡易実装です。TeXのソースをHTML/CSS2.1で出力します。

2010/11/15

Lisperのためのゲーデルの不完全性定理の反証不可能性について考えてみた

Lisperのためのゲーデルの不完全性定理では、(g g)が証明も反証もできないことが示されていない。証明できないほうはいいとして、反証できないことがすぐに理解できなかった。unprovable-pとvalid-proof-pだけで反証不能なことが証明できるの?

ちょっと考えてみた。
(g g)の否定が証明可能だとすると、
(unprovable-p
(eval
((lambda
(x)
`(unprovable-p
(eval
(,x ',x))))
'(lambda
(x)
`(unprovable-p
(eval
(,x ',x)))))))
の否定が証明可能ということなので、
(valid-proof-p
(eval
((lambda
(x)
`(unprovable-p
(eval
(,x ',x))))
'(lambda
(x)
`(unprovable-p
(eval
(,x ',x)))))))
ところがこれは、gの主張である
(unprovable-p (eval (,x ',x))))
と矛盾する。したがって(g g)は反証不可能。

こんな感じだろうか?

で、(g g)の形式的な決定不能性はいいとして、これをもってゲーデルの不完全性定理が証明できた、とは依然としていえないんじゃないだろうか。なぜなら、S式からなる形式的な系について、unprovable-pとvalid-proof-pがあるということ以上に何も情報がないから。それだけの情報では、この系が不完全性定理の前提条件を満たすかどうか確かめようがない。と思う。S式で自然数が作れるのは確かだけど、すべてのS式からなる系では当然無矛盾性を満たさないし。1階の述語論理に対応するS式のセットを再帰的に用意して、そこでunprovable-pとvalid-proof-pを(Lispの意味論を使わず形式的に)定義すればいいのだけど、簡単ではなさそう。(追記:Lispの実装にこだわらなければ、比較的わかりやすく形式化できるようです→howm wiki - 不完全性定理.改。Lispでゲーデルの不完全性定理が証明できる!のようなインパクトはないですが、「Lispを含む再帰的可算な公理系は不完全」の証明になってそう)

だからたぶんチャイティンの元記事は、不完全性定理のフレーバーをLispならS式で表せるぜ、という話であって、それは、不完全性定理のフレーバーを自然言語ならうそつきのパラドクスで表せるぜ、という話と大きく違わないのではないかと思った。

2010/10/25

原稿の形式って最適解があるの?


TeXユーザの集い2010でパネル発表をしました。この1~2年のあいだに手がけたLaTeXによる組版の本もいくつか展示しました。もし「TeXで新規に組んでる本の数」部門があったら、それなりに上位に食い込めたはず。(そういうイベントではありません)

いまうちらは本の制作にTeXを使っている。しかしそれは、「きれいに組めるから」でも「著者の原稿がTeXだから」でもない。もちろん、きれいに間違いのない組版(とくに数式)ができることはTeXの大きなメリットだけれども、うちらはそんなに数式の多い本ばかり作っているわけでもないので、それがTeXを使う必然性にはなっていない。ただ、数式を含む組版のためのツールとしてTeXに欠陥がないことは、いまの制作フローを実現するための必要条件ではある。

そのうえで、うちらの制作フローにとってTeXが満たしている十分条件は、レイアウトや、がんばれば図版までも、すべてテキストで管理できることにある。ここで「管理できる」といっているのは、印刷所にわたす直前まで、汎用のバージョン管理ツールを使って継続的にインテグレーションが可能であるということ。TeXがテキストであることは、多くのTeXユーザーもメリットとして挙げる点だと思うけれど、それが執筆からリリースの全期間にわたる継続的インテグレーションにとってうれしいという主張は、自分たち自身もあまり陽に喧伝してこなかったことなので、TeXユーザーの集い2010ではあらためてパネル発表の1枚目として大書した。



もうひとつ、このパネル発表の1枚目で強調したかったことは、「入力形式は強制しません」ということ。なんというか、原稿からHTMLなりPDFなりを生成するシステムにとって、原稿執筆のための決まり(TeXのスタイル、XMLのスキーマ、既存のWiki記法、独自のWiki記法、などなど)を画一的に定めてしまうのってどうなんでしょう? 出力するものがマニュアルや学会誌論文のような定形のドキュメントなら、標準のスキーマが有意義というか必然の要件になると思う。でも、とくに本のような「一点もの」にとっては、原稿そのものの表現方法、つまり構造の入れ方にも、選択肢というか自由度があったほうがいいんじゃないだろうか。結果として、うちら編集者は、書籍ごとに構造の入れ方が多種多様な原稿を受け入れることになるわけだけれども、そういうのを吸収するのもまた編集者の仕事だと思うわけです。そんなわけで、最近の自分の仕事は、プロジェクトごとにカスタムパーサーを書いて出版用スタイルに合わせたLaTeXファイルを出力し、PDFを自動的に生成できるようにすることから始まる。半分冗談だけど半分本当の話。

そんなわけで、オーム社開発部から「こういう形式にのっとって書くべし」などと強制することはあまりない(例外は、翻訳ものでベースになるデータがある場合)。こちらから原稿の形式を提案する場合は、たいていTeXでさえなく、各プロジェクトに適したXML風の書式を提案している。ここで「XML」という時点で、TeXの人たちからはうげーと言われてしまうのだけど、多くの場合はスキーマも何もない野良XMLとでもいうべきもので、開きタグと閉じタグで文章に構造を与えただけのもの。タグの種類は、プロジェクトにとって適切なものを自由に使ってOK(see. Geekなぺーじ : Scheme手習い - The Little Schemer -)。もちろんTeXでもOK。他の形式でもOK。構造が一意に表現できるテキストであることが最低要件。パーサーもあるとうれしいので、ReVIEWも歓迎です。

もちろん、形式が定まっているほうが執筆しやすいという人も多いはずだし、そのような場合には汎用のスタイルを提案します。たとえばXHTMLとかが候補になると思います。(see. IdeoType

最後に、とってつけたようでなんだけれども、受け入れる形式を問わずに最終的にPDFとして組んで出力できるのはTeXの自由度の高さがあればこそだなあと思った。

2010/09/11

TeXのトイ実装で数式をHTML表示する話



What TeX-modoki is



TeX-modoki is aiming to become a subset of plain TeX implementation. Instead of DVI or PDF, it is intended to generate a plain-old HTML file. Being fully compliant with TeX's macro language, it could support LaTeX or other packages. I wish all the legacy TeX manuscripts around the world someday became readable on any web browser.

TeX-modoki は plain TeX の簡易実装です。出力はDVIやPDFではなくHTMLです。TeXのマクロ言語を実装しているので、LaTeXのような一般的なパッケージを使って書かれた原稿にも原理的には対応できるはず。地球上のあらゆる既存のTeX原稿がブラウザで文字データとして閲覧できるようになればいいな。

Sample Output



For now, you get some mathematical formula in HTML/CSS2.1 from a plain TeX source, though the output needs further refinement.

現状の出力機能はやっつけだけれども、HTML/CSSなので、たいていのブラウザでそれっぽく数式を表示できるようにはなっている。

1. Simple example



Displaying fraction or choice is trivial for TeX but for HTML.

分数など。

(tokenlist->html
(output
(string->tokenlist
"$_nC_{k/2} = {n\\atopwithdelims() {k\\over 2}}$")))


The result is
 
n
 
 
 
C
 
k
 
 
/
 
 
2
 
 
 
 
 
 
 = ( 
n
 
 
 
 
k
 
 
 
2
 
 
 
  
 
 
 
 ) 
 
 
 


2. Example with mathematical symbols



Mathematical symbols can be defined in the same way as plain TeX, except you must specify them with Unicode but TeX's character encoding. You can also compose any original symbol in the TeX manner. In this example, \cdots is defined exactly the same way as the Appendix B of "The TeXbook."

数式で使う記号類は、TeXとまったく同じ方法で、TeXの文字コードの代わりにUnicodeの値を指定しておきます。独自に合成した記号も、やはりTeXと同じようにして定義できます。(実際、以下の例の \cdots は「TeXブック」付録Bの定義そのままです。)

(tokenlist->html
(output
(string->tokenlist
"\\mathchardef\\infty = \"0221e \\mathchardef\\sum = \"103a3 \\mathchardef\\cdotp = \"000b7\
\\def\\cdots{\\mathinner{\\cdotp\\cdotp\\cdotp}}\
The exponential function
$e^x = \\sum_{n=0}^{\\infty} {x^n \\over n!}
= {x^1\\over 1!} + {x^2\\over 2!}+ \\cdots$ . ")))


The result is

The exponential function e
x
 
 
 
 
 = 
 
 
 
 
 
 
Σ
n
 
 
 = 0
 
 
 
 
 
 
  
x
n
 
 
 
 
 
n
 
 
!
 
 
 
  
 
 
 =  
x
1
 
 
 
 
 
1
 
 
!
 
 
 
  
 
 
 +  
x
2
 
 
 
 
 
2
 
 
!
 
 
 
  
 
 
 + ·
 
 
·
 
 
·
 
 
 
 
 
  .


3. Square-root



Square root is hard to display neatly in HTML/CSS without font-stretch. It’s decent if the inner elements fit in a line.

根号は、CSS2.1ではフォントを上下に伸ばせないので、なかなかきれいには表示できません。中身が一行なら、そこそこの見た目にはなります。


(tokenlist->html
(output
(string->tokenlist
"\\def\\sqrt{\\radical\"2221a}
\\mathchardef\\plusminus=\"300b1
Roots of a quadratic equation $ax^2+bx+c=0$ are
$x={-b\\plusminus\\sqrt{b^2 - 4ac} \\over 2a}$.")))


The result is

Roots of a quadratic equation ax
2
 
 
 
 
 + b
 
 
x
 
 
 + c
 
 
 = 0
 
 
  are x
 
 
 =  
 
 
b
 
 
 ±  b
2
 
 
 
 
  4
 
 
a
 
 
c
 
 
 
 
 
  
2
 
 
a
 
 
 
  
 
 
 .


4. More complicated formula



Integral symbol should be nolimit style.

積分記号の添字は上下ではなく横に付くべきですが、これもTeXの定義のままHTMLで表示できます。

(tokenlist->html
(output
(string->tokenlist
"\\mathchardef\\intop=\"1222b\
\\mathchardef\\infty=\"1221e\
\\mathchardef\\pi=\"003c0\
\\mathchardef\\sigma=\"003c3\
\\mathchardef\\mu=\"003bc\
\\def\\sqrt{\\radical\"2221a}\
\\def\\int{\\intop\\nolimits}\
$\\int_{-\\infty}^\\infty \
{1 \\over \\sqrt{2\\pi\\sigma^2}}\
\\hbox{exp}(- {{(x-\\mu)}^2\\over 2\\sigma^2}) dx$")))


The result is

 
 
  
 
 
 
 
  
 
 
 
  
1
 
 
 
 2
 
 
π
 
 
σ
2
 
 
 
 
 
 
 
  
  
 
 
exp
 
 
(
 
 
 
(x
 
 
  μ
 
 
) 
2
 
 
 
 
 
2
 
 
σ
2
 
 
 
 
 
  
 
 
)d
 
 
x
 
 
 

2010/07/02

SLaTeXを使う。Gaucheで。

SLaTeXをGaucheで使いたい。

SLaTeXは、Schemeのコードを装飾するためのtex->texコンバータ。\scheme|...|とか\begin{schemedisplay}...\end{schemedisplay}といった感じでSchemeのコードを(La)TeXの原稿中に書いておくと、その各部分に装飾を施した一時的なtexファイルをSchemeスクリプトで大量に生成してくれる。それをTeXの処理系に渡すところまでやってくれるslatexというシェルスクリプトがついているので、latex foo.texのかわりにslatex foo.texとすればよい。

よいのだけど、実際に使うとなんとなく微妙。一時ファイルが大量にできるのは気持ちが悪いし、添付のスタイルが(少なくとも日本語環境では)あんまりうまくない。プリティプリンタというわけでもなさそうで、インデントの面倒も見てくれない。

あと、現時点ではそのままGaucheで使えない。とりあえず使えるように、次のようなパッチをあてた。これでgosh /(path to scmxlate)/scmxlate.scmのようにすると、Gauche用のslatex.scmと、platexを使うシェルスクリプトができる。
diff -rupN slatex/dialects/dialects-supported.scm myslatex/dialects/dialects-supported.scm
--- slatex/dialects/dialects-supported.scm 2002-11-24 05:06:34.000000000 +0900
+++ myslatex/dialects/dialects-supported.scm 2010-07-02 16:31:41.000000000 +0900
@@ -1,6 +1,7 @@
bigloo
chez
gambit
+gauche
guile
mitscheme
mzscheme
diff -rupN slatex/dialects/gauche-slatex-src.scm myslatex/dialects/gauche-slatex-src.scm
--- slatex/dialects/gauche-slatex-src.scm 1970-01-01 09:00:00.000000000 +0900
+++ myslatex/dialects/gauche-slatex-src.scm 2010-07-02 18:08:41.000000000 +0900
@@ -0,0 +1,12 @@
+(define getenv sys-getenv)
+
+(define *scheme-version*
+ (string-append "Gauche " (gauche-version)))
+
+(define void
+ (lambda ()
+ (if #f #f)))
+
+(scmxlate-postprocess
+ (define *scheme-command-name* "gosh")
+ (load "./dialects/make-echo-script.scm"))
diff -rupN slatex/dialects/make-echo-script.scm myslatex/dialects/make-echo-script.scm
--- slatex/dialects/make-echo-script.scm 2002-03-25 01:26:22.000000000 +0900
+++ myslatex/dialects/make-echo-script.scm 2010-07-02 17:13:53.000000000 +0900
@@ -3,12 +3,16 @@
(rename-file "my-slatex-src.scm" "slatex.scm")
(delete-file "slatex")
(delete-file "callsla.scm"))
+ ((gauche)
+ (sys-rename "my-slatex-src.scm" "slatex.scm")
+ (if (file-exists? "slatex") (sys-remove "slatex"))
+ (if (file-exists? "callsla.scm") (sys-remove "callsla.scm")))
(else
(system "mv my-slatex-src.scm slatex.scm")
(system "rm -f slatex callsla.scm")))


-(load "dialects/make-callsla.scm")
+(load "./dialects/make-callsla.scm")

(call-with-output-file "slatex"
(lambda (o)
@@ -18,11 +22,7 @@
(display ")" o) (newline o)
(display ";check pathname above is correct for you" o)
(newline o)
- (display "(slatex" o)
- (display (if (eqv? *dialect* 'bigloo)
- "$$"
- "::") o)
- (display "process-main-tex-file \"'$1'\")" o)
+ (display "(process-main-tex-file \"'$1'\")" o)
(if (eqv? *dialect* 'scsh)
(begin
(newline o)
@@ -32,10 +32,11 @@
(newline o)
(display "if test -f pltexchk.jnk" o) (newline o)
(display "then tex $1; rm pltexchk.jnk" o) (newline o)
- (display "else latex $1" o) (newline o)
+ (display "else platex $1" o) (newline o)
(display "fi" o) (newline o)))

(case *dialect*
((scsh) (run (chmod "+x" slatex)))
+ ((gauche) (sys-chmod "slatex" 484))
(else (system "chmod +x slatex")))

diff -rupN slatex/scmxlate-slatex-src.scm myslatex/scmxlate-slatex-src.scm
--- slatex/scmxlate-slatex-src.scm 2009-09-29 08:28:56.000000000 +0900
+++ myslatex/scmxlate-slatex-src.scm 2010-07-02 17:07:17.000000000 +0900
@@ -16,10 +16,10 @@

(scmxlate-eval
;on denali
- ;(define *target-file* "/home/dorai/.www/slatex/slatex.scm")
+ (define *target-file* "/home/kshikano/src/slatex/slatex.scm")

;on mac
- (define *target-file* "/Users/doraisitaram/public_html/slatex/slatex.scm")
+ ;(define *target-file* "/Users/doraisitaram/public_html/slatex/slatex.scm")
)

;You may define slatex::*texinputs* here. Eg,
@@ -30,7 +30,7 @@
;(define slatex::*texinputs*
;"/home/dorai/tex:/usr/local/lib/tex/macros") ;in Unix

-;(define slatex::*texinputs* (getenv "TEXINPUTS"))
+(define slatex::*texinputs* (sys-getenv "TEXINPUTS"))

;Unfortunately, that last one is not really as convenient as
;it seems, even if your Scheme has a getenv procedure.

2010/06/24

The WYSIWYG Conundrum: The Solid Cloud � An American Editor

The WYSIWYG Conundrum: The Solid Cloud � An American Editor:
"Success is much more than the number of downloads of free or 99� ebooks, especially when there is no way to know how many of those downloads actually were read or well thought of. Instead, success is having readers clamor for your books, talk about your books, express a willingness to pay a higher price for your books — all things that a professional editorial eye can help an author achieve by preventing the kinds of mistakes that turn readers away."


「(本の)成功とは、タダだったり100円だったりするebookがたくさんダウンロードされることじゃない。そのうち何冊が読まれたか確かめようがないなら、なおさらだ。成功というのは、そんなことではなく、読者がその本を話題にしてくれて、もっとお金を払いたいと思ってくれることにある。その本を読んだ人をがっかりさせるようなミスを防ぐことにこそ、プロの編集者の役割がある。」

これ以上なにも付け足すことがない。

2010/06/03

Emacs上での正規表現による検索で結果をハイライトしっぱなしにする

たまーに、「emacs」「検索」「ハイライト」で過去のエントリを見てもらっているようなのですが、あれはバグっているのです。バグっているというか、フォントロックの仕組みをちゃんと理解していなかったので、実行するとメジャーモードの色づけを葬ってしまう。

いまは改良してこうなっています。(Emacs 22.2.1)
(defun keep-highlight-regexp (re)
(interactive "sRegexp: \n")
(make-face 'my-highlight-face)
(set-face-foreground 'my-highlight-face "black")
(set-face-background 'my-highlight-face "yellow")
(defvar my-highlight-face 'my-highlight-face)
(setq font-lock-set-defaults nil)
(font-lock-set-defaults)
(font-lock-add-keywords 'nil (list (list re 0 my-highlight-face t)))
(font-lock-fontify-buffer))

(defun cancel-highlight-regexp ()
(interactive)
(setq font-lock-set-defaults nil)
(font-lock-set-defaults)
(font-lock-fontify-buffer))

(global-set-key "\C-f" 'keep-highlight-regexp)
(global-set-key "\C-d" 'cancel-highlight-regexp)
[Ctrl]-[f]で検索開始、[Ctrl]-[d]でハイライト解除。それぞれ、自分では通常のキーバインドとして使ってないので、グローバルに設定しています。

2010/03/26

稼働中のマシンのHDDから、VMware Player用の仮想マシンを作る

稼働中の物理マシンの HDD を、そっくり仮想イメージに変換して、 VMware Player で再生できるようにしたい。手順としてはこれだけなんだけど……
  1. 対象の HDD をダンプする(partimage を使う)
  2. VMware 用の仮想ディスクを空っぽの状態で作る(QEMU を使う)
  3. 2.の空っぽ仮想ディスクに領域を作る(fdisk を使う)
  4. 1.のダンプを、3.の領域へとリストアする(partimage を使う)
それなりに広大な作業スペースが必要だし、個々の作業に時間がかかるので(待ち時間にこんな記事がかけるくらい)、次回以降はできるだけ要領よく済ませたい。だから自分用にメモ。もちろん無保証です。

用意するもの。
  • 作業場
    ここでは Windows マシンを使う。対象の HDD 上で動いてなくて、VMware と QEMU が使えて、でかいディスク容量があるマシンなら、何でもいいと思う。

  • 起動環境
    ここでは Knoppix の iso イメージを使う。VMware 用の仮想イメージ以外で、fdisk と partimage が使える環境を VMware Player から起動できるものなら、何でもいいと思う。

  • QEMU
    空っぽの仮想ディスクを作るのに使う。ここでは QEMU on Windows の qemu-img コマンドを使う。


実際の作業の流れ。
  1. partimage で対象の HDD をダンプして、作業場からファイルとして見える場所にイメージファイル(群)として保管する。

  2. Windows のコマンドプロンプトで、qemu-img コマンドを使って空っぽの VMware 用仮想ディスクを作る。対象の HDD と同じサイズで vmdk 形式にする。対象が 120Gバイトならこんな具合。
    > qemu-img create -f vmdk hokansaki.vmdk 120G
    これでhokansaki.vmdkという仮想ディスクができる。

  3. 空っぽの仮想ディスクをフォーマットしたいのだけど、空っぽなので、当然のことながら VMware Player で仮想マシンを起動することができない。そこで、何かしら起動環境が必要になる。空っぽの物理ディスクに OS をインストールするときと同じ理屈ですね。つまり、BIOSチップ を CD/DVDブートにするのと同じ要領で、VMware Player の BIOS を CD/DVD ブートに設定し、ROM ドライブに Knoppix のディスクを入れて Player を再起動すればいい。VMware Player の起動時に F2 を押せば BIOS 画面に入れる。
    ただ、せっかく仮想マシンなんだから、わざわざ物理的な起動ディスクを使う必要もない。作業場の HDD 上に Knoppix の iso を置いておいて、それを Player の起動時に読むようにしたほうが手っ取り早いというもの。つまり、こんな vmx ファイルで仮想マシンを読み込めばいい。(この例では Windows の Fドライブ以下に Knoppix 5.1.1 の iso が置いてある。guestOS の一覧はこのへんを参考に。ide1 の deviceType を cdrom-image としているため、この場合も BIOS で CD/DVD ブートに設定する必要あり)
    .encoding                = "Shift_JIS"
    config.version = "8"
    virtualHW.version = "4"
    memsize = "512"

    ide0:0.present = "TRUE"
    ide0:0.fileName = "hokansaki.vmdk"
    ide0:0.mode = "persistent"
    ide0:0.deviceType = "disk"

    ide1:0.present = "TRUE"
    ide1:0.fileName = "F:\knoppix-iso\KNX5.1.1J_AC.200.iso"
    ide1:0.deviceType = "cdrom-image"

    ethernet0.present = "TRUE"
    ethernet0.connectionType = "nat"

    usb.present = "TRUE"

    displayName = "hokan saki"
    guestOS = "other26xlinux"
    nvram = "hokansaki.nvram"
    この構成で仮想マシンを起動する前に、仮想マシンから作業場(具体的には、ダンプしたイメージファイルの置き場所)が見えるようにする設定を忘れずに。VMware Player のバージョン3 には、「仮想マシン設定の編集」という GUI が用意されているので、そこから作業場のハードディスクを追加するだけだった。

  4. 空っぽの仮想ディスクを fdisk でフォーマット。上記の構成なら、くだんの空っぽの仮想ディスクは /dev/hda として認識されているはずなので、
    $ sudo fdisk /dev/hda
  5. partimage で、ダンプした対象 HDD のイメージファイルを /dev/hda1 にリストア。partimage を実行する前に、対象 HDD のイメージファイルの置き場所をマウントしておくこと。イーサネットだと、たぶんすごい時間がかかる。ついててよかった eSATA。

  6. ブートローダの修復。GRUB ならこんな感じ。
    $ sudo mount /dev/hda1 /media/hda1
    $ sudo chroot /media/hda1
    $ grub-install /dev/hda
    (マウントのときは Knoppix の UI を使わず、コンソールから mount コマンドで実行すること(Knoppix についてくる /etc/fstab の設定のせいで読み取り専用になってしまうため)
    あと、fdiskで領域(この場合は/dev/hda)をブート可能に設定しておくこと。

  7. BIOS の CD/DVD ブートを解除すれば、物理マシンで稼動していたシステムがそっくり VMware Player 上で起動するようになるはず。

2010/03/22

TeXでFizzBuzz

shibuya.lisp の テクニカルトーク#5 で、はやみずさんが「LaTeXでFizzBuzzを書く気になるか?」的な話を一瞬されたので反応しておく。そう言われて始めて書いてみようかと思うくらいだから、「書く気になるか?」という問いに対する答えは否定的なものであっていると思う。
\newcount\a \newcount\b \newcount\c
\newcount\n \newcount\i
\newif\ifdivisable

\def\fizzbuzz#1{%
\n=#1 \i=1
\loop \ifnum\i<\n
\printffizzbuzz
\advance \i by 1
\repeat}

\def\printffizzbuzz{%
\testdivisable{\i}{15} \ifdivisable fizzbuzz\par \fi
\testdivisable{\i}{3} \ifdivisable fizz\par \fi
\testdivisable{\i}{5} \ifdivisable buzz\par \fi
\ifdivisable\else \number \i\par \fi}

\def\printffizzbuzz{%
\testdivisable{\i}{15} \ifdivisable fizzbuzz \else
\testdivisable{\i}{3} \ifdivisable fizz \else
\testdivisable{\i}{5} \ifdivisable buzz \else
\number \i \fi\fi\fi \par}

\def\testdivisable#1#2{%
\a=#1 \b=#2 \c=#1
\divide \a by \b
\multiply \a by \b
\advance \c by -\a
\ifnum\c=0 \divisabletrue \else \divisablefalse \fi}

\fizzbuzz{30}

\vfill
\eject
\end
(2010.3.23 rudolphさんの指摘を受けて\printffizzbuzzを修正)

LaTeXじゃなくて素のTeX。これを fizzbuzz.tex のような名前で保存して tex fizzbuzz と実行すれば dvi ができる。

整数の計算には、\newcountコマンドでグローバルなレジスタをいくつか用意して、これを使う。これは文字通りのレジスタ計算で、レジスタに入っている値をadvancedivideといったコマンドを使って書き換えながら計算を進めていく。

リストやシーケンスのような気が利いたデータ構造は当然存在しないので、ループを使ってFizzBuzzするしかない。素のTeXでは、\loop... \repeatという構文が用意されていて、これでループが書ける。

あとトリッキーなのは、\newifというマクロを使って\ifdivisableという特定用途のための条件文を用意するところだろう。まあ、なんていうか、このへんはイディオムなので深く考えない。最初に見るとぎょっとするし、もっとうまい記述方法がないか考えても見るけど、結局こういうイディオムを使って書くのがいちばんしっくりくることに気がつくものだ。

2010/03/04

pLaTeX+dvipdfmxで基本じゃないOTFフォントを使う

ヨドバシカメラのソフト売り場で大枚はたいてOTFフォントを買ったならば、とりあえずpLaTeXでも気軽に使いたい、それもWordくらい気軽に、という話。

具体的には、「本文のゴシックはヒラギノ基本書体の角ゴW3でいいんだけど、強調したいところで角ゴW4を使いたい。ヒラギノ角ゴW4は買ってきた。原稿で\hirakakufour{モナド}って使いたい!」という状況がままあって、場当たり的な試行錯誤で「とりあえず」期待どおりの結果は得られているが、なにぶん試行錯誤でたどりついた方法なので正解かどうかはわかりません、つっこみ求む、という話。

TeXにおけるフォントとは何か、を整理する必要があるので、肝心の手順にいたるまでの説明が長くなります。まずは基礎知識。
買ってきたフォントの実体は .otf ファイルだけど、TeXが必要としているのは .tfm というファイルである。(.vf ファイルもあるけど、ややこしいので省略)
TeXのソースで指定するのは、あくまでも .tfm ファイルの名前である。.tfm ファイルには、TeXがそのフォントの文字を配置するときの幅とか前後の文字とのアキといった数値情報(メトリック)だけが入っている。これはバイナリファイルで、極端にいうとフォントの実体とぜんぜん関係ない値であっても、とにかく数値情報が決まったフォーマットでエンコードされていればいい。TeX のコマンド(platex とか)にとっては、フォントの実体なんて知ったことじゃないのである。TeX の仕事は、各ページへの要素の配置を決めるアルゴリズムを駆使して、その結果を dvi ファイルとして埋め込むだけ。それにはフォントのグリフを並べるのに必要な数値情報だけ知っていればいい。(この「なんでも数値にしてアルゴリズムさえ考え抜けばいいじゃん」という方針をクヌーシズムと称したい。)
TeX は、「この要素には○○というフォントを使って!」という情報だけをdviファイルに書き出す。
○○は、この場合は .tmf ファイルの名前。
フォントの実体は、dviファイルを解釈するDVIウェアと呼ばれるソフトウェアが扱う。
dvipdfmx や dviout といったDVIウェアが、フォントの実体である .otf ファイルを扱うので、彼らに .tfm ファイルと .otf ファイルとの対応付けを教えなければならない。

次に、ここでまとめる手順の前提条件。
ようやく手順。
  1. 何はともあれヒラギノ角ゴW4用の .tfm ファイルが必要。ここが肝要なんだろうけど、まあ角ゴW4のメトリックは角ゴW3とそんなにかわらないはずだよね、と仮定して、齋藤さんのOTFパッケージの nmlgothb-h.tfm および nmlgothb-h.tfm をそっくりコピーして使わせていただく。このへんが「とりあえず」なゆえん。(もしかするとヒラギノ角ゴW8用の tfm のほうが適切かも。)
    $ cd (TEXMF)/fonts/tfm/ptex/otf/otf  # パスとコピー先は各自でてきとうに
    $ cp nmlgothb-h.tfm nmlgothlb-h.tfm
    $ cp nmlgothb-v.tfm nmlgothlb-v.tfm
    (本来は、メトリックをS式っぽいもので記述したPLファイルというのを作って、それをpltotfというツールで変換してtfmファイルを作るらしいが、自分でやったことはない。OTFパッケージのうれしさは、ヒラギノ基本6書体に対してこれらをすべてお膳立てしてくれることにある。)
  2. dvipdfmxに、.tfm ファイルと .otf ファイルの対応付けを教える。これは、次のような map ファイルを書いて、dvipdfmx の実行時に -f オプションで指定すればよい。
    $ cat hirakakufour.map
    nmlgothlb-h H HiraKaku-W4.otf
    nmlgothlb-v V HiraKaku-W4.otf
  3. フォントの実体 HiraKaku-W4.otf を、dvipdfmx から見える場所(/usr/share/texmf/dvipdfmx/fonts/ とか)におく。

これで、たとえばこんな風にすれば、ヒラギノ角ゴW4を \hirakakufour コマンドで使えるようになる。
\DeclareFontShape{JY1}{gt}{lb}{n}{<-> nmlgothlb-h}{}
\DeclareFontShape{JT1}{gt}{lb}{n}{<-> nmlgothlb-v}{}
\def\hirakakufour#1{%
{\usefont{JY1}{gt}{lb}{n}#1}}