METAFONTでUEC校章
この記事はTeX & LaTeX Advent Calendar 2013の12/7担当分です. < 12/6 は CardinalXaroさん | | 12/8 はkuroky_plusさん>
放置ブログにAdvent Calendarの火を.放置している間に,TUG2013への参加なんかがあった.参加者は感想を投稿している人も多いのだけれど,私はTeX芸人っぽいことがしたいので,それはまた別の機会に.
しかし,今回はTeXネタでなくMETAFONTネタ.電気通信大学校章のMETAFONT化をした話*1 *2.
TeXやLaTeXを知っていても,「METAFONT? なにそれ,美味しいの?」なんて人もいるかもしれないので,一応説明しておくと,METAFONTはTeXで使用するフォントを作成するための言語である.これの記述とTeXやLaTeXで使用するまでの流れを説明をみていく.
まずは,METAFONTソース*3から(ファイル名をmyueclogo.mfとする).今回のUEC校章のものはこんな感じ.
mode_setup; em#:= 48pt#; cap:=48pt#; beginchar(65,48pt#,48pt#,0pt#); path p; gakusc# = 1/24w; ressc# = 4pt#; pickup pencircle scaled ressc#; %exact res %p := ((w-sind(6*90)*w)/2,(h-cosd(5*90)*h)/2) for k=1 upto n: ... ((w-sind(6*(360/n*k+90))*w)/2,(h-cosd(5*(360/n*k+90))*h)/2) endfor; p:= (0,h){curl 0}...{right}(7/8w,0)...{up}(w,1/8h)..tension 1.3 ..{left}(1/4w,h)...{down}(0,3/4h)..tension 1.6 ..(1/2w,0)..tension 1.6 ..{up}(w,3/4h)...{left}(3/4w,h)..tension 1.3 ..{down}(0,1/8h)...{right}(1/8w,0)...{curl 0}(w,h); draw p; pickup pencircle scaled gakusc#; %DAI-GAKU z1 = (1/2w,7/8h); x2 = x1; y1-y2 = 1/16h; y3 = y4 = y5 = y6 = y2; x3 = 1/4w; x6 = 3/4w; x3-x4 = x4-x5 = x5-x6; penpos7(gakusc#,90); penpos8(gakusc#,90); penpos9(gakusc#,90); penpos10(gakusc#,90); y7 = y8 = y9 = y10; x7 =x3; x8 =x4; x9 =x5; x10 =x6; y7 = 11/16w; penpos11(gakusc#,0);penpos12(gakusc#,0); z11 =z8l; z12 = z9l; penpos14(gakusc#,0);penpos15(gakusc#,0); penpos18(gakusc#,0);penpos19(gakusc#,0); penpos17(gakusc#,90); penpos20(gakusc#,90); x13 = x7; x14 = x8; x15 = x9; x16 = x10; y13 = y14 = y15 = y16; x17 = x7; x18 = x8; x19 = x9; x20 = x10; y17r = y18 = y19 = y20r; y7l-y13 = y13-y17r; y20 = 1/2h; penpos21(gakusc#,90); penpos22(gakusc#,90); z21 = z14r; z22 = z15l; penpos23(gakusc#,90); penpos24(gakusc#,90); z23r = z17l; z24r = z20l; y25 = y26 = 5/16h; x25 = x7; x26 = x10; y27= y28 = y29 = y30 = y23l-gakusc#; x28 = x18l; x29 = x19r; x28-x27 = x27-x23; x24-x30 =x30-x29; y31 = y32; x31 = x28; x32 =x29; y23 - y28r = y31-y33; y33 = y34 = y25; x33 = x27; x34 = x30; x35 = x36 = 1/2w; y35 = y33; y36 = y37 = 3/16h; x37 = x33 + gakusc#; erase fill z3---z25---z26---z6---cycle; erase draw z3---(x7,y7+gakusc#) withpen pencircle scaled 2gakusc#; erase draw z6---(x10,y10+gakusc#) withpen pencircle scaled 2gakusc#; erase draw z3---z6 withpen pencircle scaled 2gakusc#; draw z1---z2; draw z3---z6; draw z3---(x7,y7+gakusc#);draw z4---(x8,y8+gakusc#); draw z5---(x9,y9+gakusc#);draw z6---(x10,y10+gakusc#); erase draw z7l---z11l withpen pencircle scaled 2gakusc#; erase draw z12r---z10l withpen pencircle scaled 2gakusc#; erase draw z7l---z17r withpen pencircle scaled 2gakusc#; erase draw z10l---z20r withpen pencircle scaled 2gakusc#; draw z7l---z11l; draw z12r---z10l; draw z13--z14l; draw z15r---z16; draw z17r---z18l; draw z19r---z20r; draw z7l---z17r; draw z10l---z20r; draw z11r---z22r; draw z21r---z12l; draw z21l---z19l; draw z18r---z22l; erase draw z25---z23---z24---z26 withpen pencircle scaled 2gakusc#; erase draw z27---z33---z34---z30 withpen pencircle scaled 2gakusc#; erase draw (x35,y35-1/2gakusc#)---z36---z37 withpen pencircle scaled 2gakusc#; draw z25---z23---z24---z26; draw z27---z33---z34---z30; draw (x35,y35-1/2gakusc#)---z36---z37; penpos28(1/2gakusc#,90); penpos29(1/2gakusc#,90); pickup pencircle xscaled gakusc# yscaled 1/2gakusc#; draw z28r---z29r---z32---z31---cycle; %penlabels(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); %penlabels(21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37); endchar;
なげぇ.ネタなので説明はほどほどにする.
最初のmode_setupはおまじないみたいなもので,これによって,解像度の設定やら何やらの「モード」に対する設定を行っている.その下のemやcapはフォントのパラメータの設定である.
次のbeginchar(c, w, h, d);からendchar;までがひとつの文字を定義している部分.cが文字コードで,wは幅,hは高さ,dは深さを表していて,この値はTeXで組版するときに使用される.長さに#が付いているのは,「実際の」と言う意味で,解像度に影響されない長さであることを示している.ちなみに,これはTeXで使われる大きさであって,実際の字形がこの幅に収まっていることは保証されない.
幾つか変数を宣言した後,リサジュー図形の描画に入る.「p:=...」の部分がパスの定義で「draw p;」で描画される.記法はTikZとかとも近いので読みやすいのではないだろうか?METAFONTのいいところは,曲線を「..」や「...」で記述できるところである.このとき,METAFONTは空気を読んで滑らかに点と点を結んでくれる.
pのパス定義の部分にコメントアウトがあるが,これは実際に計算させて本当のリサジューを描くものである.METAFONTには三角関数を計算できたりパス定義中にforループを記述できたり*4するので,実は簡単にパラメトリック曲線を記述できる.実際に書いてみたところ,「電通大のリサジューは実際のリサジューではない」というどうでもよい事実に気がついたため,書きなおした歴史がある.
その後は,「大学」と書いてある部分の描画に入る.各点の位置を定義->適当につないで描画を繰り返しているのだが,ポイントはMETAFONTの「=」は「代入」ではなく,「等式」という事実である.実際「y1-y2 = 1/16h;」のような式が記述できる.C語族などに慣れた人にはわかりにくいかもしれない.METAFONTは,与えられた連立方程式を解いて,点の位置を計算してくれるという宣言的に記述が可能な良い言語である.
これを,LaTeXで使うには次のようにすれば良い.まず,TeXで組版するために必要なTFMファイルを作成する.方法は,
mktextfm myueclogo
とすればよい.LaTeX文書では
\documentclass{article} \font\uec=myueclogo \begin{document} {\uec A}電気通信大学校章 \end{document}
ちなみに,この方法はLaTeXのフォント管理を突き抜けてTeXのフォント指定法を使うというダーティな方法なので,だれかLaTeX用に仕立て直してもいいのよ?
コミュニケーションマークは一応用意してるけど,出来が良くない.
私はこれを使って,レポートの表紙を自作して提出していた.使いたければhttps://bitbucket.org/hak7a3/myueclogo:titl=ここに置いておくので,煮るなり焼くなりするといいと思う.*5
ちなみに,やろうと思っていたTeXネタは,実はTikZで遊ぶものだったのだが,間に合わなかった……(まだ空きが合った気がしますね,Advent Calendar)
TeXと異世界の交わり
研究室のゼミでやった内容の加筆版.名称などはでっち上げなので注意.
はじめに
LISP on TeXがCTANに登録されてから,そろそろ一週間が経つ.TeXLiveやMikTeXに取り込まれるなどもした.更に,CTANのTopicsに「exec-foreign」が追加され,そこにlisp-on-texが配置された*1.しかし,これ以外にも,旧来からTeXと他の言語を組み合わせる試みは多数行われてきた.そこで,ここではそれらの紹介を行う.
まず,TeXと他の言語を組み合わせる手法は,TeXエンジンの中で解決するものと外部の処理系に頼るものに大別することができる*2.それぞれについて説明する.
TeXエンジンのみの中で解決する手法
これは,TeXエンジンやマクロの機能を用いて,TeXとして閉じたまま他の言語と交じり合う方式である.この手法の大きな特徴は,外部環境への依存性が少ないこと.そもそも外界との接触がないから当然だが,複数のOSで動くことを想定する際に,この性質は役に立つ.この手法は,インタプリタ型とエンジン型に区別できる.
Load to CTAN(CTANに載るまで)
祝 LISP on TeXのCTAN入り
全国のTeX Liveをお使いの皆さん.ようこそ,LISP on TeXへ.
というわけで,LISP on TeXがCTAN*1に登録されました.TeX Liveで使えることは,
@zr_tex8r: あわわわわわ、#texlive を update したら lisp-on-tex とかいう怖そうなパッケージが乗り込んできた。 #TeX
2013-03-05 22:58:24 via web
@PowerPC7450: > sudo tlmgr update --all...[6/7, 00:14/00:14] auto-install: lisp-on-tex (29291) [108k] ... done!?
CTANへの道標
で,ココからが本題.CTANに成果物をアップロードするまでの流れを,ここに残していきます.
1. 成果物を作る
最重要.まずは,Happy TeXingすることから始める.
このとき,READMEを作ることを忘れないこと.READMEには,選択したライセンスに関する注釈を忘れない*2.READMEが日本語のものが見受けられたけど,私はつたない英語で書きました……
参考 : http://www.ctan.org/upload/
READMEはpdf形式でも構わないらしいが,その時は<<パッケージ名>>.pdfもしくは<<パッケージ名>>-doc.pdfにすべし.manual.pdfはやめろとここにある.
LaTeXのパッケージの場合,.dtxファイルや.insファイルを作るのが一般的とされているみたいだが,別に作らなくても通ります..styとかで平気.
2. アップロード形式に固める.
作成が終わったら,固めてCTAN teamへ送ります.ディレクトリ構成は,TDS*3がわかる人はそのように固めて送るといいらしい.わからなければ単一のディレクトリにまとめておけばOK.圧縮形式はzipまたはtar.gz.ただし,TDSの形式で送るときはtds.zip.
LISP on TeX におけるパーサのフックな話
生きてます(唐突に).
LISP on TeX更新情報
最近,修士論文も無事に提出できたので,LISP on TeXに機能拡張とかしてみた.
パーサのフック機能.
LISP on TeXの整数型,dimen型,およびskip型にリテラルには,それぞれ決まったプレフィクスをつけることにしている.
しかし,ユーザが新しい型を追加できない*1という問題があった.また,これ以上型を増やすと適当なプレフィクスがなくなってしまうという問題も出てきた.
そこで,汎用的にパーサを操作できる構文を追加することとした.構文は,次で示される.
+{mod::foo}
modはモジュール名,fooはモジュールmodによってパースするトークン列である.
例えば,lisp-mod-stdout.styでは,stdoutモジュールを提供している.
\documentclass{article} \usepackage{lisp} \usepackage{lisp-mod-stdout} \begin{document} \lispinterpl{+{stdout::orz}} \end{document}
と書いてタイプセットすると,
$ latex hatena.tex This is pdfTeX, Version 3.1415926-2.5-1.40.13 (TeX Live 2012/W32TeX) restricted \write18 enabled. entering extended mode (./hatena.tex LaTeX2e <2011/06/27> Babel <v3.8m> and hyphenation patterns for english, dumylang, nohyphenation, ge rman-x-2012-05-30, ngerman-x-2012-05-30, afrikaans, ancientgreek, ibycus, arabi c, armenian, basque, bulgarian, catalan, pinyin, coptic, croatian, czech, danis h, dutch, ukenglish, usenglishmax, esperanto, estonian, ethiopic, farsi, finnis h, french, friulan, galician, german, ngerman, swissgerman, monogreek, greek, h ungarian, icelandic, assamese, bengali, gujarati, hindi, kannada, malayalam, ma rathi, oriya, panjabi, tamil, telugu, indonesian, interlingua, irish, italian, kurmanji, latin, latvian, lithuanian, mongolian, mongolianlmc, bokmal, nynorsk, polish, portuguese, romanian, romansh, russian, sanskrit, serbian, serbianc, s lovak, slovenian, spanish, swedish, turkish, turkmen, ukrainian, uppersorbian, welsh, loaded. (i:/W32TeX/share/texmf/tex/latex/base/article.cls Document Class: article 2007/10/19 v1.4h Standard LaTeX document class (i:/W32TeX/share/texmf/tex/latex/base/size10.clo)) (./lisp.sty (./lisp-read.tex ) (./lisp-arith.tex) (./lisp-string.tex) (./lisp-latexutil.tex) (./lisp-prim.tex)) (./lisp-mod-stdout.sty) No file hatena.aux. orz (./hatena.aux) ) No pages of output. Transcript written on hatena.log. [1]+ Done sublime_text.exe hatena.tex
コンソールにorzが表示される*2.
また,現在のLISP on TeXでは,fpnumモジュールをlisp-mod-fpnum.styで提供している.これは,TeXのdimenを使って固定小数点数計算を行うためのモジュールで,
+{fpnum::1.0}
と記述すると,内部でfpnum型の1.0として扱われるオブジェクトを生成する.この型のオブジェクトに関する加算,減算,乗算および比較演算もlisp-mod-fpnum.styは提供している.
これを使って,マンデルブロ集合に再挑戦した.前回は,TeX on LaTeX なあれに,実行時間,精度共に惨敗したが,fpnumがなかっただけで,今ならいけるはず!
ソースはこんな感じ
\documentclass{article} \usepackage[dvipdfm,a3paper,margin=1pt,landscape]{geometry} \newcount\mlength \newcount\cstate \newdimen\mandelunit \mandelunit=0.5pt \def\w{% \ifnum\cstate=1 \global\advance\mlength1 \else \vrule width \mlength\mandelunit height \mandelunit depth 0pt \global\mlength1 \fi \global\cstate1} \def\b{% \ifnum\cstate=-1 \global\advance\mlength1 \else \hspace*{\mlength\mandelunit}\global\mlength1 \fi \global\cstate-1} \def\r{% \ifnum\cstate=1\hspace*{\mlength\mandelunit}\else\vrule width \mlength\mandelunit height \mandelunit depth 0pt \fi \global\cstate0 \global\mlength0} \usepackage{lisp} \usepackage{lisp-mod-stdout} \usepackage{lisp-mod-fpnum} \lispinterpl{% (\define \maxloop :20) (\define \scale +{fpnum::0.002}) (\define \isMandell (\lambda (\a \b \k \x \y) (\lispif (\< \maxloop \k) /t (\lispif (\fplt +{fpnum::4.0} (\fpplus (\fpmul \x \x) (\fpmul \y \y))) /f (\isMandell \a \b (\+ \k :1) (\fpplus \a (\fpmul \x \x) (\fpminus (\fpmul \y \y))) (\fpplus \b (\fpmul +{fpnum::2.0} \x \y))))))) (\define \drawMandell (\lambda (\a \b) (\begin (\lispif (\isMandell \a \b :0 +{fpnum::0} +{fpnum::0}) (\texprint '\b') (\texprint '\w')) (\immediatewrite)))) (\define \loopMandell (\lambda (\a \b) (\lispif (\fplt \b +{fpnum::-1.0}) () (\begin (\drawMandell \a \b) (\lispif (\fplt +{fpnum::0.5} \a) (\begin (\texprint '\r\\') (\immediatewrite) (\loopMandell +{fpnum::-1.5} (\fpminus \b \scale))) (\loopMandell (\fpplus \a \scale) \b)))))) } \begin{document} \noindent \leavevmode\baselineskip=\mandelunit \lispinterpl{(\loopMandell +{fpnum::-1.5} +{fpnum::1.0})} \end{document}
これで勝つる.実行結果はこんな感じ.
実行時間はというと……
real 274m44.480s user 0m0.000s sys 0m0.031s
惨敗でしたー*3.
追記
前回と同ループ回数,同メッシュでやったら37分だった.また,前回のメッシュ + ループ制限は今回のものでやったら10分で計算終了.
評価ルーチンのブラッシュアップ
これは拡張じゃないけども一応.\if系トークンの使用回数を減らしたし,若干早くなった+軽くなった,はず……
アドベントカレンダー二日目 ― \newif\ifnextyear \ifnextyeartrue
TeX & LaTeX Advent Calendar TeX で騒げ、TeX で笑え
この記事は,12/2 担当分です.< 12/1 は ZR さん | | 12/3 はk16.shikano さん>
周りは \expandafter を叫んだりする記事みたいなので,私はマイナーな(?)プリミティブである \aftergroup と LISP on TeX での利用法を一例としてあげようと思う.
そもそも \aftergroup ってなによ
黄色(LaTeX2e マクロ & プラス プログラミング基礎解説)*1にも載っていない*2が,TeX の強力なトークン展開の制御機能ひとつである.\aftergroup は現在のグループが終わった地点での動作をフックできる.使い方は,
\aftergroup<トークン>
で,トークンがグループ終了時に挿入される.複数指定したときは,指定した順序でそのすべてのトークンが挿入される.
これだけでは直感に欠けるので,コード例を.
{\aftergroup\show}\expandafter
実行結果は次のようになる.
$ tex test.tex This is TeX, Version 3.1415926 (TeX Live 2012/dev/W32TeX) encTeX v. Jun. 2004, reencoding enabled. (./test.tex > \expandafter=\expandafter. l.1 {\aftergroup\show}\expandafter ? x No pages of output. Transcript written on test.log.
グループの終わり,すなわち \expandafter の前に \show が挿入され,\show\expandafter となりこのような表示がなされる.
で,なにに使うの?
私も最初はよくわからなかった.しかし,TeX で言語処理系を実装するよくある状況*3では非常に有用なことがわかった.末尾呼び出しの最適化である.
末尾呼び出しの最適化とは?
末尾呼び出しの最適化とは,再帰呼び出しを安心してループのように使うために必要な最適化技術である.次の Scheme プログラムを例にして説明する.
(define (fact n acc) (if (= n 0) acc (fact (- n 1) (* acc n)))) (fact 10 1)
階乗を計算する末尾再帰になっているプログラムである.最適化しないナイーブな実装では,関数の呼び出しスタックは
[(fact 10 1)][(fact 9 10)][(fact 8 90)][(fact 7 720)].........[(fact 0 3628800)]
となる.ここで fact 関数の末尾での動作は,呼び出した関数の結果を返すだけというものであり,わざわざスタックを消費する必要がない.そんなときを検知して,スタックを潰すのが末尾呼び出しの最適化である.
で,\aftergroup との関連性は?
TeX でインタプリタを作成する場合,この呼び出しスタックをグループで表現するのがよくあるデザインである.グループのネストには限界があるので,末尾呼び出しの最適化は重要な課題となる*4.ここで,\aftergroup である.\aftergroup で「次にやるべき計算」*5をグループが終わったあとに挿入させるようにし,現在のグループを閉じてしまえば,不必要な要素をたたんで,新たな要素をスタックに積むという動作を実現することができる.
具体的に,LISP on Tex では \@@tco という名前のトークンに「次にやるべき計算」を束縛し,\aftergroup\@@tco とすることで末尾呼び出しを最適化している.
おまけ -- TeX におけるフック機能について
TeX には \aftergroup 以外にも,様々な場所をフックできるキチガイな言語である.一覧にしてみよう.
\output | 出力ルーチンそのもの*6 |
\par | 段落の間に挿入される.これを書き換えると,段落の終わりをフックできる.しかし,オリジナルの \par を実行しないと段落が変わらないため,初心者にはおすすめしない |
\everypar | 段落の先頭に挿入されるトークンリスト.行頭に行番号を入れるなどのマクロは,これを使うと実装できる. |
\everymath | 文章内の数式をはじめる時のフック. |
\everydisplay | ディスプレイ数式のフック. |
\everyvbox | 垂直ボックスの開始. |
\everyhbox | 水平ボックスの開始. |
\everycr | 表組みでの \cr の後ろ.TeX の表組みプリミティブである \halign と \valign を知ってないと使いづらいかもしれない. |
\afterassignment | レジスタへの代入やマクロ定義のフック. |
LISP on TeX で千反田えるな話(3)
元ネタ:"LaTeXで "千反田える" してみた(1):概略"
さて,LISP on TeX の時間である.
といっても,プログラム的には簡単なので,今回はpTeX限定な命令を使ってやってみたがメイン.漢数字にするマクロ部分に,pTeXプリミティブ\kansujiを使ってみた.
\kansujiは
\kansuji 1234
のようにして使う.結果は「一二三四」に展開される.TeXでいうところの\romannumeralとか\numberと同じ用法.
0,1,...,9に使う文字は設定可能で,デフォルトは〇,一,…,九.この出力に「千」や「百」,「十」を入れるようなマクロを書いた.
結果はこちら
\documentclass{jsarticle} \pagestyle{empty} \usepackage{lisp} \lispinterpl{% (\define \alphlist (\quote ( 'ぜっと' 'えー' 'びー' 'しー' 'でぃー' 'いー' 'えふ' 'じー' 'えいち' 'あい' 'じぇー' 'けー' 'える' 'えむ' 'えぬ' 'おー' 'ぴー' 'きゅー' 'あーる' 'えす' 'てぃー' 'ゆー' 'ぶい' 'だぶりゅー' 'えっくす' 'わい'))) (\define \strofkananum (\lambda (\n) (\ith \n \alphlist))) (\define \ith (\lambda (\n \lst) (\lispif (\= \n :0) (\car \lst) (\ith (\- \n :1) (\cdr \lst))))) (\define \erutaso (\lambda () (\erutasobody :1))) (\define \erutasobody (\lambda (\n) (\lispif (\= \n :1001) () (\begin (\texprint '\tanda') (\texprint (\group (\strOfInt \n))) (\texprint (\strofkananum (\modulo \n :26))) (\lispif (\= \n :1000) () (\texprint '\\')) (\immediatewrite) (\erutasobody (\+ \n :1)))))) (\define \modulo (\lambda (\n \m) (\- \n (\* \m (\/ \n \m))))) } \newcount\cnttanda \def\tanda#1{% \cnttanda#1\relax \advance\cnttanda10000\relax \expandafter\tandawrite\the\cnttanda} \def\tandawrite#1#2#3#4#5{% \if0#2\else\if1#2\else\kansuji#2\fi 千\fi \if0#3\else\if1#3\else\kansuji#3\fi 百\fi \if0#4\else\if1#4\else\kansuji#4\fi 十\fi \if0#5\else\kansuji#5\fi 反田} \begin{document} \noindent\lispinterpl{(\erutaso)} \end{document}
ほぼLISP(またか).出力は元ネタと同じ.
なお,このコードはいつもどおりリポジトリにおいておいた.
LISP on TeX でマンデルブロな話
LuaTeXならマンデルブロ集合も書ける。
いや,e-pLaTeX でもいけるはずだ.もっと言えば,LISP on TeX で記述できるはずだ.
というわけで書いてみた.精度は時間がかかるのでだいぶ抑えているけど.
以下ソース
\documentclass[a3paper,landscape]{jsarticle} \usepackage[dvipdfm,margin=1pt]{geometry} \usepackage{lisp} \lispinterpl{% (\define \maxloop :100) (\define \scale :100) (\define \limitr (\* :2 \scale \scale)) (\define \sq (\lambda (\x) (\/ (\* \x \x) \scale))) (\define \isMandell (\lambda (\a \b \k \x \y) (\lispif (\< \maxloop \k) /t (\lispif (\< \limitr (\+ (\sq \x) (\sq \y))) /f (\isMandell \a \b (\+ \k :1) (\+ \a (\sq \x) (\- (\sq \y))) (\+ \b (\/ (\* :2 \x \y) \scale))))))) (\define \drawMandell (\lambda (\a \b) (\lispif (\isMandell \a \b :0 :0 :0) (\begin (\texprint '*') (\immediatewrite) ) (\begin (\texprint '-') (\immediatewrite) )))) (\define \modulo (\lambda (\n \m) (\- \n (\* \m (\/ \n \m))))) (\define \loopMandell (\lambda (\n) (\lispif (\= \n (\* :4 \scale \scale)) % test (\* :4 \scale \scale) () (\begin (\drawMandell (\- (\modulo \n (\* :2 \scale)) \scale) (\- (\/ \n (\* :2 \scale)) \scale)) (\lispif (\= (\modulo \n (\* :2 \scale)) (\- (\* :2 \scale):1)) (\texprint '\\') ()) (\loopMandell (\+ \n :1)))))) } \begin{document} \fontsize{5pt}{0pt}\selectfont\ttfamily\noindent \lispinterpl{(\loopMandell :0)} \end{document}
LISPじゃねーかw
ソース自体は,リポジトリに置いてある.勇気のあるひとは実行して欲しい.
実行結果はこちら*1.アスキーアート出力なので,アスペクト比がおかしいけど,計算自体はできている.
一応,ログファイルのメモリ使用量もつけてみる.
Here is how much of TeX's memory you used: 1523 strings out of 494059 15752 string characters out of 3159691 112278 words of memory out of 3000000 5008 multiletter control sequences out of 15000+200000 9102 words of font info for 41 fonts, out of 3000000 for 9000 750 hyphenation exceptions out of 8191 39i,4n,80p,192b,229s stack positions out of 5000i,500n,10000p,500000b,50000s
ちなみに,私の実行環境(W32TeX (2012/2/4),Core 2 Quad 2.4GHz,4GB memory)での計算時間は 130 [min] ほどでした.
*1:ページ番号入れっぱなしだったのでトリミングしてある