4

This question has led to a new package: leftindex

It is a well-known problem that there seems to be no automatic way of getting nice spacing for left indices, particularly left superscripts. The most standard choice of command seems to be \prescript from mathtools, but superscripts suffer from the same problem as with other options:

enter image description here

\documentclass{article}

\usepackage{mathtools}

\begin{document}

[ \prescript{a}{b}{f}, \qquad \prescript{a}{b}{\int} ]

\end{document}

What I would like is a low-level, manual solution to this problem: A command

\manualprescript{<height>}{<superscript indentation>}{<subscript indentation>}
        {<superscript>}{<subscript>}{<symbol>}

where I can manually specify the height and the indentation of the indices. This could be either using TeX dimensions (e.g. .3em) or as tokens to be plugged into \vphantom and \hphantom. Either solution will be fine by me (or both, if you have the time). I could probably come up with some (very) bad solution to this myself using boxes and \phantom’s, which is why I am asking in here in order to obtain the right solution. (If possible, I would prefer a solution in LaTeX3 syntax since this is usually more readable and future-proof).

Gaussler
  • 12,801
  • \documentclass{article} \usepackage{mathtools} \begin{document} \[ \prescript{\rlap{a}}{b}{\int} \] \end{document} ? – Zarko Aug 06 '20 at 17:26
  • @Zarko, well, then if the upper index is too long, it will just run into the integral. And it does not allow me to manually control the spacing the way I want to. – Gaussler Aug 06 '20 at 17:30

2 Answers2

5

You can do it automatically.

\documentclass{article}
\usepackage{amsmath,mathtools,xparse}

\makeatletter \NewDocumentCommand{\preint}{e{^}}{\mathpalette\pre@int{{#1}{#2}}!\int} \newcommand{\pre@int}[2]{\pre@@int#1#2} \newcommand{\pre@@int}[3]{% \sbox0{$#1\int\sb{xxxxxx}$}% \sbox2{$#1{\int}\sb{xxxxxx}$}% \setlength{\dimen4}{\dimexpr\wd2-\wd0\relax}% % compute the spacing \settowidth{\dimen0}{$\m@th#1^{\IfValueT{#2}{#2}}$}% \addtolength{\dimen0}{-\dimen4}% \settowidth{\dimen2}{$\m@th#1{\IfValueT{#3}{#3}}$}% % start the business \mathop{}!% \ifdim\dimen0>\dimen2 \kern\dimen0\else\kern\dimen2\fi % print the scripts {\mbox{$#1\vphantom{\int}$}} ^{\mathmakebox[0pt][l]{\mathmakebox[\dimen4][r]{\IfValueT{#2}{#2}\mspace{-1mu}}}} _{\mathmakebox[0pt][r]{\IfValueT{#3}{#3}}} } \makeatother

\begin{document}

[ x\preint_a^b f(x),dx + \preint_a^{b+c+d} f(x),dx ] \begin{center} $x\preint_a^b$ \end{center}

\end{document}

enter image description here

egreg
  • 1,121,712
  • Thanks for the solution! But how can one adjust it so that it does not just fit \int, but arbitrary symbols? I suspect that one will have to specify some dimensions (or degrees of slanting) manually, since the symbols f, M, and \Gamma have different slanting and therefore require different spacing. Can one turn this solution into a general, low-level command like I suggested in the original post? – Gaussler Aug 07 '20 at 07:31
  • 1
    @Gaussler The integral is quite special. A general command? I’m afraid it’ very hard, if not impossible, because it depends on the shape of the symbol. – egreg Aug 07 '20 at 08:21
  • 1
    But that’s why I wanted a very low-level command as specified in the original post, where I can specify all those dimensions manually. One could add another factor: The slanting factor of the symbol. For \Gamma, this slanting factor is 0, and for f, it’s probably about 0.2, i.e. you have to indent by about 0.2 times the height of the symbol. (This requires more thorough testing, but the important thing is to get a manual, low-level command that allows you to plug in all this information and get a result.) – Gaussler Aug 07 '20 at 08:28
  • @Gaussler The ideas are there: the vertical dimensions can be emulated; add an argument for a horizontal displacement for both subscript and superscript, instead of computing it like I did for the integral. Then compensate the space in a similar way. – egreg Aug 07 '20 at 08:34
  • Yes, you are right. I will adjust it myself, even though I probably cannot do it on an egreg level. xD Thanks for the answer! :-) – Gaussler Aug 07 '20 at 08:37
  • Someone made me aware of spacing issues when the left index appears at the very beginning of a math expression. So I was wondering: Would it not be better to move \mathop{}\! up before the line \ifdim...? Or is there a better solution to this problem? – Gaussler Nov 24 '23 at 11:28
  • @Gaussler I'm not sure what spacing issues you're referring to: I made a few experiments and moving \mathop{}\! doesn't make a difference. – egreg Nov 24 '23 at 11:39
  • Try the line \noindent $\preint^{a}_{b}$\\$\preint^{a}_{b}$. – Gaussler Nov 24 '23 at 11:46
  • 1
    @Gaussler OK, convincing. – egreg Nov 24 '23 at 13:28
  • What would be the easiest way to replace \mathmakebox with more primitive commands to make the code independent of mathtools? I looked at the mathtools documentation, but it seems that \mathmakebox is doing a lot of stuff that isn’t really necessary in these simple cases. Some combination of \rlap and \rlap and some spacing commands could probably do the same trick, right? – Gaussler Dec 01 '23 at 14:53
  • @Gaussler Some \mathpalette trick should suffice. – egreg Dec 01 '23 at 15:11
  • How would you do that? To remove \mathmakebox, you obviously need more than just \mathpalette. – Gaussler Dec 09 '23 at 17:03
1

This solution is now available as a package: leftindex

I tried adjusting egreg’s answer to the general case. It is not built specifically for \int and therefore does not produce quite as perfect an output for that particular symbol. The benefit is that it provides relatively nice results in the general case. I provide the command

\leftindex^{<left superscript>}_{<left subscript>} {<symbol>}

This will indent the left superscript with the same value as the negative indentation of the right subscript. Sometimes, this yields wrong results. Therefore, the command takes two additional, optional arguments:

\leftindex[<slanting phantom>][<height phantom>]
    ^{<left superscript>}_{<left subscript>} {<symbol>}

This one will instead calculate the left superscript indentation using the <slanting phantom>. If provided, it will calculate the height based on the <height phantom>.

There is also another, underlying command

\manualleftindex
    {<height phantom>}
    {<slanting phantom>}
    {<subscript>}
    {<superscript>}

which is mainly intended for use in other commands (or packages).

\documentclass{article}

\usepackage{expl3,mathtools,kpfonts}

\ExplSyntaxOn

\DeclareDocumentCommand\manualleftindex { mmmm } { % #1 = height phantom % #2 = slanting phantom % #3 = left superscript % #4 = left subscript \mathpalette __leftindex_auxiliary_mathpalette_command:nn { {#1}{#2}{#3}{#4} } }

\ExplSyntaxOff

\DeclareDocumentCommand\leftindex { o o E{^_}{{}{}} m } { % #1 = slanting phantom % #2 = height phantom % #3 = left superscript % #4 = left subscript % #5 = symbol \IfValueTF {#1} { \IfValueTF{#2} { \manualleftindex { #2 } { #1 } { #3 } { #4 } } { \manualleftindex { #1 } { #1 } { #3 } { #4 } } } { \manualleftindex { #5 } { #5 } { #3 } { #4 } } #5 }

\DeclareDocumentCommand\LeftIndex { o o E{^_}{{}{}} } { % #1 = slanting phantom % #2 = height phantom % #3 = left superscript % #4 = left subscript \IfValueTF {#1} { \IfValueTF{#2} { \manualleftindex { #2 } { #1 } { #3 } { #4 } } { \manualleftindex { #1 } { #1 } { #3 } { #4 } } } { \manualleftindex { } { } { #3 } { #4 } } }

\ExplSyntaxOn

\cs_new_protected:Npn\leftindex_kern_horizontal:n#1 { \kern #1 \relax }

\cs_new_protected:Npn\leftindex_set_mathsurround_to_zero: { % This is equivalent to "\m@th" \dim_set:Nn \mathsurround { 0pt } }

\cs_new_protected:Npn__leftindex_auxiliary_mathpalette_command:nn#1#2 { __leftindex_auxiliary:nnnnn { #1 } #2 }

\dim_new:N\l__leftindex_phantom_height_dim

\box_new:N \l__leftindex_slanting_phantom_with_subscript_box \dim_new:N \l__leftindex_slanting_phantom_with_subscript_dim

\box_new:N \l__leftindex_slanting_phantom_with_subscript_without_indentation_box \dim_new:N \l__leftindex_slanting_phantom_with_subscript_without_indentation_dim

\dim_new:N \l__leftindex_indentation_of_slanting_phantom_subscript

\box_new:N \l__leftindex_superscript_temp_box \dim_new:N \l__leftindex_width_of_superscript_dim

\box_new:N \l__leftindex_subscript_temp_box \dim_new:N \l__leftindex_width_of_subscript_dim

\cs_new_protected:Npn__leftindex_auxiliary:nnnnn#1#2#3#4#5 { \group_begin: \hbox_set:Nn \l__leftindex_slanting_phantom_with_subscript_box { $ #1 #3 \sb{xxxxxx} $ } \dim_set:Nn \l__leftindex_slanting_phantom_with_subscript_dim { \box_wd:N \l__leftindex_slanting_phantom_with_subscript_box } \hbox_set:Nn \l__leftindex_slanting_phantom_with_subscript_without_indentation_box { $ #1 \hbox:n {$ #1 #3 $} \sb{xxxxxx} $ } \dim_set:Nn \l__leftindex_slanting_phantom_with_subscript_without_indentation_dim { \box_wd:N \l__leftindex_slanting_phantom_with_subscript_without_indentation_box } \dim_set:Nn \l__leftindex_indentation_of_slanting_phantom_subscript { \l__leftindex_slanting_phantom_with_subscript_without_indentation_dim - \l__leftindex_slanting_phantom_with_subscript_dim } \tl_if_blank:nTF { #4 } { \dim_zero:N \l__leftindex_width_of_superscript_dim } { \hbox_set:Nn \l__leftindex_superscript_temp_box { $ \leftindex_set_mathsurround_to_zero: #1 \sp { #4 } $ } \dim_set:Nn \l__leftindex_width_of_superscript_dim { \box_wd:N \l__leftindex_superscript_temp_box - \l__leftindex_indentation_of_slanting_phantom_subscript } } \tl_if_blank:nTF { #5 } { \dim_zero:N \l__leftindex_width_of_subscript_dim } { \hbox_set:Nn \l__leftindex_subscript_temp_box { $ \leftindex_set_mathsurround_to_zero: #1 \sb { #5 } $ } \dim_set:Nn \l__leftindex_width_of_subscript_dim { \box_wd:N \l__leftindex_subscript_temp_box } } \mathop{} \leftindex_kern_horizontal:n { \dim_max:nn { \l__leftindex_width_of_superscript_dim } { \l__leftindex_width_of_subscript_dim } } \mathopen{ \vphantom { #2 } } \tl_if_blank:nF { #4 } { \sp { \mathmakebox[0pt][l]{ \mathmakebox[ \l__leftindex_indentation_of_slanting_phantom_subscript ][r]{ #4 } } } } \tl_if_blank:nF { #5 } { \sb { \mathmakebox[0pt][r]{ #5 } } } \group_end: }

\ExplSyntaxOff

\begin{document}

[ x \leftindex^{a+b}_{c+d} {\int} f(x), dx ]

[ \leftindex^{1}{0} {f}^u_v \neq \leftindex^{pq}{0} {H}^u_v ]

[ \leftindex^{a}{b} {\Gamma}^c_d \neq \leftindex[]^{a}{b} {\Gamma}^c_d ]

\end{document}

enter image description here

Gaussler
  • 12,801
  • @egreg Any comments? :-) – Gaussler Aug 23 '20 at 11:59
  • The kerning is appropriate for the integral, definitely not for Gamma. – egreg Aug 23 '20 at 14:17
  • @egreg I don’t quite follow. Is the second solution, \manualleftindex{\Gamma}{}{a}{b}, not appropriate for \Gamma? On the surface, it looks good to me. – Gaussler Aug 23 '20 at 14:29
  • Yes, the right-hand side is good, which I can't say about the left-hand side. – egreg Aug 23 '20 at 14:37
  • @egreg No, of course not. ;-) That’s why I have the manual version, to show the difference. :-). Any other comments? I did things mostly as you did, but some things are different, e.g. I include a \mathopen, taking inspiration from mathtools. So I replace {\mbox{$#1\vphantom{\int}$}} by simply \mathopen{\vphantom{#2}}. Are there any issues with this or with other of the changes I made? Any comments will be greatly appreciated. ;-) (I will use this in a package, so I want to make 100 % sure there are no issues before I do. :-) ) – Gaussler Aug 23 '20 at 14:42
  • 1
    Remark: when using this package, it's best to only put a single symbol in the argument, otherwise there may be issues. e.g. https://tex.stackexchange.com/q/701911/250119 – user202729 Nov 21 '23 at 16:17