Skip to content

Instantly share code, notes, and snippets.

@eric-wieser
Created September 24, 2020 08:30
Show Gist options
  • Save eric-wieser/c389a726a8b86f7e9d1586089a4fc5dc to your computer and use it in GitHub Desktop.
Save eric-wieser/c389a726a8b86f7e9d1586089a4fc5dc to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### A correction to GAlgebra's `.matrix()` method. \n",
"Author: Greg Grunberg (GG) \n",
"Last updated: 2020-09-24"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\DeclareMathOperator{\\Tr}{Tr}$$\n",
"$$\\DeclareMathOperator{\\Adj}{Adj}$$\n",
"$$\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}$$\n",
"$$\\newcommand{\\lp}{\\left (}$$\n",
"$$\\newcommand{\\rp}{\\right )}$$\n",
"$$\\newcommand{\\paren}[1]{\\lp {#1} \\rp}$$\n",
"$$\\newcommand{\\half}{\\frac{1}{2}}$$\n",
"$$\\newcommand{\\llt}{\\left <}$$\n",
"$$\\newcommand{\\rgt}{\\right >}$$\n",
"$$\\newcommand{\\abs}[1]{\\left |{#1}\\right | }$$\n",
"$$\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}$$\n",
"$$\\newcommand{\\npdiff}[3]{\\bfrac{\\partial^{#3} {#1}}{\\partial {#2}^{#3}}}$$\n",
"$$\\newcommand{\\lbrc}{\\left \\{}$$\n",
"$$\\newcommand{\\rbrc}{\\right \\}}$$\n",
"$$\\newcommand{\\W}{\\wedge}$$\n",
"$$\\newcommand{\\prm}[1]{{#1}}$$\n",
"$$\\newcommand{\\ddt}[1]{\\bfrac{d{#1}}{dt}}$$\n",
"$$\\newcommand{\\R}{\\dagger}$$\n",
"$$\\newcommand{\\deriv}[3]{\\bfrac{d^{#3}#1}{d{#2}^{#3}}}$$\n",
"$$\\newcommand{\\grade}[2]{\\left < {#1} \\right >_{#2}}$$\n",
"$$\\newcommand{\\f}[2]{{#1}\\lp {#2} \\rp}$$\n",
"$$\\newcommand{\\eval}[2]{\\left . {#1} \\right |_{#2}}$$\n",
"$$\\newcommand{\\bs}[1]{\\boldsymbol{#1}}$$\n",
"$$\\newcommand{\\grad}{\\bs{\\nabla}}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{equation*} \\text{Initialization program GAlgebraInit.py has been executed.}\\\\\\text{This Jupyter notebook is now using}\\end{equation*}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{equation*} \\qquad\\bullet~ \\text{Python }3.8.3\\qquad\\bullet~ \\text{SymPy }1.7.dev\\qquad\\bullet~ \\text{GAlgebra }0.5.0.\\end{equation*}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{equation*} \\text{GAlgebra's options have been set so that:}\\end{equation*}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{equation*} \\qquad\\bullet~ M^\\star = M \\mathbf{I}^{-1} \\text{ defines dualization.}\\end{equation*}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{equation*} \\qquad\\bullet~ \\text{Multivector field arguments are suppressed.}\\end{equation*}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{equation*} \\qquad\\bullet~ \\text{Shortened form } \\partial_x \\text{ is used }\\text{for partial differentiation.}\\end{equation*}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Initializations\n",
"from sys import version\n",
" # used to report version of Python being used\n",
"\n",
"# Make SymPy available to this program\n",
"import sympy \n",
"from sympy import *\n",
"\n",
"# Make GAlgebra available to this program.\n",
"import galgebra\n",
"from galgebra.ga import * \n",
"from galgebra.mv import *\n",
"from galgebra.printer import Fmt, GaPrinter, Format\n",
" # Fmt: sets display mode of a multivector's basis expansion.\n",
" # GaPrinter: makes GA output a little more readable.\n",
" # Format: turns on latex printer.\n",
"from galgebra.gprinter import gFormat, gprint\n",
"from galgebra.lt import *\n",
"gFormat()\n",
" # Default `Fmode=True` suppresses display of a multivector fields'\n",
" # arguments. Default `Dmode=True` causes partial differentiation\n",
" # operators to be displayed in shortened form.\n",
"Ga.dual_mode('Iinv+') \n",
" # Sets dual of a multivector to be the multivector multiplied on \n",
" # its right by the inverse unit pseudoscalar.\n",
"\n",
"gprint(r'\\text{Initialization program GAlgebraInit.py has been executed.}\\\\', \n",
" r'\\text{This Jupyter notebook is now using}',\n",
" r'\\\\ \\qquad\\bullet~ \\text{Python }', version[:5],\n",
" r'\\qquad\\bullet~ \\text{SymPy }', sympy.__version__[:7],\n",
" r'\\qquad\\bullet~ \\text{GAlgebra }', galgebra.__version__[:], r'.')\n",
"gprint(r\"\\text{GAlgebra's options have been set so that:}\",\n",
" r'\\\\ \\qquad\\bullet~ M^\\star = M \\mathbf{I}^{-1} \\text{ defines dualization.}',\n",
" r'\\\\ \\qquad\\bullet~ \\text{Multivector field arguments are suppressed.}',\n",
" r'\\\\ \\qquad\\bullet~ \\text{Shortened form } \\partial_x \\text{ is used }', \n",
" r'\\text{for partial differentiation.}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Each geometric algebra $\\mathbb{G}^{p,q}$ is generated by an inner product space $\\mathbb{R}^{p,q}$ of signature $(p,q)$ and dimension $n = p + q$ . We call the basis $\\{ \\mathbf{e}_1, \\ldots, \\mathbf{e}_n \\}$ used for such a generating space the algebra's *generating basis*. The generating space is *Euclidean* if $p = n$, $q = 0$. It's *Minkowskian* if $p = 1$, $q = n-1$ (or vice versa). \n",
"\n",
"With respect to a given basis, the *standard* matrix representation $[{f^i}_j]$, of an outermorphism $\\mathsf{f}: \\mathbb{G}^{p,q} \\rightarrow \\mathbb{G}^{p,q}$ describes the action of $\\mathsf{f}$ on the algebra-generating basis vectors. Specifically, $\\mathsf{f}(\\mathbf{e}_j) = \\sum_{i=1}^n \\mathbf{e}_i {f^i}_j$, where one should note that the summation is over the *left* index $i$ (the *row* index) of the matrix entries ${f^i}_j$. (In most linear algebra textbooks, both the left and right indexes are placed as subscripts; GG prefers to use covariant-contravariant notation as he's less error prone when doing so.)\n",
"\n",
"The entries ${f^i}_j$ are determined solely by the action of $\\mathsf{f}$ on the generating basis vectors $\\mathbf{e}_j$ and so do not depend on the metric of the inner product space. However one can find the matrix entries by way of the *Fourier formula* ${f^i}_j = \\mathbf{e}^i \\cdot \\mathsf{f}(\\mathbf{e}_j)$, where $\\{ \\mathbf{e}^1, \\ldots, \\mathbf{e}^n \\}$ is the reciprocal basis. While this formula invokes the metric both explicitly (the dot product $\\cdot$) and implicitly (the reciprocal basis vector $\\mathbf{e}^i$), the two invocations occur in inverse fashion to one another, thus leaving ${f^i}_j$ metric independent."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will instantiate four different models of geometric algebras:\n",
"\n",
"- `g2a` is the **standard model** of $\\mathbb{G}^{2,0}$, being generated by an orthonormal basis `(ex, ey)` of the **Euclidean plane** $\\mathbb{R}^{2,0}$. Signature is $(p,q) = (2,0)$. \n",
"\n",
"- `g2b` is a **nonstandard model** of $\\mathbb{G}^{2,0}$, being generated by an orthogonal, but not orthonormal, basis `(eu, ev)` of the **Euclidean plane** $\\mathbb{R}^{2,0}$. Signature is $(p,q) = (2,0)$. \n",
"\n",
"- `g2c` is a **nonstandard model** of $\\mathbb{R}^{1,1}$, being generated by a *null basis* `(es, et)` of the **hyperbolic plane** $\\mathbb{R}^{1,1}$. Signature is $(p,q) = (1,1)$. The hyperbolic plane $\\mathbb{R}^{1,1}$ is the simplest of the Minkowski spaces. \n",
"\n",
"- `g2d` is a **nonstandard model** of $\\mathbb{R}^{1,1}$, being generated by a basis `(ep, eq)` of the **hyperbolic plane** $\\mathbb{R}^{1,1}$. Signature is $(p,q) = (1,1)$. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As of this writing, GAlgebra's method **`.matrix()`** does not return the standard matrix of the transformation to which it's applied. The very simple function `std_matrix()`, defined in the next cell, illustrates what GG believes must be done to correct the output of `.matrix()`. See the end of this notebook for more details."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def std_matrix(f): # use instead of `f.matrix()`, which is buggy\n",
" \"\"\" Applies a correction factor to `f.matrix()` so as to obtain\n",
" the standard matrix of outermorphism `f` with respect to the \n",
" generating basis of geometric algebra `f.Ga`. \"\"\"\n",
" return f.matrix() * f.Ga.g_inv"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"g2a_coords = (x,y) = symbols('x y', real=True)\n",
"g2b_coords = (u,v) = symbols('u v', real=True)\n",
"g2c_coords = (s,t) = symbols('s t', real=True)\n",
"g2d_coords = (p,q) = symbols('p q', real=True)\n",
"\n",
"g2a = Ga('\\mathbf{e}', g = '1 0, 0 1', coords=g2a_coords)\n",
"g2b = Ga('\\mathbf{e}', g = '1 0, 0 2', coords=g2b_coords)\n",
"g2c = Ga('\\mathbf{e}', g = '0 1, 1 0', coords=g2c_coords)\n",
"g2d = Ga('\\mathbf{e}', g = '0 -1, -1 -1', coords=g2d_coords)\n",
"\n",
"(ex, ey) = g2a.mv() # basis vectors for `g2a`\n",
"(eu, ev) = g2b.mv() # basis vectors for `g2b`\n",
"(es, et) = g2c.mv() # basis vectors for `g2c`\n",
"(ep, eq) = g2d.mv() # basis vectors for `g2d`\n",
"\n",
"(rx, ry) = g2a.mvr() # reciprocal basis vectors for `g2a`\n",
"(ru, rv) = g2b.mvr() # reciprocal basis vectors for `g2b`\n",
"(rs, rt) = g2c.mvr() # reciprocal basis vectors for `g2c`\n",
"(rp, rq) = g2d.mvr() # reciprocal basis vectors for `g2d`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the output of the next cell we show, for each of the geometric algebras `g2a`, `g2b`, `g2c`, and `g2d`, the metric tensor $\\mathsf{G} = [g_{ij}]$, the reciprocal metric tensor $\\mathsf{G}^{-1} = [g^{ij}]$, and the reciprocal basis vectors $\\mathbf{e}^i$ as linear combinations of the basis vectors $\\mathbf{e}_j$."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\text{g2a:} \\qquad\\mathsf{G} = \\left[\\begin{array}{cc}1 & 0\\\\0 & 1\\end{array}\\right] \\qquad\\mathsf{G}^{-1} = \\left[\\begin{array}{cc}1 & 0\\\\0 & 1\\end{array}\\right] \\qquad \\left( \\boldsymbol{\\mathbf{e}}^{x}, \\ \\boldsymbol{\\mathbf{e}}^{y}\\right) = \\left( \\boldsymbol{\\mathbf{e}}_{x}, \\ \\boldsymbol{\\mathbf{e}}_{y}\\right) $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{g2b:} \\qquad\\mathsf{G} = \\left[\\begin{array}{cc}1 & 0\\\\0 & 2\\end{array}\\right] \\qquad\\mathsf{G}^{-1} = \\left[\\begin{array}{cc}1 & 0\\\\0 & \\frac{1}{2}\\end{array}\\right] \\qquad \\left( \\boldsymbol{\\mathbf{e}}^{u}, \\ \\boldsymbol{\\mathbf{e}}^{v}\\right) = \\left( \\boldsymbol{\\mathbf{e}}_{u}, \\ \\frac{1}{2} \\boldsymbol{\\mathbf{e}}_{v}\\right) $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{g2c:} \\qquad\\mathsf{G} = \\left[\\begin{array}{cc}0 & 1\\\\1 & 0\\end{array}\\right] \\qquad\\mathsf{G}^{-1} = \\left[\\begin{array}{cc}0 & 1\\\\1 & 0\\end{array}\\right] \\qquad \\left( \\boldsymbol{\\mathbf{e}}^{s}, \\ \\boldsymbol{\\mathbf{e}}^{t}\\right) = \\left( \\boldsymbol{\\mathbf{e}}_{t}, \\ \\boldsymbol{\\mathbf{e}}_{s}\\right) $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{g2d:} \\qquad\\mathsf{G} = \\left[\\begin{array}{cc}0 & -1\\\\-1 & -1\\end{array}\\right] \\qquad\\mathsf{G}^{-1} = \\left[\\begin{array}{cc}1 & -1\\\\-1 & 0\\end{array}\\right] \\qquad \\left( \\boldsymbol{\\mathbf{e}}^{p}, \\ \\boldsymbol{\\mathbf{e}}^{q}\\right) = \\left( \\boldsymbol{\\mathbf{e}}_{p} - \\boldsymbol{\\mathbf{e}}_{q}, \\ - \\boldsymbol{\\mathbf{e}}_{p}\\right) $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"gprint(r'\\text{g2a:} \\qquad', r'\\mathsf{G} = ', g2a.g, r'\\qquad',\n",
" r'\\mathsf{G}^{-1} = ', g2a.g_inv, r'\\qquad', tuple(g2a.r_symbols), r'= ', g2a.mvr())\n",
"gprint(r'\\text{g2b:} \\qquad', r'\\mathsf{G} = ', g2b.g, r'\\qquad',\n",
" r'\\mathsf{G}^{-1} = ', g2b.g_inv, r'\\qquad', tuple(g2b.r_symbols), r'= ', g2b.mvr())\n",
"gprint(r'\\text{g2c:} \\qquad', r'\\mathsf{G} = ', g2c.g, r'\\qquad',\n",
" r'\\mathsf{G}^{-1} = ', g2c.g_inv, r'\\qquad', tuple(g2c.r_symbols), r'= ', g2c.mvr())\n",
"gprint(r'\\text{g2d:} \\qquad', r'\\mathsf{G} = ', g2d.g, r'\\qquad',\n",
" r'\\mathsf{G}^{-1} = ', g2d.g_inv, r'\\qquad', tuple(g2d.r_symbols), r'= ', g2d.mvr())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It's not obvious that the null vectors `(es, et)` constitute a basis of the hyperbolic plane $\\mathbb{R}^{1,1}$. Such follows from the ability to form a *standard basis* `(e1, e2)` of $\\mathbb{R}^{1,1}$ by taking appropriate linear combinations of the null basis vectors:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\text{inner products of }$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\quad\\text{g2c standard basis vectors:}\\qquad\\text{e1} \\cdot \\text{e1} = 1 \\qquad\\text{e1} \\cdot \\text{e2} = 0 \\qquad\\text{e2} \\cdot \\text{e1} = 0 \\qquad\\text{e2} \\cdot \\text{e2} = -1 $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"e1 = (es + et)/sqrt(2) # \"timelike\" vector in hyperbolic plane\n",
"e2 = (es - et)/sqrt(2) # \"spacelike\" vector in hyperbolic plane\n",
"gprint(r'\\text{inner products of }')\n",
"gprint(r'\\quad\\text{g2c standard basis vectors:}\\qquad',\n",
" r'\\text{e1} \\cdot \\text{e1} = ', e1<e1, '\\qquad',\n",
" r'\\text{e1} \\cdot \\text{e2} = ', e1<e2, '\\qquad',\n",
" r'\\text{e2} \\cdot \\text{e1} = ', e2<e1, '\\qquad', \n",
" r'\\text{e2} \\cdot \\text{e2} = ', e2<e2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Neither is it obvious that the vectors `(ep, eq)` form a basis of the hyperbolic plane $\\mathbb{R}^{1,1}$. Such follows from the ability to form a *standard basis* `(e1, e2)` of $\\mathbb{R}^{1,1}$ by taking appropriate linear combinations of the null basis vectors:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\text{inner products of }$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\quad\\text{g2c standard basis vectors:}\\qquad\\text{e1} \\cdot \\text{e1} = 1 \\qquad\\text{e1} \\cdot \\text{e2} = 0 \\qquad\\text{e2} \\cdot \\text{e1} = 0 \\qquad\\text{e2} \\cdot \\text{e2} = -1 $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"e1 = ep - eq # \"timelike\" vector in hyperbolic plane\n",
"e2 = eq # \"spacelike\" vector in hyperbolic plane\n",
"gprint(r'\\text{inner products of }')\n",
"gprint(r'\\quad\\text{g2c standard basis vectors:}\\qquad',\n",
" r'\\text{e1} \\cdot \\text{e1} = ', e1<e1, '\\qquad',\n",
" r'\\text{e1} \\cdot \\text{e2} = ', e1<e2, '\\qquad',\n",
" r'\\text{e2} \\cdot \\text{e1} = ', e2<e1, '\\qquad', \n",
" r'\\text{e2} \\cdot \\text{e2} = ', e2<e2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We next instantiate outermorphisms `K`, `L`, `M`, `N` on `g2a`, `g2b`, `g2c`and `g2c`, respectively, and also create the corresponding adjoint transformations `K_adj`, `L_adj`, `M_adj`, and `N_adj`. We use the Fourier formula to create each outermorphism's standard matrix.\n",
"\n",
"Relative to the basis for the inner product space on which they act, each of `K`, `L`, `M`, and `N` has the same action; consequently each of the four outermorphism should have the same matrix $\\left[ \\begin{matrix} 0 & 1 \\\\ 2 & 1 \\\\ \\end{matrix} \\right]$ with respect to the basis for the space on which it acts. But because of their dependence on the metric as well as the original transformation, the corresponding adjoints `K_adj`, `L_adj`, `M_adj`, and `N_adj` do *not* have the same actions relative to their bases; consequently we should not expect them to have the same standard matrix."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Instantiate specific outermorphisms:\n",
"K = g2a.lt([ [0,2], [1,1] ])\n",
"L = g2b.lt([ [0,2], [1,1] ])\n",
"M = g2c.lt([ [0,2], [1,1] ])\n",
"N = g2d.lt([ [0,2], [1,1] ])\n",
"\n",
"# Extract their adjoints:\n",
"K_adj = K.adj()\n",
"L_adj = L.adj()\n",
"M_adj = M.adj()\n",
"N_adj = N.adj()\n",
"\n",
"# Use the Fourier formula to create standard matrices:\n",
"K_Fourier = Matrix(\\\n",
" [ [(rx<K(ex)).scalar(), (rx<K(ey)).scalar()],\n",
" [(ry<K(ex)).scalar(), (ry<K(ey)).scalar()] ])\n",
"L_Fourier = Matrix(\\\n",
" [ [(ru<L(eu)).scalar(), (ru<L(ev)).scalar()],\n",
" [(rv<L(eu)).scalar(), (rv<L(ev)).scalar()] ])\n",
"M_Fourier = Matrix(\\\n",
" [ [(rs<M(es)).scalar(), (rs<M(et)).scalar()],\n",
" [(rt<M(es)).scalar(), (rt<M(et)).scalar()] ])\n",
"N_Fourier = Matrix(\\\n",
" [ [(rp<N(ep)).scalar(), (rp<N(eq)).scalar()],\n",
" [(rq<N(ep)).scalar(), (rq<N(eq)).scalar()] ])\n",
"K_adj_Fourier = Matrix(\\\n",
" [ [(rx<K_adj(ex)).scalar(), (rx<K_adj(ey)).scalar()],\n",
" [(ry<K_adj(ex)).scalar(), (ry<K_adj(ey)).scalar()] ])\n",
"L_adj_Fourier = Matrix(\\\n",
" [ [(ru<L_adj(eu)).scalar(), (ru<L_adj(ev)).scalar()],\n",
" [(rv<L_adj(eu)).scalar(), (rv<L_adj(ev)).scalar()] ])\n",
"M_adj_Fourier = Matrix(\\\n",
" [ [(rs<M_adj(es)).scalar(), (rs<M_adj(et)).scalar()],\n",
" [(rt<M_adj(es)).scalar(), (rt<M_adj(et)).scalar()] ])\n",
"N_adj_Fourier = Matrix(\\\n",
" [ [(rp<N_adj(ep)).scalar(), (rp<N_adj(eq)).scalar()],\n",
" [(rq<N_adj(ep)).scalar(), (rq<N_adj(eq)).scalar()] ])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The next cell reports for each of the outermorphisms and their adjoints, \n",
"- the action of the transformation on the generating basis vectors of its algebra, \n",
"- its standard matrix as computed using the Fourier formula, and \n",
"- the matrix that GAlgebra reports upon applicaton of `std_matrix()` to the transformation. \n",
"\n",
"$\\color{red}{\\text{BUG WORKAROUND: }}$ At the start of this notebook was defined an experimental function `std_matrix(f)`. Notice that it returns the matrix `f.matrix()` post-multiplied by the reciprocal metric tensor. We hope that `std_matrix(f)` returns the standard matrix of `f`, so should return the same matrix as that of the Fourier coefficients."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{K}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{x} &\\mapsto 2 \\boldsymbol{\\mathbf{e}}_{y} \\\\ \\boldsymbol{\\mathbf{e}}_{y} &\\mapsto \\boldsymbol{\\mathbf{e}}_{x} + \\boldsymbol{\\mathbf{e}}_{y} \\end{aligned} \\right\\} \\qquad\\text{K_Fourier} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] \\qquad\\text{std_matrix(K)} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{L}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{u} &\\mapsto 2 \\boldsymbol{\\mathbf{e}}_{v} \\\\ \\boldsymbol{\\mathbf{e}}_{v} &\\mapsto \\boldsymbol{\\mathbf{e}}_{u} + \\boldsymbol{\\mathbf{e}}_{v} \\end{aligned} \\right\\} \\qquad\\text{L_Fourier} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] \\qquad\\text{std_matrix(L)} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{M}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{s} &\\mapsto 2 \\boldsymbol{\\mathbf{e}}_{t} \\\\ \\boldsymbol{\\mathbf{e}}_{t} &\\mapsto \\boldsymbol{\\mathbf{e}}_{s} + \\boldsymbol{\\mathbf{e}}_{t} \\end{aligned} \\right\\} \\qquad\\text{M_Fourier} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] \\qquad\\text{std_matrix(M)} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{N}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{p} &\\mapsto 2 \\boldsymbol{\\mathbf{e}}_{q} \\\\ \\boldsymbol{\\mathbf{e}}_{q} &\\mapsto \\boldsymbol{\\mathbf{e}}_{p} + \\boldsymbol{\\mathbf{e}}_{q} \\end{aligned} \\right\\} \\qquad\\text{N_Fourier} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] \\qquad\\text{std_matrix(N)} = \\left[\\begin{array}{cc}0 & 1\\\\2 & 1\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{K}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{x} &\\mapsto \\boldsymbol{\\mathbf{e}}_{y} \\\\ \\boldsymbol{\\mathbf{e}}_{y} &\\mapsto 2 \\boldsymbol{\\mathbf{e}}_{x} + \\boldsymbol{\\mathbf{e}}_{y} \\end{aligned} \\right\\} \\qquad\\text{K_adj_Fourier} = \\left[\\begin{array}{cc}0 & 2\\\\1 & 1\\end{array}\\right] \\qquad\\text{std_matrix(K_adj)} = \\left[\\begin{array}{cc}0 & 2\\\\1 & 1\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{L}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{u} &\\mapsto \\frac{1}{2} \\boldsymbol{\\mathbf{e}}_{v} \\\\ \\boldsymbol{\\mathbf{e}}_{v} &\\mapsto 4 \\boldsymbol{\\mathbf{e}}_{u} + \\boldsymbol{\\mathbf{e}}_{v} \\end{aligned} \\right\\} \\qquad\\text{L_adj_Fourier} = \\left[\\begin{array}{cc}0 & 4\\\\\\frac{1}{2} & 1\\end{array}\\right] \\qquad\\text{std_matrix(L_adj)} = \\left[\\begin{array}{cc}0 & 4\\\\\\frac{1}{2} & 1\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{M}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{s} &\\mapsto \\boldsymbol{\\mathbf{e}}_{s} + 2 \\boldsymbol{\\mathbf{e}}_{t} \\\\ \\boldsymbol{\\mathbf{e}}_{t} &\\mapsto \\boldsymbol{\\mathbf{e}}_{s} \\end{aligned} \\right\\} \\qquad\\text{M_adj_Fourier} = \\left[\\begin{array}{cc}1 & 1\\\\2 & 0\\end{array}\\right] \\qquad\\text{std_matrix(M_adj)} = \\left[\\begin{array}{cc}1 & 1\\\\2 & 0\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{N}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{p} &\\mapsto - \\boldsymbol{\\mathbf{e}}_{p} + 2 \\boldsymbol{\\mathbf{e}}_{q} \\\\ \\boldsymbol{\\mathbf{e}}_{q} &\\mapsto 2 \\boldsymbol{\\mathbf{e}}_{q} \\end{aligned} \\right\\} \\qquad\\text{N_adj_Fourier} = \\left[\\begin{array}{cc}-1 & 0\\\\2 & 2\\end{array}\\right] \\qquad\\text{std_matrix(N_adj)} = \\left[\\begin{array}{cc}-1 & 0\\\\2 & 2\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"gprint(r'\\mathsf{K}:', K, r'\\qquad', r'\\text{K_Fourier} = ', K_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(K)} = ', std_matrix(K))\n",
"gprint(r'\\mathsf{L}:', L, r'\\qquad', r'\\text{L_Fourier} = ', L_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(L)} = ', std_matrix(L))\n",
"gprint(r'\\mathsf{M}:', M, r'\\qquad', r'\\text{M_Fourier} = ', M_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(M)} = ', std_matrix(M))\n",
"gprint(r'\\mathsf{N}:', N, r'\\qquad', r'\\text{N_Fourier} = ', N_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(N)} = ', std_matrix(N))\n",
"gprint(r'\\mathsf{K}^\\ast:', K_adj, r'\\qquad', r'\\text{K_adj_Fourier} = ', K_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(K_adj)} = ', std_matrix(K_adj))\n",
"gprint(r'\\mathsf{L}^\\ast:', L_adj, r'\\qquad', r'\\text{L_adj_Fourier} = ', L_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(L_adj)} = ', std_matrix(L_adj))\n",
"gprint(r'\\mathsf{M}^\\ast:', M_adj, r'\\qquad', r'\\text{M_adj_Fourier} = ', M_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(M_adj)} = ', std_matrix(M_adj))\n",
"gprint(r'\\mathsf{N}^\\ast:', N_adj, r'\\qquad', r'\\text{N_adj_Fourier} = ', N_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(N_adj)} = ', std_matrix(N_adj))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\text{K_Fourier = std_matrix(K):}~~ \\text{True} \\qquad\\text{K_adj_Fourier = std_matrix(K_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{L_Fourier = std_matrix(L):}~~ \\text{True} \\qquad\\text{L_adj_Fourier = std_matrix(L_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{M_Fourier = std_matrix(M):}~~ \\text{True} \\qquad\\text{M_adj_Fourier = std_matrix(M_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{N_Fourier = std_matrix(N):}~~ \\text{True} \\qquad\\text{N_adj_Fourier = std_matrix(N_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"gprint(r'\\text{K_Fourier = std_matrix(K):}~~', K_Fourier == std_matrix(K), r'\\qquad',\n",
" r'\\text{K_adj_Fourier = std_matrix(K_adj):}~~', K_adj_Fourier == std_matrix(K_adj))\n",
"gprint(r'\\text{L_Fourier = std_matrix(L):}~~', L_Fourier == std_matrix(L), r'\\qquad',\n",
" r'\\text{L_adj_Fourier = std_matrix(L_adj):}~~', L_adj_Fourier == std_matrix(L_adj))\n",
"gprint(r'\\text{M_Fourier = std_matrix(M):}~~', M_Fourier == std_matrix(M), r'\\qquad',\n",
" r'\\text{M_adj_Fourier = std_matrix(M_adj):}~~', M_adj_Fourier == std_matrix(M_adj))\n",
"gprint(r'\\text{N_Fourier = std_matrix(N):}~~', N_Fourier == std_matrix(N), r'\\qquad',\n",
" r'\\text{N_adj_Fourier = std_matrix(N_adj):}~~', N_adj_Fourier == std_matrix(N_adj))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*All of the above agree with hand calculations*, so GAlgebra seems to be working for *specific* outermorphisms on the four geometric algebras. But does it work on *generic* outermorphisms? The next several In[ ] cells parallel those above for `K`, `L`, `M`, `\\N` and their adjoints, but instead of specifying the actions of `R`, `S`, `T`, `U`, those outermorphisms are left generic."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# Instantiate generic outermorphisms:\n",
"R = g2a.lt('R')\n",
"S = g2b.lt('S')\n",
"T = g2c.lt('T')\n",
"U = g2d.lt('U')\n",
"\n",
"# Extract the corresponding adjoints:\n",
"R_adj = R.adj()\n",
"S_adj = S.adj()\n",
"T_adj = T.adj()\n",
"U_adj = U.adj()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# Use the Fourier formula to create standard matrices:\n",
"R_Fourier = Matrix(\\\n",
" [ [(rx<R(ex)).scalar(), (rx<R(ey)).scalar()],\n",
" [(ry<R(ex)).scalar(), (ry<R(ey)).scalar()] ])\n",
"S_Fourier = Matrix(\\\n",
" [ [(ru<S(eu)).scalar(), (ru<S(ev)).scalar()],\n",
" [(rv<S(eu)).scalar(), (rv<S(ev)).scalar()] ])\n",
"T_Fourier = simplify(Matrix(\\\n",
" [ [(rs<T(es)).scalar(), (rs<T(et)).scalar()],\n",
" [(rt<T(es)).scalar(), (rt<T(et)).scalar()] ]))\n",
"U_Fourier = simplify(Matrix(\\\n",
" [ [(rp<U(ep)).scalar(), (rp<U(eq)).scalar()],\n",
" [(rq<U(ep)).scalar(), (rq<U(eq)).scalar()] ]))\n",
"R_adj_Fourier = Matrix(\\\n",
" [ [(rx<R_adj(ex)).scalar(), (rx<R_adj(ey)).scalar()],\n",
" [(ry<R_adj(ex)).scalar(), (ry<R_adj(ey)).scalar()] ])\n",
"S_adj_Fourier = Matrix(\\\n",
" [ [(ru<S_adj(eu)).scalar(), (ru<S_adj(ev)).scalar()],\n",
" [(rv<S_adj(eu)).scalar(), (rv<S_adj(ev)).scalar()] ])\n",
"T_adj_Fourier = Matrix(\\\n",
" [ [(rs<T_adj(es)).scalar(), (rs<T_adj(et)).scalar()],\n",
" [(rt<T_adj(es)).scalar(), (rt<T_adj(et)).scalar()] ])\n",
"U_adj_Fourier = Matrix(\\\n",
" [ [(rp<U_adj(ep)).scalar(), (rp<U_adj(eq)).scalar()],\n",
" [(rq<U_adj(ep)).scalar(), (rq<U_adj(eq)).scalar()] ])"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{R}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{x} &\\mapsto R_{xx} \\boldsymbol{\\mathbf{e}}_{x} + R_{yx} \\boldsymbol{\\mathbf{e}}_{y} \\\\ \\boldsymbol{\\mathbf{e}}_{y} &\\mapsto R_{xy} \\boldsymbol{\\mathbf{e}}_{x} + R_{yy} \\boldsymbol{\\mathbf{e}}_{y} \\end{aligned} \\right\\} \\qquad\\text{R_Fourier} = \\left[\\begin{array}{cc}R_{xx} & R_{xy}\\\\R_{yx} & R_{yy}\\end{array}\\right] \\qquad\\text{std_matrix(R)} = \\left[\\begin{array}{cc}R_{xx} & R_{xy}\\\\R_{yx} & R_{yy}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{S}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{u} &\\mapsto S_{uu} \\boldsymbol{\\mathbf{e}}_{u} + S_{vu} \\boldsymbol{\\mathbf{e}}_{v} \\\\ \\boldsymbol{\\mathbf{e}}_{v} &\\mapsto \\frac{S_{uv}}{2} \\boldsymbol{\\mathbf{e}}_{u} + \\frac{S_{vv}}{2} \\boldsymbol{\\mathbf{e}}_{v} \\end{aligned} \\right\\} \\qquad\\text{S_Fourier} = \\left[\\begin{array}{cc}S_{uu} & \\frac{S_{uv}}{2}\\\\S_{vu} & \\frac{S_{vv}}{2}\\end{array}\\right] \\qquad\\text{std_matrix(S)} = \\left[\\begin{array}{cc}S_{uu} & \\frac{S_{uv}}{2}\\\\S_{vu} & \\frac{S_{vv}}{2}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{T}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{s} &\\mapsto T_{st} \\boldsymbol{\\mathbf{e}}_{s} + T_{tt} \\boldsymbol{\\mathbf{e}}_{t} \\\\ \\boldsymbol{\\mathbf{e}}_{t} &\\mapsto T_{ss} \\boldsymbol{\\mathbf{e}}_{s} + T_{ts} \\boldsymbol{\\mathbf{e}}_{t} \\end{aligned} \\right\\} \\qquad\\text{T_Fourier} = \\left[\\begin{array}{cc}T_{st} & T_{ss}\\\\T_{tt} & T_{ts}\\end{array}\\right] \\qquad\\text{std_matrix(T)} = \\left[\\begin{array}{cc}T_{st} & T_{ss}\\\\T_{tt} & T_{ts}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{U}: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{p} &\\mapsto \\left ( U_{pp} - U_{pq}\\right ) \\boldsymbol{\\mathbf{e}}_{p} + \\left ( U_{qp} - U_{qq}\\right ) \\boldsymbol{\\mathbf{e}}_{q} \\\\ \\boldsymbol{\\mathbf{e}}_{q} &\\mapsto - U_{pp} \\boldsymbol{\\mathbf{e}}_{p} - U_{qp} \\boldsymbol{\\mathbf{e}}_{q} \\end{aligned} \\right\\} \\qquad\\text{U_Fourier} = \\left[\\begin{array}{cc}U_{pp} - U_{pq} & - U_{pp}\\\\U_{qp} - U_{qq} & - U_{qp}\\end{array}\\right] \\qquad\\text{std_matrix(U)} = \\left[\\begin{array}{cc}U_{pp} - U_{pq} & - U_{pp}\\\\U_{qp} - U_{qq} & - U_{qp}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{R}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{x} &\\mapsto R_{xx} \\boldsymbol{\\mathbf{e}}_{x} + R_{xy} \\boldsymbol{\\mathbf{e}}_{y} \\\\ \\boldsymbol{\\mathbf{e}}_{y} &\\mapsto R_{yx} \\boldsymbol{\\mathbf{e}}_{x} + R_{yy} \\boldsymbol{\\mathbf{e}}_{y} \\end{aligned} \\right\\} \\qquad\\text{R_adj_Fourier} = \\left[\\begin{array}{cc}R_{xx} & R_{yx}\\\\R_{xy} & R_{yy}\\end{array}\\right] \\qquad\\text{std_matrix(R_adj)} = \\left[\\begin{array}{cc}R_{xx} & R_{yx}\\\\R_{xy} & R_{yy}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{S}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{u} &\\mapsto S_{uu} \\boldsymbol{\\mathbf{e}}_{u} + \\frac{S_{uv}}{4} \\boldsymbol{\\mathbf{e}}_{v} \\\\ \\boldsymbol{\\mathbf{e}}_{v} &\\mapsto 2 S_{vu} \\boldsymbol{\\mathbf{e}}_{u} + \\frac{S_{vv}}{2} \\boldsymbol{\\mathbf{e}}_{v} \\end{aligned} \\right\\} \\qquad\\text{S_adj_Fourier} = \\left[\\begin{array}{cc}S_{uu} & 2 S_{vu}\\\\\\frac{S_{uv}}{4} & \\frac{S_{vv}}{2}\\end{array}\\right] \\qquad\\text{std_matrix(S_adj)} = \\left[\\begin{array}{cc}S_{uu} & 2 S_{vu}\\\\\\frac{S_{uv}}{4} & \\frac{S_{vv}}{2}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{T}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{s} &\\mapsto T_{ts} \\boldsymbol{\\mathbf{e}}_{s} + T_{tt} \\boldsymbol{\\mathbf{e}}_{t} \\\\ \\boldsymbol{\\mathbf{e}}_{t} &\\mapsto T_{ss} \\boldsymbol{\\mathbf{e}}_{s} + T_{st} \\boldsymbol{\\mathbf{e}}_{t} \\end{aligned} \\right\\} \\qquad\\text{T_adj_Fourier} = \\left[\\begin{array}{cc}T_{ts} & T_{ss}\\\\T_{tt} & T_{st}\\end{array}\\right] \\qquad\\text{std_matrix(T_adj)} = \\left[\\begin{array}{cc}T_{ts} & T_{ss}\\\\T_{tt} & T_{st}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\mathsf{U}^\\ast: \\left\\{ \\begin{aligned} \\boldsymbol{\\mathbf{e}}_{p} &\\mapsto \\left ( - 2 U_{qp} + U_{qq}\\right ) \\boldsymbol{\\mathbf{e}}_{p} + \\left ( U_{qp} - U_{qq}\\right ) \\boldsymbol{\\mathbf{e}}_{q} \\\\ \\boldsymbol{\\mathbf{e}}_{q} &\\mapsto \\left ( - 2 U_{pp} + U_{pq} - 2 U_{qp} + U_{qq}\\right ) \\boldsymbol{\\mathbf{e}}_{p} + \\left ( U_{pp} - U_{pq} + U_{qp} - U_{qq}\\right ) \\boldsymbol{\\mathbf{e}}_{q} \\end{aligned} \\right\\} \\qquad\\text{U_adj_Fourier} = \\left[\\begin{array}{cc}- 2 U_{qp} + U_{qq} & - 2 U_{pp} + U_{pq} - 2 U_{qp} + U_{qq}\\\\U_{qp} - U_{qq} & U_{pp} - U_{pq} + U_{qp} - U_{qq}\\end{array}\\right] \\qquad\\text{std_matrix(U_adj)} = \\left[\\begin{array}{cc}- 2 U_{qp} + U_{qq} & - 2 U_{pp} + U_{pq} - 2 U_{qp} + U_{qq}\\\\U_{qp} - U_{qq} & U_{pp} - U_{pq} + U_{qp} - U_{qq}\\end{array}\\right] $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"gprint(r'\\mathsf{R}:', R, r'\\qquad', r'\\text{R_Fourier} = ', R_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(R)} = ', std_matrix(R))\n",
"gprint(r'\\mathsf{S}:', S, r'\\qquad', r'\\text{S_Fourier} = ', S_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(S)} = ', std_matrix(S))\n",
"gprint(r'\\mathsf{T}:', T, r'\\qquad', r'\\text{T_Fourier} = ', T_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(T)} = ', std_matrix(T))\n",
"gprint(r'\\mathsf{U}:', U, r'\\qquad', r'\\text{U_Fourier} = ', U_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(U)} = ', std_matrix(U))\n",
"gprint(r'\\mathsf{R}^\\ast:', R_adj, r'\\qquad', r'\\text{R_adj_Fourier} = ', R_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(R_adj)} = ', std_matrix(R_adj))\n",
"gprint(r'\\mathsf{S}^\\ast:', S_adj, r'\\qquad', r'\\text{S_adj_Fourier} = ', S_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(S_adj)} = ', std_matrix(S_adj))\n",
"gprint(r'\\mathsf{T}^\\ast:', T_adj, r'\\qquad', r'\\text{T_adj_Fourier} = ', T_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(T_adj)} = ', std_matrix(T_adj))\n",
"gprint(r'\\mathsf{U}^\\ast:', U_adj, r'\\qquad', r'\\text{U_adj_Fourier} = ', U_adj_Fourier,\n",
" r'\\qquad', r'\\text{std_matrix(U_adj)} = ', std_matrix(U_adj))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The output of the preceding In[ ] cell reveals a problem in GAlgebra's **lt.py** unrelated to the `.matrix()` problem. One would expect the standard matrix of a generic outermorphism `f = ga.lt('f')` to take the form $[f_{ij}]$ or, better yet from the standpoint of someone who prefers covariant-contravariant notation, the form $[{f^i}_j]$. One would expect the action of `f` on basis vectors to be reported as a system of \"mapsto\" expressions that look like this, \n",
"\n",
"$$ \\mathbf{e}_j \\mapsto {f^1}_j \\mathbf{e}_1 + {f^2}_j \\mathbf{e}_2 + \\dots + {f^n}_j \\mathbf{e}_n,$$ \n",
"\n",
"without the ellipses of course. Yet outermorphisms `S`, `T`, `U` fail that expectation. Somehow the metric tensor (or maybe its reciprocal) is getting mixed into the expression for $\\mathsf{f}(\\mathbf{e}_j)$."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This new problem is *not* related to the question of whether the function `std_matrix()` corrects the misbehavior of GAlgebra's `.matrix()` method. As the next cell shows, `std_matrix()` works as one would want on the generic outermorphisms `R`, `S`, `T`, `U` and their adjoints:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\text{R_Fourier = std_matrix(R):}~~ \\text{True} \\qquad\\text{R_adj_Fourier = std_matrix(R_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{S_Fourier = std_matrix(S):}~~ \\text{True} \\qquad\\text{S_adj_Fourier = std_matrix(S_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{T_Fourier = std_matrix(T):}~~ \\text{True} \\qquad\\text{T_adj_Fourier = std_matrix(M_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\text{U_Fourier = std_matrix(U):}~~ \\text{True} \\qquad\\text{U_adj_Fourier = std_matrix(U_adj):}~~ \\text{True} $"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"gprint(r'\\text{R_Fourier = std_matrix(R):}~~', R_Fourier == std_matrix(R), r'\\qquad',\n",
" r'\\text{R_adj_Fourier = std_matrix(R_adj):}~~', R_adj_Fourier == std_matrix(R_adj))\n",
"gprint(r'\\text{S_Fourier = std_matrix(S):}~~', S_Fourier == std_matrix(S), r'\\qquad',\n",
" r'\\text{S_adj_Fourier = std_matrix(S_adj):}~~', S_adj_Fourier == std_matrix(S_adj))\n",
"gprint(r'\\text{T_Fourier = std_matrix(T):}~~', T_Fourier == std_matrix(T), r'\\qquad',\n",
" r'\\text{T_adj_Fourier = std_matrix(M_adj):}~~', T_adj_Fourier == std_matrix(T_adj))\n",
"gprint(r'\\text{U_Fourier = std_matrix(U):}~~', U_Fourier == std_matrix(U), r'\\qquad',\n",
" r'\\text{U_adj_Fourier = std_matrix(U_adj):}~~', U_adj_Fourier == std_matrix(U_adj))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Conclusion: The function `std_matrix(f)` works correctly on both generic and specific outermorphisms.**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here's the current code for the `.matrix()` method, defined in module **lt.py** as part of the definition of class `Lt`, but with two lines modified. The lines below which read $\\color{green}{\\textsf{return self.mat * self.Ga.g_inv}}$ read, pre-modification, as $\\color{red}{\\textsf{return self.mat}}$. The modifications will make `.matrix()` return the same values that the function `std_matrix()` did in this notebook."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" def matrix(self) -> Matrix:\n",
" r\"\"\"\n",
" Returns the matrix representation of the linear transformation,\n",
" :math:`L`, defined by :math:`{{L}\\lp {{{\\eb}}_{i}} \\rp } = L_{ij}{{\\eb}}_{j}`\n",
" where :math:`L_{ij}` is the matrix representation.\n",
" \"\"\"\n",
" if self.mat is not None:\n",
" return self.mat * self.Ga.g_inv\n",
" else:\n",
" if self.spinor:\n",
" self.lt_dict = {}\n",
" for base in self.Ga.basis:\n",
" self.lt_dict[base] = self(base).simplify()\n",
" self.spinor = False\n",
" mat = self.matrix()\n",
" self.spinor = True\n",
" return mat\n",
" else:\n",
" \"\"\"\n",
" mat_rep = []\n",
" for base in self.Ga.basis:\n",
" if base in self.lt_dict:\n",
" row = []\n",
" image = (self.lt_dict[base])\n",
" if isinstance(image, mv.Mv):\n",
" image = image.obj\n",
" coefs, bases = metric.linear_expand(image)\n",
" for base in self.Ga.basis:\n",
" try:\n",
" i = bases.index(base)\n",
" row.append(coefs[i])\n",
" except:\n",
" row.append(0)\n",
" mat_rep.append(row)\n",
" else:\n",
" mat_rep.append(self.Ga.n * [0])\n",
" return Matrix(mat_rep).transpose()\n",
" \"\"\"\n",
" self.mat = Dictionary_to_Matrix(self.lt_dict, self.Ga) * self.Ga.g\n",
" return self.mat * self.Ga.g_inv"
]
},
{
"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.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment