Designing Geometric Algebras - Rotors

In the first part of this series we learnt how to create geometric algebras that can represent arbitrary objects. In this second part we will learn about how to create the rotors we want to perform translation, rotation and so on.

Rotor Recap

With each pair of basis vectors we can form a bivector. The bivector can be exponentiated which results in a rotor that, when an object is sandwiched with it, will perform one of three operations depending on what the bivector$B$squares to:
${B}^{2}$${e}^{tB}$Sandwich action on vector
-1$\mathrm{cos}\left(t\right)+B\mathrm{sin}\left(t\right)$Rotates between B's two vectors
0$1+tB$Translates orthogonal to B's two vectors
+1$\mathrm{cosh}\left(t\right)+B\mathrm{sinh}\left(t\right)$Boosts between B's two vectors
Let's take a look at ordinary 3-space GA. We have three basis vectors${e}_{x},{e}_{y},{e}_{z}$that each square to +1. We have three bivectors${e}_{xy},{e}_{yz},{e}_{xz}$that each square to -1. Thus the bivectors perform a rotation in their planes, meaning, between the components of the two basis vectors they are composed of when applied with the sandwich product to a vector.

Rotors for different up functions

With a more complicated up function this is no different. The bivectors will still eg. rotate between two components of two basis vectors. The result looks more interesting though. If we have a basis vector for the${x}^{2}$term and another basis vector for a constant term, we can rotate between a parabola and a straight line! This is demonstrated below with an algebra that has 3 basis vectors and corresponding terms in the up function${x}^{2},y,1$.
Here's another example where we rotate an elliptic curve into vertical lines (the algebra can represent vertical line tuples).

Basis vectors as mirrors

If you've seen Steven De Keninck's presentation on dual quaternions you have seen how the rotors arise naturally from viewing the action of the basis vectors as mirrors in the dual view. For example using ordinary 3-space again, each basis vector when applied with the sandwich product will reflect the components along its axis.
As you might have hoped or expected, nothing changes. If we reflect in a basis vector that has an${x}^{2}$coefficient in the up function, sandwiching with that basis vector will reflect in a parabola instead of a line. This is hard to visualize, especially for understanding how the rotors arise from these mirrors but it does all work out the same.

Rotor exploration

Here are some things I tried. I might remove this section later or move it to a new page once I figure out a good pattern for constructing our desired rotors. Beware of mistakes.
PGA-like rotors for rotation and translation
Depending on what our basis vectors square to we will get different squares for the bivectors. This makes it tricky to get all the transformations we want. For example we can't easily get both rotation between${e}_{1},{e}_{2}$and translation orthogonal to it.
However we can introduce a new basis vector${e}_{3}$that squares to zero and add it to our up function with a constant coefficient. Assuming our two basis vectors${e}_{1},{e}_{2}$we started with both square to one, we get rotors for rotation between${e}_{1},{e}_{2}$as well as translations in either direction if we sandwich with the exponential of the dual of a vector. For example${e}^{\frac{d}{2}{e}_{1}^{\ast }}=1+\frac{d}{2}{e}_{1}^{\ast }$is a translator (a rotor doing translation) in the 1-direction by$d$when applied with the sandwich product.
Shear rotors
So far this was all relatively specific to the up function used by PGA where the extra basis vector has a constant coefficient. How does the action of such a rotor look like if the coefficient is not a constant?
Let's look at the simple case with two basis vectors and up function$up\left(x,y\right)=x{e}_{1}+y{e}_{2}$and${e}_{1}^{2}=1$but${e}_{2}^{2}=0$. We have the bivector${e}_{12}$which squares to zero. When we exponentiate it and apply it with the sandwich product to a vector we get$\begin{array}{rl}& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{1}+y{e}_{2}\right)\left(1-\frac{d}{2}{e}_{12}\right)\\ =& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{1}+y{e}_{2}-\frac{d}{2}x{e}_{2}\right)\\ =& x{e}_{1}+y{e}_{2}-dx{e}_{2}\\ =& x{e}_{1}+\left(y-dx\right){e}_{2}\end{array}$It does some sort of translation in the${e}_{2}$direction proportional to the${e}_{1}$value. For$x=0$the${e}_{2}$direction is unaffected. The bigger the${e}_{1}$component gets the more the${e}_{2}$direction gets translated. This is a shear in the${e}_{2}$direction, the vector which squares to zero.
"Opposite-PGA" exploration
Let's try the previous PGA rotor example but instead make${e}_{1}^{2}={e}_{2}^{2}=0$and${e}_{3}^{2}=1$.

Applying${e}_{13}$to a vector (line)$\begin{array}{rl}& \left(1+\frac{d}{2}{e}_{13}\right)\left(x{e}_{1}+y{e}_{2}+1{e}_{3}\right)\left(1-\frac{d}{2}{e}_{13}\right)\\ =& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{1}+y{e}_{2}+1{e}_{3}+\frac{d}{2}{e}_{1}+\frac{d}{2}y{e}_{123}\right)\\ =& x{e}_{1}+y{e}_{2}+1{e}_{3}+d{e}_{1}+dy{e}_{123}\\ =& \left(x+d\right){e}_{1}+y{e}_{2}+1{e}_{3}+dy{e}_{123}\end{array}$This does translation in the${e}_{1}$direction and also some kind of shear in${e}_{123}$proportional to the${e}_{2}$component.${e}_{2}3$does the same thing but with${e}_{1}$and${e}_{2}$swapped.

Applying${e}_{12}$to a vector (line):$\begin{array}{rl}& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{1}+y{e}_{2}+1{e}_{3}\right)\left(1-\frac{d}{2}{e}_{12}\right)\\ =& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{1}+y{e}_{2}+1{e}_{3}-\frac{d}{2}{e}_{123}\right)\\ =& x{e}_{1}+y{e}_{2}+1{e}_{3}-d{e}_{123}\end{array}$This does translation in${e}_{123}$.

Applying${e}_{12}$to a bivector (point):$\begin{array}{rl}& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{31}+y{e}_{23}+1{e}_{12}\right)\left(1-\frac{d}{2}{e}_{12}\right)\\ =& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{31}+y{e}_{23}+1{e}_{12}\right)\\ =& x{e}_{31}+y{e}_{23}+1{e}_{12}\end{array}$This is the identity map.

Applying${e}_{13}$to a bivector (point):$\begin{array}{rl}& \left(1+\frac{d}{2}{e}_{13}\right)\left(x{e}_{31}+y{e}_{23}+1{e}_{12}\right)\left(1-\frac{d}{2}{e}_{13}\right)\\ =& \left(1+\frac{d}{2}{e}_{12}\right)\left(x{e}_{31}+y{e}_{23}+1{e}_{12}+\frac{d}{2}y{e}_{12}\right)\\ =& x{e}_{31}+y{e}_{23}+1{e}_{12}+dy{e}_{12}\\ =& x{e}_{31}+y{e}_{23}+\left(1+dy\right){e}_{12}\end{array}$This is a shear in the${e}_{12}$direction proportional to the${e}_{23}$component. The last bivector${e}_{23}$will do the same thing in the but proportional to the${e}_{13}$component. Since this is a projective point (which follows from inverting the up function, not conjecture!) it's a division of both x and y by$1+x$or$1+y$. Also composing the two rotors will give us the following:$\begin{array}{rl}& R=\left(1+\frac{{d}_{x}}{2}{e}_{23}\right)\left(1+\frac{{d}_{y}}{2}{e}_{13}\right)=1+\frac{{d}_{x}}{2}{e}_{23}+\frac{{d}_{y}}{2}{e}_{13}+\frac{{d}_{x}{d}_{y}}{4}{e}_{12}\\ & Rp\stackrel{~}{R}=\frac{x}{1+{d}_{x}x+{d}_{y}y}{e}_{31}+\frac{y}{1+{d}_{x}x+{d}_{y}y}{e}_{23}+1{e}_{12}\end{array}$Interestingly the composed rotor picks up the${e}_{12}$part for which we already showed that it is the identity map. In different notation, the composed map is$\begin{array}{r}\left(x,y\right)\to \left(\frac{x}{1+{d}_{x}x+{d}_{y}y},\frac{y}{1+{d}_{x}x+{d}_{y}y}\right)\end{array}$Perhaps it is possible to construct scaling rotors for each direction this way if we could change the$x$and$y$in the denominator by adjusting our up function and basis vectors.
Non-isotropic scaling rotor
We want rotors that only scale in one direction, instead of scaling all directions equally. Start with PGA, but for up instead use the logarithm on the coordinates$\begin{array}{r}up\left(x,y\right)=log\left(x\right){e}_{1}^{\ast }+log\left(y\right){e}_{2}^{\ast }+1{e}_{0}^{\ast }\end{array}$If we try to find the inverse mapping (ie. get the$\left(x,y\right)$coordinates a bivector represents) we have$\begin{array}{r}x=exp\left(\frac{⟨p{⟩}_{{1}^{\ast }}}{⟨p{⟩}_{{0}^{\ast }}}\right),y=exp\left(\frac{⟨p{⟩}_{{2}^{\ast }}}{⟨p{⟩}_{{0}^{\ast }}}\right)\end{array}$If we now apply a translator${T}_{x}\left(log\left({s}_{x}\right)\right)$that translates by$log\left({s}_{x}\right)$in the${e}_{x}^{\ast }$direction (just like in the usual PGA), we get$\begin{array}{rl}& {T}_{x}\left(log\left({s}_{x}\right)\right)up\left(x,y\right)\stackrel{~}{{T}_{x}}\left(log\left({s}_{x}\right)\right)\\ =& \left(log\left(x\right)+log\left({s}_{x}\right)\right){e}_{x}^{\ast }+log\left(y\right){e}_{y}^{\ast }+1{e}_{0}^{\ast }\\ =& log\left(x{s}_{x}\right){e}_{x}^{\ast }+log\left(y\right){e}_{y}^{\ast }+1{e}_{0}^{\ast }\end{array}$Recovering the$\left({x}^{\prime },{y}^{\prime }\right)$coordinates this result represents using the inverse up mapping we get$\begin{array}{rl}{x}^{\prime }& =exp\left(\frac{log\left(x{s}_{x}\right)}{1}\right)=x{s}_{x}\\ {y}^{\prime }& =exp\left(\frac{log\left(y\right)}{1}\right)=y\end{array}$And we have non-isotropic scaling, yay! Of course the same will work for scaling$y$too. There is still a big issue though:$x$and$y$have to be greater than zero since the logarithm is not defined otherwise (or we could just use the complex logarithm? although maybe there's a nicer GA way of avoiding arbitrary complex numbers here).
Translators in any variable for polynomial up functions
This part is flawed / wrong, but I left it up since it still contains some useful ideas.
Assume we have an up function$up\left(x,...\right)=x{e}_{1}^{\ast }+{x}^{2}{e}_{2}^{\ast }+1{e}_{0}^{\ast }+...$which can represent parabolas, lines, points and so on. If we want to have translation as rotors (translators), it's not that easy. In PGA we only have one basis vector with an$x$coefficient so we can do the translation using a single rotor${e}^{\frac{d}{2}{e}_{x0}}$, but if we did with the above up function we would change the$x$coefficient while leaving the${x}^{2}$coefficient untouched. If we look at the OPNS / VPNS of a point that was only translated in${e}_{1}^{\ast }$$\begin{array}{rl}& \left(x{e}_{1}^{\ast }+{x}^{2}{e}_{2}^{\ast }+1{e}_{0}^{\ast }\right)\vee \left(\left(a+d\right){e}_{1}^{\ast }+b{e}_{2}\ast +c{e}_{0}\ast \right)\\ =& xb{e}_{12}^{\ast }+xc{e}_{10}^{\ast }+{x}^{2}\left(a+d\right){e}_{21}^{\ast }+{x}^{2}c{e}_{20}\ast +\left(a+d\right){e}_{01}\ast +b{e}_{02}\ast \\ =& \left(xc-a-d\right){e}_{10}^{\ast }+\left(xb-a-d\right){e}_{12}^{\ast }+\left({x}^{2}c-b\right){e}_{20}^{\ast }=0\end{array}$we get three equations that have to vanish$\begin{array}{rl}xc-a-d& =0\\ xb-a-d& =0\\ {x}^{2}c-b& =0\end{array}$Notice the first and second equation together give$xb=xc$. But the third equation gives$b={x}^{2}c$. Both of these together give${x}^{3}c=xc$which can only be true for$x=0$. and our wrongly translated point does indeed not represent anything useful.
To get something useful again we need to translate all coefficients where$x$appears in the up function. For instance${x}^{2}$should get translated as$\begin{array}{}\text{(1)}& {x}^{2}\to \left(x+d{\right)}^{2}={x}^{2}+{d}^{2}+2dx\end{array}$First we need to translate the${e}_{2}^{\ast }$coefficient by${d}^{2}$which is easy using the rotor${e}^{\frac{{d}^{2}}{2}{e}_{20}}$. Next we need to translate the${e}_{2}^{\ast }$part by$2dx$which is a shear. This is not possible with the current set of basis vectors we have available as we can only translate by constants and not in proportion to$x$as required here.
We introduce a new basis vector${e}_{3}^{2}=0$with coefficient$x$in the up function. Then we get the rotors we need as${e}^{d{e}_{13}}$(note, no division by 2 as we need twice the amount). This solves the issue of translating the${x}^{2}$part. However this introduces a new problem. The new basis vector we introduced has coefficient$x$so in order to keep it consistent (non-empty OPNS / VPNS) we need to translate it too.
Again this is not that easy because usually we use the bivectors containing${e}_{0}$to do translations. We can't do that here to translate${e}_{3}$because it squares to zero and thus the bivector${e}_{30}$will result in zero when multiplied with${e}_{0}^{\ast }={e}_{123}$which is the part that usually enables us to do translation for non-zero squaring basis vectors.
The idea in this step is wrong which makes the entire thing not work out. The bivector will give a shearor not a translator, and will also affect the wrong dual basis vector.We introduce a new basis vector${e}_{4}^{2}=1$with coefficient$1$in the up function. This will allow us to do translations in${e}_{3}^{\ast }$with the bivector${e}_{34}$because it squares to zero (ie. does translation) and${e}_{34}{e}_{4}^{\ast }={e}_{34}{e}_{0123}=-{e}_{0124}$instead of zero.
Now we can compose all the rotors we just came up with to get a single rotor that does translation in$x$by$d$. In conclusion, we introduced two new basis vectors, one for allowing us to do translation in proportional to$x$and another to allow us to translate the new basis vector by a constant. The composed rotor is a lot more complicated too. However this will work for any polynomial if we apply this idea recursively. For example for${x}^{3}$we want$\left(x+d{\right)}^{3}={x}^{3}+{d}^{3}+3{d}^{2}x+3d{x}^{2}$. Here we could do the same thing:
1. Translate${x}^{3}$part by${d}^{3}$
2. Introduce new basis vector with coeff.$x$for translation by$dx$
3. Introduce new basis vector for translating the new basis vector by$d$
4. Introduce new basis vector for translation relative to${x}^{2}$
5. New basis vector needs to be translated as$\left(x+d{\right)}^{2}$so we can apply the same idea
6. ...
7. Tears, lots of new basis vectors, complicated rotors, but it works out
Finally here's an example of this in action, however the renderer doesn't seem to like this very much as the points don't get rendered correctly (or I made a mistake somewhere?) but you get the idea hopefully.Perhaps there's a better way. I don't know whether this works for functions other than polynomials either, it might for some, but it certainly doesn't for many because the correction terms can not be done with translators, although if we had more rotors in our toolbox than just translators this might be fixable.