From fed27f633aadbacbd3d1221da7993fed8d4efffe Mon Sep 17 00:00:00 2001
From: Norbert Preining <norbert@preining.info>
Date: Sun, 15 Sep 2019 03:00:57 +0000
Subject: CTAN sync 201909150300

---
 macros/latex-dev/required/amsmath/amsmath.dtx | 6383 +++++++++++++++++++++++++
 1 file changed, 6383 insertions(+)
 create mode 100644 macros/latex-dev/required/amsmath/amsmath.dtx

(limited to 'macros/latex-dev/required/amsmath/amsmath.dtx')

diff --git a/macros/latex-dev/required/amsmath/amsmath.dtx b/macros/latex-dev/required/amsmath/amsmath.dtx
new file mode 100644
index 0000000000..8671694b70
--- /dev/null
+++ b/macros/latex-dev/required/amsmath/amsmath.dtx
@@ -0,0 +1,6383 @@
+%
+% \iffalse meta-comment
+%
+% Copyright (C) 1995, 2000, 2013 American Mathematical Society.
+% Copyright (C) 2016-2019 LaTeX3 Project and American Mathematical Society.
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3c
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+%   https://www.latex-project.org/lppl.txt
+% and version 1.3c or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+% 
+% This work has the LPPL maintenance status `maintained'.
+% 
+% The Current Maintainer of this work is the LaTeX3 Project.
+%
+% \fi
+%
+%\iffalse
+%<*driver>
+\documentclass{amsdtx}
+\def\MaintainedByLaTeXTeam#1{%
+\begin{center}%
+\fbox{\fbox{\begin{tabular}{@{}l@{}}%
+This file is maintained by the \LaTeX{} Project team.\\%
+Bug reports can be opened (category \texttt{#1}) at\\%
+\url{https://latex-project.org/bugs/}.\end{tabular}}}\end{center}}
+\raggedbottom
+\let\savedarg\arg
+\usepackage{amsmath}
+\let\arg\savedarg
+\GetFileInfo{amsmath.sty}
+\begin{document}
+\title{The \pkg{amsmath} package}
+\author{Frank Mittelbach\and Rainer Sch\"opf\and Michael Downes\and
+  David M. Jones\and David Carlisle}
+\date{Version \fileversion, \filedate}
+\providecommand{\histnote}{}
+\renewenvironment{histnote}{%
+  \trivlist\item[\hspace{\labelsep}\bfseries Historical Note:]%
+}{%
+  \endtrivlist
+}
+\DocInput{amsmath.dtx}
+\end{document}
+%</driver>
+%\fi
+%
+% \maketitle
+% \MaintainedByLaTeXTeam{amslatex}
+%
+% \MakeShortVerb\|
+%
+% \section{Introduction}
+%
+%    A \latex/ package named \pkg{amstex} was created in 1988--1989 by
+%    adapting \fn{amstex.tex} for use within \latex/. The \pkg{amsmath}
+%    package is the successor of the \pkg{amstex} package. It was
+%    substantially overhauled to integrate it with \latex/2e, which
+%    arrived on the scene in 1994. It provides more or less the same
+%    features, but there are quite a few organizational differences as
+%    well as some new features and bug fixes. For example, the
+%    \pkg{amstex} package automatically loaded the \pkg{amsfonts}
+%    package, but the \pkg{amsmath} package does not. At the present
+%    time (November 1999) user-level documentation of the commands
+%    provided here is found in the AMSmath Users' Guide,
+%    \fn{amsldoc.tex}.
+%
+% \StopEventually{}
+%
+%    Standard file identification.
+%    \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}% LaTeX 2.09 can't be used (nor non-LaTeX)
+[1994/12/01]% LaTeX date must be December 1994 or later
+%    \end{macrocode}
+%
+%    Providing a rollback to earlier version(s)
+%    \begin{macrocode}
+\providecommand\DeclareRelease[3]{}
+\providecommand\DeclareCurrentRelease[2]{}
+%
+\DeclareRelease{}{2018-12-01}{amsmath-2018-12-01.sty}
+\DeclareCurrentRelease{}{2019-04-01}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\ProvidesPackage{amsmath}[2019/04/01 v2.17c AMS math features]
+%    \end{macrocode}
+%
+% \section{Catcode defenses}
+%
+%    Some packages change the catcode of characters that are essential
+%    in low-level \tex/ syntax. Any package that does so does not
+%    qualify as a PWWO package (\qq{Plays Well With Others}) because it
+%    can cause other packages to fail if they are loaded later. \LaTeX{}
+%    is partly to blame for this because it fails to provide adequate
+%    built-in safeguards in the package loading mechanisms. In the
+%    absence of such safeguards, we will provide them here.
+%    \begin{macrocode}
+\edef\@temp{\catcode 96=\number\catcode 96 }
+\catcode\string `\`=12
+\def\do#1{\catcode\number`#1=\number\catcode`#1}
+\edef\@temp{%
+  \noexpand\AtEndOfPackage{%
+    \@temp
+    \do\"\do\'\do\(\do\)\do\*\do\+\do\,\do\-\do\.%
+    \do\/\do\<\do\=\do\>\do\[\do\]\do\^\do\_\relax
+  }%
+}
+\@temp
+\def\do#1{\catcode\number`#1=12 }
+\do\"\do\'\do\(\do\)\do\*\do\+\do\,\do\-\do\.
+\do\/\do\<\do\=\do\>\do\[\do\]
+\catcode`\^=7 \catcode`\_=8
+%    \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Declare some options}
+%
+%    Handling of limits on integrals, sums, operatornames.
+%    \begin{macrocode}
+\DeclareOption{intlimits}{\let\ilimits@\displaylimits}
+\DeclareOption{nointlimits}{\let\ilimits@\nolimits}
+\DeclareOption{sumlimits}{\let\slimits@\displaylimits}
+\DeclareOption{nosumlimits}{\let\slimits@\nolimits}
+\DeclareOption{namelimits}{\PassOptionsToPackage{namelimits}{amsopn}}
+\DeclareOption{nonamelimits}{%
+  \PassOptionsToPackage{nonamelimits}{amsopn}}
+%    \end{macrocode}
+%
+%    The following two switches might have been defined already by the
+%    documentclass, but it doesn't hurt to re-execute the \cs{newif}'s.
+%    \begin{macrocode}
+\newif\ifctagsplit@
+\newif\iftagsleft@
+%    \end{macrocode}
+%    Right or left placement of equation numbers.
+%    \begin{macrocode}
+\DeclareOption{leqno}{\tagsleft@true}
+\DeclareOption{reqno}{\tagsleft@false}
+\DeclareOption{centertags}{\ctagsplit@true}
+\DeclareOption{tbtags}{\ctagsplit@false}
+%    \end{macrocode}
+%
+%    The \opt{cmex10} option is an escape hatch for people who don't
+%    happen to have sizes 7--9 of the \fn{cmex} fonts available to them
+%    yet. (Strictly speaking they are considered part of a minimum
+%    \latex/ distribution now, i.e., all \LaTeXe{} users should have
+%    them, without needing to get the AMSFonts distrib.)
+%    \begin{macrocode}
+\DeclareOption{cmex10}{%
+  \ifnum\cmex@opt=\@ne \def\cmex@opt{0}%
+  \else \def\cmex@opt{10}\fi
+}
+%    \end{macrocode}
+%    To help things work out better with various package loading orders
+%    of \pkg{amsmath} and \pkg{amsfonts}, we establish a variable to
+%    communicate the status of the cmex font definition. If the
+%    \pkg{amsfonts} package was loaded first this variable might be
+%    already defined, in which case we want to preserve its value.
+%    \begin{macrocode}
+\@ifundefined{cmex@opt}{\def\cmex@opt{7}}{}
+%    \end{macrocode}
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Flush-left equations [DMJ]}
+%
+%    The left margin of math enviroments is controlled by
+%    \cs{@mathmargin}.  This can be set to \cs{@centering} to
+%    implement the default behaviour, i.e., centered equations, and to
+%    something else to implement the flushleft style.
+%
+%    In theory, all that's needed to activate the flushleft mode
+%    in the AMS document classes is something like this:
+% \begin{verbatim}
+% \DeclareOption{fleqn}{%
+%   \AtBeginDocument{\@mathmargin30pt\relax}%
+% }
+% \end{verbatim}
+%    (In fact, unless the document class wants to specify the
+%    \cs{@mathmargin}, it doesn't need to do anything with the
+%    \opt{fleqn} option.)
+%    \begin{macrocode}
+\newif\if@fleqn
+%
+\newskip\@mathmargin
+\@mathmargin\@centering
+%
+\DeclareOption{fleqn}{%
+    \@fleqntrue
+    \@mathmargin = -1sp
+    \let\mathindent=\@mathmargin
+    \AtBeginDocument{%
+        \ifdim\@mathmargin= -1sp
+            \@mathmargin\leftmargini minus\leftmargini
+        \fi
+    }%
+}
+%    \end{macrocode}
+%
+%    DMJ: This ensures that \cs{@mathmargin} is given some sort of
+%    sensible default if the class doesn't specify one, while still
+%    allowing a user to override the default value in their document
+%    preamble.  (Incidentally, I'm initializing \cs{@mathmargin} to
+%    \cs{leftmargini} for compatibility with \fn{fleqn.clo}, but I'm
+%    not at all convinced that's the right thing to do.)
+%
+%    The next question is what happens when amsmath is used with
+%    one of the standard classes.  Unfortunately, \latex/ implements
+%    \opt{fleqn} somewhat clumsily; instead of paramaterizing the
+%    definitions of the math structures (as I've attempted to do
+%    here), \fn{fleqn.clo} declares a dimen \cn{mathindent} that is
+%    much like my \cs{@mathmargin} and then redefines \cn\[, \cn\],
+%    \cn{equation}, and \cn{eqnarray}.  This means that things could
+%    get rather messy in 2.09 compatibility mode, since \fn{fleqn.clo}
+%    might be loaded after \fn{amsmath.sty}, which could cause a real
+%    mess.
+%
+%    [mjd,1999/07/07]: Let \cs{mathindent} = \cs{@mathmargin} as
+%    envisioned by DMJ. Compatibility-mode documents will all use the
+%    \pkg{amstex} package, not \pkg{amsmath}. There is a remote chance
+%    of a problem if someone makes an assignment to \cs{mathindent} in a
+%    way that implicitly assumes it is a dimen register (inasmuch as it
+%    has now become a skip register), and the string ``plus'' follows in
+%    the input stream, but if someone's document croaks in that way, I
+%    think they will just have to bite the bullet and fix it. The
+%    alternative is to penalize a lot of other users with a known
+%    handicap.
+%
+% \section{Spacing around \cn{aligned} and \cn{gathered}}
+%
+%    [dpc, 2016] Option to control the space to the left of aligned and gathered.
+%
+%   Previously \cn{aligned} and \cn{gathered} inserted a thin space on
+%   their left but not their right, there is no good reason for this
+%   that anyone can remember, it has just always been that way
+%   inherited from amstex. The usual advice to authors has been to use
+%   |\!\begin{aligned}| to get better spacing.
+%
+% Here introduce:
+%
+% \opt{alignedleftspaceyes} to keep the behaviour of adding this space.
+%
+% \opt{alignedleftspaceno} to disable adding this space.
+%
+% \opt{alignedleftspaceyesifneg} the new default behaviour, do not add
+% the space unless the environment is preceded by a negative skip or
+% kern, so that |\!\begin{aligned}| works as before.
+%
+% \changes{v2.16a}{2016/11/05}{New options to control aligned spacing}
+%    \begin{macrocode}
+\DeclareOption{alignedleftspaceyes}{\def\alignedspace@left{\null\,}}
+\DeclareOption{alignedleftspaceno}{\def\alignedspace@left{\null}}
+\DeclareOption{alignedleftspaceyesifneg}{%
+\def\alignedspace@left{%
+  \edef\@tempa{\expandafter\@car\the\lastskip\@nil}%
+  \if-\@tempa\null\,%
+  \else
+    \edef\@tempa{\expandafter\@car\the\lastkern\@nil}%
+    \if-\@tempa\null\,%
+    \else\null
+    \fi
+  \fi}%
+}
+%    \end{macrocode}
+%
+%
+%    \begin{macrocode}
+\DeclareOption{?}{}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\ExecuteOptions{%
+  nointlimits,sumlimits,namelimits,centertags,alignedleftspaceyesifneg}
+%    \end{macrocode}
+%    The \cs{par} after \cs{ProcessOptions} is to ensure the correct
+%    line number on screen if an error occurs during option processing;
+%    otherwise the lookahead for a \qc{\*} option would result in \tex/
+%    showing the following line instead.
+%    \begin{macrocode}
+\ProcessOptions\par
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\@ifpackagewith{amsmath}{?}{%
+  \typeout{^^J%
+Documentation for the amsmath package is found in amsldoc.dvi^^J%
+(or .pdf or .tex).^^J%
+^^J%
+See also https://www.ams.org/tex/amslatex.html.^^J%
+^^J%
+Note: Using the first edition of The LaTeX Companion (1994) without^^J%
+errata as a guide for amsmath use is not recommended.^^J%
+  }%
+}{%
+  \typeout{%
+For additional information on amsmath, use the \lq ?\rq\space option.%
+  }%
+}
+%    \end{macrocode}
+%
+%    Processing to handle the \opt{cmex10} option is a little tricky
+%    because of different possible loading orders for \pkg{amsmath} and
+%    \pkg{amsfonts}. The package \pkg{amsmath} sets the \cs{cmex@opt}
+%    flag to 7 or 10, and the package \pkg{amsfonts} sets the flag to 1
+%    or 0.
+%    \begin{macrocode}
+\ifnum\cmex@opt=7 \relax
+  \DeclareFontShape{OMX}{cmex}{m}{n}{%
+    <-8>cmex7<8>cmex8<9>cmex9%
+    <10><10.95><12><14.4><17.28><20.74><24.88>cmex10%
+  }{}%
+  \expandafter\let\csname OMX/cmex/m/n/10\endcsname\relax
+\else
+  \ifnum\cmex@opt=\z@ % need to override cmex7 fontdef from amsfonts
+%    \end{macrocode}
+%    Force reloading of the OMX/cmex font definition file.
+%    \begin{macrocode}
+    \begingroup
+    \fontencoding{OMX}\fontfamily{cmex}%
+    \expandafter\let\csname OMX+cmex\endcsname\relax
+    \try@load@fontshape
+    \endgroup
+%    \end{macrocode}
+%    The \fn{cmex10} font gets special preload handling in the building
+%    of the \latex/ format file, need an extra bit here to work around
+%    that.
+%    \begin{macrocode}
+    \expandafter\let\csname OMX/cmex/m/n/10\endcsname\relax
+    \def\cmex@opt{10}%
+  \fi
+\fi
+%    \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Call some other packages}
+%
+%    The \pkg{amstext} package provides the \cn{text} command. The
+%    \pkg{amsbsy} package provides \cn{boldsymbol} and \cn{pmb}. (Since
+%    1997 it is usually better to use the \pkg{bm} package instead; but
+%    I think we have to keep \pkg{amsbsy} here for backward
+%    compatibility [mjd,1999/11/19].) The \pkg{amsopn} package provides
+%    \cn{DeclareMathOperator}.
+%    \begin{macrocode}
+\RequirePackage{amstext}[1995/01/25]
+\RequirePackage{amsbsy}[1995/01/20]
+\RequirePackage{amsopn}[1995/01/20]
+%    \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Miscellaneous}
+%
+%  \begin{macro}{\ams@newcommand}
+%    Where \pkg{stix} and \pkg{amsmath} define the same control
+%    sequences, we want to avoid inadvertently overriding \pkg{stix}'s
+%    definitions.  If \pkg{stix} is loaded before \pkg{amsmath}, the
+%    following conditional takes care of the problem.  There is
+%    similar code in the \pkg{stix} package in case \pkg{amsmath} is
+%    loaded first.
+%    \begin{macrocode}
+\@ifpackageloaded{stix}{%
+    \let\ams@newcommand\providecommand
+    \let\ams@renewcommand\providecommand
+    \let\ams@def\providecommand
+    \let\ams@DeclareRobustCommand\providecommand
+}{%
+    \let\ams@newcommand\newcommand
+    \let\ams@renewcommand\renewcommand
+    \let\ams@def\def
+    \let\ams@DeclareRobustCommand\DeclareRobustCommand
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%  \begin{macro}{\@amsmath@err}
+%    Defining this error function saves main mem.
+%    \begin{macrocode}
+\def\@amsmath@err{\PackageError{amsmath}}
+%    \end{macrocode}
+%  \end{macro}
+%
+% \begin{macro}{\AmS}
+%    The \cs{AmS} prefix can be used to construct the combination
+%    |\AmS-\LaTeX|.
+%    \begin{macrocode}
+\providecommand{\AmS}{{\protect\AmSfont
+  A\kern-.1667em\lower.5ex\hbox{M}\kern-.125emS}}
+%    \end{macrocode}
+%    In \cn{AmSfont} we call cmsy directly in lieu of trying to access
+%    it through the math fonts setup (e.g. |\the\textfont2|) because
+%    math fonts can't be relied on to be properly set up if we are not
+%    inside a math formula. This means that if this command is used in a
+%    document where CM fonts are not wanted, then a font substitution
+%    will need to be declared, e.g.:
+% \begin{verbatim}
+% \DeclareFontShape{OMS}{cmsy}{m}{n}{ <-> sub * xxx/m/n }{}
+% \end{verbatim}
+%    where |xxx| is some alternate font family.
+%    Taking the first letter of \cs{f@series} will produce |b| or |m|
+%    for the most common values (|b,bx,m|). It may produce nonsense for
+%    more unusual values of \cs{f@series}, so for safety's sake we have
+%    an additional \cs{if} test. We want to avoid setting the series to
+%    |bx| because in a standard \latex/ installation the combination
+%    |cmsy/bx/n| does not have a font definition, and the user
+%    would get a font substitution warning on screen.
+%    \begin{macrocode}
+\newcommand{\AmSfont}{%
+  \usefont{OMS}{cmsy}{\if\@xp\@car\f@series\@nil bb\else m\fi}{n}}
+%    \end{macrocode}
+% \end{macro}
+%
+%  \begin{macro}{\@mathmeasure}
+%    The function |\@mathmeasure| takes three arguments; the third arg
+%    is typeset as a math formula in an hbox, using arg |#2| as the
+%    mathstyle, and the result is left in the box named by the first
+%    arg. It is assumed that we are already in math mode, so we can turn
+%    off |\everymath| (in particular, |\check@mathfonts|).
+%
+%    As of 2018/12 release we don't turn off |\evermath| as this
+%    optimization can be harmful.
+% \changes{v2.17b}{2018/12/01}{Don't drop \cs{frozen@everymath}}
+%    \begin{macrocode}
+\ifx\leavevmode@ifvmode\@undefined  % kernel is < 2018/12
+\def\@mathmeasure#1#2#3{\setbox#1\hbox{\frozen@everymath\@emptytoks
+    \m@th$#2#3$}}
+\else
+\def\@mathmeasure#1#2#3{\setbox#1\hbox{%
+  \m@th$#2#3$}}
+\fi
+%    \end{macrocode}
+%  \end{macro}
+%
+%    The \cs{inf@bad} constant is for testing overfull boxes.
+%    \begin{macrocode}
+\@ifundefined{inf@bad}{%
+  \newcount\inf@bad \inf@bad=1000000 \relax
+}{}
+%    \end{macrocode}
+%
+%\subsection{Math spacing commands}
+%
+%    \begin{macro}{\tmspace}
+%    \begin{macro}{\,}
+%    \begin{macro}{\thinspace}
+%    \begin{macro}{\!}
+%    \begin{macro}{\negthinspace}
+%    \begin{macro}{\:}
+%    \begin{macro}{\medspace}
+%    \begin{macro}{\negmedspace}
+%    \begin{macro}{\;}
+%    \begin{macro}{\thickspace}
+%    \begin{macro}{\negthickspace}
+%    Here we fill in some gaps in the set of spacing commands, and make them
+%    all work equally well in or out of math.
+%    We want all these commands to be robust but declaring them all with
+%    \cs{DeclareRobustCommand} uses up an control sequence name per
+%    command; to avoid this, we define a common command \cs{tmspace}
+%    (text-or-math space) which carries the robustness burden for all of
+%    them. The standard \cs{relax} before the \cs{ifmmode} is not
+%    necessary because of the \cs{protect} added by
+%    \cs{DeclareRobustCommand}.
+% \changes{v2.17b}{2018/12/01}{Start LR-mode for \cs{thinspace} and
+%   friends if necessary (github/49)}
+%    \begin{macrocode}
+\ifx\leavevmode@ifvmode\@undefined
+\DeclareRobustCommand{\tmspace}[3]{%
+  \ifmmode\mskip#1#2\else\kern#1#3\fi\relax}
+\else
+\DeclareRobustCommand{\tmspace}[3]{%
+  \ifmmode\mskip#1#2\else\leavevmode@ifvmode\kern#1#3\fi\relax}
+\fi
+\renewcommand{\,}{\tmspace+\thinmuskip{.1667em}}
+\let\thinspace\,
+\renewcommand{\!}{\tmspace-\thinmuskip{.1667em}}
+\let\negthinspace\!
+\renewcommand{\:}{\tmspace+\medmuskip{.2222em}}
+\let\medspace\:
+\newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}}
+\renewcommand{\;}{\tmspace+\thickmuskip{.2777em}}
+\let\thickspace\;
+\newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%  \begin{macro}{\mspace}
+%    And while we're at it, why don't we provide an equivalent of
+%    \cn{hspace} for math mode use. This allows use of |mu| units in
+%    (for example) constructing compound math symbols.
+%    \begin{macrocode}
+\newcommand{\mspace}[1]{\mskip#1\relax}
+%    \end{macrocode}
+%  \end{macro}
+%
+% \subsection{Vertical bar symbols}
+%    \begin{macro}{\lvert}
+%    \begin{macro}{\rvert}
+%    \begin{macro}{\lVert}
+%    \begin{macro}{\rVert}
+%    Add left/right specific versions of \cn{vert}, \cn{Vert}. Don't
+%    assume the delimiter codes are the CM defaults.
+%    \begin{macrocode}
+\def\@tempa#1#2\@nil{%
+  \ifx\delimiter#1\@tempcnta#2\relax\else\@tempcnta\z@\fi
+}
+\@xp\@tempa\vert\@empty\@nil
+\ifnum\@tempcnta>\z@
+  \advance\@tempcnta "4000000
+  \xdef\lvert{\delimiter\number\@tempcnta\space }
+  \advance\@tempcnta "1000000
+  \xdef\rvert{\delimiter\number\@tempcnta\space }
+\else
+  \ifx\@@undefined\lvert
+    % Fall back to cmex encoding since we don't know what else to do.
+    \DeclareMathDelimiter{\lvert}
+      {\mathopen}{symbols}{"6A}{largesymbols}{"0C}
+    \DeclareMathDelimiter{\rvert}
+      {\mathclose}{symbols}{"6A}{largesymbols}{"0C}
+  \fi
+\fi
+\@xp\@tempa\Vert\@empty\@nil
+\ifnum\@tempcnta>\z@
+  \advance\@tempcnta "4000000
+  \xdef\lVert{\delimiter\number\@tempcnta\space }
+  \advance\@tempcnta "1000000
+  \xdef\rVert{\delimiter\number\@tempcnta\space }
+\else
+  \ifx\@@undefined\lVert
+    \DeclareMathDelimiter{\lVert}
+      {\mathopen}{symbols}{"6B}{largesymbols}{"0D}
+    \DeclareMathDelimiter{\rVert}
+      {\mathclose}{symbols}{"6B}{largesymbols}{"0D}
+  \fi
+\fi
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+% \subsection{Fractions}
+%    Bury the generalized fraction primitives \cs{over}, \cs{atop},
+%    etc., because of their bizarre syntax, which is decidedly out of
+%    place in a \latex/ document.
+%    \begin{macrocode}
+\@saveprimitive\over\@@over
+\@saveprimitive\atop\@@atop
+\@saveprimitive\above\@@above
+\@saveprimitive\overwithdelims\@@overwithdelims
+\@saveprimitive\atopwithdelims\@@atopwithdelims
+\@saveprimitive\abovewithdelims\@@abovewithdelims
+%    \end{macrocode}
+%
+%    \begin{macro}{\primfrac}
+%    If someone insists on using \cs{over}, give a warning the first
+%    time and then resurrect the old definition. Laissez-faire policy.
+%    \begin{macrocode}
+\DeclareRobustCommand{\primfrac}[1]{%
+  \PackageWarning{amsmath}{%
+Foreign command \@backslashchar#1;\MessageBreak
+\protect\frac\space or \protect\genfrac\space should be used instead%
+\MessageBreak
+  }
+  \global\@xp\let\csname#1\@xp\endcsname\csname @@#1\endcsname
+  \csname#1\endcsname
+}
+%    \end{macrocode}
+%    \end{macro}
+%    \begin{macrocode}
+\renewcommand{\over}{\primfrac{over}}
+\renewcommand{\atop}{\primfrac{atop}}
+\renewcommand{\above}{\primfrac{above}}
+\renewcommand{\overwithdelims}{\primfrac{overwithdelims}}
+\renewcommand{\atopwithdelims}{\primfrac{atopwithdelims}}
+\renewcommand{\abovewithdelims}{\primfrac{abovewithdelims}}
+%    \end{macrocode}
+%
+%    \cn{frac} calls \cn{@@over} directly instead of via \cn{genfrac}, for
+%    better speed because it is so common. \cn{tfrac} and \cn{dfrac} are
+%    abbreviations for some commonly needed mathstyle overrides. To
+%    conserve csnames we avoid making \cn{dfrac} and \cn{tfrac} robust
+%    (\cn{genfrac} is itself robust).
+%    \begin{macrocode}
+\DeclareRobustCommand{\frac}[2]{{\begingroup#1\endgroup\@@over#2}}
+\newcommand{\dfrac}{\genfrac{}{}{}0}
+\newcommand{\tfrac}{\genfrac{}{}{}1}
+%    \end{macrocode}
+%    The \cn{binom} command for binomial notation works like \cn{frac}
+%    and has similar variants. Note that we do not use \cs{z@} in
+%    \cn{dbinom} and \cn{tbinom} because they are not top-level robust
+%    like \cn{binom}, and so the \cs{z@} with the potentially
+%    problematic \qc{\@} character would become visible when writing one
+%    of those commands to a \fn{.toc} file.
+%    \begin{macrocode}
+\DeclareRobustCommand{\binom}{\genfrac()\z@{}}
+\newcommand{\dbinom}{\genfrac(){0pt}0}
+\newcommand{\tbinom}{\genfrac(){0pt}1}
+%    \end{macrocode}
+%
+%  \begin{macro}{\genfrac}
+% \changes{v2.16a}{2016/11/05}{New genfrac implementation for extended
+% TeXs}
+%    This command provides access to \tex/'s generalized fraction
+%    primitives. Args: \arg{1} left delim, \arg{2} right delim, \arg{3}
+%    line thickness, \arg{4} mathstyle override, \arg{5} numerator,
+%    \arg{6} denominator. But we only read the first four args at first,
+%    in order to give us a moment to select the proper generalized
+%    fraction primitive. Any of those four args could be empty, and when
+%    empty the obvious defaults are selected (no delimiters, default
+%    line thickness (normally .4pt), and no mathstyle override).
+%
+%    the |withdelims| primitives do not work in xetex with OpenType
+%    fonts, and the relevant font dimen parameters are often not set
+%    in luatex as theer are no matching values in the OpenType Math
+%    table, so here we use variants that use the font parameters if
+%    they are set, but scale using |\left\right| rather than the
+%    |withdelims| primitives.
+%
+%    \begin{macrocode}
+\ifx\directlua\@undefined
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\ifx\XeTeXcharclass\@undefined
+%    \end{macrocode}
+% Classic version
+%    \begin{macrocode}
+\DeclareRobustCommand{\genfrac}[4]{%
+  \def\@tempa{#1#2}%
+  \edef\@tempb{\@nx\@genfrac\@mathstyle{#4}%
+    \csname @@\ifx @#3@over\else above\fi
+    \ifx\@tempa\@empty \else withdelims\fi\endcsname}
+  \@tempb{#1#2#3}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\else   
+%    \end{macrocode}
+%     XeTeX version
+%    \begin{macrocode}
+\def\genfrac@rule#1#2#3#4{%
+\hbox{$\left#1\vcenter{\hrule \@width\z@
+                       \@height 
+                       \ifdim\fontdimen#2#3\tw@=\z@
+                       #4\fontdimen6#3\tw@
+                       \else
+                       \fontdimen#2#3\tw@
+                       \fi
+                      }\right.$}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\genfrac@choice#1#2{%
+\ifx @#2@\else
+%    \end{macrocode}
+% \changes{v2.17a}{2017/09/02}{move \cs{nulldelimiterspace} correction}
+%    \begin{macrocode}
+\ifx c#1\kern-\nulldelimiterspace\fi
+{\delimitershortfall\z@\delimiterfactor\@m
+ \mathsurround\z@\nulldelimiterspace\z@
+\mathchoice
+{\genfrac@rule{#2}{20}\textfont{2.39}}%
+{\genfrac@rule{#2}{21}\textfont{1}}%
+{\genfrac@rule{#2}{21}\scriptfont{1.45}}%
+{\genfrac@rule{#2}{21}\scriptscriptfont{1.35}}%
+}%
+\ifx o#1\kern-\nulldelimiterspace\fi
+\fi
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\DeclareRobustCommand{\genfrac}[6]{{%
+\@mathstyle{#4}%
+\genfrac@choice o{#1}%
+{\begingroup#5\endgroup\ifx @#3@\@@over\else\@@above\fi#3\relax#6}%
+\genfrac@choice c{#2}%
+}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\fi
+\else
+%    \end{macrocode}
+% LuaTeX version
+%    \begin{macrocode}
+\def\genfrac@rule#1#2#3{%
+\hbox{$\left#1\vcenter{\hrule \@width\z@
+                       \@height 
+                       \ifdim\Umathfractiondelsize#2=\z@
+                       #3\fontdimen6#3\tw@
+                       \else
+                       \Umathfractiondelsize#2%
+                       \fi
+                      }\right.$}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\genfrac@choice#1#2{%
+\ifx @#2@\else
+%    \end{macrocode}
+% \changes{v2.17a}{2017/09/02}{move \cs{nulldelimiterspace} correction}
+%    \begin{macrocode}
+\ifx c#1\kern-\nulldelimiterspace\fi
+{\delimitershortfall\z@\delimiterfactor\@m
+ \mathsurround\z@\nulldelimiterspace\z@
+\mathchoice
+{\genfrac@rule{#2}\displaystyle{2.39}}%
+{\genfrac@rule{#2}\textstyle{1}}%
+{\genfrac@rule{#2}\scriptstyle{1.45}}%
+{\genfrac@rule{#2}\scriptscriptstyle{1.35}}%
+}%
+\ifx o#1\kern-\nulldelimiterspace\fi
+\fi
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\DeclareRobustCommand{\genfrac}[6]{{%
+\@mathstyle{#4}%
+\genfrac@choice o{#1}%
+{\begingroup#5\endgroup\ifx @#3@\@@over\else\@@above\fi#3\relax#6}%
+\genfrac@choice c{#2}%
+}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\fi
+%    \end{macrocode}
+%
+% End of test for Lua\TeX/Xe\TeX.
+%
+%    \cs{@genfrac} takes the preceding arguments and reads the
+%    numerator and denominator. Note that there's no convenient way to
+%    make the numerator and denominator \emph{contents}
+%    displaystyle, through this interface.
+%
+%    Args: \arg{1} mathstyle, \arg{2} fraction primitive,
+%    \arg{3} delimiters and rule thickness,
+%    \arg{4} numerator, \arg{5} denominator.
+%    \begin{macrocode}
+\def\@genfrac#1#2#3#4#5{{#1{\begingroup#4\endgroup#2#3\relax#5}}}
+%    \end{macrocode}
+%  \end{macro}
+%
+%    Empty mathstyle arg: no change; 0 = displaystyle, 1 = textstyle, 2
+%    = scriptstyle, 3 = scriptscriptstyle.
+%    \begin{macrocode}
+\def\@mathstyle#1{%
+  \ifx\@empty#1\@empty\relax
+  \else\ifcase#1\displaystyle % case 0
+    \or\textstyle\or\scriptstyle\else\scriptscriptstyle\fi\fi}
+%    \end{macrocode}
+%
+% \subsection{Sums and Integrals}
+%    Default value for sum limits is \cs{displaylimits}, see option
+%    `nosumlimits'.
+%
+%    We redefine all the cumulative operator symbols to use
+%    \cs{slimits@} so that switching between \cs{displaylimits} and
+%    \cs{nolimits} can be controlled by package options. Also add
+%    \cs{DOTSB} for the benefit of the dots lookahead. But we'd better
+%    make sure \cn{coprod} and the others are simple mathchars; if not,
+%    the attempted changes will probably fail miserably.
+%
+% \changes{v2.15}{2016/02/20}{Accept \cs{Umathchar}}
+%    \begin{macrocode}
+\begingroup
+%    \end{macrocode}
+%    \begin{macrocode}
+\edef\@tempa{\string\mathchar"}
+\edef\@tempd{\string\Umathchar"}
+\def\@tempb#1"#2\@nil{#1"}
+\edef\@tempc{\expandafter\@tempb\meaning\coprod "\@nil}
+\ifx\@tempc\@tempd\let\@tempc\@tempa\fi
+%    \end{macrocode}
+%    \begin{macrocode}
+\ifx\@tempa\@tempc
+  \global\let\coprod@\coprod
+  \gdef\coprod{\DOTSB\coprod@\slimits@}
+  \global\let\bigvee@\bigvee
+  \gdef\bigvee{\DOTSB\bigvee@\slimits@}
+  \global\let\bigwedge@\bigwedge
+  \gdef\bigwedge{\DOTSB\bigwedge@\slimits@}
+  \global\let\biguplus@\biguplus
+  \gdef\biguplus{\DOTSB\biguplus@\slimits@}
+  \global\let\bigcap@\bigcap
+  \gdef\bigcap{\DOTSB\bigcap@\slimits@}
+  \global\let\bigcup@\bigcup
+  \gdef\bigcup{\DOTSB\bigcup@\slimits@}
+  \global\let\prod@\prod
+  \gdef\prod{\DOTSB\prod@\slimits@}
+  \global\let\sum@\sum
+  \gdef\sum{\DOTSB\sum@\slimits@}
+  \global\let\bigotimes@\bigotimes
+  \gdef\bigotimes{\DOTSB\bigotimes@\slimits@}
+  \global\let\bigoplus@\bigoplus
+  \gdef\bigoplus{\DOTSB\bigoplus@\slimits@}
+  \global\let\bigodot@\bigodot
+  \gdef\bigodot{\DOTSB\bigodot@\slimits@}
+  \global\let\bigsqcup@\bigsqcup
+  \gdef\bigsqcup{\DOTSB\bigsqcup@\slimits@}
+\fi
+\endgroup
+%    \end{macrocode}
+%
+% \subsection{Roots and radicals}
+%
+%    \begin{macro}{\root}
+%    This root stuff needs syntax work and implementation work. Surely
+%    something more compact can be done?? [mjd, 1994/09/05]
+%    \begin{macrocode}
+\newcommand{\leftroot}{\@amsmath@err{\Invalid@@\leftroot}\@eha}
+\newcommand{\uproot}{\@amsmath@err{\Invalid@@\uproot}\@eha}
+\newcount\uproot@
+\newcount\leftroot@
+\renewcommand{\root}{\relaxnext@
+  \DN@{\ifx\@let@token\uproot\let\next@\nextii@\else
+   \ifx\@let@token\leftroot\let\next@\nextiii@\else
+   \let\next@\plainroot@\fi\fi\next@}%
+  \def\nextii@\uproot##1{\uproot@##1\relax\FN@\nextiv@}%
+  \def\nextiv@{\ifx\@let@token\@sptoken\DN@. {\FN@\nextv@}\else
+   \DN@.{\FN@\nextv@}\fi\next@.}%
+  \def\nextv@{\ifx\@let@token\leftroot\let\next@\nextvi@\else
+   \let\next@\plainroot@\fi\next@}%
+  \def\nextvi@\leftroot##1{\leftroot@##1\relax\plainroot@}%
+   \def\nextiii@\leftroot##1{\leftroot@##1\relax\FN@\nextvii@}%
+  \def\nextvii@{\ifx\@let@token\@sptoken
+   \DN@. {\FN@\nextviii@}\else
+   \DN@.{\FN@\nextviii@}\fi\next@.}%
+  \def\nextviii@{\ifx\@let@token\uproot\let\next@\nextix@\else
+   \let\next@\plainroot@\fi\next@}%
+  \def\nextix@\uproot##1{\uproot@##1\relax\plainroot@}%
+  \bgroup\uproot@\z@\leftroot@\z@\FN@\next@}
+\def\plainroot@#1\of#2{\setbox\rootbox\hbox{%
+ $\m@th\scriptscriptstyle{#1}$}%
+ \mathchoice{\r@@t\displaystyle{#2}}{\r@@t\textstyle{#2}}
+ {\r@@t\scriptstyle{#2}}{\r@@t\scriptscriptstyle{#2}}\egroup}
+%    \end{macrocode}
+%    \end{macro}
+%
+% \changes{v2.0}{1999/06/17}{Normalize @@sqrt to sqrtsign}
+
+%    Name change from \cs{@@sqrt} to \cs{sqrtsign} happened in the
+%    1995/12/01 release of \latex/. If we were to assume that
+%    \cs{sqrtsign} is defined then someone with the 1995/06/01 release
+%    of \latex/ would have trouble using this package.
+%    \begin{macrocode}
+\@ifundefined{sqrtsign}{\let\sqrtsign\@@sqrt}{}
+\def\r@@t#1#2{\setboxz@h{$\m@th#1\sqrtsign{#2}$}%
+ \dimen@\ht\z@\advance\dimen@-\dp\z@
+ \setbox\@ne\hbox{$\m@th#1\mskip\uproot@ mu$}%
+ \advance\dimen@ by1.667\wd\@ne
+ \mkern-\leftroot@ mu\mkern5mu\raise.6\dimen@\copy\rootbox
+ \mkern-10mu\mkern\leftroot@ mu\boxz@}
+%    \end{macrocode}
+%
+% \subsection{Et cetera}
+%
+% \changes{v2.0}{1999/06/18}{Leave Greek cap letters unaltered}
+%
+%    Specific names for the variant italic cap Greek letters are not
+%    defined by \latex/. If no preceding package defined these, we will
+%    define them now.
+%    \begin{macrocode}
+\@ifundefined{varGamma}{%
+  \DeclareMathSymbol{\varGamma}{\mathord}{letters}{"00}
+  \DeclareMathSymbol{\varDelta}{\mathord}{letters}{"01}
+  \DeclareMathSymbol{\varTheta}{\mathord}{letters}{"02}
+  \DeclareMathSymbol{\varLambda}{\mathord}{letters}{"03}
+  \DeclareMathSymbol{\varXi}{\mathord}{letters}{"04}
+  \DeclareMathSymbol{\varPi}{\mathord}{letters}{"05}
+  \DeclareMathSymbol{\varSigma}{\mathord}{letters}{"06}
+  \DeclareMathSymbol{\varUpsilon}{\mathord}{letters}{"07}
+  \DeclareMathSymbol{\varPhi}{\mathord}{letters}{"08}
+  \DeclareMathSymbol{\varPsi}{\mathord}{letters}{"09}
+  \DeclareMathSymbol{\varOmega}{\mathord}{letters}{"0A}
+}{}
+%    \end{macrocode}
+%
+%    \begin{macro}{\overline}
+%    \amstex/ redefines \cn{overline} as shown here, for reasons that
+%    are probably less important in \latex/: Make it read its argument
+%    as a macro argument rather than a ``math field'' (\emph{The
+%    \tex/book}, Chapter 26), to avoid problems when something that is
+%    apparently a single symbol is actually a non-simple macro (e.g.,
+%    \cn{dag}) \emph{and} is given as a single-token argument without
+%    enclosing braces.
+%    \begin{macrocode}
+\@saveprimitive\overline\@@overline
+\DeclareRobustCommand{\overline}[1]{\@@overline{#1}}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\boxed}
+%    The \cs{boxed} command is specifically intended to put a box around
+%    an equation or piece of an equation. (Not including the equation
+%    number.) This isn't trivial for end-users to do it properly
+%    with \cs{fbox} so we provide a command for them.
+%    \begin{macrocode}
+\newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\implies}
+%    \begin{macro}{\impliedby}
+%    \begin{macrocode}
+\newcommand{\implies}{\DOTSB\;\Longrightarrow\;}
+\newcommand{\impliedby}{\DOTSB\;\Longleftarrow\;}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macro}{\And}
+%    \begin{macrocode}
+\def\And{\DOTSB\;\mathchar"3026 \;}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\nobreakdash}
+%    The command \cn{nobreakdash} is designed only for use before a
+%    hyphen or dash (|-|, |--|, or |---|).
+%    Setting the hyphen in a box and then unboxing it means that the
+%    normal penalty will not be added after it---and if the penalty is
+%    not there a break will not be taken (unless an explicit penalty
+%    or glue follows, thus the final \verb=\nobreak=).
+%    \begin{macrocode}
+\newcommand{\nobreakdash}{\leavevmode
+  \toks@\@emptytoks \def\@tempa##1{\toks@\@xp{\the\toks@-}\FN@\next@}%
+  \DN@{\ifx\@let@token-\@xp\@tempa
+       \else\setboxz@h{\the\toks@\nobreak}\unhbox\z@\fi}%
+  \FN@\next@
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\colon}
+%    \cs{colon} is for a colon in math that resembles a text colon:
+%    small space on the left, larger space on the right. The \qc{\:}
+%    character by itself is treated as a \cs{mathrel} i.e. large, equal
+%    spacing on both sides.
+%    \begin{macrocode}
+\renewcommand{\colon}{\nobreak\mskip2mu\mathpunct{}\nonscript
+  \mkern-\thinmuskip{:}\mskip6muplus1mu\relax}
+%    \end{macrocode}
+%    \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Ellipsis dots}
+%
+%    We can't use \cs{newif} for \cs{ifgtest@} because we want
+%    to include \cs{global} in the definitions of
+%    \cs{gtest@true} and \cs{gtest@false}.
+%    \begin{macrocode}
+\let\ifgtest@\iffalse                              % initial value
+\def\gtest@true{\global\let\ifgtest@\iftrue}
+\def\gtest@false{\global\let\ifgtest@\iffalse}
+\let\DOTSI\relax
+\let\DOTSB\relax
+\let\DOTSX\relax
+{\uccode`7=`\\ \uccode`8=`m \uccode`9=`a \uccode`0=`t \uccode`!=`h
+ \uppercase{%
+  \gdef\math@#1#2#3#4#5#6\math@{\gtest@false\ifx 7#1\ifx 8#2%
+  \ifx 9#3\ifx 0#4\ifx !#5\xdef\meaning@{#6}\gtest@true
+  \fi\fi\fi\fi\fi}}}
+{\uccode`7=`c \uccode`8=`h \uccode`9=`\"
+ \uppercase{\gdef\mathch@#1#2#3#4#5#6\mathch@{\gtest@false
+  \ifx 7#1\ifx 8#2\ifx 9#5\gtest@true\xdef\meaning@{9#6}\fi\fi\fi}}}
+%    \end{macrocode}
+% \changes{v2.15}{2016/02/20}{Accept \cs{Umathchar}}
+%    \begin{macrocode}
+{\uccode`(=`U \uccode`)=`m
+ \uppercase{\gdef\Umathch@#1#2#3#4"#5"#6\Umathch@{\gtest@false
+  \ifx(#2\ifx)#3\gtest@true
+  \ifcase"#5 \or\or\gdef\thedots@{\dotsb@}\or\gdef\thedots@{\dotsb@}\fi
+  \fi\fi
+  }}}
+%    \end{macrocode}
+% \changes{v2.15}{2016/02/20}{Decode the mathcode of character tokens for Unicode TeX}
+% For Unicode TeXs, if the next token is a character token look up the (U)mathcode. Do not do this for classic TeX for compatibility reasons.
+%    \begin{macrocode}
+\ifx\Umathcharnumdef\@undefined
+\gdef\thecharacter@#1\thecharacter@{}
+\else
+{\uccode`(=`t \uccode`)=`c
+ \uppercase{\gdef\thecharacter@#1#2#3#4#5\thecharacter@{%
+  \ifx(#1\ifx)#4%
+    \@xp\getmathcode@\meaning@\getmathcode@
+  \fi\fi
+}}}
+\def\getmathcode@#1 #2 #3#4\getmathcode@{%
+  \Umathcharnumdef\@tempa\Umathcodenum`#3\relax
+  \edef\meaning@{\meaning\@tempa}%
+  \@xp\Umathch@\meaning@\Umathch@
+}
+\fi
+%    \end{macrocode}
+%    \begin{macrocode}
+\newcount\classnum@
+\def\getmathch@#1.#2\getmathch@{\classnum@#1 \divide\classnum@4096
+ \ifcase\number\classnum@\or\or\gdef\thedots@{\dotsb@}\or
+ \gdef\thedots@{\dotsb@}\fi}
+{\uccode`4=`b \uccode`5=`i \uccode`6=`n
+ \uppercase{\gdef\mathbin@#1#2#3{\relaxnext@
+  \def\nextii@##1\mathbin@{\ifx\@sptoken\@let@token\gtest@true\fi}%
+  \gtest@false\DN@##1\mathbin@{}%
+ \ifx 4#1\ifx 5#2\ifx 6#3\DN@{\FN@\nextii@}\fi\fi\fi\next@}}}
+{\uccode`4=`r \uccode`5=`e \uccode`6=`l
+ \uppercase{\gdef\mathrel@#1#2#3{\relaxnext@
+  \def\nextii@##1\mathrel@{\ifx\@sptoken\@let@token\gtest@true\fi}%
+ \gtest@false\DN@##1\mathrel@{}%
+ \ifx 4#1\ifx 5#2\ifx 6#3\DN@{\FN@\nextii@}\fi\fi\fi\next@}}}
+{\uccode`5=`m \uccode`6=`a \uccode`7=`c
+ \uppercase{\gdef\macro@#1#2#3#4\macro@{\gtest@false
+  \ifx 5#1\ifx 6#2\ifx 7#3\gtest@true
+  \xdef\meaning@{\macro@@#4\macro@@}\fi\fi\fi}}}
+\def\macro@@#1->#2\macro@@{#2}
+\newcount\DOTSCASE@
+{\uccode`6=`\\ \uccode`7=`D \uccode`8=`O \uccode`9=`T \uccode`0=`S
+ \uppercase{\gdef\DOTS@#1#2#3#4#5{\gtest@false\DN@##1\DOTS@{}%
+  \ifx 6#1\ifx 7#2\ifx 8#3\ifx 9#4\ifx 0#5\let\next@\DOTS@@
+  \fi\fi\fi\fi\fi
+  \next@}}}
+{\uccode`3=`B \uccode`4=`I \uccode`5=`X
+ \uppercase{\gdef\DOTS@@#1{\relaxnext@
+  \def\nextii@##1\DOTS@{\ifx\@sptoken\@let@token\gtest@true\fi}%
+  \DN@{\FN@\nextii@}%
+  \ifx 3#1\global\DOTSCASE@\z@\else
+  \ifx 4#1\global\DOTSCASE@\@ne\else
+  \ifx 5#1\global\DOTSCASE@\tw@\else\DN@##1\DOTS@{}%
+  \fi\fi\fi\next@}}}
+{\uccode`5=`\\ \uccode`6=`n \uccode`7=`o \uccode`8=`t
+ \uppercase{\gdef\not@#1#2#3#4{\relaxnext@
+  \def\nextii@##1\not@{\ifx\@sptoken\@let@token\gtest@true\fi}%
+ \gtest@false\DN@##1\not@{}%
+ \ifx 5#1\ifx 6#2\ifx 7#3\ifx 8#4\DN@{\FN@\nextii@}\fi\fi\fi
+ \fi\next@}}}
+%    \end{macrocode}
+% \changes{v2.15}{2016/02/20}{macro added to strip \cs{long} during tests}
+%    \begin{macrocode}
+{\uccode`9=`\l %
+ \uppercase{\gdef\striplong@#1#2#3\relax{%
+  \ifx9#2 \@xp\@xp\@xp\zap@to@space\fi}}}
+\def\zap@to@space#1 {}
+%    \end{macrocode}
+%    \begin{macrocode}
+\def\keybin@{\gtest@true
+ \ifx\@let@token+\else\ifx\@let@token=\else
+ \ifx\@let@token<\else\ifx\@let@token>\else
+ \ifx\@let@token-\else\ifx\@let@token*\else\ifx\@let@token:\else
+   \gtest@false\fi\fi\fi\fi\fi\fi\fi}
+%    \end{macrocode}
+%    Patch to ensure \cs{@ldots} is defined. (Name changed to
+%    \cn{mathellipsis} in Dec 94 release of \latex/.)
+%    \begin{macrocode}
+\@ifundefined{@ldots}{\def\@ldots{\mathellipsis}}{}
+%    \end{macrocode}
+%    \begin{macro}{\ldots}
+%    \begin{macro}{\dots}
+%    Reiterate the standard definition of \cs{ldots} to keep it from
+%    being clobbered by the redefinition of \cs{dots}.
+%    \begin{macrocode}
+\DeclareRobustCommand{\ldots}{%
+  \ifmmode \mathellipsis \else \textellipsis \fi
+}
+\DeclareRobustCommand{\dots}{%
+  \ifmmode \@xp\mdots@\else \@xp\textellipsis \fi
+}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \begin{macrocode}
+\def\tdots@{\leavevmode\unskip\relaxnext@
+ \DN@{$\m@th\@ldots\,
+   \ifx\@let@token,\,$\else\ifx\@let@token.\,$\else
+   \ifx\@let@token;\,$\else\ifx\@let@token:\,$\else
+   \ifx\@let@token?\,$\else\ifx\@let@token!\,$\else
+     $ \fi\fi\fi\fi\fi\fi}%
+  \ \FN@\next@}
+\def\mdots@{\FN@\mdots@@}
+%    \end{macrocode}
+% \changes{v2.15}{2016/02/20}{Indent \cs{mdots@@} for readability and add additional tests}
+%    \begin{macrocode}
+\def\mdots@@{\gdef\thedots@{\dotso@}%
+ \ifx\@let@token\boldsymbol 
+   \gdef\thedots@\boldsymbol{\boldsymboldots@}%
+ \else
+   \ifx,\@let@token \gdef\thedots@{\dotsc}%
+   \else
+     \ifx\not\@let@token
+       \gdef\thedots@{\dotsb@}%
+     \else
+       \keybin@
+       \ifgtest@ % if \keybin@ test
+         \gdef\thedots@{\dotsb@}%
+       \else
+%    \end{macrocode}
+% \changes{v2.15d}{2016/06/28}{Add space token to prevent runaway argument error}
+%    \begin{macrocode}
+         \xdef\meaning@{\meaning\@let@token. .........}%
+%    \end{macrocode}
+% In previous versions \verb|\long| macros were not seen by the lokkahead.
+% That was bad as this file uses \verb|\(re)newcommand| for \verb|\implies| etc.
+%    \begin{macrocode}
+         \xdef\meaning@@{\@xp\striplong@\meaning@\relax\meaning@}%
+%    \end{macrocode}
+%    \begin{macrocode}
+         \@xp\math@\meaning@\math@
+         \ifgtest@ % if \mathxxx test
+           \@xp\mathch@\meaning@\mathch@
+           \ifgtest@ % if \mathchar
+             \@xp\getmathch@\meaning@\getmathch@
+           \fi % end if \mathchar
+         \else  % \not \mathxxx
+%    \end{macrocode}
+% Test for \verb|\Umathchar| added.
+%    \begin{macrocode}
+             \@xp\Umathch@\meaning@"0"\Umathch@
+             \ifgtest@ % if \Umathchar
+             \else % else not \Umathcar
+%    \end{macrocode}
+%    \begin{macrocode}
+           \@xp\macro@\meaning@@\macro@
+           \ifgtest@ % if macro test
+             \@xp\not@\meaning@\not@
+             \ifgtest@ % if macro starts \not test
+               \gdef\thedots@{\dotsb@}%
+             \else% else not \not
+               \@xp\DOTS@\meaning@\DOTS@
+               \ifgtest@ % \if DOTS
+                 \ifcase\number\DOTSCASE@ %ifcase dots
+                   \gdef\thedots@{\dotsb@}%
+                 \or\gdef\thedots@{\dotsi}\else
+                 \fi % endifcase dots
+               \else % not macro starts \DOTS
+                 \@xp\math@\meaning@\math@
+                 \ifgtest@ % \if macro starts \mathxxxx
+                   \@xp\mathbin@\meaning@\mathbin@
+                   \ifgtest@ % if macro starts \mathbin
+                     \gdef\thedots@{\dotsb@}%
+                   \else % not macro starting \mathbin
+                     \@xp\mathrel@\meaning@\mathrel@
+                     \ifgtest@ % if macro starts \mathrel
+                       \gdef\thedots@{\dotsb@}%
+                     \fi % endif macro starts \mathrel (no else)
+                   \fi % endif macro starts \mathbin
+                 \fi % endif macro starts with \mathxxx (no else)
+               \fi % endif macro starts \DOTS else
+             \fi % end macro  starting \not \ifgtest@ test (no else)
+%    \end{macrocode}
+% Additional test for a catcode 12 character.
+%    \begin{macrocode}
+             \else
+               \@xp\thecharacter@\meaning@\thecharacter@
+%    \end{macrocode}
+%    \begin{macrocode}
+             \fi % end macro \ifgtest@ test (no else)
+           \fi % end if \Umathchar test
+         \fi % end \math@   \ifgtest@ 
+       \fi % end \keybin@ \ifgtest@ test (no else)
+     \fi % end if \not (no else)
+   \fi % end if comma (no else)
+ \fi % end if boldsymbol (no else)
+ \thedots@}
+%    \end{macrocode}
+%
+%    The \qc{\=} character is necessary in the two \cs{let} assignments
+%    in \cs{boldsymboldots@}, because the symbol we are making
+%    bold might be an \qc{\=} sign.
+%    \begin{macrocode}
+\def\boldsymboldots@#1{%
+  \bold@true\let\@let@token=#1\let\delayed@=#1\mdots@@
+  \boldsymbol#1\bold@false}
+%    \end{macrocode}
+%
+%    The definition of \cs{@cdots} is merely the \fn{plain.tex}
+%    definition of \cs{cdots}.
+%    \begin{macrocode}
+\ams@def\@cdots{\mathinner{\cdotp\cdotp\cdotp}}
+\newcommand{\dotsi}{\!\@cdots}
+\let\dotsb@\@cdots
+%    \end{macrocode}
+%
+%    If any new right delimiters are defined, they would need to be
+%    added to the definition of \cs{rightdelim@} in order for \cn{dots}
+%    to work properly in all cases.
+%    \begin{macrocode}
+\def\rightdelim@{\gtest@true
+ \ifx\@let@token)\else
+ \ifx\@let@token]\else
+ \ifx\@let@token\rbrack\else
+ \ifx\@let@token\}\else
+ \ifx\@let@token\rbrace\else
+ \ifx\@let@token\rangle\else
+ \ifx\@let@token\rceil\else
+ \ifx\@let@token\rfloor\else
+ \ifx\@let@token\rgroup\else
+ \ifx\@let@token\rmoustache\else
+ \ifx\@let@token\right\else
+ \ifx\@let@token\bigr\else
+ \ifx\@let@token\biggr\else
+ \ifx\@let@token\Bigr\else
+ \ifx\@let@token\Biggr\else\gtest@false
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+\def\extra@{%
+ \rightdelim@\ifgtest@
+ \else\ifx\@let@token$\gtest@true
+ \else\xdef\meaning@{\meaning\@let@token..........}%
+ \@xp\macro@\meaning@\macro@\ifgtest@
+ \@xp\DOTS@\meaning@\DOTS@
+ \ifgtest@
+ \ifnum\DOTSCASE@=\tw@\gtest@true\else\gtest@false
+ \fi\fi\fi\fi\fi}
+\newif\ifbold@
+\def\dotso@{\relaxnext@
+ \ifbold@
+  \let\@let@token\delayed@
+  \def\nextii@{\extra@\@ldots\ifgtest@\,\fi}%
+ \else
+  \def\nextii@{\DN@{\extra@\@ldots\ifgtest@\,\fi}\FN@\next@}%
+ \fi
+ \nextii@}
+%    \end{macrocode}
+%    Why not save some tokens? (space vs. time).
+%    \begin{macrocode}
+\def\extrap@#1{%
+ \DN@{#1\,}%
+ \ifx\@let@token,\else
+ \ifx\@let@token;\else
+ \ifx\@let@token.\else\extra@
+ \ifgtest@\else
+ \let\next@#1\fi\fi\fi\fi\next@}
+%    \end{macrocode}
+%
+%    \begin{macro}{\cdots}
+%    \begin{macro}{\dotsb}
+%    \begin{macro}{\dotsm}
+%    \begin{macro}{\dotso}
+%    \begin{macro}{\dotsc}
+%    The \cn{cdots} command.
+%    \begin{macrocode}
+\ams@DeclareRobustCommand{\cdots}{\DN@{\extrap@\@cdots}\FN@\next@}
+\let\dotsb\cdots
+\let\dotsm\cdots
+\DeclareRobustCommand{\dotso}{\relax
+  \ifmmode \DN@{\extrap@\@ldots}%
+  \else \let\next@\tdots@\fi
+  \FN@\next@}
+\DeclareRobustCommand{\dotsc}{%
+  \DN@{\ifx\@let@token;\@ldots\,%
+       \else \ifx\@let@token.\@ldots\,%
+       \else \extra@\@ldots \ifgtest@\,\fi
+       \fi\fi}%
+  \FN@\next@}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \begin{macro}{\longrightarrow}
+%    \begin{macro}{\Longrightarrow}
+%    \begin{macro}{\longleftarrow}
+%    \begin{macro}{\Longleftarrow}
+%    \begin{macro}{\longleftrightarrow}
+%    \begin{macro}{\Longleftrightarrow}
+%    \begin{macro}{\mapsto}
+%    \begin{macro}{\longmapsto}
+%    \begin{macro}{\hookrightarrow}
+%    \begin{macro}{\hookleftarrow}
+%    \begin{macro}{\iff}
+%    Various arrows.
+%    \begin{macrocode}
+\renewcommand{\longrightarrow}{%
+  \DOTSB\protect\relbar\protect\joinrel\rightarrow}
+\renewcommand{\Longrightarrow}{%
+  \DOTSB\protect\Relbar\protect\joinrel\Rightarrow}
+\renewcommand{\longleftarrow}{%
+  \DOTSB\leftarrow\protect\joinrel\protect\relbar}
+\renewcommand{\Longleftarrow}{%
+  \DOTSB\Leftarrow\protect\joinrel\protect\Relbar}
+\renewcommand{\longleftrightarrow}{\DOTSB\leftarrow\joinrel\rightarrow}
+\renewcommand{\Longleftrightarrow}{\DOTSB\Leftarrow\joinrel\Rightarrow}
+\renewcommand{\mapsto}{\DOTSB\mapstochar\rightarrow}
+\renewcommand{\longmapsto}{\DOTSB\mapstochar\longrightarrow}
+\renewcommand{\hookrightarrow}{\DOTSB\lhook\joinrel\rightarrow}
+\renewcommand{\hookleftarrow}{\DOTSB\leftarrow\joinrel\rhook}
+\renewcommand{\iff}{\DOTSB\;\Longleftrightarrow\;}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \begin{macro}{\doteq}
+%    The \cn{doteq} command formerly used \cs{buildrel}; we avoid that
+%    because it requires `\cn{over}' as part of its syntax. Use 0pt
+%    instead of \cs{z@} for robustitude.
+%    \begin{macrocode}
+\renewcommand{\doteq}{%
+  \DOTSB\mathrel{\mathop{\kern0pt =}\limits^{\textstyle.}}}
+%    \end{macrocode}
+%    \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Integral signs}
+%
+%    \begin{macro}{\if@display}
+%    The straightforward \cs{ifinner} test to see if the current math
+%    context is non-display, fails if, for instance, we are typesetting
+%    a multiline display within an \cs{halign}, with the pieces going
+%    into constructions like
+%    \begin{verbatim}
+%    $\displaystyle...$
+%    \end{verbatim}
+%    So we need a better test to find out if we are `in a display'. We
+%    therefore create \cs{if@display}.
+%
+%    \begin{macrocode}
+\newif\if@display
+\everydisplay\@xp{\the\everydisplay \@displaytrue}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\int}
+%    \begin{macro}{\oint}
+%    \begin{macro}{\iint}
+%    \begin{macro}{\iiint}
+%    \begin{macro}{\iiiint}
+%    \begin{macro}{\idotsint}
+%    Default value for integral limits is \cs{nolimits}, see the
+%    definition of the `nointlimits' option.
+%    \begin{macrocode}
+\renewcommand{\int}{\DOTSI\intop\ilimits@}
+\renewcommand{\oint}{\DOTSI\ointop\ilimits@}
+\def\intkern@{\mkern-6mu\mathchoice{\mkern-3mu}{}{}{}}
+\def\intdots@{\mathchoice{\@cdots}%
+ {{\cdotp}\mkern1.5mu{\cdotp}\mkern1.5mu{\cdotp}}%
+ {{\cdotp}\mkern1mu{\cdotp}\mkern1mu{\cdotp}}%
+ {{\cdotp}\mkern1mu{\cdotp}\mkern1mu{\cdotp}}}
+%
+\ams@newcommand{\iint}{\DOTSI\protect\MultiIntegral{2}}
+\ams@newcommand{\iiint}{\DOTSI\protect\MultiIntegral{3}}
+\ams@newcommand{\iiiint}{\DOTSI\protect\MultiIntegral{4}}
+\newcommand{\idotsint}{\DOTSI\protect\MultiIntegral{0}}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macro}{\MultiIntegral}
+%    If the \cs{limits} option is applied, use \cs{mathop} and fudge
+%    the left-hand space a bit to make the subscript visually centered.
+%
+%    \verb'#1' is the multiplicity.
+%    \begin{macrocode}
+\newcommand{\MultiIntegral}[1]{%
+  \edef\ints@c{\noexpand\intop
+    \ifnum#1=\z@\noexpand\intdots@\else\noexpand\intkern@\fi
+    \ifnum#1>\tw@\noexpand\intop\noexpand\intkern@\fi
+    \ifnum#1>\thr@@\noexpand\intop\noexpand\intkern@\fi
+    \noexpand\intop
+    \noexpand\ilimits@
+  }%
+  \futurelet\@let@token\ints@a
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macrocode}
+\def\ints@a{%
+  \ifx\limits\@let@token \ints@b
+  \else \ifx\displaylimits\@let@token \ints@b
+  \else\ifx\ilimits@\displaylimits \ints@b
+  \fi\fi\fi
+  \ints@c
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\ints@b{%
+  \mkern-7mu\mathchoice{\mkern-2mu}{}{}{}%
+  \mathop\bgroup
+    \mkern7mu\mathchoice{\mkern2mu}{}{}{}%
+    \let\ilimits@\egroup
+}%
+%    \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Size dependent definitions}
+%
+%    We now define all stuff which has to change whenever a new math
+%    size is to be activated. \latex/ provides a hook called
+%    |\every@math@size| to support such a need. All assignments in the
+%    |\every@math@size| hook that need to take outside effect should be
+%    global.
+%
+% \subsection{Struts for math}
+%
+%    The various kinds of struts could use some analysis and perhaps
+%    consolidation.
+%
+%    For example perhaps the \cn{bBigg} delimiters could use
+% \begin{verbatim}
+% 1.2\ht\strutbox (1.8, 2.4, 3.0)
+% \end{verbatim}
+%    instead of
+% \begin{verbatim}
+% 1.0\big@size (1.5, 2.0, 2.5)
+% \end{verbatim}
+%    since \cs{strut} is reset with every size change [mjd, 1994/10/07].
+%    But this change would introduce the possibility of changed line
+%    and page breaks in existing documents, so would need to be
+%    handled with care.
+%
+% \begin{macro}{\Mathstrut@}
+% \begin{macro}{\Mathstrutbox@}
+% \begin{macro}{\resetMathstrut@}
+%    Here comes the code for Spivak's |\Mathstrut@|.
+%    \begin{macrocode}
+\newbox\Mathstrutbox@
+\setbox\Mathstrutbox@=\hbox{}
+\def\Mathstrut@{\copy\Mathstrutbox@}
+%    \end{macrocode}
+%    The setting of the height and depth of the |\Mathstrutbox@| is done
+%    in the |\every@math@size| hook since it depends on the height of a
+%    paren. As \cs{every@math@size} is triggered by |$| after a font
+%    size change, we want to avoid using another math formula |$...$| to
+%    measure the math paren height; instead we go through the mathcode
+%    of the \qc{\(} character. We assume that the mathcode has a leading
+%    hex digit 4 indicating `open delimiter'; this allows us to make a
+%    relatively simple function to get the correct font and character
+%    position.
+%
+% \changes{v2.15}{2016/02/20}{Modify \cs{resetMathstrut@} for Unicode \TeX}
+% \changes{v2.15b}{2016/03/10}{Modify \cs{resetMathstrut@} for classic \TeX\ to preserve box 0}
+% Original code assuming |\mathcode| is kept for 8bit \TeX. Unicode \TeX{}
+% uses |\Umathcharnumdef| which works for xetex and luatex, which use
+% different forms for |\mathchardef|. (New luatex always reports
+% definitions using |\Umathchardef| syntax even if |\mathchardef| used.)
+%
+% The unicode version uses e-tex |\fontcharht| to avoid boxing which
+% could also be done for pdftex, but not done here.
+%    \begin{macrocode}
+\ifx\Umathcharnumdef\@undefined
+%    \end{macrocode}
+% Original code
+%    \begin{macrocode}
+\def\resetMathstrut@{%
+  \begingroup
+  \setbox\z@\hbox{%
+    \mathchardef\@tempa\mathcode`\(\relax
+    \def\@tempb##1"##2##3{\the\textfont"##3\char"}%
+    \expandafter\@tempb\meaning\@tempa \relax
+  }%
+ \edef\@tempa{%
+     \ht\Mathstrutbox@\the\ht\z@\relax
+     \dp\Mathstrutbox@\the\dp\z@\relax}%
+  \expandafter\endgroup\@tempa
+}
+\else
+%    \end{macrocode}
+% xetex/luatex version
+% \changes{v2.15a}{2016/03/03}{missing percent added}
+%    \begin{macrocode}
+\def\resetMathstrut@{%
+    \begingroup
+    \Umathcharnumdef\@tempa\Umathcodenum`\(\relax
+    \def\@tempb##1"##2"##3"##4\relax{%
+      \endgroup
+      \ht\Mathstrutbox@=\fontcharht\textfont"##3 "##4\relax
+      \dp\Mathstrutbox@=\fontchardp\textfont"##3 "##4\relax}%
+    \expandafter\@tempb\meaning\@tempa \relax
+}
+%    \end{macrocode}
+%    \begin{macrocode}
+\fi
+%    \end{macrocode}
+%    These height and depth assignments are implicitly global.
+%    \begin{macrocode}
+\addto@hook\every@math@size{\resetMathstrut@}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\strut@}
+% \begin{macro}{\strutbox@}
+%    Next follows a special internal strut which is supposed to match
+%    the height and the depth of a normal |\strut| minus
+%    |\normallineskiplimit| according to M. Spivak.
+%
+%    This should really go into the definition of \cs{size@update}, and
+%    then the box reset could be local; but \cs{size@update} doesn't
+%    have any hook and is handled in such a way that it cannot even be
+%    changed except by changing \cs{set@fontsize}. So instead we put
+%    \cs{reset@strutbox@} into \cs{every@math@size} and make it global.
+%    Then because of some complications in the way \cs{glb@settings} and
+%    \cs{check@mathfonts} work, we have to re-invoke it at the beginning
+%    of every environment that might use \cs{strut@}. Fortunately this
+%    can be achieved (more or less) through the \cs{spread@equation}
+%    hook. [mjd,2000/03/10]
+%    \begin{macrocode}
+\newbox\strutbox@
+\def\strut@{\copy\strutbox@}
+\def\reset@strutbox@{%
+  \global\setbox\strutbox@\hbox{%
+    \lower.5\normallineskiplimit
+       \vbox{\kern-\normallineskiplimit\copy\strutbox}}}
+\addto@hook\every@math@size{\reset@strutbox@}
+\AtBeginDocument{\reset@strutbox@}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Big delimiters}
+%
+%    We are now going to redefine the plain \tex/ commands \cn{big},
+%    \cn{bigl}, etc., to produce different results in different sizes.
+%    Actually we only have to define \cn{big}, \cn{Big}, etc., since
+%    they are used to construct the directional versions \cn{bigl},
+%    \cn{bigr}, and the rest.
+%
+% \begin{macro}{\big}
+% \begin{macro}{\Big}
+% \begin{macro}{\bigg}
+% \begin{macro}{\Bigg}
+%     To save token space we put everything into the common macro
+%    |\bBigg@|. The macros are now simply a call to |\bBigg@| with a
+%    factor to determine the correct height of the delimiter as an
+%    argument. This code should better go into a future version of
+%    the \latex/ kernel; the macro |\n@space| is then superfluous (since
+%    it is only used once) and should be removed to avoid wasting hash
+%    table space unnecessarily.
+%    \begin{macrocode}
+\renewcommand{\big}{\bBigg@\@ne}
+\renewcommand{\Big}{\bBigg@{1.5}}
+\renewcommand{\bigg}{\bBigg@\tw@}
+\renewcommand{\Bigg}{\bBigg@{2.5}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bBigg@}
+%    Now we tackle the macro which has to do the real work. It
+%    actually has two arguments, the factor and the wanted delimiter.
+% \changes{v2.17b}{2018/12/01}{Start LR-mode for \cs{bigl} and
+%   friends if necessary (github/49)}
+%    \begin{macrocode}
+\ifx\leavevmode@ifvmode\@undefined
+\def\bBigg@#1#2{%
+%    \end{macrocode}
+%    We start with an extra set of braces because we want
+%    constructions like |\def\bigl{\mathopen\big}| to work without the
+%    overhead of extra arguments.
+%    \begin{macrocode}
+  {\@mathmeasure\z@{\nulldelimiterspace\z@}%
+     {\left#2\vcenter to#1\big@size{}\right.}%
+   \box\z@}}
+\else
+\def\bBigg@#1#2{\leavevmode@ifvmode
+  {\@mathmeasure\z@{\nulldelimiterspace\z@}%
+     {\left#2\vcenter to#1\big@size{}\right.}%
+   \box\z@}}
+\fi
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\big@size}
+%    |\big@size| needs to be set to 1.2 times the height of a math
+%    paren. This height is already recorded in |\Mathstrutbox@|.
+%    \begin{macrocode}
+\addto@hook\every@math@size{%
+  \global\big@size 1.2\ht\Mathstrutbox@
+  \global\advance\big@size 1.2\dp\Mathstrutbox@ }
+\newdimen\big@size
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Math accents}
+%
+%    We want to change the leading digit of math accents to be
+%    \cs{accentclass@} so that it can vary according to certain internal
+%    purposes.
+%    \begin{macrocode}
+\def\accentclass@{7}
+\def\noaccents@{\def\accentclass@{0}}
+%    \end{macrocode}
+%
+%    There are a few \meta{math alphabet}s in the standard fonts where
+%    we have to change the extra macros because the standard definitions
+%    don't account for these accent problems. The first is for the
+%    \cs{mathit} command.
+%    \begin{macrocode}
+\DeclareFontEncoding{OML}{}{\noaccents@}
+%    \end{macrocode}
+%    The next one corrects the \cs{cal} alphabet.
+%    \begin{macrocode}
+\DeclareFontEncoding{OMS}{}{\noaccents@}
+%    \end{macrocode}
+%
+%    \begin{macro}{\dddot}
+%    \begin{macro}{\ddddot}
+%    Triple and quadruple dot accents.
+%    \begin{macrocode}
+\ams@newcommand{\dddot}[1]{%
+  {\mathop{#1}\limits^{\vbox to-1.4\ex@{\kern-\tw@\ex@
+   \hbox{\normalfont ...}\vss}}}}
+\ams@newcommand{\ddddot}[1]{%
+  {\mathop{#1}\limits^{\vbox to-1.4\ex@{\kern-\tw@\ex@
+   \hbox{\normalfont....}\vss}}}}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%    The following code deals with support for compound accents.
+%    By redefining \cs{set@mathaccent} we ensure that
+%    \cn{DeclareMathAccent} will define accent commands to run our
+%    \cs{mathaccentV} function instead of the primitive \cs{mathaccent}.
+%    \begin{macrocode}
+\def\set@mathaccent#1#2#3#4{%
+  \xdef#2{\@nx\protect\@nx\mathaccentV
+    {\@xp\@gobble\string#2}\hexnumber@#1#4}%
+}
+%    \end{macrocode}
+%
+%    \begin{macro}{\hat}
+%    \begin{macro}{\check}
+%    \begin{macro}{\tilde}
+%    \begin{macro}{\acute}
+%    \begin{macro}{\grave}
+%    \begin{macro}{\dot}
+%    \begin{macro}{\ddot}
+%    \begin{macro}{\breve}
+%    \begin{macro}{\bar}
+%    \begin{macro}{\vec}
+%    \begin{macro}{\mathring}
+%    We redefine the standard math accent commands to
+%    call \cs{mathaccentV}, using the mathgroup/encoding-number
+%    information embedded in their previous definitions. If the
+%    definition of an accent command does not have the expected form, we
+%    leave the accent command alone, but give a warning. For widehat and
+%    widetilde, we need to avoid clobbering the definitions done by the
+%    \pkg{amsfonts} package. Arbitrating the contention between
+%    \pkg{amsmath} and \pkg{amsfonts} to allow doubling a widetilde
+%    accent looks tricky, so for the time being [mjd,1999/07/19] we just
+%    leave \cn{widehat} and \cn{widetilde} alone. As a result, if the
+%    \pkg{amsmath} package is loaded on top of a vanilla \latex/
+%    documentclass, everything runs through with no warnings. If a
+%    Lucida Math or other math fonts package is loaded in addition to
+%    \pkg{amsmath}, there are greater difficulties, but those are
+%    addressed elsewhere.
+%
+%
+% \changes{v2.15}{2016/02/20}{Detect \cs{Umathaccent} on package load}
+% Adjust the test made at package load to recognise
+% |\Umathaccent|. Although currently it is just used to give a
+% modified warning that the accents will not be redefined.
+%
+% Note that the engines behave quite differently here, luatex
+% even without these definitions using the OpenType accent set up by
+% unicode-math  stacks |\hat{hat{f}}| correctly but xetex acts like
+% classic tex and needs this adjustment. This difference is not
+% addressed here at all.
+%
+% This test is just at package loading and has no affect on the
+% definitions used in 8bit TeX.
+%    \begin{macrocode}
+%\def\@tempa#1{\@xp\@tempb\meaning#1\@nil#1}
+%    \end{macrocode}
+%    The extended definition below tests if the accent is already
+%    robust (as newer \LaTeX{} kernels do this by default) and if so
+%    picks up the robust definition. However, as of
+%    now it still redefines it to be non-robust.
+%    \begin{macrocode}
+\def\@tempa#1{%
+  \@ifundefined{\@xp\@gobble\string#1\space}%
+     {\@xp\@tempb\meaning#1\@nil#1}%
+     {\@xp\@xp\@xp\@tempb\@xp\meaning
+       \csname\@xp\@gobble\string#1\space\endcsname\@nil#1}%
+}
+\def\@tempb#1>#2#3 #4\@nil#5{%
+  \@xp\ifx\csname#3\endcsname\mathaccent
+    \@tempc#4?"7777\@nil#5%
+  \else
+  \@xp\ifx\csname#3\endcsname\Umathaccent
+    \@tempd#4\@nil#5%
+  \else
+    \PackageWarningNoLine{amsmath}{%
+      Unable to redefine math accent \string#5}%
+  \fi\fi}
+\def\@tempc#1"#2#3#4#5#6\@nil#7{%
+  \chardef\@tempd="#3\relax\set@mathaccent\@tempd{#7}{#2}{#4#5}}
+\def\@tempd#1\@nil#2{%
+    \PackageWarningNoLine{amsmath}{%
+      Unable to redefine \string\Umathaccent\space\string#2}%
+}
+%    \end{macrocode}
+%    \begin{macrocode}
+\@tempa{\hat}
+\@tempa{\check}
+\@tempa{\tilde}
+\@tempa{\acute}
+\@tempa{\grave}
+\@tempa{\dot}
+\@tempa{\ddot}
+\@tempa{\breve}
+\@tempa{\bar}
+\@tempa{\vec}
+\@ifundefined{mathring}{%
+  \DeclareMathAccent{\mathring}{\mathalpha}{operators}{"17}
+}{%
+  \@tempa{\mathring}
+}
+%%\@tempa\widetilde
+%%\@tempa\widehat
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%    Regression testing of amsmath 2.0 showed that in some documents
+%    there occurred fragments of the form
+% \begin{verbatim}
+% \hat\mathcal{G}
+% \end{verbatim}
+%    This is not at all correct syntax for the argument of a \latex/
+%    command but it produced the intended result anyway because of the
+%    internal syntax of the \cs{mathaccent} primitive. With
+%    \cs{mathaccentV}, it will yield an error message. We therefore do a
+%    special check for such syntax problems in order to make the error
+%    message more informative. (dmj: ??????)
+%    \begin{macrocode}
+\newcommand{\acc@check}{}
+\newcommand{\acc@error}{}
+\def\acc@check{\@ifnextchar\@empty\relax\acc@error}
+%    \end{macrocode}
+%    We put most of the tokens in a separate macro so they do not get
+%    scanned unless they are actually needed.
+%    \begin{macrocode}
+\def\acc@error{%
+  \@amsmath@err{%
+    Improper argument for math accent:\MessageBreak
+    Extra braces must be added to prevent wrong output%
+  }\@ehc
+}
+%    \end{macrocode}
+%
+%    For \cs{mathaccentV} part of the processing is dependent on the
+%    depth of nesting of math accent commands. We introduce a dedicated
+%    counter for this instead of using chardef because we want to
+%    increment/decrement it during processing, and incrementing a
+%    chardef integer is more work.
+%    \begin{macrocode}
+\newcount\macc@depth
+%    \end{macrocode}
+%
+%    Provide this function in case it is not already available.
+%    \begin{macrocode}
+\long\def\@gobblethree#1#2#3{}
+%    \end{macrocode}
+%
+%    The \cs{mathaccentV} function first counts the number of nested
+%    math accents by setting the argument in a throw-away box. (This is
+%    not as risky as such an operation would normally be because the
+%    argument is generally either a simple math symbol or a nested math
+%    accent call with a simple math symbol at the bottom of the
+%    nesting.)
+%
+%    There are two benefits from counting the nesting levels first
+%    before doing anything else: (1) we can fall back to a simple
+%    \cs{mathaccent} call if the nesting depth is 1, and (2) if the
+%    nesting depth is greater than 1, we would like to be able to tell
+%    when we have reached the lowest level, because at that point we
+%    want to save the argument for later use and place an accent on top
+%    of a phantom copy.
+%
+%    When we have multiple accents, they will be placed on top of the
+%    invisible box, followed by some suitable kerns, then a visible copy
+%    of the nucleus. To see why, let us look at what goes wrong with a
+%    double application of the \cs{mathaccent} primitive. The standard
+%    definition of \cs{hat} is \verb'\mathaccent"705E', so
+%    \verb'\hat{\hat{F}}' expands to
+%\begin{verbatim}
+%\mathaccent"705E{\mathaccent"705E{F}}
+%\end{verbatim}
+%    The result of this operation is
+%\begin{verbatim}
+%\vbox(12.11111+0.0)x7.81946
+%.\hbox(6.94444+0.0)x0.0, shifted 1.40973
+%..\OT1/cmr/m/n/10 ^
+%.\kern-4.30554
+%.\vbox(9.47221+0.0)x7.81946
+%..\hbox(6.94444+0.0)x0.0, shifted 2.24309
+%...\OT1/cmr/m/n/10 ^
+%..\kern-4.30554
+%..\hbox(6.83331+0.0)x7.81946
+%...\OML/cmm/m/it/10 F
+%\end{verbatim}
+%    \tex/ starts by constructing a vbox with the hat character on top
+%    of the F. Then it puts another hat character on top of the vbox;
+%    but without skew information, because that is only applied by
+%    \cs{mathaccent} when the base object is a simple symbol. So the
+%    first accent is skewed to the correct position but all later
+%    accents are not. By the way, the actual width of the F in the above
+%    example is less than 7.81946; the box in which it is packed was
+%    automatically lengthened by the width of the F's italic correction
+%    (without actually putting in a kern for it).
+%
+%    To get the second accent shifted farther to the right we
+%    artificially increase the width of the innermost box and add
+%    a compensating kern afterward. Furthermore, to get proper placement
+%    of a following subscript or superscript, we take the base symbol
+%    out, leaving a phantom in its place, and print it by itself
+%    following the kern. We then need to increase the kern amount to
+%    move the base character backward under the accents again.
+%    Here is what the results look like:
+%\begin{verbatim}
+%\vbox(12.11111+0.0)x9.48618
+%.\hbox(6.94444+0.0)x0.0, shifted 2.24309
+%..\OT1/cmr/m/n/10 ^
+%.\kern-4.30554
+%.\vbox(9.47221+0.0)x9.48618
+%..\hbox(6.94444+0.0)x0.0, shifted 2.24309
+%...\OT1/cmr/m/n/10 ^
+%..\kern-4.30554
+%..\hbox(6.83331+0.0)x9.48618
+%...\hbox(6.83331+0.0)x7.81946
+%...\kern 1.66672
+%\kern -9.48618
+%\OML/cmm/m/it/10 F
+%\end{verbatim}
+%
+%    Much of this implementation is based on code from the \pkg{accents}
+%    package of Javier Bezos. I added the test to revert to a simple
+%    \cs{mathaccent} when accents are not nested, and some other
+%    refinements to reduce the number of kerns used (to conserve box
+%    memory) and the number of cycles through \cs{mathchoice} (to make
+%    things run a little faster). It was all rather difficult and my
+%    first two attempts had serious bugs but I hope and believe that
+%    this version will do better. [mjd,2000/03/15]
+%
+%    The \qq{V} in \cs{mathaccentV} is just an indication that it takes
+%    five arguments. It is important that the name includes
+%    \texttt{mathaccent}, otherwise \cs{DeclareMathAccent} will balk at
+%    redefining one of our accent commands, for example when an
+%    alternative math font package is loaded.
+%    \begin{macrocode}
+\def\mathaccentV#1#2#3#4#5{%
+  \ifmmode
+    \gdef\macc@tmp{\macc@depth\@ne}%
+    \setbox\z@\hbox{%
+      \let\mathaccentV\macc@test
+      \let\use@mathgroup\@gobbletwo \let\select@group\@gobblethree
+      \frozen@everymath{}$#5$%
+    }%
+    \macc@tmp
+    \ifnum\macc@depth=\@ne
+      \global\let\macc@nucleus\@empty
+      \mathaccent"\accentclass@
+    \else
+      \@xp\macc@nested
+    \fi
+    #2#3#4{#5}%
+    \macc@nucleus
+  \else
+    \@xp\nonmatherr@\csname#1\endcsname
+  \fi
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\macc@test#1#2#3#4{\xdef\macc@tmp{\macc@tmp\advance\macc@depth\@ne}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\macc@group{-1}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\macc@nested#1#2#3#4{%
+  \begingroup
+  \let\math@bgroup\@empty \let\math@egroup\macc@set@skewchar
+  \mathsurround\z@ \frozen@everymath{\mathgroup\macc@group\relax}%
+  \macc@set@skewchar\relax
+  \let\mathaccentV\macc@nested@a
+  \macc@nested@a\relax#1#2#3{#4}%
+  \endgroup
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\let\macc@palette\mathpalette
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\macc@nested@a#1#2#3#4#5{%
+%    \end{macrocode}
+%    This test saves some work that would otherwise be always repeated
+%    fourfold thanks to \cs{mathchoice}.
+%    \begin{macrocode}
+  \ifnum\macc@group=\mathgroup
+  \else \macc@set@skewchar\relax \edef\macc@group{\the\mathgroup}%
+  \fi
+  \mathchardef\macc@code "\accentclass@ #2#3#4\relax
+  \macc@palette\macc@a{#5}%
+}
+%    \end{macrocode}
+%
+%    The reason that \cs{macc@set@skewchar} takes an argument is so that
+%    it can serve as a direct substitute for \cs{math@egroup}, in
+%    addition to being used separately.
+%
+%    Setting a skewchar with this method works for symbols of variable
+%    mathgroup (class 7, letters and numbers) but not necessarily for
+%    special symbols like \cn{partial} or \cs{xi} whose mathgroup
+%    doesn't change; fortunately the most commonly used ones come from
+%    mathgroup one, which is the fall-back mathgroup for skewchar.
+%    \begin{macrocode}
+\def\macc@set@skewchar#1{%
+  \begingroup
+  \ifnum\mathgroup=\m@ne \let\@tempa\@ne
+  \else
+    \ifnum\skewchar\textfont\mathgroup=\m@ne \let\@tempa\@ne
+    \else \let\@tempa\mathgroup
+    \fi
+  \fi
+  \count@=\skewchar\textfont\@tempa
+  \advance\count@"7100
+  \edef\@tempa{\endgroup
+    \mathchardef\noexpand\macc@skewchar=\number\count@\relax}%
+  \@tempa
+  #1%
+}
+%    \end{macrocode}
+%
+%    Arg1 is math-style, arg2 is accent base object. We assume that math
+%    style doesn't change within the nested group of accents; this means
+%    we can set \cs{macc@style} only once and redefine \cs{macc@palette}
+%    to use it, in order to run \cs{mathchoice} only once instead of
+%    multiplying the calls exponentially as the nesting level increases.
+%    \begin{macrocode}
+\def\macc@a#1#2{%
+  \begingroup
+  \let\macc@style#1\relax
+  \def\macc@palette##1{##1\macc@style}%
+  \advance\macc@depth\m@ne
+  \ifnum\macc@depth=\z@
+    \gdef\macc@nucleus{#2}%
+%    \end{macrocode}
+%    Extra \cs{@empty} tokens are to prevent low-level \tex/ errors from
+%    the potential syntactic error that \cs{acc@check} checks for.
+%    \begin{macrocode}
+    \setbox\z@\hbox{$#1#2\@empty{}\macc@skewchar$}%
+    \setbox\tw@\hbox{$#1#2\@empty\macc@skewchar$}%
+    \dimen@\tw@\wd\tw@ \advance\dimen@-\tw@\wd\z@
+    \xdef\macc@kerna{\the\dimen@\relax}%
+    \setbox4\hbox{$#1#2\acc@check\@empty$}%
+    \global\setbox\@ne\hbox to\wd4{}%
+    \ht\@ne\ht4 \dp\@ne\dp4
+    \xdef\macc@kernb{\the\wd4\relax}%
+    \mathaccent\macc@code{\box\@ne\kern\macc@kerna}%
+  \else
+    \mathaccent\macc@code{\let\macc@adjust\@empty #1#2\@empty}%
+    \macc@adjust
+  \fi
+  \endgroup
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\macc@adjust{%
+  \dimen@\macc@kerna\advance\dimen@\macc@kernb
+  \kern-\dimen@
+}
+%    \end{macrocode}
+%
+%    The commands \cs{Hat}, \cs{Tilde}, \ldots, are supported as
+%    synonyms of \cs{hat}, \cs{tilde}, \ldots, for backward
+%    compatibility.
+%    \begin{macrocode}
+\def\Hat{\hat}
+\def\Check{\check}
+\def\Tilde{\tilde}
+\def\Acute{\acute}
+\def\Grave{\grave}
+\def\Dot{\dot}
+\def\Ddot{\ddot}
+\def\Breve{\breve}
+\def\Bar{\bar}
+\def\Vec{\vec}
+%    \end{macrocode}
+%
+%    This error message about math mode is used several times so we make
+%    an abbreviation for it.
+%    \begin{macrocode}
+\def\nonmatherr@#1{\@amsmath@err{\protect
+  #1 allowed only in math mode}\@ehd}
+%    \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Mods, continued fractions, etc.}
+%
+%    \begin{macro}{\bmod}
+%    \begin{macro}{\pmod}
+%    \begin{macro}{\pod}
+%    \begin{macro}{\mod}
+%    The commands \cn{bmod}, \cn{pmod}, \cn{pod}, \cn{mod} aren't
+%    currently robust. [mjd, 1994/09/05]
+%    \begin{macrocode}
+\renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin
+  {\operator@font mod}\penalty900
+  \mkern5mu\nonscript\mskip-\medmuskip}
+\newcommand{\pod}[1]{\allowbreak
+  \if@display\mkern18mu\else\mkern8mu\fi(#1)}
+\renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}}
+\newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu
+  \else\mkern12mu\fi{\operator@font mod}\,\,#1}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macro}{\cfrac}
+%    Continued fractions. The optional arg l or r controls horizontal
+%    placement of the numerators. The |\kern-\nulldelimiterspace|
+%    is needed in the definition if we want the right-hand sides of the
+%    fraction rules to line up. The \cs{strut} keeps the numerator of
+%    a subsidiary cfrac from coming too close to the fraction rule above
+%    it.
+%    \begin{macrocode}
+\newcommand{\cfrac}[3][c]{{\displaystyle\frac{%
+  \strut\ifx r#1\hfill\fi#2\ifx l#1\hfill\fi}{#3}}%
+  \kern-\nulldelimiterspace}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\overset}
+%    \begin{macro}{\underset}
+%    \cn{overset} and \cn{underset} put symbols above, respectively
+%    below, a symbol that is not a \cs{mathop} and therefore does not
+%    naturally accept limits. \cs{binrel@@} uses information collected
+%    by \cs{binrel@} to make the resulting construction be of type
+%    mathrel or mathbin if the base symbol is either of those types.
+%    \begin{macrocode}
+\newcommand{\overset}[2]{\binrel@{#2}%
+  \binrel@@{\mathop{\kern\z@#2}\limits^{#1}}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\newcommand{\underset}[2]{\binrel@{#2}%
+  \binrel@@{\mathop{\kern\z@#2}\limits_{#1}}}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%
+%  \begin{macro}{\overunderset}
+%    This is the combination of the previous two commands which is
+%    something that is sometimes needed.
+% \changes{v2.17c}{FMi}{New command \cs{overunderset}}
+%    \begin{macrocode}
+\newcommand{\overunderset}[3]{\binrel@{#3}%
+  \binrel@@{\mathop{\kern\z@#3}\limits^{#1}_{#2}}}
+%    \end{macrocode}
+%  \end{macro}
+%
+%    \begin{macro}{\sideset}
+%    \cn{sideset} allows placing `adscript' symbols at the four
+%    corners of a \cs{mathop}, \emph{in addition to} limits. Left-side
+%    adscripts go into arg \arg{1}, in the form |_{...}^{...}|, and
+%    right-side adscripts go into arg \arg{2}.
+%
+%    As currently written [mjd, 1995/01/21] this is pretty haphazard.
+%    In order to really make it work properly in full generality we'd
+%    have to read and measure the top and bottom limits and use
+%    mathchoice to always get the right mathstyle for each piece,
+%    etc., etc.
+%    \begin{macrocode}
+\newcommand{\sideset}[3]{%
+  \@mathmeasure\z@\displaystyle{#3}%
+%    \end{macrocode}
+%    Use a global box assignment here since the depth override is
+%    implicitly global. Then move the constructed box to a local box
+%    register (2) to ensure it won't get destroyed during the next two
+%    mathmeasure statements. This precaution may be more extreme than
+%    necessary in practice.
+%    \begin{macrocode}
+  \global\setbox\@ne\vbox to\ht\z@{}\dp\@ne\dp\z@
+  \setbox\tw@\box\@ne
+  \@mathmeasure4\displaystyle{\copy\tw@#1}%
+  \@mathmeasure6\displaystyle{#3\nolimits#2}%
+  \dimen@-\wd6 \advance\dimen@\wd4 \advance\dimen@\wd\z@
+  \hbox to\dimen@{}\mathop{\kern-\dimen@\box4\box6}%
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+% \begin{macro}{\smash}
+%    We add to the \cn{smash} command an optional argument
+%    denoting the part of the formula to be smashed.
+% \changes{v2.17b}{2018/12/01}{Start LR-mode for \cs{smash}
+%   if necessary (github/49)}
+%    \begin{macrocode}
+\ifx\leavevmode@ifvmode\@undefined
+\renewcommand{\smash}[1][tb]{%
+  \def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}%
+  \edef\finsm@sh{\csname mb@#1\endcsname\z@\z@\box\z@}%
+  \ifmmode \@xp\mathpalette\@xp\mathsm@sh
+  \else \@xp\makesm@sh
+  \fi
+}
+\else
+\renewcommand{\smash}[1][tb]{%
+  \def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}%
+  \edef\finsm@sh{\csname mb@#1\endcsname\z@\z@ \leavevmode@ifvmode\box\z@}%
+  \ifmmode \@xp\mathpalette\@xp\mathsm@sh
+  \else \@xp\makesm@sh
+  \fi
+}
+\fi
+%    \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Extensible arrows}
+%
+%    The minus sign used in constructing these arrow fills is smashed so
+%    that superscripts above the arrows won't be too high. This
+%    primarily affects the \cn{xleftarrow} and \cn{xrightarrow} arrows.
+%
+%    \begin{macrocode}
+\mathchardef\std@minus\mathcode`\-\relax
+\mathchardef\std@equal\mathcode`\=\relax
+%    \end{macrocode}
+%    In case some alternative math fonts are loaded later:
+%    \begin{macrocode}
+\AtBeginDocument{%
+  \mathchardef\std@minus\mathcode`\-\relax
+  \mathchardef\std@equal\mathcode`\=\relax
+}
+%    \end{macrocode}
+%
+%    \begin{macro}{\relbar}
+%    \begin{macro}{\Relbar}
+%    \begin{macrocode}
+\ams@def\relbar{\mathrel{\mathpalette\mathsm@sh\std@minus}}
+\ams@def\Relbar{\mathrel\std@equal}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macrocode}
+\def\arrowfill@#1#2#3#4{%
+  $\m@th\thickmuskip0mu\medmuskip\thickmuskip\thinmuskip\thickmuskip
+   \relax#4#1\mkern-7mu%
+   \cleaders\hbox{$#4\mkern-2mu#2\mkern-2mu$}\hfill
+   \mkern-7mu#3$%
+}
+\def\leftarrowfill@{\arrowfill@\leftarrow\relbar\relbar}
+\def\rightarrowfill@{\arrowfill@\relbar\relbar\rightarrow}
+\def\leftrightarrowfill@{\arrowfill@\leftarrow\relbar\rightarrow}
+\def\Leftarrowfill@{\arrowfill@\Leftarrow\Relbar\Relbar}
+\def\Rightarrowfill@{\arrowfill@\Relbar\Relbar\Rightarrow}
+\def\Leftrightarrowfill@{\arrowfill@\Leftarrow\Relbar\Rightarrow}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\overarrow@#1#2#3{\vbox{\ialign{##\crcr#1#2\crcr
+ \noalign{\nointerlineskip}$\m@th\hfil#2#3\hfil$\crcr}}}
+\ams@renewcommand{\overrightarrow}{%
+  \mathpalette{\overarrow@\rightarrowfill@}}
+\ams@renewcommand{\overleftarrow}{%
+  \mathpalette{\overarrow@\leftarrowfill@}}
+\ams@newcommand{\overleftrightarrow}{%
+  \mathpalette{\overarrow@\leftrightarrowfill@}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\underarrow@#1#2#3{%
+ \vtop{\ialign{##\crcr$\m@th\hfil#2#3\hfil$\crcr
+ \noalign{\nointerlineskip\kern1.3\ex@}#1#2\crcr}}}
+\ams@newcommand{\underrightarrow}{%
+  \mathpalette{\underarrow@\rightarrowfill@}}
+\ams@newcommand{\underleftarrow}{%
+  \mathpalette{\underarrow@\leftarrowfill@}}
+\ams@newcommand{\underleftrightarrow}{%
+  \mathpalette{\underarrow@\leftrightarrowfill@}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%\newcommand{\xrightarrow}[2][]{\ext@arrow 0359\rightarrowfill@{#1}{#2}}
+\def\ext@arrow#1#2#3#4#5#6#7{%
+  \mathrel{\mathop{%
+%    \end{macrocode}
+%    Measure the superscript and subscript.
+%    \begin{macrocode}
+    \setbox\z@\hbox{#5\displaystyle}%
+    \setbox\tw@\vbox{\m@th
+      \hbox{$\scriptstyle\mkern#3mu{#6}\mkern#4mu$}%
+      \hbox{$\scriptstyle\mkern#3mu{#7}\mkern#4mu$}%
+      \copy\z@
+    }%
+    \hbox to\wd\tw@{\unhbox\z@}}%
+%    \end{macrocode}
+%    We don't want to place an empty subscript since that will produce
+%    too much blank space below the arrow.
+%    \begin{macrocode}
+  \limits
+    \@ifnotempty{#7}{^{\if0#1\else\mkern#1mu\fi
+                       #7\if0#2\else\mkern#2mu\fi}}%
+    \@ifnotempty{#6}{_{\if0#1\else\mkern#1mu\fi
+                       #6\if0#2\else\mkern#2mu\fi}}}%
+}
+%    \end{macrocode}
+%
+%    Some extensible arrows to serve as mathrels and taking
+%    sub/superscripts. These commands are robust because they take an
+%    optional argument.
+%    \begin{macrocode}
+\newcommand{\xrightarrow}[2][]{\ext@arrow 0359\rightarrowfill@{#1}{#2}}
+\newcommand{\xleftarrow}[2][]{\ext@arrow 3095\leftarrowfill@{#1}{#2}}
+%    \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Array-related environments}
+% \subsection{Remarks}
+%
+%    Because these environments can be nested within the equation
+%    structures that allow \cn{tag}, there is some cross-influence in
+%    the internal workings of the \cn{\\} command.
+%
+% \subsection{The \env{subarray} environment and \cn{substack} command}
+%
+%    The \cn{substack} command can be used to set subscripts
+%    and superscripts that consist of several lines. Usage:
+% \begin{verbatim}
+% X_{\substack{a=1\\b=2}}
+% \end{verbatim}
+%
+% \changes{v2.0}{1999/06/17}{Removed environment definitions: Sb, Sp}
+%
+% \begin{environment}{subarray}
+%    The \env{subarray} environment makes a small-size array suitable
+%    for use in a subscript or superscript. At the moment the supported
+%    arguments are not the full possibilities of \env{array} but only
+%    |c| or |l| for centered or left-aligned. And only one column.
+%    \begin{macrocode}
+\newenvironment{subarray}[1]{%
+%    \end{macrocode}
+%    Note: The predecessors of \env{subarray} (\env{Sb} and \env{Sp},
+%    inherited from \amstex/) used \cs{vbox} instead of \cs{vcenter}.
+%    But when a multiline subscript is placed in \cs{limits} position
+%    \cs{vcenter} is no worse than \cs{vbox}, and when it is placed
+%    in the \cs{nolimits} position (e.g., for an integral), \cs{vcenter}
+%    provides clearly better positioning than \cs{vbox}.
+%    \begin{macrocode}
+  \vcenter\bgroup
+%    \end{macrocode}
+%    Use \cs{Let@} to set the proper meaning of the \cn{\\} and \cn{\\*}
+%    commands. And restore the meaning of \cs{math@cr@@@} to \cs{cr}
+%    (see above) in case \env{subarray} is used inside one of the more
+%    complicated alignment macros where the meaning of \cs{math@cr@@@}
+%    is different. Similarly, call \cs{default@tag} to ensure that a
+%    line break here doesn't get an equation number!
+%    \begin{macrocode}
+  \Let@ \restore@math@cr \default@tag
+%    \end{macrocode}
+%    Set the line spacing to be the same as \cs{atop} (when \cs{atop}
+%    occurs in \cs{textstyle} or smaller), cf \textit{The \tex/book},
+%    Appendix G.
+%    \begin{macrocode}
+  \baselineskip\fontdimen10 \scriptfont\tw@
+  \advance\baselineskip\fontdimen12 \scriptfont\tw@
+  \lineskip\thr@@\fontdimen8 \scriptfont\thr@@
+  \lineskiplimit\lineskip
+%    \end{macrocode}
+%    Start the \cs{vbox} \cs{halign} structure that encloses the
+%    contents. Notice that we never get \cs{scriptscriptstyle}. That
+%    would require a \cs{mathchoice} (ugh).
+%    \begin{macrocode}
+  \ialign\bgroup\ifx c#1\hfil\fi
+    $\m@th\scriptstyle##$\hfil\crcr
+}{%
+  \crcr\egroup\egroup
+}
+%    \end{macrocode}
+% \end{environment}
+%
+% \begin{macro}{\substack}
+%    The \cn{substack} command is just an abbreviation for the
+%    most common use of \env{subarray}.
+%    \begin{macrocode}
+\newcommand{\substack}[1]{\subarray{c}#1\endsubarray}
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Matrices}
+%
+% \begin{environment}{smallmatrix}
+%    \env{smallmatrix} is again an alignment, this time in a centered
+%    box. The opening incantations are basically the same as those in
+%    \cs{multilimits@}, followed by the alignment itself. A remark:
+%    the baselineskip (|9\ex@|) used in \amstex/ is too large for
+%    use in text with the usual baselineskip of $12$ or $13$ points; we
+%    change it here to |6\ex@| and also adjust the \cs{lineskip}
+%    and \cs{lineskiplimit} slightly to compensate. (MJD)
+%    \begin{macrocode}
+\newenvironment{smallmatrix}{\null\,\vcenter\bgroup
+  \Let@\restore@math@cr\default@tag
+  \baselineskip6\ex@ \lineskip1.5\ex@ \lineskiplimit\lineskip
+  \ialign\bgroup\hfil$\m@th\scriptstyle##$\hfil&&\thickspace\hfil
+  $\m@th\scriptstyle##$\hfil\crcr
+}{%
+  \crcr\egroup\egroup\,%
+}
+%    \end{macrocode}
+% \end{environment}
+%
+% \begin{environment}{matrix}
+%    The \env{matrix} environment is just an \env{array} that provides
+%    up to ten centered columns, so that users don't have to give the
+%    col-spec argument explicitly---unless they want some of the columns
+%    noncentered, that is. The maximum number of columns is actually not
+%    fixed at ten but given by the counter |MatrixCols|, and can
+%    therefore be increased by changing that counter.
+%
+%    The extra space of \cn{arraycolsep} that \env{array} adds on each
+%    side is a waste so we remove it here (perhaps we should instead
+%    remove it from \env{array} in general, but that's a harder task).
+%
+%    TODO: Think about re-implementing \cn{matrix} to get rid of the
+%    \cs{c@MatrixCols} limit and have hard-wired preamble that doesn't
+%    have to be rebuilt each time.
+%
+%    We must use \cn{renewenvironment} for \env{matrix} and
+%    \env{pmatrix} because \latex/ doesn't kill the definitions found in
+%    \fn{plain.tex}, even though it probably should because of their
+%    foreign syntax.
+%    \begin{macrocode}
+\renewenvironment{matrix}{%
+  \matrix@check\matrix\env@matrix
+}{%
+  \endarray \hskip -\arraycolsep
+}
+%    \end{macrocode}
+% \end{environment}
+%
+%  \begin{macro}{\env@matrix}
+%
+%    \begin{macrocode}
+\def\env@matrix{\hskip -\arraycolsep
+  \let\@ifnextchar\new@ifnextchar
+  \array{*\c@MaxMatrixCols c}}
+%    \end{macrocode}
+%  \end{macro}
+%
+% \begin{macro}{\c@MaxMatrixCols}
+%    \begin{macrocode}
+\newcount\c@MaxMatrixCols \c@MaxMatrixCols=10
+%    \end{macrocode}
+% \end{macro}
+%
+%  \begin{macro}{\matrix@check}
+%    For various reasons, authors sometimes use the Plain \TeX{} form of
+%    \cn{matrix} or \cn{pmatrix} in \LaTeX{} documents. If they later
+%    add an invocation of the \pkg{amsmath} package to their document,
+%    the Plain \TeX{} syntax would lead to rather unintelligible error
+%    messages. The \cs{matrix@check} function does some checking to
+%    forestall that problem.
+%    \begin{macrocode}
+\def\matrix@check#1{%
+  \@xp\ifx\csname\@currenvir\endcsname#1%
+  \else\matrix@error#1%
+%    \end{macrocode}
+%    This error recovery is not that good but is better than the
+%    infinite loop that can result from calling \cs{array} without a
+%    matching \cs{endarray}. (The array setup leaves \cs{par} empty.)
+%    \begin{macrocode}
+    \@xp\@gobble
+  \fi
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%  \begin{macro}{\matrix@error}
+%
+%    \begin{macrocode}
+\def\matrix@error#1{%
+  \@amsmath@err{%
+Old form `\string#1' should be \string\begin{\@xp\@gobble\string#1}%
+  }{%
+`\string#1{...}' is old Plain-TeX syntax whose use is
+ill-advised in LaTeX.%
+  }%
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%    \begin{macrocode}
+\renewenvironment{pmatrix}{%
+  \left(%
+  \matrix@check\pmatrix\env@matrix
+}{
+  \endmatrix\right)%
+}
+\newenvironment{bmatrix}{\left[\env@matrix}{\endmatrix\right]}
+\newenvironment{Bmatrix}{%
+  \left\lbrace\env@matrix
+}{%
+  \endmatrix\right\rbrace
+}
+\newenvironment{vmatrix}{\left\lvert\env@matrix}{\endmatrix\right\rvert}
+\newenvironment{Vmatrix}{\left\lVert\env@matrix}{\endmatrix\right\rVert}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\let\hdots\@ldots
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\newcommand{\hdotsfor}[1]{%
+  \ifx[#1\@xp\shdots@for\else\hdots@for\@ne{#1}\fi}
+\newmuskip\dotsspace@
+\def\shdots@for#1]{\hdots@for{#1}}
+\def\hdots@for#1#2{\multicolumn{#2}c%
+  {\m@th\dotsspace@1.5mu\mkern-#1\dotsspace@
+   \xleaders\hbox{$\m@th\mkern#1\dotsspace@.\mkern#1\dotsspace@$}%
+           \hfill
+   \mkern-#1\dotsspace@}%
+   }
+%    \end{macrocode}
+%
+% \begin{environment}{cases}
+%    The easiest way to produce the \env{cases} environment is to base
+%    it on the \env{array} environment. We must use
+%    \cn{renewenvironment} to override the definition of \cn{cases} that
+%    \latex/ (unwisely) leaves in place from \fn{plain.tex}.
+%    \begin{macrocode}
+\renewenvironment{cases}{%
+  \matrix@check\cases\env@cases
+}{%
+  \endarray\right.%
+}
+\def\env@cases{%
+  \let\@ifnextchar\new@ifnextchar
+  \left\lbrace
+  \def\arraystretch{1.2}%
+  \array{@{}l@{\quad}l@{}}%
+}
+%    \end{macrocode}
+% \end{environment}
+%
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Equation sub-numbering}
+%
+%    \begin{macrocode}
+\newcounter{parentequation}% Counter for ``parent equation''.
+%    \end{macrocode}
+%
+%    We can't assume \cs{ignorespacesafterend} is defined since it was
+%    not there in the earliest releases of \latex/ 2e. And we need to
+%    include the \cs{global} for the same reason.
+%    \begin{macrocode}
+\@ifundefined{ignorespacesafterend}{%
+  \def\ignorespacesafterend{\global\@ignoretrue}%
+}{}
+%    \end{macrocode}
+%
+%    \begin{environment}{subequations}
+%    \begin{macrocode}
+\newenvironment{subequations}{%
+%    \end{macrocode}
+%    Before sending down the `equation' counter to the subordinate
+%    level, add 1 using standard \cn{refstepcounter}.
+%    \begin{macrocode}
+  \refstepcounter{equation}%
+%    \end{macrocode}
+%    Define \cn{theparentequation} equivalent to current
+%    \cn{theequation}. \cn{edef} is necessary to expand the current
+%    value of the equation counter. This might in rare cases cause
+%    something to blow up, in which case the user needs to add
+%    \cn{protect}.
+%    \begin{macrocode}
+  \protected@edef\theparentequation{\theequation}%
+  \setcounter{parentequation}{\value{equation}}%
+%    \end{macrocode}
+%    And set the equation counter to 0, so that the normal incrementing
+%    processes in the various equation environments will produce the
+%    desired results.
+%    \begin{macrocode}
+  \setcounter{equation}{0}%
+  \def\theequation{\theparentequation\alph{equation}}%
+  \ignorespaces
+}{%
+  \setcounter{equation}{\value{parentequation}}%
+  \ignorespacesafterend
+}
+%    \end{macrocode}
+%    \end{environment}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Equation numbering}
+%
+%    In the multiline equation environments provided here, the task
+%    of equation numbering is linked to the task of line breaking
+%    in the sense that it is the \cn{\\} command that marks where an
+%    equation number for the current line will be processed and added to
+%    the page.
+%
+%    \begin{macro}{\numberwithin}
+%    Provide a convenient way to specify that equations should be
+%    numbered within sections.
+%    \begin{macrocode}
+\newcommand{\numberwithin}[3][\arabic]{%
+  \@ifundefined{c@#2}{\@nocounterr{#2}}{%
+    \@ifundefined{c@#3}{\@nocnterr{#3}}{%
+      \@addtoreset{#2}{#3}%
+      \@xp\xdef\csname the#2\endcsname{%
+        \@xp\@nx\csname the#3\endcsname .\@nx#1{#2}}}}%
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\eqref}
+%    To make references to equation numbers easier, we provide
+%    \cn{eqref}.  We almost don't need \cn{textup}, except that
+%    \cs{tagform@} doesn't supply the italic correction.
+%    \begin{macrocode}
+\newcommand{\eqref}[1]{\textup{\tagform@{\ref{#1}}}}
+%    \end{macrocode}
+%    \end{macro}
+%
+% \subsection{Preliminary macros}
+%
+%    The following macros implement the \latex/ syntax for the
+%    \cn{\\} command, i.e. the possibility to add an asterisk to
+%    inhibit a page break, or an optional argument to denote additional
+%    vertical space. They are modelled more or less after the
+%    corresponding macros for \latex/'s \env{eqnarray} and \env{array}
+%    environments.
+%
+%    [We can perhaps use the eqnarray mechanism if we change it so that
+%    it also uses \cs{openup}.]
+%
+% \begin{macro}{\dspbrk@lvl}
+%    We begin by defining the \cs{dspbrk@lvl} counter. This counter
+%    records the desirability of a break after the current row, as a
+%    number between $0$ and $4$. Its default value is $-1$ meaning that
+%    no explicit \cn{displaybreak} command was given, and the default
+%    \cs{interdisplaylinepenalty} is to be used.
+%    \begin{macrocode}
+\newcount\dspbrk@lvl
+\dspbrk@lvl=-1
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\interdisplaylinepenalty}
+%    We set the \cs{interdisplaylinepenalty} to $10000$.
+%    \begin{macrocode}
+\interdisplaylinepenalty\@M
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\allowdisplaybreaks}
+%    The \cn{allowdisplaybreaks} command. Since this is intended for use
+%    outside displayed formulas (typically in the preamble), it does not
+%    need to use \cs{new@ifnextchar}.
+%    \begin{macrocode}
+\newcommand{\allowdisplaybreaks}[1][4]{%
+  \interdisplaylinepenalty\getdsp@pen{#1}\relax
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\getdsp@pen}
+%    Modelled after \latex/'s \cs{@getpen}.  We use higher numbers
+%    than would normally be provided by \cs{@lowpenalty},
+%    \cs{@medpenalty}, and \cs{@highpenalty}, since display
+%    breaks are almost always less desirable.
+%    \begin{macrocode}
+\def\getdsp@pen#1{%
+  \ifcase #1\@M \or 9999 \or 6999 \or 2999 \or \z@\fi
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\displaybreak}
+% \begin{macro}{\dspbrk@}
+% \begin{macro}{\dspbrk@context}
+% \begin{macro}{\nogood@displaybreak}
+%    For breaks in a certain row of a alignment.
+%    \begin{macrocode}
+\newcommand{\displaybreak}{\new@ifnextchar[\dspbrk@{\dspbrk@[4]}}
+\chardef\dspbrk@context=\sixt@@n
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\dspbrk@[#1]{%
+  \ifmeasuring@
+  \else
+    \ifcase\dspbrk@context % case 0 --- OK
+      \global\dspbrk@lvl #1\relax
+    \or                    % case 1 --- inside a box
+      \nogood@displaybreak
+    \else                  % other cases --- outside of a display
+      \@amsmath@err{\Invalid@@\displaybreak}\@eha
+    \fi
+  \fi
+}
+%    \end{macrocode}
+%
+%    This is the value of \cn{displaybreak} when it occurs inside some
+%    structure where it will not work.
+%    \begin{macrocode}
+\def\nogood@displaybreak{%
+  \@amsmath@err{\protect
+\displaybreak\space cannot be applied here}%
+{One of the enclosing environments creates an
+  unbreakable box\MessageBreak
+(e.g., split, aligned, gathered, ...).}%
+}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\math@cr}
+%    The macro \cs{math@cr} ends a row inside one of the equation
+%    environments, i.e., this is the internal name of the \cn{\\}
+%    commands in these environments. As usual for this kind of macro
+%    inside of alignments we insert a special brace into \tex/'s input
+%    stream. The initial \cs{relax} is needed to trigger entry into the
+%    \textit{u} template of the current column if the author ended the
+%    current row with an empty column (i.e., the mathcr was immediately
+%    preceded by an ampersand).
+%    \begin{macrocode}
+\def\math@cr{\relax\iffalse{\fi\ifnum0=`}\fi
+%    \end{macrocode}
+%    The first step is now to check whether an asterisk follows.
+%    \cs{@eqpen} is used to hold the penalty value to be put on
+%    the vertical list.
+%    Then we call up \cs{math@cr@} which performs the next step.
+%    If an asterisk is read page breaking is inhibited.
+%    \begin{macrocode}
+  \@ifstar{\global\@eqpen\@M\math@cr@}%
+%    \end{macrocode}
+%    Otherwise we have to check the \cs{dspbrk@lvl} value.
+%    \begin{macrocode}
+          {\global\@eqpen
+             \ifnum\dspbrk@lvl <\z@ \interdisplaylinepenalty
+              \else -\@getpen\dspbrk@lvl \fi
+           \math@cr@}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\math@cr@}
+%    The purpose of \cs{math@cr@} is to check whether an optional
+%    argument follows.  If not it provides \cs{z@} as default
+%    value.
+%    \begin{macrocode}
+\def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\math@cr@@}
+%    \cs{math@cr@@} closes the special brace opened in
+%    \cs{math@cr}, and calls \cs{math@cr@@@} which is supposed
+%    the `real' row ending command.  The meaning of this macro depends
+%    on the environment in which it is used.
+%    \begin{macrocode}
+\def\math@cr@@[#1]{\ifnum0=`{\fi \iffalse}\fi\math@cr@@@
+%    \end{macrocode}
+%    Finally we put the additional space onto the vertical list.
+%    \begin{macrocode}
+  \noalign{\vskip#1\relax}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\Let@}
+%    \cs{Let@} is called by all environments where \cn{\\}
+%    ends a row of an alignment.
+%    \begin{macrocode}
+\def\Let@{\let\\\math@cr}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\restore@math@cr}
+%    We mentioned already that the exact meaning of \cs{math@cr@@@}
+%    depends on the current environment.  Since it is often a simple
+%    \cs{cr} we provide \cs{restore@math@cr} to reset it.
+%    \begin{macrocode}
+\def\restore@math@cr{\def\math@cr@@@{\cr}}
+%    \end{macrocode}
+%    This is also the default case.
+%    \begin{macrocode}
+\restore@math@cr
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\intertext}
+% \begin{macro}{\intertext@}
+%    The \cn{intertext} command is used for inserting text between the
+%    rows of an alignment. It might better be done as an environment,
+%    but the \cs{begingroup} from \cn{begin} would cause the
+%    \cs{noalign} to fail.
+%    \begin{macrocode}
+\newcommand{\intertext}{\@amsmath@err{\Invalid@@\intertext}\@eha}
+%    \end{macrocode}
+%    \cs{intertext@} is called by all environments that allow the use of
+%    the \cn{intertext} command.
+%    \begin{macrocode}
+\def\intertext@{%
+  \def\intertext##1{%
+%    \end{macrocode}
+%    If current mode is not vmode, the most likely reason is that the
+%    writer forgot the \cn{\\} that is supposed to precede
+%    \cn{intertext}. All right, then, let's try adding it our ownself.
+%    But, to be slightly careful: \cn{\\} does a futurelet, and it's
+%    slightly dangerous to allow a letted token to barge around loose in
+%    our internal code when it has been let to a conditional token
+%    like \cs{fi}. So let's interpose something in front of the \cs{fi}
+%    for the futurelet to take instead. (And careful again: it has to be
+%    something evanescent, not (e.g.) \cs{relax} which would cause the
+%    next halign cell to fire up and keep \cs{noalign} from working.)
+%    \begin{macrocode}
+    \ifvmode\else\\\@empty\fi
+    \noalign{%
+      \penalty\postdisplaypenalty\vskip\belowdisplayskip
+      \vbox{\normalbaselines
+%    \end{macrocode}
+%    We need to do something extra if the outside environment is a list
+%    environment. I don't see offhand an elegant way to test ``are we
+%    inside any list environment'' that is both easy and reliable (for
+%    example, checking for zero \cs{@totalleftmargin} wouldn't catch the
+%    case where \cs{@totalleftmargin} is zero but \cs{linewidth} is less
+%    than \cs{columnwidth}), so it seems to me checking \cs{linewidth}
+%    is the best practical solution.
+% \changes{v2.15c}{2016/05/23}{\cs{ignorespaces} at the start of the argument}
+%    \begin{macrocode}
+        \ifdim\linewidth=\columnwidth
+        \else \parshape\@ne \@totalleftmargin \linewidth
+        \fi
+        \noindent\ignorespaces##1\par}%
+      \penalty\predisplaypenalty\vskip\abovedisplayskip%
+    }%
+}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsection{Implementing tags and labels}
+%
+%    In this section we describe some of the macros needed to make the
+%    \cn{tag} command work in various places. We start by defining a
+%    help text to be used when a \cn{tag} command is used somewhere
+%    it should not appear.
+%
+% \begin{macro}{\tag@help}
+%    This is the default error help text provided when \cn{tag}
+%    generates an error message.
+%    Note that \cs{newhelp} generates a control sequence name
+%    from the string given as its argument so that a leading
+%    backslash is provided automatically.
+%    \begin{macrocode}
+\newhelp\tag@help
+  {tag cannot be used at this point.\space
+   If you don't understand why^^Jyou should consult
+   the documentation.^^JBut don't worry: just continue, and I'll
+   forget what happened.}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\gobble@tag}
+%    This macro is to be used when \cn{tag} should silently
+%    skip its argument.
+%    It is made to handle the \qc{\*}-form of \cn{tag} as well.
+%    \begin{macrocode}
+\def\gobble@tag{\@ifstar\@gobble\@gobble}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\invalid@tag}
+%    \cs{invalid@tag} is a macro that should be used whenever
+%    \cn{tag} appears in an illegal place.
+%    It sets up \cs{tag@help} (as defined above) as help message,
+%    prints its argument as error message, and skips \cn{tag}'s
+%    argument.
+%    \begin{macrocode}
+\def\invalid@tag#1{\@amsmath@err{#1}{\the\tag@help}\gobble@tag}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dft@tag}
+% \begin{macro}{\default@tag}
+%    \cs{dft@tag} provides a convenient way to disallow the
+%    use of \cn{tag} at certain points.
+%    One simply has to write
+%    \begin{verbatim}
+%\let\tag\dft@tag
+%    \end{verbatim}
+%    and the \cn{tag} command will produce an error message,
+%    with a suitable error help text, and discard its argument.
+%    \begin{macrocode}
+\def\dft@tag{\invalid@tag{\string\tag\space not allowed here}}
+%    \end{macrocode}
+%    Since this is used several times we provide an abbreviation for
+%    it.
+%    \begin{macrocode}
+\def\default@tag{\let\tag\dft@tag}
+%    \end{macrocode}
+%    Since this is also the default, i.e.\ the \cn{tag} command
+%    should not be used except in special places, we issue a
+%    \cs{default@tag} command.
+%    \begin{macrocode}
+\default@tag
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%    Now that we have taken care of the case that \cn{tag} is not
+%    allowed we will provide some macros to process tags appropriately.
+%    As the user documentation states, a \cn{tag} command (without
+%    the asterisk typesets its argument according to the document
+%    styles' conventions, whereas a \cn{tag*} command typesets its
+%    argument exactly as given. We define therefore the following
+%    interface:
+%
+% \begin{macro}{\maketag@@}
+% \begin{macro}{\maketag@@@}
+% \begin{macro}{\tagform@}
+%    \cn{tag} is supposed to call \cs{maketag@@} which checks
+%    whether an asterisk follows. If this is the case it calls up
+%    \cs{maketag@@@} which sets its argument `as is'. Otherwise
+%    \cs{tagform@} is called to do the job. (This macro is to be
+%    defined appropriately by the document style.)
+%    \begin{macrocode}
+\def\maketag@@{\@ifstar\maketag@@@\tagform@}
+%    \end{macrocode}
+%    We define \cs{maketag@@@} to use the normal font of the document
+%    text (since this is the usual practice for numbering of document
+%    elements) and to put a box around the tag. Furthermore we use
+%    \cs{m@th} for exceptional cases where the tag involves a
+%    superscript or some such math. (Probably from an explicit use of
+%    \cs{tag*} rather than from the automatic numbering.)
+%    \begin{macrocode}
+\def\maketag@@@#1{\hbox{\m@th\normalfont#1}}
+%    \end{macrocode}
+%    We use the following default definition for \cs{tagform@}
+%    that puts only parentheses around the tag.
+%    \begin{macrocode}
+\def\tagform@#1{\maketag@@@{(\ignorespaces#1\unskip\@@italiccorr)}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%    We need to insinuate \cs{tagform@} into \cs{@eqnnum} in case
+%    \env{eqnarray} is used (probably in a document that was originally
+%    written without use of the \pkg{amsmath} package).
+%    \begin{macrocode}
+\iftagsleft@
+  \def\@eqnnum{\hbox to1sp{}\rlap{\normalfont\normalcolor
+    \hskip -\displaywidth\tagform@\theequation}}
+\else
+  \def\@eqnnum{{\normalfont\normalcolor \tagform@\theequation}}
+\fi
+%    \end{macrocode}
+%
+% \begin{macro}{\thetag}
+%    Sometimes one needs to set a literal tag according to the rules of
+%    the document style. To achieve this we provide the \cn{thetag}
+%    command. It typesets its argument by calling \cs{tagform@} on
+%    it.
+%    \begin{macrocode}
+\newcommand{\thetag}{\leavevmode\tagform@}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\df@tag}
+% \begin{macro}{\make@df@tag}
+% \begin{macro}{\make@df@tag@@}
+% \begin{macro}{\make@df@tag@@@}
+%    Sometimes it is necessary for a \cn{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
+%    \cn{\\} at the end of the row was seen. Such a tag is stored in
+%    the macro \cs{df@tag} (for `deferred tag'). For this purpose we
+%    provide the \cs{make@df@tag} macro. It is built very similar to
+%    the \cs{maketag@@} macro above.
+%    \begin{macrocode}
+\let\df@tag\@empty
+\def\make@df@tag{\@ifstar\make@df@tag@@\make@df@tag@@@}
+%    \end{macrocode}
+%    \cs{make@df@tag} sets \cs{@currentlabel} and defines
+%    \cs{df@tag} appropriately.
+%
+%    To simplify the task of tracking \cs{tag} and \cs{label}
+%    commands inside math display environments, we defer \cs{label}
+%    commands until the tag is typeset, similar to the way that
+%    \cs{tag}s themselves are deferred.  This allows arbitrary
+%    placement of \cs{label} and \cs{tag} commands and also means we
+%    only increment the \cs{equation} counter when we really need to,
+%    thus avoiding the \cs{setb@ck} nonsense that used to be required.
+%
+%    \begin{macrocode}
+\def\make@df@tag@@#1{%
+  \gdef\df@tag{\maketag@@@{#1}\def\@currentlabel{#1}}}
+%    \end{macrocode}
+%    Autogenerated number:
+%    \begin{macrocode}
+\def\make@df@tag@@@#1{\gdef\df@tag{\tagform@{#1}%
+  \toks@\@xp{\p@equation{#1}}\edef\@currentlabel{\the\toks@}}}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macro}{\ltx@label}
+%    \begin{macro}{\label@in@display}
+%    \begin{macro}{\df@label}
+%    Next, we store the default definition of \cs{label} in
+%    \cs{ltx@label} and then define a new version of \cs{label} for use
+%    in math display environments. \cs{label@in@display} merely issues a
+%    warning message if there is already a pending label (which will be
+%    discarded) and then stores the label in \cs{df@label}.
+%    \begin{macrocode}
+\let\ltx@label\label
+%
+\def\label@in@display{%
+    \ifx\df@label\@empty\else
+        \@amsmath@err{Multiple \string\label's:
+            label '\df@label' will be lost}\@eha
+    \fi
+    \gdef\df@label
+}
+%    \end{macrocode}
+%    In case there is an enumerate inside a minipage inside an equation,
+%    we need to reset \cn{label} to its normal value:
+%    \begin{macrocode}
+\toks@\@xp{\@arrayparboxrestore \let\label\ltx@label}%
+\edef\@arrayboxrestore{\the\toks@}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\let\df@label\@empty
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macro}{\make@display@tag}
+%    Now we define a macro to process \cs{tag} and \cs{label} commands
+%    in various display environments.  If the |@eqnsw| switch is set,
+%    then we should supply an equation number; otherwise, if the
+%    |@tag| switch is set, we should use the tag stored in
+%    \cs{df@tag}.  Finally, we process any pending \cs{label}s.
+%
+%    TODO: Arguably, \cs{make@display@tag} should issue a warning
+%    message if there is a \cs{label} but neither a tag nor an
+%    equation number.  Also, it would probably be worthwhile to
+%    explore whether \cs{iftag@} could be done away with and replaced
+%    by checks to see if \cs{df@tag} is empty or not.
+%    \begin{macrocode}
+\def\make@display@tag{%
+  \if@eqnsw \incr@eqnum \print@eqnum
+  \else \iftag@ \df@tag \global\let\df@tag\@empty \fi
+  \fi
+%    \end{macrocode}
+%    Need to check the \cs{ifmeasuring@} flag otherwise the \cs{write}
+%    node from \cn{label} might be discarded in a temp box and clearing
+%    \cs{df@label} will keep it from being reiterated on the real
+%    typesetting pass.
+%    \begin{macrocode}
+  \ifmeasuring@
+  \else
+    \ifx\df@label\@empty
+    \else
+      \@xp\ltx@label\@xp{\df@label}%
+      \global\let\df@label\@empty
+    \fi
+  \fi
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    Now we define the special versions of \cn{tag} used within the
+%    \env{align} environments.
+%
+% \begin{macro}{\tag@in@align}
+%    The \cn{tag} command may only appear once in a row of
+%    an alignment.  Therefore we first check the switch |tag@|
+%    that is set to false at the begin of every row.
+%    If this switch is true a \cn{tag} was already given in this
+%    row and we define \cs{next@} to expand to a call to
+%    \cs{invalid@tag}.
+%    \begin{macrocode}
+\def\tag@in@align{%
+    \relax
+    \iftag@
+        \DN@{\invalid@tag{Multiple \string\tag}}%
+    \else
+%    \end{macrocode}
+%    Otherwise we set the |tag@| switch.  But there is more to
+%    be done: we must also prevent the automatic generation of a
+%    tag.  Therefore we also reset the |@eqnsw|.
+%    \begin{macrocode}
+    \global\tag@true
+%    \end{macrocode}
+%    Changed to \cs{nonumber}, since that seems to be all that's
+%    required.---dmj, 1994/12/21
+%    \begin{macrocode}
+    \nonumber
+%    \end{macrocode}
+%    Within a row of an \env{align} environment the \cn{tag}
+%    command must not typeset the tag immediately since its
+%    position can be determined only later.
+%    Therefore we use the \cs{make@df@tag} macro defined
+%    earlier.
+%    Finally we call \cs{next@} to process the argument
+%    that follows.
+%    \begin{macrocode}
+        \let\next@\make@df@tag
+    \fi
+    \next@
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\raisetag}
+%    Usage: \cn{raisetag} \meta{dimen}
+%
+%    This will modify the vertical placement of the tag of the current
+%    equation by \meta{dimen}. Note that according to the current uses
+%    of \cs{raise@tag} in e.g., \cs{place@tag@gather}, no adjustment
+%    occurs if the tag falls in its normal position; i.e., \cn{raisetag}
+%    has no effect unless the tag has already been shifted off-line.
+%
+%    \begin{macrocode}
+\newcommand{\raisetag}[1]{\skip@#1\relax
+  \xdef\raise@tag{\vskip\iftagsleft@\else-\fi\the\skip@\relax}%
+}
+%    \end{macrocode}
+%    \cn{raise@tag} will be reemptied at the beginning of each equation,
+%    which might occur at a |\begin{xxx}| or \cn{\\}.
+%    \begin{macrocode}
+\let\raise@tag\@empty
+%    \end{macrocode}
+%    \end{macro}
+%
+% \begin{macro}{\notag}
+%    For consistency we provide \cn{notag}, equivalent to
+%    \cn{nonumber}. The alternative would have been to rename
+%    \cn{tag} as \cn{number} to go along with \cn{nonumber},
+%    but of course \cs{number} is a \tex/ primitive that should not
+%    be redefined.
+%    \begin{macrocode}
+\newcommand{\notag}{\nonumber}
+%    \end{macrocode}
+% \end{macro}
+%
+%  \begin{macro}{\nonumber}
+%    Need to add some additional code to \cn{nonumber} to deal with some
+%    complications related to nested environments.
+%    \begin{macrocode}
+\renewcommand{\nonumber}{%
+  \if@eqnsw
+    \ifx\incr@eqnum\@empty \addtocounter{equation}\m@ne \fi
+  \fi
+  \let\print@eqnum\@empty \let\incr@eqnum\@empty
+  \global\@eqnswfalse
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\print@eqnum{\tagform@\theequation}
+\def\incr@eqnum{\refstepcounter{equation}\let\incr@eqnum\@empty}
+%    \end{macrocode}
+%  \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Multiline equation environments}
+%
+% \subsection{Remarks}
+%
+%    In late 1994 David M. Jones did a thorough overhaul of these
+%    environments so that the number placement and a few other aspects
+%    are substantially improved over the original versions that were
+%    ported essentially unchanged from \fn{amstex.tex} in 1989. Most of
+%    the commentary in this section is DMJ's, and comments of any
+%    significance that I added are marked by my initials and date
+%    [mjd, 1995/01/11].
+%
+% \subsection{Preliminaries}
+%
+% \begin{macro}{\ifinalign@}
+% \begin{macro}{\ifingather@}
+%    We define two switches that are set to true in certain
+%    alignments: |inalign@| and |ingather@| inside of
+%    the \env{align} and \env{gather} environments.
+%    These switches are needed to control certain actions that
+%    depend on the surrounding conditions, more specifically:
+%    on the setting already done by the surrounding environments.
+%    \begin{macrocode}
+\newif\ifinalign@
+\newif\ifingather@
+%    \end{macrocode}
+% \begin{histnote}
+% Removed the \cs{ifinany@} test [mjd,1999/06/28] since it was mainly
+% used for the purpose now handled by \cs{spread@equation}.
+% \changes{v1.2g}{1999/06/28}{Removed ifinany@}
+% \end{histnote}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@arrayparboxrestore}
+%    Here we must reset a few additional parameters.
+%    \begin{macrocode}
+\@xp\def\@xp\@arrayparboxrestore\@xp{\@arrayparboxrestore
+  \ingather@false\inalign@false \default@tag
+  \let\spread@equation\@spread@equation
+  \let\reset@equation\@empty
+  \def\print@eqnum{\tagform@\theequation}%
+  \def\incr@eqnum{\refstepcounter{equation}\let\incr@eqnum\@empty}%
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\iftag@}
+%    The switch |tag@| is set to false at the beginning of every
+%    row and set to true by a \cn{tag} command.
+%    This allows us to check whether there is more than one tag on
+%    a row.
+%    \begin{macrocode}
+\newif\iftag@
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ifst@rred}
+%    The switch |st@rred| is set to true by all starred
+%    environments
+%    and set to false by the unstarred versions.
+%    \begin{macrocode}
+\newif\ifst@rred
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ifmeasuring@}
+%    All display environments get typeset twice---once during a
+%    ``measuring'' phase and then again during a ``production'' phase;
+%    \cs{ifmeasuring@} will be used to determine which case we're in,
+%    so we can take appropriate action.
+%
+%    \begin{macrocode}
+\newif\ifmeasuring@
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macro}{\ifshifttag@}
+%    \cs{ifshifttag@} is used by \env{gather} to communicate between
+%    \cs{calc@shift@gather} and \cs{place@tag@gather} whether an
+%    equation tag should be shifted to a separate line.  It's also
+%    used by \env{multline}.
+%    \begin{macrocode}
+\newif\ifshifttag@
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\row@}
+%    \begin{macrocode}
+\newcount\row@
+%    \end{macrocode}
+%    \end{macro}
+%
+% \begin{macro}{\column@}
+%    The counter \cs{column@} is used by the alignment macros to
+%    keep track of the current column.
+%
+%    \begin{macrocode}
+\newcount\column@
+%    \end{macrocode}
+% \end{macro}
+%
+%  \begin{macro}{\column@plus}
+%    \cs{\column@plus} is a useful abbreviation.
+%    \begin{macrocode}
+\def\column@plus{%
+    \global\advance\column@\@ne
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%    \begin{macro}{\maxfields@}
+%    \begin{macrocode}
+\newcount\maxfields@
+%    \end{macrocode}
+%    \end{macro}
+%
+%  \begin{macro}{\add@amp}
+%  \begin{macro}{\add@amps}
+%    \begin{macrocode}
+\def\add@amp#1{\if m#1&\@xp\add@amp\fi}
+\def\add@amps#1{%
+    \begingroup
+    \count@#1\advance\count@-\column@
+    \edef\@tempa{\endgroup
+      \@xp\add@amp\romannumeral\number\count@ 000q}%
+    \@tempa
+}
+%    \end{macrocode}
+%  \end{macro}
+%  \end{macro}
+%
+% \begin{macro}{\andhelp@}
+%    The help text stored in \cs{andhelp@} is used for errors
+%    generated by too many \qc{\&} characters in a row.
+%    \begin{macrocode}
+\newhelp\andhelp@
+{An extra & here is so disastrous that you should probably exit^^J
+and fix things up.}
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macro}{\eqnshift@}
+%    \cs{eqnshift@} is used by \env{align} and \env{gather} as the
+%    indentation of the lines of the environment from the left margin.
+%    \begin{macrocode}
+\newdimen\eqnshift@
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\alignsep@}
+%    \begin{macrocode}
+\newdimen\alignsep@
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\tagshift@}
+%    \begin{macrocode}
+\newdimen\tagshift@
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\mintagsep}
+%    \cs{mintagsep} is the minimum allowable separation between an
+%    equation and its tag.  We set it to half a quad in
+%    \cs{textfont}2, which is \tex/'s built-in value.
+%    \begin{macrocode}
+\newcommand{\mintagsep}{.5\fontdimen6\textfont\tw@}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\minalignsep}
+%    This should probably be a skip register [mjd,1999/06/18]
+%    \begin{macrocode}
+\newcommand{\minalignsep}{10pt}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\tagwidth@}
+%    \begin{macrocode}
+\newdimen\tagwidth@
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\totwidth@}
+%    \begin{macrocode}
+\newdimen\totwidth@
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lineht@}
+%    The dimen register \cs{lineht@} is used to keep track of the
+%    height (or depth, if tags are on the right) of a row in an
+%    alignment.
+%    \begin{macrocode}
+\newdimen\lineht@
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macro}{\tag@width}
+%    \begin{macro}{\savetaglength@}
+%    \begin{macro}{\shift@tag}
+%    \begin{macro}{\tag@shifts}
+%    \begin{macrocode}
+\def\tag@width#1{%
+    \ifcase\@xp#1\tag@lengths\fi
+}
+
+\def\savetaglength@{%
+    \begingroup
+        \let\or\relax
+        \xdef\tag@lengths{\tag@lengths\or \the\wdz@}%
+    \endgroup
+}
+
+\def\shift@tag#1{%
+    \ifcase\@xp#1\tag@shifts\fi\relax
+}
+
+\let\tag@shifts\@empty
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macro}{\saveshift@}
+%    \begin{macrocode}
+\def\saveshift@#1{%
+    \begingroup
+        \let\or\relax
+        \xdef\tag@shifts{\or#1\tag@shifts}%
+    \endgroup
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%  \begin{macro}{\spread@equation}
+%    This does the line-spacing adjustment that is normally wanted for
+%    displayed equations. We also call \cs{reset@strutbox@} here because
+%    otherwise a preceding font size change might leave \cs{strutbox@}
+%    with wrong contents. This is a less-than-ideal solution but
+%    probably good enough for now, until the situation can be
+%    overhauled.
+%    \begin{macrocode}
+\def\spread@equation{\reset@strutbox@
+  \openup\jot \let\spread@equation\@empty}
+\let\@spread@equation\spread@equation
+%    \end{macrocode}
+%  \end{macro}
+%
+% \begin{macro}{\displ@y}
+% \begin{macro}{\displ@y@}
+% \begin{macro}{\@display@init}
+%    \cs{displ@y} is from \fn{plain.tex}, with
+%    \cs{interdisplaylinepenalty} changed to \cs{@eqpen}. Also we
+%    transplanted most of its internal organs to \cs{@display@init} to
+%    support \cs{displ@y@} and other possibilities. Don't try to make
+%    sense of these naming conventions! They are a narrowly calculated
+%    mishmash of Knuth/Spivak/Lamport/Mittelbach precedents. The reason
+%    for not cleaning them up and forcing all names to a consistent
+%    scheme is that then in principle we'd have to do it everywhere else
+%    too. And we programmers are paranoid about the side effects of name
+%    changes.
+%    \begin{macrocode}
+\def\displ@y{\@display@init{}}
+\def\@display@init#1{%
+    \global\dt@ptrue \spread@equation
+    \everycr{%
+        \noalign{%
+            #1%
+            \ifdt@p
+                \global\dt@pfalse
+                \vskip-\lineskiplimit
+                \vskip\normallineskiplimit
+            \else
+                \penalty\@eqpen \global\dspbrk@lvl\m@ne
+            \fi
+        }%
+    }%
+}
+%    \end{macrocode}
+%    \cs{displ@y@} is nearly the same; it additionally sets the |tag@|
+%    switch and the \cs{column@} and \cs{dspbrk@lvl} counters to their
+%    default values. The argument is normally a bit of code to empty out
+%    \cs{raise@tag}, but in \env{multline} we don't want that to happen
+%    in \cs{everycr}.
+%    \begin{macrocode}
+\def\displ@y@{\@display@init{%
+  \global\column@\z@ \global\dspbrk@lvl\m@ne
+  \global\tag@false \global\let\raise@tag\@empty
+}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\black@}
+% \changes{v2.17a}{2017/09/02}{add fixed width box so overfull warning generated in centred environments in lists}
+%    This macro is made to produce an overfull box message and
+%    possibly (depending on the value of \cs{overfullrule})
+%    a rule in the margin if the total width of an alignment
+%    is larger than the value of \cs{displaywidth}.
+%    \begin{macrocode}
+\def\black@#1{%
+    \noalign{%
+        \ifdim#1>\displaywidth
+            \dimen@\prevdepth
+            \nointerlineskip
+            \vskip-\ht\strutbox@
+            \vskip-\dp\strutbox@
+            \vbox{\noindent\hbox to\displaywidth{\hbox to#1{\strut@\hfill}}}%
+            \prevdepth\dimen@
+        \fi
+    }%
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macro}{\savecounters@}
+%    \begin{macro}{\restorecounters@}
+%    These are used during the measuring phase of the various display
+%    math environments to save and restore the values of all \latex/
+%    counters. We make these local to a group, so nested environments
+%    works.
+%
+%    Changed \cn{stepcounter} to |\csname c@...\endcsname| to avoid
+%    overhead of ifundefined test [mjd, 1995/01/20].
+%    \begin{macrocode}
+\def\savecounters@{%
+    \begingroup
+        \def\@elt##1{%
+          \global\csname c@##1\endcsname\the\csname c@##1\endcsname}%
+        \xdef\@gtempa{%
+            \cl@@ckpt
+            \let\@nx\restorecounters@\@nx\@empty
+        }%
+    \endgroup
+    \let\restorecounters@\@gtempa
+}
+%
+\let\restorecounters@\@empty
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%    \begin{macro}{\savealignstate@}
+%    \begin{macro}{\restorealignstate@}
+%    These are used to save the values of various parameters that are
+%    shared by \env{align} and \env{gather} when the former is used
+%    inside the latter.
+%    \begin{macrocode}
+\def\savealignstate@{%
+    \begingroup
+        \let\or\relax
+        \xdef\@gtempa{%
+            \global\totwidth@\the\totwidth@
+            \global\row@\the\row@
+            \gdef\@nx\tag@lengths{\tag@lengths}%
+            \let\@nx\restorealignstate@\@nx\@empty
+        }%
+    \endgroup
+    \let\restorealignstate@\@gtempa
+}
+
+\let\restorealignstate@\@empty
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%  \begin{macro}{\savecolumn@}
+%  \begin{macro}{\restorecolumn@}
+%
+%    \begin{macrocode}
+\def\savecolumn@{%
+  \edef\restorecolumn@{%
+    \global\column@\number\column@
+    \let\@nx\restorecolumn@\@nx\@empty
+  }%
+}
+\let\restorecolumn@\@empty
+%    \end{macrocode}
+%  \end{macro}
+%  \end{macro}
+%
+% \subsection{Scanning the environment's body}
+%
+%    Several of the math alignment macros must scan their body twice:
+%    once to determine how wide the columns are and then to actually
+%    typeset them. This means that we must collect all text in this body
+%    before calling the environment macros.
+%
+%    \begin{macro}{\@envbody}
+%    We start by defining a token register to contain the body.
+%    \begin{macrocode}
+\newtoks\@envbody
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macro}{\addto@envbody}
+%    Then we define a macro to add something (i.e.\ its argument) to the
+%    token register \cs{@envbody}.
+%    \begin{macrocode}
+\def\addto@envbody#1{\global\@envbody\@xp{\the\@envbody#1}}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\collect@body}
+%    The macro \cs{collect@body} starts the scan for the |\end{...}|
+%    command of the current environment. It takes a macro name as
+%    argument. This macro is supposed to take the whole body of the
+%    environment as its argument. For example, |\begin{align}| would
+%    call |\collect@body\@align| if |@align#1{...}| is the macro that
+%    sets the alignment with body \arg{1}.
+%
+%    \begin{macrocode}
+\def\collect@body#1{%
+  \@envbody{\@xp#1\@xp{\the\@envbody}}%
+  \edef\process@envbody{\the\@envbody\@nx\end{\@currenvir}}%
+  \@envbody\@emptytoks \def\begin@stack{b}%
+%    \end{macrocode}
+%
+%    If we simply called \cs{collect@@body} directly,
+%    the error message for a \cn{par} token (usually from a blank line)
+%    would be
+% \begin{verbatim}
+% ! Paragraph ended before \collect@@body was complete.
+% \end{verbatim}
+%    But we use a little finesse to get a more intelligible error
+%    message:
+% \begin{verbatim}
+% ! Paragraph ended before \multline* was complete.
+% \end{verbatim}
+%    In order to avoid using up csnames unnecessarily we use the actual
+%    environment name as the name of the temporary function that is
+%    \cs{let} to \cs{collect@@body}; but then in order to preserve the
+%    theoretical possibility of nesting for environments that use
+%    \cs{collect@body} (not currently required by any \pkg{amsmath}
+%    environment [mjd,1999/06/23]), we do the \cs{let} inside a group.
+%    \begin{macrocode}
+  \begingroup
+  \@xp\let\csname\@currenvir\endcsname\collect@@body
+%    \end{macrocode}
+%    This small twist eliminates the need for \cs{expandafter}'s in
+%    \cs{collect@@body}.
+%    \begin{macrocode}
+  \edef\process@envbody{\@xp\@nx\csname\@currenvir\endcsname}%
+  \process@envbody
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%  \begin{macro}{\push@begins}
+%    When adding a piece of the current environment's contents to
+%    \cs{@envbody}, we scan it to check for additional \cn{begin}
+%    tokens, and add a `b' to the stack for any that we find.
+%    \begin{macrocode}
+\def\push@begins#1\begin#2{%
+  \ifx\end#2\else b\@xp\push@begins\fi
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\collect@@body}
+%    \cs{collect@@body} takes two arguments: the first will consist of
+%    all text up to the next \cn{end} command, the second will be the
+%    \cn{end} command's argument. If there are any extra \cn{begin}
+%    commands in the body text, a marker is pushed onto a stack by the
+%    \cs{push@begins} function. Empty state for this stack means that we
+%    have reached the \cn{end} that matches our original \cn{begin}.
+%    Otherwise we need to include the \cn{end} and its argument in the
+%    material that we are adding to our environment body accumulator.
+%
+% \begin{histnote}
+%    In a former implementation, the error messages resulting from a
+%    typo in the environment name were unsatisfactory, because it was
+%    matching of the environment name that was used to determine the end
+%    of our environment body, instead of counting begin-end pairs.
+%    Thanks to Lars Hellstr\"{o}m for a suggestion that led to this
+%    improvement. [mjd,1999/06/23]
+% \end{histnote}
+%    \begin{macrocode}
+\def\collect@@body#1\end#2{%
+  \edef\begin@stack{\push@begins#1\begin\end \@xp\@gobble\begin@stack}%
+  \ifx\@empty\begin@stack
+    \endgroup
+    \@checkend{#2}%
+    \addto@envbody{#1}%
+  \else
+    \addto@envbody{#1\end{#2}}%
+  \fi
+  \process@envbody % A little tricky! Note the grouping
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Simple aligning environments}
+%
+%  \begin{macro}{\math@cr@@@aligned}
+%    From tabskip we get an extra space of minalignsep after every
+%    second column; but when this falls at the right edge of the whole
+%    aligned structure, we need to cancel that space.
+%    \begin{macrocode}
+\def\math@cr@@@aligned{%
+  \ifodd\column@ \let\next@\@empty
+  \else \def\next@{&\kern-\alignsep@}%
+  \fi
+  \next@ \cr
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%    \begin{macro}{\start@aligned}
+%    The \env{aligned} and \env{alignedat} environments are identical
+%    except that the latter takes a mandatory argument to specify the
+%    number of align structures, while the former allows any number of
+%    align structures automatically (the use of \env{alignedat} is
+%    deprecated).  So, they will be defined in terms of
+%    \cs{start@aligned}, which will take two arguments.  The first
+%    argument specifies the placement of the environments; it is
+%    either |c|, |t|, or |b|.  The second is the number of align
+%    structures; a value of~$-1$ means that an arbitrary number are
+%    allowed.
+%    \begin{macrocode}
+\newcommand{\start@aligned}[2]{%
+    \RIfM@\else
+        \nonmatherr@{\begin{\@currenvir}}%
+    \fi
+    \savecolumn@ % Assumption: called inside a group
+%    \end{macrocode}
+%    The \cs{null} here is to keep the \cs{,} glue from causing the
+%    invocation of the clause in \tex/'s built-in tag placement
+%    algorithm that can cause an equation to be shifted all the way over
+%    to the margin.
+%    \begin{macrocode}
+    \alignedspace@left
+    \if #1t\vtop \else \if#1b \vbox \else \vcenter \fi \fi \bgroup
+        \maxfields@#2\relax
+        \ifnum\maxfields@>\m@ne
+            \multiply\maxfields@\tw@
+%    \end{macrocode}
+%    Introduced new \cs{math@cr@@@} so we can provide standard error
+%    message for too many \qc{\&}'s in \env{alignedat}.
+%    \begin{macrocode}
+            \let\math@cr@@@\math@cr@@@alignedat
+            \alignsep@\z@skip
+        \else
+            \let\math@cr@@@\math@cr@@@aligned
+            \alignsep@\minalignsep
+        \fi
+%    \end{macrocode}
+%    Reset the meaning of \cn{\\}.
+%    \begin{macrocode}
+        \Let@ \chardef\dspbrk@context\@ne
+%    \end{macrocode}
+%    Restore the default definition of \cn{tag} (error message), in
+%    case \env{aligned} is used inside, e.g., a \env{gather}
+%    environment that accepts \cn{tag}.
+%    \begin{macrocode}
+        \default@tag
+        \spread@equation % no-op if already called
+%    \end{macrocode}
+%    Finally we start the alignment itself. For \env{aligned} we add
+%    \cs{minalignsep} after every second column to mimic the
+%    behavior of \env{align}. For \env{alignedat} the user has to
+%    specify interalign space explicitly.
+%    \begin{macrocode}
+        \global\column@\z@
+        \ialign\bgroup
+           &\column@plus
+            \hfil
+            \strut@
+            $\m@th\displaystyle{##}$%
+            \tabskip\z@skip
+           &\column@plus
+            $\m@th\displaystyle{{}##}$%
+            \hfil
+            \tabskip\alignsep@
+            \crcr
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\math@cr@@@alignedat}
+%    \cs{math@cr@@@alignedat} checks to make sure the user hasn't put in
+%    too many \qc{\&}s in \env{alignedat}.  Since \env{alignedat}
+%    doesn't use \cs{displ@y@}, we also reset \cs{column@} here.  Note
+%    than in \env{aligned}, \cs{column@} will increase without bound,
+%    since it never gets reset, but this is harmless.
+%    \begin{macrocode}
+\def\math@cr@@@alignedat{%
+    \ifnum\column@>\maxfields@
+        \begingroup
+          \measuring@false
+          \@amsmath@err{Extra & on this line}%
+            {\the\andhelp@}% "An extra & here is disastrous"
+        \endgroup
+    \fi
+    \global\column@\z@
+    \cr
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%  \begin{macro}{\alignsafe@testopt}
+%    Testing for an optional argument can be really, really tricky in
+%    certain complicated contexts. This we discovered by getting some
+%    bug reports for uses of \env{aligned}. So here is a safer
+%    form of \latex/'s \cs{@testopt} function.
+%    \begin{macrocode}
+\def\alignsafe@testopt#1#2{%
+  \relax\iffalse{\fi\ifnum`}=0\fi
+  \@ifnextchar[%
+    {\let\@let@token\relax \ifnum`{=\z@\fi\iffalse}\fi#1}%
+    {\let\@let@token\relax \ifnum`{=\z@\fi\iffalse}\fi#1[#2]}%
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+% \begin{environment}{aligned}
+%    The \env{aligned} environment takes an optional argument that
+%    indicates its vertical position in relation to surrounding
+%    material: |t|, |c|, or |b| for top, center, or bottom.
+%    \begin{macrocode}
+\newenvironment{aligned}{%
+  \let\@testopt\alignsafe@testopt
+  \aligned@a
+}{%
+  \crcr\egroup
+  \restorecolumn@
+  \egroup
+}
+\newcommand{\aligned@a}[1][c]{\start@aligned{#1}\m@ne}
+%    \end{macrocode}
+% \end{environment}
+%
+% \begin{environment}{alignedat}
+%    To get a top or bottom positioned \env{alignedat} structure, you
+%    would write something like
+% \begin{verbatim}
+% \begin{alignedat}[t]{3}
+% \end{verbatim}
+%
+%    \begin{macrocode}
+\newenvironment{alignedat}{%
+  \let\@testopt\alignsafe@testopt
+  \alignedat@a
+}{%
+  \endaligned
+}
+\newcommand{\alignedat@a}[1][c]{\start@aligned{#1}}
+%    \end{macrocode}
+% \end{environment}
+%
+% \begin{environment}{gathered}
+%    The \env{gathered} environment is for several lines that are
+%    centered independently.
+%    \begin{macrocode}
+\newenvironment{gathered}[1][c]{%
+    \RIfM@\else
+        \nonmatherr@{\begin{gathered}}%
+    \fi
+    \alignedspace@left
+    \if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi \bgroup
+        \Let@ \chardef\dspbrk@context\@ne \restore@math@cr
+        \spread@equation
+        \ialign\bgroup
+            \hfil\strut@$\m@th\displaystyle##$\hfil
+            \crcr
+}{%
+  \endaligned
+}
+%    \end{macrocode}
+% \end{environment}
+%
+%
+%    \subsection{The \env{gather} environment}
+%
+% \begin{macro}{\start@gather}
+%    \begin{macrocode}
+\def\start@gather#1{%
+    \RIfM@
+        \nomath@env
+        \DN@{\@namedef{end\@currenvir}{}\@gobble}%
+    \else
+        $$%
+        #1%
+        \ifst@rred \else \global\@eqnswtrue \fi
+        \let\next@\gather@
+    \fi
+    \collect@body\next@
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{environment}{gather}
+%    \begin{environment}{gather*}
+%    \begin{macrocode}
+\newenvironment{gather}{%
+  \start@gather\st@rredfalse
+}{%
+  \math@cr \black@\totwidth@ \egroup
+  $$\ignorespacesafterend
+}
+
+\newenvironment{gather*}{%
+  \start@gather\st@rredtrue
+}{%
+  \endgather
+}
+%    \end{macrocode}
+%    \end{environment}
+%    \end{environment}
+%
+%    \begin{macro}{\gather@}
+%    \begin{macrocode}
+\def\gather@#1{%
+    \ingather@true \let\split\insplit@
+    \let\tag\tag@in@align \let\label\label@in@display
+    \chardef\dspbrk@context\z@
+    \intertext@ \displ@y@ \Let@
+    \let\math@cr@@@\math@cr@@@gather
+    \gmeasure@{#1}%
+    \global\shifttag@false
+    \tabskip\z@skip
+    \global\row@\@ne
+    \halign to\displaywidth\bgroup
+        \strut@
+        \setboxz@h{$\m@th\displaystyle{##}$}%
+        \calc@shift@gather
+        \set@gather@field
+        \tabskip\@centering
+       &\setboxz@h{\strut@{##}}%
+        \place@tag@gather
+        \tabskip \iftagsleft@ \gdisplaywidth@ \else \z@skip \span\fi
+        \crcr
+        #1%
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\gmeasure@}
+%    \begin{macrocode}
+\def\gmeasure@#1{%
+    \begingroup
+        \measuring@true
+        \totwidth@\z@
+        \global\let\tag@lengths\@empty
+        \savecounters@
+        \setbox\@ne\vbox{%
+            \everycr{\noalign{\global\tag@false
+              \global\let\raise@tag\@empty \global\column@\z@}}%
+            \let\label\@gobble
+            \halign{%
+                \setboxz@h{$\m@th\displaystyle{##}$}%
+                \ifdim\wdz@>\totwidth@
+                    \global\totwidth@\wdz@
+                \fi
+               &\setboxz@h{\strut@{##}}%
+                \savetaglength@
+                \crcr
+                #1%
+                \math@cr@@@
+            }%
+        }%
+        \restorecounters@
+        \if@fleqn
+            \global\advance\totwidth@\@mathmargin
+        \fi
+        \iftagsleft@
+            \ifdim\totwidth@>\displaywidth
+                \global\let\gdisplaywidth@\totwidth@
+            \else
+                \global\let\gdisplaywidth@\displaywidth
+            \fi
+        \fi
+    \endgroup
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\math@cr@@@gather}
+%    Modified \cs{math@cr@@@gather} so that it always puts in the
+%    final field, which needs to be done under the new method for
+%    determining tag placement.  This is probably more efficient
+%    anyway.
+%
+%    \begin{macrocode}
+\def\math@cr@@@gather{%
+    \ifst@rred\nonumber\fi
+   &\relax
+    \make@display@tag
+    \ifst@rred\else\global\@eqnswtrue\fi
+%    \end{macrocode}
+%    We advance \cs{row@} here, rather than at the beginning of the
+%    preamble, because otherwise the \env{split} environment will
+%    cause \cs{row@} to be advanced twice instead of once.
+%    \begin{macrocode}
+    \global\advance\row@\@ne
+    \cr
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\calc@shift@gather}
+%    \cs{calc@shift@gather} has must make two decisions: (1) whether the
+%    equation tag for the current line should be put on a separate
+%    line and (2) what the distance between the equation and the
+%    equation tag should be.  We implement \tex/'s built-in
+%    tag-placement as well as possible, with one improvement: the
+%    minimum separation between tag and equation is now a
+%    user-settable parameter.
+%
+%    [1995/01/17] Added a check to make sure that the width of the tag
+%    on the current line is $>0$ before testing to see if tagwidth +
+%    linewidth + mintagsep $>$ displaywidth. Since an imbedded align
+%    shows up as line with width \cn{displaywidth}, and even lines
+%    without a tag get processed as if an empty tag were present, the
+%    result was that the empty tag assigned to the line containing the
+%    align was being shifted downwards, creating extra space after the
+%    align.
+%    \begin{macrocode}
+\def\calc@shift@gather{%
+    \dimen@\mintagsep\relax
+    \tagwidth@\tag@width\row@\relax
+%    \end{macrocode}
+%    If we're in \opt{fleqn} mode, there is no flexibility about
+%    placement of the equation, so all we can do is see if there's
+%    room for the tag in the given margin.
+%    \begin{macrocode}
+    \if@fleqn
+        \global\eqnshift@\@mathmargin
+        \ifdim\tagwidth@>\z@
+            \advance\dimen@\tagwidth@
+            \iftagsleft@
+                \ifdim\dimen@>\@mathmargin
+                    \global\shifttag@true
+                \fi
+            \else
+                \advance\dimen@\@mathmargin
+                \advance\dimen@\wdz@
+                \ifdim\dimen@>\displaywidth
+                   \global\shifttag@true
+                \fi
+            \fi
+        \fi
+    \else
+        \global\eqnshift@\displaywidth
+        \global\advance\eqnshift@-\wdz@
+        \ifdim\tagwidth@>\z@
+            \multiply\dimen@\tw@
+            \advance\dimen@\wdz@
+            \advance\dimen@\tagwidth@
+            \ifdim\dimen@>\displaywidth
+                \global\shifttag@true
+            \else
+                \ifdim\eqnshift@<4\tagwidth@
+                    \global\advance\eqnshift@-\tagwidth@
+                \fi
+            \fi
+        \fi
+        \global\divide\eqnshift@\tw@
+        \iftagsleft@
+            \global\eqnshift@-\eqnshift@
+            \global\advance\eqnshift@\displaywidth
+            \global\advance\eqnshift@-\wdz@
+        \fi
+        \ifdim\eqnshift@<\z@
+            \global\eqnshift@\z@
+        \fi
+    \fi
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\place@tag@gather}
+%    \begin{macro}{\set@gather@field}
+%    \begin{macrocode}
+\def\place@tag@gather{%
+    \iftagsleft@
+        \kern-\gdisplaywidth@
+        \ifshifttag@
+            \rlap{\vbox{%
+                \normalbaselines
+                \boxz@
+                \vbox to\lineht@{}%
+                \raise@tag
+            }}%
+            \global\shifttag@false
+        \else
+            \rlap{\boxz@}%
+        \fi
+    \else
+        \ifdim\totwidth@>\displaywidth
+            \dimen@\totwidth@
+            \advance\dimen@-\displaywidth
+            \kern-\dimen@
+        \fi
+        \ifshifttag@
+            \llap{\vtop{%
+                \raise@tag
+                \normalbaselines
+                \setbox\@ne\null
+                \dp\@ne\lineht@
+                \box\@ne
+                \boxz@
+            }}%
+            \global\shifttag@false
+        \else
+            \llap{\boxz@}%
+        \fi
+    \fi
+}
+%
+\def\set@gather@field{%
+    \iftagsleft@
+        \global\lineht@\ht\z@
+    \else
+        \global\lineht@\dp\z@
+    \fi
+    \kern\eqnshift@
+    \boxz@
+    \hfil
+}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%
+% \subsection{The \env{align} family of environments}
+%
+%    The \env{align}, \env{flalign}, \env{alignat}, \env{xalignat},
+%    and \env{xxalignat} environments are virtually
+%    identical, and thus will share much code.  We'll refer to the
+%    environments generically as ``\env{align}'' and will
+%    distinguish between them explicitly
+%    only when necessary.
+%
+% \begin{macro}{\ifxxat@}
+% \begin{macro}{\ifcheckat@}
+% \begin{macro}{\xatlevel@}
+%    The \cs{xatlevel@} macro will be used, informally speaking, to
+%    distinguish between the \env{alignat} and \env{xalignat}, and
+%    \env{xxalignat} environments.
+%
+%    \begin{macrocode}
+\newif\ifxxat@
+
+\newif\ifcheckat@
+
+\let\xatlevel@\@empty
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+% \begin{macro}{\start@align}
+%    \cs{start@align} will be called by all of the \env{align}-like
+%    environments.  The first argument will be the \cs{xatlevel@},
+%    i.e., 0, 1, or~2; the second argument will be either
+%    \cs{st@rredtrue} or \cs{st@rredfalse}.  The third argument will
+%    be the number of aligned
+%    structures in the environment (either as supplied by the user, or
+%    $-1$ to indicate that checking shouldn't be done).  After
+%    performing the appropriate error detection and initialization,
+%    \cs{start@align} calls \cs{align@}.
+%
+%    Note that the \cs{equation} counter is no longer stepped at the
+%    beginning of these environments.
+%
+%    TODO: Implement \cs{shoveleft} and \cs{shoveright} for
+%    \env{align}.
+%    \begin{macrocode}
+\def\start@align#1#2#3{%
+    \let\xatlevel@#1% always \z@, \@ne, or \tw@
+    \maxfields@#3\relax
+    \ifnum\maxfields@>\m@ne
+        \checkat@true
+        \ifnum\xatlevel@=\tw@
+            \xxat@true
+        \fi
+        \multiply\maxfields@\tw@
+    \else
+        \checkat@false
+    \fi
+    \ifingather@
+        \iffalse{\fi\ifnum0=`}\fi
+        \DN@{\vcenter\bgroup\savealignstate@\align@#2}%
+    \else
+        \ifmmode
+          \if@display
+             \DN@{\align@recover}%
+          \else
+            \nomath@env
+            \DN@{\@namedef{end\@currenvir}{}\@gobble}%
+          \fi
+        \else
+            $$%
+            \let\split\insplit@
+            \DN@{\align@#2}%
+        \fi
+    \fi
+    \collect@body\next@
+}
+%    \end{macrocode}
+%
+%    With version 1.2 of \pkg{amsmath}, it was possible to use
+%    \env{align*} and relatives in certain wrong contexts without
+%    getting an error, e.g.
+% \begin{verbatim}
+% \begin{equation*}
+% \begin{align*}
+% ...
+% \end{align*}
+% \end{equation*}
+% \end{verbatim}
+%
+%    For backward compatibility we therefore give only a warning for
+%    this condition instead of a full error, and try to recover using
+%    the \env{aligned} environment. The alignment of the material may be
+%    adversely affected but it will at least remain readable.
+%    \begin{macrocode}
+\def\align@recover#1#2#3{%
+  \endgroup
+  \@amsmath@err{%
+Erroneous nesting of equation structures;\MessageBreak
+trying to recover with `aligned'%
+  }\@ehc
+  \begin{aligned}\relax#1\end{aligned}%
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{environment}{align}
+%    \begin{environment}{align*}
+%    \begin{environment}{flalign}
+%    \begin{environment}{flalign*}
+%    \begin{environment}{alignat}
+%    \begin{environment}{alignat*}
+%    \begin{environment}{xalignat}
+%    \begin{environment}{xalignat*}
+%    \begin{environment}{xxalignat}
+%    The definitions of the various \env{align} environments are quite
+%    straight-forward.
+%
+%    \begin{macrocode}
+\newenvironment{alignat}{%
+  \start@align\z@\st@rredfalse
+}{%
+  \endalign
+}
+\newenvironment{alignat*}{%
+  \start@align\z@\st@rredtrue
+}{%
+  \endalign
+}
+\newenvironment{xalignat}{%
+  \start@align\@ne\st@rredfalse
+}{%
+  \endalign
+}
+\newenvironment{xalignat*}{%
+  \start@align\@ne\st@rredtrue
+}{%
+  \endalign
+}
+\newenvironment{xxalignat}{%
+  \start@align\tw@\st@rredtrue
+}{%
+  \endalign
+}
+\newenvironment{align}{%
+  \start@align\@ne\st@rredfalse\m@ne
+}{%
+  \math@cr \black@\totwidth@
+  \egroup
+  \ifingather@
+    \restorealignstate@
+    \egroup
+    \nonumber
+    \ifnum0=`{\fi\iffalse}\fi
+  \else
+    $$%
+  \fi
+  \ignorespacesafterend
+}
+\newenvironment{align*}{%
+  \start@align\@ne\st@rredtrue\m@ne
+}{%
+  \endalign
+}
+\newenvironment{flalign}{%
+  \start@align\tw@\st@rredfalse\m@ne
+}{%
+  \endalign
+}
+\newenvironment{flalign*}{%
+  \start@align\tw@\st@rredtrue\m@ne
+}{%
+  \endalign
+}
+%    \end{macrocode}
+%    \end{environment}
+%    \end{environment}
+%    \end{environment}
+%    \end{environment}
+%    \end{environment}
+%    \end{environment}
+%    \end{environment}
+%    \end{environment}
+%    \end{environment}
+%
+%
+%  \begin{macro}{\align@}
+%    TODO: Some of these sets of initializations show up in multiple
+%    places.  It might be worth making an abbreviation for them.
+%
+%    \begin{macrocode}
+\def\align@#1#2{%
+    \inalign@true \intertext@ \Let@ \chardef\dspbrk@context\z@
+    \ifingather@\else\displ@y@\fi
+    \let\math@cr@@@\math@cr@@@align
+    \ifxxat@\else \let\tag\tag@in@align \fi
+    \let\label\label@in@display
+    #1% set st@r
+    \ifst@rred\else \global\@eqnswtrue \fi
+    \measure@{#2}%
+    \global\row@\z@
+    \tabskip\eqnshift@
+    \halign\bgroup
+        \span\align@preamble\crcr
+        #2%
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\math@cr@@@align}
+%    \begin{macrocode}
+\def\math@cr@@@align{%
+  \ifst@rred\nonumber\fi
+  \if@eqnsw \global\tag@true \fi
+  \global\advance\row@\@ne
+  \add@amps\maxfields@
+  \omit
+  \kern-\alignsep@
+  \iftag@
+    \setboxz@h{\@lign\strut@{\make@display@tag}}%
+    \place@tag
+  \fi
+  \ifst@rred\else\global\@eqnswtrue\fi
+  \global\lineht@\z@
+  \cr
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\math@cr@@@align@measure}
+%    \begin{macrocode}
+\def\math@cr@@@align@measure{%
+   &\omit
+    \global\advance\row@\@ne
+    \ifst@rred\nonumber\fi
+    \if@eqnsw \global\tag@true \fi
+    \ifnum\column@>\maxfields@
+        \ifcheckat@
+            \begingroup
+              \measuring@false
+              \@amsmath@err{Extra & on this line}%
+                {\the\andhelp@}% "An extra & here is disastrous"
+            \endgroup
+        \else
+            \global\maxfields@\column@
+        \fi
+    \fi
+    \setboxz@h{\@lign\strut@{%
+        \if@eqnsw
+            \stepcounter{equation}%
+            \tagform@\theequation
+        \else
+            \iftag@\df@tag\fi
+        \fi
+    }}%
+    \savetaglength@
+    \ifst@rred\else\global\@eqnswtrue\fi
+    \cr
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macro}{\field@lengths}
+%    \begin{macro}{\savefieldlength@}
+%    \begin{macro}{\fieldlengths@}
+%    \begin{macrocode}
+\let\field@lengths\@empty
+
+\def\savefieldlength@{%
+    \begingroup
+        \let\or\relax
+        \xdef\field@lengths{%
+            \field@lengths
+            \ifnum\column@=0
+                \or
+            \else
+                ,%
+            \fi
+            \the\wdz@
+        }%
+    \endgroup
+}
+
+\def\fieldlengths@#1{%
+    \ifcase\@xp#1\field@lengths\fi
+}
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%    \end{macro}
+%
+%  \begin{macro}{\maxcolumn@widths}
+%    \cs{maxcolumn@widths} will be used to hold the widths of the
+%    fields of the \env{alignat} environment.  The widths will be
+%    separated by the token \cn{or}, making it easy to extract a given
+%    width using \cn{ifcase}.
+%    \begin{macrocode}
+\let\maxcolumn@widths\@empty
+%    \end{macrocode}
+%  \end{macro}
+%
+%  \begin{macro}{\maxcol@width}
+% \cs{maxcol@width} $n$ = maximum width of $n$th column of the current
+%    \env{alignat} (i.e., the $n$th field of \cs{maxcolumn@widths}.)
+%    It expands to a \<dimen>, so it can be used as the right-hand
+%    side of a \<variable assignment> or \<arithmetic> statement.
+%    It's argument can be any \<number>, \<integer variable> or macro
+%    that expands to one of these.  [Check to make sure this is true.]
+%
+%    This is subtler than it looks.
+%    \begin{macrocode}
+\def\maxcol@width#1{%
+    \ifcase\@xp#1\maxcolumn@widths\fi\relax
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%    Now comes the real fun.  A typical \env{align} environments looks
+%    something like this, where the vertical bars mark the edges of
+%    the fields of the underlying \cs{halign}:
+%    \[
+%    \makeatletter\tabskip\@centering\offinterlineskip
+%    \halign to\displaywidth{%^^A
+%       &$\strut$\vrule\hfil$\m@th\displaystyle{\@lign#}$\vrule
+%      \tabskip1pt&\vrule$\m@th\displaystyle{\@lign#}$\hfil\vrule
+%      \tabskip\@centering\cr
+%    \omit\small\hfil 1\hfil &\omit\small\hfil 2 &\omit\small\hfil
+%    3\hfil &\omit\small\hfil 4\hfil & \omit\small\hfil 5\hfil
+%    &\omit\small\hfil 6\hfil\cr
+%    \noalign{\vskip8pt\relax}
+%    V_i + q_i v_j & =v_i , &  X_i & = x_i - q_i x_j,
+%     &  U_i & = u_i,\qquad
+%      \hbox{for $i\ne j$;} %&\omit\hfill \llap{(3)}
+%    \cr
+%    V_j & = v_j, &  X_j & = x_j,
+%      &  U_j & = u_j + \sum_{i\ne j} q_i u_i. %&\omit\hfill \llap{(4)}
+%    \cr}
+%    \]
+%    Note that each align structure consists of two fields, with no
+%    space between them (a small space has been added here to
+%    highlight the boundaries).  Furthermore, the text inside the
+%    odd-numbered fields is flushright, while the text inside the
+%    even-numbered fields is flushleft.  The equation tags (shown on
+%    the right here) can be on either the right or the left.  If there
+%    is not room (in a sense to be defined shortly) for the tag on the
+%    same line as the equation, the tag will be shifted to a separate
+%    line.
+%
+%    Each environment also has a certain number of ``flexible
+%    spaces,'' meaning spaces whose width we are allowed to adjust to
+%    take up the amount of ``free space'' in the line, meaning the
+%    space not taken up by the equation tag and the fields of the
+%    underlying \cs{halign}.
+%
+%    The flexible spaces come in two flavors: interalign spaces and
+%    margin spaces.  If there are $n$ align structures ($n=3$ in the
+%    illustration above), there are $n-1$ interalign spaces, unless we
+%    are in an \env{alignat} environment, in which case there are no
+%    flexible interalign spaces.
+%
+%    The number of margin spaces is a little more complicated:
+%    Normally, there are two, but if we're in \opt{fleqn} mode, there
+%    is only one.  Furthermore, if we're in an \env{xxalignat} or
+%    \env{flalign} environment (corresponding to $\cs{xatlevel@} = 2$,
+%    then there are no flexible margin spaces.
+%
+%    Calculating the interalign and margin spaces is done in two
+%    stages.
+%
+%    First, the total amount of free space is divided uniformly among
+%    all the flexible spaces, without regard for the lengths of the tags
+%    on the various lines. For the non-\opt{fleqn} case, this
+%    corresponds to centering the align structures between the margins.
+%    Note that in \opt{fleqn} mode, the right margin is still allowed to
+%    be larger than \cs{@mathmargin}. This introduces an element of
+%    asymmetry into the appearance of the environment, but it has the
+%    advantage of leaving more space for equation tags in the right
+%    margin. If the right margin were constrained to be equal to the
+%    left margin in this case, tags would need to be shifted to a
+%    separate line more often than would be desirable.
+%
+%    Ordinarily, all flexible spaces will be given the same width.
+%    However, this is not invariably true, since the interalign spaces
+%    are constrained to be at least \cs{minalignsep} wide, while---in
+%    the absence of equation tags, at least---the margin spaces are
+%    allowed to shrink to zero.  As we shall see in a minute, if there
+%    are tags in the environment, then the margins are also bounded
+%    below by \cs{mintagsep}.
+%
+%    Next, we examine each line of the environment that has a tag to
+%    see if there is a gap of at least \cs{mintagsep} between the
+%    equation and its tag.  If there isn't, we attempt to center the
+%    equation between the tag and the opposite margin, leaving a gap
+%    of at least \cs{mintagsep} on either side, in order to preserve
+%    some symmetry, i.e., we want the equation to \emph{look} like
+%    it's centered between the margin and the tag, so we don't want
+%    the margin space to be less than the gap between the tag and the
+%    equation.  (Arguably, it would be better to allow the margin
+%    space to shrink to zero in this case in order to avoid shifting
+%    the tag to a separate line at any cost, but that would require
+%    all of our calculations to be a little more complicated and hence
+%    a little slower.)  Finally, if no values of the interalign spaces
+%    and the margins (with the constraints outlined above) will
+%    produce an acceptable distance between the equation and its tag,
+%    then the tag will be shifted to a separate line.
+%
+%  \begin{macro}{\measure@}
+%    \cs{measure@} collects the various bits of information that we'll
+%    need to perform the calculations outlined above, namely, the
+%    number of align structures in the environment, the natural
+%    lengths of the fields on each row, the maximum widths of each
+%    column, and the widths of the equation tags on each line.  It
+%    also calculates the number of flexible interalign and margin
+%    spaces and computes the initial values of the parameters
+%    \cs{eqnshift@} and \cs{alignsep@}, which correspond to the widths
+%    of the margins and the interalign spaces, respectively.
+%    \begin{macrocode}
+\def\measure@#1{%
+    \begingroup
+        \measuring@true
+        \global\eqnshift@\z@
+        \global\alignsep@\z@
+        \global\let\tag@lengths\@empty
+        \global\let\field@lengths\@empty
+        \savecounters@
+        \global\setbox0\vbox{%
+            \let\math@cr@@@\math@cr@@@align@measure
+            \everycr{\noalign{\global\tag@false
+              \global\let\raise@tag\@empty \global\column@\z@}}%
+            \let\label\@gobble
+            \global\row@\z@
+            \tabskip\z@
+            \halign{\span\align@preamble\crcr
+                #1%
+                \math@cr@@@
+                \global\column@\z@
+                \add@amps\maxfields@\cr
+            }%
+        }%
+        \restorecounters@
+%    \end{macrocode}
+%    It's convenient to have \cs{maxfields@} rounded up to the nearest
+%    even number, so that \cs{maxfields@} is precisely twice the
+%    number of align structures.
+%    \begin{macrocode}
+        \ifodd\maxfields@
+            \global\advance\maxfields@\@ne
+        \fi
+%    \end{macrocode}
+%    It doesn't make sense to have a single align structure in either
+%    \env{flalign} or \env{xxalignat}.  So, we check for that case now
+%    and, if necessary, switch to an \env{align} or \env{alignat}.
+%    Arguably, we should issue a warning message, but why bother?
+%    \begin{macrocode}
+        \ifnum\xatlevel@=\tw@
+            \ifnum\maxfields@<\thr@@
+                \let\xatlevel@\z@
+            \fi
+        \fi
+%    \end{macrocode}
+%    |\box0| now contains the lines of the \cs{halign}.  After the
+%    following maneuver, |\box1| will contain the last line of the
+%    \cs{halign}, which is what we're interested in.  (Incidentally,
+%    the penalty we're removing is the \cs{@eqpen} inserted by
+%    \cs{math@cr}.  Normally, this is \cs{interdisplaylinepenalty},
+%    unless the user has overridden that with a \cs{displaybreak}
+%    command.)
+%    \begin{macrocode}
+        \setbox\z@\vbox{%
+          \unvbox\z@ \unpenalty \global\setbox\@ne\lastbox
+        }%
+%    \end{macrocode}
+%    |\box1| begins with \cs{tabskip} glue and contains alternating
+%    \cs{hbox}es (the fields whose widths we're trying to get) and
+%    \cs{tabskip} glue [need better diagram]:
+%    \begin{verbatim}
+%    \hbox{\tabskip\hbox\tabskip...\hbox\tabskip}\end{verbatim}
+%    In fact, all the \cs{tabskip} glue will be 0pt, because all the
+%    \cs{tabskip}s in an \env{alignat} environment have a natural
+%    width of 0pt, and the \cs{halign} has been set in its natural
+%    width.
+%
+%    One nice result of this is that we can read \cs{totwidth@} off
+%    immediately, since it is just the width of |\box1|, plus
+%    \cs{@mathmargin} if we're in \opt{fleqn} mode.  (Actually, we
+%    also have to take \cs{minalignsep} into account, but we'll do
+%    that later):
+%    \begin{macrocode}
+        \global\totwidth@\wd\@ne
+        \if@fleqn \global\advance\totwidth@\@mathmargin \fi
+%    \end{macrocode}
+%    Now we initialize \cs{align@lengths} and start peeling the boxes
+%    off, one by one, and adding their widths to \cs{align@lengths}.
+%    We stop when we run out of boxes, i.e., when \cs{lastbox} returns
+%    a void box.  We're going to build a list using \cs{or} as a
+%    delimiter, so we want to disable it temporarily.
+%    \begin{macrocode}
+        \global\let\maxcolumn@widths\@empty
+        \begingroup
+          \let\or\relax
+          \loop
+            \global\setbox\@ne\hbox{%
+              \unhbox\@ne \unskip \global\setbox\thr@@\lastbox
+            }%
+          \ifhbox\thr@@
+           \xdef\maxcolumn@widths{ \or \the\wd\thr@@ \maxcolumn@widths}%
+          \repeat
+        \endgroup
+%    \end{macrocode}
+%    Now we calculate the number of flexible spaces and the initial
+%    values of \cs{eqnshift@} and \cs{alignsep@}.
+%    We start by calculating $\cs{displaywidth}-\cs{totwidth@}$,
+%    which gives us the total amount of ``free space'' in a row.
+%    \begin{macrocode}
+        \dimen@\displaywidth
+        \advance\dimen@-\totwidth@
+%    \end{macrocode}
+%    Next we calculate the number of columns of flexible spaces in the
+%    display, which depends on whether we're in \opt{fleqn} mode and
+%    in which particular environment we are in.
+%
+%    We use \cs{@tempcnta} to store the total number of flexible spaces
+%    in the align and \cs{@tempcntb} for the number of interalign
+%    spaces.
+%    \begin{macrocode}
+        \ifcase\xatlevel@
+%    \end{macrocode}
+%    In \env{alignat}, the interalign spaces are under user control,
+%    not ours.  So, we set \cs{alignsep@} and \cs{minalignsep} both
+%    equal to 0pt.  Later, when calculating a new value for
+%    \cs{alignsep@}, we will only save the new value if it is less
+%    than the current value of \cs{alignsep@} (i.e., \cs{alignsep@}
+%    will never increase).  Since the values we calculate will never
+%    be negative, this will ensure that \cs{alignsep@} remains zero in
+%    \env{alignat}.
+%    \begin{macrocode}
+            \global\alignsep@\z@
+            \let\minalignsep\z@
+            \@tempcntb\z@
+%    \end{macrocode}
+%    In \opt{fleqn} mode, the left margin---and hence the right margin
+%    in this case---is fixed.  Otherwise, we divide the free space
+%    equally between the two margins.
+%    \begin{macrocode}
+            \if@fleqn
+                \@tempcnta\@ne
+                \global\eqnshift@\@mathmargin
+            \else
+                \@tempcnta\tw@
+                \global\eqnshift@\dimen@
+                \global\divide\eqnshift@\@tempcnta
+            \fi
+        \or
+%    \end{macrocode}
+%    In an \env{align} or \env{xalignat} environment with $n$ aligned
+%    structures, there are $n-1$ interalign spaces and either 1 or~2
+%    flexible margins, depending on whether we're in \opt{fleqn} mode
+%    or not.
+%    \begin{macrocode}
+            \@tempcntb\maxfields@
+            \divide\@tempcntb\tw@
+            \@tempcnta\@tempcntb
+            \advance\@tempcntb\m@ne
+%    \end{macrocode}
+%    If we are in \opt{fleqn} mode, we fix the left margin and divide
+%    the free space equally among the interalign spaces and the right
+%    margin.
+%    \begin{macrocode}
+            \if@fleqn
+                \global\eqnshift@\@mathmargin
+                \global\alignsep@\dimen@
+                \global\divide\alignsep@\@tempcnta
+            \else
+%    \end{macrocode}
+%    Otherwise, we divide the free space equally among the interalign
+%    spaces and both margins.
+%    \begin{macrocode}
+                \global\advance\@tempcnta\@ne
+                \global\eqnshift@\dimen@
+                \global\divide\eqnshift@\@tempcnta
+                \global\alignsep@\eqnshift@
+            \fi
+        \or
+%    \end{macrocode}
+%    Finally, if we're in an \env{flalign} or \env{xxalignat}
+%    environment, there are no flexible margins and $n-1$ flexible
+%    interalign spaces.
+%    \begin{macrocode}
+            \@tempcntb\maxfields@
+            \divide\@tempcntb\tw@
+            \global\advance\@tempcntb\m@ne
+            \global\@tempcnta\@tempcntb
+            \global\eqnshift@\z@
+            \global\alignsep@\dimen@
+%    \end{macrocode}
+%    If we're in \opt{fleqn} mode, we need to add back the
+%    \cs{@mathmargin} that was removed when \cs{dimen@} was originally
+%    calculated above.
+%    \begin{macrocode}
+            \if@fleqn
+                \global\advance\alignsep@\@mathmargin\relax
+            \fi
+            \global\divide\alignsep@\@tempcntb
+        \fi
+%    \end{macrocode}
+%    Now we make sure \cs{alignsep@} isn't too small.
+%    \begin{macrocode}
+        \ifdim\alignsep@<\minalignsep\relax
+            \global\alignsep@\minalignsep\relax
+            \ifdim\eqnshift@>\z@
+                \if@fleqn\else
+                    \global\eqnshift@\displaywidth
+                    \global\advance\eqnshift@-\totwidth@
+                    \global\advance\eqnshift@-\@tempcntb\alignsep@
+                    \global\divide\eqnshift@\tw@
+                \fi
+            \fi
+        \fi
+        \ifdim\eqnshift@<\z@
+            \global\eqnshift@\z@
+        \fi
+        \calc@shift@align
+%    \end{macrocode}
+%    Next, we calculate the value of \cs{tagshift@}.  This is the glue
+%    that will be inserted in front of the equation tag to make sure
+%    it lines up flush against the appropriate margin.
+%    \begin{macrocode}
+        \global\tagshift@\totwidth@
+        \global\advance\tagshift@\@tempcntb\alignsep@
+        \if@fleqn
+            \ifnum\xatlevel@=\tw@
+                \global\advance\tagshift@-\@mathmargin\relax
+            \fi
+        \else
+            \global\advance\tagshift@\eqnshift@
+        \fi
+        \iftagsleft@ \else
+            \global\advance\tagshift@-\displaywidth
+        \fi
+%    \end{macrocode}
+%    Finally, we increase \cs{totwidth@} by an appropriate multiple of
+%    \cs{minalignsep}.  If the result is greater than
+%    \cs{displaywidth}, it means that at least one line in the
+%    \env{align} is overfull and we will issue an appropriate warning
+%    message (via \cs{bl@ck}) at the end of the environment.
+%    \begin{macrocode}
+        \dimen@\minalignsep\relax
+        \global\advance\totwidth@\@tempcntb\dimen@
+        \ifdim\totwidth@>\displaywidth
+            \global\let\displaywidth@\totwidth@
+        \else
+            \global\let\displaywidth@\displaywidth
+        \fi
+    \endgroup
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%    The code for calculating the appropriate placement of equation
+%    tags in the \env{align} environments is quite complicated and
+%    varies wildly depending on the settings of the |tagsleft@| and
+%    |@fleqn| switches.  To minimize memory and hash space usage, we
+%    only define the variant appropriate for the current setting of
+%    those switches.
+%
+%    It would be worthwhile to examine this code more closely someday
+%    and see if it could be optimized any.
+%
+%    \paragraph{Tag placement when \cs{tagsleft@true},
+%    \cs{@fleqntrue}.}
+%
+%    We begin with the version of \cs{calc@shift@align} appropriate
+%    for flush-left equations with tags on the left.
+%
+%    \begin{macro}{\calc@shift@align}
+%    This is the simplest case.  Since the left margin is fixed, in
+%    general the only thing to do is check whether there is room for
+%    the tag in the left margin.  The only exception is that if
+%    $\cs{eqnshift@} = 0\,\mathrm{pt}$---meaning that we're in a
+%    \env{flalign} environment and this is the first line with a tag
+%    that we've encountered---then we set $\cs{eqnshift@} =
+%    \cs{@mathmargin}$ and recalculate \cs{alignsep@}.  This is done
+%    by \cs{x@calc@shift@lf}.
+%    \begin{macrocode}
+\iftagsleft@\if@fleqn
+    \def\calc@shift@align{%
+        \global\let\tag@shifts\@empty
+        \begingroup
+%    \end{macrocode}
+%    \cs{@tempdima} is initialized to $\cs{@mathmargin} -
+%    \cs{mintagsep}$, which yields the maximum size of a tag that will
+%    not be shifted to another line.
+%    \begin{macrocode}
+            \@tempdima\@mathmargin\relax
+            \advance\@tempdima-\mintagsep\relax
+%    \end{macrocode}
+%    Now we examine each row in turn.  If the width of the tag on the
+%    line is non-positive---meaning either that there is no tag or
+%    else that the user has forced it to have zero width---we mark the
+%    tag to remain unshifted.  Otherwise, we call \cs{x@calc@shift@lf}
+%    to determine whether any adjustments need to be made to
+%    \cs{eqnshift@} and \cs{alignsep@}.  Note the difference in
+%    treatment of zero-width tags between this code and \tex/'s
+%    built-in algorithm: here, a width of zero prohibits the tag from
+%    being shifted, while in \tex/'s built-in algorithm, a width of
+%    zero forces the tag to be shifted.
+%    \begin{macrocode}
+            \loop
+                \ifnum\row@>0
+                    \ifdim\tag@width\row@>\z@
+                        \x@calc@shift@lf
+                    \else
+                        \saveshift@0%
+                    \fi
+                    \advance\row@\m@ne
+            \repeat
+        \endgroup
+    }
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\x@calc@shift@lf}
+%    As mentioned above, \cs{x@calc@shift@lf} first checks to see if
+%    the current left margin is set to 0 and, if so, resets it to
+%    \cs{@mathmargin} and recalculates \cs{alignsep@}.  Next, it
+%    checks whether the length of the current tag exceeds the
+%    previously calculated limit and, if so, marks the tag to be
+%    shifted to a separate line.
+%    \begin{macrocode}
+    \def\x@calc@shift@lf{%
+        \ifdim\eqnshift@=\z@
+            \global\eqnshift@\@mathmargin\relax
+            \alignsep@\displaywidth
+            \advance\alignsep@-\totwidth@
+            \global\divide\alignsep@\@tempcntb
+            \ifdim\alignsep@<\minalignsep\relax
+                \global\alignsep@\minalignsep\relax
+            \fi
+        \fi
+        \ifdim\tag@width\row@>\@tempdima
+            \saveshift@1%
+        \else
+            \saveshift@0%
+        \fi
+    }
+\fi\fi
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \paragraph{Tag placement when \cs{tagsleft@false},
+%    \cs{@fleqntrue}.}
+%
+%    Next we consider the case when equations are flush-left, but tags
+%    are on the right.  This case is somewhat more complicated than
+%    the previous one, since we can adjust the right margin by varying
+%    the inter-align separatin. Thus, when a tag is found to be too
+%    close to its equation, we first attempt to decrease
+%    \cs{alignsep@} enough to move the equation off to an acceptable
+%    distance.  Only if that would require a value of \cs{alignsep@}
+%    less than \cs{minalignsep} do we move the tag to a separate line.
+%
+%    \begin{macro}{\calc@shift@align}
+%    This version of \cs{calc@shift@align} differs from the previous
+%    version only in calling \cs{x@calc@shift@rf} rather than
+%    \cs{x@calc@shift@lf}.
+%    \begin{macrocode}
+\iftagsleft@\else\if@fleqn
+    \def\calc@shift@align{%
+        \global\let\tag@shifts\@empty
+        \begingroup
+            \loop
+                \ifnum\row@>0
+                    \ifdim\tag@width\row@>\z@
+                        \x@calc@shift@rf
+                    \else
+                        \saveshift@0%
+                    \fi
+                    \advance\row@\m@ne
+            \repeat
+        \endgroup
+    }
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\x@calc@shift@rf}
+%    To start, we need to know two quantities: the number of align
+%    structures in the current row and the ``effective length'' of the
+%    row, defined as the distance from the left margin to the
+%    right edge of the text assuming that \cs{eqnshift@} and
+%    \cs{alignsep@} are both~0.  To get the number of align
+%    structures, we first count the number of columns by counting the
+%    number of entries in the \cs{fieldlengths@} for the current row.
+%    The effective length is calcuated by \cs{x@rcalc@width} and put
+%    in the temporary register \cs{@tempdimc}, using \cs{@tempdimb} as
+%    an auxiliary variable.
+%    \begin{macrocode}
+    \def\x@calc@shift@rf{%
+        \column@\z@
+        \@tempdimb\z@
+        \@tempdimc\z@
+        \edef\@tempb{\fieldlengths@\row@}%
+        \@for\@tempa:=\@tempb\do{%
+            \advance\column@\@ne
+            \x@rcalc@width
+        }%
+        \begingroup
+%    \end{macrocode}
+%    If there are $n$ columns in the current row, then there are
+%    $\lfloor (n+1)/2 \rfloor$ align structures and $\lfloor (n-1)/2
+%    \rfloor$ interalign spaces.
+%    \begin{macrocode}
+            \advance\column@\m@ne
+            \divide\column@\tw@
+%    \end{macrocode}
+%    If this is smaller than the maximum number of interalign spaces
+%    in the environment, then we need to reduce \cs{@tempcnta} (the
+%    total number of flexible spaces in the current line) by
+%    $\cs{@tempcntb} - \cs{column@}$ and reset \cs{@tempcntb} to
+%    \cs{column@}.
+%    \begin{macrocode}
+            \ifnum\@tempcntb>\column@
+                \advance\@tempcnta-\@tempcntb
+                \advance\@tempcnta\column@
+                \@tempcntb\column@
+            \fi
+%    \end{macrocode}
+%    Next, we add the width of the tag and the (fixed) left margin to
+%    the effective length calculated above.  This can be used to
+%    calculate how much ``free space'' there is in the current line
+%    and thus how much leeway we have to increase the amount of space
+%    between the tag and the equation.
+%    \begin{macrocode}
+            \tagwidth@\tag@width\row@\relax
+            \@tempdima\eqnshift@
+            \advance\@tempdima\@tempdimc\relax
+            \advance\@tempdima\tagwidth@
+%    \end{macrocode}
+%    The first thing to check is whether the tag should be shifted to
+%    a separate line.  To do this, we add the minimum interalign
+%    separation and the \cs{mintagsep} to the value of \cs{@tempdima}
+%    just calculated.  This yields the minimum acceptable length of
+%    the current line.  If that is greater than \cs{displaywidth}, we
+%    mark the tag to be calculated.  Otherwise, we mark the tag to be
+%    kept on the same line and then check to see if the \cs{alignsep@}
+%    needs to be reduced to make room for the tag.
+%    \begin{macrocode}
+            \dimen@\minalignsep\relax
+            \multiply\dimen@\@tempcntb
+            \advance\dimen@\mintagsep\relax
+            \advance\dimen@\@tempdima
+            \ifdim\dimen@>\displaywidth
+                \saveshift@1%
+            \else
+                \saveshift@0%
+%    \end{macrocode}
+%    Now we perform essentially the same calculation, but using the
+%    current value of \cs{alignsep@} instead of \cs{minalignsep}.
+%    This gives the current length of the line.  If this is greater
+%    than \cs{displaywidth}, we recalculate \cs{alignsep@} to make
+%    room for the tag.
+%    \begin{macrocode}
+                \dimen@\alignsep@\relax
+                \multiply\dimen@\@tempcntb
+                \advance\dimen@\@tempdima
+                \advance\dimen@\tagwidth@
+                \ifdim\dimen@>\displaywidth
+                    \dimen@\displaywidth
+                    \advance\dimen@-\@tempdima
+                    \ifnum\xatlevel@=\tw@
+                        \advance\dimen@-\mintagsep\relax
+                    \fi
+                    \divide\dimen@\@tempcnta
+                    \ifdim\dimen@<\minalignsep\relax
+                        \global\alignsep@\minalignsep\relax
+                    \else
+                        \global\alignsep@\dimen@
+                    \fi
+                \fi
+            \fi
+        \endgroup
+    }
+\fi\fi
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \paragraph{Tag placement when \cs{tagsleft@false},
+%    \cs{@fleqnfalse}.}
+%
+%    This is similar to the previous case, except for the added
+%    complication that both \cs{alignsep@} and \cs{eqnshift@} can
+%    vary, which makes the computations correspondingly more
+%    complicated.
+%
+%    \begin{macro}{\calc@shift@align}
+%    \begin{macrocode}
+\iftagsleft@\else\if@fleqn\else
+    \def\calc@shift@align{%
+        \global\let\tag@shifts\@empty
+        \begingroup
+            \loop
+                \ifnum\row@>0
+                    \ifdim\tag@width\row@>\z@
+                        \x@calc@shift@rc
+                    \else
+                        \saveshift@0%
+                    \fi
+                    \advance\row@\m@ne
+            \repeat
+        \endgroup
+    }
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\x@calc@shift@rc}
+%    \begin{macrocode}
+    \def\x@calc@shift@rc{%
+        \column@\z@
+        \@tempdimb\z@
+        \@tempdimc\z@
+        \edef\@tempb{\fieldlengths@\row@}%
+        \@for\@tempa:=\@tempb\do{%
+            \advance\column@\@ne
+            \x@rcalc@width
+        }%
+        \begingroup
+            \advance\column@\m@ne
+            \divide\column@\tw@
+            \ifnum\@tempcntb>\column@
+                \advance\@tempcnta-\@tempcntb
+                \advance\@tempcnta\column@
+                \@tempcntb\column@
+            \fi
+            \tagwidth@\tag@width\row@\relax
+            \@tempdima\@tempdimc
+            \advance\@tempdima\tagwidth@
+            \dimen@\minalignsep\relax
+            \multiply\dimen@\@tempcntb
+            \advance\dimen@\mintagsep\relax
+            \ifnum\xatlevel@=\tw@ \else
+                \advance\dimen@\mintagsep\relax
+            \fi
+            \advance\dimen@\@tempdima
+            \ifdim\dimen@>\displaywidth
+                \saveshift@1%
+            \else
+                \saveshift@0%
+                \dimen@\eqnshift@
+                \advance\dimen@\@tempdima
+                \advance\dimen@\@tempcntb\alignsep@
+                \advance\dimen@\tagwidth@
+                \ifdim\dimen@>\displaywidth
+                    \dimen@\displaywidth
+                    \advance\dimen@-\@tempdima
+                    \ifnum\xatlevel@=\tw@
+                        \advance\dimen@-\mintagsep\relax
+                    \fi
+                    \divide\dimen@\@tempcnta
+                    \ifdim\dimen@<\minalignsep\relax
+                        \global\alignsep@\minalignsep\relax
+                        \eqnshift@\displaywidth
+                        \advance\eqnshift@-\@tempdima
+                        \advance\eqnshift@-\@tempcntb\alignsep@
+                        \global\divide\eqnshift@\tw@
+                    \else
+                        \ifdim\dimen@<\eqnshift@
+                            \ifdim\dimen@<\z@
+                                \global\eqnshift@\z@
+                            \else
+                                \global\eqnshift@\dimen@
+                            \fi
+                        \fi
+                        \ifdim\dimen@<\alignsep@
+                            \global\alignsep@\dimen@
+                        \fi
+                    \fi
+                \fi
+            \fi
+        \endgroup
+    }
+\fi\fi
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\x@rcalc@width}
+%    \begin{macrocode}
+\iftagsleft@\else
+    \def\x@rcalc@width{%
+        \ifdim\@tempa > \z@
+            \advance\@tempdimc\@tempdimb
+            \ifodd\column@
+                \advance\@tempdimc\maxcol@width\column@
+                \@tempdimb\z@
+            \else
+                \advance\@tempdimc\@tempa\relax
+                \@tempdimb\maxcol@width\column@
+                \advance\@tempdimb-\@tempa\relax
+            \fi
+        \else
+            \advance\@tempdimb\maxcol@width\column@\relax
+        \fi
+    }
+\fi
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \paragraph{Tag placement when \cs{tagsleft@true},
+%    \cs{@fleqnfalse}.}
+%
+%    \begin{macro}{\calc@shift@align}
+%    \begin{macrocode}
+\iftagsleft@\if@fleqn\else
+    \def\calc@shift@align{%
+        \global\let\tag@shifts\@empty
+        \begingroup
+            \loop
+                \ifnum\row@>\z@
+                    \ifdim\tag@width\row@>\z@
+                        \x@calc@shift@lc
+                    \else
+                        \saveshift@0%
+                    \fi
+                    \advance\row@\m@ne
+            \repeat
+        \endgroup
+    }
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\x@calc@shift@lc}
+%    \begin{macrocode}
+    \def\x@calc@shift@lc{%
+        \column@\z@
+%    \end{macrocode}
+%    \cs{@tempdima} will (eventually) be set to the effective width of
+%    the current row, defined as the distance from the leftmost point
+%    of the current line to the end of the last field of the
+%    \cs{halign}, ignoring any intervening \cs{tabskip}s, plus the
+%    width of the current tag.  That is, it will be the width of the
+%    first non-empty field plus the sum of the maximum widths of all
+%    following fields, plus the tag width.
+%
+%    \cs{@tempdimb} will be the ``indentation'' of leftmost end of
+%    text, ignoring the \cs{tabskip} glue, i.e., it will be the sum of
+%    the maximum widths of any fields to the left of the first
+%    non-empty field, plus whatever empty space there is at the
+%    beginning of the first non-empty field.
+%    \begin{macrocode}
+        \@tempdima\z@ % ``width of equation''
+        \@tempdimb\z@ % ``indent of equation''
+        \edef\@tempb{\fieldlengths@\row@}%
+        \@for\@tempa:=\@tempb\do{%
+            \advance\column@\@ne
+            \x@lcalc@width
+        }%
+        \begingroup
+            \tagwidth@\tag@width\row@\relax
+%    \end{macrocode}
+%    \cs{@tempdima} is now easy to calculate, since it is just
+%    $\cs{totwidth@} - \cs{@tempdimb} + \cs{tagwidth@}$.
+%    \begin{macrocode}
+            \@tempdima\totwidth@
+            \advance\@tempdima-\@tempdimb
+            \advance\@tempdima\tagwidth@
+%    \end{macrocode}
+%    Next, we check to see whether there is room for both the equation
+%    and the tag on the same line, by calculating the minimum
+%    acceptable length of the current row and comparing that to
+%    \cs{displaywidth}.  Note that here we use \cs{@tempcntb}, i.e.,
+%    the number of interalign spaces after the first non-empty align
+%    structure.
+%    \begin{macrocode}
+            \dimen@\minalignsep\relax
+            \multiply\dimen@\@tempcntb
+            \advance\dimen@\mintagsep\relax
+            \ifnum\xatlevel@=\tw@ \else
+                \advance\dimen@\mintagsep\relax
+            \fi
+            \advance\dimen@\@tempdima
+%    \end{macrocode}
+%    If the minimum acceptable width of the current line is greater
+%    than \cs{displaywidth}, we mark the current tag to be shifted to
+%    a separate line.
+%    \begin{macrocode}
+            \ifdim\dimen@>\displaywidth
+                \saveshift@1%
+            \else
+%    \end{macrocode}
+%    Otherwise, the tag can stay on the same line as the equation, but
+%    we need to check whether it is too close to the equation.  So, we
+%    calculate the distance between the left margin and the left side
+%    of the equation, using the current values of \cs{eqnshift@} and
+%    \cs{alignsep@}.  Note that we use \cs{count@} here, not
+%    \cs{@tempcntb}, as above.
+%    \begin{macrocode}
+                \saveshift@0%
+                \dimen@\alignsep@
+                \multiply\dimen@\count@
+                \advance\dimen@\eqnshift@
+                \advance\dimen@\@tempdimb
+%    \end{macrocode}
+%    If the left margin is less than twice the tag width, we calculate
+%    new values of \cs{eqnshift@} and \cs{alignsep@} to move the
+%    equation further away from the tag.  In particular, we center the
+%    current line between its tag and the right margin.  Note that
+%    although we later will need to transform \cs{dimen@} into a value
+%    suitable for use as \cs{eqnshift@}, for the time being it is more
+%    useful to think of it as the space separating the tag from the
+%    equation.
+%    \begin{macrocode}
+                \ifdim\dimen@<2\tagwidth@
+                    \dimen@\displaywidth
+                    \advance\dimen@-\@tempdima
+                    \ifnum\xatlevel@=\tw@
+                        \advance\dimen@-\mintagsep\relax
+                    \fi
+%    \end{macrocode}
+%    In certain circumstances we will get a divide-by-zero error here
+%    unless we guard against it. Use of \cs{@tempcnta} is complicated,
+%    sometimes it is assigned globally, sometimes locally. Need to sort
+%    it out one of these days [mjd,2000/06/02].
+%    \begin{macrocode}
+                    \ifnum\@tempcnta>\z@
+                      \divide\dimen@\@tempcnta
+                    \else \dimen@\z@
+                    \fi
+%    \end{macrocode}
+%    As usual, we check to make sure we don't set \cs{alignsep@}
+%    smaller than \cs{minalignsep} and, in any case, that we don't
+%    replace \cs{alignsep@} by a larger value.
+%    \begin{macrocode}
+                    \ifdim\dimen@<\minalignsep\relax
+                        \global\alignsep@\minalignsep\relax
+                        \dimen@\displaywidth
+                        \advance\dimen@-\@tempdima
+                        \advance\dimen@-\@tempcntb\alignsep@
+                        \global\divide\dimen@\tw@
+                    \else
+                        \ifdim\dimen@<\alignsep@
+                            \global\alignsep@\dimen@
+                        \fi
+                    \fi
+%    \end{macrocode}
+%    Next, we calculate an appropriate value of \cs{eqnshift@},
+%    assuming that \cs{dimen@} is the desired separation between the
+%    tag and equation of the current line.  This means that we first
+%    need to adjust \cs{dimen@} if we're in an \env{flalign}
+%    environment.
+%    \begin{macrocode}
+                    \ifnum\xatlevel@=\tw@
+                        \dimen@\mintagsep\relax
+                    \fi
+%    \end{macrocode}
+%    Now we calculate the value of \cs{eqnshift@} needed to produce a
+%    separation of \cs{dimen@} between the equation tag and the
+%    beginning of the equation.  To do this, we need the following
+%    equation to hold:
+%    \[
+%       \cs{eqnshift@} + n\cs{alignsep@} + \cs{@tempdimb}
+%           = \cs{tagwidth@} + \cs{dimen@}
+%    \]
+%    where $n = \cs{count@}$ is the number of interalign spaces before
+%    the first non-empty field of the current line.
+%    \begin{macrocode}
+                    \advance\dimen@\tagwidth@
+                    \advance\dimen@-\@tempdimb
+                    \advance\dimen@-\count@\alignsep@
+%    \end{macrocode}
+%    The value of \cs{eqnshift@} just calculated is the minimum
+%    acceptable value; thus, we save it only if it is larger than the
+%    current value.
+%    \begin{macrocode}
+                    \ifdim\dimen@>\eqnshift@
+                        \global\eqnshift@\dimen@
+                    \fi
+                \fi
+            \fi
+        \endgroup
+    }
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{macro}{\x@lcalc@width}
+%    This macro calculates the ``indentation'' of the current row, as
+%    defined above under the description of \cs{x@calc@shift@lc}.
+%    This macro is called for each field of the current line, with
+%    \cs{@tempa} set to the width of the current field.  Ideally, the
+%    loop enclosing \cs{x@lcalc@width} would terminate as soon as
+%    \cs{@tempa} is non-zero, but that would be a bit tricky to
+%    arrange.  Instead, we use \cs{@tempdima} as a flag to signal when
+%    we've encountered the first non-empty field.
+%
+%    \begin{macrocode}
+    \def\x@lcalc@width{%
+        \ifdim\@tempdima = \z@
+%    \end{macrocode}
+%    If the current field is empty (i.e., $\cs{@tempa} =
+%    \mathrm{0\,pt}$, then we increment \cs{@tempdimb} by the width of
+%    the current field).  Otherwise, we set $\cs{@tempdima} =
+%    \mathrm{1\,pt}$ as a signal value and increment \cs{@tempdimb} by
+%    the width of whatever empty space there might be at the left of
+%    the current field.
+%    \begin{macrocode}
+            \ifdim\@tempa > \z@
+                \@tempdima\p@
+                \ifodd\column@
+                    \advance\@tempdimb \maxcol@width\column@
+                    \advance\@tempdimb-\@tempa
+                \fi
+%    \end{macrocode}
+%    In addition, we need to adjust the values of \cs{@tempcnta} and
+%    \cs{@tempcntb} to account for any empty align structures that
+%    might occur at the beginning of the current line.  More
+%    specifically, we first set \cs{count@} equal to the number of
+%    interalign spaces preceding the current field (namely, $\lfloor
+%    (\cs{\column@}-1)/2 \rfloor$), and then subtract \cs{count@} from
+%    both \cs{@tempcnta} and \cs{@tempcntb}.  The rationale is that
+%    for the purposes of adjusting the spacing between the tag and the
+%    equation, the only flexible interalign spaces are those after
+%    the first non-empty align structure, so we need to treat those
+%    different from the ones before the first non-empty align
+%    structure.
+%    \begin{macrocode}
+                \count@\column@
+                \advance\count@\m@ne
+                \divide\count@\tw@
+                \advance\@tempcnta-\count@
+                \advance\@tempcntb-\count@
+            \else
+                \advance\@tempdimb \maxcol@width\column@\relax
+            \fi
+        \fi
+    }
+\fi\fi
+%    \end{macrocode}
+%    \end{macro}
+%
+%  \begin{macro}{\place@tag}
+%    \cs{place@tag} takes care of the placment of tags in the
+%    \env{align} environments.
+%    \begin{macrocode}
+\def\place@tag{%
+    \iftagsleft@
+        \kern-\tagshift@
+        \if1\shift@tag\row@\relax
+            \rlap{\vbox{%
+                \normalbaselines
+                \boxz@
+                \vbox to\lineht@{}%
+                \raise@tag
+            }}%
+        \else
+            \rlap{\boxz@}%
+        \fi
+        \kern\displaywidth@
+    \else
+        \kern-\tagshift@
+        \if1\shift@tag\row@\relax
+%    \end{macrocode}
+%    Added depth to correct vertical spacing of shifted
+%    equation tags.---dmj, 1994/12/29
+%    \begin{macrocode}
+            \llap{\vtop{%
+                \raise@tag
+                \normalbaselines
+                \setbox\@ne\null
+                \dp\@ne\lineht@
+                \box\@ne
+                \boxz@
+            }}%
+        \else
+            \llap{\boxz@}%
+        \fi
+    \fi
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+% \begin{macro}{\align@preamble}
+%    \begin{macrocode}
+\def\align@preamble{%
+   &\hfil
+    \strut@
+    \setboxz@h{\@lign$\m@th\displaystyle{##}$}%
+    \ifmeasuring@\savefieldlength@\fi
+    \set@field
+    \tabskip\z@skip
+   &\setboxz@h{\@lign$\m@th\displaystyle{{}##}$}%
+    \ifmeasuring@\savefieldlength@\fi
+    \set@field
+    \hfil
+    \tabskip\alignsep@
+}
+%    \end{macrocode}
+%  \end{macro}
+%
+%  \begin{macro}{\set@field}
+%    \cs{set@field} increments the column counter, tracks the value of
+%    \cs{lineht@} and finally inserts the box containing the contents
+%    of the current field.
+%    \begin{macrocode}
+\def\set@field{%
+    \column@plus
+    \iftagsleft@
+        \ifdim\ht\z@>\lineht@
+            \global\lineht@\ht\z@
+        \fi
+    \else
+        \ifdim\dp\z@>\lineht@
+            \global\lineht@\dp\z@
+        \fi
+    \fi
+    \boxz@
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%
+% \subsection {The \env{split} environment}
+%
+%    \begin{macro}{\split@err}
+%    A special error function for \env{split} to conserve main mem (at a
+%    cost of string pool/hash size.
+%    \begin{macrocode}
+\edef\split@err#1{%
+    \@nx\@amsmath@err{%
+        \string\begin{split} won't work here%
+    }{%
+        \@xp\@nx\csname
+  Did you forget a preceding \string\begin{equation}?^^J%
+  If not, perhaps the `aligned' environment is what
+  you want.\endcsname}%
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+%    \begin{environment}{split}
+%    If the \env{split} environment occurs inside \env{align} or
+%    \env{gather}, it can make use of the enclosing halign; if it is
+%    called inside a simple equation, we add an implicit `gather'
+%    container.
+%
+%    \begin{macrocode}
+\newenvironment{split}{%
+  \if@display
+    \ifinner
+      \@xp\@xp\@xp\split@aligned
+    \else
+      \ifst@rred \else \global\@eqnswtrue \fi
+    \fi
+  \else \let\endsplit\@empty \@xp\collect@body\@xp\split@err
+  \fi
+  \collect@body\gather@split
+}{%
+      \crcr
+    \egroup
+  \egroup
+  \iftagsleft@ \@xp\lendsplit@ \else \@xp\rendsplit@ \fi
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\let\split@tag\relax % init
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\gather@split#1#2#3{%
+  \@xp\endgroup \reset@equation % math@cr will handle equation numbering
+  \iftag@
+     \toks@\@xp{\df@tag}%
+     \edef\split@tag{%
+       \gdef\@nx\df@tag{\the\toks@}%
+       \global\@nx\tag@true \@nx\nonumber
+     }%
+  \else \let\split@tag\@empty
+  \fi
+  \spread@equation
+%    \end{macrocode}
+%    The extra vcenter wrapper here is not really a good thing but
+%    without it there are compatibility problems with old documents that
+%    throw in some extra material between \verb'\begin{equation}' and
+%    \verb'\begin{split}' (for example, \verb'\hspace{-1pc}' or
+%    \verb'\left\{'). [mjd,1999/09/20]
+%    \begin{macrocode}
+  \vcenter\bgroup
+    \gather@{\split@tag  \begin{split}#1\end{split}}%
+    \def\endmathdisplay@a{%
+      \math@cr \black@ \totwidth@ \egroup
+      \egroup
+    }%
+}
+%    \end{macrocode}
+%
+%    \end{environment}
+%
+% \begin{macro}{\insplit@}
+%    \begin{macrocode}
+\def\insplit@{%
+  \global\setbox\z@\vbox\bgroup
+    \Let@ \chardef\dspbrk@context\@ne \restore@math@cr
+    \default@tag % disallow use of \tag here
+    \ialign\bgroup
+      \hfil
+      \strut@
+      $\m@th\displaystyle{##}$%
+     &$\m@th\displaystyle{{}##}$%
+      \hfill % Why not \hfil?---dmj, 1994/12/28
+      \crcr
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\rendsplit@}
+%    Moved the box maneuvers inside the \cs{ifinalign@}, since that is
+%    the only place they are needed.---dmj, 1994/12/28
+%
+%    TODO: Explore interaction of tag-placement algorithm with
+%    \env{split}.  Is there any way for \env{split} to pass the
+%    relevant information out to the enclosing \env{gather} or
+%    \env{align}?
+%    \begin{macrocode}
+\def\rendsplit@{%
+    \ifinalign@
+%    \end{macrocode}
+%    Changed |\box9| into a \cs{vtop} here for better spacing.
+%    \begin{macrocode}
+        \global\setbox9 \vtop{%
+            \unvcopy\z@
+            \global\setbox8 \lastbox
+            \unskip
+        }%
+        \setbox\@ne\hbox{%
+            \unhcopy8
+            \unskip
+            \global\setbox\tw@\lastbox
+            \unskip
+            \global\setbox\thr@@\lastbox
+        }%
+        \ifctagsplit@
+            \gdef\split@{%
+                \hbox to\wd\thr@@{}%
+               &\vcenter{\vbox{\moveleft\wd\thr@@\boxz@}}%
+            }%
+        \else
+            \global\setbox7 \hbox{\unhbox\tw@\unskip}%
+%    \end{macrocode}
+%    Added \cs{add@amps} to make sure we put the last line of the
+%    \env{split} into the proper column of an \env{align} environment
+%    with multiple align structures.---dmj, 1994/12/28
+%
+%    Special care has to be taken in this case because the \env{split}
+%    turns into two lines of the \env{align} instead of just one.  So,
+%    we have to make sure that the first line produced by the
+%    \env{split} doesn't upset our bookkeeping, hence we call
+%    \cs{savetaglength@} to insert 0\,pt as the tag for this
+%    pseudo-line, and we advance the \cs{row@} counter and reset
+%    \cs{lineht@} afterwards.  It would be nice if we could just
+%    replace the \cs{crcr} by \cs{math@cr@@@}, but that would cause
+%    problems with the tag processing.
+%    \begin{macrocode}
+            \gdef\split@{%
+                \global\@tempcnta\column@
+               &\setboxz@h{}%
+                \savetaglength@
+                \global\advance\row@\@ne
+                \vbox{\moveleft\wd\thr@@\box9}%
+                \crcr
+                \noalign{\global\lineht@\z@}%
+                \add@amps\@tempcnta
+                \box\thr@@
+               &\box7
+            }%
+        \fi
+    \else
+        \ifctagsplit@
+            \gdef\split@{\vcenter{\boxz@}}%
+        \else
+%    \end{macrocode}
+%    Changed to just \cs{boxz@}, otherwise last line gets centered
+%    rather than aligned properly with respect to the rest of the
+%    lines.  But this means that we can't see inside of the last line
+%    to decide whether the tag needs to be moved.  Will have to think
+%    about this.---dmj, 1994/12/28
+%    \begin{macrocode}
+            \gdef\split@{%
+                \boxz@
+%                \box9
+%                \crcr
+%                \hbox{\box\thr@@\box7}%
+            }%
+        \fi
+    \fi
+    \aftergroup\split@
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lendsplit@}
+%    \begin{macrocode}
+\def\lendsplit@{%
+    \global\setbox9\vtop{\unvcopy\z@}%
+    \ifinalign@
+%    \end{macrocode}
+%    Moved following two boxes inside the \cs{ifinalign@}, since they
+%    are only used in that case.  In fact, if we just kept track of
+%    the width of the first column, we could dispense with this
+%    entirely.  Surely that would be more efficient than all these box
+%    copies.---dmj, 1994/12/28
+%    \begin{macrocode}
+        \setbox\@ne\vbox{%
+            \unvcopy\z@
+            \global\setbox8\lastbox
+        }%
+        \setbox\@ne\hbox{%
+            \unhcopy8%
+            \unskip
+            \setbox\tw@\lastbox
+            \unskip
+            \global\setbox\thr@@\lastbox
+        }%
+        \ifctagsplit@
+            \gdef\split@{%
+                \hbox to\wd\thr@@{}%
+               &\vcenter{\vbox{\moveleft\wd\thr@@\box9}}%
+            }%
+        \else
+            \gdef\split@{%
+                \hbox to\wd\thr@@{}%
+               &\vbox{\moveleft\wd\thr@@\box9}%
+            }%
+        \fi
+    \else
+        \ifctagsplit@
+            \gdef\split@{\vcenter{\box9}}%
+        \else
+            \gdef\split@{\box9}%
+        \fi
+    \fi
+    \aftergroup\split@
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%    With \pkg{amsmath} 1.2 it was possible to put things like
+%    \verb'\left\{' between \verb'\begin{equation}' and
+%    \verb'\begin{split}' without getting any error message. For
+%    backward compatibility we try to avoid a fatal error in this case
+%    and instead attempt recovery with \env{aligned}.
+%    \begin{macrocode}
+\def\split@aligned#1#2{%
+   \iffalse{\fi\ifnum0=`}\fi
+   \collect@body\split@al@a}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\split@al@a#1#2#3{%
+  \split@warning
+  \endgroup
+%    \end{macrocode}
+%    If the \opt{fleqn} and \opt{tbtags} options are both in effect then
+%    we will need to add an optional argument on the \env{aligned}
+%    environment.
+%    \begin{macrocode}
+  \toks@{\begin{aligned}}%
+  \if@fleqn \split@al@tagcheck \fi
+%    \end{macrocode}
+%    The \cs{relax} here is to prevent \cs{@let@token} from being left
+%    equal to an ampersand if that happens to be the first thing in the body.
+%    \begin{macrocode}
+  \the\toks@\relax#1\end{aligned}%
+  \ifnum0=`{\fi\iffalse}\fi
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\split@al@tagcheck{%
+   \ifctagsplit@
+   \else
+     \iftagsleft@ \toks@\@xp{\the\toks@ [t]}%
+     \else \toks@\@xp{\the\toks@ [b]}%
+     \fi
+   \fi
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\split@warning{%
+  \PackageWarning{amsmath}{%
+Cannot use `split' here;\MessageBreak trying to recover with `aligned'}%
+}
+%    \end{macrocode}
+%
+% \subsection{The \env{multline} environment}
+%
+%    In the original \amstex/, \cn{multlinegap} is a macro with an
+%    argument that resets an internal dimension (one with an \qc{\@}
+%    character in its name). Here, to save control sequence names, we
+%    define \cn{multlinegap} to be the dimension itself and the
+%    documentation instructs users to use \cn{setlength} if they
+%    need to change it.
+% \begin{macro}{\multlinegap}
+% \begin{macro}{\multlinetaggap}
+%    Changed \cs{multlinegap} and \cs{multlinetaggap} to skip
+%    registers.  Also changed name to \cs{multlinetaggap} from
+%    \cs{multlinetaggap@}.
+%    \begin{macrocode}
+\newskip\multlinegap
+\multlinegap10pt
+\newskip\multlinetaggap
+\multlinetaggap10pt
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%    \begin{macro}{\start@multline}
+%    \begin{macrocode}
+\def\start@multline#1{%
+    \RIfM@
+        \nomath@env
+        \DN@{\@namedef{end\@currenvir}{}\@gobble}%
+    \else
+        $$%
+        #1%
+        \ifst@rred
+            \nonumber
+        \else
+            \global\@eqnswtrue
+        \fi
+        \let\next@\multline@
+    \fi
+    \collect@body\next@
+}
+%    \end{macrocode}
+%    \end{macro}
+%
+% \begin{environment}{multline}
+% \begin{environment}{multline*}
+%    \begin{macrocode}
+\newenvironment{multline}{%
+  \start@multline\st@rredfalse
+}{%
+  \iftagsleft@ \@xp\lendmultline@ \else \@xp\rendmultline@ \fi
+  \ignorespacesafterend
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\newenvironment{multline*}{\start@multline\st@rredtrue}{\endmultline}
+%    \end{macrocode}
+% \end{environment}
+% \end{environment}
+%
+% \begin{macro}{\multline@}
+%    \begin{macrocode}
+\def\multline@#1{%
+    \Let@
+%    \end{macrocode}
+%
+%    For multline neither \cs{displ@y} no \cs{displ@y@} is quite right;
+%    we want to advance the row number and (I suppose?) the
+%    display-pagebreak level, but we only want to do tag-related stuff
+%    once before the first line, not repeat it for every line. (Recall
+%    that the arg of \cs{@display@init} goes into \cs{everycr}.)
+%    \begin{macrocode}
+    \@display@init{\global\advance\row@\@ne \global\dspbrk@lvl\m@ne}%
+    \chardef\dspbrk@context\z@
+    \restore@math@cr
+%    \end{macrocode}
+%    The \env{multline} environment is somewhat unusual, in that
+%    \cs{tag} and \cs{label} are enabled only during the measuring
+%    phase and disabled during the production phase.
+%    Here we disable \cs{tag} and \cs{label}; \cs{mmeasure@} will
+%    re-enable them temporarily.
+%    \begin{macrocode}
+    \let\tag\tag@in@align
+    \global\tag@false \global\let\raise@tag\@empty
+    \mmeasure@{#1}%
+    \let\tag\gobble@tag \let\label\@gobble
+    \tabskip \if@fleqn \@mathmargin \else \z@skip \fi
+    \totwidth@\displaywidth
+    \if@fleqn
+        \advance\totwidth@-\@mathmargin
+    \fi
+    \halign\bgroup
+        \hbox to\totwidth@{%
+%    \end{macrocode}
+%    In order to get the spacing of the last line right in fleqn
+%    mode, we need to play a little game here.  Normally the
+%    stretchability of the \cs{hskip} here will be suppressed by the
+%    \cs{hfil} at the end of the template, except inside the last line,
+%    when that \cs{hfil} will be removed by the \cs{hfilneg} in
+%    \cs{lendmultline@}.
+%    \begin{macrocode}
+            \if@fleqn
+                \hskip \@centering \relax
+            \else
+                \hfil
+            \fi
+            \strut@
+            $\m@th\displaystyle{}##\endmultline@math
+            \hfil
+        }%
+        \crcr
+%    \end{macrocode}
+%    In \opt{fleqn} mode, it's the \cs{tabskip} of \cs{@mathmargin}
+%    that needs to be removed in the first line, not the \cs{hfil} at
+%    the beginning of the template.
+%    \begin{macrocode}
+        \if@fleqn
+            \hskip-\@mathmargin
+            \def\multline@indent{\hskip\@mathmargin}% put it back
+        \else
+            \hfilneg
+            \def\multline@indent{\hskip\multlinegap}%
+        \fi
+        \iftagsleft@
+            \iftag@
+                \begingroup
+                    \ifshifttag@
+                        \rlap{\vbox{%
+                                \normalbaselines
+                                \hbox{%
+                                    \strut@
+                                    \make@display@tag
+                                }%
+                                \vbox to\lineht@{}%
+                                \raise@tag
+                        }}%
+%    \end{macrocode}
+%    If the equation tag doesn't fit on the same line with the first
+%    line of the display, we'll indent the first line by
+%    \cn{multlinegap}.  This is a change from \pkg{amstex}, where the
+%    first line would have been flush against the left margin in this
+%    case.  A corresponding change will be made in \cs{rendmultline@}.
+%    \begin{macrocode}
+                        \multline@indent
+                    \else
+                        \setbox\z@\hbox{\make@display@tag}%
+                        \dimen@\@mathmargin \advance\dimen@-\wd\z@
+                        \ifdim\dimen@<\multlinetaggap
+                          \dimen@\multlinetaggap
+                        \fi
+                        \box\z@ \hskip\dimen@\relax
+                    \fi
+                \endgroup
+            \else
+                \multline@indent
+            \fi
+        \else
+            \multline@indent
+        \fi
+    #1%
+}
+%    \end{macrocode}
+%
+%    An extra level of indirection for the closing \verb'$' in multline
+%    allows us to avoid getting an extra thinmuskip from a final
+%    mathpunct in the equation contents, when equation numbers are on
+%    the right. If we did not use this workaround, the sequence of
+%    elements for a final comma would be, e.g.,
+% \begin{verbatim}
+% ... ,<hskip><box containing equation number>
+% \end{verbatim}
+%    which is equivalent to a sequence \verb'<mathpunct><mathord>' as
+%    far as the automatic math spacing is concerned.
+%    \begin{macrocode}
+\def\endmultline@math{$}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lendmultline@}
+%    Bug fix: changed \cs{crcr} to \cs{math@cr} so that \cs{@eqpen}
+%    gets reset properly if \cs{displaybreak} is used on the
+%    penultimate line of an \env{align}.
+%    \begin{macrocode}
+\def\lendmultline@{%
+        \hfilneg
+        \hskip\multlinegap
+        \math@cr
+    \egroup
+    $$%
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\rendmultline@}
+%    \begin{macrocode}
+\def\rendmultline@{%
+    \iftag@
+        $\let\endmultline@math\relax
+            \ifshifttag@
+                \hskip\multlinegap
+%    \end{macrocode}
+%    Added depth to correct vertical spacing of shifted equation
+%    tags.---dmj, 1994/12/29
+%    \begin{macrocode}
+                \llap{\vtop{%
+                    \raise@tag
+                    \normalbaselines
+                    \setbox\@ne\null
+                    \dp\@ne\lineht@
+                    \box\@ne
+                    \hbox{\strut@\make@display@tag}%
+                }}%
+            \else
+                \hskip\multlinetaggap
+                \make@display@tag
+            \fi
+    \else
+        \hskip\multlinegap
+    \fi
+    \hfilneg
+%    \end{macrocode}
+%    Use \cs{math@cr} rather than just \cs{crcr} so that \cs{@eqpen}
+%    gets reset properly if \cs{displaybreak} is used.
+%    \begin{macrocode}
+        \math@cr
+    \egroup$$%
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\mmeasure@}
+%    \begin{macrocode}
+\def\mmeasure@#1{%
+    \begingroup
+        \measuring@true
+%    \end{macrocode}
+%    We use \cs{begin/endgroup} rather than |{}| in this definition of
+%    \cn{label} because the latter would create an extra (wasteful of
+%    main mem) null box in the current math list. [mjd, 1995/01/17]
+%    \begin{macrocode}
+        \def\label##1{%
+          \begingroup\measuring@false\label@in@display{##1}\endgroup}%
+        \def\math@cr@@@{\cr}%
+        \let\shoveleft\@iden \let\shoveright\@iden
+        \savecounters@
+        \global\row@\z@
+        \setbox\@ne\vbox{%
+            \global\let\df@tag\@empty
+            \halign{%
+                \setboxz@h{\@lign$\m@th\displaystyle{}##$}%
+                \iftagsleft@
+                    \ifnum\row@=\@ne
+                        \global\totwidth@\wdz@
+                        \global\lineht@\ht\z@
+                    \fi
+                \else
+                    \global\totwidth@\wdz@
+                    \global\lineht@\dp\z@
+                \fi
+                \crcr
+                #1%
+                \crcr
+            }%
+        }%
+        \ifx\df@tag\@empty\else\global\tag@true\fi
+        \if@eqnsw\global\tag@true\fi
+        \iftag@
+            \setboxz@h{%
+                \if@eqnsw
+                    \stepcounter{equation}%
+                    \tagform@\theequation
+                \else
+                    \df@tag
+                \fi
+            }%
+            \global\tagwidth@\wdz@
+            \dimen@\totwidth@
+            \advance\dimen@\tagwidth@
+            \advance\dimen@\multlinetaggap
+            \iftagsleft@\else
+                \if@fleqn
+                    \advance\dimen@\@mathmargin
+                \fi
+            \fi
+            \ifdim\dimen@>\displaywidth
+                \global\shifttag@true
+            \else
+                \global\shifttag@false
+            \fi
+        \fi
+        \restorecounters@
+    \endgroup
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macro}{\shoveleft}
+%    \begin{macro}{\shoveright}
+%    \cs{shoveleft} and \cs{shoveright} need to do slightly different
+%    things depending on whether tags are on the left or the right and
+%    whether we're in \opt{fleqn} mode.  For compactness of code, we
+%    make the appropriate decisions at ``compile'' time rather than at
+%    load time.
+%
+%    TODO: Investigate making \cs{shoveright} behave ``properly''(?) if
+%    used on the first line of a \env{multline} and make \cs{shoveleft}
+%    behave properly if used on the last line of a \env{multline}. But
+%    in his \fn{amstex.doc} Spivak indicates those commands should never
+%    be used on a first or last line. Perhaps better to leave the
+%    question open unless/until real-life examples turn up.
+%    \begin{macrocode}
+\iftagsleft@
+    \def\shoveright#1{%
+        #1%
+        \hfilneg
+        \hskip\multlinegap
+    }
+\else
+    \def\shoveright#1{%
+        #1%
+        \hfilneg
+        \iftag@
+            \ifshifttag@
+                \hskip\multlinegap
+            \else
+                \hskip\tagwidth@
+                \hskip\multlinetaggap
+            \fi
+        \else
+            \hskip\multlinegap
+        \fi
+    }
+\fi
+
+\if@fleqn
+    \def\shoveleft#1{#1}%
+\else
+    \iftagsleft@
+        \def\shoveleft#1{%
+            \setboxz@h{$\m@th\displaystyle{}#1$}%
+            \setbox\@ne\hbox{$\m@th\displaystyle#1$}%
+            \hfilneg
+            \iftag@
+                \ifshifttag@
+                    \hskip\multlinegap
+                \else
+                    \hskip\tagwidth@
+                    \hskip\multlinetaggap
+                \fi
+            \else
+                \hskip\multlinegap
+            \fi
+            \hskip.5\wd\@ne
+            \hskip-.5\wdz@
+            #1%
+        }
+    \else
+        \def\shoveleft#1{%
+            \setboxz@h{$\m@th\displaystyle{}#1$}%
+            \setbox\@ne\hbox{$\m@th\displaystyle#1$}%
+            \hfilneg
+            \hskip\multlinegap
+            \hskip.5\wd\@ne
+            \hskip-.5\wdz@
+            #1%
+        }
+    \fi
+\fi
+%    \end{macrocode}
+%    \end{macro}
+%    \end{macro}
+%
+%    \subsection{The \env{equation} environment}
+%
+%    Rewritten from the ground up for version 2.0 to fix no-shrink and
+%    no-shortskips bugs [mjd,2000/01/06].
+%
+%    Standard \latex/ provides three environments for one-line equations:
+%    \cn{[}\cn{]}, \env{equation}, and \env{displaymath}. We add
+%    \env{equation*} as a synonym for \env{displaymath}.
+%    \begin{macrocode}
+\@saveprimitive\leqno\@@leqno
+\@saveprimitive\eqno\@@eqno
+\def\eqno{\@@eqno\let\eqno\relax\let\leqno\relax}
+\def\leqno{\@@leqno\let\leqno\relax\let\eqno\relax}
+%
+\let\veqno=\@@eqno
+\iftagsleft@ \let\veqno=\@@leqno \fi
+%    \end{macrocode}
+%
+%    Support for the \pkg{showkeys} package: provide no-op definitions
+%    for a couple of SK functions, if they are not already defined. Then
+%    we can just call them directly in our code without any extra fuss.
+%    If the \pkg{showkeys} package is loaded later, our trivial
+%    definitions will get overridden and everything works fine.
+%    \begin{macrocode}
+\@ifundefined{SK@@label}{%
+  \let\SK@@label\relax \let\SK@equationtrue\relax
+}{}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\let\reset@equation\@empty
+%    \end{macrocode}
+%
+%    Cf \cs{tag@in@align}. This is a bit of a mess though. Could use
+%    some work. [mjd,1999/12/21]
+%    \begin{macrocode}
+\let\alt@tag\@empty
+\def\tag@in@display#1#{\relax\tag@in@display@a{#1}}
+\def\tag@in@display@a#1#2{%
+  \iftag@
+    \invalid@tag{Multiple \string\tag}\relax
+  \else
+    \global\tag@true \nonumber \reset@equation \st@rredtrue
+    \if *\string#1%
+      \gdef\alt@tag{\def\SK@tagform@{#2\@gobble}%
+        \ifx\SK@@label\relax \let\tagform@\SK@tagform@ \fi
+      }%
+      \make@df@tag@@{#2}%
+    \else
+      \make@df@tag@@@{#2}%
+    \fi
+  \fi
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\let\restore@hfuzz\@empty
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\mathdisplay#1{%
+  \ifmmode \@badmath
+  \else
+    $$\def\@currenvir{#1}%
+%    \end{macrocode}
+%    Allow use of \cn{displaybreak}.
+%    \begin{macrocode}
+    \let\dspbrk@context\z@
+%    \end{macrocode}
+%    Although in some cases simpler label handling would seem to be
+%    sufficient, always using \cs{label@in@display} makes it easier to
+%    support the \pkg{showkeys} package.
+%    \begin{macrocode}
+    \let\tag\tag@in@display \let\label\label@in@display \SK@equationtrue
+    \global\let\df@label\@empty \global\let\df@tag\@empty
+    \global\tag@false
+    \let\mathdisplay@push\mathdisplay@@push
+    \let\mathdisplay@pop\mathdisplay@@pop
+    \if@fleqn
+%    \end{macrocode}
+%    Turn off overfull box messages temporarily\mdash otherwise there
+%    would be unwanted extra ones emitted during our measuring
+%    operations.
+%    \begin{macrocode}
+      \edef\restore@hfuzz{\hfuzz\the\hfuzz\relax}%
+      \hfuzz\maxdimen
+%    \end{macrocode}
+%    Initially set the equation body in a box of displaywidth. Then if
+%    the box is not overfull, as we find by checking \cs{badness}, we
+%    have acquired useful information for the subsequent processing.
+%    \begin{macrocode}
+      \setbox\z@\hbox to\displaywidth\bgroup
+        \let\split@warning\relax \restore@hfuzz
+        \everymath\@emptytoks \m@th $\displaystyle
+    \fi
+  \fi
+}
+%    \end{macrocode}
+%
+%    Arg 1 is not currently used. I thought it might come in handy for
+%    error messages.
+%    \begin{macrocode}
+\def\endmathdisplay#1{%
+  \ifmmode \else \@badmath \fi
+  \endmathdisplay@a
+  $$%
+%    \end{macrocode}
+%    I guess the following code means this structure is non-reentrant.
+%    But there is plenty of scope for tricky bugs here; suppressing them
+%    by brute force at least makes it possible to get things working
+%    correctly for normal use. [mjd,2000/01/06]
+%    \begin{macrocode}
+  \global\let\df@label\@empty \global\let\df@tag\@empty
+  \global\tag@false \global\let\alt@tag\@empty
+  \global\@eqnswfalse
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\endmathdisplay@a{%
+  \if@eqnsw \gdef\df@tag{\tagform@\theequation}\fi
+  \if@fleqn \@xp\endmathdisplay@fleqn
+  \else \ifx\df@tag\@empty \else \veqno \alt@tag \df@tag \fi
+    \ifx\df@label\@empty \else \@xp\ltx@label\@xp{\df@label}\fi
+  \fi
+  \ifnum\dspbrk@lvl>\m@ne
+    \postdisplaypenalty -\@getpen\dspbrk@lvl
+    \global\dspbrk@lvl\m@ne
+  \fi
+}
+%    \end{macrocode}
+%
+%    A boolean variable: Was that last box overfull or not? A value of 0
+%    means yes, it was overfull.
+%    \begin{macrocode}
+\let\too@wide\@ne
+%    \end{macrocode}
+%
+%    Special handling is needed for flush-left equations. We need to
+%    measure the equation body (found in box 0 after we close it with
+%    the \cs{egroup}). Then after a fairly normal test to see if it fits
+%    within the available space, we need to consider overlapping into
+%    the displayindent area if displayindent is nonzero (as in an
+%    indented list). If there is an equation number we may have to shift
+%    it by hand to a separate line when there is not enough room;
+%    we can no longer take advantage of the automatic shifting provided
+%    by the \cn{leqno}, \cn{eqno} primitives.
+%
+%    We initially add \cs{@mathmargin} glue at the end of box 0 to get
+%    an accurate overfull test. If \cs{@mathmargin} contains any shrink
+%    then we cannot reliably tell whether the box will be overfull or
+%    not simply by doing hand calculations from the actual width of the
+%    equation body. We have to actually set the box and find out what
+%    happens.
+%
+%    On the other hand if we put the \cs{@mathmargin} glue at the
+%    beginning of the box it's awkward to remove it afterwards. So we
+%    first put it in at the end and later we will move it to the
+%    beginning as needed.
+%
+%    \begin{macrocode}
+\def\endmathdisplay@fleqn{%
+  $\hfil\hskip\@mathmargin\egroup
+%    \end{macrocode}
+%    We need to save the information about whether box 0 was overfull in
+%    a variable, otherwise it will disappear in the next setbox
+%    operation. And we couldn't set the equation number box earlier than
+%    now, because the body of the equation might have contained a
+%    \cs{tag} command (well, it could have been done, but this way
+%    we can reuse the tag-handling code from elsewhere).
+%    \begin{macrocode}
+  \ifnum\badness<\inf@bad \let\too@wide\@ne \else \let\too@wide\z@ \fi
+  \ifx\@empty\df@tag
+  \else
+    \setbox4\hbox{\df@tag
+      \ifx\df@label\@empty \else \@xp\ltx@label\@xp{\df@label}\fi
+    }%
+  \fi
+  \csname emdf@%
+    \ifx\df@tag\@empty U\else \iftagsleft@ L\else R\fi\fi
+  \endcsname
+}
+%    \end{macrocode}
+%
+%    For an unnumbered flush-left equation we hope first that the
+%    the contents fit within displaywidth. If not we need to fall back
+%    on a more complicated reboxing operation.
+%    \begin{macrocode}
+\def\emdf@U{%
+  \restore@hfuzz
+  \ifodd\too@wide % not too wide: just need to swap the glue around
+    \hbox to\displaywidth{\hskip\@mathmargin\unhbox\z@\unskip}%
+  \else % M+B > displaywidth
+    \emdf@Ua
+  \fi
+}
+%    \end{macrocode}
+%
+%    Some notation: $M$ \cs{@mathmargin}, $B$ the width of the equation
+%    body, $I$ \cs{displayindent}, $D$ \cs{displaywidth}, $N$ the width
+%    of the equation number (aka the tag), $S$ \cs{mintagsep}, $C$
+%    \cs{columnwidth}. If $M+B > \mbox{displaywidth}$, and if we assume
+%    $M$ contains shrink, then the only solution left is to encroach
+%    into the displayindent space.
+%    \begin{macrocode}
+\def\emdf@Ua{%
+  \hbox to\columnwidth{%
+    \ifdim\displayindent>\z@
+      \hskip\displayindent minus\displayindent
+    \fi
+    \hskip\@mathmargin \unhbox\z@ \unskip
+  }%
+  \displayindent\z@ \displaywidth\columnwidth
+}
+%    \end{macrocode}
+%
+%    Find out first if the tag fits in ideal position. If so we can just
+%    plunk down box 2. Otherwise we need to do something more complicated.
+%    \begin{macrocode}
+\def\emdf@R{%
+  \setbox\tw@\hbox to\displaywidth{%
+    \hskip\@mathmargin \unhcopy\z@\unskip\hfil\hskip\mintagsep\copy4
+  }%
+  \restore@hfuzz
+  \ifnum\badness<\inf@bad \box\tw@ \else \emdf@Ra \fi
+}
+%    \end{macrocode}
+%
+%    We shift the equation number to line 2 if it does not fit within
+%    \cs{displaywidth}. Note that we do not first attempt to let the
+%    equation body shift leftward into the \cs{displayindent} space. If
+%    that is desired it will have to be done by hand by adding negative
+%    space at the beginning of the equation body. I don't expect this to
+%    arise very often in practice since most of the time
+%    \cs{displayindent} is zero anyway.
+%    \begin{macrocode}
+\def\emdf@Ra{%
+  \skip@\displayindent minus\displayindent
+  \displayindent\z@ \displaywidth\columnwidth
+  \spread@equation \everycr{}\tabskip\z@skip
+  \halign{\hbox to\displaywidth{##}\cr
+    \relax
+    \ifdim\skip@>\z@ \hskip\skip@ \fi
+    \hskip\@mathmargin\unhbox\z@\unskip\hfil\cr
+    \noalign{\raise@tag}%
+    \hfil\box4 \cr}%
+}
+%    \end{macrocode}
+%
+%    Find out first if the tag fits in ideal position. If so we can just
+%    plunk down box 2. Otherwise we need to do something more
+%    complicated.
+%    \begin{macrocode}
+\def\emdf@L{%
+%    \end{macrocode}
+%    Calculate the difference between $M$ and $N+S$. If the latter is
+%    greater, we don't want to add any extra glue between the number and
+%    the equation body. Otherwise the amount that we want to add is
+%    \verb'x minus x' where $x=M-(N+S)$. I.e., the distribution of
+%    spaces across the line is $N,S,x minus x,B,hfil$.
+%    \begin{macrocode}
+  \@tempdima\@mathmargin
+  \advance\@tempdima-\wd4 \advance\@tempdima-\mintagsep
+  \skip@\@tempdima minus\@tempdima
+  \setbox\tw@\hbox to\displaywidth{%
+    \copy4\hskip\mintagsep
+    \ifdim\skip@>\z@ \hskip\skip@\fi
+    \unhcopy\z@\unskip
+  }%
+  \restore@hfuzz
+  \ifnum\badness<\inf@bad \box\tw@ \else \emdf@La \fi
+}
+%    \end{macrocode}
+%
+%    If the equation body and equation number will not fit on the same
+%    line, we put the number on line 1 and the body on line 2, with the
+%    body positioned as for an unnumbered equation.
+%    \begin{macrocode}
+\def\emdf@La{%
+  \spread@equation \everycr{}\tabskip\z@skip
+  \halign{\hbox to\displaywidth{##}\cr
+    \box4 \hfil \cr
+    \noalign{\raise@tag}%
+    \hskip\@mathmargin\unhbox\z@\unskip\hfil\cr}%
+}
+%    \end{macrocode}
+%
+%    If someone has \verb'\[ \]' nested inside a minipage environment
+%    nested inside a numbered equation, the mathdisplay variables that
+%    are global will get out of whack unless we take extra care. So we
+%    make a stack and push all the variables before entering mathdisplay
+%    and pop them afterwards. But we can save a little work by not doing
+%    this at the top level, only at inner levels.
+%    \begin{macrocode}
+\newtoks\mathdisplay@stack
+\let\mathdisplay@push\@empty
+\def\mathdisplay@@push{%
+  \begingroup
+  \toks@\@xp{\df@label}\@temptokena\@xp{\df@tag}%
+  \toks8\@xp{\alt@tag}%
+  \edef\@tempa{%
+    \global\if@eqnsw\@nx\@eqnswtrue\else\@nx\@eqnswfalse\fi
+    \global\iftag@\@nx\tag@false\else\@nx\tag@true\fi
+    \gdef\@nx\df@label{\the\toks@}\gdef\@nx\df@tag{\the\@temptokena}%
+    \gdef\@nx\alt@tag{\the\toks8}%
+    \global\mathdisplay@stack{\the\mathdisplay@stack}%
+  }%
+  \global\mathdisplay@stack\@xp{\@tempa}
+  \endgroup
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\let\mathdisplay@pop\@empty
+\def\mathdisplay@@pop{\the\mathdisplay@stack}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\renewenvironment{equation}{%
+  \incr@eqnum
+  \mathdisplay@push
+  \st@rredfalse \global\@eqnswtrue
+  \mathdisplay{equation}%
+}{%
+  \endmathdisplay{equation}%
+  \mathdisplay@pop
+  \ignorespacesafterend
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\newenvironment{equation*}{%
+  \mathdisplay@push
+  \st@rredtrue \global\@eqnswfalse
+  \mathdisplay{equation*}%
+}{%
+  \endmathdisplay{equation*}%
+  \mathdisplay@pop
+  \ignorespacesafterend
+}
+%    \end{macrocode}
+%
+%    Note: \latex/ defines the \env{displaymath} environment in
+%    terms of \cn{[} and \cn{]}.
+%    \begin{macrocode}
+\DeclareRobustCommand{\[}{\begin{equation*}}
+\DeclareRobustCommand{\]}{\end{equation*}}
+%    \end{macrocode}
+%
+%    The usual \cs{endinput} to ensure that random garbage at the end of
+%    the file doesn't get copied by \fn{docstrip}.
+%    \begin{macrocode}
+\endinput
+%    \end{macrocode}
+%
+% \section{Credits}
+%
+%    Much of the code for the \pkg{amsmath} package had its orgin in
+%    \fn{amstex.tex}, written by Michael Spivak. The initial work of
+%    porting \fn{amstex.tex} to \fn{amstex.sty} was done in 1988--1989
+%    by Frank Mittelbach and Rainer Sch\"opf. In 1994 David M. Jones
+%    added the support for the \opt{fleqn} option and did extensive
+%    improvements to the \env{align[at]} family of environments and to
+%    the equation number handling in general. Michael Downes at the AMS
+%    served as coordinator for the efforts of Mittelbach, Sch\"opf, and
+%    Jones, and has contributed various bug fixes and additional
+%    refinements over time.
+%
+%    Versions 1.0 and 1.1 of the package carried the name \pkg{amstex}
+%    instead of \pkg{amsmath}, to indicate its origins; the name was
+%    changed in 1994 to make it user-oriented rather than
+%    history-oriented.
+%
+\endinput
-- 
cgit v1.2.3

