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

Это занимает 15 секунд с pdflatexили 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.Выбор из четырех вариантов производитсяпоздноЧтобы понять, что означает «поздно», нам нужно признать, что 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}

Просматривая PDF-файл в программе просмотра TeXworks во время его компиляции, мы видим:

После первого прохода:

1-й

После второго прохода:

2-й

После третьего прохода:

3-й

После четвертого прохода:

4-й

Таким образом, решение компенсирует количество проходов, чтобы повысить скорость каждого прохода. (Хотя было бы хорошо, если бы оно также предупреждало вас, когда документ еще не стабилен.) Хотя это и не идеальное решение, я убежден, что это едва ли не лучшая возможная альтернатива, учитывая природу TeX (и сам TeX вряд ли изменится в этом отношении в обозримом будущем).

Также есть mathstyleпакет (см. обсуждение здесь), который работает \mathchoiceпутем использования всех разделителей математического режима (но\(по-видимому, нет!), и вводить некоторую логику, чтобы отслеживать, каким будет текущий математический стиль, вне диапазона TeX. Но, как указано вКомментарий Адитьи здесь, есть случаи, когда он не может предсказать поведение TeX. Например, при использовании \over, \atopпримитивов TeX. (Хотя комментарию уже 5 лет. Может быть, за это время он стал лучше?)

Поэтому лучшим ответом будет сокращение количества \mathchoiceуровней вложенности (обратите внимание, что a \mathchoiceсодержится в \ThisStyle, \text, \mathpalette, и т.д.) там, где это возможно (например,Я удалил несколько лишних \TextStyleбукв в предыдущем вопросе.), или если вы можете вывести математический стиль, используя здравый смысл, вы могли быпереопределить \mathchoiceлокально, чтобы замкнуть его.

В общем, это удивительный результат. Это первый раз, когда я хотел что-то сделать с LaTeX, и это оказалось непрактичным. Кроме того, пытаясь хакнуть \mathchoice, я столкнулся со всеми ужасами макроязыков, где вы никогда не знаете, что будет расширяться в каком порядке. (Просто взгляните на "классический" способ, находящийся \expandafter\expandafter\expandafter\expandafter\expandafter...вэто решение, и вы понимаете, что что-то не так.) Наконец, для программного обеспечения семидесятых годов семантика \mathchoiceкажется несколько неэффективной, даже если ее предполагаемое назначение — просто набор одного пользовательского символа...

Связанный контент