# Space Time Algebra¶

## Intro¶

This notebook demonstrates how to use `clifford`

to work with Space
Time Algebra. The Pauli algebra of space \(\mathbb{P}\), and Dirac
algebra of space-time \(\mathbb{D}\), are related using the
*spacetime split*. The split is implemented by using a `BladeMap`

,
which maps a subset of blades in \(\mathbb{D}\) to the blades in
\(\mathbb{P}\). This *split* allows a spacetime bivector \(F\)
to be broken up into relative electric and magnetic fields in space.
Lorentz transformations are implemented as rotations in
\(\mathbb{D}\), and the effects on the relative fields are computed
with the split.

## Setup¶

First we import `clifford`

, instantiate the two algebras, and populate
the namespace with the blades of each algebra. The elements of
\(\mathbb{D}\) are prefixed with \(d\), while the elements of
\(\mathbb{P}\) are prefixed with \(p\). Although unconventional,
it is easier to read and to translate into code.

```
In [1]:
```

```
from clifford import Cl, pretty
pretty(precision=1)
# Dirac Algebra `D`
D, D_blades = Cl(1,3, firstIdx=0, names='d')
# Pauli Algebra `P`
P, P_blades = Cl(3, names='p')
# put elements of each in namespace
locals().update(D_blades)
locals().update(P_blades)
```

## The Space Time Split¶

To two algebras can be related by the spacetime-split. First, we create
a `BladeMap`

which relates the bivectors in \(\mathbb{D}\) to the
vectors/bivectors in \(\mathbb{P}\). The scalars and pseudo-scalars
in each algebra are equated.

```
In [2]:
```

```
from IPython.display import SVG
SVG('_static/split.svg')
```

```
Out[2]:
```

```
In [3]:
```

```
from clifford import BladeMap
bm = BladeMap([(d01,p1),
(d02,p2),
(d03,p3),
(d12,p12),
(d23,p23),
(d13,p13),
(d0123, p123)])
```

## Splitting a space-time vector (an event)¶

A vector in \(\mathbb{D}\), represents a unique place in space and time, i.e. an event. To illustrate the split, create a random event \(X\).

```
In [4]:
```

```
X = D.randomV()*10
X
```

```
Out[4]:
```

```
-(7.5^d0) - (6.6^d1) + (16.2^d2) + (1.3^d3)
```

This can be *split* into time and space components by multiplying with
the time-vector \(d_0\),

```
In [5]:
```

```
X*d0
```

```
Out[5]:
```

```
-7.5 + (6.6^d01) - (16.2^d02) - (1.3^d03)
```

and applying the `BladeMap`

, which results in a scalar+vector in
\(\mathbb{P}\)

```
In [6]:
```

```
bm(X*d0)
```

```
Out[6]:
```

```
-7.5 + (6.6^p1) - (16.2^p2) - (1.3^p3)
```

The space and time components can be separated by grade projection,

```
In [7]:
```

```
x = bm(X*d0)
x(0) # the time component
```

```
Out[7]:
```

```
-7.5
```

```
In [8]:
```

```
x(1) # the space component
```

```
Out[8]:
```

```
(6.6^p1) - (16.2^p2) - (1.3^p3)
```

We therefor define a `split()`

function, which has a simple condition
allowing it to act on a vector or a multivector in \(\mathbb{D}\).
Splitting a spacetime bivector will be treated in the next section.

```
In [9]:
```

```
def split(X):
return bm(X.odd*d0+X.even)
```

```
In [10]:
```

```
split(X)
```

```
Out[10]:
```

```
-7.5 + (6.6^p1) - (16.2^p2) - (1.3^p3)
```

The split can be inverted by applying the `BladeMap`

again, and
multiplying by \(d_0\)

```
In [11]:
```

```
x = split(X)
bm(x)*d0
```

```
Out[11]:
```

```
-(7.5^d0) - (6.6^d1) + (16.2^d2) + (1.3^d3)
```

## Splitting a Bivector¶

Given a random bivector \(F\) in \(\mathbb{D}\),

```
In [12]:
```

```
F = D.randomMV()(2)
F
```

```
Out[12]:
```

```
(1.9^d01) - (0.3^d02) - (0.7^d03) - (0.3^d12) + (0.6^d13) + (1.7^d23)
```

\(F\) *splits* into a vector/bivector in \(\mathbb{P}\)

```
In [13]:
```

```
split(F)
```

```
Out[13]:
```

```
(1.9^p1) - (0.3^p2) - (0.7^p3) - (0.3^p12) + (0.6^p13) + (1.7^p23)
```

If \(F\) is interpreted as the electromagnetic bivector, the Electric and Magnetic fields can be separated by grade

```
In [14]:
```

```
E = split(F)(1)
iB = split(F)(2)
E
```

```
Out[14]:
```

```
(1.9^p1) - (0.3^p2) - (0.7^p3)
```

```
In [15]:
```

```
iB
```

```
Out[15]:
```

```
-(0.3^p12) + (0.6^p13) + (1.7^p23)
```

## Lorentz Transformations¶

Lorentz Transformations are rotations in \(\mathbb{D}\), which are implemented with Rotors. A rotor in G4 will, in general, have scalar, bivector, and quadvector components.

```
In [16]:
```

```
R = D.randomRotor()
R
```

```
Out[16]:
```

```
0.2 - (1.6^d01) - (1.6^d02) + (5.1^d03) + (1.5^d12) - (6.5^d13) - (1.4^d23) - (4.1^d0123)
```

In this way, the effect of a lorentz transformation on the electric and magnetic fields can be computed by rotating the bivector with \(F \rightarrow RF\tilde{R}\)

```
In [17]:
```

```
F_ = R*F*~R
F_
```

```
Out[17]:
```

```
-(60.9^d01) - (153.3^d02) - (121.1^d03) + (161.6^d12) + (95.1^d13) - (82.1^d23)
```

Then splitting into \(E\) and \(B\) fields

```
In [18]:
```

```
E_ = split(F_)(1)
E_
```

```
Out[18]:
```

```
-(60.9^p1) - (153.3^p2) - (121.1^p3)
```

```
In [19]:
```

```
iB_ = split(F_)(2)
iB_
```

```
Out[19]:
```

```
(161.6^p12) + (95.1^p13) - (82.1^p23)
```

## Lorentz Invariants¶

Since lorentz rotations in \(\mathbb{D}\), the magnitude of elements of \(\mathbb{D}\) are invariants of the lorentz transformation. For example, the magnitude of electromagnetic bivector \(F\) is invariant, and it can be related to \(E\) and \(B\) fields in \(\mathbb{P}\) through the split,

```
In [20]:
```

```
i = p123
E = split(F)(1)
B = -i*split(F)(2)
```

```
In [21]:
```

```
F**2
```

```
Out[21]:
```

```
1.0 + (7.0^d0123)
```

```
In [22]:
```

```
split(F**2) == E**2 - B**2 + (2*E|B)*i
```

```
Out[22]:
```

```
True
```