\ThisStyle \SavedStyle 速度非常慢......有其他选择吗?

\ThisStyle \SavedStyle 速度非常慢......有其他选择吗?

在使用第一版定制帽子字形时此解决方案pdflatex开始需要很长时间才能编译文档。链接的答案指出这是一个较慢的解决方案,但最初速度很慢,但这并不重要。然后,在我使用两顶堆叠的帽子后,它变得可以忍受缓慢。在我去调查并堆叠了三顶帽子之后,它变得非常慢。

简单来说原因如下:

  \documentclass[12pt, a4paper]{article}
  \usepackage{scalerel}

  \begin{document}
  \ensuremath{
  \ThisStyle{
      \SavedStyle\ThisStyle{
      \SavedStyle\ThisStyle{
      \SavedStyle\ThisStyle{
      \SavedStyle\ThisStyle{
      \SavedStyle\ThisStyle{
      \SavedStyle\ThisStyle{
      \SavedStyle\ThisStyle{
          \SavedStyle . }}}}}}}
  }}
  \end{document}

使用pdflatex或需要 15 秒latex。如果我们弹出一层嵌套,则时间缩短至 2 秒,而添加比示例多一层的嵌套,则时间缩短至 269 秒。

显然,事情正在呈指数级增长。scalerel.sty\SavedStyle,和的代码\ThisStyle如下:

\def\SavedStyle{\csname @mstyle\m@switch\endcsname}


\newcommand\ThisStyle[1]{%
  \ifmmode%
    \def\@mmode{T}\mathchoice%
      {\edef\m@switch{D}\LMex=1ex\relax\LMpt=1pt\relax#1}%
      {\edef\m@switch{T}\LMex=1ex\relax\LMpt=1pt\relax#1}%
      {\edef\m@switch{S}\LMex=\scriptstyleScaleFactor ex\relax%
                        \LMpt=\scriptstyleScaleFactor pt\relax#1}%
      {\edef\m@switch{s}\LMex=\scriptscriptstyleScaleFactor ex\relax%
                        \LMpt=\scriptscriptstyleScaleFactor pt\relax#1}%
  \else%
    \def\@mmode{F}%
    \edef\m@switch{T}\LMex=1ex\relax\LMpt=1pt\relax#1%
  \fi%
}

我猜想 的参数\ThisStyle在每个级别都会被扩展四次。换句话说,\mathchoice并不懒惰。

有没有办法将#1这些参数排除在外\mathchoice,同时仍保留相同的行为?这些\m@switch\LMex定义是否在下一个“ }”之后继续存在?

如果没有,还有其他方法可以实现\ThisStyle,\SavedStyle等效效果吗?我想不出有什么方法可以在嵌套深度方面以线性时间工作,并且在存在可重入性的情况下仍能正常工作。

答案1

简短的回答:不可以——没有办法在所有情况下或一次 LaTeX 传递中正确地做到这一点。


经过大量的学习和实验,似乎解决这个问题的唯一方法就是曼努埃尔的回答和评论在这里. 不存在这样的事\whatIsTheMathStyleHere除非我们用的是 LuaTeX)。 这\mathchoice命令是一个 TeX 原语四个选项的选择晚的要理解“late”的含义,我们需要了解 TeX 具有几个消化阶段:眼睛,嘴巴,食道、胃,每个部分都通过语义上有意义的标记子集,将逻辑文档转换成更接近最终视觉文档的形式。有时它会回到之前的阶段。(但是,我们所期待的几乎好得令人难以置信的排版智能,难道不值得一定程度的复杂性吗?)那么,围绕\mathchoice 其参数内部的 会在应用自身之前进行宏扩展\mathchoice。事实上,据我所知,不仅是扩展,其他 TeX 命令(例如 )\ifx也会在 之前进行处理\mathchoice,因此在处理的每个阶段中可能会有多个分层子阶段?

Manuel 的替代方案名为\mathcase,它使用了一个巧妙的技巧,即插入一个纳米级空间,其大小取决于数学样式。然后它检查空间的大小并确定样式。如果只有在文档成为完全解析的结构后才能确定所有地方的最终数学样式,那么这怎么能行得通呢?它使用包来实现这一点zref-savepos。阅读 的文档zref,有一条注释:

页面位置不是立即知道的。首先必须通过 TEX 的异步输出例程构造页面。因此,知道位置的时间就是页面输出时间。因此,在第一次运行中记录信息并在第二次运行中可用的参考系统非常有用。

换句话说,正确的数学风格取决于出口,此时它不能用于任何\if或其他决策结构,但它存储在 AUX 文件中(如您通过检查下面示例的 AUX 文件所看到的那样),并在第二遍中可用。

不幸的是,这会导致以下问题,级联数学样式会向下传播一系列嵌套的\mathcases:如果嵌套深度为 N 层,则在编译 N 次之前,文档无法保证稳定。例如:

(这是来自曼努埃尔的回答,我刚刚改变了文档主体。)

\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}

\let\savedstyle\displaystyle

\def\thisstyle#1{\begingroup\mathcase{\let\savedstyle\displaystyle}{\let\savedstyle\textstyle}{\let\savedstyle\scriptstyle}{\let\savedstyle\scriptscriptstyle}#1\endgroup}

\begin{document}

\[
\sum \scriptstyle \sum \thisstyle{%
    \fbox{\( \sum \savedstyle \sum \thisstyle{%
    \fbox{\( \sum \savedstyle \sum \thisstyle{%
    \fbox{\( \sum \savedstyle \sum \)}%
    }\)}%
    }\)}%
}
\]

\end{document}

在编译 PDF 时,使用 TeXworks 查看器查看 PDF,我们看到:

第一遍之后:

第一

第二遍之后:

第二

第三次传递后:

第三

第四遍之后:

第四

因此,该解决方案以传递次数为代价来提高每次传递的速度。(不过,如果在文档尚未稳定时也发出警告就更好了。)虽然这不是一个完美的解决方案,但我相信,考虑到 TeX 的性质(而且 TeX 本身在可预见的未来不太可能在这方面发生变化),这几乎是最好的替代方案。

还有mathstyle包(参见此处的讨论\mathchoice),通过利用所有数学模式分隔符(但\(显然不是!),并注入一些逻辑来跟踪当前的数学样式,与 TeX 无关。但是,正如Aditya 的评论在这里,有些情况下它无法预测 TeX 的行为。例如,使用\overTeX\atop原语。(不过这条评论已经有 5 年了。也许在此期间它已经变得更好了?)

因此,最好的答案是尽可能减少\mathchoice嵌套级别数(请注意,a\mathchoice包含在\ThisStyle\text、等中)(例如\mathpalette\TextStyle我删除了前置问题中的几个多余的),或者如果你能用常识推理推断出数学风格,那么你可以重新定义\mathchoice本地以短路

总而言之,这是一个令人惊讶的结果。这是我第一次想用 LaTeX 做点什么,但结果却不切实际。此外,在尝试破解时\mathchoice,我遇到了宏语言的所有麻烦,你永远不知道什么会以什么顺序扩展。(只需看看“经典”方式\expandafter\expandafter\expandafter\expandafter\expandafter...方式此解决方案,你就知道有些不对劲了。)最后,对于 70 年代的软件来说,的语义\mathchoice似乎有些低效,即使它的预期目的只是排版一个自定义符号……

相关内容