test_gprinter.py
1 from __future__ import annotations 2 3 import os 4 import unittest 5 import pytest 6 import subprocess 7 from pathlib import Path 8 9 # Make SymPy available to this program: 10 import sympy 11 from sympy import symbols, simplify, sin, cos 12 13 # Make GAlgebra available to this program: 14 from galgebra.ga import Ga 15 # from galgebra.mv import * 16 from galgebra.printer import Fmt, GaPrinter, Format 17 # Fmt: sets the way that a multivector's basis expansion is output. 18 # GaPrinter: makes GA output a little more readable. 19 # Format: turns on latex gprinter. 20 from galgebra.gprinter import gFormat, gprint, gxpdf, gPrint_Function 21 22 ROOT = Path(__file__).parent.parent 23 DIR_TEST = ROOT / 'test' 24 DIR_GENERATED = DIR_TEST / 'generated' 25 DIR_FIXTURES = DIR_TEST / 'fixtures' 26 DIR_DIFF = DIR_TEST / 'diff' 27 28 29 def lin_tran(): 30 gFormat() 31 gPrint_Function() 32 (x, y, z) = xyz = symbols('x,y,z',real=True) 33 (o3d, ex, ey, ez) = Ga.build('e_x e_y e_z', g=[1, 1, 1], coords=xyz) 34 grad = o3d.grad 35 (u, v) = uv = symbols('u,v',real=True) 36 (g2d, eu, ev) = Ga.build('e_u e_v', coords=uv) 37 grad_uv = g2d.grad 38 v_xyz = o3d.mv('v','vector') 39 A_xyz = o3d.mv('A','vector',f=True) 40 A_uv = g2d.mv('A','vector',f=True) 41 # gprint(r'\text{3d orthogonal ($A$ is vector function)}') 42 gprint('A =', A_xyz) 43 gprint('A^{2} =', A_xyz * A_xyz) 44 gprint(r'\nabla \cdot A =', grad | A_xyz) 45 gprint(r'\nabla A =', grad * A_xyz) 46 gprint('v|(grad*A) =',v_xyz|(grad*A_xyz)) 47 gprint(r'\text{2d general ($A$ is vector function)}') 48 gprint('A =', A_uv) 49 gprint('A^{2} =', A_uv * A_uv) 50 gprint(r'\nabla \cdot A =', grad_uv | A_uv) 51 gprint(r'\nabla A =', grad_uv * A_uv) 52 A = o3d.lt('A') 53 gprint(r'\text{3d orthogonal ($A$, $B$ are linear transformations)}') 54 gprint('A =', A) 55 gprint(r'\f{mat}{A} =', A.matrix()) 56 gprint('\\f{\\det}{A} =', A.det()) 57 gprint('\\overline{A} =', A.adj()) 58 gprint('\\f{\\Tr}{A} =', A.tr()) 59 gprint('\\f{A}{e_x \\wedge e_y} =', A(ex^ey)) 60 gprint('\\f{A}{e_x} \\wedge \\f{A}{e_y} =', A(ex)^A(ey)) 61 B = o3d.lt('B') 62 gprint('g =', o3d.g) 63 gprint('g^{-1} =', o3d.g_inv) 64 65 gprint('A + B =', A + B) 66 gprint('AB =', A * B) 67 gprint('A - B =', A - B) 68 gprint('General Symmetric Linear Transformation') 69 Asym = o3d.lt('A',mode='s') 70 gprint('A =', Asym) 71 gprint('General Antisymmetric Linear Transformation') 72 Aasym = o3d.lt('A',mode='a') 73 gprint('A =', Aasym) 74 gprint(r'\text{2d general ($A,\\;B$ are linear transformations)}') 75 A2d = g2d.lt('A') 76 gprint('g =', g2d.g) 77 gprint('g^{-1} =', g2d.g_inv) 78 gprint('gg^{-1} =', simplify(g2d.g * g2d.g_inv)) 79 gprint('A =', A2d) 80 gprint(r'\f{mat}{A} =', A2d.matrix()) 81 gprint('\\f{\\det}{A} =', A2d.det()) 82 A2d_adj = A2d.adj() 83 gprint('\\overline{A} =', A2d_adj) 84 gprint('\\f{mat}{\\overline{A}} =', simplify(A2d_adj.matrix())) 85 gprint('\\f{\\Tr}{A} =', A2d.tr()) 86 gprint('\\f{A}{e_u \\wedge e_v} =', A2d(eu^ev)) 87 gprint('\\f{A}{e_u} \\wedge \\f{A}{e_v} =', A2d(eu)^A2d(ev)) 88 B2d = g2d.lt('B') 89 90 gprint('B =', B2d) 91 gprint('A + B =', A2d + B2d) 92 gprint('A - B =', A2d - B2d) 93 gprint('AB =', A2d * B2d) 94 a = g2d.mv('a','vector') 95 b = g2d.mv('b','vector') 96 gprint(r'a|\f{\overline{A}}{b}-b|\f{\underline{A}}{a} =',((a|A2d.adj()(b))-(b|A2d(a))).simplify()) 97 m4d = Ga('e_t e_x e_y e_z', g=[1, -1, -1, -1],coords=symbols('t,x,y,z',real=True)) 98 T = m4d.lt('T') 99 gprint('g =', m4d.g) 100 gprint(r'\underline{T} =',T) 101 gprint(r'\overline{T} =',T.adj()) 102 gprint(r'\f{\det}{\underline{T}} =',T.det()) 103 gprint(r'\f{\mbox{tr}}{\underline{T}} =',T.tr()) 104 a = m4d.mv('a','vector') 105 b = m4d.mv('b','vector') 106 gprint(r'a|\f{\overline{T}}{b}-b|\f{\underline{T}}{a} =',((a|T.adj()(b))-(b|T(a))).simplify()) 107 coords = (r, th, phi) = symbols('r,theta,phi', real=True) 108 (sp3d, er, eth, ephi) = Ga.build('e_r e_th e_ph', g=[1, r**2, r**2*sin(th)**2], coords=coords) 109 grad = sp3d.grad 110 sm_coords = (u, v) = symbols('u,v', real=True) 111 smap = [1, u, v] # Coordinate map for sphere of r = 1 112 sph2d = sp3d.sm(smap,sm_coords,norm=True) 113 (eu, ev) = sph2d.mv() 114 grad_uv = sph2d.grad 115 F = sph2d.mv('F','vector',f=True) 116 f = sph2d.mv('f','scalar',f=True) 117 gprint('f =',f) 118 gprint(r'\nabla f =',grad_uv * f) 119 gprint('F =',F) 120 gprint(r'\nabla F =',grad_uv * F) 121 tp = (th,phi) = symbols('theta,phi',real=True) 122 smap = [sin(th)*cos(phi),sin(th)*sin(phi),cos(th)] 123 sph2dr = o3d.sm(smap,tp,norm=True) 124 (eth, ephi) = sph2dr.mv() 125 grad_tp = sph2dr.grad 126 F = sph2dr.mv('F','vector',f=True) 127 f = sph2dr.mv('f','scalar',f=True) 128 gprint('f =',f) 129 gprint(r'\nabla f =',grad_tp * f) 130 gprint('F =',F) 131 gprint(r'\nabla F =',grad_tp * F) 132 return 133 134 135 class TestGprinter(unittest.TestCase): 136 def setUp(self): 137 os.makedirs(DIR_GENERATED, exist_ok=True) 138 os.makedirs(DIR_DIFF, exist_ok=True) 139 os.chdir(DIR_GENERATED) 140 141 def gen_pdf(self, name, documentclass): 142 gxpdf('%s.tex' % name, pdfprog='tectonic', rm=False, null=False, evince=False, documentclass=documentclass) 143 144 def check_pdf(self, name, expected_retcode=0): 145 retcode = subprocess.call([ 146 'diff-pdf', 147 '--output-diff=%s' % (DIR_DIFF / ('%s-diff.pdf' % name)), 148 DIR_FIXTURES / ('%s.pdf' % name), 149 DIR_GENERATED / ('%s.pdf' % name) 150 ]) 151 assert retcode == expected_retcode 152 153 @pytest.mark.skipif("TEST_GXPDF" not in os.environ, reason="Only run if TEST_GXPDF is set") 154 def test_gxpdf(self): 155 gFormat() 156 # Set up standard G^3 geometric algebra 157 g3coords = (x, y, z) = symbols('x y z', real=True) # Without real=True, symbols are complex 158 g3 = Ga(r'\mathbf{e}', g=[1, 1, 1], coords=g3coords) 159 (ex, ey, ez) = g3.mv() # Program names of basis vectors. 160 (exr, eyr, ezr) = g3.mvr() # Program names of reciprocal basis vectors. 161 162 B = g3.mv('B', 'bivector') 163 Fmt(1) # Set Fmt globally 164 gprint(r'\mathbf{B} =', B) # B will be bold. 165 gprint(r'\mathbf{B} =', B.Fmt(3)) # Fmt(3) here only. 166 gprint(r'\mathbf{B} =', B) # Global Fmt remembered. 167 168 gprint(r'\mathbf{B}^2 =', B*B) 169 170 M = g3.mv('M', 'mv') 171 gprint(r'\langle \mathbf{M} \rangle_2 =', M.grade(2)) 172 # grade(2) could be replaced by, e.g., odd(), or omitted altogether. 173 174 gprint(r'\alpha_1\mathbf{X}/\gamma_r^3') 175 176 grad = g3.grad 177 178 gprint(r'{\nabla} = ', grad) 179 180 self.gen_pdf('test_gprinter', documentclass='book') 181 self.check_pdf('test_gprinter') 182 183 # This test is a POC, and should skip for now 184 @pytest.mark.skip 185 def test_lt_pdf(self): 186 lin_tran() 187 self.gen_pdf('test_lt_pdf', documentclass='report') 188 self.check_pdf('test_lt_pdf', expected_retcode=1)