def test06():
    __cdbkernel__=create_scope()
    {X,G,Y,A,B}::SortOrder.
    {X,A}::AntiCommuting.
    obj6:= A B G X A X;
    sort_product(obj6)
    tst6:= X X G A A B + @(obj6);
    collect_terms(_)
    assert(tst6==0)
    print('test06 passed')

test06()

def test07():
    __cdbkernel__=create_scope()
    {X,G,Y,A,B}::SortOrder.
    {X,A}::NonCommuting.
    obj7:= A*B*G*X*A*X;
    sort_product(_)
    tst7:= G A X A X B - @(obj7);
    collect_terms(_)
    assert(tst7==0)
    print('test07 passed')

test07()

def test08():
    __cdbkernel__=create_scope()
    { W_{m n}, W_{m} }::SortOrder.
    { W_{m n}, W_{m} }::AntiCommuting.
    obj8:= W_{m n} W_{p} W_{q r} W_{s} W_{t};
    sort_product(_)
    tst8:= - W_{m n} W_{q r} W_{p} W_{s} W_{t} - @(obj8);
    collect_terms(_)
    assert(tst8==0)
    print('test08 passed')

test08()

def test09():
    __cdbkernel__=create_scope()
    { \theta_a, \theta_b }::SelfAntiCommuting.
    obj9:= \theta_c \theta_b \theta_a;
    sort_product(_)
    tst9:= \theta_a \theta_b \theta_c + @(obj9);
    assert(tst9==0)
    print('test09 passed')

test09()

def test10():
    __cdbkernel__=create_scope()
    {a,b,c,d}::Indices.
    { \theta_a, \chi_a }::Commuting.
    {\theta_{a}, \theta_{b}}::SelfAntiCommuting.
    {\chi_{a},\chi_{b}}::SelfAntiCommuting.
    { \theta_a, \chi_a }::SortOrder.
    obj10:= \theta_c \theta_b \theta_d \chi_d \theta_a \chi_a;
    sort_product(_)
    tst10:= \theta_a \theta_b \theta_c \theta_d \chi_a \chi_d + @(obj10);
    assert(tst10==0)
    print('test10 passed')

test10()

def test12():
    __cdbkernel__=create_scope()
    \bar{#}::Accent.
    {D,K,B,A}::SortOrder.
    obj12:= A \bar{B} \bar{K} D;
    sort_product(_)
    tst12:= D \bar{K} \bar{B} A - @(obj12);
    collect_terms(_)
    assert(tst12==0)
    print('test12 passed')

test12()

def test16():
    __cdbkernel__=create_scope()
    {A_\mu, B_\mu}::AntiCommuting.
    \diff{#}::Derivative.
    obj16:= \diff{B_\mu}_{\nu} * \diff{A_\rho}_{\sigma};
    sort_product(_)
    tst16:= \diff{A_\rho}_{\sigma} * \diff{B_\mu}_{\nu} + @(obj16);
    collect_terms(_)
    assert(tst16==0)
    print('test16 passed')

test16()

def test16b():
    __cdbkernel__=create_scope()
    ex:= C A D B;
    sort_product(_);
    tst:= A B C D - @(ex);
    assert(tst==0)
    print("Test 16b passed")

def test17():
    __cdbkernel__=create_scope()
    \Gamma{#}::GammaMatrix.
    obj17a:= (\Gamma_{m n} + A_{m} \Gamma_{n})\Gamma_{p q r};
    sort_product(_)
    tst17a:= (\Gamma_{m n} + A_{m} \Gamma_{n})\Gamma_{p q r} - @(obj17a);
    assert(tst17a==0)
    obj17b:= \Gamma_{p q r} (\Gamma_{m n} + A_{m} \Gamma_{n});
    sort_product(_)
    tst17b:= \Gamma_{p q r} (\Gamma_{m n} + A_{m} \Gamma_{n}) - @(obj17b);
    assert(tst17b==0)
    print('test17 passed')

test17()

def test18():
    __cdbkernel__=create_scope()
    {\psi, \chi}::Spinor.
    {\psi, \chi, \Gamma_{#}}::NonCommuting.
    \Gamma_{#}::GammaMatrix.
    {\chi,\psi}::SortOrder.
    \bar{#}::Accent.
    obj18:= \bar{\psi} \Gamma_{m n p} \chi;
    sort_product(_)
    tst18:= \bar{\psi} \Gamma_{m n p} \chi - @(obj18);
    collect_terms(_)
    assert(tst18==0)
    print('test18 passed')

test18()

def test22():
    __cdbkernel__=create_scope()
    {\chi, \psi}::Weight(label=grassmann, value=1).
    tst22a:= \chi \psi \chi;
    #drop_weight(_, grassmann=3)

test22()

def test23():
    __cdbkernel__=create_scope()
    \nabla{#}::Derivative.
    ex:=\nabla_{i}{ C D E };
    substitute(_, $D->0$)
    assert(ex==0)
    print("Test 23 passed")
    
test23()

def test24():
    __cdbkernel__=create_scope()
    {s,r,l,k,m,n}::Indices(vector).
    {s,r,l,k,m,n}::Integer(0..d-1).
    \Gamma{#}::GammaMatrix(metric=\delta).
    \delta_{m n}::KroneckerDelta.
    obj:= \Gamma_{l r} \Gamma_{k s} q \Gamma_{r s} + \Gamma_{l r} d \Gamma_{k s} \Gamma_{r s};
    sort_product(_)
    tst:= \Gamma_{l r} \Gamma_{k s} \Gamma_{r s} q + \Gamma_{l r} \Gamma_{k s} \Gamma_{r s} d - @(obj);
    assert(tst==0)
    print('Test 24 passed')

test24()

def test25():
    __cdbkernel__=create_scope()
    ex:=(a*d+b)*c;
    distribute(_)
    tst:= a d c + b c - @(ex);
    assert(tst==0)
    print('Test 25 passed')

test25()

def test26():
    __cdbkernel__=create_scope()
    # This example shows that indices can match to integers
    # provided you declare them a such. You need to declare
    # m,n as Symbol otherwise you cannot write one term with
    # an 'n' index and another one with a '-n' index.
    {m,n}::Integer.
    {m,n}::Symbol.
    ex:= a_{1} a_{0} a_{-1};
    rl:= a_{n} a_{m} = a_{m} a_{n} + m \delta_{m}_{-n};
    substitute(ex, rl)
    tst:= a_{0} a_{1} a_{-1} - @(ex);
    assert(tst==0)
    print("Test 26 passed")
    
test26()

def test27():
    __cdbkernel__=create_scope()
    ex:=A;
    ex2:= @(ex)^{\mu\nu};
    tst:=A^{\mu\nu} - @(ex2);
    assert(tst==0)
    print("Test 27 passed")

test27()

def test28():
    __cdbkernel__=create_scope()
    ex:=A+B;
    ex2:= @(ex)^{\mu\nu};
    tst:=(A+B)^{\mu\nu} - @(ex2);
    assert(tst==0)
    print("Test 28 passed")

test28()

# def post_process(ex):
# 	sort_product(ex)
# 	#canonicalise(ex)
# 	collect_terms(ex)

{\mu,\nu,\rho}::Indices(position=free).
x::Coordinate.
\partial{#}::Derivative.

F_{\mu\nu}::AntiSymmetric.
F_{\mu\nu}::Depends(x).
A_{\mu}::Depends(x,\partial{#}).
\delta{#}::Accent.

S:= -1/4 \int{ F_{\mu\nu} F^{\mu\nu} }{x};
rl:= F_{\mu\nu} = \partial_{\mu}{A_{\nu}} - \partial_{\nu}{A_{\mu}};
substitute(S, rl);
vary(S, $A_{\mu} -> \delta{A_{\mu}}$);
distribute(S);


def test30():
    __cdbkernel__=create_scope()
    # Matching of numerical values in expressions to indices in patterns
    # should respect index position.
    {m,n}::Indices(position=fixed);
    {m,n}::Integer(0..3).
    g_{m}^{n}::KroneckerDelta;
    ex:= g^{0 0};
    ex:= 1 + g_{0}^{0};
    ex:= g^{0 0} + g_{0}^{0};
    substitute(_, $g^{a? b?} -> h^{a? b?}$)
    tst:= h^{0 0} + 1 - @(ex);
    assert(tst==0)

test30()


def test31():
    __cdbkernel__=create_scope()
    {m,n}::Indices(position=fixed);
    {m,n}::Integer(0..3).
    g_{m}^{n}::KroneckerDelta;
    g_{m n}::Metric;
    ex:= g_{0 0} + g_{0}^{0};
    substitute(_, $g_{m n} = h_{m n}$)
    tst:= h_{0 0} + 1 - @(ex);
    assert(tst==0)
    print("Test 31 passed")

test31()

def test32():
    __cdbkernel__=create_scope()
    {m,n}::Indices(position=fixed);
    ex1:= A_{m} A^{m};
    try:
        ex2:= A_{m} A_{m};
        assert(1==0)
    except:
        print('Test 32 passed')

test32()

def test33():
    __cdbkernel__=create_scope()
    {m,n}::Indices(position=fixed);
    try:
        ex:= A_{m n} + A_{m};
        assert(1==0)
    except:
        print('Test 33 passed')

test33()

def test34():
    __cdbkernel__=create_scope()
    {m,n}::Indices(position=fixed);
    try:
        ex:= A_{m n} A^{m} B_{m};
        assert(1==0)
    except:
        print('Test 34 passed')

test34()

def test35():
    __cdbkernel__=create_scope()
    {\del{#}, \delbar{#}}::PartialDerivative.
    {\Psi_{\mu}, \Psibar_{\mu}, \eps, \epsbar}::AntiCommuting;
    {\Psi_{\mu}, \Psibar_{\mu}}::SelfAntiCommuting;
    {\Psi_{\mu}, \Psibar_{\mu}, X_{\mu}}::Depends(\del{#}, \delbar{#});
    {i, \Psi_\mu, \Psibar_\mu, \eps, \epsbar, X_\mu}::SortOrder;
    ex:= i\epsbar\del{\Psi_{\mu}} \delbar{X_{\mu}};
    sort_product(_)
    tst:= -i\del{\Psi_{\mu}} \epsbar \delbar{X_{\mu}} - @(ex);
    assert(tst==0)
    print("Test 35 passed")
    
test35()

def test36():
    __cdbkernel__=create_scope()
    {a,b,c,d,e}::Indices;
    x^{a}::Weight(label=field);
    ex:= x^{a} + A_{b} x^{a} x^{b} + A_{b c} x^{a} x^{b} x^{c};
    keep_weight(_, $field=2$);
    tst:= A_{b} x^{a} x^{b} - @(ex);
    assert(tst==0)
    print("Test 36 passed")

test36()

def test37():
    __cdbkernel__=create_scope()
    {a,b,c,d,e}::Indices;
    x1^{a}::Weight(label=field);
    ex:= x1^{a} + A_{b} x1^{a} x1^{b} + A_{b c} x1^{a} x1^{b} x1^{c};
    keep_weight(_, $field=2$);
    tst:= A_{b} x1^{a} x1^{b} - @(ex);
    assert(tst==0)
    print("Test 37 passed")

test37()

def test38():
    __cdbkernel__=create_scope()
    ex1:= a+b = c+e;
    ex2:= g+h = c;
    ex:= 3 @(ex1) - 2 @(ex2);
    assert(lhs(ex)==$3a + 3b - 2g - 2h$)
    assert(rhs(ex)==$c + 3e$)
    print("Test 38 passed")

test38()

def test39():
    __cdbkernel__=create_scope()
    A#_{a b c}::AntiSymmetric;
    tst:=A1_{a b c} + A1_{a c b};
    canonicalise(_)
    assert(tst==0)
    print("Test 39 passed")

test39()
        
def test40():
    __cdbkernel__=create_scope()
    {a,b,c,d,e,f,g,h}::Indices(position=independent);
    T#^{a b c}_{e f}::TableauSymmetry(shape={1,1}, indices={3,4});
    ex:=T1^{a b c}_{e f} T2^{e f g}_{h i} - T1^{a b c}_{e f} T2^{f e g}_{h i};
    canonicalise(ex)
    tst:=2 T1^{a b c}_{e f} T2^{e f g}_{h i} - @(ex);
    assert(tst==0)
    print("Test 40 passed")

test40()

def test41():
    __cdbkernel__=create_scope()
    ex:= -a**2;
    substitute(ex, $a -> -b$)
    tst:= -b**2 - @(ex);
    assert(tst==0)
    print("Test 41 passed")

test41()

