问题
我有兴趣获得以下结果,通过不是直接用代码编写。
\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}
该命令aligneqs
在序言中定义如下:
\usepackage{tocloft}
\newcommand{\loename}{List of equations}
\newlistof{equations}{equ}{\loename}
\newcommand{\aligneqs}[2]% <=== HERE
{\addcontentsline{equ}{equations}{\protect\numberline{\ref{#2}}#1}}
我心中的总体想法是能够写align
如下内容:
\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
先前的结果
我实际上已经想出了一个解决方案,在这个问题,但仅在单独测试时才有效(即不包含其他包)。
我在这里附上代码以防其他问题被关闭:
\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}
可以看出,命令执行(\aligneqs
s)在某个时刻被推迟了。当方程式被“声明”时,它被存储在一个列表中,连同引用(在另一个列表中)和要推迟的命令(在另一个列表中)。
一旦它们被收集起来,使用\@for
循环,将方程式插入到宏中(带有标签占位符),然后使用另一个\@for
循环,将占位符替换为其相应的标签。
最后,align
排版并最后,延迟的命令最终被执行(在方程列表中插入行)。
问题
鉴于它只有在单独测试时才有效,有没有更好的方法来推迟命令的执行?
答案1
已编辑以处理使用\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}\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}
第2页:
我在定义中提供了一个注释的替代形式\InsertEquation
,可以用作 的替代形式\g@addto@macro\aligngroup{\aligneqs{#2}{#3}#1\label{#3}\\}
。替代形式如下所示:
答案2
目前尚不清楚为什么这里需要延迟执行
\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}