\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 秒。

顯然,正在發生指數級的變化。調查尺度相關性\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 原語四個選項的選擇已完成晚的。要理解「遲到」的含義,我們需要了解 TeX 具有幾個消化階段:眼睛、嘴巴、食道,胃,每個都通過語義上有意義的標記的子集將邏輯文檔轉換為更接近最終視覺文檔的形式。有時它會回到前一個階段。(但是,我們所期望的幾乎好得令人難以置信的排版智慧難道不證明一定程度的複雜性是合理的嗎?)\mathchoice \mathchoice在應用其自身之前,其參數內部會進行巨集擴展。事實上,據我所知,不僅僅是擴展,還有其他 TeX 命令,例如\ifx,在 之前得到處理\mathchoice,所以在每個處理階段中可能有幾個分層的子階段?

曼努埃爾的替代方案稱為\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}

編譯時在 TeXworks 檢視器中查看 PDF,我們看到:

第一遍之後:

第一名

第二遍之後:

第二名

第三遍之後:

第三名

第四遍之後:

第四名

因此,此解決方案會權衡傳遞次數以提高每次傳遞的速度。 (不過,如果它在文件尚未穩定時也向您發出警告,那就太好了。)雖然這不是一個完美的解決方案,但考慮到TeX(以及TeX)的性質,我相信這只是可能的最佳替代方案在可預見的將來,這方面本身不太可能改變)。

還有一個mathstyle包包(請參閱此處的討論\mathchoice),它透過利用所有數學模式分隔符號來解決(但是\(顯然不! ),並注入一些邏輯來追蹤當前的數學風格,在 TeX 之外。但是,正如指出的Aditya 的評論在這裡,在某些情況下它無法預測 TeX 的行為。例如,使用\over, \atopTeX 原語。 (不過這條評論已經有 5 年歷史了。也許在此期間它已經變得更好了?)

所以最好的答案是減少\mathchoice嵌套的層數(注意 a\mathchoice包含在\ThisStyle, \text,\mathpalette等)(例如我去掉了一些多餘的\TextStyle我刪除了前導問題中的),或者如果您可以使用常識推理來推斷數學風格,您可以重新定義\mathchoice以使其短路

總而言之,這是一個令人驚訝的結果。這是我第一次想用 LaTeX 做點什麼,但結果證明這是不切實際的。另外,在嘗試破解時\mathchoice,我遇到了宏語言的所有恐怖之處,你永遠不知道什麼會以什麼順序擴展。 (看看「經典」方式是\expandafter\expandafter\expandafter\expandafter\expandafter...這個解決方案\mathchoice,你知道出了什麼問題。

相關內容