
# Substituting requires many dummy index relabelling. 
#
# Test 1: 'm' relabelling is triggered by a_{m} outside
#         'n' relabelling in second term ditto
#         'n' relabelling in first term because c_{pmn} -> c_{nmn} .

def test01():
    __cdbkernel__=create_scope()
    {d1,d2,d3,d4,m,n,p,r}::Indices(vector).
    obj1:= a_{m}*b_{n} + c_r b_r d_{m n};
    substitute(_, $b_{p} -> c_{p m n} A^{m n} + c_{p}$ )
    distribute(_)
    tst1:= a_{m} * c_{n d2 d1} * A^{d2 d1} + a_{m} * c_{n} + c_{r} * c_{r d1 d2} * A^{d1 d2} * d_{m n} + c_{r} * c_{r} * d_{m n} - @(obj1); 
    assert(tst1==0)
    print('Test 01 passed')

test01()

def test02():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(position=fixed).
    ex:= F_{m n} F^{m n};
    rl:= F_{m n} -> G_{m n};
    substitute(ex, rl)
    tst:= G_{m n} F^{m n} - @(ex);
    assert(tst==0)
    print('Test 02 passed')    

test02()

def test02b():
    # Product substitutions.
    __cdbkernel__=create_scope()
    {d1,d2,d3,d4,m,n,p,r,s,t,a,b}::Indices(vector).
    obj2:= a_{m n} * q * e * b_{m p} * o + d_{n p};
    substitute(obj2, $a_{r s} b_{r t} -> c_{s t}$ )
    tst2:= c_{n p} q e o + d_{n p} - @(obj2);
    assert(tst2==0)
    print('Test 02b passed')    

test02b()

def test02c():
    # Reducing to zero
    __cdbkernel__=create_scope()
    obj3:= A_{m n} B_{m n} k1_{a} k1_{a} k2_{b};
    substitute(_,  $k1_a k1_a -> 0$ )
    assert(obj3==0)
    print('Test 02c passed')    

test02c()
    
def test03():
    # Upper and lower indices replaced automagically.
    #
    # Side note: the replacement
    #    rl:= F_{m n} -> G_{m n} + H^{m n};
    # is tricky. A rule will be generated for all objects
    # matched on the lhs. So _m and _n to something. But on the rhs, that would
    # not normally match. Best to disallow these rules.
    __cdbkernel__=create_scope()
    {m,n,p,q}::Indices(position=free).
    ex:= F_{p q} F^{p q};
    rl:= F_{m n} -> G_{m n};
    substitute(ex, rl)
    rename_dummies(ex)
    tst2:= G_{m n} G^{m n} - @(ex);
    assert(tst2==0)
    print('Test 03 passed')
    
test03()

def test04():
    # Basic test of variational derivative.
    __cdbkernel__=create_scope()
    obj43:= A*B*A + D*E;
    vary(obj43, $A->C$)
    tst43:= C*B*A + A*B*C - @(obj43);
    assert(tst43==0)
    print('Test 04 passed')
    
test04()

def test04b():
    # Indices in the pattern.
    __cdbkernel__=create_scope()
    obj4:= A_m A_n + B_m C_n + D_{m n} A_p A_p;
    substitute(_, $A_a A_a -> q$ )
    tst4:= A_m A_n + B_m C_n + D_{m n} q - @(obj4);
    assert(tst4==0)
    print('Test 04b passed')
    
#test04b()


def test05():
    # Variational derivative under Accents.
    __cdbkernel__=create_scope()
    \bar{?}::Accent.
    obj45:= \bar{A}*B*A;
    vary(obj45, $A -> C$)
    tst45:= \bar{C}*B*A + \bar{A}*B*C - @(obj45);
    assert(tst45==0)
    print('Test 05 passed')
    
test05()

def test06():
    # Nested substitutes.
    __cdbkernel__=create_scope()
    {a,b,c,d}::Indices.
    { \partial{#}, \partialp{#} }::PartialDerivative.
    A::Depends(\partial{#}).
    B::Depends(\partialp{#}).
    \Omega{#}::Derivative.
    obj46:= \Omega( \partial_{a}{A} )( \partialp_{b}{B} );
    rl:= \Omega( \partial_{a}{A??} )( B?? ) -> \partial_{a}{ \Omega(A??)(B??) };
    substitute(obj46, rl)
    tst46:= \partial_{a}{ \Omega(A)(\partialp_{b}{B}) } - @(obj46);
    assert(tst46==0)
    print('Test 06 passed')
    
test06()

def test07():
    # Vary multiple terms and single-factor terms.
    __cdbkernel__=create_scope()
    obj70:= A + B Q;
    vary(_, $A -> Q, B -> Z$ )
    tst70:= Q + Z Q - @(obj70);
    assert(tst70==0)
    print('Test 07 passed')
    
test07()

def test17():
    # Test 17: Object wildcards
    obj17:= [ A B, C];
    substitute(_, $[ M? N?, P? ] -> P? M? N?$ )
    tst17:= @(obj17) - C A B;
    assert(tst17==0)
    print('Test 17 passed')
    
test17()

def test84():
    # Bug reported Sun, 9 Nov 2014 15:51:05 +0800
    \partial{#}::PartialDerivative.
    yy:= a+ a*A;
    vary(yy, $A->\delta{A}$ )
    tst84:= a \delta{A} - @(yy);
    assert(tst84==0)
    print('Test 84 passed')

test84()

def test100():
    {\mu,\nu,\rho}::Indices(position=free).
    \partial{#}::PartialDerivative.
    ex:= \int{\partial_{\mu}{A_{\nu}} - \partial_{\nu}{A_{\mu}}}{x};
    vary(ex, $A_{\mu} -> \delta{A_{\mu}}$)


def test101():
    __cdbkernel__=create_scope()
    {m,n,p}::Integer;
    A_{m}::SelfNonCommuting.
    ex:= A_{3} A_{2} A_{1} A_{0} + A_{0} A_{8};
    rl:= A_{m} A_{n} | m > n -> Q;
    substitute(ex, rl, repeat=True)
    tst:= Q Q + A_{0} A_{8} - @(ex);
    assert(tst==0)
    print('Test 101 passed')

test101()

def test102():
    __cdbkernel__=create_scope()
    {m,n,p}::Integer;
    {m,n,p}::Symbol;
    A_{m}::SelfNonCommuting;
    ex:= A_{2} A_{3} A_{1} + A_{1} A_{0};
    rl:= A_{m} A_{n} | m > n -> A_{n} A_{m} + Q;
    ex.reset()
    while ex.changed():
        distribute(ex)
        substitute(ex, rl)
        sort_product(ex)
    
    tst:= A_{1} A_{2} A_{3} + A_{3} Q + A_{2} Q + A_{0} A_{1} + Q - @(ex);
    assert(tst==0)
    print('Test 102 passed')

test102()
    
def test103():
    __cdbkernel__=create_scope()
    \partial{#}::PartialDerivative;
    rl:= A_{m? n?} -> \partial_{m?}{B_{n?}};
    ex:= A_{4 k} A_{k 4};
    substitute(ex, rl)
    tst:= \partial_{4}{B_{k}} \partial_{k}{B_{4}} - @(ex);
    assert(tst==0)

test103()

def test104():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(position=independent);
    ex:= g^{4};
    rl:= g_{4} -> A;
    # How is this thing supposed to know that 4 is in the {m,n,p} set?
    substitute(ex, rl)
    tst:= g^{4} - @(ex);
    assert(tst==0)
    print("Test 104 passed")

test104()

def test105():
    __cdbkernel__=create_scope()
    ex:= A_{m n} + B_{m n};
    rl:= C?_{m? n?} -> n? C?_{n?};
    substitute(ex, rl)
    tst:= n A_{n} + n B_{n} - @(ex);
    assert(tst==0)
    print("Test 105 passed")

test105()

def test106():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(position=free);
    ex:=\int{ A_{m} A^{m} }{x};
    rl:= A_{m} -> B_{m n} C^{n};
    substitute(ex, rl)
    tst:= \int{ B_{m n} C^{n} B^{m}_{p} C^{p} }{x} - @(ex);
    assert(tst==0)
    print("Test 106 passed")
    
test106()
    
def test107():
    __cdbkernel__=create_scope()
    ex:= A_{m n} - B_{m n};
    substitute(ex, $_{m} -> _{2}$)
    tst:= A_{2 n} - B_{2 n} - @(ex);
    assert(tst==0)
    print("Test 107 passed")

test107()

def test108():
    __cdbkernel__=create_scope()
    \nabla{#}::Derivative;
    {\mu,\nu,\rho,\sigma}::Indices(position=fixed);
    ex:= \nabla_{\mu}{K^{\nu}} = B_{\mu} D^{\nu};
    substitute(_, $\nabla_{\mu}{A?^{\nu}} = C_{\mu}^{\nu}$)
    tst:= C_{\mu}^{\nu} = B_{\mu} D^{\nu};
    assert(ex==tst)
    print("Test 108 passed")

test108()

def test109():
    __cdbkernel__=create_scope()
    {\mu,\nu,\rho,\sigma}::Indices;
    \partial{#}::PartialDerivative;
    g_{\mu\nu}::Metric;
    g^{\mu\nu}::InverseMetric;
    g^{\mu}_{\nu}::KroneckerDelta;
    g_{\mu}^{\nu}::KroneckerDelta;
    ex:= \partial_{5}{ g^{5 5} } \partial_{5}{ g_{5 5} }  - A_{5};
    substitute(ex, $g_{5 5} -> B$)
    tst:= \partial_{5}{ g^{5 5} } \partial_{5}{B} - A_{5} - @(ex);
    assert(tst==0)
    print("Test 109 passed")

test109()

# def test110():
# {\mu,\nu,\rho}::Integer(0..d-1).
# {\mu,\nu,\rho}::Indices.
# {m,n}::Integer.
# rl:= \alpha_{m}^{\mu} \alpha_{n}^{\nu} | m > n -> \alpha_{n}^{\nu} \alpha_{m}^{\mu} +  \delta_{m}_{-n} \delta^{\mu\nu};
# ex:= \alpha_{1}^{\mu} \alpha_{0}^{\mu};
# substitute(ex, rl);

def test110():        
    __cdbkernel__=create_scope()
    ex:= A + 2 B + C + 2 D;
    substitute(_, $B + D = Q$)
    tst:= A + C + 2 Q - @(ex);
    assert(tst==0)
    print("Test 110 passed")

test110()

def test111():
    __cdbkernel__=create_scope()        
    {t,x}::Coordinate;        
    {\mu, \nu, \rho, \sigma}::Indices(values={t,x}, position=fixed);
    \partial{#}::PartialDerivative;
    ex:= \partial_{\mu}{ g_{\rho\sigma} };
    rl:= \partial_{t}{ g_{\mu\nu} } -> C_{\mu\nu};
    substitute(ex, rl)
    tst:= \partial_{\mu}{ g_{\rho\sigma} } - @(ex);
    assert(tst==0)
    print("Test 111 passed")

test111()

def test112():
    __cdbkernel__=create_scope()
    {m,n,p,q}::Indices;        
    ex:=A B_{m n} C;
    rl:=A?_{p q} -> - 2 A?_{p q};
    substitute(ex, rl)
    tst:=-2 A B_{m n} C - @(ex);
    assert(tst==0)
    print("Test 112 passed")

test112()

def test113():
    # spotted by Leo Brewin 15-Mar-2018.
    __cdbkernel__=create_scope()
    {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s}::Indices(position=fixed).
    ex := A^{f} A^{m} B_{g f} G^{a}_{m e} G^{e}_{b d}.
    substitute(_, $A^{e} B_{c e} G^{a}_{b d} -> A^{f} B_{f} R^{a}_{b c d}$)
    tst:= A^{f} B_{f} R^{a}_{m g e} A^{m} G^{e}_{b d} - @(ex);
    assert(tst==0)
    print("Test 113 passed")

test113()

def test114():
    __cdbkernel__=create_scope()
    {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s}::Indices(position=fixed).       
    ex := B^{c}_{a d} A^{d} A^{e}.
    substitute(ex, $A^{c} A^{b} B^{a}_{d b} -> A^{b} A^{c} C^{a}_{b d}$)
    tst:= A^{d} A^{e} C^{c}_{d a} - @(ex);
    assert(tst==0)
    print("Test 114 passed")

test114()

def test115():
    __cdbkernel__=create_scope()
    {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s}::Indices(position=fixed).
    ex := B^{c}_{a d} A^{d} A^{e}.
    substitute(ex, $B^{a}_{d b} A^{c} A^{b} -> A^{b} A^{c} C^{a}_{b d}$)
    tst:= A^{d} A^{e} C^{c}_{d a} - @(ex);
    assert(tst==0)
    print("Test 115 passed")

test115()

def test116():
    __cdbkernel__=create_scope()
    D{#}::Derivative;
    {\epsilon, \psi_{\mu},\psi_{\mu\nu} }::Spinor(dimension=4, type=Majorana);
    \Gamma_{#}::GammaMatrix(metric=\delta);
    ex:= \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e_{m}^{\mu} e_{n}^{\nu} e_{p}^{\rho} + Q;
    pat:= \bar{D_{\mu}{\epsilon}} A??;
    sort_product(_)
    take_match(ex, pat)
    tst:= \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e_{m}^{\mu} e_{n}^{\nu} e_{p}^{\rho} - @(ex);
    assert(tst==0)
    print("Test 116 passed")

test116()

def test117():
    __cdbkernel__=create_scope()
    ex:= s A_{s};
    substitute(ex, $s -> 1$)
    tst:= A_{s} - @(ex);
    assert(tst==0)
    print("Test 117a passed")
    {p,q,r,s,t,u,v,w}::Indices.
    ex := s**2 y^{r} y^{s} A_{r s};
    substitute(ex, $s->1$)
    tst:= y^{r} y^{s} A_{r s} - @(ex);
    assert(tst==0)
    print("Test 117b passed")

test117()

def test118():
    __cdbkernel__=create_scope()
    ex:= s A_{s};
    substitute(ex, $_{s} -> _{1}$)
    tst:= s A_{1} - @(ex);
    assert(tst==0)
    print("Test 118 passed")

test118()

def test119():
    __cdbkernel__=create_scope()
    {a,b,c,d,e,f}::Indices(spinor);
    {m,n,p,q}::Indices(spacetime);
    \theta^{a}::SelfAntiCommuting;
    ex:=\theta^{a} \sigma^{m}_{a b} \theta^{b} \tau^{n c d} \sigma^{p}_{d e} \theta^{e} \theta^{f};
    rl:=\theta^{a} \theta^{b} \theta^{c} \sigma^{m}_{c d} \theta^{d} -> \tau^{m a b};
    substitute(ex, rl)
    tst:= \tau^{n c d} \sigma^{p}_{d e} \tau^{m e f} - @(ex);
    assert(tst==0)
    print("Test 119 passed")

test119()

def test120():
    __cdbkernel__=create_scope()
    {a,b,c,d,e,f}::Indices(spinor);
    {m,n,p,q}::Indices(spacetime);
    \theta^{a}::SelfAntiCommuting;
    ex:=\theta^{b} \sigma^{m}_{a b} \theta^{a} \tau^{n c d} \sigma^{p}_{d e} \theta^{e} \theta^{f};
    rl:=\theta^{a} \theta^{b} \theta^{c} \sigma^{m}_{c d} \theta^{d} -> \tau^{m a b};
    substitute(ex, rl)
    tst:= -\tau^{n c d} \sigma^{p}_{d e} \tau^{m e f} - @(ex);
    assert(tst==0)
    print("Test 120 passed")

test120()

def test121():
    __cdbkernel__=create_scope()
    {\dagger}::Symbol.
    {a,n,\sigma,\tau}::Symbol;
    {\Gamma^{\dagger}_{\tau?}, N_{a? \tau?}, G_{n? \sigma?}}::NonCommuting.
    {\Gamma^{\dagger}_{\tau?}, N_{a? \tau?}}::Depends(\commutator{#});
    rule:= N_{a? \tau?} G_{n?? \sigma?} -> n?? G_{(n??-1) \sigma?}
             \commutator{N_{a? \tau?}}{\Gamma^{\dagger}_{\sigma?}}
           + 1/2 n?? (n??-1)
              \commutator{\commutator{N_{a? \tau?}}{\Gamma^{\dagger}_{\sigma?}}}{\Gamma^{\dagger}_{\sigma?}} G_{(n??-2) \sigma?};
    ex:=N_{a \tau} G_{{n-1} \sigma};
    substitute(_,rule)
    tst:= (n-1) G_{{n-2} \sigma} \commutator{ N_{a \tau} }{ \Gamma^{\dagger}_{\sigma} } +
          1/2 (n-1) (n-2) \commutator{ \commutator{ N_{a \tau} }{ \Gamma^{\dagger}_{\sigma} }}{ \Gamma^{\dagger}_{\sigma} } G_{{n-3} \sigma} - @(ex);
    assert(tst==0)
    print("Test 121 passed")

test121()

def test122():        
    __cdbkernel__=create_scope()
    ex:= L_{0 1} + L_{4 5};
    rl:= L_{a? b?} | a? > 3 -> Q_{a? b?};
    substitute(ex, rl)
    tst:= L_{0 1} + Q_{4 5} - @(ex);
    assert(tst==0)
    print("Test 122 passed")

test122()

def test123():
    __cdbkernel__=create_scope()
    {A, B, C, D, E, F}::NonCommuting;
    ex:= A B C D E F + B C A D E F;
    substitute(_, $C D E -> Q$)
    tst:= A B F + B C A D E F - @(ex);
    assert(tst==0)
    print("Test 123a passed")        
    ex:= A B C D E F + B C A D E F;
    substitute(_, $C D E -> Q$, partial=False)
    tst:= A B C D E F + B C A D E F - @(ex);
    assert(tst==0)
    print("Test 123b passed")
    ex:= A + B + C + D;
    substitute(_, $A + C = Q$);
    tst:= Q + B + D - @(ex);
    assert(tst==0)
    print("Test 123c passed")
    ex:= A + B + C + D;
    substitute(_, $A + C = Q$, partial=False);
    tst:= A + B + C + D - @(ex);
    assert(tst==0)
    print("Test 123d passed")

#test123()
        
# substitute(_, $A C?* F -> F A B C?* $, partial=False);        

def test124():
    __cdbkernel__=create_scope()
    \dot{#}::Accent;
    {\dot{\alpha}, \dot{\beta}, \dot{\gamma}, \dot{\delta}}::Indices(spinor, position=fixed);
    {\dot{\alpha}, \dot{\beta}, \dot{\gamma}, \dot{\delta}}::Integer(1..2);
    \nabla{#}::Derivative;
    ex:=\nabla^{\dot{\gamma}}(\theta^{\dot{\alpha}}) \theta_{\dot{\alpha}};
    substitute(_, $\nabla^{\dot{\alpha}}{\theta^{\dot{\beta}}} -> \epsilon^{\dot{\beta} \dot{\alpha}}$)
    tst:= \epsilon^{\dot{\alpha} \dot{\gamma}} \theta_{\dot{\alpha}} - @(ex);
    assert(tst==0)
    print("Test 124 passed")

test124()

def test125():
    __cdbkernel__=create_scope()
    ex:=T_{A};
    substitute(ex, $T{A?} = Q$)
    try:
        tst:= T_{A} - @(ex);
        assert(tst==0)
        print("Test 125a passed")
    except:
        assert(False)
    
    ex:=T{A};
    substitute(ex, $T_{A?} = Q$)
    try:
        tst:= T{A} - @(ex);
        assert(tst==0)
        print("Test 125b passed")
    except:
        assert(False)

test125()

# \del{#}::LaTeXForm("\partial").
# ex:=\del_{m}{A};
# res=ex._latex_()
#     
# ex:=A_{m}(x);
# substitute(ex, $A{#}->Q$);
#         
# \hat{R}_{a b c d}
# R(x,y)

def test126():
    # Inside powers, dummies can be repeated.
    __cdbkernel__=create_scope()
    {n,m,p,q}::Indices;
    ex:= A^{n} / (A^{m} A^{m});
    rename_dummies(ex)
    tst:= A^{n} / (A^{n} A^{n}) - @(ex);
    assert(tst==0)
    print("Test 126 passed")

test126()
        
def test127():
    # Expect an exception when substituting with empty rule.
    __cdbkernel__=create_scope()
    ex:= A + B;
    try:
        substitute(ex, $ $);
        assert(False)
    except Exception:
        print("Test 127a passed")
    try:
        substitute(ex, ${ }$)
        assert(1==0)
    except Exception:
        print("Test 127b passed")
    
test127()

def test128():
    # FIXME: adding create_scope here makes things fail, why?
    # __cdbkernel__=create_scope()
    a::Symbol;
    b::Symbol;
    
    {a**m?, b**n?, a, b}::NonCommuting;
    
    r1 := {
    a b**m?  -> (1+b a) b**{m?-1},
    a b -> 1 + b a,
    };
    
    def act(ex):
        converge(ex):
            substitute(ex,r1)
            distribute(ex)
            collect_factors(ex)
            print(ex)
        return ex
    
    ex:=a b**5;
    act(ex);
    tst:= 5 b**4 + b**5 a - @(ex);
    assert(tst==0)
    print("Test 128 passed")

test128()
