8

I want to write a macro that expands differently depending on the pattern following it. Specifically I want to use it to allow a more readable notation for quantum mechanical states, e.g.

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

The way LaTeX works, it can expand only one of the definitions. If I skipped the last one, a possible fix would be to change the catcode of <,|,> to 11, but that brings issues of its own (e.g. by breaking \ifnum .. < .. forms).

Is there some facility in latex, maybe through a package, that allows matching a single macro to multiple patterns of subsequent tokens?

Clarification Because it came up: I don not want to define commands \bra, ket, etc, or rather this is what I did so far. I am trying to move to a solution that results in more readable code and while writing \bra <\psi_i| \Operator \ket |\psi_j> would be a step towards that target, I'd prefer a form as close as possible to <\psi_i|\Operator|\psi_j>; Pattern matching would be the closest solution I could think of that could work without preprocessing outside of latex.

Furthermore writing complex macros, that analyze the token stream, isn't something I want to do on a per-document level. I'd prefer if there was a package that abstracts such things away, such that even the definition of the pattern remains well-readable for the sake of avoiding unexpected behaviour. If TeX's \def natively supported pattern-matching, the example code above would suit that requirement.

19
  • 1
    This can be done using a look-ahead but we need to know the 'conditions'. In particular, how is \m<#1| different from \m<#1|#2>? (We can look after a | for 'something' but will need a clue, for example is the first case always followed by a space?)
    – Joseph Wright
    Feb 19, 2016 at 10:14
  • 1
    @kdb That still doesn't answer the question I posed: how do we differentiate between the first pattern and the last one? What is it that tells us in the first case to stop and not look ahead for a closing >?
    – Joseph Wright
    Feb 19, 2016 at 12:03
  • 2
    @kdb But the pattern will then absorb all of the rest of the document if there is no closing >. You have to have some restriction on what can be present in #2 to allow us to know when to stop!
    – Joseph Wright
    Feb 19, 2016 at 12:24
  • 1
    Pattern-matching on a grabbed argument is easier (either in TeX or as @Mico suggests in Lua). However, you want to do pattern matching to define the grabbed argument, which is harder. For example, if we know that < is always ultimately followed by > we can grab everything up to > then use a variety of approaches to process the text.
    – Joseph Wright
    Feb 19, 2016 at 12:27
  • 2
    If you accept something like \m*...* where ... can have the various forms <#1>, <#1|, |#1>, <#1|#2> or <#1|#2|#3>, then it's doable. But without a fixed terminator it would be very hard and fragile.
    – egreg
    Feb 19, 2016 at 12:38

4 Answers 4

7

UPDATE Embrace the power of expl3 and xparse. I choose the delimiter ; to make the macro possible. To be honest v.2: it was quite simple and I totally lied earlier! This is the new 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

Look how beautiful it is!

enter image description here

You can use the macro as follows: \BrKt<j|\otimes<k|e^{a^\dagger/\hbar}|n>\otimes|m>;, \BrKt|0>|1>|0>|1> = |3>_4; or \BrKt|m>\equiv<\Psi|A|B|\varphi>|n>;$. This allows a much greater variety then originally intended.


Old Post To be honest: I don't think you can't perfectly achieve what you want with little effort. It would be possible though. But if you stick to the basics you could use the power of xparse. I worked out the start

\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

This command structure strictly demands input of the form \m<input1|input2>, however it checks whether input1 or input2 is empty and processes the input accordingly. But note, this cannot create something like <\Psi\Phi>, without the pipe in the middle. Also note, in this realization the opening < is not mandatory and will only produce a warning if it's missing. I hope you can work with this and go on further.

4

This is somewhat possible with the suffix package:

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

However, there's a significant limitation with this approach, in that the same "suffix" can only be used once, so your proposed \m<#1> syntax cannot be supported by this package as well as \m<#1|. This no doubt makes the approach a non-starter, but I thought it would be good to add this answer for completeness.

1
  • 1
    It certainly is the simplest solution that comes close. Since I made the experience that any complicated solution is likely to come back to bite me, that's a plus. But yes, overall it doesn't quite fit the purpose -- it doesn't allow avoiding the verbosity of having different macros instead of one pattern-interpreting macro.
    – kdb
    Feb 19, 2016 at 19:05
4

With expl3 the proposed syntax \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}

And with plain LaTeX and a bit different syntax \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}

enter image description here

PS: instead of \: the usual thing is to use \; but they look too big to me, you could use \nonscript\muskip5mu or whatever you want instead.

3

(Revised the Lua code after noticing that the OP doesn't want "set" notation (with curly braces) for items such as <a|b> but, instead, large angle brackets and a tall middle vertical bar.)

A comment up-front: I strongly recommend that you use a delimiter symbol that's unlikely to occur in your braket-like expressions. That way, no ambiguity can arise as to when these expressions starts and when they end. In the code below, I use & as this symbol; feel free to switch to a different one.

I'd prefer a form as close as possible to <\psi_i|\Operator|\psi_j>

With the notational convention I'm proposing, you'd write & <\psi_i|\Operator|\psi_j> &.

Here's a LuaLaTeX-based solution. The Lua function brkt is set to scan each input line and perform sequential pattern matching. Patterns for which there's a match are converted into instructions that use the macros of the braket package -- \Braket, \Bra, and \Ket. The scanning and replacing happens at a very early stage of processing, i.e., before TeX's "eyes" and "mouth" begin their work.

Two TeX-side macros are provided as well: \braketON to start the processing, and \braketOFF in case you need to stop processing at some point in the document.

enter image description here

% !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}
3
  • Probably having \m at the start can help in avoiding problems if multiple calls are present in the same line: just stop scanning when \m is seen.
    – egreg
    Feb 19, 2016 at 15:06
  • I'm unsure what happens if you try <\phi| < 2 or something like that.
    – egreg
    Feb 19, 2016 at 15:11
  • @egreg - I decided to rework the answer so that it assumes that the braket-like expressions are delimited by symbols that act as delimiters. I suggest using & as such a delimiter; obviously, there are many other possibilities. As you and Joseph noted in earlier comments, the presence of such explicit delimiters guarantees that the pattern matching can be carried out unambiguously.
    – Mico
    Feb 19, 2016 at 16:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .