7

Basic Problem

I'm trying to produce a command sequence \m that

  1. Is called from within math mode, with a single argument list
  2. "Replaces" all instances , and ; in list with & and \\ (resp.)
  3. Creates a pmatrix with output of 1 & 2 as its content

For example, the code

\[
    \m{a,b;c,d}\m{x;y}
\]

should expand to be equivalent to the following:

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

After spending more time on this than I should have, I came up with the following partial solution to the problem using xstring:

\def\foo#1{
    \StrSubstitute{#1}{,}{&}[\result]

    \verbtocs{\bslashes}|\\|
    \expandarg
    \StrSubstitute{\result}{;}{ \bslashes }[\result]
}

\begin{document}
    % Fairly complicated matrix input
    \foo{a,b,c;d,e_{f,g},h;i,j_{1,e^n},k}
    \[
        \begin{pmatrix}
            \result
        \end{pmatrix}
    \]
\end{document}

This is close to what I was hoping for, but I haven't come up with a way to use \foo as a helper function for \m to get exactly what I want. I was thinking that defining \m in the preamble by

\def\m#1{
    \foo{#1}
    \begin{pmatrix}
        \result
    \end{pmatrix}
}

would work, but then even calling something as simple as \m{a} in math mode will produce errors. It looks as though math mode attempts to parse the definition of \m instead of letting \m fully expand, but my understanding of how this works is too limited to know how to fix my code.

Is there a way to modify the definitions of \m and \foo to make them do what I want? Can I somehow escape math mode in the definition of \m to avoid these errors?

4

Here is a method the old-fashioned way, using macros with delimited parameters.

\documentclass{article}
\usepackage{amsmath} % for pmatrix environment

\newtoks\asqltoks
\makeatletter

\def\gobtilundef #1\undef {}

\def\matlabmatrix #1{\asqltoks{\begin{pmatrix}}\@asqlA #1;\undef;}

% \def\@asqlA #1;{\gobtilundef #1\@asqlE\undef\@asqlR #1,\undef,}
% update: simplified to ->
\def\@asqlA #1;{\@asqlR #1,\undef,}

\def\@asqlB #1;{\gobtilundef #1\@asqlE\undef
                \asqltoks\expandafter{\the\asqltoks \\}\@asqlR #1,\undef,}

\def\@asqlE\undef #1\undef,\undef,{%
    \asqltoks\expandafter{\the\asqltoks\end{pmatrix}}\the\asqltoks }

\def\@asqlR #1,{\asqltoks\expandafter{\the\asqltoks #1}\@asqlS }
\def\@asqlS #1,{\gobtilundef #1\@asqlZ\undef
                \asqltoks\expandafter{\the\asqltoks &#1}\@asqlS }
\def\@asqlZ #1\@asqlS {\@asqlB }

\makeatother

\begin{document}

$\matlabmatrix {m}$

$\matlabmatrix {m,n}$

$\matlabmatrix {m,n;p,q}$

$\matlabmatrix {a,b,c;d,e_{f,g},h;i,j_{1,e^n},k}$

\end{document}

matrices

5

Here's an implementation with expl3 functions:

\documentclass{article}
\usepackage{xparse,amsmath}
\ExplSyntaxOn
\NewDocumentCommand{\matlabmatrix}{m}
 {
  \asql_matlab_matrix:n { #1 }
 }

\seq_new:N \l_asql_rows_seq
\seq_new:N \l_asql_one_row_seq
\tl_new:N \l_asql_matrix_tl

\cs_new_protected:Npn \asql_matlab_matrix:n #1
 {
  % clear the token list variable containing the final data
  \tl_clear:N \l_asql_matrix_tl
  % split the argument at the semicolon
  \seq_set_split:Nnn \l_asql_rows_seq { ; } { #1 }
  % build one row at a time
  \seq_map_inline:Nn \l_asql_rows_seq
   {
    \__asql_build_row:n { ##1 }
   }
  % print the matrix
  \begin{pmatrix}
  \tl_use:N \l_asql_matrix_tl
  \end{pmatrix}
 }

% the inner function
\cs_new_protected:Npn \__asql_build_row:n #1
 {
  % split the input at commas
  \seq_set_split:Nnn \l_asql_one_row_seq { , } { #1 }
  % add the row to the token list variable
  % items are separated by &
  \tl_put_right:Nx \l_asql_matrix_tl
   { \seq_use:Nnnn \l_asql_one_row_seq { & } { & } { & } }
  % add also the \\ row terminator
  \tl_put_right:Nn \l_asql_matrix_tl { \\ }
 }
\ExplSyntaxOff

\begin{document}
\begin{gather*}
\matlabmatrix{a,b;c,d}\matlabmatrix{x;y} \\
\matlabmatrix{a,b,c;d,e_{f,g},h;i,j_{1,e^n},k}
\end{gather*}
\end{document}

It's quite straightforward: we first split the argument at semicolons; then each item is split at commas and, row by row, the contents of the matrix is built. Finally the contents is inserted between \begin{pmatrix} and \end{pmatrix} for printing.

enter image description here

  • although this is very instructive, i hope the author using it isn't intending to submit this for publication in a journal. there is more and more call for journals to be made available in electronic form, and this may call for conversion to mathjax. unless i greatly misunderstand the capabilities of mathjax conversion, a journal editor would have to "unwind" the input into more basic latex syntax; at worst, the publisher might simply decide that is too expensive, and send the file out for rekeyboarding from the author's output. neither is desirable. better to keep it simple. – barbara beeton Jun 8 '13 at 20:44
  • @barbarabeeton What sort of electronic form are you referring to above? Available as a webpage rather than a "document"? – Scott H. Jun 8 '13 at 21:01
  • I decided to accept unbonpetit's answer because it was based in xstring like my original code, but this is a nice example use of expl3. Thanks! – Dan Jun 8 '13 at 21:04
  • @ScottH. -- perhaps a web page, but also possibly an e-book. as much as i hope it will be possible to generate competent e-books with (la)tex, that may not be the final choice if mathjax turns out to be easier to re-flow. (although i doubt it.) just mentioning the possibilities i've heard as scuttlebut, and also noting that coding of this sort already causes serious production difficulties. – barbara beeton Jun 8 '13 at 22:02
  • @barbarabeeton Thanks, I hadn't thought of e-books. – Scott H. Jun 8 '13 at 22:14
4

This code should do what you want:

\documentclass{article}
\usepackage{xstring,amsmath}
\newcommand*\mmm[1]{%
    \begingroup\expandarg
    \StrSubstitute{\noexpand#1},&[\result]%
    \StrSubstitute\result{\noexpand;}{\noexpand\\}[\result]%
    \begin{pmatrix}\result\end{pmatrix}\endgroup
}
\begin{document}
\[\mmm{a,b,c;d,e_{f,g},h;i,j_{1,e^n},k}\]

\[\mmm{a}\]
\end{document}
  • Thanks a lot! This is very nice, and I think I have a better idea from it how to use \noexpand with \expandarg effectively. – Dan Jun 8 '13 at 20:35
  • @egreg - I believe that's because unbonpetit's code doesn't load amsmath. – Dan Jun 8 '13 at 20:39
  • Yes, sorry: a copy-paste error, I forgot the amsmath package. Thank for editing my answer. – unbonpetit Jun 8 '13 at 20:53
3

You don't have to do string replacement you can just define , and ; to do the right thing in pmatrix

enter image description here

\documentclass{article}
\usepackage{amsmath}
\def\m#1{{%
\mathcode`\,"8000
\mathcode`\;"8000
\begingroup\lccode`\~`\,%
\lowercase{\endgroup\def~}{&}%
\begingroup\lccode`\~`\;%
\lowercase{\endgroup\def~}{\\}%
\begin{pmatrix}#1\end{pmatrix}}}

\begin{document}
\[
    \m{a,b;c,d}\m{x;y}
\]
\end{document}
  • This wouldn't work with \m{1_{a,b},c;d,e}} – egreg Jun 8 '13 at 21:19
  • 2
    @egreg well don't do that then:-) – David Carlisle Jun 8 '13 at 21:20
3

Well, if you’re already using xstring, you could just try xparse.

Apparently, pmatrix survives an additional \\ after the last line without adding an extra line (unlike the usual math environments). The additional & though has to be removed, this is done by \@gobblesecondoftwo.

I have also included a solution that does use TeX’s delimited parameter to split the argument at ;s and ,s.

Code

\documentclass{article}
\usepackage{amsmath}

% xparse solution
\usepackage{xparse}
\makeatletter
\def\@gobblethirdofthree#1#2#3{#1#2}
\def\@gobblesecondoftwo#1#2{#1}
\NewDocumentCommand\foo{>{\SplitList;}m}{
 \begin{pmatrix} \ProcessList{#1}\@foo \end{pmatrix}
}
\NewDocumentCommand\@foo{>{\SplitList,}m}{
  \expandafter\expandafter\expandafter\@gobblesecondoftwo
  \ProcessList{#1}\@@foo \\
}
\def\@@foo#1{&#1}

% plain delimited parameters
\newcommand*{\fooo}[1]{%
  \begin{pmatrix}\foo@split@semi#1;\foo@@@split@semi\foo@@split@semi\end{pmatrix}
}
\def\foo@split@semi#1;#2\foo@@split@semi{%
  \foo@split@comma#1,\foo@@@split@comma\foo@@split@comma
  \ifx\foo@@@split@semi#2\expandafter\@gobble\else
    \expandafter\@firstofone
  \fi{\\\foo@split@semi#2\foo@@split@semi}%
}
\def\foo@split@comma#1,#2\foo@@split@comma{%
  #1
  \ifx\foo@@@split@comma#2\expandafter\@gobble\else
    \expandafter\@firstofone
  \fi{&\foo@split@comma#2\foo@@split@comma}%
}
\makeatother
\begin{document}
$\foo{a,b,c;d,e_{f,g},h;i,j_{1,e^n},k}$
$\foo{m}$

$\fooo{a,b,c;d,e_{f,g},h;i,j_{1,e^n},k}$
$\fooo{m}$
\end{document}

Output

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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