这篇文章的诞生源于一个非常实际的原因:我发现,在包含大量数学知识的许多文档中,当然有很多交叉引用,但有时甚至很难记住引用的内容中说了什么。例如:如果你有一个证明,你说“然后从引理 7.12 中我们得到 f 在 (a,b) 中有一个最大值”,但作为读者的你甚至不记得引理 7.12 说了什么,因为你现在在第 16 章,而这个引理是 200 页之前的内容。
因此,我希望重新定义用于插入定理/引理/命题等的环境,以便您可以存储输入的内容\begin{theorem} ... \end{theorem}
,然后可以使用一个命令\marginpar
,该命令使用您存储该定理的标签,以便稍后在需要时在引用该定理的空白处打印它实际说的内容。这会有多难?
答案1
您可以使用restatable
由thmtools
包创建一个可以重述的定理。其工作原理如下:
- 你应该
\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}
输出: