# Derivatives are generic objects satisfying the product rule # in one or more of their arguments. Commutators are examples of # such objects. def test01(): __cdbkernel__=create_scope() D(#)::Derivative. obj1:= a*b*D(c*d*e)*f*g; product_rule(_) tst1:= a*b*(D(c)*d*e+c*D(d)*e+c*d*D(e))*f*g-@(obj1); assert(tst1==0) print("Test 01 passed") test01() def test02(): __cdbkernel__=create_scope() D(a??)(b??)(c??)::Derivative. obj2:= a*b*D(c*d*e)(h1)(h2)*f*g; product_rule(_) tst2:= a*b*(D(c)(h1)(h2)*d*e+c*D(d)(h1)(h2)*e+c*d*D(e)(h1)(h2))*f*g-@(obj2); assert(tst2==0) print("Test 02 passed") test02() # Using the properties of \diff. def test03(): __cdbkernel__=create_scope() \diff{#}::PartialDerivative. obj5:= \diff{A*B}_\mu; product_rule(_) tst5:= \diff{A}_\mu * B + A * \diff{B}_\mu - @(obj5); assert(tst5==0) print("Test 03 passed") test03() def test04(): __cdbkernel__=create_scope() \diff{#}::PartialDerivative; obj6:= \diff{g^{\mu \kappa} * \diff{g_{\kappa \nu}}_{\rho}}_{\sigma}; product_rule(_) tst6:= \diff{g^{\mu \kappa}}_{\sigma} * \diff{g_{\kappa \nu}}_{\rho} +g^{\mu \kappa} * \diff{g_{\kappa \nu}}_{\rho \sigma} - @(obj6); assert(tst6==0) print("Test 04 passed") test04() def test07(): __cdbkernel__=create_scope() \diff{#}::PartialDerivative; {\mu,\nu,\rho,\sigma,\kappa,\lambda,\eta}::Indices(spacetime); obj7:= g^{\eta \kappa} * \diff{\eta_{\nu \sigma}}_{\kappa} * g^{\mu \lambda} * \diff{eta_{\lambda \eta}}_{\rho}; rl:=\diff{\eta_{\mu\nu}}_{\rho} -> 0; substitute(obj7, rl) assert(obj7==0) print("Test 07 passed") test07() # \delta in combination with \diff # def test08(): __cdbkernel__=create_scope() \delta_{n q}::KroneckerDelta; \diff{#}::Derivative; obj8:= \diff{A_{m n}}_{p} \delta_{n q} \delta_{p t}; eliminate_kronecker(_) tst8:= \diff{A_{m q}}_{t} - @(obj8); assert(tst8==0) print("Test 08 passed") test08() # Multiple derivatives and the product rule def test09(): __cdbkernel__=create_scope() \diff{#}::PartialDerivative. obj9:= 3 \diff_{m n}{4*A*B}; product_rule(_) distribute(_) product_rule(_) tst9:= 12 \diff_{m n}{A} B + 12 \diff_{m}{A} \diff_{n}{B} + 12 \diff_{n}{A} \diff_{m}{B} + 12 A \diff_{m n}{B} - @(obj9); assert(tst9==0) print("Test 09 passed") test09() # Order of child nodes on PartialDerivative. def test10(): __cdbkernel__=create_scope() {a,b,c,d}::Indices(vector). \partial{#}::PartialDerivative. A_{a b}::AntiSymmetric. obj10:= \partial_{b a}{ A_{d c} }; canonicalise(_) tst10:= \partial_{a b}{ A_{c d} } + @(obj10); collect_terms(_) assert(tst10==0) print("Test 10 passed") test10() def test10b(): __cdbkernel__=create_scope() {a,b,c,d}::Indices(vector). \partial{#}::PartialDerivative. A_{a b}::AntiSymmetric. obj10b:= \partial{ A_{d c} }_{b a}; canonicalise(_) tst10b:= \partial{ A_{c d} }_{a b} + @(obj10b); assert(tst10b==0) print("Test 10b passed") test10b() # Multiple derivatives again # # def test11(): # __cdbkernel__=create_scope() # \partial{#}::PartialDerivative. # obj11a:= \partial(A B C)_{a b}; # product_rule(_) # tst11a:= \partial{\partial(A)_{a} * B * C + A * \partial(B)_{a} * C + A * B * \partial(C)_{a}}_{b} - @(obj11a); # collect_terms(_) # assert(tst11a==0) # # test11() def test11b(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj11b:= \partial_{a b}(A B C); product_rule(_) tst11b:= \partial_{a}{\partial_{b}(A) * B * C + A * \partial_{b}(B) * C + A * B * \partial_{b}(C)} - @(obj11b); collect_terms(_) assert(tst11b==0) print("Test 11b passed") test11b() # More tricky derivatives def test12(): __cdbkernel__=create_scope() \Omega{#}::Derivative. {A,B,C,D}::Depends(\Omega{#}); obj12:= \Omega_{a}(A B)(C D); product_rule(_) product_rule(_) distribute(_) tst12:= \Omega_{a}(A)(C) * D * B + C * \Omega_{a}(A)(D) * B + A * \Omega_{a}(B)(C) * D + A * C * \Omega_{a}(B)(D) -@(obj12); collect_terms(_) assert(tst12==0) print("Test 12 passed") test12() # Test 13: Inheritance # # reset. # \nabla{#}::Derivative. # A_{m n}::Traceless. # obj13:= \nabla_{m}{A_{p p}}*Q_{m}; # canonicalise(_); # Product_rule on powers def test14(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj14a:= \partial_{m n}{A**2}; product_rule(_) tst14a:= \partial_{m}(2*A*\partial_{n}{A}) - @(obj14a); collect_terms(_) assert(tst14a==0) print("Test 14 passed") test14() def test14b(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj14b:= \partial_{m n}{A**3}; product_rule(_) tst14b:= \partial_{m}(3*A**2*\partial_{n}{A}) - @(obj14b); collect_terms(_) assert(tst14b==0) print("Test 14b passed") test14b() # reset. # \partial{#}::PartialDerivative. # obj14c:= \partial_{m n}{A**(d+1)}; # product_rule(_); # # FIXME def test14d(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj14d:= \partial_{m n}{A**d}; product_rule(_) tst14d:= \partial_{m}(d * A**(d - 1) * \partial_{n}{A}) - @(obj14d); collect_terms(_) assert(tst14d==0) print("Test 14d passed") test14d() def test14f(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj14f:= \partial{A*\partial{A}}; product_rule(_) tst14f:= \partial{A} * \partial{A} + A * \partial{\partial{A}} - @(obj14f); collect_terms(_) assert(tst14f==0) print("Test 14f passed") test14f() def test15(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj15:= \partial{-a**2}; product_rule(_) tst15:= 2 a \partial{a} + @(obj15); collect_terms(_) assert(tst15==0) print("Test 15 passed") test15() def test16(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj16:= \partial{-a**3}; product_rule(_) tst16:= 3 a**2 \partial{a} + @(obj16); collect_terms(_) assert(tst16==0) print("Test 16 passed") test16() # Flattening # def test17(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative. obj17:= \partial_{a}{\partial_{b c}{F}}; tst17:= \partial_{a b c}{F} - @(obj17); assert(tst17==0) print("Test 17 passed") test17() # # Test 18: more flattening # # # # FIXME: Because multi-derivatives get collected, we would now need # # to have a notation like \nabla_{a??.. b}{A??} -> # \partial{#}::PartialDerivative. # \nabla{#}::Derivative. # obj18:= \nabla_{a}{\nabla_{b}{F}}; # substitute(_, "\nabla_{a}{A??} -> \partial_{a}{A??}" ); # tst18:= \partial_{a b}{F} - @(obj18); # collect_terms(_); # assert(tst18); # # Test 19: Grassman derivatives # def test19(): __cdbkernel__=create_scope() {\alpha,\beta,\gamma}::Indices(spinor). \theta^{\alpha}::Coordinate. \theta^{\alpha}::SelfAntiCommuting. D{#}::Derivative. obj19a:= D_{\theta^{\alpha}}{\theta^\beta \theta^\gamma}; product_rule(_) tst19a:= D_{\theta^{\alpha}}{\theta^{\beta}} \theta^{\gamma} - \theta^{\beta} D_{\theta^{\alpha}}{\theta^{\gamma}} - @(obj19a); assert(tst19a==0) print("Test 19 passed") test19() def test19b(): __cdbkernel__=create_scope() {\alpha,\beta,\gamma}::Indices(spinor). {\alpha,\beta,\gamma}::AntiCommuting. \theta^{\alpha}::Coordinate. D{#}::Derivative. obj19b:= D_{\alpha}{\theta^\beta \theta^\gamma}; product_rule(_); tst19b:= D_{\alpha}{\theta^{\beta}} \theta^{\gamma} - \theta^{\beta} D_{\alpha}{\theta^{\gamma}} - @(obj19b); assert(tst19b==0) print("Test 19b passed") def test19c(): __cdbkernel__=create_scope() {\alpha,\beta,\gamma}::Indices(spinor, position=fixed). {\alpha,\beta,\gamma}::AntiCommuting. D{#}::Derivative. obj19c:= D^{\alpha}{ D_{\alpha}{T^{\beta} S^{\gamma}}}; product_rule(_) distribute(_) product_rule(_) tst19c:= D^{\alpha}{D_{\alpha}{T^{\beta}}} * S^{\gamma} + D_{\alpha}{T^{\beta}} * D^{\alpha}{S^{\gamma}} - D^{\alpha}{T^{\beta}} * D_{\alpha}{S^{\gamma}} + T^{\beta} * D^{\alpha}{D_{\alpha}{S^{\gamma}}} - @(obj19c); assert(tst19c==0) print("Test 19c passed") test19c() # In the following test, the objects 'b' and 'c' carry an implicit # spinor index, and the derivative 'D' carries an explicit spinor # index. Moving a 'D_\alpha' through 'b' should pick up a minus sign. # def test19d(): # {\alpha,\beta,\gamma}::Indices(spinor, position=fixed). # {\alpha,\beta,\gamma}::AntiCommuting. # D{#}::Derivative. # {b, c}::SelfAntiCommuting. # {b, c}::ImplicitIndex(spinor). # obj19d:= D^{\alpha}{D_{\alpha}{b*c}}; # product_rule(_); # distribute(_); # product_rule(_); # distribute(_); # tst19d:= D^{\alpha}{D_{\alpha}{b}} c # - D_{\alpha}{b} D^{\alpha}{c} # + D^{\alpha}{b} D_{\alpha}{c} # + b D^{\alpha}{D_{\alpha}{c}} - @(obj19d); # collect_terms(_); # assert(tst19d==0) # # test19d() # Anti-commuting indices. def test20(): __cdbkernel__=create_scope() \dot{#}::Accent. {a,b,c,d}::Indices(spinor). {\dot{a},\dot{b},\dot{c},\dot{d}}::Indices(dspinor). {a,b,c,d,\dot{a},\dot{b},\dot{c},\dot{d}}::AntiCommuting. D{#}::Derivative. obj20:= D_{a}{D_{\dot{a}}{f g}}; product_rule(_) distribute(_) product_rule(_) tst20:= D_{a}{D_{\dot{a}}{f}} * g - D_{\dot{a}}{f} * D_{a}{g} + D_{a}{f} * D_{\dot{a}}{g} + f * D_{a}{D_{\dot{a}}{g}} - @(obj20); collect_terms(_) assert(tst20==0) print("Test 20 passed") test20() # Two index sets, anti-commuting def test21(): __cdbkernel__=create_scope() {\alpha,\beta,\gamma}::Indices(Spinor). {\dalpha,\dbeta,\dgamma}::Indices(DottedSpinor). {\alpha,\beta,\gamma,\dalpha,\dbeta,\dgamma,b,c}::AntiCommuting. {\bD{#}, D{#}}::Derivative. obj21:= D_{\alpha}{\bD_{\dalpha}{b*c}}; product_rule(_) distribute(_) product_rule(_) distribute(_) tst21:= D_{\alpha}{\bD_{\dalpha}{b}} * c + \bD_{\dalpha}{b} * D_{\alpha}{c} - D_{\alpha}{b} * \bD_{\dalpha}{c} + b * D_{\alpha}{\bD_{\dalpha}{c}} - @(obj21); collect_terms(_) assert(tst21==0) print("Test 21 passed") test21() # Explicit and implicit indices def test22(): __cdbkernel__=create_scope() {\alpha,\beta,\gamma}::Indices(). {\theta,\lambda}::ImplicitIndex(). {\alpha,\beta,\gamma,\theta,\lambda}::AntiCommuting. D{#}::Derivative. obj22:= D_{\alpha}{\theta \lambda}; product_rule(_) tst22:= D_{\alpha}{\theta} \lambda - \theta D_{\alpha}{\lambda} - @(obj22); collect_terms(_) assert(tst22==0) print("Test 22 passed") test22() # Multiple indices on tensors. def test23(): __cdbkernel__=create_scope() {a,b,c,d,e}::Indices. {a,b,c,d,e}::AntiCommuting. D{#}::Derivative. obj23:= D_{a}{A^{b} T^{c d} C^{e}}; product_rule(_) tst23:= D_{a}{A^{b}} * T^{c d} * C^{e} - A^{b} * D_{a}{T^{c d}} * C^{e} - A^{b} * T^{c d} * D_{a}{C^{e}} - @(obj23); collect_terms(_) assert(tst23==0) print("Test 23 passed") test23() # Unwrapping. def test24(): __cdbkernel__=create_scope() \hat{#}::Accent; \hat{#}::Distributable; B::Depends(\hat{#}); ex:=\hat{A+B+C}; distribute(_) unwrap(_) tst:=\hat{B}-@(ex); assert(tst==0) print("Test 24 passed") test24() # Bug reported def test25(): __cdbkernel__=create_scope() \del{#}::Derivative. X::Depends(\del{#}). ex1:= \del{X*Y*Z*\del{X}}; product_rule(ex1) unwrap(ex1) tst:=\del{X} Y Z \del{X} + X Y Z \del{\del{X}} - @(ex1); assert(tst==0) print("Test 25a passed") ex2:= \del{X*Y*Z*\del{Y}}; product_rule(ex2) unwrap(ex2) assert(ex2==0) print("Test 25b passed") test25() def test26(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative; ex:=\partial_{\mu}{A}; substitute(_, $A -> 3$) assert(ex==0) print("Test 26 passed") test26() def test27(): __cdbkernel__=create_scope() \partial{#}::Derivative; ex:=\partial_{\mu}{A}; substitute(_, $A -> 3$) assert(ex==0) print("Test 27 passed") test27() def test28(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative; { A, B, C, D }::Depends(\partial{#}); ex := \partial_{\alpha}{ A (B + r C) }; unwrap(ex) tst:= \partial_{\alpha}{ A (B + r C) } - @(ex); assert(tst==0) print("Test 28 passed") test28() def test29(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative; { A, B, C, D }::Depends(\partial{#}); ex := \partial_{\alpha}{ (A + r B) (C + r D) }. unwrap(ex) tst:= \partial_{\alpha}{ (A + r B) (C + r D) } - @(ex); assert(tst==0) print("Test 29 passed") test29() def test30(): __cdbkernel__=create_scope() { \del{#}, \delbar{#} }::PartialDerivative; X_{\mu}::Depends(\del{#}, \delbar{#}); ex:= \del{\delbar{X_{\mu}}}; unwrap(_) tst:= \del{\delbar{X_{\mu}}} - @(ex); assert(tst==0) print("Test 30 passed") test30() def test31(): __cdbkernel__=create_scope() \hat{#}::Accent; \partial{#}::PartialDerivative; A::Depends(\partial{#}, \hat{#}); ex:=\partial{A \hat{A} B}; product_rule(_) unwrap(_) tst:= \partial{A} \hat{A} B + A \partial{\hat{A}} B - @(ex); assert(tst==0) print("Test 31 passed") test31() def test32(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative; ex:= \partial_{\mu}{A_{\nu}} = B_{\mu\nu}; ex2:= 4 \partial^{\mu}{ @(ex) }; lhs2 = lhs(ex2) rhs2 = rhs(ex2) lhstst:= 4 \partial^{\mu}_{\mu}{A_{\nu}} - @(lhs2); rhstst:= 4 \partial^{\mu}{ B_{\mu\nu} } - @(rhs2); assert(lhstst==0) assert(rhstst==0) print("Test 32 passed") test32() def test33(): __cdbkernel__=create_scope() d{#}::ExteriorDerivative; A::DifferentialForm(degree=3); B::DifferentialForm(degree=3); ex:= A = B; ex2:= d{ @(ex) }; lhs2 = lhs(ex2) rhs2 = rhs(ex2) lhstst := d{A} - @(lhs2); rhstst := d{B} - @(rhs2); assert(lhstst==0) assert(rhstst==0) print("Test 33 passed") test33() def test34(): __cdbkernel__=create_scope() {\mu,\nu,\rho}::Indices(position=fixed, values={0,1,2,3}); \partial{#}::PartialDerivative; A^{\mu}::Depends(\partial{#}); ex:= \partial_{\mu}{A^{2}}; unwrap(ex) tst:= \partial_{\mu}{A^{2}} - @(ex); assert(tst==0) print("Test 34 passed") test34() def test35(): __cdbkernel__=create_scope() \partial{#}::PartialDerivative; {\mu,\nu,\rho}::Indices; ex:= \partial_{\mu}{ (\partial_{\nu}{\phi} \partial^{\nu}{\phi})**3 }; product_rule(ex) tst:= 3 (\partial_{\nu}{\phi} \partial^{\nu}{\phi})**2 \partial_{\mu}{\partial_{\nu}{\phi} \partial^{\nu}{\phi} } - @(ex); assert(tst==0) print("Test 35 passed") test35() def test36(): __cdbkernel__=create_scope() # When there are more types of accents and derivatives, unwrap # needs to be guided about what to unwrap, or it will do all. {m, n, p, q}::Indices( position=independent); \partial{#}::PartialDerivative; X_{m}::Depends(\partial{#}); \Gamma{#}::GammaMatrix; { \theta, \psi }::Spinor(dimension=10, type=MajoranaWeyl); \bar{\theta}::Depends(\partial{#}); \bar{#}::DiracBar; ex:=\bar{Q \Gamma^{m} \theta}\partial_{\mu}{X_{m}} + \partial_{\mu}{\Gamma^{m}\bar{\theta}} X_{m}; unwrap(_, $\partial{#}$) tst:=\bar{Q \Gamma^{m} \theta}\partial_{\mu}{X_{m}} + \Gamma^{m} \partial_{\mu}{\bar{\theta}} X_{m} - @(ex); assert(tst==0) print("Test 36a passed") unwrap(ex) tst:=Q \bar{\Gamma^{m} \theta}\partial_{\mu}{X_{m}} + \Gamma^{m} \partial_{\mu}{\bar{\theta}} X_{m} - @(ex); assert(tst==0) print("Test 36b passed") test36() def test37(): __cdbkernel__=create_scope() A::DifferentialForm(degree=1). B::DifferentialForm(degree=2). C::DifferentialForm(degree=3). d{#}::ExteriorDerivative. ex:=C= d{B}+A ^ B; ge:=d{C}+A ^ C; substitute(ge, ex) distribute(ge) product_rule(ge) tst:= d{A} ^ B - @(ge); assert(tst==0) print("Test 37 passed") test37() def test38(): __cdbkernel__=create_scope() A::DifferentialForm(degree=1). B::DifferentialForm(degree=1). C::DifferentialForm(degree=2). ex:= A ^ B + B ^ A + A ^ C + C ^ A; sort_product(_) tst:= 2 A ^ C - @(ex); assert(tst==0) print("Test 38 passed") test38() def test39(): __cdbkernel__=create_scope() A0::DifferentialForm(degree=0). A1::DifferentialForm(degree=1). A2::DifferentialForm(degree=2). A3::DifferentialForm(degree=3). ex:= A3 ^ A1 - A1 ^ A3 + A2 ^ A2 ^ A0; sort_product(_) tst:= - 2 A1 ^ A3 + A0 ^ A2 ^ A2 - @(ex); assert(tst==0) print("Test 39 passed") test39() # def test40(): # __cdbkernel__=create_scope() # {m,n,p,q}::Indices(); # \partial{#}::PartialDerivative; # \phi::Depends(m); # ex:=\partial_{m}{ c \phi }; # unwrap(_) # tst:= c \partial_{m}{\phi} - @(ex); # assert(tst==0) # print("Test 40 passed") # # test40() # {dx,dp}::DifferentialForm(degree=1); # ex:= ( x dp ) ^ ( p dx ) + ( p dx ) ^ ( x dp ); # sort_product(ex); def test40a(): __cdbkernel__=create_scope() {x,y}::Coordinate. \partial{#}::PartialDerivative. f::Depends(x); g::Depends(y); ex:=\partial_{x}{A*f*g}; unwrap(_) tst:= A g \partial_{x}{f} - @(ex); assert(tst==0) print("Test 40a passed") def test40b(): __cdbkernel__=create_scope() {x,y}::Coordinate. \partial{#}::PartialDerivative. f::Depends(x); g::Depends(y); ex:=\partial_{y}{A*f*g}; unwrap(_) tst:= A f \partial_{y}{g} - @(ex); assert(tst==0) print("Test 40b passed") test40a() test40b() def test41(): __cdbkernel__=create_scope() {a,b}::Indices; F^{a b}::AntiSymmetric; \nabla{#}::Derivative; ex:=\nabla_{b}{F^{a b}}; young_project_tensor(ex) tst:= \nabla_{b}{ 1/2 F^{a b} - 1/2 F^{b a} } - @(ex); assert(tst==0) print("Test 41 passed") test41() # {\mu,\nu,\rho,\sigma}::Indices; # \partial{#}::Derivative; # \psi_{\mu}::SelfAntiCommuting; # ex:= \psi_{\nu} \psi_{\mu} + \psi_{\mu} \psi_{\nu}; # sort_product(_); # ex:= \partial_{\mu}{\psi_{\nu}} \psi_{\rho} + \psi_{\rho} \partial_{\mu}{\psi_{\nu}}; # sort_product(_); # # ex:= \partial{\psi_{\nu}} \partial{\psi_{\mu}} + \psi_{\nu} \psi_{\mu}; # canonicalise(_); # # ex:= \partial{\psi_{\nu}} \partial{\psi_{\mu}} + \psi_{\nu} \psi_{\mu}; # sort_product(_); def test42(): __cdbkernel__=create_scope() \nabla{#}::Derivative; A::ImplicitIndex; tr{#}::Trace; \nabla{#}::ImplicitIndex; ex:=tr{\nabla{A B}}; product_rule(ex) tst:= tr{\nabla{A} B + A \nabla{B}} - @(ex); assert(tst==0) print("Test 42 passed") test42()