-
-
Save eric-wieser/c389a726a8b86f7e9d1586089a4fc5dc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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