Ao trabalhar com glifos de chapéu personalizados usando a primeira versão doesta solução, pdflatex
comecei a demorar muito para compilar um documento. Essa resposta vinculada observa que é uma solução mais lenta, mas inicialmente foi lenta, o que não importava. Então ficou toleravelmente lento depois que usei dois chapéus empilhados. E depois que fui investigar e empilhei três chapéus, tornou-se uma eternidade lenta.
Aqui está um motivo resumido:
\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}
Isso leva 15 segundos com pdflatex
ou latex
. Se retirarmos um nível de aninhamento, ele será reduzido para 2 segundos, e adicionando mais um nível do que no exemplo, obteremos 269 segundos.
Claramente, há algo exponencial acontecendo. Olhando dentroscalerel.sty, o código para \SavedStyle
e \ThisStyle
é o seguinte:
\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%
}
Meu palpite é que o argumento é \ThisStyle
expandido quatro vezes em todos os níveis. Em outras palavras, \mathchoice
não é preguiçoso.
Existe uma maneira de eliminar #1
esses \mathchoice
argumentos e ainda manter o mesmo comportamento? Essas \m@switch
e \LMex
definições sobrevivem além do próximo " }
"?
Caso contrário, existe alguma outra abordagem para fazer o \ThisStyle
equivalente \SavedStyle
? Não consigo pensar em nada que funcione em tempo linear com relação à profundidade do aninhamento e ainda funcione corretamente na presença de reentrada.
Responder1
Resposta curta: não — não há como fazer isso corretamente em todas as situações ou em uma passagem do LaTeX.
Depois de muito aprendizado e experimentação, parece que a única maneira de contornar isso é algo comoResposta e comentário do Manuel aqui. Não existe tal coisa como \whatIsTheMathStyleHere
(a menos que estejamos no LuaTeX). O\mathchoice
comando é uma primitiva TeX.A escolha das quatro opções é feitatarde. Para entender o que significa "atrasado", precisamos entender que o TeXalguns estágios digestivos: olho, boca,esôfago, estômago, cada um dos quais transforma o documento lógico em uma forma mais próxima do documento visual final, trabalhando através de um subconjunto de tokens semanticamente significativos.Às vezes, volta ao estágio anterior.(Mas a inteligência tipográfica quase boa demais para ser verdade que esperamos não justifica algum grau de complexidade?) Então, as coisas que cercam\mathchoice
edentro de seus argumentos é macro-expandido antes de \mathchoice
ser aplicado. Na verdade, até onde eu sei, não apenas a expansão, mas outros comandos TeX, como \ifx
, são processados antes \mathchoice
, portanto, dentro de cada estágio de processamento pode haver vários subestágios estratificados?
A alternativa de Manuel, chamada \mathcase
, usa um truque inteligente, onde é inserido um espaço em nanoescala, de tamanho dependente do estilo matemático. E então verifica o tamanho do espaço e determina o estilo. Como isso pode funcionar, se o estilo matemático final em todos os lugares deve ser determinado somente depois que o documento se torna uma estrutura totalmente resolvida? Isso é feito usando o zref-savepos
pacote. Lendo a documentação do zref
, há uma observação:
A posição da página não é conhecida instantaneamente. Primeiro a página deve ser construída pela rotina de saída assíncrona do TEX. Assim, o tempo em que a posição é conhecida é o tempo de envio da página. Assim, um sistema de referência onde a informação é registada na primeira execução e disponibilizada para utilização na segunda execução é útil.
Em outras palavras, o estilo matemático correto é determinado emenvio, ponto em que ele não pode ser usado em nenhuma \if
ou outras estruturas de tomada de decisão, mas é armazenado no arquivo AUX (como você pode ver inspecionando o arquivo AUX no exemplo abaixo) e fica disponível durante a segunda passagem .
Infelizmente, isso causa o seguinte tipo de problema, com estilos matemáticos em cascata se propagando por uma série aninhada de \mathcase
s: se o aninhamento tiver N níveis de profundidade, então não é garantido que o documento seja estável até que seja compilado N vezes. Por exemplo:
(Isto é deA resposta de Manoel, onde acabei de alterar o corpo do documento.)
\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}
Olhando para o PDF no visualizador TeXworks durante a compilação, vemos:
Após a primeira passagem:
Após a segunda passagem:
Após a terceira passagem:
Após a quarta passagem:
Portanto, a solução compensa o número de passagens para melhorar a velocidade de cada passagem. (Embora fosse bom se ele também avisasse quando o documento ainda não está estável.) Embora não seja uma solução perfeita, estou convencido de que esta é a melhor alternativa possível, dada a natureza do TeX (e do TeX é pouco provável que este aspecto mude num futuro próximo).
Há também o mathstyle
pacote (veja a discussão aqui), que funciona \mathchoice
tocando em todos os delimitadores do modo matemático (mas\(
aparentemente não!), e injetando alguma lógica para acompanhar qual será o estilo matemático atual, fora de sintonia com o TeX. Mas, como apontado emComentário de Aditya aqui, há casos em que ele não consegue prever o comportamento do TeX. Por exemplo, com o uso de \over
primitivas \atop
TeX. (O comentário já tem 5 anos. Talvez tenha melhorado nesse meio tempo?)
Portanto, a melhor resposta é reduzir o número de \mathchoice
níveis de aninhamento (observe que a \mathchoice
está contido em \ThisStyle
, \text
, \mathpalette
, etc.) sempre que possível (por exemploEu removi alguns redundantes \TextStyle
na pergunta precursora), ou se você puder inferir o estilo matemático usando o raciocínio de bom senso, você poderiaredefinir \mathchoice
localmente para causar curto-circuito.
Em suma, é um resultado surpreendente. Esta é a primeira vez que quis fazer algo com LaTeX e acabou sendo impraticável. Além disso, ao tentar hackear \mathchoice
, encontrei todos os horrores das linguagens macro, onde você nunca sabe ao certo o que vai se expandir e em que ordem. (Basta dar uma olhada no jeito "clássico" de estar \expandafter\expandafter\expandafter\expandafter\expandafter...
emesta solução, e você sabe que algo está errado.) Finalmente, para software dos anos setenta, a semântica de \mathchoice
parece um tanto ineficiente, mesmo que seu objetivo seja apenas compor um único símbolo personalizado...