8

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

enter image description here

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.

4
  • 1
    Potentially useful: tex.stackexchange.com/q/98443/218142 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
  • 2
    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
7

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}
\]

\subsection*{With the hand-made macro}
\[
\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}

enter image description here

5
  • 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. Nov 30 '20 at 16:07
5

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,
    define keys={
        {dot}{ command=\dot },
        {ddot}{ command=\ddot },
        {pre index}{ right return, symbol put right={{}} },
        {post index}{ right return, symbol put right=\kern-\scriptspace },
    },
    define keys[1]={
        {default}{ pre index, lower={#1}, post index },
        {arg}{ pre index, upper={#1}, post index },
    },
]

\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}

enter image description here


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

\documentclass{article}

\usepackage{semantex}

\NewVariableClass\Tensor[
    output=\Tensor,
    define keys={
        {dot}{ command=\dot },
        {ddot}{ command=\ddot },
        {pre index}{ right return, symbol put right={{}} },
        {post index}{ right return, symbol put right=\kern-\scriptspace },
    },
    define keys[1]={
        {up}{ pre index, upper={#1}, post index },
        {low}{ pre index, lower={#1}, post index },
    },
]

\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}

enter image description here

2

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}

enter image description here

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...

1

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}$
2
  • Thank you, this is the simplest and I could probably reverse engineer this to learn something.
    – Myridium
    Nov 30 '20 at 15:14
  • 1
    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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.