0

Background

Using a handful of answers in this site, I have come up with a solution for building a list of equations (with tocloft), such that two or more of them can be grouped inside an align environment and high-level typesetting is relatively simple:

\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}

The problem

When isolated and compiled with latexmk -pdf, the code above works as it should. However, when trying to integrate such code into a larger project (a maths book, complete with TOC, references and the like), I keep getting:

  1. either TeX input capacity exceeded (sorry), or
  2. Runaway argument?

Such results are strange, given that the solution works alone.

The question

Are using lists to store commands or other data (just like in the example) prone to stack exhaustion when combined with other packages?

Depending on the answer, I will post another question, regarding the efficiency of the solution.

  • you can write code that uses tail recursion and so uses no stack, it all depends what you want to do. You don't show the error message to see what capacity that you exceeded, if for example it was main memory then your list has too much data rather than too deep a stack... Also you are missing lots of % at ends of lines (that on its own can prevent tail recursion) – David Carlisle Aug 21 '17 at 6:22
  • I didn't trace all the above code but it seems to be undecided whether to store things in a list or via a sequence of macros with numbered names (either work, with different pros and cons, but using both at the same time looks more complicated than it need be, especially using global counters) – David Carlisle Aug 21 '17 at 6:28
  • @DavidCarlisle Let me see if I can recreate the error (I have reverted back so that I could continue with the book). I am also rewording the question: see it here. – logo_writer Aug 21 '17 at 6:28
  • @DavidCarlisle I guess it is because it is a Frankenstein made up from a bunch of questions I checked (and included in the source!) – logo_writer Aug 21 '17 at 6:30
  • It sort of depends on what the list consists of. Simple text is easy: LaTeX handles strings as linked lists of character nodes which are easily recycled. Formatted text like equations get very ugly with expanded. You might consider creating an array using \csname instead. – John Kormylo Aug 21 '17 at 21:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.