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.

I am trying to write macros for quickly formatting matrices in math mode. Here is a simple, working example:

\documentclass{article}
\usepackage{amsmath}
\newcommand{\pmat}[1]{\begin{pmatrix}#1\end{pmatrix}}

\begin{document}
\begin{displaymath}
M = \pmat{1&0\\0&1}
\end{displaymath}
\end{document}

This also works if used within an aligned environment (a table, align environment, cases environment, etc.):

\documentclass{article}
\usepackage{amsmath}
\newcommand{\pmat}[1]{\begin{pmatrix}#1\end{pmatrix}}

\begin{document}
\begin{align}
M &= \pmat{1&0\\0&1}
\end{align}
\end{document}

Normally, within the align environment the & symbol tells LaTeX to start a new column, but since the matrix values are contained between {} group tokens, LaTeX does not attempt to parse the 1&0\\0&1 argument and thus everything works as it was intended.

Let's create a new macro that does not use the group tokens {} to denote the macro argument. For example, it is fairly common to use square brackets to group an argument as in this working example (try it!):

\documentclass{article}
\usepackage{amsmath}
\newcommand{\bmat}[1][]{\begin{bmatrix}#1\end{bmatrix}}

\begin{document}
\begin{displaymath}
M = \bmat[1&0\\0&1]
\end{displaymath}
\end{document}

So far, so good. Here comes the problem! If I try to use my new macro \bmat within another aligned environment:

% DOES NOT WORK!!!
\documentclass{article}
\usepackage{amsmath}
\newcommand{\bmat}[1][]{\begin{bmatrix}#1\end{bmatrix}}

\begin{document}
\begin{align}
M &= \bmat[1&0\\0&1]
\end{align}
\end{document}

I get an error because LaTeX tries to interpret the & within the matrix argument as part of the outer align environment.

The difference between the way LaTeX treats the first macro \pmat{} and the second one \bmat[] is that the group tokens {} prevent LaTeX from parsing the argument contained within the curly braces until after the macro \pmat has been called. On the other hand, when LaTeX sees the \bmat[arg] macro, the argument is not surrounded by group tokens and so LaTeX tries to parse it before getting eaten up by \bmat. The extra & character screws up the syntax of the align environment and so LaTeX crashes. At least, that is my understanding of what is going on, and I could be wrong!

So, the question is whether or not it is possible to force LaTeX to treat the argument in the [] case just as it did in the {} case (without causing additional problems). In other words, I want to be able to write a macro a-la \bmat[1&0\\0&1] that works in aligned environments but retains the square bracket syntax.

CONCLUSION:

Here is the final macro with working [] syntax, thanks to egreg (requires xparse and must be contained in a separate package file or between \makeatletter and \makeatother in preamble):

\DeclareDocumentCommand\mat{}{{\ifnum\z@=`}\fi\@mat}
\DeclareDocumentCommand\@mat{ g o d() d|| }
{
    \IfNoValueTF{#1}
    {
        \IfNoValueTF{#2}
        {
            \IfNoValueTF{#3}
            {
                \IfNoValueTF{#4}
                {()}
                {\begin{vmatrix}#4\end{vmatrix}}
            }
            {
                \begin{pmatrix}#3\end{pmatrix}
                \IfNoValueTF{#4}{}{|#4|}
            }
        }
        {
            \begin{bmatrix}#2\end{bmatrix}
            \IfNoValueTF{#3}{}{(#3)}
            \IfNoValueTF{#4}{}{|#4|}
        }
    }
    {
        \begin{matrix}#1\end{matrix}
        \IfNoValueTF{#2}{}{[#2]}
        \IfNoValueTF{#3}{}{(#3)}
        \IfNoValueTF{#4}{}{|#4|}
    }
    \ifnum\z@=`{\fi}
}

This macro works like an overloaded function with different argument delimiters {}, [], (), or ||. There are probably many reasons why this is a terrible idea --- so please, post your comments below. I would like to hear from those who know better than me.

share|improve this question
    
Is using {\bmat[1&0\\0&1]} an acceptable option? –  Scott H. Nov 30 '12 at 21:14
    
Welcome to TeX.SX! It's not at all clear why you should want \bmat to take its argument in brackets. –  egreg Nov 30 '12 at 21:15
    
the "inner" &s really have to be hidden, so putting them in braces is essential. –  barbara beeton Nov 30 '12 at 21:25
    
Thank you all for your helpful replies! Indeed, it is best to group everything within braces as Scott H. and barbara beeton have suggested. To that end, egreg provided a very sneaky way to insert the grouping braces I need to make it work the way I would like. –  Sergio Dec 3 '12 at 15:01
    
@Sergio I've added to my answer how I would manage the thing, rather than with that complex macro. –  egreg Dec 3 '12 at 17:50

2 Answers 2

up vote 4 down vote accepted

You can do it, but I strongly recommend you not doing it. You gain nothing in using [ and ] as delimiters for a mandatory argument.

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand\bmat{{\ifnum\z@=`}\fi\@bmat}
\def\@bmat[#1]{\begin{bmatrix}#1\end{bmatrix}\ifnum\z@=`{\fi}}
\makeatother

\begin{document}
$\bmat[1&0\\0&1]$
\begin{align}
M &= \bmat[1&0\\0&1]
\end{align}
\end{document}

enter image description here

(Note: I have reduced the text width to shorten the output.)

When you understand the trick, you are allowed to use it. :) Hint: look for \eegroup in Appendix D of the TeXbook.


Defining \mat to look for the next token in order to decide a delimiter is, in my opinion, wrong. I'd do like this:

\newcommand{\mat}[2][]{\begin{#1matrix}#1\end{#1matrix}}

so that

\mat{1&2\\3&4}    % no fences
\mat[b]{1&2\\3&4} % brackets
\mat[p]{1&2\\3&4} % parentheses
\mat[v]{1&2\\3&4} % vertical lines
\mat[V]{1&2\\3&4} % double vertical lines
\mat[B]{1&2\\3&4} % braces

would do even better, with minimum hassle and better readability.

Personally, I would stick with the long form, but it's a matter of taste.

share|improve this answer
    
This is exactly the sort of trick I was looking for. Thank you for the TeXbook reference, it proved to be very enlightening. It also makes me feel better that this trick is in the TeXbook itself! I will append my initial entry with the final implementation the macro I was working on using your trick. I would be interested in your opinion of my macro, as it may be controversial in terms of proper LaTeX syntax. –  Sergio Dec 3 '12 at 15:06
    
@Sergio I've already stated my opinion: you gain nothing (and probably lose something) by using such a syntax. –  egreg Dec 3 '12 at 15:18

Why this happens is rather interesting, since of course the raw code

\begin{align}
 M = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}
\end{align}

does work even though the array separators are not between braces. The reason is that bmatrix itself inserts braces specifically to make this work, and by the time scanning has reached the separators, TeX has already read the opening brace and knows that it should protect them.

In your code, it would seem that \bmat is replaced with its expansion, which is the above code, before the & is read, but in fact, the & has already been read at that point: it needs to be picked up by the macro argument grabber. That is to say, even though the & wasn't "executed" it was seen, and apparently, TeX will detect the end of an array cell even just when going through tokenization.

Because of this, there is no way to use the normal \newcommand\bmat[1][]{} syntax to define a command that "just works" in arrays; egreg's answer shows how you can roll your own that accepts the same syntax but sneakily inserts braces. It's probably also possible to make a \catcode change prior to scanning for the argument that would make [] into functional brace characters, but for all that effort, I suggest you redesign your macro not to use an optional argument instead. As a perhaps compromise, you can place braces around it: {\bmat[1&0\\0&1]}, as Scott H. suggested.

share|improve this answer
    
Thank you for the detailed and helpful analysis of how LaTeX parses this code! I considered \catcode changes but decided to steer clear of anything that might cause confusing [} mismatched delimiters and the like. –  Sergio Dec 3 '12 at 15:04
    
Doing with changes to catcodes is made very problematic because of what the amsmath environments like align do, they scan their entire contents, hence no catcode can be changed by a macro therein. So simple approaches like \def\@pmat#1{#1\end{pmatrix}} \def\pmat{\begin{pmatrix}\catcode[=1 \catcode`]=2 \@pmat}` which do work in inline and display math fail in amsmath environments. (there is a backtick texsx formatting problem in my comment that I don't know how to fix) –  jfbu Dec 3 '12 at 18:01
    
@jfbu: I should have known that. Is there anything that \@ifmeasuring doesn't make difficult? –  Ryan Reich Dec 3 '12 at 19:29
    
@RyanReich alas! I got bitten hard by that one some time ago, while attempting to produce a very very lightweight and minimal 'poor man beamer' for my private use to do presentations... –  jfbu Dec 3 '12 at 20:11

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.