При работе с индивидуальными символами шляпы с использованием первой версииэто решение, 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 в примере ниже) и становится доступным во время второго прохода.
К сожалению, это приводит к следующему виду проблем с каскадными математическими стилями, распространяющимися вниз по вложенной серии \mathcase
s: если вложение имеет глубину 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 во время его компиляции, мы видим:
После первого прохода:
После второго прохода:
После третьего прохода:
После четвертого прохода:
Таким образом, решение компенсирует количество проходов, чтобы повысить скорость каждого прохода. (Хотя было бы хорошо, если бы оно также предупреждало вас, когда документ еще не стабилен.) Хотя это и не идеальное решение, я убежден, что это едва ли не лучшая возможная альтернатива, учитывая природу 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
кажется несколько неэффективной, даже если ее предполагаемое назначение — просто набор одного пользовательского символа...