Cadabra quick start
This is a quick start introduction to Cadabra. For more in-depth discussion of its features, consult the various tutorials. After installation, Cadabra can be started withcadabra2-gtk
from the command line,
or by picking it from the 'Education' menu.
Bosonic basics
Before discussing actual calculations, let us start with a few words concerning notation. This discussion can be short because mathematical expressions are entered essentially as one would enter them in TeX (with a few restrictions to avoid ambiguities, which we will discuss as we go along). In order to manipulate expressions, Cadabra often needs to know a bit more about properties of tensors or other symbols. Such properties are entered using the '::
' symbol. A simple example is the declaration of
index sets, useful for automatic dummy index relabelling. An example
will clarify this,{ a, b, c, d }::Indices;
ex:= A_{a b} B_{b c};
\(\displaystyle{}\text{Attached property Indices(position=free) to }\left[a, b, c, d\right].\)
\(\displaystyle{}A_{a b} B_{b c}\)
A_{a b} B_{b c}
substitute(_, $B_{a b} -> C_{a b c} D_{c}$ );
\(\displaystyle{}A_{a b} C_{b c d} D_{d}\)
A_{a b} C_{b c d} D_{d}
The automatic index relabelling which has taken place in this
substitute command was clearly only possible because of the property
declaration in the first line. Note how the substitute command has
also figured out that
B_{a b}
on the left-hand side is
equivalent to B_{b c}
, without any explicit wildcards or
patterns. We will see more of this type of field-theory motivated
logic throughout the paper.Indices can be simple letters, as in the example above, but it is also
perfectly possible to put accents on them. This can be useful for
e.g. notations involving chiral spinors. The following example
illustrates the use of accents on indices.
\dot{#}::Accent;
A_{\dot{a} \dot{b}}::AntiSymmetric;
ex:= A_{\dot{b} \dot{a}};
canonicalise(_);
\(\displaystyle{}-A_{\dot{a} \dot{b}}\)
Here we also see a second usage of property declarations: the
construction in the first line declares that the $A_{\dot{a} \dot{b}}$
tensor is antisymmetric in its indices. The canonicalise command
subsequently writes the input in a canonical form, which in this
trivial example simply means that the indices gets sorted in
alphabetical order. Continuing the example above, one can also use
subscripts or superscripts on indices, as in the example below.
{ a_{1}, a_{2}, a_{3}, a_{4} }::Indices(vector);
ex:= V_{a_{1}} W_{a_{1}};
substitute(_, $V_{a_{2}} -> M_{a_{2} a_{1}} N_{a_{1}}$ );
\(\displaystyle{}\text{Attached property Indices(position=free) to }\left\{a_{1}, \mmlToken{mo}[linebreak="goodbreak"]{} a_{2}, \mmlToken{mo}[linebreak="goodbreak"]{} a_{3}, \mmlToken{mo}[linebreak="goodbreak"]{} a_{4}\right\}.\)
\(\displaystyle{}V_{a_{1}} W_{a_{1}}\)
\(\displaystyle{}M_{a_{1} a} N_{a} W_{a_{1}}\)
The input format is a mixture of Cadabra's own LaTeX-like language for
the description of mathematical expressions, and Python. The
underscore symbol '
_
' always refers to the last-used expression.A guiding principle in Cadabra is that nothing ever has to be declared
unless this is absolutely needed. This is in contrast to many other
systems, where for instance one has to declare manifolds and index
sets and so on before one can even enter a tensor expression. This
makes code hard to read, but more importantly, such additional
declarations are hard to remember. As an example of how Cadabra works,
one can e.g. input tensor expressions and perform substitution on them,
without ever declaring the symbols used for indices. Only when the
program needs to generate new dummy indices does one need to declare
index sets, so that dummy indices can be taken out of the right
set. The general guideline is that "one only
needs to tell the program about the meaning of symbols when this is
actually required to do the manipulation correctly".
In order to declare symmetries of tensors, it is possible to use
simple shorthands like the
AntiSymmetric
in the example above.
More generally, symmetries can be declared using a generic Young
tableau notation. An object with the symmetries of a Riemann tensor,
for example, can be declared as in the following example.R_{a b c d}::TableauSymmetry(shape={2,2}, indices={0,2,1,3}).
ex:=R_{a b c d} R_{d c a b};
canonicalise(_);
\(\displaystyle{}R_{a b c d} R_{d c a b}\)
\(\displaystyle{}-R_{a b c d} R_{a b c d}\)
The first line indicates that the tensor has the symmetries of the
$2\times 2$ Young tableau. The
canonicalise
command writes
the input in canonical form with respect to mono-term symmetries
(anti-symmetry in the two index pairs and symmetry under pair
exchange). The Ricci symmetry is also encoded in the Young tableau and
will be discussed later. Many tensor symmetries have shorthand
notations, so one often does not have spell out the tableau (e.g. RiemannTensor
or SatisfiesBianchi
).
Derivatives and dependencies
There are relatively few surprises when it comes to derivatives. It is possible to write derivatives with respect to coordinates, i.e. write $\partial_x$ where $x$ is a coordinate, but it is also possible to use indices, as in $\partial_i$ with $i$ being a vector index. It is also possible to make objects implicitly dependent on a derivative operator, so that one can write $\partial A$ without an explicit specification of the coordinate which is involved here.In order to make this possible, however, derivative objects have to be
declared just like indices, otherwise the system does not know which
symbol ($\partial$, $D$, $d$, $\nabla$, ...) one wants to use for
them. Implicit dependencies of objects on coordinates associated to
derivatives is indicated through a
Depends
property. Here is an
example to illustrate all this:{m,n,p,q,r}::Indices(position=free);
\nabla{#}::Derivative;
\partial{#}::PartialDerivative;
A_{m n}::AntiSymmetric;
V_{m}::Depends(\nabla{#});
ex:= \partial_{m p}( A_{q r} V_{n} ) A^{p m};
\(\displaystyle{}\text{Attached property Indices(position=free) to }\left\{m, \mmlToken{mo}[linebreak="goodbreak"]{} n, \mmlToken{mo}[linebreak="goodbreak"]{} p, \mmlToken{mo}[linebreak="goodbreak"]{} q, \mmlToken{mo}[linebreak="goodbreak"]{} r\right\}.\)
\(\displaystyle{}\text{Attached property Derivative to }\nabla{\#}.\)
\(\displaystyle{}\text{Attached property PartialDerivative to }\partial{\#}.\)
\(\displaystyle{}\text{Attached property AntiSymmetric to }A_{m n}.\)
\(\displaystyle{}\text{Attached property Depends to }V_{m}.\)
\(\displaystyle{}\partial_{m p}\left(A_{q r} V_{n}\right) A^{p m}\)
canonicalise(_);
\(\displaystyle{}0\)
ex:=\nabla_{m p}( A_{q r} V_{n} ) A^{p m};
canonicalise(_);
\(\displaystyle{}\nabla_{m p}\left(A_{q r} V_{n}\right) A^{p m}\)
\(\displaystyle{}-\nabla^{m p}\left(A_{q r} V_{n}\right) A_{m p}\)
unwrap(_);
\(\displaystyle{}-A_{q r} \nabla^{m p}{V_{n}} A_{m p}\)
Note how the symmetry of a double partial derivative has automatically
been taken into account (it
is part of the
PartialDerivative
property). This is called
"property inheritance".