# What's wrong with my braket macro?

Based on egreg's alternate solution to my previous question from which I learned the idea of making characters into macros, I've now defined a different syntax for bra-kets which I actually like even more. My macro almost works (although there's a bit of cargo cult programming going on here because I've copied some part of his solution which I didn't fully understand — the two lines beginning with \begingroup\lccode — in my macro and adapted them slightly; I suspect the problem is in there, because the rest I believe I understand sufficiently, thanks to egregs explanations to the other question).

Here's my macro definition:

\newcommand{\braket}[2][\middle]{\ensuremath{
\begingroup
\begingroup\lccode~=<
\lowercase{\endgroup\def~}{#1\langle}
\begingroup\lccode~=|
\lowercase{\endgroup\def~}{#1\pipedel}
\begingroup\lccode~=>
\lowercase{\endgroup\def~}{#1\rangle}
\edef\pipedel{\delimiter\the\delcode|}
\mathchardef\lt\mathcode<
\mathchardef\pipechar\mathcode|
\mathchardef\gt\mathcode>
\mathcode\<=\string"8000
\mathcode\|=\string"8000
\mathcode\>=\string"8000
\left.
#2
\right.
\endgroup
}}


The following usages all work as expected:

\braket{<\psi|\psi>}
\braket{<\psi|A|\psi>}
\braket{<\psi|\frac{p^2}{2m}|\psi>}
\braket[\Big]{<\alpha|\beta>}
\braket{|a \gt 0>}
\braket[]{<\psi|\frac{p^2}{2m}|\phi>}


(the last one simply disables automatic size adaption).

However, the following does not work correctly:

\braket{<0|1>}


It should give "〈0|1〉" but only gives "〈0〉".

So what's wrong with my macro, and how do I fix it?

-
You need something to "terminate" the macro |. \bracket{<0| 1>} produces the expected result. –  Werner Dec 1 '11 at 3:05
Since there is the braket package, this looks to me like reinventing the wheel. –  Thorsten Donig Dec 2 '11 at 8:51
@ThorstenDonig: In some sense it is. But on one hand, the braket package lacks flexibility (there are specific macros for each single case; if you have a case which was not provided by the author — like ketbra, or something like \braket{||\psi>>} — the braket package doesn't help you). On the other hand I don't learn anything by just using the package. –  celtschk Dec 2 '11 at 18:49

The problem is that when TeX finds the active pipe, it expands it to

\delimiter 2532108


and a number following it will be incorporated to that code.

\mathchardef\lt\mathcode<
\mathchardef\pipechar\mathcode|
\mathchardef\gt\mathcode>
\edef\pipedel{\delimiter\the\delcode| }
\show\pipedel
\newcommand{\braket}[2][\middle]{
\begingroup
\begingroup\lccode~=<
\lowercase{\endgroup\def~}{#1\langle}
\begingroup\lccode~=|
\lowercase{\endgroup\def~}{#1\pipedel\relax}
\begingroup\lccode~=>
\lowercase{\endgroup\def~}{#1\rangle}
\mathcode\<=\string"8000
\mathcode\|=\string"8000
\mathcode\>=\string"8000
\mathopen{}\left.#2\right.\mathclose{}
\endgroup
}


The \relax will avoid the problem. Also some parts are better outside the definition and \ensuremath is not recommendable.

## Note on the \lowercase trick

When a character (of category code 11 or 12) is assigned mathcode "8000 and is found in math mode, it is treated by TeX as if it were active (that is, like a macro) and a definition of it as an active character is needed.

A trick very commonly used is to exploit that ~ is active; when we want to give a meaning to the active <, there are two strategies. The first one is

{\catcode<=\active \gdef<{something}}


which has some drawback: we are forced to execute it in advance and it is global. So we use a different strategy:

\begingroup\lccode~=< \lowercase{\endgroup\def~}{something}


How does this work? First of all, we open a group and in the group we tell TeX that the lowercase counterpart of ~ is <. Then we do \lowercase, which transforms character tokens into their lowercase counterpart (but leaving control sequences unaltered) and puts back the tokens as if they were there from the beginning. So TeX sees

\endgroup\def<{something}


(but < is active, as \lowercase doesn't change category codes). The \endgroup undoes the correspondence between ~ and < and the definition is performed. When, later, we say \mathcode<=\string"8000, the magic will happen (\string is a precaution against babel which might have made " into an active character).

-
Thank you, it works great! However: What's wrong with \ensuremath? Also, what do \mathopen{} and \mathclose{} do? –  celtschk Dec 1 '11 at 8:21
@celtschk \mathopen{} and \mathclose{} will avoid additional space inserted by the \left and \right; \ensuremath does really no good here: \braket is to be used in math formulas. –  egreg Dec 1 '11 at 8:27
Thanks for the explanation. Yes, avoiding extra space is a good idea here. BTW, I'm now wondering if it would make sense to move the \relax into the definition of \pipedel. –  celtschk Dec 1 '11 at 8:38
@celtschk It would be the same. –  egreg Dec 1 '11 at 9:14
One thing I still don't understand is the definition method I copied from your code for the other question. I've already found out that it ultimately translates the \def~ into \def| (or \def< or \def>) by declaring that character as lowercase equivalent of ~; also I guess the \begingroup/\endgroup is there so that this lowercase definition does not persist. However what I don't understand is the idea behind this construction; it's obviously a trick, but I don't understand what it is for. –  celtschk Dec 1 '11 at 12:08