# Expressive macro for tensors; raised and lowered indices

Does anyone have a satisfying solution to the problem of typesetting tensors with raised/lowered indices? For example, I can write the following equation: \ddot x^\mu = \Gamma^{\mu}{}_{\alpha}{}_{\beta} \dot x^\alpha \dot x^\beta

When writing a lot of tensors, this is cumbersome.

What I'm looking for is a way to construct a command which can produce tensors like \Gamma above with more expressive syntax. For example, a command \tens that operates like this would be ideal:

\ddot \tens{x}{\mu} = \tens{Gamma}{\mu}[\alpha][\beta] \dot \tens{x}{\alpha} \tens{x}{\beta}

The key quality of my desired syntax is that there is an arbitrary number of arguments of two distinct types. Argument encased in { } are raised indices, while arguments encased in [ ] are lowered indices. I don't need a command that looks exactly like this; I am looking for something that is similarly expressive.

Does anyone have a solution to this problem? An implementation of a \tens command that works as above? I don't know how to do this.

• Potentially useful: tex.stackexchange.com/q/98443/218142 – LaTeXereXeTaL Nov 27 '20 at 2:16
• @LaTeXereXeTaL - thanks. I don't know how to adjust the answer there, and it's a different problem because in this case there is no fixed number of arguments. For my use case, upper and lower indices may occur any number of times, and in any order. – Myridium Nov 27 '20 at 2:21
• I'm not sure if it's actually possible for the \tens function to determine when its argument list has ended... maybe I need to declare the total number of upper and lower indices as an argument to \tens. – Myridium Nov 27 '20 at 2:22
• With the tensor package you can type \tensor{\Gamma}{^\mu_\alpha_\beta} which seems not far from your idea. – egreg Nov 27 '20 at 9:06

In my opinion, the subscripts and superscripts are a single argument.

You can use the tensor package, without reinventing the wheel: it has a very handy syntax.

I also provide a \tens command according to your preferences.

\documentclass{article}
\usepackage{tensor}

%\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\tens}{mo}
{
#1
\IfNoValueTF { #2 }
{
\__myridium_tens_up_lookup:
}
{
\__myridium_tens_down_lookup: [ #2 ]
}
}

\cs_new_protected:Nn \__myridium_tens_down_lookup:
{
\peek_charcode_ignore_spaces:NTF [
{
\__myridium_tens_down:w
}
{ \kern2\scriptspace }
}
\cs_new_protected:Npn \__myridium_tens_down:w [ #1 ]
{
{\mathstrut}
\sb{#1}
\kern-\scriptspace
\__myridium_tens_up_lookup:
}
\cs_new_protected:Nn \__myridium_tens_up_lookup:
{
\peek_catcode_ignore_spaces:NTF \c_group_begin_token
{
\__myridium_tens_up:n
}
{ \kern2\scriptspace }
}
\cs_new_protected:Nn \__myridium_tens_up:n
{
{\mathstrut}
\sp{#1}
\kern-\scriptspace
\__myridium_tens_down_lookup:
}
\ExplSyntaxOff

\begin{document}

\subsection*{With \texttt{tensor}}
$\tensor{\ddot{x}}{^\mu}= \tensor{\Gamma}{^\mu_\alpha_\beta} \tensor{\dot{x}}{^\alpha} \tensor{\dot{x}}{^\beta}$

$\tensor{\Gamma}{_\mu^\nu^\rho_\alpha^\nu^\rho} \tensor{\dot{\Gamma}}{_\mu^\nu^\rho_\alpha^\nu^\rho}$

$\tens{\ddot{x}}{\mu}= \tens{\Gamma}{\mu}[\alpha\beta] \tens{\dot{x}}{\alpha} \tens{\dot{x}}{\beta}$

$\tens{\Gamma}[\mu]{\nu\rho}[\alpha]{\nu\rho} \tens{\dot{\Gamma}}[\mu]{\nu\rho}[\alpha]{\nu\rho}$

\end{document}

• What you are making there is equivalent in all but name to having a g-type argument, which is something you seem to strongly oppose. I don’t quite understand why g-types are supposed to be awful, but de facto g-types are fine. – Gaussler Nov 27 '20 at 13:39
• @Gaussler I answered the OP's question. This doesn't mean I endorse this kind of syntax, as explained in the first paragraph of my answer. – egreg Nov 27 '20 at 13:43
• Thanks, I wasn't aware of the tensor package. I agree it is syntactically better. Where should I go to learn how to understand the custom \tens command you defined? – Myridium Nov 27 '20 at 23:38
• @Myridium That's just a proof-of-concept written in the expl3 language. Do texdoc expl3 and texdoc interface3. – egreg Nov 28 '20 at 0:01
• Regarding the tensor package, the maintainer sent me an updated version that addresses the issue raised in this question tex.stackexchange.com/a/558820/218142. The update has not yet been pushed to CTAN however. – LaTeXereXeTaL Nov 30 '20 at 16:07

I wouldn’t use such a syntax, but SemanTeX can be set up to accomplish something resembling this (disclaimer: I am the author). Note that you will need a recent update of SemanTeX (October or later, I think) for this example to work. Note that I also prefer defining keys dot and ddot instead of directly using the commands \dot and \ddot.

\documentclass{article}

\usepackage{semantex}

\NewVariableClass\tens[
output=\tens,
definekeys={
{dot}{ command=\dot },
{ddot}{ command=\ddot },
{preindex}{ rightreturn, symbolputright={{}} },
{postindex}{ rightreturn, symbolputright=\kern-\scriptspace },
},
definekeys[1]={
{default}{ preindex, lower={#1}, postindex },
{arg}{ preindex, upper={#1}, postindex },
},
]

\begin{document}

$\tens{\dot x}{\mu} = \tens{\dot{\Gamma}}{\mu}[\alpha][\beta] \tens{\dot{x}}{\alpha} \tens{\dot{x}}{\beta}$

$\tens{\ddot x}{\mu} = \tens{\dot{\Gamma}}{\mu}[\alpha][\beta] \tens{\dot{x}}{\alpha} \tens{\dot{x}}{\beta}$

$\tens{x}[ddot]{\mu} = \tens{\Gamma}[dot]{\mu}[\alpha][\beta] \tens{x}[dot]{\alpha} \tens{x}[dot]{\beta}$

\end{document}

Personally, I would prefer to use a more keyval-based syntax, as below:

\documentclass{article}

\usepackage{semantex}

\NewVariableClass\Tensor[
output=\Tensor,
definekeys={
{dot}{ command=\dot },
{ddot}{ command=\ddot },
{preindex}{ rightreturn, symbolputright={{}} },
{postindex}{ rightreturn, symbolputright=\kern-\scriptspace },
},
definekeys[1]={
{up}{ preindex, upper={#1}, postindex },
{low}{ preindex, lower={#1}, postindex },
},
]

\begin{document}

$\Tensor{x}[dot,up=\mu] = \Tensor{\Gamma}[dot,up=\mu,low=\alpha,low=\beta] \Tensor{x}[dot,up=\alpha] \Tensor{x}[dot,up=\beta]$

$\Tensor{x}[dot,up=\mu] = \Tensor{\Gamma}[dot,up=\mu,low=\alpha,low=\beta] \Tensor{x}[dot,up=\alpha] \Tensor{x}[dot,up=\beta]$

\NewObject\Tensor\tGamma{\Gamma}
\NewObject\Tensor\tx{x}

$\tx[dot,up=\mu] = \tGamma[dot,up=\mu,low=\alpha,low=\beta] \tx[dot,up=\alpha] \tx[dot,up=\beta]$

$\tx[dot,up=\mu] = \tGamma[dot,up=\mu,low=\alpha,low=\beta] \tx[dot,up=\alpha] \tx[dot,up=\beta]$

\end{document}

Here is something that works like you describe but with round brackets instead of curly ones. As usual such things can be a bit fragile, so occasionally you need to \relax a bit to mark it fully work, as can be seen in the second example.

\documentclass{article}
\makeatletter
\edef\tens@u{(}
\edef\tens@l{[}
\def\tens@U#1)#2{{}^{#1}\expandafter\tens@i#2\relax}
\def\tens@L#1]#2{{}_{#1}\expandafter\tens@i#2\relax}
\def\tens@i#1#2{\edef\tens@t{#1}%
\ifx\tens@t\tens@u
\expandafter\tens@U#2
\else
\ifx\tens@t\tens@l
\expandafter\tens@L#2
\else
#1#2
\fi
\fi}
\def\tens#1#2{#1\expandafter\tens@i#2}
\makeatother
\begin{document}
\begin{tabular}{rl}
works: &
$\tens{\Gamma}[\mu](\nu\rho)[\alpha](\nu\rho) \dot\tens{x}(\alpha) \dot\tens{x}(\beta)$ \\[2em]

does not work: &
$\tens{\Gamma}[\mu](\nu\rho)[\alpha](\nu\rho) \dot\tens{x}(\alpha) \tens{x}(\beta)$ \\[2em]

relax and it works again: &
$\tens{\Gamma}[\mu](\nu\rho)[\alpha](\nu\rho) \dot\tens{x}(\alpha)\relax \tens{x}(\beta)$ \\
\end{tabular}
\end{document}

To be clear: such macros are mainly for recreation purposes and not for the real world. These days the LaTeX world has enough other problems...

The definition of your desired macro \tens using TeX primitives follows:

\def\tens#1{#1\futurelet\next\tensA}
\def\tensA{\def\tensX{}%
\ifx\next[\def\tensX[##1]{{}_{##1}\futurelet\next\tensA}\fi
\ifx\next\bgroup \def\tensX##1{{}^{##1}\futurelet\next\tensA}\fi
\tensX}

%% test:

$\tens\Gamma [\mu]{\nu\rho}[\alpha]{\nu\rho}$

$\ddot\tens{x}{\mu} = \tens{\Gamma}{\mu}[\alpha][\beta] \dot\tens{x}{\alpha} \dot\tens{x}{\beta}$
• Thank you, this is the simplest and I could probably reverse engineer this to learn something. – Myridium Nov 30 '20 at 15:14
• You need not to do complicate reverse engineering: there are only four well documented TeX primitives \def, \futurelet, \ifx, \fi. – wipet Nov 30 '20 at 15:20