from numpy import pi,e
from clifford import Cl, conformalize

G2, blades_g2 = Cl(2)

blades_g2 # inspect the G2 blades

"""
Explanation: This notebook is part of the clifford documentation: https://clifford.readthedocs.io/.
Conformal Geometric Algebra
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 
$$e_{o} = \frac{1}{2}(e_{-} -e_{+})\e_{\infty} = e_{-}+e_{+}$$
A vector in the original space $x$ is up-projected into a conformal vector $X$  by 
$$X = x + \frac{1}{2} x^2 e_{\infty} +e_o $$
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$,
$$ X = \frac{X}{X \cdot e_{\infty}}$$
then 
$$x = X \wedge E_0\, E_0^{-1}$$
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}$.
End of explanation
"""


G2c, blades_g2c, stuff = conformalize(G2)

blades_g2c   #inspect the CGA blades

"""
Explanation: Now, conformalize it
End of explanation
"""


stuff

"""
Explanation: Additionally lets inspect stuff
End of explanation
"""


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

"""
Explanation: 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,
End of explanation
"""


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

down(X)

"""
Explanation: Now we can use the up() and down() functions to go in and out of CGA
End of explanation
"""


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

"""
Explanation: Operations
Conformal transformations in $G_n$ are achieved through versors in the conformal space $G_{n+1,1}$. These versors can be categorized by their relation to the added minkowski plane, $E_0$. There are three categories,

versor purely in $E_0$
versor partly in $E_0$
versor out of $E_0$

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

Versors purely in $E_0$
First we generate some vectors in G2, which we can operate on
End of explanation
"""


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

"""
Explanation: Inversions
$$e_{+} X e_{+}$$
Inversion is a reflection in  $e_+$, this swaps $e_o$  and $e_{\infty}$, as can be seen from the model above.
End of explanation
"""


assert(down(E0*up(a)*E0) == -a)

"""
Explanation: Involutions
$$E_0 X E_0$$
End of explanation
"""


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))


"""
Explanation: Dilations
$$D_{\alpha}  =  e^{-\frac{\ln{\alpha}}{2} \,E_0} $$
$$D_{\alpha} \, X \, \tilde{D_{\alpha}} $$
End of explanation
"""


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

"""
Explanation: Versors partly in $E_0$
Translations
$$ V = e ^{\frac{1}{2} e_{\infty} a } = 1 + e_{\infty}a$$
End of explanation
"""


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) ) 

"""
Explanation: Transversions
A transversion is an inversion,  followed by a translation, followed by a inversion. The versor is 
$$V= e_+ T_a e_+$$
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$,
$$ e_+ (1+e_{\infty}a)e_+ $$
$$ e_+^2 + e_+e_{\infty}a e_+$$
$$2 +2e_o a$$
the factor of 2 may be dropped, because the conformal vectors are null
End of explanation
"""


m = 5*e1 + 6*e2
n = 7*e1 + 8*e2


assert(down(m*up(a)*m) == -m*a*m.inv())


"""
Explanation: Versors Out of  $E_0$
Versors that are out of $E_0$ are made up of the versors 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
$$ -mam^{-1}  \rightarrow MA\tilde{M}  $$
End of explanation
"""


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


"""
Explanation: Rotations
$$ mnanm = Ra\tilde{R} \rightarrow RA\tilde{R}  $$
End of explanation
"""


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

"""
Explanation: Combinations of Operations
simple example
As a simple example consider the combination  operations of translation,scaling, and inversion. 
$$b=-2a+e_0 \quad \rightarrow \quad B= (T_{e_0}E_0 D_2) A \tilde{ (D_2 E_0 T_{e_0})} $$
End of explanation
"""


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


"""
Explanation: Transversion
A transversion may be built from a inversion, translation, and inversion. 
$$c = (a^{-1}+b)^{-1}$$
In conformal GA, this is accomplished by 
$$C = VA\tilde{V}$$
$$V= e_+ T_b e_+$$
End of explanation
"""


