1

The problem

I am interested in getting the following result, by not writing it directly in code.

\begin{align}
    T(x) &= ae^{-\frac{(x-b)^2}{2c^2}} \\
    \frac{1}{2} < a &\leq 1 \label{eq:m1va} \\
    b &= \SI{25}{\degreeCelsius} \label{eq:m1vb} \\
    c &= \frac{5}{\sqrt{2 \ln{2a}}} > 0 \label{eq:m1vc}
\end{align}
\aligneqs{Model 1: Condition 1}{eq:m1va}
\aligneqs{Model 1: Condition 2}{eq:m1vb}
\aligneqs{Model 1: Condition 3}{eq:m1vc}

The command aligneqs is defined in the preamble as follows:

\usepackage{tocloft}
\newcommand{\loename}{List of equations}
\newlistof{equations}{equ}{\loename}
\newcommand{\aligneqs}[2]% <=== HERE
    {\addcontentsline{equ}{equations}{\protect\numberline{\ref{#2}}#1}}

The general idea I have in mind is to be able to write the align as follows:

\InsertEquation{T(x) &= ae^{-\frac{(x-b)^2}{2c^2}}}{Model 1: Base formula}{eq:m1gauss}
\InsertEquation{\frac{1}{2} < a &\leq 1}{Model 1: Condition 1}{eq:m1va}
\InsertEquation{b &= \SI{25}{\degreeCelsius}}{Model 1: Condition 2}{eq:m1vb}
\InsertEquation{c &= \frac{5}{\sqrt{2 \ln{2a}}} > 0}{Model 1: Condition 3}{eq:m1vc}
\GenerateAlign

Previous results

I have actually come up with a solution, which is thoroughly explained in this question, but only works when tested alone (i.e. no other packages are included).

I include the code here in case the other question gets closed:

\documentclass{article}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{amsmath}
\usepackage{tocloft}

\usepackage{blindtext}

% Add a new list for equations
\newcommand{\loename}{List of equations}
\newlistof{equations}{equ}{\loename}
\newcommand{\aligneqs}[2]%
    {\addcontentsline{equ}{equations}{\protect\numberline{\ref{#2}}#1}}
\setlength{\cftequationsnumwidth}{2.5em}

% https://tex.stackexchange.com/q/451/53787
% https://tex.stackexchange.com/q/16883/53787
\makeatletter
    % Temporary lists: store equations, references, and deferred commands
    \gdef\listeqs{}
    \gdef\listrefs{}
    \gdef\listdefers{}
    \newcounter{DeferredCommands}

    % Converts a number to Roman notation
    % https://tex.stackexchange.com/q/9718/53787
    % https://tex.stackexchange.com/q/23487/53787
    \newcommand*{\rom}[1]{\expandafter\@slowromancap\romannumeral #1@}

    % Add an element to a list
    \def\addtolist#1#2{%
        \g@addto@macro{#1}{#2,}
    }

    % Add an element to a list, expanding it first
    % https://tex.stackexchange.com/q/67367/53787
    \def\addexpandedtolist#1#2{%
        \edef\ATL@temp{\noexpand\g@addto@macro\noexpand#1{\noexpand#2,}}
        \ATL@temp
    }

    % Defers the execution of a command, storing it in a list
    \DeclareDocumentCommand{\DeferCommand}{mm}{%
        \stepcounter{DeferredCommands}
        \expandafter\def\csname DC@\rom{\arabic{DeferredCommands}}\endcsname{#2}
        \addexpandedtolist{#1}{DC@\rom{\arabic{DeferredCommands}}}
    }

    % Inserts an equation, its reference, and its TOC line to their
    % respective lists
    \DeclareDocumentCommand{\InsertEquation}{mmm}{%
        \addtolist{\listeqs}{#1}
        \addtolist{\listrefs}{#3}
        \DeferCommand{\listdefers}{\aligneqs{#2}{#3}}
    }

    % Execute all the deferred commands of the given list
    % https://tex.stackexchange.com/q/28787/53787
    \DeclareDocumentCommand{\DeferredExecute}{m}{%
        \@for \i:=#1 \do{\@nameuse{\i}}
        \setcounter{DeferredCommands}{0}
        \let#1\@empty
    }

    % http://handyfloss.net/2007.08/latex-programming-how-to-implement-conditionals/
    \newcounter{GArepnum}
    \newif\ifGA@first

    % Put all the equations inside a macro (first traversal) along
    % with placeholders for labels, substitute the placeholders with
    % their respective labels (second traversal), and show everything
    % inside an "align". After it, execute all the deferred commands
    % (stored when inserting an equation) that add the corresponding
    % lines to the list of equations.
    \DeclareDocumentCommand{\GenerateAlign}{}{%
        \def\GA@ans{}

        \setcounter{GArepnum}{1}
        \GA@firsttrue

        \@for \i:=\listeqs \do{%
            % https://tex.stackexchange.com/q/53068/53787
            \ifx\i\empty\else
                \ifGA@first
                    \GA@firstfalse
                \else
                    % https://tex.stackexchange.com/q/74707/53787
                    \edef\GA@temp{\noexpand\g@addto@macro\noexpand\GA@ans{\noexpand\\}}
                    \GA@temp
                \fi

                \edef\GA@temp{\noexpand\g@addto@macro\noexpand\GA@ans{\i ???}}
                \GA@temp
                \stepcounter{GArepnum}
            \fi
        }

        \@for \j:=\listrefs \do{%
            \ifx\j\empty\else
                % https://tex.stackexchange.com/q/104506/53787
                \begingroup\edef\GA@perform{\endgroup
                    \noexpand\patchcmd
                    {\noexpand\GA@ans}%
                    {\noexpand ???}%
                    {\noexpand\label{\unexpanded\expandafter{\j}}}%
                    {}%
                    {}%
                }%
                \GA@perform
            \fi
        }

        \begin{align}
            \GA@ans
        \end{align}
        \DeferredExecute{\listdefers}

        \let\listeqs\@empty
        \let\listrefs\@empty
    }
\makeatother

\begin{document}
    \listofequations
    \clearpage

    \section*{Important formulas}

    \blindtext

    \InsertEquation{a^2 + b^2 &= c^2}{Pythagorean theorem}{eq:first}
    Following is eq.~\ref{eq:first}, depicting Pythagora's theorem:
    \GenerateAlign

    \Blindtext

    \InsertEquation{e &= mc^2}{Einstein Relativity theory}{eq:second}
    Following is eq.~\ref{eq:second}, depicting Einstein's relativity theory:
    \GenerateAlign

    \blindtext
\end{document}

It can be seen that command execution (the \aligneqss) is deferred at some point. When the equation is "declared", it is stored in a list, along with the reference (in another list) and the command to be deferred (in yet another list).

Once they have been gathered, using a \@for loop, the equations are inserted into a macro (with label placeholders), and then, with another \@for loop, the placeholders are replaced by their corresponding labels.

Finally, the align is typeset and at the end of it, the deferred commands are finally executed (which insert lines in the list of equations).

The question

Given that it only works when tested alone, is there a better way to defer the execution of commands?

2

EDITED to handle use of \allowdisplaybreaks.

\documentclass{article}
\usepackage{amsmath,siunitx,tocloft,lipsum}
\newcommand{\loename}{List of equations}
\newlistof{equations}{equ}{\loename}
\makeatletter
\newcommand{\aligneqs}[2]{\addcontentsline{equ}{equations}{\protect\numberline{\ref{#2}}#1}}
\newcommand\aligngroup{}
\newcommand\GenerateAlign{\expandafter\GenerateAlignaux\aligngroup\relax}
\def\GenerateAlignaux#1\\\relax{\begin{align}#1\end{align}\gdef\aligngroup{}}
\newcommand\InsertEquation[3]{%
  \g@addto@macro\aligngroup{\aligneqs{#2}{#3}#1\label{#3}\\}%
%  \g@addto@macro\aligngroup{\aligneqs{#2}{#3}&\text{#2}&#1\label{#3}\\}%  ALTERNATE FORM
}
\makeatother
\allowdisplaybreaks
\begin{document}
\listofequations\vspace{140pt}
\InsertEquation{T(x) &= ae^{-\frac{(x-b)^2}{2c^2}}} {Model 1: Base formula}{eq:m1gauss}
With a blah-blah here,%
\InsertEquation{\frac{1}{2} < a &\leq 1}            {Model 1: Condition 1} {eq:m1va}
and a blah-blah there,%
\InsertEquation{b &= \SI{25}{\degreeCelsius}}       {Model 1: Condition 2} {eq:m1vb}
here a blah, there a blah,%
\InsertEquation{c &= \frac{5}{\sqrt{2 \ln{2a}}} > 0}{Model 1: Condition 3} {eq:m1vc}
everywhere a blah-blah.

\lipsum[1-2]Blah-blah occurs before the \texttt{align} is generated:
\GenerateAlign
In equation~\ref{eq:m1vb}...
\end{document}

enter image description here

Page 2:

enter image description here

I provide a commented alternate form inside of the \InsertEquation definition, which could be employed as an alternative to \g@addto@macro\aligngroup{\aligneqs{#2}{#3}#1\label{#3}\\}. The alternative form looks like this:

enter image description here

  • It seems it will work! Let me check it and will get back to you. – logo_writer Aug 22 '17 at 7:07
  • I don't understand why you globally declare \aligngroup when it was already defined as a command (with \newcommand). The same goes for the meaning of \relax. I get the general idea, though: storing in a macro the things to include, and then expanding them when the real align is put is really clever! – logo_writer Aug 22 '17 at 7:21
  • 1
    My bad, I have finally realised why the \gdef: you are resetting \aligngroup so it can be used again! XD – logo_writer Aug 22 '17 at 7:34
1

It isn't clear why you need deferred execution here

\documentclass{article}

\usepackage{amsmath,siunitx}

\usepackage{tocloft}
\newcommand{\loename}{List of equations}
\newlistof{equations}{equ}{\loename}


\newcommand\InsertEquation[3]{%
\\%
#1\label{#3}%
\addcontentsline{equ}{equations}{\protect\numberline{\ref{#3}}{#2}}%
}
\def\firstequation{\expandafter\gobblenl}
\def\gobblenl\\{}
\begin{document}

\listofequations


\begin{align}
\firstequation
\InsertEquation{T(x) &= ae^{-\frac{(x-b)^2}{2c^2}}}{Model 1: Base formula}{eq:m1gauss}
\InsertEquation{\frac{1}{2} < a &\leq 1}{Model 1: Condition 1}{eq:m1va}
\InsertEquation{b &= \SI{25}{\degreeCelsius}}{Model 1: Condition 2}{eq:m1vb}
\InsertEquation{c &= \frac{5}{\sqrt{2 \ln{2a}}} > 0}{Model 1: Condition 3}{eq:m1vc}
\end{align}

\end{document}
  • Deferring was my initial idea as I couldn't include inside an align the necessary commands to include a line in the list of equations, referencing such formula. I'll check your answer, though. – logo_writer Aug 22 '17 at 7:07
  • This solution seems simpler, for just adding a \firstequation command. Why is it needed? Without it, I couldn't get the \addcontentsline to work. – logo_writer Aug 22 '17 at 7: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.