amsmath aligned environment: correct positioning of equation number on the last line with tbtags

tl;dr

How to place the equation number on the last line of an {aligned}[t] environment?
(Similar questions have been asked in Equation number in aligned environment after last line and How can I position the tag of a "nested" aligned environment?, but the situation I describe here is more complicated and not easily solved by the answers posted there.)

The situation

Consider the following situation: The tbtags option for the amsmath package is in use, i.e., tags on the right hand side should always be placed on the bottommost line of each eqution. I have multiple equations in a single align environment. All the relation symbols need to be aligned. In each equation I may need additional alignment points. (In the following example the opening parentheses will be aligned.) The secondary alignment points will not be at the same horizontal position. (I.e., alignat can't be used here.) The equations are typeset by nesting aligned inside split and align.

The example

\documentclass{article}
\usepackage[tbtags]{amsmath}
\begin{document}
\begin{align}
x &= 1234[\!\begin{aligned}[t]
&(a+b)\\
&(c+d+e)\\
&(f+g)]\end{aligned}\\
\begin{split}
y &= 5[(h+i)+j]\\
&= 6[\!\begin{aligned}[t]
&(k+l)\\
&(m+n+o)]\end{aligned}
\end{split}
\end{align}
\end{document}


In the image the black font shows the output when compiling the example code. The equations themselves are typeset exactly as I want, but I disagree with the position of the equation numbers. The red numbers show where I want the tags to be positioned.

The problem

The equation numbers are not placed on what would mathematically be considered the last line of the equations, i.e., lines 3 and 6. Instead they are placed on lines 1 and 5. (I think this happens because LaTeX-internally only lines 1, 4 and 5 are actually considered lines.)

The solution?

1. Don't use aligned at all. (Don't use split either.) Use \notag on lines 1, 2, 4 and 5. Use something like \hphantom{{}=prefactor[} on lines 2, 3 and 6.
2. Put each equation in a split and use something like \end{aligned}\\[-XXpt]&\end{split}\\[YYpt], thus introducing a new line that LaTeX considers worthy of a number but move it upwards so that the printed tag appears not on its own line but the previous one.
3. I hate soultions 1 and 2. Solution 1 requires duplication the prefactor many times (The best I can do is store it in a macro for each equation and call that on every line that needs the leading whitespace), solution 2 requires finetuning the vertical spaces XX and YY (I have no idea whether those could be measured and inserted automatically). Both are tedious, might have unintended side effects that I don't know of, it will be very annoying when typesetting a large number of equations, and it might fail if a tag has to be moved from its default position because of a long line.

Can anyone think of a better, more automatic or more elegant solution?

Bonus question

If you have a good solution for the problem above then you might also be able to answer this: How to solve the same problem when cases is used (instead of aligned), i.e., how to place the tag on the line with the last case? In this situation solution 1 cannot be used and the calculation for solution 2 becomes more complicated.

Bonus bonus question

How to tackle the same problem if you have aligned inside cases inside split inside align?

• There should be three boni – one for each ‘inside’ ;o) – Bernard Mar 16 '16 at 20:27
• So basically you want to align the "aligned" to the top on the left and to the bottom on the right (automatically). Hard to do with a single baseline. Frankly, solution 2 is easier. – John Kormylo Mar 16 '16 at 21:50

This uses tikz to place (overlay) the tag, consequently it takes two runs to position the tags correctly.

It ignores whether the equation is too wide, since it may not be too wide where the tag is. \taghere does provide an optional argument to apply additional vertical offset.

\documentclass{article}
\usepackage{amsmath}
\usepackage{tikz}

\makeatletter
\newif\iftag@here

\newcommand*{\taghere}[1][0pt]% #1 = additional vertical offset (optional)
{\ifmeasuring@\else% do not expand until displayed
\global\tag@heretrue
\tikz[remember picture,overlay]{\coordinate (taghere) at (0pt,#1);}%
\fi}

\def\place@tag{%
\iftagsleft@
\kern-\tagshift@
\iftag@here
\global\tag@herefalse
\tikz[remember picture,overlay]%
{\path (taghere) -| node[anchor=base]{\rlap{\boxz@}} (0pt,0pt);}%
\else
\if1\shift@tag\row@\relax
\rlap{\vbox{%
\normalbaselines
\boxz@
\vbox to\lineht@{}%
\raise@tag
}}%
\else
\rlap{\boxz@}%
\fi
\kern\displaywidth@
\fi% end of \iftag@here
\else
\kern-\tagshift@
\iftag@here
\global\tag@herefalse
\tikz[remember picture,overlay]%
{\path  (taghere) -|  node[anchor=base]{\llap{\boxz@}} (0pt,0pt);}%
\else
\if1\shift@tag\row@\relax
\llap{\vtop{%
\raise@tag
\normalbaselines
\setbox\@ne\null
\dp\@ne\lineht@
\box\@ne
\boxz@
}}%
\else \llap{\boxz@}%
\fi
\fi% end of \iftas@here
\fi
}
\makeatother

\begin{document}
\begin{align}
x &= 1234[\!\begin{aligned}[t]
&(a+b)\\
&(c+d+e)\\
&(f+g)\taghere]
\end{aligned}\\
\begin{split}
y &= 5[(h+i)+j]\\
&= 6[\!\begin{aligned}[t]
&(k+l)\\
&(m+n+o)\taghere]
\end{aligned}
\end{split}\\
z &= \begin{cases}
1 & x>0\\
0 & \textrm{otherwise}\taghere
\end{cases}
\end{align}

\end{document}


• First off: This is beautiful. It still has some problems, though. Two problems are illustrated by the following example: \begin{align}a\\b\\c\taghere\end{align}. Line a has no tag at all (this one I do not understand, it seems that \iftag@here is set to true, even though \taghere has not been specified in that line), line b is correct and in line c the tag has the wrong horizontal postition (I think this can be fixed by node[anchor=base]{\llap{\boxz@}}). Thank you very much. – wea0 Mar 20 '16 at 16:20
• Fixed it. Now \taghere only expands when displayed. – John Kormylo Mar 21 '16 at 0:06
• I used it in quite a few real world applications today and aside from long lines it worked everywhere. Very good. – wea0 Mar 21 '16 at 17:18
• Did you use the optional argument for the long lines? That is what it is there for. BTW, the horizontal offset was because I forgot to add [inner sep=0pt]. But I suspect using \llap is faster. – John Kormylo Mar 21 '16 at 17:34
• Hi, the code from this answer has been very helpful and I have been using it in my work. Would you be willing to grant me a license to the code posted in this answer under the current LPPL (or even any compatible permissive license such as CC0)? I would like to put it in my personal LaTeX package where I collect math-mode snippets that I found useful. Since that package already contains code copied and modified from other existing packages it should be under LPPL so that I can legally "redistribute" (i.e., share with a handful of coauthors) it as one package. – wea0 Sep 15 '17 at 0:42

split only allows one alignment point. Use phantoms:

\documentclass{article}
\usepackage[tbtags]{amsmath}

\newcommand\?[1]{\mathopen{\hphantom{#1}}}

\begin{document}

\begin{align}
\begin{split}
x ={}& 1234[(a+b)\\
& (c+d+e)\\
& (f+g)]
\end{split}\\
\begin{split}
y ={}& 5[(h+i)+j]\\
={}& 6[(k+l)\\
& (m+n+o)]
\end{split}
\end{align}

\begin{align}
\begin{split}
x ={}& 1234[(a+b)\\
& \?{1234[}(c+d+e)\\
& \?{1234[}(f+g)]
\end{split}\\
\begin{split}
y ={}& 5[(h+i)+j]\\
={}& 6[(k+l)\\
& \?{[}(m+n+o)]
\end{split}
\end{align}

\end{document}


• Excuse my ignorance, but what does \? do? I don't usually have to typeset maths, but recently, I don't seem able to escape it :(. – cfr Sep 5 '17 at 17:47
• @cfr It inserts a phantom treated as an open atom, for adding some space – egreg Sep 5 '17 at 19:01

I have been pointed to \pdfsavepos and then found the zref-savepos package. I tried to construct an alternative solution based on this functionality. It works (at least somewhat) for aligned and cases. The implementation basically measures the difference in position of the center and the bottom line and then \raiseboxes everything except the ampersand token.

1. In the case of long lines the equation number is sometimes (but not always) a bit too far off. It seems to depend on the surrounding equations. (I don't understand this behavior at all.)
2. If the lines are big then the tag is on the desired baseline.
3. It works inside split.
4. My alternative to cases does not work properly if the last case is aligned.

I am quite unhappy with the syntax of my new commands. It is not flexible and also it is very unlike the standard environments, but this is the best I can come up with right now.

Is there any way to move math content vertically without having to resort to \raisebox{len}{$inline-math$}? Is there any way to raise or lower the position of the ampersand token? (It cannot be put in inline math.)

\documentclass{article}
\usepackage[tbtags]{amsmath}
\usepackage{zref-savepos}

\newcounter{index}

% Three arguments:
% #1 terms left of the relation symbol
% #2 relation symbol and prefactors
% #3 content to be put in aligned/cases

\newcommand{\myaligned}[3]{%
\stepcounter{index}%
\raisebox{\dimexpr\zposy{c\theindex}sp-\zposy{b\theindex}sp}{$\displaystyle#1$}%
&%
\raisebox{\dimexpr\zposy{c\theindex}sp-\zposy{b\theindex}sp}{\displaystyle{}#2\zsaveposy{c\theindex}\!\begin{aligned}[t]#3\zsaveposy{b\theindex}\end{aligned}}%
}

\newcommand{\mycases}[3]{%
\stepcounter{index}%
\raisebox{\dimexpr\zposy{c\theindex}sp-\zposy{b\theindex}sp}{$\displaystyle#1$}%
&%
\raisebox{\dimexpr\zposy{c\theindex}sp-\zposy{b\theindex}sp}{$\displaystyle{}#2\zsaveposy{c\theindex}\begin{cases}#3\zsaveposy{b\theindex}\end{cases}$}%
}

\begin{document}
\begin{minipage}{.4\textwidth}
\begin{align}
%  uncommenting this somehow fixes the too large separation of the first tag
%  a&=a\\
\myaligned{x}{=1234[}{
&(a+b)\\
&(c+d+e)\\
&(f+g)loooooooong]
}\\
\begin{split}
y&=5[(h+i)+j]\\
\myaligned{}{=6[}{
&\biggl(k+l\biggr)\\
&\biggl(m+n+o\biggr)]
}
\end{split}
\end{align}

\begin{align}
x&=1\\
\begin{split}
y&=first\ line\ in\ split\\
\mycases{}{=prefactor}{
blah\\
blah\\
blah\\
blah
}
\end{split}\\
z&=3
\end{align}

\begin{align}
\mycases{y}{=2}{
blah\\
blah\\
aligned\!\begin{aligned}[t]&first\\&second\end{aligned}
}
\end{align}
\end{minipage}
\end{document}