# Define a macro for a vector to display differently in inline/display math mode

I'd like to define a command that defines a vector based on whether it's in display or inline math mode. I've tried this so far, but it hasn't worked:

\newcommand{\ve}[1]{\ensuremath{%
\mathchoice{%
\begin{pmatrix}%
\StrSubstitute{#1}{,}{\\}%
\end{pmatrix}%
}{%
\left(\begin{smallmatrix}%
\StrSubstitute{#1}{,}{\\}%
\end{smallmatrix}\right)%
}{#1}{#1}%
}}


I'd like to get $$\ve{1,2,x}$$ to expand to

\begin{pmatrix}
1\\2\\x
\end{pmatrix}


and $\ve{1,2,x}$ to expand to

\left(\begin{smallmatrix}
1\\2\\x
\end{smallmatrix}\right)

• Are you willing and able to entertain a LuaLaTeX-based solution, or does it have to work with pdfLaTeX?
– Mico
Jan 19, 2021 at 7:22
• Please also indicate how or where \StrSubstitute is defined.
– Mico
Jan 19, 2021 at 7:23
• @Mico I'd like to stick to PDFLaTeX. \StrSubstitute is defined in the xstrings package (or something like that). Jan 19, 2021 at 7:26

Distinguishing inline and display math is different from distinguishing \displaystyle from \textstyle and can be tricky, since the align-like environments of amsmath use internally $\displaystyle...$. Your definition with \ensuremath will furthermore always use \textstyle if you call the macro outside of math mode. In my (of course questionable) opinion \ensuremath shouldn't be used unless the life of sweet kittens and fluffy bunnies depends on it; and also in that case it shouldn't be used lightly.

Luckily, amsmath provides a boolean \if@display, so we can (ab)use it. I'd load mathtools, an extension to amsmath, which among other things defines already a psmallmatrix environment.

\documentclass{article}

\makeatletter

\newcommand*{\ve}[1]{%
\begingroup
\if@display
\def\@tempa{{pmatrix}}
\else
\def\@tempa{{psmallmatrix}}
\fi
\expandafter\begin\@tempa
\@ve#1,\@@nil,
\expandafter\end\@tempa
\endgroup
}

\def\@ve#1,{\ifx\@@nil#1\else#1\\\expandafter\@ve\fi}

\makeatother

\begin{document}

\hsize=4cm % for the snapshot

$\ve{a}\ve{a,b}\ve{a,b,c}$

\begin{align*}
\ve{a}\ve{a,b}\ve{a,b,c}
\end{align*}

$\ve{a}\ve{a,b}\ve{a,b,c}$

\end{document}


EDIT A version which like egreg's answer uses \mathchoice. I've added for completeness also a row vector. This required some more trickery, becase there is no harm in adding \\ at the end of a column vector (like my first coded did) but it goes wrong when you add a & at the end of a row.

\documentclass{article}

\usepackage{mathtools}

\makeatletter

\newcommand*{\cvector}[1]{\cr@vector{\\}{#1}}
\newcommand*{\rvector}[1]{\cr@vector{&}{#1}}

\newcommand*{\cr@vector}[2]{%
\mathchoice{\cr@@vector{#1}{#2}{}}%
{\cr@@vector{#1}{#2}{small}}%
{\cr@@vector{#1}{#2}{small}}%
{\cr@@vector{#1}{#2}{small}}%
}

\newcommand*{\cr@@vector}[3]{%
\def\@tempa{\gdef\@tempa{#1}}% first time does nothing, afterwards it's \\ or &
\def\@tempb##1,{\ifx\@@nil##1\else\@tempa##1\expandafter\@tempb\fi}%
\begin{p#3matrix}
\@tempb#2,\@@nil,
\end{p#3matrix}
}

\makeatother

\begin{document}

\hsize=5cm % for smaller snapshot

Display
\begin{align*}
\rvector{a,b,c} \cvector{a,b,c}
= \frac{\rvector{x,y} \cvector{u,v}}{\rvector{1,2,3}\cvector{4,5,6}}
\end{align*}
and inline $\rvector{a,b,c}$, $\cvector{a,b,c,d,e}$

\end{document}


One could use \mathchoice directly in the definition of \cvector and \rvector and spare one intermediate macro but I find the code would be less readable.

• Thanks @campa! This works perfectly, is extremely readable, and doesn't involve importing extra packages. The \psmallmatrix is genius as well! Jan 19, 2021 at 17:29
• @Raymo111 Readability might be one thing, but as far as egreg's answer is concerned consider that (1) xparse is a rather standard package and even for an older distribution where it's not part of the format you might already have it (maybe you don't load it directly but there are many common packages which do) and (2) my solution will give you larger matrices also e.g. in fractions, while egreg's will give you smaller matrices. Not that anybody in their sane mind would type something like that, but keep the difference in mind. Jan 19, 2021 at 17:43
• I get that xparse is standard, but if I'm sharing \ve with friends I don't really want to make them import xparse if they're not on the latest Tex distribution. What do you mean by larger/smaller matrices? Jan 19, 2021 at 18:01
• @Raymo111 Try using the \ve macro in an argument of \frac. My version will stay large; egreg's will become smaller (which is the sensible behaviour). Jan 19, 2021 at 18:03
• @Raymo111 LOL, yes, I know what is wrong :-D In the definition of \@ve there is \ifx#1\relax, and in this case this becomes \ifx((a))\relax so the two ( are compared and they are of course equal... I can't test now but quick fix: use \ifx\relax#1 instead. I'll see tomorrow if there are more pitfalls. Feb 4, 2021 at 19:23

The idea is good. Not so \ensuremath, of course.

\documentclass[twocolumn]{article} % twocolumn is just to get a smaller picture
\usepackage{amsmath}

\ExplSyntaxOn
\NewDocumentCommand{\ve}{m}
{
\mathchoice
{\raymo_ve_display:n {#1}}
{\raymo_ve_inline:n {#1}}
{\raymo_ve_inline:n {#1}}
{\raymo_ve_inline:n {#1}}
}
\cs_new_protected:Nn \__raymo_ve_make:n
{
\seq_set_split:Nnn \l__raymo_ve_body_seq { , } { #1 }
\seq_use:Nn \l__raymo_ve_body_seq { \\ }
}
\cs_new_protected:Nn \raymo_ve_display:n
{
\begin{pmatrix}
\__raymo_ve_make:n { #1 }
\end{pmatrix}
}
\cs_new_protected:Nn \raymo_ve_inline:n
{
\left(\begin{smallmatrix}
\__raymo_ve_make:n { #1 }
\end{smallmatrix}\right)
}
\ExplSyntaxOff

\begin{document}

This is inline $\ve{1,2,x}$ and there is also a display
$\ve{1,2,x}$

\end{document}


If you're not running the latest LaTeX kernel (2020-10-01), you need \usepackage{xparse}.

I find expl3 much better than xstrings.

“Optimized” code for also supporting row vectors:

\documentclass[twocolumn]{article} % twocolumn is just to get a smaller picture
\usepackage{amsmath,mathtools}

\ExplSyntaxOn
\NewDocumentCommand{\gve}{mm}
{% #1 = c or r
\mathchoice
{\raymo_ve_build:nnn {#1}{#2}{}}
{\raymo_ve_build:nnn {#1}{#2}{small}}
{\raymo_ve_build:nnn {#1}{#2}{small}}
{\raymo_ve_build:nnn {#1}{#2}{small}}
}
\NewDocumentCommand{\ve}{m}{\gve{c}{#1}}
\NewDocumentCommand{\rve}{m}{\gve{r}{#1}}

\cs_new_protected:Nn \__raymo_ve_make:nn
{
\seq_set_split:Nnn \l__raymo_ve_body_seq { , } { #2 }
\seq_use:Nn \l__raymo_ve_body_seq { \str_case:nn {#1}{{c}{\\}{r}{&}} }
}
\cs_new_protected:Nn \raymo_ve_build:nnn
{
\begin{p#3matrix}
\__raymo_ve_make:nn { #1 } { #2 }
\end{p#3matrix}
}
\ExplSyntaxOff

\begin{document}

This is inline $\ve{1,2,x}\rve{1,2,x}$ and there is also a display
$\ve{1,2,x}\rve{1,2,x}$

\end{document}


• Thanks for a working answer! Upvoted, though I must accept @campa's answer as it doesn't involve using xparse and is overall shorter and easier to read. Jan 19, 2021 at 17:28