重新定义定理环境以保存其内容

重新定义定理环境以保存其内容

这篇文章的诞生源于一个非常实际的原因:我发现,在包含大量数学知识的许多文档中,当然有很多交叉引用,但有时甚至很难记住引用的内容中说了什么。例如:如果你有一个证明,你说“然后从引理 7.12 中我们得到 f 在 (a,b) 中有一个最大值”,但作为读者的你甚至不记得引理 7.12 说了什么,因为你现在在第 16 章,而这个引理是 200 页之前的内容。

因此,我希望重新定义用于插入定理/引理/命题等的环境,以便您可以存储输入的内容\begin{theorem} ... \end{theorem},然后可以使用一个命令\marginpar,该命令使用您存储该定理的标签,以便稍后在需要时在引用该定理的空白处打印它实际​​说的内容。这会有多难?

答案1

您可以使用restatablethmtools包创建一个可以重述的定理。其工作原理如下:

  • 你应该\usepackage{thmtools}在你的序言中添加内容。
  • 你不需要使用,而\begin{theorem}..\end{theorem}需要将定理表述为

    \begin{restatable}[<name>]{theorem}{<macro name>}<thm contents>\end{restatable}

  • 然后,您可以将定理的副本放在文档中\<macro name>*(环境的最后一个参数restatable,前面是 a \,后面是 a *),但这只能完成由于不使用辅助文件,因此陈述了该定理。您不能复制文档中稍后出现的定理。

请参阅文档了解更多信息。


这似乎有点不令人满意,所以我编写了一些代码,应该可以让它完全按照您描述的方式工作。这仍然使用来自的重述机制thmtools,但它将定理内容存储在辅助文件中而不是宏中,并且您可以使用分配给定理的标签名称来重述它。

工作原理如下:

  • 您需要在序言中添加一大块代码(下面的“定义”部分)
  • 如果一个定理有一个标签,比如说\label{thm:mythm},你现在可以用 来重述它\restate{thm:mythm}。要把它放在边距中,你可以使用\restateinmargin{thm:mythm},如果你想要\ref定理将 一份 副本 放在 您 可以使用 的 页边距 处\restateref{thm:mythm}.
  • 你至少需要运行 LaTeX三次

代码如下:

\documentclass{article}

%%---------------------%%
%%     Definitions     %%
%%---------------------%%

\usepackage{amsthm} %% <- also works without amsthm, or with ntheorem
\usepackage{thmtools}

\makeatletter                 %% <- change @ so that it can be used in command names
  \newif\ifrthm@restating     %% <- changes behaviour of theorem environment when we restate
  \newcounter{rthm@ctr}       %% <- generates unique ids for theorems
  \addtotheorempostheadhook{% %% <- executed at \begin{theorem}
    \ifrthm@restating\else    %% <- if this is the actual theorem
      \thmt@thisistheonetrue  %% <- tell thm-restate/thmtools this is not a copy
      \thmt@restatethistrue   %% <- pretend a restate=... key+val was passed
      \stepcounter{rthm@ctr}% %% <- unique id
      \ifdefined\rthm@originallabel\else %% <- test if \label was already redefined, to be safe
        \let\rthm@originallabel\label
        \renewcommand*\label[2][]{% %% <- %% Optional argument is just there for cleveref
          \protected@edef\rthm@lastlabelname{#2}%
          \if\relax\detokenize{#1}\relax\@xa\@firstoftwo\else\@xa\@secondoftwo\fi
            {\rthm@originallabel{#2}}{\rthm@originallabel[#1]{#2}}%
        }                     %% <- redefine label to extract its name
      % \let\rthm@lastlabelname\relax %% <- unnecessary because rthm@restating contains a \label
      \fi
      \protected@edef\tmp@a{% %% <- perform some expansions first
        \@nx\@xa\@nx\thmt@restatable\@nx\@xa[\@nx\thmt@optarg]%
          {\thmt@envname}{restate\arabic{rthm@ctr}}%
      }%
      \@xa\tmp@a              %% <- now call thmt@restatable from thm-restate/thmtools
    \fi
  }

  %% Write theorem contents and counter values to the aux file
  \addtotheoremprefoothook{% %% <- executed at \end{theorem}
    \ifrthm@restating\else   %% <- if this is the actual theorem
      \@for\rthm@temp:=\rthm@labellist\do{% %% <- loop over requested theorems
        \ifx\rthm@lastlabelname\rthm@temp   %% <- if this is one of them
          \immediate\write\@auxout{%        %% <- write it to the aux file
            \global\string\@namedef{rthmbody@\rthm@lastlabelname}%
              {\@xa\@xa\@xa\unexpanded\@xa\@xa\@xa
                {\csname thmt@stored@restate\arabic{rthm@ctr}\endcsname}}%
          }%
          \let\rthm@lastlabelname\relax     %% <- don't do this more than once
        \fi
      }%
    \fi
  }

  %% This restates a theorem
  \def\rthm@newlabellist{}
  \def\rthm@labellist{}
  \AtEndDocument{\immediate\write\@auxout{\global\def\string\rthm@labellist{\rthm@newlabellist}}}%
  \newcommand\restate[1]{\ifrthm@restating\else\begingroup
      \rthm@restatingtrue     %% <- we are restating
      \thmt@thisistheonefalse %% <- tell thm-restate/thmtools this is a copy
      \@nameuse{rthmbody@#1}% %% <- restate the theorem using macro from aux file
      \xdef\rthm@newlabellist{\rthm@newlabellist,{#1}}
    \endgroup\fi}
  %% Same thing, but in the margin
  \newcommand\restateinmargin[1]{%
    \ifrthm@restating\else
      \marginpar{\small\restate{#1}}%
    \fi
  }
  %% Combine \ref and \restateinmargin
  \newcommand\restateref{\@ifstar\restaterefstar\restaterefnostar}
  \newcommand\restaterefstar[1]{\ref*{#1}\restateinmargin{#1}}
  \newcommand\restaterefnostar[1]{\ref{#1}\restateinmargin{#1}}
\makeatother %% <- change @ back

%%---------------------%%
%%    /Definitions     %%
%%---------------------%%

\usepackage{hyperref} %% <- optional
\usepackage[hmargin={3cm,6cm},marginparwidth=4cm]{geometry} %% <- just for the margins
\usepackage{amsmath} %% <- for \numberwithin, \lvert and \rvert
\numberwithin{equation}{section}

\newtheorem{theorem}{Theorem}[section]

\begin{document}

\section{First section}

\noindent Theorem~\restateref{thm:paradox} and Theorem~\restateref{thm:isitthough?} are problematic.

\begin{theorem}[Burnside's lemma] \label{thm:burnside}
    Let $G$ be a finite group that acts on a finite set $X$, then
    \begin{equation}
        \lvert X / G \rvert = \frac1{\lvert G\rvert} \sum_{g \in G} \lvert X^g \rvert,
    \end{equation}
    where $X^g$ denotes the set of points of $X$ that are fixed by $g$.
\end{theorem}

\section{Second section}

\begin{theorem} \label{thm:isitthough?}
    This statement is true
\end{theorem}

\begin{theorem} \label{thm:paradox}
    This theorem is false.
\end{theorem}

\noindent Theorem~\restateref{thm:burnside} is pretty nice.

\end{document}

输出

在底层,我只是从thm-restate包(加载并由加载thmtools)调用几个命令,并将结果写入辅助文件。您需要运行 LaTeX 三次的原因是,只有那些实际被重述的定理才会\restate被写入辅助文件:在第一次运行期间,我们收集了重述的定理,在第二次运行期间,这些定理被写入辅助文件,以便在第三次运行期间可以重述它们。

编辑:答案得到了显着改善(几次):

  • 它现在加载thmtools包,而不是从中“窃取”代码
  • 现在可以在定理环境中使用(并重新陈述包含不会导致循环的\restate(ref)定理),\restate
  • 只有你已经研究过的那些定理\restate才会写入辅助文件中。

编辑:在页边重申定理时,若要抑制方程编号,请使用

\newcommand\restateinmargin[1]{%
  \ifrthm@restating\else
    \marginpar{\everydisplay\expandafter{\the\everydisplay\nonumber}\small\restate{#1}}%
  \fi
}

而不是上面提供的定义\restateinmargin。(需要amsmath。)

答案2

以下是我评论中建议的简短实施:

我编写了一个名为 的宏\NewTheorem,它是 的包装器\newtheorem,期望的参数与 相同\newtheorem。它创建一个环境,该环境是 所创建环境的包装器\newtheorem。此包装器环境接受一个可选参数(与 所创建的环境一样\newtheorem)并需要两个附加参数。第一个附加参数是标签,第二个是简短描述。

然后,您可以使用\TheoremRef作为可选参数的定理来引用该定理,该参数接受引用宏(默认情况下\ref),并要求提供定理的标签。它将引用放在文本中,并且(如果定理已知)创建一个\marginpar包含该定理简短描述的文本。

它需要两次传递才能正常工作并将信息写入辅助文件。

\documentclass[twoside]{article}

\usepackage[]{amsmath}
\usepackage{amsthm}

\newtheorem{theorem}{Theorem}

\makeatletter
\newcommand\NewTheorem[2]
  {%
    \newtheorem{#1@core}{#2}%
    \newenvironment{#1}[3][]
      {%
        \begin{#1@core}[##1]%
          \label{##2}%
          \protected@write \@auxout {}
            {%
              \string\expandafter\gdef
              \string\csname\space ##2@Theorem@ShortDescription\endcsname
                {##3}%
            }%
          \protected@write \@auxout {}
            {%
              \string\expandafter\gdef
              \string\csname\space ##2@Theorem@Type\endcsname{#2}%
            }
          \if\relax\detokenize{##1}\relax
          \else
            \protected@write \@auxout {}
              {%
                \string\expandafter\gdef
                \string\csname\space ##2@Theorem@Name\endcsname{##1}%
              }%
          \fi
      }
      {%
        \end{#1@core}%
      }%
  }
\newcommand*\TheoremRef[2][\ref]
  {%
    #1{#2}%
    \ifcsname #2@Theorem@ShortDescription\endcsname
      \marginpar
        {%
          \csname #2@Theorem@Type\endcsname\space\ref{#2}%
          \ifcsname #2@Theorem@Name\endcsname
            \space(\csname #2@Theorem@Name\endcsname)%
          \fi
          :\\
          \csname #2@Theorem@ShortDescription\endcsname
        }%
    \fi
  }
\makeatother
\NewTheorem{lem}{Lemma}

\begin{document}
\begin{lem}[foo]{lem:test}{The testing lemma}
  This lemma is just for testing purposes, to see whether everything works
\end{lem}
As shown by lemma \TheoremRef{lem:test} you can see that this works.
\end{document}

输出:

在此处输入图片描述

相关内容