4

Is it possible to create an equivalent of Backreferences for equations for theorems, propositions definitions etc.?

Meaning that after stating the theorem it would be stated where the theorem was referenced at and it would work with hyperref.

Usage of table/figures shown in caption provides almost an answer, but how would one append this to happen automatically at the end of an labeled theorem/definition?

Example of what I would need to happen automatically, except with \Cref

\documentclass{article}
\usepackage{etoolbox,xstring,xspace}
\usepackage{amsmath,amsthm,amssymb,thmtools}
\usepackage{hyperref}
\usepackage{cleveref}
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}

\makeatletter
\AtBeginDocument{%
\let\origref\ref
\renewcommand*\ref[1]{%
  \origref{#1}\xlabel{#1}}
}
\newrobustcmd*\xlabel[1]{%
   \ifcsdef{siteref@doc@#1}{}{\csgdef{siteref@doc@#1}{,}}%
    \@bsphack%
    \begingroup
       \csxdef{siteref@doc@#1}{\csuse{siteref@doc@#1},\thepage}%
         \protected@write\@auxout{}%
        {\string\SiteRef{siteref@#1}{\csuse{siteref@doc@#1}}}%
     \endgroup
     \@esphack%
}

\newrobustcmd*\SiteRef[2]{\csgdef{#1}{#2}}

\newrobustcmd*\xref[1]{%
\ifcsundef{siteref@#1}{%
     \@latex@warning@no@line{Label `#1' not defined}
     }{%
    \begingroup
      \StrGobbleLeft{\csuse{siteref@#1}}{2}[\@tempa]\relax%
      \def\@tempb{}%
      \@tempcnta=0\relax%
      \@tempcntb=\@ne\relax%
      \def\do##1{\advance\@tempcnta\@ne}%
      \expandafter\docsvlist\expandafter{\@tempa}%
       \def\do##1{%
         \ifnum\@tempcntb=\@tempcnta\relax%
            \hyperpage{##1}%
         \else
            \hyperpage{##1},%
          \fi%
          \advance\@tempcntb\@ne
       }%
       [\expandafter\docsvlist\expandafter{\@tempa}]\xspace%
    \endgroup
   }%
}
\makeatother


\begin{document}

\begin{theorem}\label{fancytheorem}
Fancy Theorem
\end{theorem}
Referenced on page(s)\xref{fancytheorem}

\newpage\section{page two}\ref{fancytheorem}
\end{document}

Thanks!

3

Here is one way to do what you want. I started with your code and added and changed a few things. A no-so-brief summary:

  • I renamed siteref@ as thmref@ throughout as this made more sense to me:)
  • I have wrapped the theorem environment inside a \NewDocumentEnvironment, called Theorem, that takes two arguments: the optional argument to the theorem environment and a (mandatory) label. The label is used to define a thmref@<label> macro, which is used to store the page numbers that contain references to the theorem. At the end of the Theorem environment the \xref command is called in order to automatically add the cross-reference information.
  • Rather than writing a \SiteRef command to the auxfile every time \ref is called I have used \AtEndDocument to write it only once using \SaveTheoremRef.
  • I have made the \ref etc smart enough to only save "thmref" information for references associated with theorems. Previously this was stored in the aux file whenever \ref was used.
  • The code works with \ref and \cref. I haven't added \Cref but that is trivial to do.
  • I had to change the \xref command as it didn't work for me with multiple references. I also made it print only one page reference for each page and to use page or pages depending on the number of pages that contain references to the theorem.
  • If there are no references, No references is printed.

EDIT

I have changed the definition of \@theoremref so that it now allows references to occur before the theorem. The cost is that thmref@<label> references are now constructed for all references, not just theorems, but they are only stored in the aux file for theorems. At the same time I added an "and" between the last two page references when there is more than one reference, which was slightly tricky, and I fixed a bug in the original version of the code by putting the embedded theorem environments into their own group. I removed the unnecessary packages and renamed \xref as \AddTheoremReferences to avoid name conflicts as I think that \xref might be defined in some package(?). Finally, as requested in the comments, I allowed for multiple labels being passed to \ref{...} and friends.

Here is the output from the first page of my MWE incorporating these changes:

enter image description here

and here is the code:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{amsmath,amsthm,amssymb,thmtools}
\usepackage{hyperref}
\usepackage{cleveref}
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}

\makeatletter

% This command is written to the aux file by \SaveTheoremRef, hence
% allowing us to access the cross-referencing data via \thmref@aux@<label>
\newrobustcmd*\TheoremRef[2]{\csgdef{thmref@aux@#1}{#2}}

% save theorem reference data. Called via \AtEndDocument{...}
\newrobustcmd*\SaveTheoremRef[1]{
   \ifcsdef{thmref@#1}{%
     \immediate\write\@auxout{\string\TheoremRef{#1}{\csuse{thmref@#1}}}%
   }{}
}

% stores page reference data in thmref@<label>
\newcommand\@theoremref[1]{%
   \def\do##1{\ifcsdef{thmref@##1}{\csxappto{thmref@##1}{,\number\thepage}}%
                                  {\csxdef{thmref@##1}{\number\thepage}}%
   }%
   \docsvlist{#1}%
}

% Overwrite definitions of \ref and \cref. Since other packages such as
% hyperref and cleverref change these this should be done at the
% beginning of the document.
\AtBeginDocument{
    \let\originalref\ref
    \renewcommand*\ref[1]{\originalref{#1}\@theoremref{#1}}
    \let\originalcref\cref
    \renewcommand*\cref[1]{\originalcref{#1}\@theoremref{#1}}
}

% \AddTheoremReferences<label> prints the cross-referencing information for theorem <label>
\newrobustcmd*\AddTheoremReferences[1]{%
    \ifcsdef{thmref@aux@#1}{% proceed only if thmref data exists
       \def\@tempa{0}% used to check for repeats
       \@tempcnta=0% used to check for plural
       \def\@thmref{}% will contain cross-referencing hyperlinks
       \def\do##1{\ifnum##1=\@tempa\relax% skip over repeat references on each page
                  \else%
                      \ifnum\@tempcnta=1% skip \@tempcnta=0
                        \xappto\@thmref{\noexpand\hyperpage{\@tempa}}% first page reference
                      \else\ifnum\@tempcnta>1% already have ref so add a comma
                           \xappto\@thmref{, \noexpand\hyperpage{\@tempa}}%
                           \fi%
                      \fi%
                      \global\advance\@tempcnta by 1% increment reference counter
                      \edef\@tempa{##1}% store to check for repeat next time
                  \fi%
       }
       \xdef\@@thmref{\csuse{thmref@aux@#1}}
       \expandafter\docsvlist\expandafter{\@@thmref}
       \typeout{Refefenced: \the\@tempcnta.}
       \ifnum\@tempcnta=1% only one reference
           \noindent[Referenced on page \expandafter\hyperpage{\@tempa}]%
       \else% at least two references so add an "and"
           \noindent[Referenced on pages \@thmref\space and \expandafter\hyperpage{\@tempa}]%
       \fi%
       }{\noindent[Not referenced]\@latex@warning@no@line{Theorem reference `#1' is not defined}}%
}

\makeatother

\usepackage{xparse}
% \begin{Theorem}[heading]{label} ... \end{Theorem}
\NewDocumentEnvironment{Theorem}{ o m }
   {\AtEndDocument{\SaveTheoremRef{#2}}
    \IfNoValueTF{#1}{\begin{theorem}}{\begin{theorem}[#1]}
    \label{#2}
   }
   {\end{theorem}\AddTheoremReferences{#2}}


\setcounter{page}{11}% for testing purposes only

\begin{document}
  A reference to \cref{fanciertheorem}.

  \begin{Theorem}{fancytheorem}
  Fancy Theorem
  \end{Theorem}

  \begin{Theorem}[Really fancy!]{fanciertheorem}
  Fancier Theorem
  \end{Theorem}

  \begin{Theorem}[Plain theorem]{plaintheorem}
  Plain Theorem
  \end{Theorem}

  \newpage\section{page two}
    \cref{fancytheorem,fanciertheorem}
    \ref{fanciertheorem}

  \newpage\section{page three}
    \ref{fanciertheorem}
\end{document}
  • Thanks! This almost works, but there is a problem if the reference is before the theorem, then the references are ignored since it checks the existence of thmref, I tried to override this one but failed so how would one on the first hit write the TheoremRef and pagenumber and after that append pagenumbers to it? – asd fsgt Jan 18 '17 at 21:43
  • Well, I think it did work because this case did not appear in your MWE! :) This said, I have modified the code to allow for this. See the edit for a description of the changes. – Andrew Jan 19 '17 at 2:41
  • Another issue is if \cref contains multiple arguments ala \cref{fanciertheorem,fancytheorem}, then we would need to be able to separate the arguments based on comma. I really should have thought my example better. This one How do I write a macro having comma-separated and variable number of arguments? might give the solution. – asd fsgt Jan 19 '17 at 5:17
  • @asdfsgt This is a fairly easy enhancement that just requires adding a \docsvlist command inside \@theoremref. (The macro \AddTheoremReferences also processes comma separated variables, or csv lists, using \docsvlist.) Done! – Andrew Jan 19 '17 at 6:25
  • Thanks! This worked almost perfectly, but I found some weird behavior still: If the page number is twice the same number f.e. 11 or 22, then the commands \@@thmref and \@tempa does not seem to work because of the line \ifx##1@\relax% ignore the leading @ but I cannot figure out how to fix it. – asd fsgt Feb 19 '17 at 22: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.