2

I want to define a set of macros, with similar behaviour but applied to different symbols. To avoid repetitions, I thought it would be a good idea to generate them programmatically from a template.

I have a bunch of quantities

  1. with general indices (\idx) applied to them,
  2. but I occasionally need variations of this index (e.g., for defining recurrence relations);
  3. or to scrap the automatic index altogether and replace it with something else.

I thought of using a O{\idx} argument type, but I do not like this solution, as I would like to especially restate \idx for 2.. It seems like a star argument could be useful here.

This is why I came up with:

\documentclass[12pt]{article}

\usepackage{amsmath}

\NewDocumentCommand\idx{}{j}
\NewDocumentCommand\pmatstar{mm}{#1_{#2}}
\NewDocumentCommand\pmatnostar{mm}{#1_{\idx#2}}
\NewDocumentCommand\matnum{smO{}}{
    \IfBooleanTF{#1}{
        \pmatstar{#2}{#3}
    }{
        \pmatnostar{#2}{#3}
    }
}

%%%%%
% What I do not know how to do
%
% \NewDocumentCommand\specmatnum{mm}{...}
% \spectmatnum{mlow}{L}
% \spectmatnum{mupp}{U}
% ...
%
%%%%%

%%%%%
% This is what I want to avoid
%
% \NewDocumentCommand\mlow{sO{}}{
%     \IfBooleanTF{#1}{
%         \pmatstar{L}{#2}
%     }{
%         \pmatnostar{L}{#2}
%     }
% }
% \NewDocumentCommand\mupp{sO{}}{
%     \IfBooleanTF{#1}{
%         \pmatstar{U}{#2}
%     }{
%         \pmatnostar{U}{#2}
%     }
% }
% ...
%
%%%%%
\begin{document}

\begin{align*}
\text{Default: } &\matnum{L}\\
\text{No star, modified default: } &\matnum{L}[+1]\\
\text{Star, no optional argument: } &\matnum*{L}\\
\text{Star, optional '2': } &\matnum*{L}[2]
\end{align*}

%%%%%
% How I would like to be able to replicate the above example without calling \matnum directly
%
% \mlow
% \mlow[+1]
% \mlow*
% \mlow*[2]
%
%%%%%

\end{document}

Example output

My question being, how not to duplicate the definition of \matnum for all my symbols? The main difficulty for me being the passing of the *, without rewriting the \IfBooleanTF{}{}{}; which nullifies the point of having \matnum in the first place. I think the rest is straightforward.

2 Answers 2

4

enter image description here

\documentclass[12pt]{article}

\usepackage{amsmath}

\NewDocumentCommand\idx{}{j}
\NewDocumentCommand\matnum{msO{}}{#1_{\IfBooleanF{#2}{\idx}#3}}

\NewDocumentCommand\specmatnum{mm}{%
 \ExpandArgs{c}\NewDocumentCommand{#1}{}{\matnum{#2}}}

\specmatnum{mlow}{L}
\specmatnum{mupp}{U}

\begin{document}

\begin{align*}
\text{Default: } &\mlow\\
\text{No star, modified default: } &\mlow[+1]\\
\text{Star, no optional argument: } &\mlow*\\
\text{Star, optional '2': } &\mlow*[2]
\end{align*}


\end{document}
3
  • Thanks, it seems to work brilliantly when built on Overleaf. However, I cannot get it to work on my own machine, which sports a more recent version of TeX Live (format=lualatex 2022.11.10 against format=lualatex 2022.8.9). ExpandArgs seems to be a fairly new addition? It does not appear on the 2021-04-12 version of New LaTeX methods for authors. I do have it defined it latex.ltx and latexrelease.sty, under /usr/share/texmf-dist/tex/latex-dev. I have manual entries, but no binaries for the *-dev versions. Any thoughts?
    – Aubergine
    Commented Nov 29, 2022 at 6:11
  • @Aubergine you have that backwards, it works on recent releases but not on your older one. If you can not update your machine to texlive 2022 then replace \ExpandArgs{c}\NewDocumentCommand{#1} by \expandafter\NewDocumentCommand\csname#1\endcsname Commented Nov 29, 2022 at 9:07
  • @Aubergine or simpler use the syntax \specmatnum{\mlow}{L} and \NewDocumentCommand#1 the expansion control is just for the requested syntax with no \ (which is a strange choice anyway as you use the command with a \ ) Commented Nov 29, 2022 at 9:12
3

Write down what you want to abstract and it becomes simpler:

\documentclass{article}
\usepackage{amsmath}

% we want that
% \spectmatnum{\mlow}{L}
% defines \mlow so
% \mlow -> L_{j}
% \mlow[+1] -> L_{j+1}
% \mlow* -> L
% \mlow*[2] -> L_{2}
%
% \NewDocumentCommand{\mlow}{so}{%
%   L%
%   \IfBooleanTF{#1}{%
%     \IfValueT{#2}{_{#2}}%
%   }{%
%     _{\idx\IfValueT{#2}{#2}}%
%   }%
% }

\NewDocumentCommand{\spectmatnum}{mm}{%
  % #1 = command name
  % #2 = letter
  \NewDocumentCommand{#1}{so}{%
    #2%
    \IfBooleanTF{##1}{%
      \IfValueT{##2}{_{##2}}%
    }{%
      _{\idx\IfValueT{##2}{##2}}%
    }%
  }%
}

\NewDocumentCommand{\idx}{}{j}

\spectmatnum{\mlow}{L}
\spectmatnum{\mupp}{U}



\begin{document}

$\mlow\quad\mlow[+1]\quad\mlow*\quad\mlow*[2]$

$\mupp\quad\mupp[+1]\quad\mupp*\quad\mupp*[2]$

%%% comparison with \matnum
\NewDocumentCommand\matnum{msO{}}{#1_{\IfBooleanF{#2}{\idx}#3}}
\NewDocumentCommand{\MLOW}{}{\matnum{L}}

$\mlow*|$

$\MLOW*|$

\end{document}

The parameters in the inner \NewDocumentCommand become ##1 and ##2, whereas #1 and #2 refer to the argument to the outer one.

Since \spectmatnum defines a command, just give the command as argument, not just the name.

Why not sO{\idx} as the argument specifier? You can see the reason at the bottom, where the presence of an unwanted space is shown.

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .