Macro: ¿Expandir de manera diferente según el patrón?

Macro: ¿Expandir de manera diferente según el patrón?

Quiero escribir una macro que se expanda de manera diferente según el patrón que la sigue. Específicamente quiero usarlo para permitir una notación más legible para estados de mecánica cuántica, por ejemplo

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

Tal como funciona LaTeX, sólo puede ampliar una de las definiciones. Si me salté el último, una posible solución sería cambiar el código cat de <, |, >a 11, pero eso trae sus propios problemas (por ejemplo, al romper \ifnum .. < ..formularios).

¿Existe alguna función en látex, tal vez a través de un paquete, que permita hacer coincidir una sola macro con múltiples patrones de tokens posteriores?

AclaraciónPorque surgió: no quiero definir comandos \bra, ket, etc, o mejor dicho esto es lo que hice hasta ahora. Estoy intentando pasar a una solución que dé como resultado un código más legible y, aunque escribir \bra <\psi_i| \Operator \ket |\psi_j>sería un paso hacia ese objetivo, preferiría un formulario lo más parecido posible a <\psi_i|\Operator|\psi_j>; La coincidencia de patrones sería la solución más cercana que se me ocurre y que podría funcionar sin preprocesamiento fuera del látex.

Además, escribir macros complejas que analicen el flujo de tokens no es algo que quiera hacer a nivel de documento. Preferiría que hubiera un paquete que abstraiga tales cosas, de modo que incluso la definición del patrón siga siendo bien legible para evitar comportamientos inesperados. Si TeX \defadmite de forma nativa la coincidencia de patrones, el código de ejemplo anterior se adaptaría a ese requisito.

Respuesta1

ACTUALIZARAbraza el poder de expl3y xparse. Elijo el delimitador ;para hacer posible la macro. Para ser honesto, v.2: ¡fue bastante simple y mentí totalmente antes! Esta es la nueva 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

¡Mira qué bonito es!

ingrese la descripción de la imagen aquí

Puede utilizar la macro de la siguiente manera \BrKt<j|\otimes<k|e^{a^\dagger/\hbar}|n>\otimes|m>;: \BrKt|0>|1>|0>|1> = |3>_4;o \BrKt|m>\equiv<\Psi|A|B|\varphi>|n>;$. Esto permite una variedad mucho mayor de la prevista originalmente.


Publicación antigua Para ser honesto: no creo que no puedas lograr perfectamente lo que quieres con poco esfuerzo. Aunque sería posible. Pero si te ciñes a lo básico, podrías utilizar el poder de xparse. resolví el comienzo

\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 estructura de comando exige estrictamente una entrada del formulario \m<input1|input2>, sin embargo, verifica si input1o input2está vacío y procesa la entrada en consecuencia. Pero tenga en cuenta que esto no puede crear algo como <\Psi\Phi>, sin la tubería en el medio. También tenga en cuenta que, en esta realización, la apertura <no es obligatoria y solo producirá una advertencia si falta. Espero que puedas trabajar con esto y seguir adelante.

Respuesta2

Esto es algo posible con el paquete de sufijos:

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

Sin embargo, hay una limitación significativa con este enfoque, ya que el mismo "sufijo" sólo se puede usar una vez, por lo que la \m<#1>sintaxis propuesta no puede ser compatible con este paquete ni con \m<#1|. Sin duda, esto hace que el enfoque no sea un comienzo, pero pensé que sería bueno agregar esta respuesta para que esté completo.

Respuesta3

Con expl3la sintaxis propuesta \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}

Y con LaTeX simple y una sintaxis un poco 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}

ingrese la descripción de la imagen aquí

PD: en lugar de \:lo habitual es usar \;pero a mí me parecen muy grandes, podrías usar \nonscript\muskip5muo lo que quieras en su lugar.

Respuesta4

(Se revisó el código Lua después de notar que el OP no quiere notación "establecida" (con llaves) para elementos como <a|b>pero, en su lugar, corchetes angulares grandes y una barra vertical media alta.)

Un comentario inicial: le recomiendo encarecidamente que utilice un símbolo delimitador que es poco probable que aparezca en sus expresiones tipo paréntesis. De esta forma, no puede surgir ninguna ambigüedad sobre cuándo comienzan y cuándo terminan estas expresiones. En el código siguiente, utilizo &este símbolo; no dudes en cambiar a uno diferente.

Preferiría una forma lo más cercana posible a<\psi_i|\Operator|\psi_j>

Con la convención de notación que propongo, escribirías & <\psi_i|\Operator|\psi_j> &.

Aquí hay una solución basada en LuaLaTeX. La función Lua brktestá configurada para escanear cada línea de entrada y realizar una coincidencia de patrones secuencial. Los patrones para los que hay una coincidencia se convierten en instrucciones que utilizan las macros del braketpaquete -- \Braket, \Bray \Ket. El escaneo y el reemplazo ocurren en una etapa muy temprana del procesamiento, es decir,antesLos "ojos" y la "boca" de TeX comienzan su trabajo.

También se proporcionan dos macros del lado TeX: \braketONpara iniciar el procesamiento y \braketOFFen caso de que necesite detener el procesamiento en algún momento del documento.

ingrese la descripción de la imagen aquí

% !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}

información relacionada