# Conformal Geometric Algebra¶

## Intro¶

Conformal Geometric Algebra (CGA) is a projective geometry tool which allows conformal transformations to be implemented with rotations. To do this, the original geometric algebra is extended by two dimensions, one of positive signature \(e_+\) and one of negative signature \(e_-\). Thus, if we started with \(G_p\), the conformal algebra is \(G_{p+1,1}\).

It is convenient to define a *null* basis given by

A vector in the original space \(x\) is *up-projected* into a
conformal vector \(X\) by

To map a conformal vector back into a vector from the original space, the vector is first normalized, then rejected from the minkowski plane \(E_0\),

then

To implement this in `clifford`

we could create a CGA by instantiating
the it directly, like `Cl(3,1)`

for example, and then making the
definitions and maps described above relating the various subspaces. Or,
we you can use the helper function `conformalize()`

.

## Using `conformalize()`

¶

The purpose of `conformalize()`

is to remove the redundancy associated
with creating a conformal geometric algebras. `conformalize()`

takes
an existing geometric algebra layout and *conformalizes* it by adding
two dimensions, as described above. Additionally, this function returns
a new layout for the CGA, a dict of blades for the CGA, and dictionary
containing the added basis vectors and up/down projection functions.

To demonstrate we will conformalize \(G_2\), producing a CGA of \(G_{3,1}\).

```
In [1]:
```

```
from numpy import pi,e
from clifford import Cl, conformalize
G2, blades_g2 = Cl(2)
blades_g2 # inspect the G2 blades
```

```
Out[1]:
```

```
{'e1': (1^e1), 'e2': (1^e2), 'e12': (1^e12)}
```

Now, conformalize it

```
In [2]:
```

```
G2c, blades_g2c, stuff = conformalize(G2)
blades_g2c #inspect the CGA blades
```

```
Out[2]:
```

```
{'e1': (1^e1),
'e2': (1^e2),
'e3': (1^e3),
'e4': (1^e4),
'e12': (1^e12),
'e13': (1^e13),
'e14': (1^e14),
'e23': (1^e23),
'e24': (1^e24),
'e34': (1^e34),
'e123': (1^e123),
'e124': (1^e124),
'e134': (1^e134),
'e234': (1^e234),
'e1234': (1^e1234)}
```

Additionally lets inspect `stuff`

```
In [3]:
```

```
stuff
```

```
Out[3]:
```

```
{'ep': (1^e3),
'en': (1^e4),
'eo': -(0.5^e3) + (0.5^e4),
'einf': (1^e3) + (1^e4),
'E0': (1.0^e34),
'up': <function clifford.conformalize.<locals>.up(x)>,
'down': <function clifford.conformalize.<locals>.down(x)>,
'homo': <function clifford.conformalize.<locals>.homo(x)>,
'I_base': (1.0^e12)}
```

It contains the following:

`ep`

- positive basis vector added`en`

- negative basis vector added`eo`

- zero vector of null basis (=.5*(en-ep))`einf`

- infinity vector of null basis (=en+ep)`E0`

- minkowski bivector (=einf^eo)`up()`

- function to up-project a vector from GA to CGA`down()`

- function to down-project a vector from CGA to GA`homo()`

- function to homogenize a CGA vector

We can put the `blades`

and the `stuff`

into the local namespace,

```
In [4]:
```

```
locals().update(blades_g2c)
locals().update(stuff)
```

Now we can use the `up()`

and `down()`

functions to go in and out of
CGA

```
In [5]:
```

```
x = e1+e2
X = up(x)
X
```

```
Out[5]:
```

```
(1.0^e1) + (1.0^e2) + (0.5^e3) + (1.5^e4)
```

```
In [6]:
```

```
down(X)
```

```
Out[6]:
```

```
(1.0^e1) + (1.0^e2)
```

## Operations¶

Conformal transformations in \(G_n\) are achieved through versers in the conformal space \(G_{n+1,1}\). These versers can be categorized by their relation to the added minkowski plane, \(E_0\). There are three categories,

- verser purely in \(E_0\)
- verser partly in \(E_0\)
- verser out of \(E_0\)

A three dimensional projection for conformal space with the relevant subspaces labeled is shown below.

```
In [7]:
```

```
from IPython.display import Image
Image(url='_static/conformal space.svg')
```

```
Out[7]:
```

## Versers purely in \(E_0\)¶

First we generate some vectors in G2, which we can operate on

```
In [8]:
```

```
a= 1*e1 + 2*e2
b= 3*e1 + 4*e2
```

### Inversions¶

Inversion is a reflection in \(e_+\), this swaps \(e_o\) and \(e_{\infty}\), as can be seen from the model above.

```
In [9]:
```

```
assert(down(ep*up(a)*ep) == a.inv())
```

### Dilations¶

```
In [11]:
```

```
from scipy import rand,log
D = lambda alpha: e**((-log(alpha)/2.)*(E0))
alpha = rand()
assert(down( D(alpha)*up(a)*~D(alpha)) == (alpha*a))
```

```
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-11-0e2e8e068b72> in <module>
3 D = lambda alpha: e**((-log(alpha)/2.)*(E0))
4 alpha = rand()
----> 5 assert(down( D(alpha)*up(a)*~D(alpha)) == (alpha*a))
AssertionError:
```

## Versers partly in \(E_0\)¶

### Translations¶

```
In [12]:
```

```
T = lambda x: e**(1/2.*(einf*x))
assert(down( T(a)*up(b)*~T(a)) == b+a)
```

### Transversions¶

A transversion is an inversion, followed by a translation, followed by a inversion. The verser is

which is recognised as the translation bivector reflected in the \(e_+\) vector. From the diagram, it is seen that this is equivalent to the bivector in \(x\wedge e_o\),

the factor of 2 may be dropped, because the conformal vectors are null

```
In [13]:
```

```
V = ep * T(a) * ep
assert ( V == 1+(eo*a))
K = lambda x: 1+(eo*a)
B= up(b)
assert( down(K(a)*B*~K(a)) == 1/(a+1/b) )
```

## Versers Out of \(E_0\)¶

Versers that are out of \(E_0\) are made up of the versers within the original space. These include reflections and rotations, and their conformal representation is identical to their form in \(G^n\), except the minus sign is dropped for reflections,

### Reflections¶

```
In [14]:
```

```
m = 5*e1 + 6*e2
n = 7*e1 + 8*e2
assert(down(m*up(a)*m) == -m*a*m.inv())
```

### Rotations¶

```
In [15]:
```

```
R = lambda theta: e**((-.5*theta)*(e12))
theta = pi/2
assert(down( R(theta)*up(a)*~R(theta)) == R(theta)*a*~R(theta))
```

```
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-15-30854c418944> in <module>
1 R = lambda theta: e**((-.5*theta)*(e12))
2 theta = pi/2
----> 3 assert(down( R(theta)*up(a)*~R(theta)) == R(theta)*a*~R(theta))
AssertionError:
```

## Combinations of Operations¶

### simple example¶

As a simple example consider the combination operations of translation,scaling, and inversion.

```
In [16]:
```

```
A = up(a)
V = T(e1)*E0*D(2)
B = V*A*~V
assert(down(B) == (-2*a)+e1 )
```

```
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-16-992fe6a0dbf4> in <module>
2 V = T(e1)*E0*D(2)
3 B = V*A*~V
----> 4 assert(down(B) == (-2*a)+e1 )
AssertionError:
```

### Transversion¶

A transversion may be built from a inversion, translation, and inversion.

In conformal GA, this is accomplished by

```
In [17]:
```

```
A = up(a)
V = ep*T(b)*ep
C = V*A*~V
assert(down(C) ==1/(1/a +b))
```

### Rotation about a point¶

Rotation about a point \(a\) can be achieved by translating the origin to \(a\), then rotating, then translating back. Just like the transversion can be thought of as translating the involution operator, rotation about a point can also be thought of as translating the Rotor itself. Covariance.