2

Apparently the \DHLhksqrt macro in the MWE below measures its content 20 times:

enter image description here

Questions:

  1. Where exactly can I put the \measuring@true and \measuring@false so that I get the count of 1? If you uncomment the \measuring lines the count drops to 16 so then 4 measurements are taking place between the two commented lines.

  2. Bonus: Where are the 20 measurements coming from?

Reference:

Code:

\documentclass{article}
\usepackage{mathtools}
\usepackage{xparse}
\usepackage{letltxmacro}

\LetLtxMacro{\oldsqrt}{\sqrt}

\makeatletter
\newcommand{\ClosedSqrt}[1][]{\def\DHLindex{#1}\mathpalette\DHLhksqrt}%
\def\DHLhksqrt#1#2{%
  %\measuring@true
  \setbox0=\hbox{$#1\oldsqrt{#2\,}$}\dimen0=\ht0\relax%
  \advance\dimen0-0.25\ht0\relax%
  \setbox2=\hbox{\kern-0.375pt\vrule height\ht0 depth -\dimen0}%
  %\measuring@false
  {%
    \hbox{$#1\expandafter\oldsqrt\expandafter[\DHLindex]{#2\,}$}%
    \lower\ifx\math@version\bold@name0.60pt\else0.4pt\fi\box2%
  }%
}%
\RenewDocumentCommand{\sqrt}{O{\hphantom{3}} O{0} O{0}  m}{\ClosedSqrt[\leftroot{#2}\uproot{#3}#1]{#4}}%

\newcounter{NumberOfInstances}
\setcounter{NumberOfInstances}{0}
\newcommand*{\MyValue}{%
    \ifmeasuring@\else%
        \stepcounter{NumberOfInstances}%
    \fi
    x%
}%
\makeatother

\begin{document}\noindent
NumberOfInstances=\arabic{NumberOfInstances}.
\[ \sqrt{\MyValue} \]      
NumberOfInstances=\arabic{NumberOfInstances}.
\end{document}
  • I don't think you can get it smaller than 4 because og the mathpalette, don't it have to run it in all four modes before deciding which one to use? – daleif Dec 17 '15 at 6:57
  • @daleif: But $\frac{\MyValue}{1}$ does not have such a problem. Doesn't \frac{}{} goes through a similar process to decide how the fraction should be typeset? – Peter Grill Dec 17 '15 at 7:06
  • Not sure, you'd probably need egreg to explain it. – daleif Dec 17 '15 at 7:16
  • I don't think amsmath's \measuring@ is thought out to be set. And anyhow if I do not load mathtools at all comment out the \leftroot, \uproot, and \ifmeasuring@ things, I again get 20 with your code. – user4686 Dec 17 '15 at 7:49
  • Every \mathchoice command (called by \mathpalette) typesets four boxes. Five calls of \mathchoice make for twenty boxes; the original \sqrt command (when the optional argument is used) calls \mathpalette and so does \phantom in math mode. – egreg Dec 17 '15 at 7:49
3

There is a problem when text is processed multiple times and this of course happens when \mathpalette is involved.

If you try

\documentclass{article}
\usepackage{amsmath}
\newcounter{noi}
\newcommand{\doit}{\stepcounter{noi}x}
\begin{document}
$\sqrt[3]{\doit}$
Number of instances: \thenoi 
\end{document}

(note the optional argument) you get 4 as the number of instances. You'd get just 1 with \sqrt{\doit}.

In the case of the closed square root symbol, the optional argument is always assumed, so the routine is called four times because \mathpalette enters into action.

You can greatly reduce the amount of stepping by loading amsmath (well, amstext) and redefining \mathpalette to set \iffirstchoice@. The package redefines \stepcounter and \addtocounter to do nothing when \iffirstchoice@ returns false. This is used in \text for avoiding to step counters four times. However, \mathpalette is not redefined, so we need to. Also, \firstchoice@false must be issued when the argument possibly containing counter stepping is subject to trial typesetting.

Note that this just turns off excess stepping, not the number of times the boxes are typeset (which is indeed 20).

\documentclass{article}
\usepackage{mathtools}
\usepackage{xparse}
\usepackage{letltxmacro}

\makeatletter
\def\mathpalette#1#2{%
  \mathchoice
    {#1\displaystyle{#2}}%
    {\firstchoice@false#1\textstyle{#2}}%
    {\firstchoice@false#1\scriptstyle{#2}}%
    {\firstchoice@false#1\scriptscriptstyle{#2}}}
\makeatother

\LetLtxMacro{\oldsqrt}{\sqrt}

\makeatletter
\newcommand{\ClosedSqrt}[1][]{\def\DHLindex{#1}\mathpalette\DHLhksqrt}%
\def\DHLhksqrt#1#2{%
  \sbox0{\firstchoice@false$#1\oldsqrt{#2\,}$}\dimen0=\ht0\relax
  \advance\dimen0-0.25\ht0\relax
  \sbox2{\kern-0.375pt\vrule height\ht0 depth -\dimen0}%
  {%
    \hbox{$#1\expandafter\oldsqrt\expandafter[\DHLindex]{#2\,}$}%
    \lower\ifx\math@version\bold@name0.60pt\else0.4pt\fi\box2
  }%
}%
\RenewDocumentCommand{\sqrt}{O{\hphantom{3}} O{0} O{0}  m}{\ClosedSqrt[\leftroot{#2}\uproot{#3}#1]{#4}}%

\newcounter{NumberOfInstances}
\setcounter{NumberOfInstances}{0}
\newcommand*{\MyValue}{%
        \stepcounter{NumberOfInstances}%
    x%
}%
\makeatother

\begin{document}\noindent
NumberOfInstances=\arabic{NumberOfInstances}.
\[ \sqrt{\MyValue} \]      
NumberOfInstances=\arabic{NumberOfInstances}.
\[ \oldsqrt[3]{\MyValue} \]      
NumberOfInstances=\arabic{NumberOfInstances}.
\end{document}

enter image description here

For reducing the stepping to one, you need to also modify the definition of \r@@t.

\documentclass{article}
\usepackage{mathtools}
\usepackage{xparse}
\usepackage{letltxmacro}

\makeatletter
\def\mathpalette#1#2{%
  \mathchoice
    {#1\displaystyle{#2}}%
    {\firstchoice@false#1\textstyle{#2}}%
    {\firstchoice@false#1\scriptstyle{#2}}%
    {\firstchoice@false#1\scriptscriptstyle{#2}}}
\def\r@@t#1#2{%
  \ifx#1\displaystyle\else\firstchoice@false\fi
  \setbox\z@\hbox{$\m@th#1\sqrtsign{#2}$}%
  \dimen@\ht\z@ \advance\dimen@-\dp\z@
  \mkern5mu\raise.6\dimen@\copy\rootbox
  \mkern-10mu\box\z@}
\makeatother

\LetLtxMacro{\oldsqrt}{\sqrt}

\makeatletter
\newcommand{\ClosedSqrt}[1][]{\def\DHLindex{#1}\mathpalette\DHLhksqrt}%
\def\DHLhksqrt#1#2{%
  \sbox4{\firstchoice@false$#1\oldsqrt{#2\,}$}\dimen0=\ht4\relax
  \advance\dimen0-0.25\ht0\relax
  \sbox2{\kern-0.375pt\vrule height\ht0 depth -\dimen0}%
  {%
    \hbox{$#1\expandafter\oldsqrt\expandafter[\DHLindex]{#2\,}$}%
    \lower\ifx\math@version\bold@name0.60pt\else0.4pt\fi\box2
  }%
}%
\RenewDocumentCommand{\sqrt}{O{\hphantom{3}} O{0} O{0}  m}{\ClosedSqrt[\leftroot{#2}\uproot{#3}#1]{#4}}%

\newcounter{NumberOfInstances}
\setcounter{NumberOfInstances}{0}
\newcommand*{\MyValue}{%
        \stepcounter{NumberOfInstances}%
    x%
}%
\makeatother

\begin{document}\noindent
NumberOfInstances=\arabic{NumberOfInstances}.
\[ \sqrt{\MyValue} \]      
NumberOfInstances=\arabic{NumberOfInstances}.
\[ \oldsqrt[3]{\MyValue} \]      
NumberOfInstances=\arabic{NumberOfInstances}.
\end{document}

enter image description here

  • perhaps you could make more explicit that the effect of \firstchoice@false is to suppress the \stepcounter/\addtocounter action, that there continues to be the four-fold mathpalette typesetting ? I am not sure but I gather the OP was using \MyValue to count the typesetting phases, maybe I do not quite get what he is aiming at. (in other terms the 20 is still there, but now hidden if the thermometer has been suppressed via \firstchoice@false) – user4686 Dec 17 '15 at 9:37
  • 1
    @jfbu Unfortunately today's train was on schedule, so I hadn't the usual additional time for polishing my answer. – egreg Dec 17 '15 at 9:47
  • So it is safe to redefine \mathpalette? – Peter Grill Dec 17 '15 at 11:04
  • @PeterGrill I see no problem, provided amstext is loaded (via amsmath, usually). – egreg Dec 17 '15 at 12:36
2

A more detailed count. Done without amsmath for clarification, as \ifmeasuring@ is only for querying and setting it can have no effect except surprises.

\documentclass{article}
%\usepackage{mathtools}
\usepackage{xparse}
\usepackage{letltxmacro}

\LetLtxMacro{\oldsqrt}{\sqrt}

\makeatletter
\newcommand{\ClosedSqrt}[1][]{\def\DHLindex{#1}\mathpalette\DHLhksqrt}%
\def\DHLhksqrt#1#2{%
  %\measuring@true
\typeout{Processing DHLhksqrt (#1, start): \the\value{NumberOfInstances}}%
  \setbox0=\hbox{$#1\oldsqrt{#2\,}$}\dimen0=\ht0\relax%
\typeout{Processing DHLhksqrt (#1, after first oldsqrt): \the\value{NumberOfInstances}}%
  \advance\dimen0-0.25\ht0\relax%
  \setbox2=\hbox{\kern-0.375pt\vrule height\ht0 depth -\dimen0}%
  %\measuring@false
  {%
    \hbox{$#1\expandafter\oldsqrt\expandafter[\DHLindex]{#2\,}$}%
    \lower\ifx\math@version\bold@name0.60pt\else0.4pt\fi\box2%
  }%
\typeout{Processing DHLhksqrt (#1, after second oldsqrt): \the\value{NumberOfInstances}}%
}%


%\RenewDocumentCommand{\sqrt}{O{\hphantom{3}} O{0} O{0}  m}{\ClosedSqrt[\leftroot{#2}\uproot{#3}#1]{#4}}%
\RenewDocumentCommand{\sqrt}{O{\hphantom{3}} O{0} O{0}  m}{\ClosedSqrt[#2#3#1]{#4}}%

\newcounter{NumberOfInstances}
\setcounter{NumberOfInstances}{0}
\newcommand*{\MyValue}{%
%    \ifmeasuring@%\else%
        \stepcounter{NumberOfInstances}%
%    \fi
    x%
}%
\makeatother

\begin{document}\noindent
NumberOfInstances=\arabic{NumberOfInstances}.
\[ \sqrt{\MyValue} \]      
NumberOfInstances=\arabic{NumberOfInstances}.
\end{document}

Here is the log:

Processing DHLhksqrt (\displaystyle , start): 0
Processing DHLhksqrt (\displaystyle , after first oldsqrt): 1
Processing DHLhksqrt (\displaystyle , after second oldsqrt): 5
Processing DHLhksqrt (\textstyle , start): 5
Processing DHLhksqrt (\textstyle , after first oldsqrt): 6
Processing DHLhksqrt (\textstyle , after second oldsqrt): 10
Processing DHLhksqrt (\scriptstyle , start): 10
Processing DHLhksqrt (\scriptstyle , after first oldsqrt): 11
Processing DHLhksqrt (\scriptstyle , after second oldsqrt): 15
Processing DHLhksqrt (\scriptscriptstyle , start): 15
Processing DHLhksqrt (\scriptscriptstyle , after first oldsqrt): 16
Processing DHLhksqrt (\scriptscriptstyle , after second oldsqrt): 20

Conclusion: using \sqrt with optional argument causes 4 passes. And 20 = 4x(1+4).

  • in the last sentence \sqrt refers naturally to original \sqrt. – user4686 Dec 17 '15 at 8:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.