スキップしてメイン コンテンツに移動

定理を再掲したときに定理番号も揃える(amsmathのtagと似た挙動の定理環境を作る).

LaTeXの話題です.amsmath.styで定義されているtagコマンドは,数式環境の式番号部分を自由な文字列で置き換えることができるようになっています.下に例を挙げます.

この画像を生成するLaTeXのコードは次のようになります.
\documentclass[a4paper,dvipdfmx,uplatex]{jsarticle}

\usepackage[dvipdfmx,bookmarks=true,bookmarksnumbered=true,%
,colorlinks=true,linkcolor=blue]{hyperref}%

\usepackage{showkeys}
\usepackage{amsmath}
\numberwithin{equation}{section}


\begin{document}

\section{amsmath.styに含まれるtagコマンドの挙動}

\begin{equation}
 \label{eq:euler}
e^{i\theta}=\cos\theta +i\sin\theta
\end{equation}

\eqref{eq:euler}


\section{amsmath.styに含まれるtagコマンドの挙動の検証}


\begin{equation}
  \label{eq:euler2}
  \tag{\ref{eq:euler}}
e^{i\theta}=\cos\theta +i\sin\theta
\end{equation}


\eqref{eq:euler2}

\end{document}
最初のequation環境にeq:eulerというlabelをつけ,第2のequation環境ではtagコマンドを使って数式番号部分に¥ref{eq:euler}と書くことで,実際に表示される式番号が第1のequation環境のものと同じになっています.この第2のequation環境にはeq:euler2というlabelを付けており,これを¥eqref{eq:euler2}と参照すると表示される番号は第1のequation環境のものであるにも関わらず,リンクをクリックすると第2のequation環境にジャンプします.

このような現象が起こるのは,上記のファイルをタイプセットして得られるauxファイルの記述を見てみるとわかります.以下はauxファイルのリンク作成に関係する部分を抜き出したものです.
\@writefile{toc}{\contentsline {section}{\numberline {1}amsmath.styに含まれるtagコマンドの挙動}{1}{section.1}}
\newlabel{eq:euler}{{1.1}{1}{amsmath.styに含まれるtagコマンドの挙動}{equation.1.1}{}}
\@writefile{toc}{\contentsline {section}{\numberline {2}amsmath.styに含まれるtagコマンドの挙動の検証}{1}{section.2}}
\newlabel{eq:euler2}{{{\ref  {eq:euler}}}{1}{amsmath.styに含まれるtagコマンドの挙動の検証}{equation.2.1}{}}
第1のequation環境のlabelから作成されたnewlabelには,最初の引数にlabel名が,第2の引数には数式番号が入力されています.第2のequation環境のlabelから作成されたnewlabelには,最初の引数にlabel名が入力されているのは同じですが,第2の引数に¥ref{eq:euler}という文字列が入力されていて,これが実行されることで第2のequation環境の数式番号部分が第1のものに置き換わるわけです.newlabelの2番めの引数部分は,labelコマンドを用いた時点での¥@currentlabelの値が入力されるので,これを変更することでrefコマンドを使った文字列を入力することができそうです.

以上のtagの性質は,例えば1つの文書内のある場所に数式を書いたものの,その場所とはかなり離れた部分で頻繁に参照する場合,もう一度同じ数式を書きたいが,数式番号は以前に記述したものと一致させたいとなったときに便利です.

同様に定理環境ついても1つの文書内のある場所で定理を証明し,遠く離れた場所でその定理を頻繁に参照するようなときに,定理を再掲するも定理番号は最初のものと一致させたいという場合があるのではないでしょうか.また定理番号は最初のものを使いますが,リンク先は再掲した定理の部分に飛ぶほうが文書を読みやすいと思います.そこで上記のtagコマンドと同じような挙動をする定理環境をでっち上げてみました.結果は次のようになりました.
showkeys.styを使ってlabel名や参照先を表示させています.hyperrefで使われるlabelを再定義するという力技を使っているため,定理番号を再利用している部分のlabel名はshowkeysでは表示できなくなってしまっています.ソースファイルは以下のようになりました.
\documentclass[a4paper,dvipdfmx,uplatex]{jsarticle}

\usepackage[dvipdfmx,bookmarks=true,bookmarksnumbered=true,%
bookmarkstype=toc,colorlinks=true,linkcolor=blue]{hyperref}%
\usepackage{nameref}

\usepackage{showkeys}
\usepackage{amsmath}
\numberwithin{equation}{section}
\usepackage{tcolorbox}
\usepackage{varwidth} 
\tcbuselibrary{breakable}
\tcbuselibrary{skins}
\tcbuselibrary{xparse} %内部でxparse.styを読み込むのでNewDocumentCommandなどが使える.

%定理環境の定理番号部分の背景色
\definecolor{tcbtitlebackcolor}{RGB}{52,48,39}


%%%定理環境の定義
\newcounter{theoi}
\newcounter{theoii}
\numberwithin{theoi}{section}% numberwithinはamsmathで定義されているので要amsmath.sty
\NewTColorBox{theobox}{o m o}{%oは省略可能な引数、mは必須の引数を表す。
%dは省略可能な引数でとで囲まれた部分を引数とする.
%#1=タイトル(省略可), #2=定理環境名, #3=定理番号部分を再利用したいときに\refコマンドを入れる.
enhanced,
coltitle=white,fonttitle=\bfseries\sffamily,
colbacktitle=tcbtitlebackcolor,
colback=white,
extras broken={%
colback=white,
frame empty,
},
breakable=true,
borderline={0.5mm}{0mm}{tcbtitlebackcolor},
leftrule=0pt,rightrule=0pt,
sharp corners=all,
boxsep=1mm,
before skip=3mm,
attach boxed title to top left={yshift*=-\tcboxedtitleheight-2.5mm},
boxed title style={sharp corners=all,toprule=0pt,bottomrule=0pt,leftrule=0pt,rightrule=0pt,
},
IfValueTF={#3}{%3つ目のオプション引数がある場合はタイトルの番号部分を書き換える。
IfNoValueTF={#1}{title={#2~#3.}}{title={#2~#3\,:~{#1}}}%
}%
{%
IfNoValueTF={#1}{title={#2~\thetheoi.}}{title={#2~\thetheoi\,:~{#1}}}%
},%
pad after break=-4.1mm, %breakした後の空きの調整
}

%% nameref.styのlabelコマンドの\@currentlabel部分を再利用するラベルで書き換えたものを
%% \my@labelというコマンドで定義する.
\makeatletter
\newcommand{\my@reuselabel}[1]{
\def\my@label##1{%
  \@bsphack
  \begingroup
    \def\label@name{##1}%
    \label@hook
    \protected@write\@auxout{}{%
      \string\newlabel{##1}{%
      % {\@currentlabel}%
        {#1}% \@currentlabelの部分に再利用するラベルを入れる
        {\thepage}%
        {\@currentlabelname}%
        {\@currentHref}{}%
      }%
    }%
  \endgroup
  \@esphack
}%
\ifNR@showkeys% showkeys.styを読み込んだときの対策
  \def\my@label##1{%
    \@bsphack
    \SK@\SK@@label{##1}%
    \begingroup
      \def\label@name{##1}%
      \label@hook
      \protected@write\@auxout{}{%
        \string\newlabel{##1}{%
 % {\@currentlabel}%
          {#1}% \@currentlabelの部分に再利用するラベルを入れる
          {\thepage}%
          {\@currentlabelname}%
          {\@currentHref}{}%
        }%
      }%
    \endgroup
    \@esphack
  }%
\fi
}

\NewDocumentEnvironment{theorem}{o m d<>}{%NewDocumentEnvironmentはxparse.styで定義されている。
 \IfValueTF{#3}{%
\let\my@@label=\label% \my@@labelに\labelをコピー
\my@reuselabel{#3}% 再利用するlabel名
\let\label=\my@label% labelコマンドを再定義
\my@reuselabel{#3}
\refstepcounter{theoii}
}{\refstepcounter{theoi}}
\begin{theobox}[#1]{#2}[#3]}{\end{theobox}
\IfValueT{#3}{\let\label=\my@@label}% labelコマンドを元に戻す。
}
\makeatother

\NewDocumentEnvironment{theo}{o d<>}{% 再利用するラベルは<>の中に入れる。
\begin{theorem}[#1]{定理}<#2>
}{\end{theorem}}

\NewDocumentEnvironment{prop}{o d<>}
{\begin{theorem}[#1]{命題}<#2>%
}{\end{theorem}}

\NewDocumentEnvironment{lem}{o d<>}
{\begin{theorem}[#1]{補題}<#2>%
}{\end{theorem}}


\NewDocumentEnvironment{coro}{o d<>}
{\begin{theorem}[#1]{系}<#2>%
}{\end{theorem}}




\begin{document}

\section{定理環境の再利用}

\begin{theo}[主定理]
\label{theo}
定理1~\fbox{\texttt{theo}}
\end{theo}

\begin{prop}
\label{prop:1}
命題1
\end{prop}

\begin{lem}
補題1
\end{lem}


\begin{theo}[主定理コピー]<\ref{theo}>
\label{theo:2}
定理2~\fbox{\texttt{theo:2}}
\end{theo}

\begin{coro}[主定理の系]
\label{coro:1}
系1
\end{coro}

定理~\ref{theo}

定理~\ref{theo:2}, 

命題~\ref{prop:1}, 

系~\ref{coro:1}


\pagebreak

\section{定理環境の再利用2}

\begin{prop}
\label{prop:2}
 命題2
\end{prop}

\begin{theo}[主定理コピー]<\ref{theo}>
\label{theo:3}

定理3~\fbox{\texttt{theo:3}}
\end{theo} 

\begin{theo}[主定理コピー]<\ref{theo:2}>
\label{theo:4}

定理4~\fbox{\texttt{theo:4}}
\end{theo} 

命題~\ref{prop:2}

定理~\ref{theo}, 

定理~\ref{theo:2}, 

定理~\ref{theo:3}, 

定理~\ref{theo:4}, 

\end{document}
上のソースファイルでは,hyperref.styのlabelコマンドの定義が書かれているnameref.styの該当部分をそのままコピーし,¥@currentlabel部分をrefコマンドで無理矢理書き換えるという操作を行っています.これで目的の挙動をする定理環境ができたのですが,考えてみればあまり使わないかもしれません.

このブログの人気の投稿

OpenCv-PythonとpdfLaTeXで自炊pdfファイルの位置調整

この記事は TeX & LaTeX Advent Calendar 2021 の11日目の記事です. 10日目は t_kemmochi さん,12日目は yukishita さんです.   動機  書籍の自炊にブックエッジスキャナーの AvisionのFB2280E を利用しています。書籍を裁断せずに1ページずつスキャンを行うため、本の開き具合などの要因で本の序盤、中盤、終盤で得られるスキャン画像の位置ずれが大きくなります。以前からpdfLaTeXを利用して位置調整をしていたのですが、OpenCvを利用して自動化できそうだったので試してみました。 やること 本記事では、pdf化した文書画像の版面(文字の印刷された部分の意味で使います)を半自動的に計算してpdfの画像の位置調整をするために、OpenCvとpdfLaTeXを利用する方法を解説します。手順としては Pythonの画像認識用ライブラリであるOpenCvを利用して版面を計算する。 テンプレートエンジンライブラリのJinja2を使って画像のバウンディングボックスなどを記述したLaTeXファイルを作成する。 pdfLaTeXでpdfを読み込み、位置の調整されたpdfを作成する。 という流れになっています。作業環境としては、 Visual Studio CodeをRemove - WSL拡張機能と併用 しています。PythonやそのライブラリはWSL上のUbuntuにインストールし、他にもpdfファイルを他のファイル形式にするためにpoppler-utilsなんかもインストールしました。 参考記事 OpenCvを利用した文書画像のレイアウト解析については ブログSomething Like Programming内の記事 Document Layout Analysis githubリポジトリ rbaguila/document-layout-analysis OpenCv-Pythonチュートリアル を参考にしました。 pdfLaTeXがpdf加工に使えるという話と、pdfpagesパッケージの存在は doraTeXさんのブログTeX Alchemist Onlineの記事 pdfTeX による見開きPDFの結合・分割 で知ったように思います。 画像pdfをpdfpagesで取り込む ま...

定理環境をmdframedからtcolorboxへ乗り換え

追記:2016/05/02 以前に掲載していた定理環境のマクロでは、カウンターが変化しないような記述をしてしまっていたので、全面的に書き換えました。 追記:2016/06/06 tcolorboxのオプションを追加できるように書き直しをしました( tcolorboxを使った定理環境 )。 LaTeXの話です。 これまで定理環境の修飾にmdframed.styを利用してきました。 mdframedを用いた定理環境の修飾(platex+dvipdfmx, tikz) しかし上の投稿で用いた記述をしていると、定理環境がページの下部にきたとき、まれに以下のように環境が新しいページに送られてしまい変なところで改ページが起こります。 TeX-LaTeX Stack Exchangeでも同様の不具合が報告されていて、mdframed.styの作者が回答して解決しているようなのですが、私の場合は上手く行きませんでした。タイトル部分の位置の計算に問題があるようです。 そういう訳で、mdframed.styよりも高い表現力を持つtcolorbox.styには興味を持っていました。今回は、mdframed.styで記述していた部分を、ソースの変更無しにtcolorboxで置き換えてみたので、その紹介をします。 tcolorbox.styで置き換えた結果は次のようになりました。 見た目はほとんど変わっていません。中のboxは別のtcolorbox環境です。 この定理環境のソースコードは次のようになります。 \usepackage{tcolorbox} \usepackage{varwidth} \tcbuselibrary{breakable} \tcbuselibrary{skins} \definecolor{frameinnercolor}{RGB}{49,44,44} \newcounter{theorem} \numberwithin{theorem}{section}% numberwithinはamsmath.styで定義されている \newenvironment{theorem}[2][]{% %#1 = タイトル, #2 = 定理環境名 \refstepcounter{theorem}% \newtcolorbox{...