9

I want to create a statement enumeration environment together with a referencing mechanism such that the code

\section{A section}
\begin{theorem}
    \begin{statement}
        \item Test \label{Test1}
        \item Test \label{Test2}
    \end{statement}
\end{theorem}
\begin{lemma}
    \begin{statement}
        \item Test \label{Test3}
        \item Test \label{Test4}
        \item Test \label{Test5}
    \end{statement}
\end{lemma}

\reference{Test1},

\referenceWithTheorem{Test2},

\labelreference{Test3},

\labelreferenceWithTheorem{Test4}

\referenceWithTheorem{Test5}

produces the following output with appropriate hyperlinks:

enter image description here

The following is important to me:

  1. I can use the same environment statement for within theorem and lemma.
  2. If I use \referenceWithTheorem or \labelreferenceWithTheorem, then precisely <section>.<theorem> <statement> becomes a hyperlink pointing to that statement.
  3. The mechanism determines whether a statement is placed within a theorem or a lemma.

I will be very grateful if someone could provide help.

Appendix: Here is the code I used to produce the screenshot:

\documentclass{article}

\usepackage{amsthm}
\usepackage{enumitem}
\usepackage{hyperref}

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}

\begin{document}
    \section{A section}
    \begin{theorem}
        \begin{enumerate}[label=(\roman*)]
            \item Test \label{Test1}
            \item Test \label{Test2}
        \end{enumerate}
    \end{theorem}
    \begin{lemma}
        \begin{enumerate}[label=(\roman*)]
            \item Test \label{Test3}
            \item Test \label{Test4}
            \item Test \label{Test5}
        \end{enumerate}
    \end{lemma}

    Statement~\hyperref[Test1]{(i)},

    Theorem~\hyperref[Test2]{1.1 (ii)},

    \hyperref[Test3]{(i)},

    \hyperref[Test4]{1.2 (ii)},

    Lemma~\hyperref[Test5]{1.2 (iii)}



\end{document}
  • 2
    Off-topic: \upshape, like \slshape and \bfseries, does not take an argument. – Mico Mar 7 '18 at 9:53
  • @Mico Thank you for the suggestion. So rather remove the curly braces after \upshape or rather replace \upshape by \textup ? – John Dorian Mar 7 '18 at 10:08
  • Indeed. The only meaningful difference is that {\upshape ...} allows paragraph breaks inside the curly braces, whereas \textup{...} does not. – Mico Mar 7 '18 at 10:15
  • @Mico \textup also handles italic correction – David Carlisle Mar 7 '18 at 15:34
  • 1
    @Mico presumably \textup is used in an italic context or why use it at all? compare \documentclass{article} \showoutput \begin{document} \itshape f \textup{AAA} f f {\upshape AAA} f \end{document} – David Carlisle Mar 7 '18 at 15:43
7
+50

Here is another possible solution.

I'm using the cleveref package, which defines macros that automatically format references. With this package, \Cref{<some section>} will produce "Section ⟨number⟩" and, if you are using amsthm, \Cref{<some theorem>} will produce "⟨theorem type⟩ ⟨number⟩".

I've made some modifications that allow you to reference items in the statement environment (and their names) in two ways.

  • I'm using the package enumitem (which you also appear to use) to define the statement environment and I've set it up so that the label that is written to the aux file is actually of the form \@twolabels{(i)}{1.1~(i)}.
  • I've defined \@twolabels as \@firstoftwo, so that \@twolabels{(i)}{1.1~(i)} expands to (i). Thus, when you expand \ref{Test<n>} the output will be (i).
  • When you call \refWithTheorem{Test<n>}, \@twolabels is temporarily redefined to \@secondoftwo, after which \ref{Test<n>} is called. You will thus see the second part of the label, which contains the number of the surrounding theorem.
  • At the start of the statement environment, I tell cleveref that the type corresponding to the statementi counter is \@twolabels{statementi}{<the type of the surrounding environment>}.
  • The macro \CrefWithTheorem is defined as \refWithTheorem: it redefines \@twolabels to \@secondoftwo and then calls \Cref.

Here is the code:

\documentclass{article}

\usepackage{amsthm}
\usepackage{enumitem} %% For \newlist
\usepackage{hyperref}
\usepackage{cleveref} %% For \Cref,\cref. You may or may not want to add [capitalize]

%% Defining the statement environment
\newlist{statement}{enumerate}{1}
%% Set ref to a pair consisting of the statement label and the combined label, with \@twolabels in front
\setlist[statement]{label=(\roman*),ref=\doublelabel{(\roman*)},before=\setcrefdoublealias}
%% Teaching cleveref about the name of this environment
\crefname{statementi}{statement}{statements} %% arguments are: name of counter, singular name, plural name

\makeatletter
%% \doublelabel defines a label of the form \@twolabels{<current>}{<previous>~<current>}
\newcommand*\doublelabel[1]{\protect\@twolabels{#1}{\@currentlabel~#1}}
%% \@twolabels causes the first label to be shown by default
%% It can be redefined to \@secondoftwo to retrieve the other label
\let\@twolabels\@firstoftwo

%% Telling cleveref that statementi is an alias for either itself or for the surrounding environment
%% (Which it is depends on how \@twolabels is defined)
\def\setcrefdoublealias{%
  \begingroup\edef\x{\endgroup%
    \noexpand\crefalias{statementi}{%
      \noexpand\protect\noexpand\@twolabels%
        {statementi}{\expandafter\@extractcounterfromcreflabel\cref@currentlabel\end@extractcounterfromcreflabel}%
    }%
  }\x%
}
%% Extracts the environment name from \cref@currentlabel (which is of the form "[<counter name>]<other stuff>")
\def\@extractcounterfromcreflabel[#1]#2\end@extractcounterfromcreflabel{#1}

%% For defining WithTheorem versions of ref, cref, etc.
\newcommand*\versionWithTheorem[1]{\@ifstar{\versionWithTheorem@aux{#1*}}{\versionWithTheorem@aux{#1}}}
\newcommand*\versionWithTheorem@aux[2]{\begingroup\let\@twolabels\@secondoftwo#1{#2}\endgroup}
\makeatother

% % Versions of \ref and \Cref that include the surrounding environment name/label
\DeclareRobustCommand*\refWithTheorem{\versionWithTheorem\ref}
\DeclareRobustCommand*\CrefWithTheorem{\versionWithTheorem\Cref}
\DeclareRobustCommand*\crefWithTheorem{\versionWithTheorem\cref}
\DeclareRobustCommand*\nameCrefWithTheorem{\versionWithTheorem\nameCref}
\DeclareRobustCommand*\namecrefWithTheorem{\versionWithTheorem\namecref}

%% Theorem definitions
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}

\begin{document}

\section{A section}
\begin{theorem}
        \begin{statement}
        \item Test \label{Test1} 
        \item Test \label{Test2}
    \end{statement}
\end{theorem}
\begin{lemma}
    \begin{statement}
        \item Test \label{Test3}
        \item Test \label{Test4}
        \item Test \label{Test5}
    \end{statement}
\end{lemma}

\Cref{Test1}

\CrefWithTheorem{Test2}

\ref{Test3},

\refWithTheorem{Test4}

\CrefWithTheorem{Test5}

%% Support for referencing multiple labels at once
%% To also capitalise "lemma", use "\usepackage[capitalize]{cref}" above
Bonus (plural): \CrefWithTheorem{Test1,Test5,Test2}

%% Support for starred versions
Bonus (unlinked): \CrefWithTheorem*{Test4}

\end{document}

And here is the output:

enter image description here

Edit: Fixed a silly bug, don't use the old version.

Edit: Apparently \setlist has a before key, which makes using \AtBeginEnvironment (and loading etoolbox) unnecessary. Also added support for the starred (unlinked) versions of \ref, \cref and \Cref

Edit: Removed trailing \makeatletter (oops)

  • Thank you also for your great answer. Due to the bonuses and the presence of the general cref functionality which I do enjoy, I would like to give the bounty to you (although I feel really bad in view of the other great answer). I also managed to add some babel functionality to your code and all in all I am very happy with it :-) – John Dorian Mar 10 '18 at 22:30
  • You're welcome, and thank you for the bounty =).</lag> – Circumscribe Mar 12 '18 at 8:32
5

More sophisticated reference problems require more sophisticated tools for generation of cross-referencing information.

zref is such a powerful tool. It has the property features which allows for storing additional information.

I have defined 3 properties:

  • envname, which stores the outer environment name, e.g. Theorem or Lemma
  • theorem → stores the theorem number as output by \thetheorem
  • lemma → similar to theorem, stores \thelemma.

The macros

  • \reference
  • \referencewithTheorem
  • \labelreference
  • \labelreferencewithTheorem

all extract the relevant information written by \zlabel and show the information as desired.

\zlabel is done automatically by using the \crtprelabelhook.


\documentclass{article}

\usepackage{amsthm}
\usepackage{enumitem}
\usepackage{etoolbox}
\usepackage[user,counter,hyperref]{zref}
\usepackage{hyperref}

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}


\usepackage{crossreftools}

\newlist{statement}{enumerate}{1}
\setlist[statement,1]{label={(\roman*)}}


\makeatletter
\providecommand{\@lastouterenv}{}

\zref@newprop{envname}[-1]{\@lastouterenv}

\zref@newprop{Lemma}[-1]{\thelemma}
\zref@newprop{Theorem}[-1]{\thetheorem}


\zref@addprops{main}{envname,Lemma,Theorem}


\renewcommand{\crtprelabelhook}[1]{%
  \zlabel{#1}%
}

\AtBeginEnvironment{theorem}{\renewcommand{\@lastouterenv}{Theorem}}
\AtBeginEnvironment{lemma}{\renewcommand{\@lastouterenv}{Lemma}}



\newcommand{\reference}[1]{%
  \zref@ifrefundefined{#1}{}{%
    Statement \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{default}}%
  }%
}

\newcommand{\labelreference}[1]{%
  \zref@ifrefundefined{#1}{}{%
    \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{default}}%
  }%
}


\newcommand{\referencewithTheorem}[1]{%
  \zref@ifrefundefined{#1}{%
  }{%
    \zref@extract{#1}{envname}~\hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{\zref@extract{#1}{envname}} \zref@extract{#1}{default}}%
  }%
}

\newcommand{\labelreferencewithTheorem}[1]{%
  \zref@ifrefundefined{#1}{%
  }{%
    \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{\zref@extract{#1}{envname}} \zref@extract{#1}{default}}%
  }%
}


\makeatother


\begin{document}
    \section{A section}
    \begin{theorem}
        \begin{statement}
            \item Test \label{Test1}
            \item Test \label{Test2}
        \end{statement}
    \end{theorem}
    \begin{lemma}
        \begin{statement}
            \item Test \label{Test3}
            \item Test \label{Test4}
            \item Test \label{Test5}
        \end{statement}
    \end{lemma}

    \reference{Test1}%

    \referencewithTheorem{Test1}

    \labelreference{Test3},

    \labelreferencewithTheorem{Test4}

    \referencewithTheorem{Test5}




\end{document}

enter image description here

  • Thank you very much. Your solution works perfectly fine and also you managed to make me understand the zref package a little bit better (which the documentation could not manage, due to lack of examples). I am also glad to have found out about thecrossreftools package by you. I am looking forward to v.1.0 :-) – John Dorian Mar 10 '18 at 22:26

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.