Skip to content

Instantly share code, notes, and snippets.

@arsenovic
Created November 5, 2021 14:04
Show Gist options
  • Save arsenovic/b9cb44796a4d54e25ea3704a00f65cb8 to your computer and use it in GitHub Desktop.
Save arsenovic/b9cb44796a4d54e25ea3704a00f65cb8 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# The Cross Ratio in GA, a Lorentz Invariant "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook gives a formula for the complex cross-ratio in Conformal Geometric Algebra (CGA) and a numerical proof that it is equilent to the conventional complex form. Previous authors have given the cross ratio only for colinear points[1], while it is known that the cross ratio is a conformal invariant for any four points in the complex plane. The GA-version of the cross-ratio of four vectors can be interpreted as a Lorentz invariant.\n",
"\n",
"*[1] \"The design of linear algebra and geometry\", David Hestenes*\n",
"\n",
"### Invariance \n",
"\n",
"Given a set of 4 vectors in STA, $(a,b,c,d)$ which are transformed by a lorentz transformation $R$ into $(w,x,y,z)$ as \n",
"\n",
"$$(w,x,y,z) = R(a,b,c,d)\\tilde{R}$$\n",
"\n",
"the function \n",
"\n",
"$$f(a,b,c,d)\\equiv 1 + \\frac{\\langle acdb\\rangle _{(0,4)}}{\\langle adcb\\rangle_{ (0,4)}}$$\n",
"\n",
"is a lorentz invariant, meaning, \n",
"$$f(a,b,c,d) =f(w,x,y,z) $$\n",
"\n",
"This is obvious due to the commutation relations of scalars and psuedoscalars in the algebra. What is less obvious is that this expression is equivalent to the cross-ratio in complex algebra. \n",
"\n",
"### Equivalence\n",
"It is justifiable to call this function $f$ the cross ratio because this function produces the same values as the complex cross-ratio, when computed in CGA for the plane. This means given four complex numbers $(a,b,c,d)$, this set can be converted to vectors in $G_2$, then up-projected into null vectors in CGA, $G_{3,1}$. The cross ratio defined above can be computed, which yields a scalar+psuedoscalar. This invariant can be mapped directly back onto the complex plane, and the result is equivalent to the classic cross-ratio. \n",
"\n",
"$$ \\text{d2c} (f(\\uparrow(\\text{c2v}(a,b,c,d)) = \\frac{(a-b)(c-d)}{(a-d)(c-b)}$$\n",
"\n",
"where c2v() is complex-to-vector, and d2c() is duality-to-complex, and $\\uparrow$() is the standard CGA mapping of a vector up into CGA.\n",
"\n",
"\n",
"$$ \\text{c2v}(z)\\equiv \\text{Re}(z)e_1 + \\text{Im} (z)e_2 $$\n",
"$$ \\text{d2c}(Z)\\equiv \\langle Z\\rangle_{0} + \\langle Z\\rangle_{ 4}j $$\n",
"\n",
"\n",
"### Another form \n",
"Another form for the cross-ratio which is equivalent to the complex version, can be found by using the projective split. \n",
" \n",
"\n",
"$$ f(a,b,c,d) = \\frac{1}{2}(1- \\frac{a\\wedge d}{a \\cdot d} \\frac{b\\wedge c}{b \\cdot c}) = \\frac{1}{2}(1-B_{ad}B_{cd}) $$\n",
"\n",
"Where $B_{ad}$ and $B_{cd}$ are bivectors generated from the split between the vectors in their subscripts. \n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Numerical Proof with [clifford](https://clifford.readthedocs.io/en/latest/)\n",
"\n",
"### invariance"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(0.65711 - (0.00198^d0123), 0.65711 - (0.00198^d0123))"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from pylab import * \n",
"from clifford.sta import * # imports the spacetime algebra\n",
"isclose = lambda x,y:abs(x-y)< 1e-9 # numerical test for equality\n",
"I = d0123\n",
"\n",
"\n",
"def cr_ga(a,b,c,d):\n",
" '''cross ration in GA'''\n",
" return 1+(a*c*d*b)(0,4)/(a*d*c*b)(0,4)\n",
"\n",
"\n",
"abcd = D.randomV(4) # 4 random vectors \n",
"R = e**(D.randomMV()(2)) # exponentiate a random bivector, to create `R`\n",
"wxyz = [R*k*~R for k in abcd] # (w,x,y,z) = R(a,b,c,d)~R \n",
"cr_ga(*abcd), cr_ga(*wxyz) # compute cross-ratio for both vector sets"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"assert(isclose( cr_ga(*abcd), cr_ga(*wxyz)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Equivalence \n",
"A proof that the GA-version of the cross ratio defined above, `cr_ga`, is equivalent to the conventional cross ratio of complex analysis. \n"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(7.098834917399649-2.457553146316387j)"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import numpy as np\n",
"from clifford.cga import CGA\n",
"from numpy.random import rand \n",
"\n",
"N=2\n",
"cga = CGA(N)\n",
"locals().update(cga.blades)\n",
"\n",
"v2c = lambda x: float(x|e1) + float(x|e2)*1j\n",
"d2c = lambda x: float(x(0)) + float(x|x.pseudoScalar)*1j\n",
"c2v = lambda x: x.real*e1 + x.imag*e2\n",
"\n",
" \n",
"def cr(a,b,c,d):\n",
" '''The traditional cross ratio'''\n",
" return (a-b)*(c-d)/((a-d)*(c-b))\n",
"\n",
"abcd = rand(4) + rand(4)*1j \n",
"cr(*abcd)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(7.098834917399661-2.4575531463163727j)"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# as read from inside-out:\n",
"# convert complex to vector, up-project into cga, compute cr_ga, convert duality to complex\n",
"d2c(cr_ga(*map(cga.up, map(c2v, abcd))))"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"assert(isclose(d2c(cr_ga(*map(cga.up, map(c2v, abcd)))), cr(*abcd)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Other Form, using a split "
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(7.098834917399595-2.4575531463163713j)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"split = lambda Z,x,y: (Z[x]^Z[y])/float((Z[x]|Z[y])(0))\n",
"a = list(map(cga.up, map(c2v, abcd)))\n",
"Ai = split(a,0,3)\n",
"Aj = split(a,1,2)\n",
"d2c(.5*(1 - Ai*Aj)(0,4)).conjugate() "
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"assert(isclose(d2c(.5*(1 - Ai*Aj)(0,4)).conjugate(), cr(*abcd)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.8"
},
"toc": {
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"toc_cell": false,
"toc_position": {},
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment