27

Is there a test for the different styles within maths mode? What I really want is to be able to save the current style to reinvoke it later on, but a \if along the lines of \ifmmode would work just as well.

In the specific example, I want to measure how big something will be when displayed in maths mode, so I do:

\settoheight{\mathheight}{some bit of maths}

except that it complains because the some bit of maths gets put in a box and measured, and the box doesn't know that it's maths. So instead I put:

\settoheight{\mathheight}{\(some bit of maths\)}

except that then I get the wrong answer if this is used in displayed maths. So ideally, I want:

\ifdisplaystyle
 \let\currentstyle\displaystyle
\else
 \iftextstyle
  \let\currentstyle\textstyle
 ...
 \fi
\fi
\settoheight{\mathheight}{\(\currentstyle some bit of maths\)}

and then I'll be happy.

Is there such a test?


Okay, so \mathchoice is clearly the way to go (thanks Martin!), but its behaviour is a little odd and since I want to use it to define a macro depending on which mode I'm in, this oddity is quite important. Here's the code:

\newcommand{\mathtest}{%
\gdef\name{a}%
\mathchoice{%
\name
\gdef\name{b}%
}{%
\name
\gdef\name{c}%
}{%
\name
\gdef\name{d}%
}{%
\name
\gdef\name{e}%
}%
\name}

\[
\mathtest
\]

If \mathchoice behaved like \if, this ought to print ab. But it prints ae. All the options to \mathchoice get processed (which makes me wonder a bit how it works, but that's by-the-by).

So, is there an obvious way to make \mathchoice behave a little more like \if?

4
  • 5
    TeX never knows what is the current math style. This is because of the \over, \atop, etc macros. As you discovered, \mathchoice processes all 4 variants and use the appropriate one once the end of the math list is reached. The mathstyle gets around this limitation by assuming that a LaTeX user will not use \over, \atop, etc in the text. These are used behind the scenes in amsmath, so mathstyle redefines the amsmath macros \frac, \binom, etc. That way, it is able to keep track of the current mathstyle. Of course, this will fail if you use an explicit \over, \atop, etc in your document.
    – Aditya
    Aug 6, 2010 at 18:48
  • Also, normally you can work around the limitation of mathchoice by defining your macros accordingly. For example, definition that you are using can also be written as \def\mathtest {\gdef\name{a} \name \gdef\name{\mathchoice{b}{c}{d}{e}} \name} which gives the correct result.
    – Aditya
    Aug 6, 2010 at 18:56
  • @adityam: thanks for the comments. Unfortunately, the implementation of the mathstyle package doesn't work for \( .. \) making it not work for what I want (which is closer to the first example than the second - that was to show that \mathchoice didn't behave how I wanted). Aug 6, 2010 at 19:04
  • 2
    For the behaviour of \mathchoice, see TeX by Topic: 'The primitive command \mathchoice{D}{T}{S}{SS}lets the user specify four variants of a formula for the four styles. TeX constructs all four and inserts the appropriate one.'
    – Joseph Wright
    Aug 7, 2010 at 5:54

6 Answers 6

15

Lets call such a macro mathsettoheight. I'll keep things simple and define only mathsettoheight (and not mathsettowidth and mathsettodepth).

IIUC, you want this macro to behave like

\mathsettoheight{\dimen}{content}

First, lets consider a simplified version of \settoheight

\def\settoheight#1#2%
  {\setbox\@tempboxa\hbox{{#2}}%
   #1=\ht\@temboxa
   \setbox\@temboxa\box\voidb@x}

The only change that we need to do in \mathsettoheight is to set the box correctly. Instead of

\hbox{#2}

use

\hbox{$\mathpalette{}{#2}$}

\mathpalette is a shortcut used for convenience and is usually defined by all macro packages (plain TeX, LaTeX, ConTeXt) as

\def\mathpalette#1#2{%
  \mathchoice
    {#1\displaystyle{#2}}%
    {#1\textstyle{#2}}%
    {#1\scriptstyle{#2}}%
    {#1\scriptscriptstyle{#2}}}

A minor improvement is to use

\hbox{$\m@th\mathpalette{}{#2}$}

where \m@th sets the math surround to zero (useful if you are interested in the width of the content).

And thats it. The complete definition with you example is

\documentclass{amsart}

\makeatletter

\def\mathsettoheight#1#2%
  {\setbox\@tempboxa\hbox{{#2}}%
   #1=\ht\@temboxa
   \setbox\@temboxa\box\voidb@x}

\def\mathsettoheight#1#2%
  {\setbox\@tempboxa\hbox{$\m@th\mathpalette{}{#2}$}%
   #1=\ht\@tempboxa
   \setbox\@tempboxa\box\voidb@x}

\makeatother

% Test case

\newlength\mathheight
\newcommand*\intheight{%
  \mathsettoheight{\mathheight}{\int}
  \the\mathheight
}


\begin{document}

$\intheight$

\begin{align}
\text{displaystyle}&={\displaystyle\text{\intheight}}\\
 \text{textstyle}&={\textstyle\text{\intheight}} \\
 \text{scriptstyle}&={\scriptstyle\text{\intheight}} \\
 \text{scriptscriptstyle}&={\scriptscriptstyle\text{\intheight}} 
\end{align}

{\obeylines
 \text{displaystyle}= $\displaystyle\text{\intheight}$\\
 \text{textstyle}=$\textstyle\text{\intheight}$ \\
 \text{scriptstyle}=$\scriptstyle\text{\intheight}$ \\
 \text{scriptscriptstyle}=$\scriptscriptstyle\text{\intheight}$ 
\endgraf}

\end{document}
1
  • In this specific case the mathpalette is redundant though. The \text already does an implicit \mathchoice (plus various complicated things to make both text size and math size correct).
    – user202729
    Aug 9, 2022 at 2:25
11

This answer will only apply to LuaTeX and LuaLaTeX, but your question was quite general, so ...

The luatex engine defines a primitive that allows you to query the current math style.

This primitive is called \mathstyle, and when the value is queried (after \ifnum, for example) it returns a number between -1 (not in math mode), 0 (display style), and 7 (cramped scriptscript style).

Luatex also defines four new primitives with \cramped.. prefix: \crampeddisplaystyle, \crampedtextstyle, \crampedscriptstyle, \crampedscriptscriptstyle. These are like their non-prefixed cousins (\displaystyle ... \scriptscriptstyle) except that they explicitly switch to one of the 'cramped' math styles.

Finally, there is the new primitive \Ustack, that is to be used as a prefix for \over.. and \atop.. constructs (which is what commands like \frac and \binom eventually expand into), like so

\Ustack {a \over b}

If you do not do this, \mathstyle will return the wrong value in the initial part of {... \over ...}, as explained by Aditya.

All combined together, these primitives allow code like this:

\ifnum\mathstyle=\textstyle
   \message{normal text style}
\else \ifnum\mathstyle=\crampedtextstyle
   \message{cramped text style}
\fi \fi

and this:

\def\cramped#1% switch the argument to a cramped math style
  {{\ifcase\mathstyle
    \crampeddisplaystyle      \or \or % 0 -> 1
    \crampedtextstyle         \or \or % 2 -> 3
    \crampedscriptstyle       \or \or % 4 -> 5
    \crampedscriptscriptstyle \fi     % 6 -> 7
    #1}}

and even allow you to define a version of \mathchoice that does not typeset everything four times:

\def\mathchoice#1#2#3#4%
  {{\ifcase\mathstyle
    #1\or #1\or
    #2\or #2\or
    #3\or #2\or
    #4\or #4\else #2\fi}}

All this can currently only be used if your underlying engine is luatex, but it is hoped that this extension will eventually become supported by xetex as well.

1
  • Thanks. I did not know the \UStack macro. I believe that \genfrac in ConTeXt MkIV needs to be adapted to use it.
    – Aditya
    Aug 7, 2010 at 13:32
7

Yes, you have \mathchoice

\documentclass{article}

\newcommand\mathtest{%
  \mathchoice
  {displaystyle}
  {text style}
  {scriptstyle}
  {scriptscriptstyle}
}

\begin{document}
\[
 \mathtest x^{\mathtest^{\mathtest}}
\]

\(
  \mathtest
\)

\end{document}
1
  • 1
    Clearly that's part of the answer, but it doesn't work quite how I expected! I've edited my question to focus on this (since describing the behaviour is a little long for a comment). Aug 6, 2010 at 15:12
4

Try using package mathstyle http://ctan.org/pkg/mathstyle. This solution is more along the lines of the original question.

\documentclass{article}
\usepackage{mathtools}
\usepackage{mathstyle}
\usepackage{calc}

\newlength\mathheight
\newcommand*\intheight{%
  \settototalheight{\mathheight}{$\currentmathstyle\int$}
  \the\mathheight
}

\begin{document}

\begin{align}
 \text{displaystyle}&={\displaystyle\text{\intheight}}\\
 \text{textstyle}&={\textstyle\text{\intheight}} \\
 \text{scriptstyle}&={\scriptstyle\text{\intheight}} \\
 \text{scriptscriptstyle}&={\scriptscriptstyle\text{\intheight}} 
\end{align}

\end{document}
2
  • 1
    So close! And yet so far. Looking at the style file, mathstyle works by hooking in to \displaystyle etc. But that means that if they don't get called, then it defaults to \displaystyle. Fine for displayed maths, but it does mean that \(\text{\intheight}\) gives the wrong height. Aug 6, 2010 at 18:51
  • You are right, but I don't have a fix right now. Aug 7, 2010 at 0:50
3

Here it comes a late late solution which, by the way, hasn't been tested thoroughly, but works in the case of what OP intended to do.

It's semiexpandable, i.e., the macro \def\mathcase{\getmsty\mstycase} has two parts \getmsty which is not expandable, and \mstycase which is indeed expandable. Similar, e.g., to \pgfmathparse{..} and \pgfmathresult. For instance, if you want to put something inside a csname you would need \getmsty\csname\mstycase{cdot}{times}{div}{cdots}\endcsname.

Any comment is welcome, because this might not work as expected, at least as I intended.

\documentclass{scrartcl}

\usepackage{mathtools}


\usepackage{zref-savepos}
\newcount\mmstynum
\newcount\tmpnum
\protected\def\getmsty
 {\global\advance\mmstynum1 %
  \expandafter\getstyA\expandafter{\number\mmstynum}}
\protected\def\getstyA#1%
 {\zsaveposx{mmsty-#1-a}%
  \mathchoice{\kern4sp}{\kern3sp}{\kern2sp}{\kern1sp}%
  \zsaveposx{mmsty-#1-b}
  \tmpnum=\numexpr
            \zposx{mmsty-#1-b} - \zposx{mmsty-#1-a}
          \relax
   \ifcase\tmpnum\or\kern-1sp \or\kern-2sp \or\kern-3sp \or\kern-4sp \fi}
\protected\def\mstycase
 {\ifcase\tmpnum\expandafter\gobblefour\or\expandafter\usefourth\or
   \expandafter\usethird\or\expandafter\usesecond\or
   \expandafter\usefirst\else\expandafter\gobblefour\fi}
\protected\def\mathcase{\getmsty\mstycase}

\long\def\gobblefour#1#2#3#4{}
\long\def\usefourth#1#2#3#4{#4}
\long\def\usethird#1#2#3#4{#3}
\long\def\usesecond#1#2#3#4{#2}
\long\def\usefirst#1#2#3#4{#1}


\def\tmpa{If this prints it means it doesn't work}
\newcommand*\foo
 {\mathcase % compare with \mathchoice
   {\def\tmpa{displaystyle}}
   {\def\tmpa{textstyle}}
   {\def\tmpa{scriptstyle}}
   {\def\tmpa{scriptscriptstyle}}
  \text\tmpa}

\begin{document}

\begin{align}
 \text{displaystyle} &= {\displaystyle\foo}\\
 \text{textstyle} &= {\textstyle\foo} \\
 \text{scriptstyle} &= {\scriptstyle\foo} \\
 \text{scriptscriptstyle} &= {\scriptscriptstyle\foo} 
\end{align}

\end{document}

Or… may be this solution doesn't work because of how it calculates the current style, it might not be robust (which is done by adding a small space and then checking with \pdfsavepos the space that has been inserted).

3
  • To emulate Steven's \ThisStyle behaviour you can do \def\thisstyle#1% {\begingroup\mathcase{\let\savedstyle\displaystyle}{\let\savedstyle\textstyle} {\let\savedstyle\scriptstyle}{\let\savedstyle\scriptscriptstyle}#1\endgroup}
    – Manuel
    Oct 26, 2015 at 1:43
  • 1
    I've added a critique of this approach here. Feb 17, 2016 at 9:36
  • That's good. I see that this approach is far from good, but at least for my uses it does work, my only concerns is if there are other problems apart from needed more than one run. Thanks for checking it ;)
    – Manuel
    Feb 17, 2016 at 13:51
3

The OP states, "What I really want is to be able to save the current style to reinvoke it later on". The method I described in my answer at Proper use of \mathchoice has been incorporated into my scalerel package under the syntax \ThisStyle{...\SavedStyle...}. When one wishes to save the current math style, issue a \ThisStyle{} at that point. Then place all the messy boxed stuff inside the argument, and whenever "this style" needs to be recalled, issue a \SavedStyle inside the \ThisStyle argument.

A most simple example is given in the MWE below, showing that script (or scriptscript) style can be remembered inside of an \fbox and recalled.

\documentclass{article}
\usepackage{scalerel}
\begin{document}
\def\tmp{\ThisStyle{\fbox{$\SavedStyle 1+y$}}}
$\tmp\quad 
X_{\tmp}\quad 
Z_{X_{\tmp}}$
\end{document}

enter image description here

It is good to remember that this approach utilizes a \mathchoice approach to implementation, but can often save a lot of typing relative to the \mathchoice syntax.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .