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 \aligneqs
s) 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?