見出し画像

LaTeXで定理や命題などのスペシャルな環境を作る.パート2

前回,以下の私の記事でスペシャルな定理環境を整えるという話をしましたが相互参照がうまくいってなかったり,コードが蛇足で長くなっていたりと問題が多くありましたゆえ改訂版を製作いたしました.


はじめに

まずはこの記事で何を書くか宣言します.この記事では次の10個の要請通りのLaTeXの定理や命題の環境を整備する方法と解説を行います.
仕組みはどうでもいいので使い方だけ教えてくれ!という方はそれ用に仕様書のような記事を後日出すつもりです.

要請

(1)以下のような見た目の定理や命題,補題などの枠を作る.

最終的な見た目

(2)枠は都度いちいち作るのではなく,以下のように打つことで自動で作られてほしい.
(LaTeXでは\begin{}…\end{}みたいなやつを"環境"といいます.つまり自作の環境をつくって定理や命題の枠を作らせようということ.)

\begin{環境の名前}<ステートメントの種類>[ラベルの名前](ステートメントの名前)
 ステートメント本体
\end{環境の名前}

ここで「環境の名前」とはあとで自分で自作する環境の名前.
「ステートメントの種類」とは公理とか定義とか定理とかのこと.
「ラベルの名前」とはあとで相互参照用に使うラベルのこと.
「ステートメントの名前」とはピタゴラスの定理とかクルルの次元定理とかそういうもの.

(3)枠のデザインは自由に一括で設定できるようにしたい.決まったパッケージで決まった枠を使うのではなく,自分で見た目を設定しようということである.また,枠の色やそもそも枠にするのではなく左だけに線を引くとか文末には決まった記号を置きたいとか薄くドラえもんの絵を印字したいとか,自由度を高めたい.しかもデザインの変更は容易であってほしい.例えば公理の部分の色は赤じゃなくて灰色にしたい,となった場合はプリアンブルの一部をいじるだけで文書内の公理枠は全部灰色に変更できるようであってほしい.Axiomではなく公理と表示させたい場合も同様.

(4)枠はPage Breakしてほしい.つまり以下のように枠がページにまたがった際はうまく分割されてほしい.(分割されずにどちらかのページにねじ込むといった設定も可能)

Page Break

(5)番号はセクション番号をn,そのセクション内での順番をmとしたときにn.mのように表示したい.ただしmはステートメントの種類によらずに通し番号にしたい.つまり「公理1.1→公理1.2→定義1.3→命題1.4→定理1.5→定義2.1→補題2.2→注意2.3→…」のようなカウントをしてほしい.しかも自動で.つまり命題を途中に差し込んだ場合でも自動で番号が振られ直されるようであってほしい.

(6)番号がない以下のような枠も欲しい.ただしこれが現れた場合は番号をカウントしないものとする.(これに対しての再掲も可能)

(7)相互参照において,(2)のソースコード中の[]オプションで,例えばchoiceと打てば自動で「axiom:choice」という名前のラベルが生成されてほしい.より具体的には公理環境を使った場合には指定したラベルの名前の前に「axiom:」とついてほしい,定理環境なら「th:」など.こうすることで\refなどの参照系コマンドを使った際に以下のように「axiom」と打った段階で公理のラベルしか出てこないようになり,探すのが楽になる.
(どうやら予測変換はラベル系のコマンドでラベリングした後一度コンパイルし,さらに「ref」の文字列が入ったコマンドの引数に文字を打とうとすると出てくるVScodeの仕様があるっぽいです.したがって自作のrefコマンドでrefの文字列が入っていないと予測変換は機能しない可能性があります.)

予測変換

(8)ラベル名を適切なコマンド内に打つだけで定理や命題の再掲が可能になってほしい.つまり以下のようにコマンドを打てば

\recallrefspは自作のコマンド

次のように表示されてほしい.

再掲

(9)(7)の再掲の際は画像のように【Recall】が付くなど,再掲用のデザインは別であってほしい.さらに再掲のときは「Axiom 1.1」の部分は元のステートメントへのハイパーリンクとなっていてほしい.(ハイパーリンクにしないこともできます.)

(10)相互参照系のコマンドはただ1通りであってほしい.つまり公理を参照するときは公理専用の参照用コマンド「\axiomref」などを作って用いるのではなく,全部1つの\refコマンドで参照したい.

要請の実現に向けて

実現に向けて行うことをスピーディかつ簡単に解説します.早く書き方を教えてくれ,という人はここは飛ばしてもいいでしょう.

枠の実装

(1)~(4)のような要請に応えるため,枠はtcolorboxというパッケージを用います.つまりプリアンブル(\documentclass…から\begin{document}の間の部分のこと)に以下のように書くのです.

\usepackage[many]{tcolorbox}

オプションのmanyはよくわかりませんがなにやらうれしい機能をこれ1つでたくさん付加してくれるようなのでテキトーに入れときます.
ただし問題もあって,tcolorboxで作った枠の中にさらに枠を入れるとうまくPage Breakしてくれないようです.聞くところによるとどうやらこれはtcolorbox パッケージそのものの現行の仕様のようです.

他にmdframedパッケージを使って枠を作るやり方もあります.しかしこれには以下のデメリットがあります.

  • Page Breakの設定が面倒

  • パッケージの最終更新が10年以上前(tcolorboxは2024年現在でも更新され続けている)

  • シンプルに使い方がムズイ

はじめ私はこちらで実装しました.うまくいくにはいきましたがPage Breakはどうしてもバグってしまいました.一方tcolorboxならほぼ何も考えずPage Breakしてくれます.しかもPage Breakしないという設定も可能です.

カウンターの実装

(5)の要請のようにカウンターを作るために自分でカウンターを定義します.LaTeXでは

\newcounter{カウンターの名前}[親カウンター]

とすることで「カウンターの名前」という名前のカウンターが,既定の「親カウンター」の番号が上がると1にリセットされるようなカウンターとして作成できます.これを利用して「公理1.1→公理1.2→定義1.3→命題1.4→定理1.5→定義2.1→補題2.2→注意2.3→…」というような番号を可能にします.

相互参照の実装

(7)(10)の要請に応えるため,今回はprettyrefパッケージを用います.これはラベルの名前が「axiom:choice」のようであった場合,「:」の前の文字列に応じて相互参照の出力形式を変更できるというものです.したがってラベルの名前を「axiom:choice:1」のように複数のコロンをラベルの名前に用いることは推奨されません.

他にcleverrefを用いるといったことが考えられますが,これは参照先のラベルがラベリングしているカウンター名に応じて出力形式を変更できるという仕様なので,通し番号にしたい(したがってカウンター名はひとつ)という今回の場合には不向きです.カウンターの名前を増やせば実装できますが,かなりソースコードが煩雑になります.

再掲の実装

(9)(10)のような要請に応えるのがとても難しいです.正直未だに実装方法が分かりませんが以下のegreg様の回答を参照してソースコードを改造して使用します.

完成系

こちらが完成系のスタイルファイルです.コマンドの競合などにお気を付けください.

こちらのスタイルファイル内に何が書いてあるのかなどを次章で解説します.ちなみにスタイルファイルとは,雑に言えば\usepackageと書くときの親玉です.\usepackageではこのスタイルファイルに書いてあるものを読み込んでおり,プリアンブルに書くべきものをスタイルファイルに押し付けて凝縮しているイメージです.したがってこのファイルの中身を丸々コピペしてプリアンブルに書いてもいいですし,以下の@syunt様の記事にしたがってパッケージのように使ってもいいのです.

実装の手順と解説

上記のスタイルファイルの中身を上から順に解説していきます.

用いるパッケージの解説

まずはここですね.

%Enviroment of Axiom, Def (definition), Th (theorem), Prop (proposition), Lem (lemma), Cor(corollary), Rem (remark), Ex (example), Question, Pred (prediction).
\usepackage{xcolor}
\usepackage[dvipdfmx]{graphicx}
\usepackage{tikz}
\usepackage{ifthen} %Using \ifthenelse
\usepackage{amsthm} %Proof environment
\usepackage[many]{tcolorbox} %Insert tcolorbox package and its option
\usepackage{refcount}
\usepackage{mfirstuc} %Capitalize only first letter

各段落の%以降の文は全部コメントアウトですので動作には関係ありません.ここでは実装に必要なパッケージたちを読み込んでいます.
xcolorはLaTeXに色を導入するパッケージです.これがなければ文書はすべて白黒になるでしょう.
graphicxはよくわかりません.dvipdfmxもよくわかりません.ただこれがないとtcolorboxで作った枠が消滅して表示されます.
tikzは枠の設定を細かくできるようにするためのパッケージです.
ifthenはその名の通りifによる条件分岐を使えるようにするためのパッケージです.
amsthmは証明の環境を作るためのパッケージです.ここはカウンターとか参照とか無いので既存のパッケージに乗っかります.
tcolorboxはまさに枠を自作するためのパッケージです.本来は枠を作るだけのパッケージなのですかね?しかしステートメントの枠を作るのに多く利用されます.
refcountはよくわかりません.これは再掲を実装するために必要なパッケージですがどこに寄与するかは不明です.
mfirstucは英語などの最初の文字のみを大文字に変換するコマンドを使用できるパッケージです.axiomと打ったときにAxiomと表示させ直すのに用います.

相互参照の基本設定の解説

次はこうなってます.

%Refference
\mathtoolsset{showonlyrefs=true} %Give numbers of equation in equation and align environment only to refered them.
\usepackage[
    dvipdfmx,
    setpagesize=false,
    bookmarks=true,
    bookmarksdepth=tocdepth,
    bookmarksnumbered=true,
    colorlinks=true,
    linkcolor=blue,
    pdftitle={},
    pdfsubject={},
    pdfauthor={},
    pdfkeywords={}
]{hyperref} %Insert hyperlink into a document
\usepackage{pxjahyper} %PDFのしおり機能の日本語文字化けを防ぐ((u)pLaTeXのときのみかく)
\usepackage{prettyref}
\newrefformat{axiom}{Axiom~\ref*{#1}}
\newrefformat{def}{Def~\ref*{#1}}
\newrefformat{th}{Th~\ref*{#1}}
\newrefformat{prop}{Prop~\ref*{#1}}
\newrefformat{lem}{Lem~\ref*{#1}}
\newrefformat{cor}{Cor~\ref*{#1}}
\newrefformat{rem}{Rem~\ref*{#1}}
\newrefformat{ex}{Ex~\ref*{#1}}
\newrefformat{question}{Question~\ref*{#1}}
\newrefformat{pred}{Pred~\ref*{#1}}
\newcommand{\refsp}[1]{\hyperref[#1]{\prettyref{#1}}}

mathtoolsetのところはalignなどの数式環境で必要なければ数式に勝手にラベルが付くのを防ぎます.必要があれば式番号を表示させることも可能になります.
hyperrefは相互参照にハイパーリンク(ボタンを押すとその箇所にバッととぶやつ)を追加できる機能です.そして中身の[]オプションに追加しているやつはよくわからんのでいっぱい追加しています.ここを参考にしました.

ちなみにcolorlinksの部分をtrueにすると文字の色が設定できてハイパーリンクっぽくできます.その下のlinkcolorで文字の色を設定できます.おそらくですがさきほどのxcolorパッケージの後にこの部分を書かないとうまく動かないかもしれません.
pxjahyperもよくわかりません.
prettyrefは先ほど説明した通り,labelの名前の「:」の前の文字列に対応して参照の出力形式を変更できるパッケージです.その下の\newrefformatコマンドで出力形式の変更が可能です.具体的には

\newrefformat{ラベル種}{出力形式}

のように書くのです.ラベル種というのはラベルの名前をたとえば「axiom:choice」とつけた場合の「axiom」の部分です.prettyrefの仕様上このようなラベルのつけ方をしなければなりませんが,のちほどこの「axiom:」のような部分は自動で付くように設定します.出力形式は今回のように書けば「Axiom 1.1」のように表示されます.\ref*というのはハイパーリンクはつけない相互参照コマンドです.#1というのはprettyrefによる相互参照用コマンド,\prettyref{ラベル名}の「ラベル名」の部分です.で,最後に\newcommand{\refsp}…などとすることで\refspというコマンドを新たに作成し,「Axiom 1.1」を丸ごとハイパーリンクのボタンとして設定しています.このあたりの設定は以下を参考にしました.

カウンターの設定の解説

次はここ.

%Define counter
\newcounter{statementnum}[section]
\renewcommand{\thestatementnum}{\arabic{section}.\arabic{statementnum}}

ここで「Axiom 1.5」とかの5の部分のカウンターを定義します.名前は自由ですが今回は「statementnum」というカウンター名でこれを記述します.後ろの[section]というのをつけるとsectionという名前のカウンターが上がると,このstatementnumカウンターが1にリセットされるという設定にできます.ちなみにこの場合のstatementnumカウンターをsectionカウンターの子カウンターと呼び,sectionカウンターをstatementnumカウンターの親カウンターと呼びます.
sectionカウンターなんてカウンター定義してないぞ!と思われるかもしれませんが,これはLaTeXに標準で定義されているカウンター名です.その名の通りセクション番号に使います.(\sectionコマンドなどを使うたびに1上がる設定になっています.)
次の\renewcounterではなにをしているかというと,実はLaTeXではカウンターを自分で作成すると「\the(カウンター名)」というコマンドが自動生成されます.このコマンドはそのカウンターの現在の値を返すコマンドです.これを書き換えて「(sectionの値).(statementnumの値)」を出力するコマンドにします.

色の設定の解説

次はここです.

%Statement color
\definecolor{axiomcol}{rgb}{1,.8,.8}
\definecolor{defcol}{rgb}{1,.8,.8}
\definecolor{thcol}{rgb}{.8,.8,1}
\definecolor{propcol}{rgb}{.8,.8,1}
\definecolor{lemcol}{rgb}{.8,.8,1}
\definecolor{corcol}{rgb}{.8,.8,1}
\definecolor{remcol}{rgb}{1,1,.6}
\definecolor{excol}{rgb}{.8,.8,.8}
\definecolor{questioncol}{rgb}{.8,1,.8}
\definecolor{predcol}{rgb}{1,.8,1}

これはステートメントの種類ごとに枠の色を設定する場所です.色を決めるだけなのでここでもう枠が完成する,なんてことはないです.\definecolor{A}{B}{C}でAという名前の色をBという「色の指定形式(RGBとかそういうこと)」でCのような色であると定義します,という意味ですね.例えばあとから公理の枠の色を変えたいと思ったら,ここだけ変更すれば文書内の公理の枠すべての色が変わります.ひとつひとつ変える必要はないわけです.ちなみにRGBの順に0.8, 0.0, 1.0のように各色は0から1までの間で強さ指定します.全部1にすると真っ白になります.全部の色を混ぜると白になりますもんね.(光の場合の話です.絵具だと黒になりますが.)真っ赤にしたければ1.0, 0.0, 0.0にすればいいといった具合です..8とかは0.8の略です.こういう書き方も許されるようです.

枠の形状などの設定

次にここ.

%Foundamental design of tcolorbox
\tcbset{
    statement/.style={
            enhanced,
            coltitle=black,
            colframe=#1,
            boxrule=2pt,
            colback=white,
            breakable,
            sharp corners,
            attach boxed title to top left={xshift=3mm, yshift*=-\tcboxedtitleheight/2},
            boxed title style={
                    colframe=#1,
                    boxrule=2pt,
                    colback=#1,
                    sharp corners
                },
            after upper=\hfill $\square$
        }
}

ここはすべてのステートメントの種類に共通のデザインを定義する場所です.あとでtcolorboxパッケージを用いて枠のデザインを作るわけですが枠の形は冒頭お見せしたようにすべて同じです.違うのは色くらいですもんね.色の設定はさきほど定義した色「axiomcolとか」を用いてうまくやります.
tcolorboxで枠を作るときは以下のようにするのですが,

\begin{tcolorbox}[オプション]
 枠の中の文章など
\end{tcolorbox}

このオプションの部分に枠のデザインを入力するのです.しかしここが長くなったら見にくいし共通のデザインは決まっているのにすべての\begin{tcolorbox}のオプションに長い文言を入れるのはめんどくさいです.メンテナンスも大変.(例えば先端恐怖症だから枠の角は丸くしてくれ,と言われたらいちいち全部の\begin{tcolorbox}のオプションを見に行かなければなりません.)よって\tcbsetコマンドでこのオプションの部分を事前にカスタマイズしてstatementという名前のスタイルを作っているのです.これであとで

\begin{tcolorbox}[statement]

みたいにかくことで事前に作ったスタイルを読み込ませることができるのです.(正確にはもうちょい書くものがある.)
しかしこの作り方のせいで公理環境のみ枠のデザインを変えて,定義環境は変えない,などの細かいことをしようと思うとソースコードのリフォーム規模が大きくなります.
tcbsetの中身について説明します.
enhancedはtikzで見た目を制御するために必要な命令です.多分.よくわかってません.
coltitleはタイトルの文字の色です.今回はblack.
colframeは枠の線の色です.これはステートメントの種類によって変えたいところですね.しかしあとから\begin{tcolorbox}のオプションにいちいち書くのは面倒です.実はここを#1としておくと変数扱いになってあとから代入するという芸当が可能です.つまりここは#1としておいて公理環境を作るときに公理に対応する色を代入するんですね.
boxruleというのは枠の線の太さです.
colbackというのは枠の内部(位相空間的な意味での内部と思っていい)の背景色です.もし文書全体の背景色を別の色にしている場合は枠だけ白色になって浮きます.ここを文書の既定の色に自動的になるように設定することもできるんですけどめんどくさいので割愛.
breakable.これが1番欲しい機能です.これをここに書いておくだけで枠が自動的にページまたぎに対応します.しかし,現在のところtcolorboxの中にtcolorboxを入れた場合はbreakはうまく機能せずバグってしまうようです.tcolorboxの中にさらにtcolorboxを入れた場合にPage Breakできる方法をご存じでしたらご一報ください.
sharp cornersはその名の通り,枠の四隅を角ばらせます.個人的な好みに過ぎませんが.
attach boxed title to top leftは枠の左上にタイトル用の小さいボックスをこういう風に作ってねという命令です.

この中身の命令はこのボックスを右に3mm,下にボックスの縦の長さの半分の長さ,これだけ移動せよという命令です.これも個人的な好みです.
boxed title styleはその名の通りタイトルボックスの設定です.中身も見ればわかるコマンドかと思います.
after upperは枠の中身の最後の最後に付け加えることができる文や記号を設定できる命令です.個人的な好みでステートメントの末尾には白い四角を置きたいので今回は□を枠の中の最後の文の右端に置く設定をしています.

自作環境の構築の解説

ここからが本命です.LaTeXで「statementsp」という名前の環境を自作します.(ステートメントスペシャル,というつもり.ほどほどにダサくてコマンドの競合が起こりにくそうだと思ったのでこういう名前にします.もちろん他の名前にもできますが例えば「def」とかはコマンドの競合が多すぎてやらない方が後々のためです.)
次に書いてある

\ExplSyntaxOn

はよくわかりません.後に出てくる

\ExplSyntaxOff

に関係がありそうですね.以降のよくわからんやつは以下を参考にしています.再掲コマンドの実装に利用するコマンドです.

次の

%Counter for recall
\newcounter{recallnum}
\seq_new:N \g_ephraim_recallnum_seq

も再掲用です.よくわかっていませんがrecallnumというカウンターを別に動かして定理や命題でラベルが付けられるたびにこのカウンターの現在の番号を保存し,その後番号を上げる,ということをするようです.そうしてあとから参照用のコマンドでrecallnumの番号を適切に参照するとrecallnumの番号に対応して一緒に保存していたその定理の文言などを呼び出して出力する,というメカニズムのようです.したがって実は1つのステートメントにつき2つのラベルが生成されます.1つは相互参照用,もう1つはこの再掲用ですね.

そして次.

%statementsp environment
\NewDocumentEnvironment{statementsp}{r<> d[] d() +!b}{
    \IfNoValueTF{#2}{
        \stepcounter{statementnum}
    }{
        \refstepcounter{recallnum}\label{re#1:#2}
        \refstepcounter{statementnum}\label{#1:#2}
        \IfNoValueTF{#3}{
            \seq_gput_right:Nn \g_ephraim_recallnum_seq{
                \begin{tcolorbox}[statement=#1col, title={\underline{\hyperref[#1:#2]{\MFUsentencecase{#1}~\ref*{#1:#2}}}~【Recall】}]
                    #4
                \end{tcolorbox}
            }
        }{
            \seq_gput_right:Nn \g_ephraim_recallnum_seq{
                \begin{tcolorbox}[statement=#1col, title={\underline{\hyperref[#1:#2]{\MFUsentencecase{#1}~\ref*{#1:#2}}}~:(#3)~【Recall】}]
                    #4
                \end{tcolorbox}
            }
        }
    }
    \IfNoValueTF{#3}{
        \tcbset{
            blank/.style={title={\underline{\MFUsentencecase{#1}~\thestatementnum}}}
        }
    }{
        \tcbset{
            blank/.style={title={\underline{\MFUsentencecase{#1}~\thestatementnum}~:~(#3)}}
        }
    }
    \begin{tcolorbox}[statement=#1col, blank]
        #4
    \end{tcolorbox}
}{}

ちょっと長いですが順に解説します.まず環境を作るためのコマンドが

\NewDocumentEnvironment{新環境名}{オプション}{はじまり}{おわり}

というものです.ほかに\newenvironmentという同種のコマンドがありますが,NewDocumentEnvironmentの方が上位互換といってよいです.詳しくは以下のthth様の記事をご覧ください.最強の環境自作コマンドです.

「新環境名」とは今回「statementsp」とする部分です.
「オプション」ですが「r<>」と書くと「必ずつけなければならないオプションであって括弧の種類が<>であるようなもの」という意味になり,これを最初に書いたのでこれが第1引数となります.括弧の種類まで指定できてしまいます.極端な話「rzk」などと書けば括弧が「zk」というもので与えられるオプションです,ということもできてしまいます.多分.今回はこの<>オプションの中にはステートメントの種類(定理とか命題とか補題とか)を指定する文言を入れることにします.ちなみに後で出てくる「#1」とかはこの1つ目の引数の文字列そのものを表します.「d[]」と書くと「任意で付けられるオプションで(したがって書かなくてもよい)括弧の種類が[]であるようなもの」という意味になります.これは今回はラベル名をつけたいとき(つまりあとで相互参照や再掲の必要性があると予測されるステートメントであるとき)に入れるオプションとします.次の「d()」にはステートメントの名前(ピタゴラスの定理とかクルルの次元定理とか)を入れたいときに入れられるようにするオプションということにします.次の「+!b」ですがこれが特に最強で,環境で囲った中身の文章など,つまり

\begin{環境}
 ここのこと
\end{環境}

ここの部分をまるごと引数とする,という設定ができるのが「b」です.「+」は中に改行があっても気にせず引数としてとってこい,という設定で「!」とは両端にスペースがあったとしてもそれも込みで引数としてとってこい,という設定です.これにより中身の文章を一旦保存し,あとでコマンド1発で再掲できる機能を実現します.
「はじまり」の部分は環境の中身に来る文よりも前に書いておくべきものを書いておける部分です.「おわり」も同様.
次の\IfNoValueTF{#2}{A}{B}というのは「#2という引数(今回ならd[],つまりラベルとして設定したい部分)が空ならA,空じゃなければBという条件分岐をしなさい」というコマンドです.Aの部分では単にstatementnumの番号を上げています.ラベルがない場合の処理ですのでこれくらいしかしません.Bの部分では\refstepcounterというコマンドでrecallnumカウンターの現在の番号を直後に着けたラベルにラベリングさせるとともにカウンターを1個上げるということをまずしています.次は通し番号のstatementnumの現在の番号をラベリングさせて番号を上げています.ここでラベルの名前は例えばaxiom環境なら「choice」という名前にしても勝手に「reaxiom:choice」や「axiom:choice」というラベル名にされます.「reaxiom:choice」は再掲用に必要な別途のラベルですが人間がこのラベルの存在を認識する必要はありません.1つの定理につき1つのラベル,「axiom:choice」がついていると思えばよいです.理由は後で説明します.
次の\IfNoValueTF{#3}{A}{B}も同じように条件分岐で,#3,つまりステートメントの名前がないときの処理がA,あるときの処理がBとなっています.それぞれ後ろでごちゃごちゃ書いてるのは再掲したときの枠のデザインを指定しています.再掲されるときに限りハイパーリンク付きの題名になっていてほしく,しかも【再掲】などとついてほしいのでこのデザインをここで指定しています.\g_ephraim_recallnum_seqの後の{}の中に再掲した際にどう出力されてほしいかを書きます.tcolorboxのオプションの#1colというのは例えばaxiom環境ならaxiomcolと文字列が置き換わるのでさきほど定義した色が使われることになります.LaTeXの仕様を利用してこのようにソースコードを短縮しています.
つぎも#3があるかないかで条件分岐してますがここは再掲ではなくほんちゃんの定理や命題を表示させる部分を記述します.実は\NewDocumentEnvironmentの仕様上「b」で環境内部の文章を引数とした場合その引数(今回なら#4)を表示させるコマンドを書かないと中身が表示されません.なので#4を囲む感じでtcolorbox環境を用意します.その際にステートメントの名前があるかないかで枠のデザインが若干変わるので条件分岐しています.

このつぎのstatementsp*環境は定理や命題の番号がないただの枠を作る場合の記述です.したがってこの中にstatementnumは現れません.当たり前ですが番号がないので相互参照用のラベルもつけません.つけることもできますが「命題」とだけ書かれたハイパーリンクを見せられても意味がないだろうという思想のもとで作っているので作りません.ちなみにこの場合でも再掲はできますが,するべきではないと考えます.再掲するほど議論が長くなったり価値の高いステートメントなら参照性の高さも担保されるべきなので番号をつけるべきでしょう.ということにしてめんどくさくなるのを回避します.

再掲コマンドの設定の解説

次にここ.

%Recall command
\NewDocumentCommand{\recallrefsp}{m}{
    % #1 is a list of labels
    \clist_map_inline:nn{#1}{
        \seq_item:Nn \g_ephraim_recallnum_seq{\getrefnumber{re#1}}
        \par
    }
}

ここは\recallrefspという再掲用コマンドです.最後の方の\getrefnumberで以前にrecallnumにつけたラベルを参照するとそれに伴う枠を出力します.ここで前にreとつけておけば人間側は「axiom:choice」というようなラベルが定理や定義ごとに1つずつついていると認識しておけばよく,実質1つの定理に1つのラベルがついている状態となります.つまりまとめると,ラベルを[choice]とつけたならあとから相互参照するときは「\refsp{axiom:choice}」と打てばよく,再掲するときは「\recallrefsp{axiom:choice}」と打てばよいのです.いいアイデアですね.これは友人が無料で教えてくれました.無料で.
axiomと付け忘れそうじゃない?と思われるかもしれませんがVScodeの予測変換で「あ~あの,ラベル名忘れたけど公理ではあったな.axiom:っと,,,」と打った段階で「axiom:choice」が候補に出てきて他の定理や命題といった公理ではないラベル名は候補から外れて劇的に探しやすくなります.どうしても慣れなければ勝手にaxiom:が付かないようにもできますが,そうすると今回の仕様上,相互参照の出力は「Axiom 1.1」といったようにはできません.
次の

\NewDocumentCommand{\printallsaved}{}{
    \seq_use:Nn \g_ephraim_recallnum_seq{\par}
}

は\printallsavedと打つと今までラベルを付けたものを一気に全部出力できます.すべて再掲用のデザインで出力されますが被りなく出力されます.

証明環境の実装

証明用の環境を書きます.これは囲ったり番号をつけたりしないので簡単です.

%Proof environment
\renewcommand{\proofname}{\textit{pf}.)} %Change first style of proof
\renewcommand{\qedsymbol}{$\blacksquare$} %Change end style of proof
\makeatletter
\renewenvironment{proof}[1][\proofname]{\par
    \pushQED{\qed}%
    \normalfont \topsep6\p@\@plus6\p@\relax
    \trivlist
    \item\relax
    {
        #1\@addpunct{}}\hspace\labelsep\ignorespaces
}{%
    \popQED\endtrivlist\@endpefalse
}
\makeatother

\newenvironment{pfsp}{\begin{proof}}{\end{proof}}

前半ふたつは証明の際に現れる最初の文字を変えています.はじめは(証明)と表示させたい場合や最後はQ.E.D.と表示させたい場合はここをいじります.
\makeatletterというのは@という記号を文字として認識させますという宣言です.これにより新たに定義するコマンドやパッケージで既定の@を含むコマンドをコマンドであると認識させることができます.@を他のアルファベットと同じ扱いにしますという宣言といってもいいですね.
\renewenvironmentの部分は正直よくわかってないのですがamsthmパッケージの公式マニュアルの11ページのものを改造しました.これは友人にやってもらいました.

\makeatotherというのは@をもとの扱いに戻します,という意味です.\makeatletterの効果をここで打ち消すのです.やらなくてもいいとは思いますが一応.

さいごに

解説はこれで終わりです.もっと細かく解説してくれ,とかこんな機能があったらさらにうれしい,とかこうすればもっとうまくいくんじゃ?とかがあれば何なりとお申し付けください.

この記事が気に入ったらサポートをしてみませんか?