この記事はSATySFi Advent Calendar13日目の記事です。前の記事は@na4zagin3さんの「素敵なライブラリをSatyrographosで配布しよう!」で次は@zptmtrさんの「SATySFiの組版結果をテストする」です。本記事では物理系の大学院生である筆者がD論をSATySFiで書いた話について紹介します。
#利用したもの
すでにgfngfnさんの修論用のクラスファイルcs-thesisで目次の作成や図の挿入などの基本的な機能は実装されているため、これをベースに各自調整し、足りない機能を追加していくことになります。自分の場合は余白やフォントの変更に加え、cs-thesisのコードを参考にして、LaTeXにおけるAppendixや式番号などの機能を追加しました。例えば、式番号をつける数式\eqn-num
は
let-mutable num-eqn <- 0
let eqn-scheme ctx labelopt =
let () = num-eqn <- !num-eqn + 1 in
let s-num = arabic !num-chapter ^ `.` ^ arabic !num-eqn in
let () =
match labelopt with
| Some(label) -> register-cross-reference (`eqn:` ^ label ^ `:num`) s-num
| None -> ()
in
let it-num = embed-string (`(` ^ s-num ^ `)`) in
it-num
let-inline ctx \eqn-num ?:labelopt inner =
let num = eqn-scheme ctx labelopt in
read-inline ctx {\eqn ?:(num) (inner);}
といった具合で追加できます。今回のD論で用いたクラスファイルについては近いうちに公開する予定です。
以下ではその他に実装する必要があったものなどについて紹介します。
#参考文献リスト
D論ともなると(分野にもよるとは思いますが)参考文献の数は膨大となり、.bib
ファイルのような外部ファイルを利用し、ハイフネーションやコンマ区切り、引用文献の並び替えなどをうまいことやってくれるような、BibTeX相当の機能が必須となってきます。SATySFiでD論を書こうかなと漠然と考えていた9月頃に調べた限りではこのようなパッケージがなかったため、SATySFiの練習がてらにbib-satysfiを実装しました1。このパッケージはモジュール化などのコードの整備をしていない部分があるのでそのうちアップデートする予定ですが、通常使用する分には現状のままでも特に問題なさそうです2。SATySFiから.bib
ファイルのデータを直接読み込む手段がなさそうだったので、.bib
ファイルを.satyh
ファイルに変換するPythonスクリプトも一緒に置いてあります3。ただし、日本語文献は想定されていないのでうまく変換できません。
使い方としては、まず.bib
ファイルを.satyh
に変換します。SATySFiの本文中では(括弧が多くて煩わしいですが)、
\cite([`hoge`;`fuga`]); % -> [1,2]
\cite([`hoge`;`fuga`;`piyo`]); % -> [1-3]
などのように引用し、文献リストは
+references(bibliography);
で出力します。なお、.bib
からの自動変換が難しいものについては、数が多くないのであれば別の.satyhファイルを手動でを作っておいて
bibliography = (List.append bibliography user-bibliography);
のようにリストを結合すればなんとかなります。
ところで実装するにあたっていかにもcross-reference
が使えそうな気がしていたのですが、cross-reference
にはkeyとvalueに登録できるのがstring
のみという制限があります。本文で出てきた順番に1から番号を割り振って並び替えるという用途に合わなかったため、今回はlet-mutable
のみを使って実装しています4。
#数式コマンド
物理でよく使うような、LaTeXにおける\hat
や\dot
、 \braket
などは用意されていないので自分でコマンド定義を書く必要がありました。実装するにあたって必要なことはSATySFi Bookにだいたい書いてありますが、よく使うパターンについてここでまとめておきます。個人的な見解ですが、コマンド定義で重要なプリミティブは
embed-math : context -> math -> inline-boxes
text-in-math: math-class -> (context -> inline-boxes) -> math
math-paren: paren -> paren -> math -> math
あたりだと思います。特にembed-math
とtext-in-math
を使うことで、math型
とinline-boxes型
を相互に変換するというのは常套手段で以下でも紹介します。この記事で紹介しているものを含め、筆者が実装した数式コマンドもクラスファイルとまとめてそのうち公開する予定です。
##文字や記号の上に描画
\hbar
や\hat
などがこれにあたります。これは文字や記号をembed-math
でinline-boxes
にしてからinline-graphics
を用いて上から描画することで実現することができます。例えば、\hat
は以下のように実装できます。
let-math \hat inner =
let hat ctx =
let ib = embed-math ctx inner in
let (w, h, d) = get-natural-metrics ib in
let thickness = 0.4pt in
let color = Color.black in
inline-graphics w h d (fun (x, y) ->
[
stroke thickness color
(start-path (x +' w *' 0.35, y +' h *' 1.2)
|> line-to (x +' w *' 0.6, y +' h *' 1.4)
|> line-to (x +' w *' 0.85, y +' h *' 1.2)
|> terminate-path);
draw-text (x, y) ib
])
in
text-in-math MathOp hat
embed-math
でmath型のinner
をinline-boxes型に変換してハット部分の描画を行い、最終的にはtext-in-math
でmathに戻しています。なお、\hbar
や\AA
などの特殊文字に関しては同様に定義することも可能ですが、フォントが存在する場合はそのまま直接本文に入力したり、
let-math = math-char MathOrd (string-unexplode [8463])
let-inline ctx \AA = read-inline ctx {Å}
などとしてコマンド定義することもできます。
##括弧で囲う
こちらはmath-paren
を使います。例えば、物理でよく使う\ket
や\braket
は
let-math \ket = math-paren Math.abs-left (Math.angle-right 0.5pt)
let-math \braket =
math-paren-with-middle (Math.angle-left 0.5pt) (Math.angle-right 0.5pt) Math.abs-right
のように実装することができます。微分における代入を表す縦線など、片側のみに伸縮する"括弧"が欲しい場合は"空の括弧"Math.empty-paren
を使います。
let-math \eval-bar = math-paren Math.empty-paren Math.abs-right
また、行列組版用のパッケージsatysfi-matrixやmath.satyhの\cases
などのように、tabular
で作ったinline-boxesをtext-in-math
でmathに戻すことで表を様々な括弧で囲うこともできます。
##文中数式
物理系の論文なので文中数式は必須ですが、分数やルート、下付き上付き文字、伸縮する括弧などが組み合わさると縦方向に際限なく伸びてかなり不格好になってしまう上に、行間の設定によっては上下の行と接触してしまうこともあるようです。文中数式の分数や括弧は\frac
や\paren
ではなく単にa/b
や\(a\)
5などを使って回避しました。ルートについては
let-math \smsqrt inner =
let smsqrt ctx =
let size = get-font-size ctx in
let ctx-small = ctx |> set-font-size (size *' 0.85) in
embed-math ctx-small ${\sqrt{#inner}} in
text-in-math MathOrd smsqrt
のように中身のフォントサイズを小さくする\smsqrt
を定義しました。\sqrt
などに渡す数式そのものを小さくするコマンドを定義してもいいかもしれません。ここでわざわざembed-math
とtext-in-math
を通しているのは、math型ではcontextが変更できない6ために一度inline-boxesを通す必要があるからです。以上でどうにもならないような複雑な数式に関してはそもそも文中数式ではなく別行立て数式にしてしまった方が無難な気がします。
#印刷
提出締め切りの週になってD論のpdfを印刷しようとしたら、なぜかプリンタ側でエラーが出て詰みかけました。どうもMacOSのプレビューからSATySFiで生成したpdfを印刷しようとすると(少なくとも弊研究室で使っているプリンタでは)エラーがでるようで、Adobe Acrobat Readerからだと問題なく印刷できました。これに関しては理由がイマイチわかっていないのですが、締め切り直前は印刷がうまくいかないなどのトラブルは起きがちなので前もって確認しておきましょう。
#最後に
この記事では筆者がSATySFiでD論を書いたときに利用したものや、新たに実装した機能などについて紹介しました。SATySFiはまだ歴史が浅いこともあり、必要なものがまだ実装されていないケースが多く、(必要なことはだいたいSATySFi Bookに書いてあるものの)インターネット上の情報が少ないという点が大変でした。一方、SATySFiには他人のコマンド定義が比較的に容易に読めるという利点があり、SATySFi本体のパッケージ群を参考にするとうまくいくことが多かったです。この記事が今後SATySFiで学位論文やレポートなどを書く人々の参考になれば幸いです。
-
実装するにあたり、学部生の頃にすごいH本などで関数型言語に触れたことがあったのがかなり役に立った気がします。 ↩
-
100以上引用してとりあえず問題なく使えています。 ↩
-
ウムラウトなどの特殊文字の変換が面倒でそんなに数が多いわけでもなかったので、今の所は元ファイル自体を手動で直しています。簡単にやれる方法があったら教えていただけるとありがたいです。また、論文のタイトルを文献リストに表示することも想定していないのでタイトルの数式のエスケープはかなり適当です。 ↩
-
数式中では'('と')'にはエスケープが必要。 ↩
-
SATySFi Bookによると「math 型の値はインラインテキストに近いもので, 単に数式の “構造” を保持しているだけ」とのこと。 ↩