11

Since I am using 2 x 2 matrices very frequently, I would like to define a command which would work like this: \matr{a, b, c, d} would produce $\begin{pmatrix} a & b \\ c & d \end{pmatrix}$.

Of course, I know how to get this result using something like \matr{a}{b}{c}{d}, but the point is to have a "comma-separated list" of arguments. A solution using \matr{a, b}{c, d} could be interesting as well (especially its generalization to 3 x 3 matrices).

Most of the answers from here, there or there seem to rely on xparse package. But I am highly unused to the LaTeX3 syntax, so I have no clue on how to tackle with my problem.

Watson
  • 890
  • Oh, it seems that I cannot use LaTeX? It does not render currently... :-( – Watson Feb 25 '21 at 17:58
  • 2
    We deliberately do not have MathJaX on the site: if you need to show TeX output, make an image and upload it – Joseph Wright Feb 25 '21 at 18:00
  • This function already exists from within Emacs for matrices of all sizes. As a bonus, you can do all kinds of calculations on the matrices, see my answer for more precision. – gigiair Mar 11 '21 at 06:45
  • There is an analogue command in mlist package: https://mirror.foobar.to/CTAN/macros/latex/contrib/mlist/mlist.pdf. – Watson Mar 20 '21 at 17:32

6 Answers6

12

The argument is first split at commas in a sequence which is mapped taking into account the positions, so we can add & or \\ as needed.

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn \NewDocumentCommand{\matr}{m} { \begin{pmatrix} \seq_set_from_clist:Nn \l__watson_matr_seq { #1 } \seq_indexed_map_function:NN \l__watson_matr_seq __watson_matr_entry:nn \end{pmatrix} }

\seq_new:N \l__watson_matr_seq

\cs_new:Nn __watson_matr_entry:nn { #2 % the entry \int_case:nn { #1 } { {1}{&} {2}{\} {3}{&} } } \ExplSyntaxOff

\begin{document}

[ \matr{a,b,c,d} ]

\end{document}

enter image description here

Can we generalize it? Yes.

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn \NewDocumentCommand{\matr}{O{2}m} { \int_set:Nn \l__watson_matr_size_int { #1 } \begin{pmatrix} \watson_matr:nn { #1 } { #2 } \end{pmatrix} }

\seq_new:N \l__watson_matr_seq \int_new:N \l__watson_matr_size_int

\cs_new_protected:Nn \watson_matr:nn { \seq_set_from_clist:Nn \l__watson_matr_seq { #2 } \seq_indexed_map_function:NN \l__watson_matr_seq __watson_matr_entry:nn } \cs_new_protected:Nn __watson_matr_entry:nn { #2 % the entry \int_compare:nTF { \int_mod:nn { #1 } { \l__watson_matr_size_int } = 0 } { \ } { & } } \ExplSyntaxOff

\begin{document}

[ \matr{a,b,c,d}\ne\matr[3]{1,2,3,4,5,6,7,8,9} ]

\end{document}

enter image description here

If you're willing to accept a slightly different syntax, with semicolons for ending rows, you can easily produce matrices with different shapes and delimiters.

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn \NewDocumentCommand{\matr}{O{p}m} { \seq_set_split:Nnn \l__watson_matr_full_seq { ; } { #2 } \begin{#1matrix} \seq_map_function:NN \l__watson_matr_full_seq __watson_matr_makerow:n \end{#1matrix} }

\seq_new:N \l__watson_matr_full_seq \seq_new:N \l__watson_matr_row_seq

\cs_new_protected:Nn __watson_matr_makerow:n { \seq_set_split:Nnn \l__watson_matr_row_seq { , } { #1 } \seq_use:Nn \l__watson_matr_row_seq { & } \ } \ExplSyntaxOff

\begin{document}

[ \matr{a,b;c,d}\ne\matr[b]{1,2,3;4,5,6;7,8,9;10,11,12} ]

\end{document}

enter image description here

projetmbc
  • 13,315
egreg
  • 1,121,712
  • Thank you very much. I think one should include \usepackage{xparse}. Even with it, it does not compile with the TexLive2018 distribution... The log file says "! Undefined control sequence. \matr code ...eq {#1}\seq_indexed_map_function:NN \l__watson_matr_seq __wat... l.26 \matr{a,b,c,d}" – Watson Feb 25 '21 at 18:48
  • @Watson Only if you're running an older LaTeX kernel. Update, TL 2018 is really outdated. – egreg Feb 25 '21 at 20:57
  • @Watson I added a different method for matrices of arbitrary shape. – egreg Feb 25 '21 at 23:17
9

I am highly unused to the LaTeX3 syntax too, so I give you non-exp3 solution based only on TeX primitives. You need not any LaTeX package (and you basically don't even need LaTeX):

\documentclass[12pt]{article}

\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}} \def\matr#1{\def\matrL{}\matrA#1\end} \def\matrA#1{\ifx\end#1\pmatrix{\matrL}\else \ifx,#1\addto\matrL{&}\else \ifx;#1\addto\matrL{\cr}\else \addto\matrL{#1}\fi\fi \expandafter\matrA\fi }

\begin{document}

$$ \matr{a,b;c,d}\ne\matr{1,2,3;4,5,6;7,8,9;10,11,12} $$

\end{document}

wipet
  • 74,238
  • 2
    Wonderful! I think that I will accept this answer since it seems to be the only one that works with the (old) TexLive 2018, and also I feel that I would be able to understand this answer (as opposed to the scary LaTeX3 syntax...). – Watson Feb 26 '21 at 07:18
  • Some update: the above code doesn't work with \usepackage{amsmath}, which rise the error Package amsmath Error: Old form \pmatrix should be \begin{pmatrix}.. One has simply to use \begin{pmatrix}\matrL\end{pmatrix} instead of \pmatrix{\matrL} in your code. But then there is an issue with babel french option! I asked about it here: https://tex.stackexchange.com/questions/586677 – Watson Mar 10 '21 at 15:28
7

Here I use tokcycle to replace the commas with & separators. WHile I show 2x2 and 3x3, any number of columns are acceptible, as long as the matrices contain 2 or (optionally) 3 rows.

\documentclass{article}
\usepackage{amsmath,tokcycle}
\newcommand\matr[1][2]{\tctestifnum{3=#1}{\matrTHREE}{\matrTWO}}
\newcommand\matrTWO[2]{%
  \tokcyclexpress{#1\\#2}%
  \begin{pmatrix}\the\cytoks\end{pmatrix}}
\newcommand\matrTHREE[3]{%
  \tokcyclexpress{#1\\#2\\#3}%
  \begin{pmatrix}\the\cytoks\end{pmatrix}}
\Characterdirective{\tctestifx{,#1}{\addcytoks{&}}{\addcytoks{#1}}}
\begin{document}
\[
\matr{a, b}{c, d}
\]
\[
\matr[3]{a, b,c}{d, e, f}{g, h, i}
\]
\end{document}

enter image description here

OPTIONAL SINGLE ARGUMENT APPROACH

This allows any combination of rows and columns within a single argument with the syntax \matr{ a, b / c, d} Here, commas are taken a column separators and / tokens are taken as row separators:

\documentclass{article}
\usepackage{amsmath,tokcycle}
\newcommand\matr[1]{\tokcyclexpress{#1}%
  \begin{pmatrix}\the\cytoks\end{pmatrix}}
\Characterdirective{\tctestifx{,#1}{\addcytoks{&}}{%
  \tctestifx{/#1}{\addcytoks{\\}}{\addcytoks{#1}}}}
\begin{document}
\[
\matr{a, b / c, d}
\]
\[
\matr{a, b,c / d, e, f/ g, h, i}
\]
\end{document}
5

A solution without any packages that is based on two fast loops to replace , with & and ; with \\ (so the syntax is the same as in @wipet's answer, but the execution is marginally faster, and it has no problems with braced groups, e.g., \matr{\mathbf{stuff},b;c,d} works as intended). To change to other parsing tokens than , and ; just swap out these two in every definition...

Also, I separated the parsing macro from the pmatrix, so that you could also use other matrix/tabular like enviroments (e.g., \begin{tabular}{cc}\matrinp{a,b;c,d}\end{tabular} would work as well).

\documentclass[]{article}

\usepackage[]{amsmath}

\makeatletter \newcommand\matr[1] {% \begin{pmatrix} \matrinp{#1}% \end{pmatrix} } \newcommand\matrinp[1] {% \expandafter@firstofone\expandafter {% \romannumeral \matr@commas \matr@nil#1\matr@mark \matr@stop\matr@commas ,\matr@stop\matr@commas@done }% } \long\def\matr@commas#1,#2\matr@stop#3{#3#1&#2\matr@stop#3} \long\def\matr@commas@done#1\matr@stop#2\matr@commas@done {\matr@semicolon#1\matr@stop\matr@semicolon;\matr@stop\matr@done} \long\def\matr@semicolon#1;#2\matr@stop#3{#3#1\#2\matr@stop#3} \long\def\matr@done#1\matr@mark#2\matr@done{\expandafter\z@@gobble#1} \makeatother

\begin{document} [ \matr{a,b;c,d}\ne\matr{1,2,3;4,5,6;7,8,9;10,11,12} ] \end{document}

Skillmon
  • 60,462
2

A little bit late to the party, but for the sake of variety, here's a LuaLaTeX-based solution. Regarding input syntax, I make the assumption that , is used as the separator between cells in a given row, while ; is used as the separator between rows.

enter image description here

\documentclass{article}
\usepackage{amsmath} % for 'pmatrix' environment
\usepackage{luacode} % for '\luaexec' macro

\luaexec{ function matr ( s ) s = s:gsub ( ";" , "\\" ) s = s:gsub ( "," , "&" ) tex.sprint ( "\begin{pmatrix}" .. s .. "\end{pmatrix}" ) end } \newcommand\matr[1]{\directlua{ matr ( "#1" ) }}

\begin{document} $\matr{ a, b ; c, d }$ \end{document}

Mico
  • 506,678
1

If you are a Emacs user, such a command already exists. You just type (for example)

\[ [[a b][c d]]\]

and when the point is on this formula, call the Calc-embedded command (C-x * e) . Emacs immediately returns:

\[ \begin{pmatrix} a & b \\ c & d \end{pmatrix}\]

As a bonus, Calc allows you to perform many matrix operations.

You have to call again Calc-embedded to return to normal latex-mode.

gigiair
  • 1,812