5

Can someone explain what amsmath does to \@currentlabel in the align environments?

Better yet: if I want to write what would be expected to be the \@currentlabel together with some other information into an auxiliary output file, what's the best way to access that information in the align environments?

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand\storelabel[1]{%
    \xdef#1{\@currentlabel}}
\makeatother


\begin{document}

\begin{equation}
    A = B  \storelabel{\firstone}
\end{equation}
Now
\begin{align}
    C &= D \storelabel{\secondone}\\
    C' &= D' \storelabel{\thirdone}
\end{align}
\begin{equation}
    E = F \storelabel{\fourthone}
\end{equation}
The counters are \firstone, \secondone, \thirdone, \fourthone.
\end{document}

enter image description here

Willie Wong
  • 24,733
  • 8
  • 74
  • 106
  • Why don't you just use \label and \ref? – Henri Menke Jul 12 '16 at 21:51
  • The \storelabel command is executed before the equation number is set, i.e. \@currentlabel is just empty! The reason it works for equation is that \inc@eqnum is used right at the begin of the environment, not in the \toks@ token register at the very end –  Jul 12 '16 at 22:40
  • @HenriMenke because I am trying to write into an auxiliary file. The output of \ref{label}, as far as I know, is not "just" the counter value. \typeout{\ref{equation1}} yields something like 1\hbox {}. If you have an idea how I can just use \ref to get only the reference number that I can stuff into an auxiliary file, I'd also welcome that solution. (I don't mind having to run pdflatex multiple times.) – Willie Wong Jul 12 '16 at 23:13
  • 1
    @WillieWong: You can use the \getrefnumber command from refcount package -- that is expandable, \ref isn't –  Jul 12 '16 at 23:21
  • @ChristianHupfer: That's awesome. I didn't know about that package. While that doesn't answer the question I asked, it answers the question I should've asked. If you can edit your last comment as an alternate part to your answer below (or as a second answer), I'll accept it. – Willie Wong Jul 12 '16 at 23:27
  • @WillieWong: Added to the answer –  Jul 12 '16 at 23:29

2 Answers2

5

The behaviour of \refstepcounter in equation and align (for example) is different in the sense that

  • in equation the \incr@eqnum command (a wrapper for \refstepcounter etc.) is used right at the start of the environment, so \storelabel can access \@currentlabel
  • in align however, the \storelabel command is used before the tag is set, i.e. \@currentlabel is just empty at that time of usage.

Either the \make@display@tag command is patched or shortly redefined where the shifted definition of \xdef...{\@currentlabel} is used after \incr@eqnum.

The \storelabel command is actually a fake command now, just defining the next name to be set, but the true definition of the macro name is done later on.


\documentclass{article}
\usepackage{amsmath}

\makeatletter

\usepackage{etoolbox}

\newcommand{\extractstoretag}{%
  \@ifundefined{nextstoretag}{%
  }{%
    \expandafter\xdef\csname \nextstoretag\endcsname{\@currentlabel}
    \let\nextstoretag\relax
  }%
}
\AtEndEnvironment{equation}{%
  \extractstoretag%
}

\def\make@display@tag{%
  \if@eqnsw \incr@eqnum \extractstoretag \print@eqnum
  \else \iftag@ \df@tag \global\let\df@tag\@empty \fi
  \fi
  \ifmeasuring@
  \else
    \ifx\df@label\@empty
    \else
      \@xp\ltx@label\@xp{\df@label}%
      \global\let\df@label\@empty
    \fi
  \fi
}


\newcommand\storelabel[1]{%
  \xdef\nextstoretag{#1}%
}%
\makeatother


\begin{document}
\begin{equation}
    A = B  \storelabel{firstone}
  \end{equation}
  Now
\begin{align}
    C  &= D   \storelabel{secondone} \\
    C' &= D'  \storelabel{thirdone}
\end{align}
\begin{equation}
    E = F \storelabel{fourthone}
\end{equation}
The counters are \firstone, \secondone, \thirdone,\fourthone.
\end{document}

Here's the version with \..... macros in the \storelabel command:

\documentclass{article}
\usepackage{amsmath}

\usepackage{etoolbox}

\makeatletter


\newcommand{\extractstoretag}{%
  \@ifundefined{nextstoretag}{%
    \relax%
  }{%
    \expandafter\xdef\csname \nextstoretag\endcsname{\@currentlabel}
    \let\nextstoretag\relax
  }%
}
\AtEndEnvironment{equation}{%
  \extractstoretag%
}

\def\make@display@tag{%
  \if@eqnsw \incr@eqnum \extractstoretag \print@eqnum
  \else \iftag@ \df@tag \global\let\df@tag\@empty \fi
  \fi
  \ifmeasuring@
  \else
    \ifx\df@label\@empty
    \else
      \@xp\ltx@label\@xp{\df@label}%
      \global\let\df@label\@empty
    \fi
  \fi
}


\newcommand{\storelabel}[1]{%
    \xdef\nextstoretag{\expandafter\@gobble\string#1}%
  }%
\makeatother


\begin{document}
\begin{equation}
    A = B  \storelabel{\firstone}
  \end{equation}

  \begin{align}
    C  &= D   \storelabel{\secondone} \\
    C' &= D'  \storelabel{\thirdone}
  \end{align}
  \begin{equation}
    E = F \storelabel{\fourthone}
\end{equation}


The counters are \firstone, \secondone, \thirdone\ and \fourthone.
\end{document}

Update/Edit

Apparently, another solution to get the 'real' content what is written to the .aux file can be achieved by using the \getrefnumber from the package refcount by Heiko Oberdiek.

5

From the amsmath documentation (section 15.2 Implementing tags and labels, p 39):

Sometimes it is necessary for a \tag command to store a tag in a safe place and to process it later, e.g., for a tag in a row of an alignment where the tag can only be typeset when the \\ at the end of the row was seen. Such a tag is stored in the macro \df@tag (for ‘deferred tag’). For this purpose we provide the \make@df@tag macro. It is built very similar to the \maketag@@ macro [..].

\let\df@tag\@empty
\def\make@df@tag{\@ifstar\make@df@tag@@\make@df@tag@@@}

\make@df@tag sets \@currentlabel and defines \df@tag appropriately.

To simplify the task of tracking \tag and \label commands inside math display environments, we defer \label commands until the tag is typeset, similar to the way that \tags themselves are deferred. This allows arbitrary placement of \label and \tag commands and also means we only increment the \equation counter when we really need to, thus avoiding the \setb@ck nonsense that used to be required.

\def\make@df@tag@@#1{%
  \gdef\df@tag{\maketag@@@{#1}\def\@currentlabel{#1}}}

Autogenerated number:

\def\make@df@tag@@@#1{\gdef\df@tag{\tagform@{#1}%
  \toks@\@xp{\p@equation{#1}}\edef\@currentlabel{\the\toks@}}}

The crucial part of the above discussion is the mention that within a display, amsmath takes control of the \label and \tag, deferring the former until the tag has been set. It allows for ease-of-use from a user's perspective*.

So you will either have to tap into the setting of the tag in order to extract the correct \@currentlabel, or you'll have to stick to using a \label-\ref system. refcount is another option for extracting the reference in an expandable way, still using a \label-\ref-like setup:

enter image description here

\documentclass{article}

\usepackage{amsmath,refcount}

\begin{document}

\begin{equation}
  A = B  \label{firstone}
\end{equation}
Now
\begin{align}
  C &= D \label{secondone} \\
  C' &= D' \label{thirdone}
\end{align}
\begin{equation}
  E = F \label{fourthone}
\end{equation}
The counters are \getrefnumber{firstone}, \getrefnumber{secondone}, \getrefnumber{thirdone}, \getrefnumber{fourthone}.

\end{document}

*In an analogous (yet opposite) way there's no control over the placement of the \caption inside a float - it's set inline with the placement. As such, the user has to make sure that \label comes after the \caption; amsmath tries to accommodate the user by allowing them to place \label wherever inside the display - before or after the \tag even without a \tag.

Werner
  • 603,163