
def test01():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(spacetime, position=fixed);
    {a,b,c,d,e,f,g,h}::Indices(spinor, position=fixed);
    \sigma^{p}::ImplicitIndex(\sigma^{p a}_{b});
    \psi::ImplicitIndex(\psi_{a});
    \chi::ImplicitIndex(\chi^{a});
    ex:= \psi \sigma^{m} \sigma^{n} \chi \lambda^{a} + 1/2 \lambda_{b} \chi^{b} T^{m n}\chi^{a};
    explicit_indices(_)
    tst:= \psi_{c} \sigma^{m c}_{d} \sigma^{n d}_{e} \chi^{e} \lambda^{a} + 1/2 \lambda_{b} \chi^{b} T^{m n}\chi^{a} - @(ex);
    assert(tst==0)
    print("Test 01a passed")
    ex:= \psi \sigma^{m} \chi;
    explicit_indices(_)
    tst:= \psi_{a} \sigma^{m a}_{b} \chi^{b} - @(ex);
    assert(tst==0)
    print("Test 01b passed")

test01()

def test02():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(spacetime, position=fixed);
    {a,b,c,d,e,f,g,h}::Indices(spinor, position=fixed);
    \sigma^{p}::ImplicitIndex(\sigma^{p a}_{b});
    \psi::ImplicitIndex(\psi_{a});
    \chi::ImplicitIndex(\chi^{a});
    \partial{#}::PartialDerivative;
    ex:= \psi \sigma^{m} \sigma^{n} \partial_{n}{\chi} \lambda^{a} + \lambda_{b} \chi^{b} T^{m}\chi^{a};
    explicit_indices(_)
    tst:= \psi_{c} \sigma^{m c}_{d} \sigma^{n d}_{e} \partial_{n}{\chi^{e}} \lambda^{a} + \lambda_{b} \chi^{b} T^{m}\chi^{a} - @(ex);
    assert(tst==0)
    print("Test 02 passed")

test02()

def test03():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(spacetime, position=fixed);
    {a,b,c,d,e,f,g,h}::Indices(spinor, position=fixed);
    \sigma^{p}::ImplicitIndex(\sigma^{p a}_{b});
    \psi::ImplicitIndex(\psi_{a});
    \chi::ImplicitIndex(\chi^{a});
    ex:= 2 \sigma^{m} \chi \psi \sigma^{n} \chi;
    explicit_indices(_)
    tst:= 2 \sigma^{m a}_{b} \chi^{b} \psi_{c} \sigma^{n c}_{d} \chi^{d} - @(ex);
    assert(tst==0)
    print("Test 03 passed")
        
test03()

def test04():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(spacetime, position=fixed);
    {a,b,c,d,e,f,g,h}::Indices(spinor, position=fixed);
    \sigma^{p}::ImplicitIndex(\sigma^{p}_{a b});
    \tau^{p}::ImplicitIndex(\tau^{p a b});        
    Tr{#}::Trace(indices=spinor);
    ex:= Tr( \sigma^{m} \tau^{n} );
    explicit_indices(_)
    tst:= \sigma^{m}_{a b} \tau^{n b a} - @(ex);
    assert(tst==0)
    print("Test 04 passed")
        
test04()
        
def test05():
    __cdbkernel__=create_scope()
    {m,n,p}::Indices(spacetime, position=fixed);
    {a,b,c,d,e,f,g,h}::Indices(spinor, position=fixed);
    \sigma^{p}::ImplicitIndex(\sigma^{p}_{a b});
    \tau^{p}::ImplicitIndex(\tau^{p a b});        
    Tr{#}::Trace(indices=spinor);
    ex:= 1/3 Tr( \sigma^{m} \tau^{n} + \tau^{n} \sigma^{m} );
    explicit_indices(_)
    tst:= 1/3 \sigma^{m}_{a b} \tau^{n b a} + 1/3 \tau^{n a b} \sigma^{m}_{b a} - @(ex);
    assert(tst==0)
    print("Test 05 passed")
        
test05()

# A more complicated example for the pattern matcher,
# matching indices to index values, both symbolically
# and numerically.        
def test06():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;
    {\mu,\nu}::Indices(spacetime, values={r,t});
    {a,b,c,d}::Indices(group, values={0,1});
    \partial{#}::PartialDerivative;
    ex:= \partial_{\mu}(A_{a b}) \partial_{\mu}(A_{b a});
    A_{a b}::Depends(r,t);
    {q1,q2}::Depends(r,t);
    rl:= { A_{0 0} = q1, A_{1 1} = q2 };
    evaluate(ex, rl, simplify=False)
    tst:= \partial_{t}{q1} \partial_{t}{q1}
         +\partial_{r}{q1} \partial_{r}{q1}
         +\partial_{t}{q2} \partial_{t}{q2}
         +\partial_{r}{q2} \partial_{r}{q2}
         - @(ex);
    assert(tst==0)
    print("Test 06 passed")
        
test06()
        
def test07():
    __cdbkernel__=create_scope()
    {r,t,v,w}::Coordinate;
    {\mu,\nu}::Indices(spacetime, values={r,t});
    {a,b,c,d}::Indices(group, values={v,w});
    \partial{#}::PartialDerivative;
    ex:= \partial_{\mu}(A_{a b}) \partial_{\mu}(A_{b a});
    A_{a b}::Depends(r,t);
    evaluate(ex, simplify=False)
    tst:=\partial_{t}(A_{w w}) \partial_{t}(A_{w w}) + \partial_{r}(A_{w w}) \partial_{r}(A_{w w}) + \partial_{t}(A_{v w}) \partial_{t}(A_{w v}) + \partial_{r}(A_{v w}) \partial_{r}(A_{w v}) + \partial_{t}(A_{w v}) \partial_{t}(A_{v w}) + \partial_{r}(A_{w v}) \partial_{r}(A_{v w}) + \partial_{t}(A_{v v}) \partial_{t}(A_{v v}) + \partial_{r}(A_{v v}) \partial_{r}(A_{v v}) - @(ex);
    assert(tst==0)
    print("Test 07 passed")

test07()
        
def test08():
    __cdbkernel__=create_scope()
    {a,b,c,d}::Indices(vector).
    tr{#}::Trace(indices=vector).
    A::ImplicitIndex(A_{a b}).
    B::ImplicitIndex(B_{a b}).
    C::ImplicitIndex(C_{a b}).
    D::ImplicitIndex(D_{a b}).
    ex:=tr(c A B) tr(C D);
    explicit_indices(_);
    tst:= c A_{a b} B_{b a} C_{c d} D_{d c} - @(ex);
    print("Test 08 passed")

test08()
    
    
# The original question:
    
# Tr{#}::Trace;
# {\mu,\nu}::Indices(spacetime, values={0,1,2,3});
# #, position=fixed);
# {r,t}::Coordinate;
# {a,b,c,d}::Indices(group, values={r,t});
# A::ImplicitIndex(A_{a b});
# \partial{#}::PartialDerivative;
# A::Depends(\partial{#});
# ex:= Tr( \partial_{\mu}{A} \partial^{\mu}{A} );
# explicit_indices(_);
# A_{a b}::Depends(r,t);
# #\partial{#});
# #{q1, q2}::Depends(\partial{#});
# # \mu
# rl:= { A_{r r} = q1, A_{t t} = q2 };
# evaluate(ex, simplify=False);    
# evaluate(ex, rl, simplify=False);
# tst:= \partial_{\mu}{q1} \partial^{\mu}{q1} + \partial_{\mu}{q2} \partial^{\mu}{q2} - @(ex);
# assert(tst==0)
# print("Test 06 passed")
    



#ex:= \chi \psi \sigma^{n} \chi;
#explicit_indices(_);
        
# Normally index contraction aims for adjacent indices.
# With 'eager=True', contractions are generated as much
# as possible, even if that does not lead to adjacent indices.


# 
# {m,n,p}::Indices(spacetime, position=fixed);
# {a,b,c,d,e,f,g,h}::Indices(spinor, position=fixed);
# \sigma^{p}::ImplicitIndex(\sigma^{p}_{a b});
# \tau^{p}::ImplicitIndex(\tau^{p a b});
# \theta::ImplicitIndex(\theta^{a});
# 
# ex := \sigma^{p} \theta \tau^{m};
# tst:= \sigma^{p}_{a b} \theta^{b} \tau^{m a c};
#         

# The `combine` algorithm puts objects in the
# wrong order!
{A^{a \alpha}, B^{b}_{\alpha}}::NonCommuting;
A^{a}::ImplicitIndex(A^{a \alpha});
B^{b}::ImplicitIndex(B^{b}_{\alpha});
ex:=(A^a)^\alpha (B^b)_{\alpha};
print(tree(ex))
combine(ex);
