\ThisStyle \SavedStyle dolorosamente lento ... alternativas?

\ThisStyle \SavedStyle dolorosamente lento ... alternativas?

Ao trabalhar com glifos de chapéu personalizados usando a primeira versão doesta solução, pdflatexcomecei 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 pdflatexou 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 \SavedStylee \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 é \ThisStyleexpandido quatro vezes em todos os níveis. Em outras palavras, \mathchoicenão é preguiçoso.

Existe uma maneira de eliminar #1esses \mathchoiceargumentos e ainda manter o mesmo comportamento? Essas \m@switche \LMexdefinições sobrevivem além do próximo " }"?

Caso contrário, existe alguma outra abordagem para fazer o \ThisStyleequivalente \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\mathchoicecomando é 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 \mathchoiceser 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-savepospacote. 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 \ifou 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 \mathcases: 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:

1º

Após a segunda passagem:

2º

Após a terceira passagem:

3º

Após a quarta passagem:

4º

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 mathstylepacote (veja a discussão aqui), que funciona \mathchoicetocando 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 \overprimitivas \atopTeX. (O comentário já tem 5 anos. Talvez tenha melhorado nesse meio tempo?)

Portanto, a melhor resposta é reduzir o número de \mathchoiceníveis de aninhamento (observe que a \mathchoiceestá contido em \ThisStyle, \text, \mathpalette, etc.) sempre que possível (por exemploEu removi alguns redundantes \TextStylena pergunta precursora), ou se você puder inferir o estilo matemático usando o raciocínio de bom senso, você poderiaredefinir \mathchoicelocalmente 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 \mathchoiceparece um tanto ineficiente, mesmo que seu objetivo seja apenas compor um único símbolo personalizado...

informação relacionada