3

I have been using something like

\renewcommand\vec[1] {\boldsymbol{\MakeLowercase{#1}}}
\newcommand\mat[1]   {\boldsymbol{\MakeUppercase{#1}}}

for some time now to typeset vectors and matrices. However, every time this comes up when I ask a question, people tell me it is a bad idea to use \Makeuppercase in math mode. Furthermore, \Makeuppercase is pretty much broken for me at this point, so I might need an alternative.

For this alternative, I was thinking it would suffice if I could issue a warning when a lowercase symbol is used for matrices (or an uppercase symbol for vectors). I know how to issue a warning using \@warning or \GenericWarning, but I can't figure out how to test if something is lower- or upper case.

Also, would this actually be a better way to enforce consistent typesetting of vectors and matrices as described above or should I consider something completely different?


Addendum

Because everyone keeps on commenting how bad of an idea it is to enforce case in math mode I feel that I have to emphasise that I am aware of these concerns and this is my attempt to find a workaround. My main concern is that the commands I had, helped me to keep my notation consistent and the semantics of my LaTeX code clear and I would prefer to keep this consistency somehow.

To give an example, a typical set of equations that I work with looks as follows:

\begin{align*}
  \vec{f} &= \sigma(\mat{W}_\mathrm{fx} \vec{x} + \mat{W}_\mathrm{fh} \vec{h} + \vec{b}_\mathrm{f}) \\
  \vec{i} &= \sigma(\mat{W}_\mathrm{ix} \vec{x} + \mat{W}_\mathrm{ih} \vec{h} + \vec{b}_\mathrm{i}) \\
  \vec{s} &= \sigma(\mat{W}_\mathrm{sx} \vec{x} + \mat{W}_\mathrm{sh} \vec{h} + \vec{b}_\mathrm{s}) \\
  \vec{c} &\gets \vec{f} \odot \vec{c} + \vec{i} \odot \phi(\vec{s})
\end{align*}

Now, depending on context, it might be useful/necessary to write this as follows:

\begin{align*}
  \mat{F} &= \sigma(\mat{X} \mat{W}_\mathrm{fx}^\mathsf{T} + \mat{H} \mat{W}_\mathrm{fh} + \vec{b}_\mathrm{f} \mat{1}) \\
  \mat{I} &= \sigma(\mat{X} \mat{W}_\mathrm{ix}^\mathsf{T} + \mat{H} \mat{W}_\mathrm{ih} + \vec{b}_\mathrm{i} \mat{1}) \\
  \mat{S} &= \sigma(\mat{X} \mat{W}_\mathrm{sx}^\mathsf{T} + \mat{H} \mat{W}_\mathrm{sh} + \vec{b}_\mathrm{s} \mat{1}) \\
  \mat{C} &\gets \mat{F} \odot \mat{C} + \mat{I} \odot \phi(\mat{S})
\end{align*}

In these transformations it often happens that I overlook the capitalisation of one or more variables. Because these equations align quite nicely, it would be easy to spot in the output, but it also happens that it is not immediately visible. I find that the \vec and \mat commands make the LaTeX core more readable and when checking the formulas I find it easier to focus on those commands than on the actual case of each variable. I just like to believe that there is nothing wrong with using technology to compensate for my shortcomings.

This being said, I agree that enforcing case is not the best thing to do. Therefore, I am now looking for a solution that notifies me when the case does not match what I expect for a vector/matrix so that I don't have to do the checking manually.

  • 2
    If you want A then type A, and if you want a, then type a. Shorter and simpler. And you likely know what object you are writing about. – mickep Jan 15 '24 at 14:08
  • The problem is that I have these things wrapped in commands \vec and \mat, resp. and it regularly happens that I (have to) rewrite the math so that \vec becomes a regular scalar and \mat becomes a \vec or vice versa. – Mr Tsjolder from codidact Jan 15 '24 at 14:12

2 Answers2

3

Check whether the argument is the same as its lowercase/uppercase version. If they differ, issue a warning.

\documentclass{article}
\usepackage{amsmath}
\usepackage{bm}

\ExplSyntaxOn

\RenewDocumentCommand{\vec}{m}{\tsjolder_vec:n { #1 }} \NewDocumentCommand{\mat}{m}{\tsjolder_mat:n { #1 }}

\msg_new:nnn { tsjolder/vec-mat } { wrong-case} { WARNING:~#1~used~when~#2~is~expected~\msg_line_context: }

\cs_new_protected:Nn \tsjolder_vec:n { \str_if_eq:eeTF { #1 } { \str_lowercase:n { #1 } } { \bm{#1} } { \msg_warning:nnnn { tsjolder/vec-mat } { wrong-case} { uppercase } { lowercase } \bm{\text_lowercase:n { #1 }} } } \cs_new_protected:Nn \tsjolder_mat:n { \str_if_eq:eeTF { #1 } { \str_uppercase:n { #1 } } { \bm{#1} } { \msg_warning:nnnn { tsjolder/vec-mat } { wrong-case} { lowercase } { uppercase } \bm{\text_uppercase:n { #1 }} } }

\ExplSyntaxOn

\begin{document}

$\mat{a}\vec{B}$

\end{document}

With this code you'd get

Package tsjolder/vec-mat Warning: WARNING: lowercase used when uppercase is
(tsjolder/vec-mat)                expected on line 41

Package tsjolder/vec-mat Warning: WARNING: uppercase used when lowercase is (tsjolder/vec-mat) expected on line 41

in the log file and on the terminal, but the output will be correct anyway.

enter image description here

egreg
  • 1,121,712
  • This is exactly the point of my question: I don't necessarily want this. However, I do wish to have consistent notation. Therefore, my question is how to issue a warning when a vector is not lowercase. This would notify me of (possible) mistakes without enforcing anything. Your answer could solve my issue with \Makeuppercase, but this question is not really about that. – Mr Tsjolder from codidact Jan 15 '24 at 15:44
  • @MrTsjolderfromcodidact Implemented the requested check. – egreg Jan 15 '24 at 16:44
2

You can retrieve the character code with `[char] and compare that with \ifnum. Upper case latin is 65-90 and lower case is 97-122.

MWE:

\documentclass{article}
\def\vec#1{\ifnum`#1<97 #1 not lc!\else$\mathbf{#1}$\fi}
\def\mat#1{\ifnum`#1>90 #1 not uc!\else$\mathbf{#1}$\fi}

\begin{document} \vec{X}

\vec{x}

\mat{X}

\mat{x} \end{document}

Result:

enter image description here


A more robust version that checks the actual ranges and can handle predefined arguments instead of literal characters, using stringstrings:

\documentclass{article}
\usepackage{stringstrings}
\def\vec#1{\testsolelylowercase{#1}\ifsolelylowercase$\mathbf{#1}$\else#1 not lc!\fi}
\def\mat#1{\testsolelyuppercase{#1}\ifsolelyuppercase$\mathbf{#1}$\else#1 not uc!\fi}

\begin{document} \vec{X}

\vec{x}

\mat{X}

\mat{x}

% this one fails with the \ifnum code above \def\myx{x} \mat{\myx} \end{document}


I adjusted the logic of the stringstrings checks a bit such that non-alphabetic arguments such as \delta and 1 are permitted, and the macros only check the first character so things like X' are also ok for a matrix (but x' is not).

The check now is: if the first character is non-alphabetic then print always, otherwise check if the first character is upper case, then reject for a vector and accept for a matrix. Note that I changed the macro names because \vec is already defined.

Also I moved the math mode outside of the command, which works fine. I used \text from amsmath for the message, but I imagine this should be an actual \GenericWarning and then \text is not needed.

\documentclass{article}
\usepackage{amsmath}
\usepackage{stringstrings}
\def\chkvec#1{%
   \testleadingalpha{#1}%
   \ifleadingalpha%
      \testcapitalized{#1}%
      \ifcapitalized%
         \text{vector argument } #1 \text{ starts with upper case!}%
      \else%
         \mathbf{#1}%
      \fi%
   \else%
      \mathbf{#1}%
   \fi}
\def\chkmat#1{%
   \testleadingalpha{#1}%
   \ifleadingalpha%
      \testcapitalized{#1}%
      \ifcapitalized%
         \mathbf{#1}%
      \else%
         \text{matrix argument }#1\text{ starts with lower case!}%
      \fi%
   \else%
      \mathbf{#1}%
   \fi}

\begin{document} $\chkvec{X^2}$

$\chkvec{x^2}$

$\chkmat{X'}$

$\chkmat{x'}$

\def\myx{X}

$\chkmat{\myx}$

$\chkvec{\delta}$

$\chkvec{1}$ \end{document}

enter image description here

Marijn
  • 37,699
  • Your first solution seems to work great for letters, but I also occasionally use this for numbers, like $\vec{1}$ (which leads to unnecessary warnings for vectors) and greek literals, like $\vec{\delta}$, (which simply fails entirely). I guess numbers is just another check, but any idea about the greek letters?

    The second solution seems to fail when putting the math mode outside of the command (i.e. $\vec{x}$ with \ifsolelylowercase\mathbf{#1}\else).

    – Mr Tsjolder from codidact Jan 15 '24 at 15:27
  • PS: it would be great if the error for $\delta$ could be avoided, I do not insist on checking the difference between $\delta$ and $\Delta$ (\MakeUppercase also ignores greek letters), but bonus points if you would know how to do this... – Mr Tsjolder from codidact Jan 15 '24 at 15:46
  • @MrTsjolderfromcodidact I modified the code a bit to allow for the extra cases you mentioned. – Marijn Jan 17 '24 at 13:53