Skip to content

Instantly share code, notes, and snippets.

@JustSlavic
Last active December 28, 2023 20:39
Show Gist options
  • Save JustSlavic/99d979d62ed9560a256372d9f632412f to your computer and use it in GitHub Desktop.
Save JustSlavic/99d979d62ed9560a256372d9f632412f to your computer and use it in GitHub Desktop.
Introduction to the geometric algebra for my 'based' library

Disclaimer: this is not a textbook, this is just a short explanation, so you can use this library

Geometric algebra in 2D

Let's say we have a 2d-vector:

$$ v = (v_1, v_2) $$

We can rewrite this expression in another form:

$$ v = x e_1 + y e_2 $$

where $e_1$ and $e_2$ are basis vectors.

In geometric algebra we have three kinds of product of vectors: inner, outer, and geometric products.

You already know inner producs, it's just a dot product of vectors

$$ a \cdot b = a_1 b_1 + a_2 b_2 \in \mathbb{R} $$

So we are going to introduce the second kind of product - wedge product.

Wedge product (also called outer product) is defined as an oriented plane, that is common for those two vectors. Orientation is given by right-hand rule, and magnitude of that plane is equal to the area of parallelogram, defined by those two vectors. Actually wedge product and cross product are very much alike, except cross product is defined only for vectors in 3D, and outer product is defined in any dimensions.

image

Out of this definition we can conclude that $a \wedge a = 0$ and $a \wedge b = - b \wedge a$. By using these properties, we can see that

$$ \begin{aligned} v \wedge w &= (v_1 e_1 + v_2 e_2) \wedge (w_1 e_1 + w_2 e_2) = \\ &= v_1 w_1 (e_1 \wedge e_1) + v_1 w_2 (e_1 \wedge e_2) + v_2 w_1 (e_2 \wedge e_1) + v_2 w_2 (e_2 \wedge e_2) = \\ &= v_1 w_2 (e_1 \wedge e_2) + v_2 w_1 (e_2 \wedge e_1) \\ &= (v_1 w_2 - v_2 w_1) (e_1 \wedge e_2) \end{aligned} $$

Outer product have not much use by itself, so I did not define outer product elements in the library by itself. But it participates in the geometric product, so let's look at it.

Geometric product

Now we can define final, and most useful kind of product - geometric product.

$$ \begin{equation} ab = a \cdot b + a \wedge b \end{equation} $$

Let's look at the product of two basis vectors:

$$ e_1 e_2 = e_1 \cdot e_2 + e_1 \wedge e_2 $$

but $e_1$ and $e_2$ are orthogonal, so $e_1 \cdot e_2 = 0$, thus

$$ e_1 e_2 = e_1 \wedge e_2 $$

Let's see what we get if we square basis vectors:

$$ \begin{aligned} e_1^2 &= e_1 e_1 = e_1 \cdot e_1 + e_1 \wedge e_1 = 1 \\ e_2^2 &= e_2 e_2 = e_2 \cdot e_2 + e_2 \wedge e_2 = 1 \end{aligned} $$

Now we can write $e_1 e_2 = e_{12}$ to be short, but also we can use very convenient symbol manipulations: $e_{ij} = -e_{ji}$, and $e_{ii} = 1$.

For example, if we encounter such expression $e_{121}$ we can use rules above to manipulate it such: $e_{121} = -e_{112} = -e_2$.

But what if we square $e_{12}$ ?

$$ e_{12}^2 = e_{12} e_{12} = e_1 e_2 e_1 e_2 = - e_1 e_1 e_2 e_2 = -1 $$

It looks very much like imaginary unit $i$!

Complex numbers

We remember that complex numbers are represented as two numbers: $z = x + iy$, we can view this number like this: $z = x + y e_{12}$.

Multivectors

There's not much to it in 2D, except the fact that vectors and complex numbers are elements of this unifying algebra, operating on elements $(\mathbb{1}, e_1, e_2, e_{12})$, but in fact it's not useful to represent multivectors in a program.

Much more important is to get used to geometric product and its properties, so we can move on to more interesting algebras.

Geometric algebra in 3D

Similarly to 2D case, we have basis vectors $e_1$, $e_2$, $e_3$, which are all square to 1.

But when we multiply two vectors together, we get

$$ \begin{aligned} ab = & (a_1 e_1 + a_2 e_2 + a_3 e_3) (b_1 e_1 + b_2 e_2 + b_3 e_3) = \\ = & (a_1 b_1 + a_2 b_2 + a_3 b_3) + \\ & (a_2 b_3 - a_3 b_2) e_{23} + \\ & (a_3 b_1 - a_1 b_3) e_{31} + \\ & (a_1 b_2 - a_2 b_1) e_{12} \end{aligned} $$

We can see that $e_{23}^2 = -1$, $e_{31}^2 = -1$, and $e_{12}^2 = -1$. So we can use those to define quaternions, if we define $e_{23} = i$, $e_{31} = j$, and $e_{12} = k$.

Just like in the 2D case, it's not much interesting by itself. Yes, we can get quaternion out of two vectors. This quaternion will rotate any vector by twice the angle between original two vectors. But that's it, if you're familiar with any math libraries out there, you will see all familiar functions.

In library

In my library I define 2D vectors, and all familiar operators:

struct vector2 {
    float32 x, y;
};

vector2 operator - (vector2);
vector2 operator + (vector2, vector2);
vector2 operator - (vector2, vector2);
vector2 operator * (float32, vector2);
vector2 operator * (vector2, float32);
vector2 operator / (vector2, float32);

float32 inner        (vector2, vector2);
float32 norm_squared (vector2);
float32 norm         (vector2);
void    normalize    (vector2 &);
vector2 normalized   (vector2);

Note that functions like normalize performs normalization in place, while normalized returns vector of length 1.

struct complex {
    float re, im;
};

complex operator - (complex);
complex operator + (complex, complex);
complex operator - (complex, complex);
complex operator * (float32, complex);
complex operator * (complex, float32);
complex operator * (complex, complex);
complex operator / (complex, float32);
complex operator / (float32, complex);
complex operator / (complex, complex);

void    conjugate    (complex &);
complex conjugated   (complex);
float32 norm_squared (complex);
float32 norm         (complex);
void    normalize    (complex &);
complex normalized   (complex);

Geometric algebra allow us to define one more operator:

complex operator * (vector2 a, vector2 b) {
    complex result;
    result.re = a.x * b.x + a.y * b.y; // inner(a, b)
    result.im = a.x * b.y - a.y * b.x; // outer(a, b)
    return result;
}

In 3D I define vectors and quaternions with all familiar operations:

struct vector3 {
    float x, y, z;
};

vector3 operator - (vector3);
vector3 operator + (vector3, vector3);
vector3 operator - (vector3, vector3);
vector3 operator * (float32, vector3);
vector3 operator * (vector3, float32);
vector3 operator / (vector3, float32);

float32 inner        (vector3, vector3);
float32 norm_squared (vector3);
float32 norm         (vector3);
void    normalize    (vector3 &);
vector3 normalized   (vector3);

struct quaternion {
    float i, j, k, w;
};

quaternion operator + (quaternion, quaternion);
quaternion operator - (quaternion, quaternion);
quaternion operator * (quaternion, float32);
quaternion operator * (float32, quaternion);
quaternion operator / (quaternion, float32);
quaternion operator * (quaternion, quaternion);

void       conjugate    (quaternion & q)
quaternion conjugated   (quaternion q) 
float32    norm_squared (quaternion q) 
float32    norm         (quaternion q) 
void       normalize    (quaternion & q)
quaternion normalized   (quaternion q) 
quaternion inverse      (quaternion q) 

Geometric algebra allow us to define one more operator:

quaterion operator * (vector3 a, vector3 b) {
    quaternion result;
    result.i = a.y * b.z - a.z * b.y;
    result.j = a.z * b.x - a.x * b.z;
    result.k = a.x * b.y - a.y * b.x;
    result.w = inner(a, b);
    return result;
}

References

  1. Geometric Algebra for Physicists (PDF)
  2. Why you can't multiply vectors (YouTube)
  3. The library (Github)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment