可重述定理周围的额外空间

可重述定理周围的额外空间

我正在学习如何使用 thmtools 包,遇到了一个奇怪的怪癖。一个简单的例子如下:

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}

\declaretheorem{theorem}

\begin{document}

\begin{restatable*}{theorem}{mythm}
This is a restated theorem.
\end{restatable*}


\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm
\mythm
\mythm

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm*
\mythm*
\mythm*

\end{document}

当我编译此代码时,重新陈述和重新编号的定理(\mythm 命令)上方有多余的空间。这些定理下方没有多余的空间(如您在定理 5 和 6 之间看到的)。\mythm* 命令不会创建任何多余的空间。

实际上,restatable* 环境将用于在论文开头陈述结果。只会有一个附带的 \mythm 命令(并且可能有任意数量的 \mythm* 命令)。因此,这个额外的空间只会成为一次问题。不过,我想知道这里发生了什么。

在此处输入图片描述

答案1

我在宏定义中添加了一行\thmt@rst@storecounters:硬连线\vspace. 它可能不漂亮,但可以完成工作。(已编辑以修复较小的例程,从而占用更少的空间。原始帖子已将相同的修复应用于更长的环境thmt@restatable。)

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}

\makeatletter

\def\thmt@rst@storecounters#1{%
%THIS IS THE LINE I ADDED:
\vspace{-1.9ex}%
  \bgroup
        % ugly hack: save chapter,..subsection numbers
        % for equation numbers.
  %\refstepcounter{thmt@dummyctr}% why is this here?
  %% temporarily disabled, broke autorefname.
  \def\@currentlabel{}%
  \@for\thmt@ctr:=\thmt@innercounters\do{%
    \thmt@sanitizethe{\thmt@ctr}%
    \protected@edef\@currentlabel{%
      \@currentlabel
      \protect\def\@xa\protect\csname the\thmt@ctr\endcsname{%
        \csname the\thmt@ctr\endcsname}%
      \ifcsname theH\thmt@ctr\endcsname
        \protect\def\@xa\protect\csname theH\thmt@ctr\endcsname{%
          (restate \protect\theHthmt@dummyctr)\csname theH\thmt@ctr\endcsname}%
      \fi
      \protect\setcounter{\thmt@ctr}{\number\csname c@\thmt@ctr\endcsname}%
    }%
  }%
  \label{thmt@@#1@data}%
  \egroup
}%

\makeatother

\declaretheorem{theorem}

\begin{document}

\begin{restatable*}{theorem}{mythm}
This is a restated theorem.
\end{restatable*}

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm
\mythm
\mythm

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm*
\mythm*
\mythm*

\end{document}

在此处输入图片描述

答案2

您的解决方案的问题在于,restatable 仅在其前面有另一个环境时才会引入额外空格。在其他情况下,空格是正确的,应避免使用 \vspace。

通过多次实验,似乎罪魁祸首是\label{thmt@@#1@data}in \thmt@rst@storecounters。通过删除该\label命令,间距是正确的,但其他东西可能会出错。我的解决方案(这些天我正在测试)是将调用移至\thmt@rst@storecountersin 。这是我现在正在测试\thmt@restatable的版本:\thmt@restatable

\renewenvironment{thmt@restatable}[3][]{%
  \thmt@toks{}% will hold body
  \stepcounter{thmt@dummyctr}% used for data storage label.
  \long\def\thmrst@store##1{%
    \@xa\gdef\csname #3\endcsname{%
      \@ifstar{%
        \thmt@thisistheonefalse\csname thmt@stored@#3\endcsname
      }{%
        \thmt@thisistheonetrue\csname thmt@stored@#3\endcsname
      }%
    }%
    \@xa\long\@xa\gdef\csname thmt@stored@#3\@xa\endcsname\@xa{%
      \begingroup
      \ifthmt@thisistheone
        % nothing here in my patched version
      \else
        % this one should use other numbers...
        % first, fake the theorem number.
        \@xa\protected@edef\csname the#2\endcsname{%
          \thmt@trivialref{thmt@@#3}{??}}%
        % if the number wasn't there, have a "re-run to get labels right"
        % warning.
        \ifcsname r@thmt@@#3\endcsname\else
          \G@refundefinedtrue
        \fi
        % prevent stepcountering the theorem number,
        % but still, have some number for hyperref, just in case.
        \@xa\let\csname c@#2\endcsname=\c@thmt@dummyctr
        \@xa\let\csname theH#2\endcsname=\theHthmt@dummyctr
        % disable labeling.
        \let\label=\@gobble
        \let\ltx@label=\@gobble% amsmath needs this
        % We shall need to restore the counters at the end
        % of the environment, so we get
        % (4.2) [(3.1 from restate)] (4.3)
        \def\thmt@restorecounters{}%
        \@for\thmt@ctr:=\thmt@innercounters\do{%
          \protected@edef\thmt@restorecounters{%
            \thmt@restorecounters
            \protect\setcounter{\thmt@ctr}{\arabic{\thmt@ctr}}%
          }%
        }%
        % pull the new semi-static definition of \theequation et al.
        % from the aux file.
        \thmt@trivialref{thmt@@#3@data}{}%
      \fi
      % call the proper begin-env code, possibly with optional argument
      % (omit if stored via key-val)
      \ifthmt@restatethis
        \thmt@restatethisfalse
      \else
        \csname #2\@xa\endcsname\ifx\@nx#1\@nx\else[{#1}]\fi
      \fi
      \ifthmt@thisistheone
         % these are the valid numbers, store them for the other
         % occasions.
         \thmt@rst@storecounters{#3}%
        % store a label so we can pick up the number later.
        \label{thmt@@#3}%
      \fi
      % this will be the collected body.
      ##1%
      \csname end#2\endcsname
      % if we faked the counter values, restore originals now.
      \ifthmt@thisistheone\else\thmt@restorecounters\fi
      \endgroup
    }% thmt@stored@#3
    % in either case, now call the just-created macro,
    \csname #3\@xa\endcsname\ifthmt@thisistheone\else*\fi
    % and artificially close the current environment.
    \@xa\end\@xa{\@currenvir}
  }% thm@rst@store
  \thmt@collect@body\thmrst@store
}{%
  %% now empty, just used as a marker.
}

答案3

有一种简单的方法可以解决这个问题,虽然不是那么普遍,但(在我看来)是最自然的情况,即定理一出现就会得到一个数字,并且所有重述都有相同的数字。所以情况是:

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}

\declaretheorem{theorem}

\begin{document}

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{restatable}{theorem}{mythm}
This is a restated theorem.
\end{restatable}

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm*
\mythm*
\mythm*

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm*
\mythm*
\mythm*

\end{document}

1

我使用 而\begin{theorem}[restated = mythm, name = ]不是 来修复它\begin{restatable}{theorem}{mythm}

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}

\declaretheorem{theorem}

\begin{document}

\begin{theorem}
This is a regular theorem.
\end{theorem}

% If you have only restate argument then the name argument value will be , (comma),
% so you need to specify any other argument
\begin{theorem}[restate = mythm, name = ]\label{Thm:my}
This is a restated theorem.
\end{theorem}

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm*
\mythm*
\mythm*

\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}
\begin{theorem}
This is a regular theorem.
\end{theorem}

\mythm*
\mythm*
\mythm*

\end{document}

2

答案4

总结:etoolbox这是一个依赖于和的修复hyperref

\usepackage{etoolbox}
\usepackage{hyperref}
\usepackage{thm-restate}

\makeatletter
\pretocmd{\thmt@rst@storecounters}{\Hy@SaveLastskip}{}{}
\apptocmd{\thmt@rst@storecounters}{\Hy@RestoreLastskip}{}{}
\makeatother

etoolbox请参阅下文以了解不依赖于额外包的(更长)版本hyperref以及完整的工作示例。


正如 Gianlu 所指出的,问题在于\label\thmt@rst@storecounters这是因为基本上两个定理(或证明、引理等)之间的任何内容都会弄乱定理间的间距。

这个问题和答案是关于同一个问题的。答案建议使用hyperref包中的两个内部宏:\Hy@SaveLastskip\Hy@RestoreLastskip。为了解决这个问题,我们要把放在\Hy@SaveLastskip前面\label\Hy@RestoreLastskip后面。

上述代码加载了hyperref,它提供了前面提到的宏,和etoolbox,它提供了一种将它们添加到 的开始(pretocmd)和 的结束(apptocmd)的方法,而\thmt@rst@storecounters无需复制整个定义。

可以通过以下方式避免使用额外的包:(1)从复制\Hy@SaveLastskip和的定义,以及 (2) 手动重新定义,主要是从 复制原始内容。如下所示。\Hy@RestoreLastskiphyperref\thmt@rst@storecountersthm-restate

% Instead of loading `hyperref`
\def\Hy@SaveLastskip{%
  \let\Hy@RestoreLastskip\relax
  \ifvmode
    \ifdim\lastskip=\z@
      \ifnum\lastnodetype=1 %
        \let\Hy@RestoreLastskip\relax
      \else
        \let\Hy@RestoreLastskip\nobreak
      \fi
    \else
      \begingroup
        \skip@=-\lastskip
        \edef\x{%
          \endgroup
          \def\noexpand\Hy@RestoreLastskip{%
            \noexpand\ifvmode
              \noexpand\nobreak
              \vskip\the\skip@
              \vskip\the\lastskip\relax
            \noexpand\fi
          }%
        }%
      \x
    \fi
  \else
    \ifhmode
      \ifdim\lastskip=\z@
        \let\Hy@RestoreLastskip\nobreak
      \else
        \begingroup
          \skip@=-\lastskip
          \edef\x{%
            \endgroup
            \def\noexpand\Hy@RestoreLastskip{%
              \noexpand\ifhmode
                \noexpand\nobreak
                \hskip\the\skip@
                \hskip\the\lastskip\relax
              \noexpand\fi
            }%
          }%
        \x
      \fi
    \fi
  \fi
}

% Instead of loading `etoolbox`
\def\thmt@rst@storecounters#1{%
  %%% NEW ADDITION:
  \Hy@SaveLastskip
  \bgroup
  \def\@currentlabel{}%
  \@for\thmt@ctr:=\thmt@innercounters\do{%
    \thmt@sanitizethe{\thmt@ctr}%
    \protected@edef\@currentlabel{%
      \@currentlabel
      \protect\def\@xa\protect\csname the\thmt@ctr\endcsname{%
        \csname the\thmt@ctr\endcsname}%
      \ifcsname theH\thmt@ctr\endcsname
        \protect\def\@xa\protect\csname theH\thmt@ctr\endcsname{%
          (restate \protect\theHthmt@dummyctr)\csname theH\thmt@ctr\endcsname}%
      \fi
      \protect\setcounter{\thmt@ctr}{\number\csname c@\thmt@ctr\endcsname}%
    }%
  }%
  \label{thmt@@#1@data}%
  \egroup
  %%% NEW ADDITION:
  \Hy@RestoreLastskip
}

完整工作示例: 在此处输入图片描述

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}
\usepackage{hyperref}
\usepackage{etoolbox}

\declaretheorem{theorem}

\makeatletter
\newcommand{\fixit}{%
  \pretocmd{\thmt@rst@storecounters}{\Hy@SaveLastskip}{}{}
  \apptocmd{\thmt@rst@storecounters}{\Hy@RestoreLastskip}{}{}
}
\makeatother

\newcommand{\demo}{%
  \begin{restatable*}{theorem}{mythm}
    This is a restated theorem.
  \end{restatable*}

  \begin{theorem}
    This is a regular theorem.
  \end{theorem}
  \begin{theorem}
    This is a regular theorem.
  \end{theorem}

  \mythm
  \mythm
  \mythm

  \begin{theorem}
    This is a regular theorem.
  \end{theorem}
  \begin{theorem}
    This is a regular theorem.
  \end{theorem}
  \begin{theorem}
    This is a regular theorem.
  \end{theorem}

  \mythm*
  \mythm*
  \mythm*
}

\begin{document}

% Original
\demo
% Implement the patch
\fixit
% Visual separation between original and fixed demos
\bigskip\hrule\bigskip
% Reset theorem counter so the two demos use the same numbers
\setcounter{theorem}{0}
% Fixed
\demo

\end{document}

相关内容