# How to italicise characters, but not digits for a specific math font?

I created commands to display vectors, matrices and tensors. For the tensors I am using a bold italicised math font, which looks exactly as I want for characters. However, when denoting a tensor with a digit, things look inconsistent:

\documentclass{standalone}

\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{bm}

\DeclareMathAlphabet{\mathsfit}{T1}{\sfdefault}{m}{sl}
\SetMathAlphabet{\mathsfit}{bold}{T1}{\sfdefault}{bx}{sl}

\renewcommand\vec[1] {\bm{\MakeLowercase{#1}}}
\newcommand\mat[1]   {\bm{\MakeUppercase{#1}}}
\newcommand\ten[1]   {\bm{\mathsfit{\MakeUppercase{#1}}}}

\begin{document}

\begin{tabular}{lcccc}
& scalar & vector & matrix & tensor \\
character & $a$ & $\vec{a}$ & $\mat{a}$ & $\ten{a}$ \\
digit & $1$ & $\vec{1}$ & $\mat{1}$ & $\ten{1}$
\end{tabular}

\end{document}


As you can see, the digits are generally not italicised in the regular math font. However, when using the custom math font for the tensors, they are slanted, which leads to an inconsistent look. I tried to create a solution with \DeclareMathSymbol (as in this answer), but this changed all digits (also the scalar, vector and matrix digits).

Is there any way to avoid numbers being italicised for this custom tensor font?

You can exploit the fact that math alphabet choices are not cumulative.

\documentclass{article}
\usepackage{fix-cm}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{bm}

\DeclareMathAlphabet{\mathsfit}{T1}{\sfdefault}{m}{sl}
\SetMathAlphabet{\mathsfit}{bold}{T1}{\sfdefault}{bx}{sl}

\ExplSyntaxOn
\RenewDocumentCommand\vec{m}
{ \bm { \text_lowercase:n { #1 } } }
\NewDocumentCommand\mat{m}
{ \bm { \text_uppercase:n { #1 } } }
\NewDocumentCommand\ten{m}
{
\tsjolder_tensor_check_number:n { #1 }
\bm { \mathsfit { \l__tsjolder_tensor_tl } }
}

\tl_new:N \l__tsjolder_tensor_tl

\cs_new_protected:Nn \tsjolder_tensor_check_number:n
{
\tl_set:Nx \l__tsjolder_tensor_tl { \text_uppercase:n { #1 } }
\regex_replace_all:nnN { ([[:digit:]]) } { \c{mathsf}\cB\{\1\cE\} } \l__tsjolder_tensor_tl
}

\ExplSyntaxOff

\begin{document}

\begin{tabular}{lcccc}
& scalar & vector & matrix & tensor \\
character & $a$ & $\vec{a}$ & $\mat{a}$ & $\ten{a}$ \\
digit & $1$ & $\vec{1}$ & $\mat{1}$ & $\ten{1}$
\end{tabular}

\end{document}


In the case of \ten, the digits in the arguments are replaced by \mathsf{<digit>}.

On the other hand, I can't see why uppercasing or lowercasing: if you mean a lowercase letter, you should input it as such. With this proviso and the assumption that the input is just one character, there is a simpler implementation:

\documentclass{article}
\usepackage{fix-cm}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{bm}

\DeclareMathAlphabet{\mathsfit}{T1}{\sfdefault}{m}{sl}
\SetMathAlphabet{\mathsfit}{bold}{T1}{\sfdefault}{bx}{sl}

\ExplSyntaxOn
\RenewDocumentCommand\vec{m}
{
\bm { #1 }
}

\NewDocumentCommand\mat{m}
{
\bm { #1 }
}
\NewDocumentCommand\ten{m}
{
\regex_match:nnTF { [[:digit:]] } { #1 }
{
\bm { \mathsf { #1 } }
}
{
\bm { \mathsfit { #1 } }
}
}

\ExplSyntaxOff

\begin{document}

\begin{tabular}{lcccc}
& scalar & vector & matrix & tensor \\
character & $a$ & $\vec{a}$ & $\mat{A}$ & $\ten{A}$ \\
digit & $1$ & $\vec{1}$ & $\mat{1}$ & $\ten{1}$
\end{tabular}

\end{document}

• The uppercase thing is mainly laziness because I often end up changing matrices to vectors and vice versa. Feb 24 at 9:41

The unicode-math package for LuaLaTeX or XeLaTeX lets you do what you want (except for automatically changing the case) with the right package options. Here, I choose a font where 𝟏 and 𝟭 are more distinct than the default.

\documentclass{article}
\usepackage[math-style=ISO, bold-style=ISO, sans-style=italic]{unicode-math}
\usepackage{libertinus}

\newcommand\vectorsym[1]{\symbf{#1}}
\newcommand\matrixsym[1]{\symbf{#1}}
\newcommand\tensorsym[1]{\symbfsf{#1}}

\begin{document}

\begin{tabular}{lcccc}
& scalar & vector & matrix & tensor \\
character & $a$ & $\vectorsym{a}$ & $\matrixsym{A}$ & $\tensorsym{A}$ \\
digit & $1$ & $\vectorsym{1}$ & $\matrixsym{1}$ & $\tensorsym{1}$
\end{tabular}

\end{document}


This set-up will also give you slanted uppercase Greek letters, should you use something like \vectorsym{\Psi}, but it is possible to tweak that.

If you should want to use upright letters for constant vectors, that would be \symbfup, which you could wrap in a command like \newcommand\cvector[1]{\symbfup{#1}}. There is similarly a \symbfsfup alphabet for constant tensors.

Some publishers still require authors to use PDFTeX in 2021. The closest thing to a package that does what you want is isomath, which provides \vectorsym, \tensorsym and \matrixsym commands. The \tensorsym digits probably won’t work the way you want, as existing sans-serif math fonts use those slots either for old-style numerals or have sans-serif italic digits. Although you could use \DeclareMathAlphabet commands directly to use a legacy font encoding other than OML, I’m not aware of any bold sans-serif TeX font with italic letters and upright digits.

However, you can define an upright sans-serif bold alphabet yourself:

\documentclass{article}
\usepackage{amsmath}
\usepackage{biolinum}
\usepackage[OMLmathrm,OMLmathsf]{isomath}

\newcommand\mathbfsfup[1]{%
\mathalpha{\text{\sffamily\bfseries\upshape\selectfont #1}}}

\newcommand\tensorone{\mathbfsfup{1}}

\begin{document}

\begin{tabular}{lcccc}
& scalar & vector & matrix & tensor \\
character & $a$ & $\vectorsym{a}$ & $\matrixsym{A}$ & $\tensorsym{A}$ \\
digit & $1$ & $\vectorsym{1}$ & $\matrixsym{1}$ & $\tensorone$
\end{tabular}

\end{document}


If you really, truly want a function with special handling for digits, you will need to write that wrapper function yourself. An expl3 function that performs regex search-and-replace (like egreg’s) could do the job.

• I have no experience with LuaLaTeX or XeLaTeX, but I tried the isomath solution. However this gives a much shorter 1 than the other fonts, which makes it look inconsistent again. Feb 24 at 10:05
• @MrTsjolder I think you’re referring to the old-style digits in the default \mathsfbfit. You can try a different font. Feb 24 at 14:10
• @MrTsjolder Alternatively, if you’re wrapping the whole thing in an expl3 function that processes the input, you could recognize digits and replace them with \mathsfbf{1}. Or you could define \mbfsansone as \mathsfbf{1}, as in unicode-math. Feb 24 at 14:12
• Could you point me to fonts with OML encodings? According to the comments in isomath.sty, there are only few fonts that would work with this approach. Feb 24 at 14:27
• @MrTsjolder See this list from 2012. For a more up-to-date list, search your TeX tree for files matching oml*.fd. Actually, let me edit in another solution. Feb 24 at 15:42

I ended up combining the information from the answers to this question.

I used the algorithm from this answer with a piece of code I found in the isomath package as suggested in this answer).

Concretely, I created a command to distinguish between numbers and non-numbers, as follows (I am not quite familiar with the explsyntax from the original answer):

\DeclareMathAlphabet{\mathsfit}{T1}{\sfdefault}{m}{sl}
\SetMathAlphabet{\mathsfit}{bold}{T1}{\sfdefault}{bx}{sl}

\newcommand\mathsans[1]  {%
\ifnum9<1#1
\mathsf{#1}%
\else
\mathsfit{#1}%
\fi
}


and then used the following tensor definition

\newcommand\ten[1]   {\bm{\MakeUppercase{\mathsans{#1}}}}


which got me the following result. I also added the table with isomath results for comparison:

The result is not exactly perfect, but I think the inconsistency is less apparent than the result I got with isomath.