2020年12月7日

SATySFiで可換図式

これはSATySFi advent calendarの七日目の記事です.昨日はpuripuri2100さんの予定です.明日はamutakeさんの予定です.

ちょっと長めの文書をSATySFiで最近作っています.で,図式を描く必要が起こったので,パッケージMatrixCDを作りました.LaTeXパッケージのtikz-cdのように書けるようにしました.実は標準パッケージに図式を描くものがあったり,それとは別に既存のパッケージNon-Commutative Squaresというのがあったりするんですが,前者はすっかり忘れていて後者は存在に気がついたのが大分できてからでした.シンタックス大分違うのでまぁいいかと.tikz-cd万歳.

ドキュメント書こうと思っていたのですが間に合わずでした.

インストール

Satyrographosが入っていれば楽です.

$ opam install satysfi-matrixcd
$ satyrographos install

またはmatrixcd.satyを適当なフォルダに置けばよいです.

使い方

プリアンブルに次が書かれていることを仮定します.

@require: matrixcd/matrixcd
open MatrixCD

簡単な例は次の通りです.

+p{
  \eqn(${
    \matrixcd{
      |A \arrow![to `r`; label ${f}]\arrow![to `rd`] | B\arrow![to `d`;label ${g}]\cr
      | | D
    |}
  });
}

これで次のような出力が得られます.

+p{}は段落,\eqn(${...});がディスプレイ数式なのはSATySFiのいつも通りです.その中の\matrixcdが図式を出力します.書式は(tikz-cdと同様に)表の形で並べて,\arrowで矢印を引きます.表組みの区切りは|です.easytableとかと同じですね.改行は\crで指定します.

矢印へのもろもろの指定は\arrow![<引数>]への引数で行います.複数の設定をする場合は;で区切ります.ほぼ必須設定がtoで,矢印の行き先を指定します.引数は``で囲まれた文字列でrludの四文字の組み合わせです.それぞれ右,左,上,下で始点からの相対位置で指定します.

矢印に付随させてラベルをつけられます.label ${<ラベル>}で指定します.

\arrowのオプション

\matrixcd{
  |A\arrow![to `r`;label ?:[swap] ${f}] | B
|}

\arrowではなくlabelのオプションです.labelへのオプションはこのようにlabel ?:[<オプション>] ${<ラベル>}のように指定します.swapは表示位置を反転させるオプションです.

\matrixcd{
  |A\arrow![to `r`;hook] | B\arrow![to `r`;twoheadrightarrow] | C\arrow![to `r`;equal] | D | E\arrow![to `l`;hook-swap]\cr
  |F\arrow![to `r`;dotted] | G\arrow![to `r`;dashed] | H\arrow![to `r`;mapsto] | I
|}

色々な矢印.

\matrixcd{
  |A\arrow![to `r`;label ?:[description] ${f}] | B
|}

これもlabelへのオプション.矢印の間に挟む.

\matrixcd{
  |A \arrow![to `d`;shift (10pt,0pt)] \arrow![to `r`;shift (0pt,5pt)] | B\cr
  |C \arrow![to `u`;shift (-10pt,0pt)] | D \arrow![to `lu`;shift (5pt,5pt)]
|}

矢印をずらす.shift (<x>,<y>)で右にx,上にyずらします.

\matrixcd{
  |A \arrow![to `r`; shift-out (0pt,5pt)] | B\arrow![to `r`;shift-in (0pt,-5pt)] | C
|}

矢印の出発地点をずらすshift-outと到着地点をずらすshift-in

\matrixcd{
  |A \arrow![to `r`; bend 90.0] | B\arrow![to `r`;bend-right] | C\arrow![to `r`;bend-left] |D\cr
  |E \arrow![to `r`; arrow-in 315.0; arrow-out 225.0] | F
|}

曲がる矢印.矢印がでたり入ったりする角度をずらします.bendは引数の角度分だけ矢印の出入りの方向を回します.bend-leftbend 30.0bend-rightbend 330.0です.この小数点は省略できません.bend 30はエラーです.arrow-inarrow-outは指定された方向へと矢印の入る方向と出る方向を変更します.

\matrixcd{
  |a \arrow![to `r`; phantom; label ${\in}] | A
|}

phantomを指定すると矢印が消えてラベルが真ん中に出ます.

\matrixcd{
  |A \arrow![to `r`; label ?:[pos 0.2] ${f}] | B\arrow![to `r`; label ?:[pos 0.8] ${g}] | C
|}

これもlabelへのオプション.posは指定された値の割合に応じてラベルの位置をずらします.0から1までの値を指定し,0の方が始点に近く,1の方が始点から遠い.

\matrixcd{
  |A \arrow![to `rd`;crossing-over] | B\arrow![to `ld`] \cr
  |C | D
|}

crossing-overで矢印を重ねます.たまにうまく行きません.上に引く矢印が後にあるとまずいみたいなんですが,逆ならともかく何でだろう.

\matrixcd{
  |A \arrow![to `r`;arrow-color Color.red] | B\arrow![to `r`; label ?:[label-color Color.blue] ${f}] | C
|}

色をつけます.

\matrixcd{
  |A | B\arrow![from `l`]
|}

矢印はtoで終点を指定する方がわかりやすいと思いますが,始点をfromで指定することもできます.両方使うこともできて,もう全然関係ない場所から矢印がでちゃう.

\matrixcd ?:![row-sep 15pt; column-sep 60pt]{
  |A\arrow![to `r`]\arrow![to `d`] | B\cr
  | C | 
|}

これは\matrixcdへのオプション.各行,各列の間の距離を指定します.デフォルトは40pt.

実装

半分メモ書きです.

  • 上のシンタックスを実現するために,可変参照を多用しています.例えば\crの実装は次のようになっています.
    let-mutable ref-cr <- false
      let-math \cr =
      let aux ctx =
        let () = ref-cr <- true in
        ${}
      in
      text-in-math MathOrd (fun ctx -> embed-math ctx (aux ctx))
    
    このようにref-cr\crが現れたというフラグをたてるだけです.なお,auxの引数ctxは不要そうに見えますが,これを消すと評価場所の関係でref-crにうまく値が入りません.いずれにせよ,このような命令が含まれているmath listを\matrixcdは受け取ります.\matrixcdはこのリストを
    % リストの中身を順番に処理している
    % itに今処理しているmathが入っている.
    let () = ref-cr >- false in % ref-crにfalseをセット
    let ib = embed-math ctx it in % itをinline-boxesに変換,\crがあればここで処理される.
    % 以下ref-crの値に応じて改行するか否かの処理
    
    という感じで処理します.\arrowも同様で,矢印の設定などの情報を適当な可変参照に代入していきます.
  • 矢印は「head」「tail」「body」の三カ所に分けて作っています.外からいじれるわけじゃないですが…….headとtailを出力するのは
    arrow-option-data -> length * length -> length * length -> context -> (length * length) * graphics list;
    という関数で,<オプション> <始点> <終点> <context>を受け取り,(<pt>,<graphics list>)を返します.オプションは\arrowのオプションとして渡される物(の一部)であまり重要ではありません.<graphics list>が矢印の形そのものです.<pt>は,bodyの終点と始点を表します.bodyを出力する関数には,tailとheadから返されたこの始点と終点が渡されます.bodyを出力する関数は
    arrow-option-data -> length * length -> length * length -> context -> graphics list;
    です.やはり始点,終点,contextを受け取り,graphics listを返します.ここに渡される始点,終点はtailおよびheadが返したものです.最も単純な実装としては始点から終点まで線を引くだけのものになります.

0 件のコメント:

コメントを投稿

コメントの追加にはサードパーティーCookieの許可が必要です