% % \iffalse meta-comment % % Copyright (C) 1995, 2000, 2013 American Mathematical Society. % Copyright (C) 2016-2023 LaTeX 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 LaTeX 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} % %\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}. % % \MaybeStop{} % % 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}[2023/05/13 v2.17o 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 0, 7 or 10, and in the past the package % \pkg{amsfonts} did set the flag to 1 or 0. These days it always % sets it to 10. The situation is a bit unsettled but we don't own % \pkg{amsfonts}. % \changes{v2.17d}{2019/12/01}{docu update, no code change (gh/200)} % \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)} % % We start by undefining a number of commands (which in a current % \LaTeX{} kernel will be defined, so that the % \cs{DeclareRobustCommand} declarations below do not add a % ``Command redefined'' info into the log. % \begin{macrocode} \let\tmspace\@undefined \let\,\@undefined \let\!\@undefined \let\:\@undefined \let\negmedspace\@undefined \let\negthickspace\@undefined % \end{macrocode} % % % \changes{v2.17g}{2020/03/07}{Math/text spacing commands are now in % the \LaTeX{} kernel and are made robust (gh/303)} % \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 \DeclareRobustCommand\,{\tmspace+\thinmuskip{.1667em}} \let\thinspace\, \DeclareRobustCommand\!{\tmspace-\thinmuskip{.1667em}} \let\negthinspace\! \DeclareRobustCommand\:{\tmspace+\medmuskip{.2222em}} \let\medspace\: \DeclareRobustCommand\negmedspace{\tmspace-\medmuskip{.2222em}} \renewcommand\;{\tmspace+\thickmuskip{.2777em}} \let\thickspace\; \DeclareRobustCommand\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 % \end{macrocode} % Use \cs{protected} on the new delimiters. % \changes{v2.17e}{2020/01/20}{Make delimiters robust (gh/251))} % \begin{macrocode} \protected\xdef\lvert{\delimiter\number\@tempcnta\space } \advance\@tempcnta "1000000 \protected\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 \protected\xdef\lVert{\delimiter\number\@tempcnta\space } \advance\@tempcnta "1000000 \protected\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). % \changes{v2.17i}{2020/09/23}{added \cs{Ustack} for luatex (moved patch from lualatex-math)} % \changes{v2.17n}{2022/04/08}{Make fraction commands robust (gh/123)} % \begin{macrocode} % \ifx\directlua\@undefined \DeclareRobustCommand{\frac}[2]{{\begingroup#1\endgroup\@@over#2}} \else \DeclareRobustCommand{\frac}[2]{{\Ustack{\begingroup#1\endgroup\@@over#2}}} \fi \DeclareRobustCommand{\dfrac}{\genfrac{}{}{}0} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make binom commands robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\binom}{\genfrac()\z@{}} \DeclareRobustCommand{\dbinom}{\genfrac(){0pt}0} \DeclareRobustCommand{\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} % \changes{v2.17i}{2020/09/23}{added \cs{Ustack} (moved patch from lualatex-math)} % \begin{macrocode} \DeclareRobustCommand{\genfrac}[6]{{% \@mathstyle{#4}% \genfrac@choice o{#1}% {\Ustack {\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. % \changes{v2.17n}{2022/04/08}{Make \cs{boxed} command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make \cs{colon} command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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\MultiIntegral{2}} \ams@newcommand{\iiint}{\DOTSI\MultiIntegral{3}} \ams@newcommand{\iiiint}{\DOTSI\MultiIntegral{4}} \newcommand{\idotsint}{\DOTSI\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. % \changes{v2.17n}{2022/04/08}{Make \cs{MultiIntegral} command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make biggg commands robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\big}{\bBigg@\@ne} \DeclareRobustCommand{\Big}{\bBigg@{1.5}} \DeclareRobustCommand{\bigg}{\bBigg@\tw@} \DeclareRobustCommand{\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. % \changes{v2.17f}{2020/02/20}{Add a kern so that a single char is not % vertically shifted and move the dots slightly to the right (gh/126)} % \begin{macrocode} \ams@newcommand{\dddot}[1]{% {\mathop{\kern\z@#1}\limits^{\vbox to-1.4\ex@{\kern-\tw@\ex@ \hbox{\,\normalfont...}\vss}}}} \ams@newcommand{\ddddot}[1]{% {\mathop{\kern\z@#1}\limits^{\vbox to-1.4\ex@{\kern-\tw@\ex@ \hbox{\,\normalfont....}\vss}}}} % \end{macrocode} % % We make the commands robust only at the end of the preamble as % \pkg{amsmath} interacts with \pkg{stix} (which should also move % to robust commands). % \changes{v2.17n}{2022/04/08}{Make dddot commands robust (gh/123)} % \begin{macrocode} \AtBeginDocument{% \MakeRobust\dddot \MakeRobust\ddddot } % \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}. % \changes{v2.17d}{2019/11/16}{Added \cs{MakeRobust} to match kernel % change (gh/216)} % \begin{macrocode} \def\set@mathaccent#1#2#3#4{% % \end{macrocode} % Now that the redefinitions done inside amsmath of the basic accents % are all robust we can drop the \cs{protect} here. % \begin{macrocode} \xdef#2{% % \@nx\protect \@nx\mathaccentV {\@xp\@gobble\string#2}\hexnumber@#1#4}% \MakeRobust#2% } % \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{% % \end{macrocode} % Drop the inner part of the robust accent so that it can be recreated % without a warning. % \changes{v2.17d}{2019/11/16}{Make temporarily fragile to match kernel % change (gh/216)} % \begin{macrocode} \@xp\let\csname\@xp\@gobble\string#7\space\endcsname\@undefined \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] % Now they are % \changes{v2.17n}{2022/04/08}{Make mod commands robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin {\operator@font mod}\penalty900 \mkern5mu\nonscript\mskip-\medmuskip} \DeclareRobustCommand{\pod}[1]{\allowbreak \if@display\mkern18mu\else\mkern8mu\fi(#1)} \DeclareRobustCommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make \cs{cfrac} command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make \cs{overset}, \cs{underset} and % \cs{overunderset} commands robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\overset}[2]{\binrel@{#2}% \binrel@@{\mathop{\kern\z@#2}\limits^{#1}}} % \end{macrocode} % % \begin{macrocode} \DeclareRobustCommand{\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}{2019/04/01}{New command \cs{overunderset}} % \begin{macrocode} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make \cs{sideset} command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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)} % \changes{v2.17n}{2022/04/08}{Make \cs{smash} command robust (gh/123)} % \begin{macrocode} \ifx\leavevmode@ifvmode\@undefined \DeclareRobustCommand{\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 \DeclareRobustCommand{\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. % \changes{v2.17h}{2020/08/24}{detect unicode engines and use their commands} % \begin{macrocode} \@ifundefined{Umathcode} {% \mathchardef\std@minus\mathcode`\-\relax \mathchardef\std@equal\mathcode`\=\relax } {% \Umathcharnumdef\std@minus\Umathcodenum`\-\relax \Umathcharnumdef\std@equal\Umathcodenum`\=\relax } % \end{macrocode} % In case some alternative math fonts are loaded later: % \begin{macrocode} \@ifundefined{Umathcode} {% \AtBeginDocument{% \mathchardef\std@minus\mathcode`\-\relax \mathchardef\std@equal\mathcode`\=\relax }% } {% \AtBeginDocument{% \Umathcharnumdef\std@minus\Umathcodenum`\-\relax \Umathcharnumdef\std@equal\Umathcodenum`\=\relax }% } % \end{macrocode} % % \begin{macro}{\relbar} % \begin{macro}{\Relbar} % \changes{v2.17n}{2022/04/08}{Make commands robust (gh/123)} % \begin{macrocode} \ams@DeclareRobustCommand\relbar{\mathrel{\mathpalette\mathsm@sh\std@minus}} \ams@DeclareRobustCommand\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} % Again we delay making commands robut for \pkg{stix}. % \changes{v2.17n}{2022/04/08}{Make commands robust (gh/123)} % \begin{macrocode} \AtBeginDocument{% \expandafter\let\csname overleftarrow \endcsname\@undefined \expandafter\let\csname overrightarrow \endcsname\@undefined \MakeRobust\overrightarrow \MakeRobust\overleftarrow \MakeRobust\overleftrightarrow } % \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} % % % \changes{v2.17n}{2022/04/08}{Make commands robust (gh/123)} % \begin{macrocode} \AtBeginDocument{% \MakeRobust\underrightarrow \MakeRobust\underleftarrow \MakeRobust\underleftrightarrow } % \end{macrocode} % % \changes{v2.17n}{2022/04/08}{Make commands robust (gh/123)} % \begin{macrocode} %\DeclareRobustCommand{\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} \DeclareRobustCommand{\xrightarrow}[2][]{\ext@arrow 0359\rightarrowfill@{#1}{#2}} \DeclareRobustCommand{\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. % \changes{v2.17i}{2020/09/23}{moved to version from lualatex-math for luatex} % \begin{macrocode} \ifx\directlua\@undefined \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 } \else \newenvironment{subarray}[1]{% \vcenter\bgroup \Let@ \restore@math@cr \default@tag \baselineskip \Umathstacknumup \scriptstyle \advance\baselineskip \Umathstackdenomdown \scriptstyle \lineskip \Umathstackvgap \scriptstyle \lineskiplimit \lineskip \ialign\bgroup\ifx c#1\hfil\fi \Ustartmath \m@th\scriptstyle## \Ustopmath \hfil\crcr }{% \crcr\egroup\egroup } \fi % \end{macrocode} % \end{environment} % % \begin{macro}{\substack} % The \cn{substack} command is just an abbreviation for the % most common use of \env{subarray}. % \changes{v2.17n}{2022/04/08}{Make command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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. The \LaTeX{} kernel contains a similar command % \cs{counterwithin} (with a slightly extended syntax) that can be used % as a drop-in replacement for \cs{numberwithin}. % \changes{v2.17n}{2022/04/08}{Make command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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}. % \changes{v2.17n}{2022/04/08}{Make command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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. % \changes{v2.17n}{2022/04/08}{Make command robust (gh/123)} % \begin{macrocode} \DeclareRobustCommand{\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). % \changes{v2.17j}{2021/04/20}{Use \cs{protected} for \cs{\bslash} variant (gh/548)} % \begin{macrocode} \protected\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{% % \end{macrocode} % We set \cs{@currentcounter} here so that it applies to both branches. %\changes{v2.17l}{2021/10/15}{Explicitly set \cs{@currentcounter} (gh/687)} % \begin{macrocode} \def\@currentcounter{equation}% \@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. % One exception is the \env{xxalignat} environment where this is set % to true. % \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}{\ams@start@box} % This macro tests the optional positioning argument (in % \texttt{gathered} or \texttt{aligned}. It explicitly tests for the % value \texttt{b}, \texttt{c} and \texttt{t} and if the value is % different, then we assume that it is a bracket group that belongs % to the formula instead of being an misspelled optional argument. % (In earlier versions of the code anything other than \texttt{b} % or \texttt{t} was interpreted as \texttt{c} and the data was % otherwise dropped.) % \changes{v2.17g}{2020/03/10}{Explicity test for b/t/c and return % optional argument is different (gh/5)} % \begin{macrocode} \def\ams@start@box#1{% % \end{macrocode} % As we may pick up an arbitrary part of the formula by mistake, we % need to be very careful with the testing to avoid low-level % errors. This is why we use \cs{detokenize}. But we also need to % expand the argument (if possible) in case the position value is % hidden inside a macro. We therefore apply the \cs{romannumeral} % trick (known as f-expansion in \texttt{expl3}) in its old form. % The code assumes that % the default is correctly set up (which in this case is \texttt{c}). % \begin{macrocode} \edef\reserved@a{\csname ams@pos@\expandafter\detokenize \expandafter{\romannumeral-`\0#1}\endcsname}% \expandafter\ifx\reserved@a\relax % \end{macrocode} % If the argument is neither \texttt{b}, \texttt{c} or \texttt{t} % we save it in \cs{ams@return@opt@arg}, so it can later be % returned as part of the environment body. We could at this point % also issue a warning that bracket group was found at the start of % the formula and that it is safer to add a \cs{relax} before it. % \begin{macrocode} \PackageWarning{amsmath}{% Bracket group \detokenize{[#1]} at formula start!\MessageBreak It could be a misspelled positional argument.\MessageBreak If it belongs to the formula add a \relax in\MessageBreak front to hide it}% \def\ams@return@opt@arg{[#1]}\vcenter % \end{macrocode} % If the argument was identified then we clear % \cs{ams@return@opt@arg} (just in case somebod ever nests these % environment. % \begin{macrocode} \else \let\ams@return@opt@arg\@empty\reserved@a \fi } % \end{macrocode} % % \begin{macro}{\ams@pos@t} % \begin{macro}{\ams@pos@b} % \begin{macro}{\ams@pos@c} % % \begin{macrocode} \def\ams@pos@t{\vtop} \def\ams@pos@b{\vbox} \def\ams@pos@c{\vcenter} % \end{macrocode} % And we accept an empty argument as a way to get the default (as % that was the case before as well, albeit by mistake in some sense). % \begin{macrocode} \let\ams@pos@\ams@pos@c % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \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 % \end{macrocode} % Select the right kind of box based on the optional argument \verb=#1=. % \begin{macrocode} \ams@start@box{#1}\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} % If we picked up a bracket group by mistake here is the place to % return it for processing. % \changes{v2.17g}{2020/03/10}{Explicity test for b/t/c and return % optional argument is different (gh/5)} % \begin{macrocode} \ams@return@opt@arg } % \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 % \end{macrocode} % Select the right kind of box based on the optional argument \verb=#1=. % \begin{macrocode} \ams@start@box{#1}\bgroup \Let@ \chardef\dspbrk@context\@ne \restore@math@cr \spread@equation \ialign\bgroup \hfil\strut@$\m@th\displaystyle##$\hfil \crcr % \end{macrocode} % And put a mistaking picked up bracket group back: % \changes{v2.17g}{2020/03/10}{Explicity test for b/t/c and return % optional argument is different (gh/5)} % \begin{macrocode} \ams@return@opt@arg }{% \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 \, so it can be used as the right-hand % side of a \ or \ statement. % It's argument can be any \, \ 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} % ... , % \end{verbatim} % which is equivalent to a sequence \verb'' 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. % \changes{v2.17m}{2022/02/03}{Make \cs{shoveright} robust (if def is not trival)} % \begin{macrocode} \iftagsleft@ \protected\def\shoveright#1{% #1% \hfilneg \hskip\multlinegap } \else \protected\def\shoveright#1{% #1% \hfilneg \iftag@ \ifshifttag@ \hskip\multlinegap \else \hskip\tagwidth@ \hskip\multlinetaggap \fi \else \hskip\multlinegap \fi } \fi % \end{macrocode} % \changes{v2.17m}{2022/02/03}{Make \cs{shoveleft} robust (if def is not trival)} % \begin{macrocode} \if@fleqn \def\shoveleft#1{#1}% \else \iftagsleft@ \protected\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 % \end{macrocode} % \changes{v2.17m}{2022/02/03}{Added missing \cs{relax} for (gh/716)} % \begin{macrocode} \hskip-.5\wdz@ \relax #1% } \else \protected\def\shoveleft#1{% \setboxz@h{$\m@th\displaystyle{}#1$}% \setbox\@ne\hbox{$\m@th\displaystyle#1$}% \hfilneg \hskip\multlinegap \hskip.5\wd\@ne % \end{macrocode} % \changes{v2.17m}{2022/02/03}{Added missing \cs{relax} for (gh/716)} % \begin{macrocode} \hskip-.5\wdz@ \relax #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}. % \changes{v2.17o}{2023/05/13}{Do not error if \cs{eqno} not primitive (gh/1059)} % \begin{macrocode} \let\@@eqno\eqno \let\@@leqno\leqno \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} %\changes{v2.17k}{2021/08/24}{Move the counter inside the equation and guard % with a mathopen for better compability with hyperref, issue gh/652} % As with hyperref incrementing the counter creates a box to raise the anchor % it should be in a place where is doesn't affect spacing. % Currently the code from hyperref is used to avoid this problem: % If fleqn isn't active the counter is set inside the equation and the potential % box guarded by a mathopen to avoid side effects on following unary symbols. % If fleqn is activated it has to be outside to avoid problems with labels. % This solution is temporary and not necessarly the best. % \begin{macrocode} \if@fleqn \renewenvironment{equation}{% \incr@eqnum \mathdisplay@push \st@rredfalse \global\@eqnswtrue \mathdisplay{equation}% }{% \endmathdisplay{equation}% \mathdisplay@pop \ignorespacesafterend } \else \renewenvironment{equation}{% \mathdisplay@push \st@rredfalse \global\@eqnswtrue \mathdisplay{equation}% \incr@eqnum\mathopen{}% }{% \endmathdisplay{equation}% \mathdisplay@pop \ignorespacesafterend } \fi % \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