20

This question led to a new package:
underoverlap

Introduction

Based on this question and then this question, I'm trying to perfect the \overunderbrace macro. Right now, I'm trying to get the spacing right.

Minimal Working Example

\documentclass[varwidth=20cm,margin=3mm]{standalone}

\usepackage{mathtools}
\usepackage{xcolor}

\makeatletter
\def\overunderbrace#1#2#3{%
    \begingroup%
    \let\overunderbrace@sup\empty%
    \let\overunderbrace@sub\empty%
    \ignorespaces%
    \@ifnextchar^{%
        \@overunderbracesup{#1}{#2}{#3}%
    }{%
        \ignorespaces%
        \@ifnextchar_%
            {\@overunderbracesub{#1}{#2}{#3}}%
            {\@overunderbrace   {#1}{#2}{#3}}%
    }%
}

\def\@overunderbracesup#1#2#3^#4{%
    \def\overunderbrace@sup{#4}%
    \ignorespaces%
    \@ifnextchar_%
        {\@overunderbracesub{#1}{#2}{#3}}%
        {\@overunderbrace   {#1}{#2}{#3}}%
}

\def\@overunderbracesub#1#2#3_#4{%
    \def\overunderbrace@sub{#4}%
    \ignorespaces%
    \@ifnextchar^%
        {\@overunderbracesup{#1}{#2}{#3}}%
        {\@overunderbrace   {#1}{#2}{#3}}%
}

\def\@overunderbrace#1#2#3{%
    \mathrlap{\overbrace{\textcolor{red}{#1#2}}^{\mathclap{\overunderbrace@sup}}}%
    #1%
    \mathrlap{\underbrace{\textcolor{green}{#2#3}}_{\mathclap{\overunderbrace@sub}}}%
    #2%
    #3%
    \endgroup%
}
\makeatother

\newcommand{\config}[2]{\left\langle\,#1, #2\,\right\rangle}

\begin{document}
    $$
        \config{F\vphantom{F'}}{p}
        \longrightarrow
        \config{F'}{p}
        \longrightarrow
        \config{F'}{p'}
        \longrightarrow
        \cdots
    $$
    $$
        \overbrace
            {\config{F\vphantom{F'}}{p}\longrightarrow\config{F'}{p}}^{test}
        \longrightarrow
        \config{F'}{p'}
        \longrightarrow
        \cdots
    $$
    $$
        \overunderbrace
            {\config{F\vphantom{F'}}{p}\longrightarrow}
            {\config{F'}{p}}
            {\longrightarrow\config{F'}{p'}}
            ^{\text{environmental}}
            _{\text{local}}
        \longrightarrow
        \cdots
    $$
\end{document}

enter image description here

As you can see, the braces are horizontally misaligned to the content.

Note

The \@overunderbrace code here may seem (unnecessarily) more complicated than the code from the answer I based it on, but that's because I'm trying to set up a repeating pattern, so we can get more than just two overlapping braces. The way to do that seems to be to:

  • set [brace 1] with [phantom+rlap arguments 1+2]
  • set [argument 1]
  • set [brace 2 with [phantom+rlap arguments 2+3]
  • set [argument 2]
  • etc...

Diagnosis

To diagnose the problem, I replaced \phantom with \textcolor in the following code:

\def\@overunderbrace#1#2#3{%
    \mathrlap{\overbrace{\textcolor{red}{#1#2}}^{\mathclap{\overunderbrace@sup}}}%
    #1%
    \mathrlap{\underbrace{\textcolor{green}{#2#3}}_{\mathclap{\overunderbrace@sub}}}%
    #2%
    #3%
    \endgroup%
}

enter image description here

The black output is identical to the previous image. The red (green) content is the placement that the over(under)brace is based on.

It occurred to me that TeX determines spacing between math 'atoms' based on their respective types (ord, bin, rel, etc.). And I'm messing with this process by reordering the segments, \phantoming and \mathrlaping them.

Attempted Solution

So I augmented the formal parameters, making sure they always encounter the same 'environment' (to the best of my ability):

\def\@overunderbrace#1#2#3{%
    \@@overunderbrace%
        {\mathord{}#1\vphantom{#2}}%
        {\vphantom{\mathord{}#1}#2\vphantom{#3\mathord{}}}%
        {\vphantom{#2}#3\mathord{}}%
}

\def\@@overunderbrace#1#2#3{%
    ... the old \@overunderbrace ...
}

enter image description here

For comparison, I added the same formula without any braces, and then with only the overbrace (from the TeX command). As you see, no color is visible anymore (except for the rulers I added manually), so the printed content is aligned with its phantom images.

This solution is usable, but as you can see by the comparison, the spacing is still not right. Possibly because it's now using some 'inter-atom' glue twice in a row.

This is the point where I give up and ask for help.

Question: How can I get perfect spacing in a setup like this?

mhelvens
  • 6,126
  • Thanks! I'm going to read that. That's not what's causing the problem here, however. – mhelvens Jan 29 '13 at 18:36
  • If you use \newcommand{\config}[2]{{}\left\langle\,#1, #2\,\right\rangle{}}, it works. Somewhere on the way, your math-lapping gets in the way of TeX’s math-spacing algorithm. Meaning: The left and right angles do not see the appropriate math classes and assume something else (or nothing?). – Qrrbrbirlbel Jan 29 '13 at 18:54
  • @Qrrbrbirlbel Nice observation on the {}. Building on that, I've actually made the following sensible change: \newcommand{\config}[2]{\mathord{\left\langle\,#1, #2\,\right\rangle}}, and it works. This doesn't fix the general problem, of course, but it is another diagnostic result. – mhelvens Jan 29 '13 at 19:04
  • Yes, it is not the right place to fix that. Another way would be to prepend {} to the the first and the second argument of \overunderbrace: \overunderbrace {{}\config{F\vphantom{F'}}{p}\longrightarrow} {{}\config{F'}{p}} … or directly: \def\@overunderbrace#1#2#3{% \mathrlap{\overbrace{\textcolor{red}{{}#1{}#2}}^{\mathclap{\overunderbrace@sup}}}% #1% \mathrlap{\underbrace{\textcolor{green}{{}#2#3}}_{\mathclap{\overunderbrace@sub}}}% #2% #3% \endgroup% } – Qrrbrbirlbel Jan 29 '13 at 19:08
  • This looks a lot like my own attempted solution as shown in the question, only it works better. But can I be sure that the spacing will be correct for all cases? Or only when the left and right boundaries of the brace are 'ord'-like? (I'll try a few combinations in a little while. Right now I gotta go.) – mhelvens Jan 29 '13 at 19:13
  • @mhelvens: Great work with the new package! I just spotted a typo in the documentation: on page 6, line 2 it should say \UOLunaugment and not \UOLaugment in the left margin. – Hendrik Vogt Feb 02 '13 at 16:27
  • Thanks! I fixed it locally, but the fix'll have to wait for the next version to appear online. – mhelvens Feb 02 '13 at 16:31

1 Answers1

8

Nice colour debugging (+1 for that:-)

You can measure the extra space that would have been between #1 and #2 normally and re-insert it:

enter image description here

\def\@overunderbrace#1#2#3{%
    \setbox\z@\hbox{${#1#2}$}\setbox\tw@\hbox{${#1}{#2}$}\dimen@\dimexpr\wd\z@-\wd\tw@
    \mathrlap{\overbrace{\textcolor{red}{{#1#2}}}^{\mathclap{\overunderbrace@sup}}}%
    {#1}%
    \kern\dimen@
    \mathrlap{\underbrace{\textcolor{green}{{#2#3}}}_{\mathclap{\overunderbrace@sub}}}%
    {#2%
     #3}%
    \endgroup%
}
David Carlisle
  • 757,742
  • Looking good! But I'll have to put off testing it until tomorrow evening. (I can only look forward to 4.5 hours sleep as it is.) --- One question in the mean time, though: I was under the impression that \z@ was a 'dimen' register (i.e., not a 'box' register); moreover, one that must not be changed under any circumstances, or so the TeXbook tells me. So.. what's up with that? – mhelvens Jan 29 '13 at 23:40
  • It's not being changed it is just being used as an efficient 0 see http://tex.stackexchange.com/questions/55400/what-does-z-do/55401#55401 – David Carlisle Jan 29 '13 at 23:42
  • Ah, yes of course. \setbox takes an index. But \z@... one wonders if such an 'optimization' makes a significant difference in this day and age. More to the point: is it worth obscuring the meaning of the code? – mhelvens Jan 30 '13 at 05:16
  • It was out of habit rather than optimisation, it also makes it much less likely to get expansion errors as if you use a literal 0 tex has to scan ahead to see if more digits follow. if you look at much latex (or amsmath) code you will see literally hundreds of uses if \z@ so I wasn't expecting it to be obscure to anyone who was happy to see code with setbox at all. – David Carlisle Jan 30 '13 at 09:32
  • I must be at just that point in the TeXbook where I know about \setbox but not about \z@. ;-) – mhelvens Jan 30 '13 at 20:17
  • Your code doesn't work yet with cases like $aaaa + bbbb$\\$\overunderbrace{aaaa}{+}{bbbb}$. I'll try to solve it myself, but your help would be appreciated. Also, I imagine the same problem would occur with tokens before and after the use of our macro. Can we do anything about that? – mhelvens Jan 31 '13 at 11:40
  • \def@overunderbrace#1#2#3{% \setbox\z@\hbox{${#1#2{}}$}\setbox\tw@\hbox{${#1}{{}#2{}}$}\dimen@\dimexpr\wd\z@-\wd\tw@ \mathrlap{\overbrace{\textcolor{red}{{#1#2{}}}}^{\mathclap{\overunderbrace@sup}}}% {#1}% \kern\dimen@ \mathrlap{\underbrace{\textcolor{green}{{{}#2#3}}}_{\mathclap{\overunderbrace@sub}}}% {{}#2% #3}% \endgroup% } – David Carlisle Jan 31 '13 at 12:45
  • Here's another one: $aaaa + bbbb + cccc$\\$\overunderbrace{aaaa +}{bbbb}{+ cccc}$. It doesn't know about the 'binary-ness' of the first +. I could compensate for this one by adding {} after every occurrence of #1. I guess we could go on like this for a while, but will we ever be sure we're covering all cases? (Maybe I should write a test-suite...) – mhelvens Jan 31 '13 at 13:46
  • well probably adding {} everywhere would be good enough, the problems are not really related to the over-under brace you see the same spacing change if you go ${aaaa +}{bbbb}{+ cccc}$ probably the spacing for ${aaaa +{}}{{}bbbb{}}{{}+ cccc}$ is always going to be acceptable even if it is possible to find cases where it is different to the string without any braces at all. ams alignments have a similar problem and just use a {} at the beginning of the cell and no one complains much – David Carlisle Jan 31 '13 at 13:58
  • Do you believe it is not possible to get perfect spacing (as Knuth intended)? It might be worth it to write a general solution package that other package authors can use for \overunderbrace kind of stuff. – mhelvens Jan 31 '13 at 14:02
  • yes it is, possible it just depends how far you want to push (or push me) to getting it right. for example in 99% of the cases just doing the box measuring between #1#2 - {#1}{#2} and #2#3-{#2}{#3} would work but in the case #2 is a single character as in your + example you have to work harder and probably measure #1#2#3 - {#1}{#2}{#3} as well as missing off the text on one side turns it from a mathbin to a mathord which affects the spacing on both sides. – David Carlisle Jan 31 '13 at 14:42
  • Yeah, I see the difficulty. It would be easier if we had access to the 'current state' of the spacing algorithm. --- I didn't mean to push you. I'm just perfectionist to a fault. :-) I could try to get every pixel of spacing correct while neglecting to actually write my article. ;-) I guess I'm happy with our results for now. Thanks for your help! – mhelvens Jan 31 '13 at 14:50