Macro: Expandir de forma diferente dependendo do padrão?

Macro: Expandir de forma diferente dependendo do padrão?

Quero escrever uma macro que se expanda de maneira diferente dependendo do padrão que a segue. Especificamente, quero usá-lo para permitir uma notação mais legível para estados da mecânica quântica, por exemplo

% Non-working example
\def \m<#1|    { \left\langle #1 \right|}
\def \m|#1>    { \left|       #1 \right\rangle }
\def \m<#1>    { \left\langle #1 \right\rangle }
\def \m<#1|#2> { \left\langle #1 \middle| #2 \right\rangle }

Da forma como o LaTeX funciona, ele pode expandir apenas uma das definições. Se eu pulasse o último, uma possível solução seria alterar o catcode de <, |, >para 11, mas isso traz seus próprios problemas (por exemplo, quebrando \ifnum .. < ..formulários).

Existe alguma facilidade no látex, talvez através de um pacote, que permite combinar uma única macro com vários padrões de tokens subsequentes?

EsclarecimentoPorque surgiu: não quero definir comandos \bra, ket, etc, ou melhor, foi isso que fiz até agora. Estou tentando mudar para uma solução que resulte em um código mais legível e, embora escrever \bra <\psi_i| \Operator \ket |\psi_j>seja um passo em direção a esse objetivo, prefiro um formulário o mais próximo possível <\psi_i|\Operator|\psi_j>; A correspondência de padrões seria a solução mais próxima que eu poderia imaginar que poderia funcionar sem pré-processamento fora do látex.

Além disso, escrever macros complexas, que analisam o fluxo de tokens, não é algo que eu queira fazer por documento. Eu preferiria que houvesse um pacote que abstraísse essas coisas, de modo que até mesmo a definição do padrão permanecesse bem legível para evitar comportamentos inesperados. Se a correspondência de padrões fosse suportada nativamente pelo TeX \def, o código de exemplo acima atenderia a esse requisito.

Responder1

ATUALIZARAbrace o poder de expl3e xparse. Eu escolho o delimitador ;para tornar a macro possível. Para ser sincero v.2: foi bem simples e eu menti totalmente antes! Esta é a nova macro

\ExplSyntaxOn
\tl_new:N \kdb_temp
\DeclareDocumentCommand{\BrKt}{u;}%
{
    \left.
    \tl_set:Nn \kdb_temp {#1}
    \tl_replace_all:Nnn \kdb_temp{<}{\middle\langle}
    \tl_replace_all:Nnn \kdb_temp{|}{\middle|}
    \tl_replace_all:Nnn \kdb_temp{>}{\middle\rangle}
    \tl_use:N \kdb_temp
    \right.
}
\ExplSyntaxOff

Olha que lindo!

insira a descrição da imagem aqui

Você pode usar a macro da seguinte maneira: \BrKt<j|\otimes<k|e^{a^\dagger/\hbar}|n>\otimes|m>;, \BrKt|0>|1>|0>|1> = |3>_4;ou \BrKt|m>\equiv<\Psi|A|B|\varphi>|n>;$. Isto permite uma variedade muito maior do que a originalmente pretendida.


Postagem antiga Para ser honesto: não acho que você não consiga alcançar perfeitamente o que deseja com pouco esforço. Seria possível, no entanto. Mas se você seguir o básico, poderá usar o poder do xparse. Eu planejei o começo

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareDocumentCommand{\m}{t< u{|} u>}%
{
    \IfBooleanTF{#1}{}{\GenericWarning{}{Watch out! A missing "<" encountered!}}
    \if\relax\detokenize{#2}\relax
        \if\relax\detokenize{#3}\relax
%           \langle\rangle
        \else
            \left| #3\right\rangle
        \fi
    \else
        \if\relax\detokenize{#3}\relax
            \left\langle #2\right|
        \else
            \left\langle #2 \middle| #3\right\rangle
        \fi
    \fi
}
\ExplSyntaxOff

Esta estrutura de comando exige estritamente a entrada do formulário \m<input1|input2>, porém verifica se input1ou input2está vazio e processa a entrada de acordo. Mas observe, isso não pode criar algo como <\Psi\Phi>, sem o cano no meio. Observe também que nesta realização a abertura <não é obrigatória e só produzirá um aviso se estiver faltando. Espero que você possa trabalhar com isso e seguir em frente.

Responder2

Isso é possível com o pacote de sufixo:

\documentclass{article}
\usepackage{suffix}
\begin{document}
\WithSuffix\def\m<#1|{\left\langle #1 \right|}
\WithSuffix\def\m|#1>{\left|       #1 \right\rangle}
\[ \m<x| \quad \m|y>  \]
\end{document}

No entanto, há uma limitação significativa nesta abordagem, pois o mesmo "sufixo" só pode ser usado uma vez, portanto a \m<#1>sintaxe proposta não pode ser suportada por este pacote tão bem quanto pelo \m<#1|. Isso, sem dúvida, torna a abordagem um fracasso, mas achei que seria bom adicionar esta resposta para completar.

Responder3

Com expl3a sintaxe proposta \m{<x|y>}.

\documentclass{article}

\usepackage{mathtools,xparse}
\usepackage{mleftright}

\ExplSyntaxOn
\NewDocumentCommand \m { m } { \kdb_m:n {\begm#1\endm} }
\cs_new_protected:Npn \kdb_m:n #1
 {
  \group_begin:
   \tl_set:Nn \l_tmpa_tl {#1}
   \tl_replace_once:Nnn \l_tmpa_tl { \begm< } { \mleft\langle  }
   \tl_replace_once:Nnn \l_tmpa_tl { \begm| } { \mleft\lvert   }
   \tl_replace_once:Nnn \l_tmpa_tl { >\endm } { \mright\rangle }
   \tl_replace_once:Nnn \l_tmpa_tl { |\endm } { \mright\rvert  }
   \tl_replace_all:Nnn \l_tmpa_tl { | } { \:\middle\vert\: }
   \tl_use:N \l_tmpa_tl
  \group_end:
 }
\ExplSyntaxOff

\begin{document}

\[
  \m{<x>} \quad \m{<x|} \quad \m{|x>} \quad \m{<x|y|z>} \quad \m{<x^{2^{2^{2^{2^{2^2}}}}}|y>}
\]

\end{document}

E com LaTeX simples e uma sintaxe um pouco diferente \m<x|>.

\documentclass{article}

\usepackage{mathtools}
\usepackage{mleftright}

\makeatletter
\def\activevert{\@ifnextchar\mlast{\mright\rvert\@gobble}{\:\middle\vert\:}}
{\catcode`\|=\active\gdef|{\activevert}}
\gdef\m<#1>{\begingroup\mathcode`\|="8000
   \@ifnextchar|{\mleft\lvert\@gobble}{\mleft\langle}#1\mlast\endgroup}
\def\mlast{\mright\rangle}
\makeatother

\begin{document}

\[
  \m<x> \quad \m<x|> \quad \m<|x> \quad \m<x|y|z> \quad \m<x^{2^{2^{2^{2^{2^2}}}}}|y>
\]

\end{document}

insira a descrição da imagem aqui

PS: em vez do \:habitual é usar \;mas me parecem grandes demais, você pode usar \nonscript\muskip5muou o que quiser.

Responder4

(Revisou o código Lua depois de perceber que o OP não deseja a notação "definida" (com chaves) para itens como <a|b>, mas, em vez disso, colchetes grandes e uma barra vertical central alta.)

Um comentário inicial: recomendo fortemente que você use um símbolo delimitador que provavelmente não ocorrerá em suas expressões do tipo freio. Dessa forma, nenhuma ambigüidade pode surgir sobre quando essas expressões começam e quando terminam. No código abaixo, utilizo &como este símbolo; sinta-se à vontade para mudar para um diferente.

Eu preferiria um formulário o mais próximo possível de<\psi_i|\Operator|\psi_j>

Com a convenção de notação que estou propondo, você escreveria & <\psi_i|\Operator|\psi_j> &.

Aqui está uma solução baseada em LuaLaTeX. A função Lua brktestá configurada para varrer cada linha de entrada e realizar correspondência sequencial de padrões. Os padrões para os quais há correspondência são convertidos em instruções que usam as macros do braketpacote -- \Braket, \Bra, e \Ket. A digitalização e a substituição acontecem numa fase muito inicial do processamento, ou seja,antesOs “olhos” e “boca” do TeX começam seu trabalho.

Duas macros do lado do TeX também são fornecidas: \braketONpara iniciar o processamento e \braketOFFcaso você precise interromper o processamento em algum ponto do documento.

insira a descrição da imagem aqui

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode,braket,mathtools,mleftright}
\DeclarePairedDelimiter\abs\lvert\rvert % just for this example

%% Lua-side code
\begin{luacode}
function brkt ( buff )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)|([^&]-)|([^&]-)>[%s]-&", "\\Braket{%1|%2|%3}" )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)|([^&]-)>[%s]-&" , "\\mleft\\langle %1\\;\\middle|\\; %2\\mright\\rangle" )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)>[%s]-&", "\\mleft\\langle %1\\mright\\rangle " )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)%|[%s]-&", "\\Bra{%1}" )
  buff = string.gsub ( buff, "&[%s]-|([^&]-)>[%s]-&", "\\Ket{%1}" )  
  return buff
end
\end{luacode}

%% TeX-side code
\newcommand\braketON{\directlua{%
  luatexbase.add_to_callback ( "process_input_buffer", brkt, "brkt" )}}
\newcommand\braketOFF{\directlua{%
  luatexbase.remove_from_callback ( "process_input_buffer", "brkt" )}}

\begin{document}
\braketON

$
&< \phi | \frac{\partial^2}{\partial t^2} | \psi > &, \quad
&   <x\in\mathbf{R}^2 | 0<\abs*{\frac{x}{2}}<5 > & , \quad
& <\frac{a}{b},\frac{c}{d}> &$

\medskip
$ \displaystyle
&  < \phi | \frac{\partial^2}{\partial t^2} | \psi > &, \quad
&<x\in\mathbf{R}^2 | 0<\abs*{\frac{x}{2}}<5 >&,
\quad
& <\frac{a}{b},\frac{c}{d}> &$

\medskip
$ &<A|&, &<B|&, &|C>&,  &<D|& $

\bigskip
$ & <x^{2^{2^{2^{2^{2^2}}}}}|y> &$ % with a nod to @Manuel's code :-)
\end{document}

informação relacionada