Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Is there a way to have a macro optionally prefixed with \left or \right and have it expand differently depending on that? For example, have \bra{x} expand to \langle x |, but \left\bra{x} to \left\langle x \middle|? Extra bonus if it works also with explicit size prefixes, giving that size to both \langle and |.

Some examples of what you could do with such macros:

Assuming a corresponding \ket macro, one could then write e.g.

\left\bra{x} \frac{\hat p}{m} \right\ket{x}

and have it expand to

\left\langle x \middle| \frac{\hat p}{m} \middle| x \right\rangle

i.e. the size of the brackets would depend on both the arguments and what's in between. On the other hand,

\bra{x} \frac{\hat p}{m} \ket{x}

would just expand to

\langle x | \frac{\hat p}{m} | \rangle

that is, without extension. Since there would be exactly one \left in the expansion of the \left-prefixed macro, and exactly one \right in the expansion of the \right-prefixed macro, one could also combine it with normal delimiters (including the "pseudo-delimiter" .). So for example,

\left\langle{x^2}\right.

would expand only according to what is inside the argument.

(Note: I am aware of the braket package, so no need to point that out. Note that it doesn't the \left/\right thing either.)

share|improve this question
    
Did you know that $(x)$ is equivalent in appearance to $\left(x\right)$? Therefore, you can use \left and \right even if the contents doesn't require the delimiters to expand. –  Werner Nov 16 '11 at 17:39
    
@Werner: The x was an example. It could be something larger. But then, note that the corresponding \right is not in the macro, so something outside that macro would also influence the size, e.g. (assuming a corresponding \ket): \left\bra{x}\frac{\hat{p}}{m}\right\ket{x} would give quite large parens despite the argument of \bra and \ket being single letters. –  celtschk Nov 16 '11 at 17:45
    
@Werner: I just note that I had a mistake in my post (I forgot the {x} in the \left version), maybe that led you in the wrong direction. I've now added it (I also corrected another mistake (\left instead of \mid), but that didn't change anything I said in my other comment). –  celtschk Nov 16 '11 at 17:49
1  
I find the question requires a little more explanation. For example, \left requires a \right partner while in your example you want it to expand to \left...\mid. Also \mid is a symbol and not a macro to extend the delimiter |. –  Werner Nov 16 '11 at 17:56
    
Welcome to TeX.SE. It would be very helpful if you would compose a MWE that illustrates the problem and provides a test case. –  Peter Grill Nov 16 '11 at 18:01
show 4 more comments

2 Answers

up vote 4 down vote accepted

Nice problem without a real solution, I'm afraid; unless one redefines \left, which I'm not willing to do. Werner's definition is quite safe and might be extended to \bigl and company. But this doesn't make it more manageable than a syntax with an optional argument.

The following one works, but has a big drawback: if \bra is found in a group formed by another \left, everything will die horribly.

\let\TeXmiddle\middle

\def\bra#1{\langle#1
  \ifnum\currentgrouptype=16
    \neutralizeright
  \else
      \neutralizemiddle
  \fi}

\def\neutralizeright{%
  \def\middle##1{\TeXmiddle##1}%
  \let\rightket\right
  \let\right\relax
  \aftergroup\neutralizeright}
\def\neutralizemiddle{\let\middle\relax}
\let\rightket\relax
\def\ket#1{#1\rightket\rangle}

$\bra{x}\middle|y\middle|\ket{z}$

$\left\bra{x} \middle| \frac{a}{b} \middle| \right\ket{z}$

The \middle in the first formula is optional as it does nothing. However, as I said before, something like

$\left( \bra{x}|y|\ket{z} \right)$

will die. The conditional \ifnum\currentgrouptype=16 checks whether we are in a group initiated by \left. Since \left expands the following token in order to find a delimiter, \bra is expanded after it and the business can go on. But there's no way to know when \left has been opened as the third example shows.

I would prefer a syntax such as

\bra{x} | y | \ket{z}
\bra[\left]{x} | y | \ket{z}
\bra[\big]{x} | y | \ket{z}

that could be defined in a rather straightforward way. Here is a way:

\documentclass[a4paper]{article}
\usepackage{amsmath}

\begingroup\lccode`~=`|
  \lowercase{\endgroup\def~}{\braketmiddle}
\edef\pipedel{\delimiter\the\delcode`|}
\mathchardef\pipechar\mathcode`|

\newcommand{\bra}[2][]{\begingroup
  \mathcode`\|=\string"8000
  #1\langle
  \csname @bra\string#1ket@\endcsname#2}
\newcommand{\ket}[1]{%
  #1\braketright\rangle\endgroup}
\expandafter\def\csname @braket@\endcsname{%
  \def\braketmiddle{\pipechar}
  \def\braketright{}
}
\expandafter\def\csname @bra\string\left ket@\endcsname{%
  \def\braketmiddle{\middle\pipedel}
  \def\braketright{\right}
  \expandafter\aftergroup\csname @bra\string\left ket@\endcsname
}
\expandafter\def\csname @bra\string\bigl ket@\endcsname{%
  \def\braketmiddle{\big\pipedel}
  \def\braketright{\bigr}
}
\expandafter\def\csname @bra\string\Bigl ket@\endcsname{%
  \def\braketmiddle{\Big\pipedel}
  \def\braketright{\Bigr}
}
\expandafter\def\csname @bra\string\biggl ket@\endcsname{%
  \def\braketmiddle{\bigg\pipedel}
  \def\braketright{\biggr}
}
\expandafter\def\csname @bra\string\Biggl ket@\endcsname{%
  \def\braketmiddle{\Bigg\pipedel}
  \def\braketright{\Biggr}
}

\begin{document}

%\tracingmacros=1 \tracingonline=1
$\bra{x} | \bra{1}|2|\ket{3} y | \ket{z}$

$\bra[\left]{x} | \bra{1}|2|\ket{3}\dfrac{y}{2} | \ket{z}$

$\bra[\bigl]{x} | y | \ket{z}$

$\bra[\Bigl]{x} | y | \ket{z}$

$\bra[\biggl]{x} | y | \ket{z}$

$\bra[\Biggl]{x} | y | \ket{z}$

\end{document}

This even allows nesting.

Some comments about the second solution. The syntax is

\bra[<size>]{x} | y | \ket{z}

where the y | part is optional. In order to process correctly the | character we'll assign it \mathcode"8000 which means that it will behave like an active character. So first of all we define the active version of | as \braketmiddle, which in turn will be defined in different ways according to the <size> argument. Its default definition (no <size> specification) is \pipechar which is defined by \mathchardef\pipechar=\mathcode`| that is, to be like the ordinary |. So | in the braket will give a simple vertical bar.

When a size specification has been given, \braketmiddle will become \middle\pipedel or \big\pipedel and similarly for the others; \middle, \big and company want to see a delimiter after them so we have defined

\edef\pipedel{\delimiter\the\delcode`|}

Each character has a \delcode (for most of them it's zero, meaning that they are not delimiters). The | character has one and we access it with \the\delcode`| (we couldn't say \middle|, because we have assigned the special mathcode to |). Thus in our context \middle\pipedel is the same as an ordinary \middle| and the same for \big and company.

Similarly each <size> specification defines a meaning for \braketright that's put in front of the closing \rangle. There's a subtle point here in the case when <size> is \left. When TeX finds \left...\middle it opens a group with \left and closes it at \middle to reopen it until finding the next \middle or \right. So we have to carry over the redefinitions we made to the next group and this is achieved by the strange \aftergroup. But this would take too far.

share|improve this answer
    
Again, a nice solution. Definitely a +1. However I've got a problem now: I can only select one of the answers. But both would have earned it: Your first solution has the exact syntax, but is not robust, while Werner's solution is robust, but slightly modifies the syntax. Your second solution looks also quite interesting; however I don't really understand it. Could you please add some short explanation of those \delcode, \mathcode and \string? I think I might be able to figure out the rest. –  celtschk Nov 17 '11 at 21:33
    
Thanks for the extra explanation. I've now decided to make your answer the accepted one; however want to stress again that actually both answers would have deserved it. –  celtschk Nov 27 '11 at 13:08
add comment

If you are willing to use a (marginally) modified version of \left and \right, you could activate a toggle (a boolean true/false variable) to keep track of whether you're within a \left-\right scope.

In the MWE below, I've defined the toggle insidedelim that is true when you call \left* and becomes false after calling \right* - it is specific to the definition of \bra and \ket. Well, actually only \ket, but you could define other macros in a similar way as long as they duplicate the structure of \ket (which turns the toggle insidedelim off). The reason for this small alteration is because of your interest to make the delimiters extend based on contents outside it's scope. The regular \left and \right delimiter pairs still work as usual.

enter image description here

\documentclass{article}
\usepackage{amsmath}% http://ctan.org/pkg/amsmath
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\usepackage{xparse}% http://ctan.org/pkg/xparse
\newtoggle{insidedelim}% 
\newcommand{\bra}[1]{% \bar{<stuff>}
  \iftoggle{insidedelim}%
    {\oldleft\langle #1 \middle|}% \left*
    {\langle #1|}% \langle #1 \mid
}
\newcommand{\ket}[1]{% \ket{<stuff>}
  \iftoggle{insidedelim}%
    {\middle| #1 \oldright\rangle\togglefalse{insidedelim}}% \right*
    {|#1 \rangle}% \mid #1 \rangle
}
\let\oldleft\left
\let\oldright\right
\RenewDocumentCommand{\left}{s}{%
  \IfBooleanTF{#1}% starred/unstarred
    {\toggletrue{insidedelim}}% \left*
    {\oldleft}% \left
}
\RenewDocumentCommand{\right}{s}{%
  \IfBooleanTF{#1}% starred/unstarred
    {}% \right*
    {\oldright}% \right
}
\begin{document}
$\langle x | \frac{\hat{p}}{m} | x \rangle$ \par \bigskip

$\bra{x} \frac{\hat{p}}{m} \ket{x}$ \par \bigskip

$\left\langle x \middle| \frac{\hat{p}}{m} \middle| x \right\rangle$ \par \bigskip

$\left*\bra{x} \frac{\hat{p}}{m} \right*\ket{x}$
\end{document}

Toggles and switching is provided by etoolbox while the advanced command definition interface is provided by xparse.

share|improve this answer
    
Nice, thank you. Definitely a +1. I'll wait some time if someone finds a solution without the star, if not, I'll also accept this answer as the right one. –  celtschk Nov 16 '11 at 20:38
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.