1

I have a longer book written in memoir using many theorems defined by ntheorem. I would like to check if I correctly restated all theorems (done with the help of thm-restate) in later chapters.

\documentclass{memoir}
\usepackage{ntheorem}
\usepackage{thm-restate}

\newtheorem{theorem}{Theorem}

\begin{document}

\chapter{One}

\begin{restatable}{theorem}{thone}
Blah
\end{restatable}

\begin{restatable}{theorem}{thtwo}
Blah
\end{restatable}

%Does not count within the same chapter:
\thone*
\thtwo*


\chapter{Two}

\thone*
%thtwo* is missing here!

\end{document}

Printing the full list of theorems does not really help: I would need to check every theorem nevertheless. What I need is a list of theorems which are restatable, but were never restated in a later chapter. Is this possible?

Alternatively, maybe can I get an error if something was declared restatable, but was never restated?

  • You should mention that you use the thm-restate package also. Or you make your example compilable, which would be even better. – Ruben Sep 17 '17 at 9:11
  • Thanks, I also mentioned thm-restate. I was not sure which parts are actually relevant (e.g. memoir?). Btw. seems like the solution is not 100% complete. It does not check if a theorem was restated within "One" but not in later chapters. But I can remove the restated commands within "One" manually, so it isn't a big issue. Thanks again! – markus23 Sep 17 '17 at 23:46
  • So you want to be able to check chapterwise? This would be a relevant information, as well as which packages and which class you use to produce your mwe. Ideally your example would start with \documentclass... and end with \end{document]. – Ruben Sep 18 '17 at 0:05
  • Checking chapterwise should be trivial with your code (print and reset counters?). But the check should be the following way: For any theorem, was it restated in a chapter after its introduction. I updated the example, it is a MWE now. – markus23 Sep 18 '17 at 10:10
  • So, you need to check from the next chapter on regarding to where the theorem was introduced? (This should be possible with a little bit of counter juggling.) – Ruben Sep 18 '17 at 10:19
3

This solution provides a patch to the restatable environment that creates two lists that contain 1) all restatable theorems (\listofrestatable) and 2) all actually restated theorems (\listofrestatated) - which is done with the following steps.

Let #2 and #3 be the macro inputs of the restatable environment. Then:

  1. Append the current theorem name and its theorem-environment-name to a token register.

    \g@addto@toks\listofrestatable{\process@comma#3 (#2)}
    

    where \g@addto@toks is an auxiliary macro to append tokens to a token register and \process@comma is an auxiliary macro to make sure that the commas in the list are processed correctly.

  2. Define a dedicated \add@restated@<restatable thm> macro that disables itself after its first use to make sure that the \listofrestated does not contain duplicate entries.

    \global\@namedef{add@restated@#3}{%
      \g@addto@toks\listofrestatated{#3; }%
      \global\cslet{add@restated@#3}{\relax}%
    }
    
  3. Prepend the last macro to the definition of \<restatable thm>(in your example \aTheorem): \csgpreto{#3}{\@nameuse{add@restated@#3}}.

  4. Create a debugging chapter in the end as follows to check the lists.

    \chapter{Debugging}
    \typeout{restatable: \the\listofrestatable}
    List of restatable theorems: \the\listofrestatable
    
    \vspace{1pc}
    
    \typeout{restatated: \the\listofrestatable}
    \noindent
    List of restatated theorems: \the\listofrestatated
    

Note that in my example (the complete code is below) I created two other restatable theorems 'bTheorem' and 'cTheorem' for testing purposes.

debug_showcase

Addionally and finally you can use all this to check for theorems that were not restated by looping over all restatable theorems and check if the corresponding \<restatable thm> was let to \relax which would mean that it was restated (see above):

\def\notrestated{}
\def\checknotrestated{%
  \@for\@rthm:=\the\@toks@restatable\do{%
    \ifx\@rthm\@empty\else
      \expandafter\ifx\csname add@restated@\@rthm\endcsname\relax\else
        \xdef\notrestated{\notrestated\@rthm; }\fi
    \fi
  }
  \ifx\notrestated\empty\else
    \par\vspace{1pc}\par\noindent
    Warning! -- There were theorems that have not been restated: \notrestated
    \@latex@warning{There were theorems that have not been restated: \notrestated}%
\fi
}

This would require a little bit of preparation beforehand, i.e. the \@toks@restatable register that contains the restatable theorem names only:

...
\makeatletter
\long\def\g@addto@toks#1#2{\global#1\expandafter{\the#1#2}}
\newtoks\@toks@restatable
\newtoks\listofrestatable
...
\renewenvironment{restatable}[3][]{%
  \g@addto@toks\@toks@restatable{#3,}%
...

The \checknotrestated macro could then be used in the debugging chapter in the end.

\chapter{Debugging}
\typeout{restatable: \the\listofrestatable}
List of restatable theorems: \the\listofrestatable

...

\checknotrestated

This would add the expected output:

Warning! – There were theorems that have not been restated: bTheorem; cTheorem;

Complete Code

\documentclass{memoir}
\usepackage{ntheorem}
  \newtheorem{theorem}{Theorem}
\usepackage{thm-restate}
\usepackage{etoolbox}

\makeatletter
\long\def\g@addto@toks#1#2{\global#1\expandafter{\the#1#2}}
\newtoks\@toks@restatable
\newtoks\listofrestatable
\newtoks\listofrestatated
\let\tre@restatable\restatable
\let\tre@endrestatable\endrestatable
\renewenvironment{restatable}[3][]{%
  \g@addto@toks\@toks@restatable{#3,}%
  \g@addto@toks\listofrestatable{\process@comma#3 (#2)}%
  \global\@namedef{add@restated@#3}{%
    \g@addto@toks\listofrestatated{#3; }%
    \global\cslet{add@restated@#3}{\relax}%
  }
  \tre@restatable[#1]{#2}{#3}%
  \csgpreto{#3}{\@nameuse{add@restated@#3}}%
}{\tre@endrestatable}
\def\process@comma{\def\process@comma{,\space}}
\def\notrestated{}
\def\checknotrestated{%
  \@for\@rthm:=\the\@toks@restatable\do{%
    \ifx\@rthm\@empty\else
      \expandafter\ifx\csname add@restated@\@rthm\endcsname\relax\else
        \xdef\notrestated{\notrestated\@rthm; }\fi
    \fi
  }
  \ifx\notrestated\empty\else
    \par\vspace{1pc}\par\noindent
    Warning! -- There were theorems that have not been restated: \notrestated
    \@latex@warning{There were theorems that have not been restated: \notrestated}%
\fi
}
\makeatletter

\begin{document}
\chapter{One}
\begin{restatable}{theorem}{aTheorem}
  some text
\end{restatable}

\begin{restatable}{theorem}{bTheorem}
  foo
\end{restatable}

\begin{restatable}{theorem}{cTheorem}
  bar
\end{restatable}

\chapter{Later}
\aTheorem*

%\bTheorem*

%\cTheorem*


\chapter{Debugging}
\typeout{restatable: \the\listofrestatable}
List of restatable theorems: \the\listofrestatable

\vspace{1pc}

\typeout{restatated: \the\listofrestatable}
\noindent
List of restatated theorems: \the\listofrestatated

\checknotrestated
\end{document}
  • Thank you, the first two parts work great, but I have troubles bringing the last part to work: ./backmatter.tex:64: You can't use `\spacefactor' in vertical mode. ./backmatter.tex:64: Missing $ inserted. ./backmatter.tex:64: You can't use `\spacefactor' in math mode. Any ideas what these errors could be? They stem from the \@for\@rthm:=\the\@toks@restatable\do{% loop. Is there maybe a problem with one of the theorems' names? If the errors mean nothing to you, I can try to create a minimal example, but I have no idea what the error message is trying to tell me. – markus23 Sep 16 '17 at 22:30
  • @markus23, don't have an idea at the moment. In fact in my minimal example it works. I'll post it to the end of the answer. Can you try to compile it and then try adding bits you need in your document that might break the functionality (to create a mwe that way). – Ruben Sep 17 '17 at 9:04
  • Thank you, your complete code worked! Seems like I merged your previous code wrongly. I found exactly one non-restated theorem, would be near-impossible to find it manually, so a big thanks! – markus23 Sep 17 '17 at 23:38
  • @markus23, very glad that my answer helped you! And I'm especially happy that it was able to operate that "precise" : ) – Ruben Sep 17 '17 at 23:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.