# Testing that some expressions are canonicalised # properly using the meld algorithm import timeit import sys # Flag to skip the comparison tests no_comp = ("--no-comp" in sys.argv) # *_tableaux tests # Simple symmetric/antisymmetic tensors def tab01(): __cdbkernel__ = create_scope() S_{a b c}::Symmetric; ex:= S_{a b c}S_{b a c} + S_{b a c}S_{c a b}: meld(ex) assert ex == $2S_{a b c}S_{b a c}$, ex print("Test tab01 passed") tab01() def tab02(): __cdbkernel__ = create_scope() A_{a b c}::AntiSymmetric. ex = meld($A_{a b c} - A_{b a c}$) assert ex == $2A_{a b c}$, ex print("Test tab02 passed") tab02() def tab03(): __cdbkernel__ = create_scope() A_{a b c}::AntiSymmetric. ex = meld($A_{a b c} + A_{a c b}$) assert ex == $0$, ex print("Test tab03 passed") tab03() def tab04(): __cdbkernel__ = create_scope() A_{a b c}::AntiSymmetric. ex = meld($A_{c a b}A_{b a c} + A_{b c a}A_{c b a} + 2A_{a b c}A_{a b c}$) assert ex == 0, ex print("Test tab04 passed") tab04() def tab05(): __cdbkernel__ = create_scope() A_{a b}::AntiSymmetric; ex = meld($k * A_{a b} + l * A_{b a}$) assert ex == $(k - l) A_{a b}$, ex print("Test tab05 passed") tab05() # Bianchi identities def tab06(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor. ex = meld($R_{a b c d} + R_{a c d b} + R_{a d b c}$) assert ex == $0$, ex print("Test tab06 passed") tab06() def tab07(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor. ex = meld($k * R_{a b c d}R_{a b c d} + l * R_{a b c d}R_{a c b d}$) assert ex == $(k + 1/2 l) R_{a b c d} R_{a b c d}$, ex print("Test tab07 passed") tab07() def tab08(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor. #ex = meld($R_{a b c d}R_{a b c d} + R_{a b c d}R_{a c b d}$) ex = meld($R_{a b c d}R_{a b c d} + R_{a b c d}R_{a c b d}$) assert ex == $3/2 R_{a b c d}R_{a b c d}$, ex print("Test tab08 passed") tab08() def tab09(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor. ex := R_{a b c d} + R_{a d b c}; meld(ex) assert ex == $R_{a b c d} + R_{a d b c}$, ex print("Test tab09 passed") tab09() def tab10(): __cdbkernel__ = create_scope() {a, b, c, d, e, f, g, h}::Indices. A_{a b}::AntiSymmetric. S_{a b}::Symmetric. ex = $A_{a b}S_{c d}A_{e f}S_{g h} + A_{b a}S_{c d}A_{e f}S_{h g}$ meld(ex) assert ex == $0$, ex print("Test tab10 passed") tab10() def tab11(): __cdbkernel__ = create_scope() {a, b, c, d, e, f, g, h}::Indices. T_{a b c}::Symmetric. ex = meld($T_0 + m_1 * T_{a b c}T^{b a c} + m_2 * T_{b c a}T^{c b a}$) assert ex == $T_0 + (m_1 + m_2) T_{a b c}T^{b a c}$, ex print("Test tab11 passed") tab11() def tab12a(): __cdbkernel__ = create_scope() {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. ex:= W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} - W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a} + (1/4) W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}: meld(ex) assert ex == 0, ex if no_comp: tab12a() print("Test tab12 passed") else: print("Test tab12a (using meld) passed in", timeit.timeit(tab12a,number=1)) def tab12b(): __cdbkernel__ = create_scope() {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. ex:= W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} - W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a} + (1/4) W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}: young_project_product(ex) rename_dummies(ex) assert ex == 0, ex if not no_comp: print("Test tab12b (using young_*) passed in", timeit.timeit(tab12b,number=1)) def tab13(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor. A^{a b c}::AntiSymmetric. ex:= R_{a b c d} A^{a b c}. meld(ex) assert(ex == 0) print("Test tab13a passed") ex:=R_{a b c d} A_{a b c}. meld(ex) assert ex == $R_{a b c d} A_{a b c}$, ex print("Test tab13b passed") tab13() def tab14(): __cdbkernel__ = create_scope() A_{a b c d e}::AntiSymmetric. ex = meld($9A_{b a c e d} - 3A_{e d c b a}$) assert ex == $6A_{b a c e d}$, ex print("Test tab14 passed") tab14() def tab15(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor. ex := k * R_{a b c d} + l * R_{a c d b} + m * R_{a d b c}: meld(ex) assert ex == $(k - m) R_{a b c d} + (l - m) R_{a c d b}$, ex print("Test tab15 passed") tab15() def tab16(): __cdbkernel__ = create_scope() S_{a b c}::Symmetric. assert meld($a + b + c$) == $a + b + c$ assert meld($0$) == $0$ print("Test tab16 passed") tab16() def tab17(): __cdbkernel__ = create_scope() ex := A_{m n} B_{m n} - A_{p q} B_{p q}. meld(ex) assert ex == 0, ex print("Test tab17 passed") tab17() def tab18a(): __cdbkernel__ = create_scope() {a,b,c,d}::Indices(group); {\mu,\nu,\rho,\sigma}::Indices(spacetime); \epsilon^{\mu\nu\rho\sigma}::EpsilonTensor; ex1:=F^{a b}_{\mu\sigma} A^{b c}_{\nu} A^{c a}_{\rho} \epsilon^{\mu\sigma\nu\rho}; ex2:=A^{a b}_{\mu} F^{b c}_{\nu\sigma} A^{c a}_{\rho} \epsilon^{\mu\nu\sigma\rho}; ex:=@(ex1)+@(ex2); sort_product(ex) meld(ex) assert ex == 0, ex if no_comp: tab18a() print("Test tab18 passed") else: print("Test tab18a (using meld) passed in", timeit.timeit(tab18a,number=1000)) def test18b(): __cdbkernel__ = create_scope() {a,b,c,d}::Indices(group); {\mu,\nu,\rho,\sigma}::Indices(spacetime); \epsilon^{\mu\nu\rho\sigma}::EpsilonTensor; ex1:=F^{a b}_{\mu\sigma} A^{b c}_{\nu} A^{c a}_{\rho} \epsilon^{\mu\sigma\nu\rho}; ex2:=A^{a b}_{\mu} F^{b c}_{\nu\sigma} A^{c a}_{\rho} \epsilon^{\mu\nu\sigma\rho}; ex:=@(ex1)+@(ex2); sort_product(ex) canonicalise(ex) assert ex == 0, ex if not no_comp: print("Test tab18b (using canonicalise) passed in", timeit.timeit(test18b,number=1000)) def tab19(): __cdbkernel__ = create_scope() {\mu,\nu,\rho,\sigma}::Indices(spacetime) \epsilon^{\mu\nu\rho\sigma}::EpsilonTensor. {a,b,c,d}::Indices(group) F_{\mu\sigma}::ImplicitIndex(F^{b c}_{\mu\sigma}) A_{\mu}::ImplicitIndex(A^{a b}_{\mu}) Tr{#}::Trace(indices=group) ex1:= F_{\mu\sigma} A_{\nu} A_{\rho} \epsilon^{\mu\sigma\nu\rho}: ex2:= A_{\mu} F_{\nu\sigma} A_{\rho} \epsilon^{\mu\nu\sigma\rho}: ex:= Tr {@(ex1) + @(ex2)}; # This crashes here: explicit_indices(ex) sort_product(ex) meld(ex) assert ex == 0, ex print("Test tab19 passed") #tab19() print("Test tab19 SKIPPED") def tab20(): __cdbkernel__ = create_scope() {\mu, \nu, \rho}::Indices(vector) A_{\mu, \nu}::AntiSymmetric. {a^{\mu}, b^{\nu}}::NonCommuting. ex := A_{\mu \nu} a^{\mu} b^{\rho} a^{\nu}: meld(ex) assert ex == $A_{\mu \nu} a^{\mu} b^{\rho} a^{\nu}$, ex print("Test tab20 passed") tab20() def tab21(): __cdbkernel__ = create_scope() T_{a b c}::SelfAntiCommuting. ex := T_{a b c}T_{b a c} + T_{b a c}T_{a b c}: meld(ex) assert ex == $0$, ex print("Test tab21 passed") tab21() def tab22(): __cdbkernel__ = create_scope() {m,n,p,q,r,s}::Indices; A_{m n}::AntiSymmetric; B_{m n}::Symmetric; ex:= A_{m n} B_{n p} - A_{n m} B_{n p} + A_{m p} B_{q r} B_{q r} - A_{p m} B_{q s} B_{q s}; meld(ex, repeat=False) assert ex == $2A_{m n} B_{n p} + 2A_{m p} B_{q r} B_{q r}$, ex print("Test tab22 passed") tab22() # Portugal's example. def tab23(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor; ex:= 2 R_{a b c d} R_{e f a k} R_{h c k b} R_{d h e f} +4 R_{a b c d} R_{e f k a} R_{h b c e} R_{d k f h} - R_{a b c d} R_{e f k a} R_{h b f e} R_{c d k h} +4 R_{a b c d} R_{h k d f} R_{e f k a} R_{h b c e}; meld(ex) assert ex == 0, ex print("Test tab23 passed") tab23() # RiemannRule13 from MathTensor def tab24(): __cdbkernel__ = create_scope() R_{a b c d}::RiemannTensor; ex:= R_{a b c d} R_{e a g b} R_{c d e g} -1/2 R_{p q r s} R_{t u p q} R_{r s t u}; meld(ex) assert ex == 0, ex print("Test tab24 passed") tab24() def tab25(): import numpy as np {n#}::Indices; R_{n1 n2 n3 n4}::RiemannTensor; str="" for n in range(4): p = np.random.permutation(4*4) for tensor in range(4): str+="R_{" for index in range(4): str+=ilist[p[tensor*4+index]]+' ' str+="} " if n<3: str+="+ " ex=Ex(str) meld(ex); print("Test tab25 passed") #tab25() print("Test tab25 SKIPPED") # Bianchi identity with coordinates and integers def tab26(): R_{a b c d}::RiemannTensor. {t, x, y, z}::Coordinate. ex = meld($R_{t a b c} + R_{t b c a} + R_{t c a b}$) assert ex == 0, ex print("Test tab26 passed") tab26() # Raising and lowering indices def tab27(): {\mu, \nu, \rho, \lambda}::Indices(setA, position=fixed). {A, B, C, D}::Indices(setB, position=independent) {t, r, \phi, \theta}::Coordinate. # Fixed and free indices combine ex = meld($a_{\mu} b^{\mu} - a^{\mu} b_{\mu}$) assert ex == 0, ex ex = meld($T_{\mu\nu} K^{\mu} - T^{\mu}_{\nu} K_{\mu}$) assert ex == 0, ex ex = meld($a_{i}b^{i} - a^{i}b_{i}$) assert ex == 0, ex # Independent indices and coordinates don't ex = meld($a_{A}b^{A} + a^{A}b_{A}$) assert ex == $a_{A}b^{A} + a^{A}b_{A}$, ex ex = meld($a_{t}b^{t} + a^{t}b_{t}$) assert ex == $a_{t}b^{t} + a^{t}b_{t}$, ex print("Test tab27 passed") tab27() # Raising and lowering through a derivative def tab28(): \partial{#}::PartialDerivative. \nabla{#}::Derivative. {\mu, \nu, \rho, \lambda}::Indices(setA, position=fixed). # Free indices through a derivative do combine ex = meld($a_{i} \partial_{\nu}{b^{i}} + a^{i} \partial_{\nu}{b_{i}}$) assert ex == $2a_{i} \partial_{\nu}{b^{i}}$, ex # Fixed indices through a derivative don't combine ex = meld($a_{\mu} \partial_{\nu}{b^{\mu}} + a^{\mu} \partial_{\nu}{b_{\mu}}$) assert ex == $a_{\mu} \partial_{\nu}{b^{\mu}} + a^{\mu} \partial_{\nu}{b_{\mu}}$, ex ex = meld($a_{\mu} \partial_{t}{b^{\mu}} + a^{\mu} \partial_{t}{b_{\mu}}$) assert ex == $a_{\mu} \partial_{t}{b^{\mu}} + a^{\mu} \partial_{t}{b_{\mu}}$, ex ex = meld($a_{\mu} \nabla_{\nu}{b^{\mu}} - a^{\mu} \partial_{\nu}{b_{\mu}}$) assert ex == $a_{\mu} \nabla_{\nu}{b^{\mu}} - a^{\mu} \partial_{\nu}{b_{\mu}}$, ex print("Test tab28 passed") tab28() # Multiple tableaux as product def tab29(): T_{a b c d}::TableauSymmetry(shape={1,1}, indices={0,1}, shape={1,1}, indices={2,3}). ex := T_{a b c d} + T_{b a c d} + T_{a b d c} + T_{b a d c}. meld(ex) assert ex == 0, ex # Bianchi shouldn't hold for this ex := T_{a b c d} + T_{a c d b} + T_{a d b c}. meld(ex) assert ex == $T_{a b c d} + T_{a c d b} + T_{a d b c}$, ex print("Test tab29 passed") tab29() def tab30(): T_{a b c}::TableauSymmetry(shape={2}, indices={0,1}, shape={1,1}, indices={0,1}). ex := T_{a b c}. meld(ex) assert ex == 0, ex print("Test tab30 passed") tab30() # Multiple tableaux as sum def tab31(): T_{a b c}::TableauSymmetry(shape={2,1}, indices={0,2,1}, shape={1,1,1}, indices={0,1,2}). ex := T_{a b c} + T_{b a c}. meld(ex, project_as_sum=True) assert ex == 0, ex print("Test tab31 passed") tab31() def tab32(): R_{a b c d e}::TableauSymmetry(shape={3,2}, indices={0,2,4,1,3}, shape={2,2,1}, indices={0,2,1,3,4}). ex = meld($R_{a b c d e} + R_{a c d b e} + R_{a d b c e}$, project_as_sum=True) assert ex == 0, ex print("Test tab32 passed") tab32() # Automicatically construct tableaux for derivatives of Riemann tensors def tab33(): D{#}::Derivative. R_{a b c d}::RiemannTensor. ex := D_{e}{D_{a}{R_{a b c d}}} D_{h}{D_{i}{R_{b e f g}}} D_{d}{D_{h}{R_{c f g i}}} - 1/8 D_{e}{D_{e}{R_{a b c d}}} D_{h}{D_{i}{R_{a b f g}}} D_{i}{D_{h}{R_{c d f g}}}. meld(ex) assert ex == 0, ex print("Test 33 passed") tab33() def tab34(): \nabla{#}::Derivative. R_{a b c d}::RiemannTensor. ex := \nabla_{e}{R_{a b c d}} + \nabla_{c}{R_{a b d e}} + \nabla_{d}{R_{a b e c}}. meld(ex) assert ex == 0, ex print("Test 34 passed") tab34() def tab35(): {j,k}::Indices; ex := A = - x x n_{k} n_{k} - x x n_{j} n_{j}; meld(_); assert ex == $-2 x x n_{k} n_{k}$, ex print("Test 35 passed") def tab36(): {a,b,c}::Indices. {a,b,c}::Integer(1..3). {X,Y}::Symbol. {X,Y,n_{a}}::Commuting. exA := 10 X n_{a} Y + 2 Y X n_{a}. exB := @(exA). meld(exA) assert exA == $(10X Y + 2Y X) n_{a}$, exA sort_product(exB) meld(exB) assert exB == $12X Y n_{a}$, exB print("Test 36 passed") # *_cycle_traces tests def cyctrace01(): from cdb.core.trace import combine_traces __cdbkernel__ = create_scope() Tr{#}::Trace. {A, B, C, D}::NonCommuting. ex := Tr{A B C D + C D A B + B C D A} - Tr{D A B C}. combine_traces(ex) meld(ex) assert ex == $2 * Tr{A B C D}$, ex print("Test cyctrace01 passed") cyctrace01() def cyctrace02(): __cdbkernel__ = create_scope() {\mu,\nu,\rho}::Indices(vector). {a^{\mu},b^{\mu},c^{\mu}}::NonCommuting. tr{#}::Trace. ex := tr(a^{\mu} b^{\nu} c^{\rho} a^{\mu} b^{\rho} c^{\nu} + b^{\mu} c^{\nu} a^{\rho} b^{\nu} c^{\mu} a^{\rho} + c^{\mu} a^{\nu} b^{\mu} c^{\rho} a^{\nu} b^{\rho}). meld(ex) assert ex == $3 * tr(a^{\mu} b^{\nu} c^{\rho} a^{\mu} b^{\rho} c^{\nu}$, ex print("Test cyctrace02 passed") cyctrace02() def cyctrace03(): __cdbkernel__ = create_scope() {\mu,\nu}::Indices(vector). u^{\mu}::ImplicitIndex. u^{\mu}::SelfNonCommuting. tr{#}::Trace. ex := tr{u^{\mu} u^{\mu} u^{\nu} u^{\nu}} - tr{u^{\mu} u^{\nu} u^{\nu} u^{\mu}}. meld(ex) assert ex == $0$, ex print("Test cyctrace03 passed") # cyctrace03() print("Test cyctrace03 SKIPPED") def cyctrace04(): __cdbkernel__ = create_scope() {\mu,\nu,\rho}::Indices(vector). A^{\mu\nu}::AntiSymmetric. B^{\mu\nu}::Symmetric. C^{\mu\nu}::AntiSymmetric. tr{#}::Trace. {A^{\mu\nu},B^{\mu\nu},C^{\mu\nu}}::NonCommuting. {A^{\mu\nu},B^{\mu\nu},C^{\mu\nu}}::SelfNonCommuting. {A^{\mu\nu},B^{\mu\nu},C^{\mu\nu}}::ImplicitIndex. ex := a tr{A^{\mu\nu} B^{\mu\rho} B^{\nu\rho}}+b tr{C^{\mu\nu} A^{\mu\rho} B^{\nu\rho}}+c tr{C^{\mu\nu} B^{\mu\rho} A^{\nu\rho}}. meld(ex) assert ex == $a tr{A^{\mu\nu} B^{\mu\rho} B^{\nu\rho}}+b tr{C^{\mu\nu} A^{\mu\rho} B^{\nu\rho}}+c tr{C^{\mu\nu} B^{\mu\rho} A^{\nu\rho}}$, ex print("Test cyctrace04 passed") cyctrace04() def cyctrace05(): __cdbkernel__ = create_scope() {\mu,\nu}::Indices(vector). tr{#}::Trace. u^{\mu}::SelfNonCommuting. u^{\mu}::ImplicitIndex. ex:=tr{A u^{\nu} u^{\mu} u^{\mu} u^{\nu} + B u^{\mu} u^{\mu} u^{\nu} u^{\nu}}. meld(ex) assert ex == $tr{ (A+B) u^{\nu} u^{\mu} u^{\mu} u^{\nu} }$, ex print("Test cyctrace05 passed") cyctrace05() def cyctrace06(): __cdbkernel__ = create_scope() {\mu,\nu,\rho}::Indices(vector). A^{\mu\nu}::AntiSymmetric. B^{\mu\nu}::Symmetric. C^{\mu\nu}::AntiSymmetric. tr{#}::Trace. {A^{\mu\nu},B^{\mu\nu},C^{\mu\nu}}::NonCommuting. {A^{\mu\nu},B^{\mu\nu},C^{\mu\nu}}::SelfNonCommuting. {A^{\mu\nu},B^{\mu\nu},C^{\mu\nu}}::ImplicitIndex. ex := tr{ a A^{\mu\nu} B^{\mu\rho} B^{\nu\rho} + b C^{\mu\nu} A^{\mu\rho} B^{\nu\rho} + c C^{\mu\nu} B^{\mu\rho} A^{\nu\rho} }; assert meld($@(ex)$) == ex print("Test cyctrace06 passed") cyctrace06() # *_diagonal tests def diag01(): __cdbkernel__=create_scope() {t,r}::Coordinate; {a,b}::Indices(values={t,r},position=fixed); A_{a b}::Diagonal; ex = $A_{t r}$ + $A_{r r}$ + $A_{r t}$ + $A_{t t}$ meld(ex) assert ex == $A_{r r} + A_{t t}$, ex print("Test diag01 passed") diag01() def diag02(): __cdbkernel__=create_scope() {m,n}::Integer; \delta_{m n}::Diagonal. ex = $-\delta_{1 1}\delta_{2 2}$ + $\delta_{1 2}\delta_{1 2}$ + $\delta_{1 1}\delta_{2 2}$ meld(ex) assert ex == $0$, ex print('Test diag02 passed') diag02() # *_traceless tests def traceless01(): __cdbkernel__=create_scope() {m,n,p,q,r,s,t,u}::Indices(vector). dR_{m n p q r s}::TableauSymmetry(shape={4,2}, indices={2,3,0,1,4,5}). dR_{m n p q r s}::Traceless. ex := dR_{m n p q r r}; meld(_) assert ex == $0$, ex print('Test traceless01 passed') traceless01() # {a,b,c,i,j,k}::Indices; # {a,b,c,i,j,k}::Integer(1..3); # {ct, st}::Symbol; # \nabla{#}::Derivative; # {st,ct,n_{k}}::Depends(\nabla{#}) # # {d{#}}::KroneckerDelta; # {e_{a b c}}::EpsilonTensor(delta=d); # # rota := R_{a j} = ct d_{a j} + (1-ct) n_{a} n_{j} - st e_{a j k} n_{k}; # FGR := \nabla{R_{a k}}_{j} \nabla{R_{a k}}_{j}; # # substitute(FGR, rota); distribute(_, repeat=True); # product_rule(_); unwrap(_); # distribute(_, repeat=True); # collect_factors(_); sort_product(_); sort_sum(_); # meld(_);