# The scalar backend used for these component tests can be switched
# using either one of
#
# kernel(scalar_backend="sympy")

# Testing a substitution rule in which an abstract index in the 
# expression is matched against a coordinate in the pattern.
# FIXME: this is not supposed to match!
# {m,n,p}::Indices(values={t,r}).
# {r,t}::Coordinate.
# ex:= A_{m n} + B_{m n};
# rl:= A_{t r} + B_{t r} = 3;
# substitute(ex, rl)

def test01():
    __cdbkernel__=create_scope()
    print(__cdbkernel__.scalar_backend)
    {r,t}::Coordinate.
    {m,n}::Indices(values={t,r}, position=fixed).
    ex:= A_{m};
    rl:= A_{t} = 3;
    evaluate(ex, rl, simplify=True)
    tst:= \components_{m}( \comma{ \comma{t} = 3  } ) - @(ex);
    collect_components(_)
    assert(tst==0)
    print("Test 01 passed")

test01()

def test02():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate.
    {m,n,p,s}::Indices(values={t,r}, position=free).
    C::Depends(r,t).
    ex:= A_{n m} B_{m n p} ( C_{p s} + D_{s p} );
    rl:= [ A_{r t} = 3, B_{t r t} = 2, B_{t r r} = 5, C_{t r} = 1, D_{r t} = r**2*t, D_{t r}=t**2 ];
    evaluate(ex, rl)
    tst:= \components_{s}{\comma{r}= 6 r**2 t + 6, \comma{t}=15 t**2} - @(ex):
    collect_components(_)
    assert(tst==0)
    print("Test 02 passed")

test02()


# Riemann curvature example.

def test03():
    __cdbkernel__=create_scope()
    {r,t,\phi,\theta}::Coordinate.
    {\mu,\nu,\rho,\sigma,\lambda,\kappa,\gamma,\chi}::Indices(values={t,r,\phi,\theta}, position=fixed).
    \partial{#}::PartialDerivative.
    g_{\mu\nu}::Metric.
    g^{\mu\nu}::InverseMetric.         
    ss:= { g_{t t} = -(1-2 M/r),  g_{r r} = 1/(1-2 M/r),
           g_{\theta\theta} = r**2,  g_{\phi\phi}=r**2 \sin(\theta)**2 };
    complete(ss, $g^{\mu\nu}$)
    ch:= \Gamma^{\mu}_{\nu\rho} = 1/2 g^{\mu\sigma} ( \partial_{\rho}{g_{\nu\sigma}}
                                                +\partial_{\nu}{g_{\rho\sigma}}
                                                -\partial_{\sigma}{g_{\nu\rho}} );
    evaluate(ch, ss, rhsonly=True)
    chtst=rhs(ch)
        # Check against e.g. arxiv:0904.4184.
    tst:=\components^{\mu}_{\nu\rho}{ {t,r,t}          =  M/r**2 (1-2 M/r)**(-1),
                                {t,t,r}            =  M/r**2 (1-2 M/r)**(-1),
                                {r,r,r}            = -M/r**2 (1-2 M/r)**(-1),
                                {r,t,t}            =  M/r**2 (1-2 M/r),
                                {r,\theta,\theta}  = -r (1-2M/r),
                                {r,\phi,\phi}      = - (r-2M) \sin(\theta)**2,
                                {\theta,\theta,r}  = 1/r,
                                {\theta,r,\theta}  = 1/r,
                                {\phi,\phi,r}      = 1/r,
                                {\phi,r,\phi}      = 1/r,
                                {\theta,\phi,\phi} = -\sin(\theta)\cos(\theta),
                                {\phi,\theta,\phi} = \cos(\theta)/\sin(\theta),
                                {\phi,\phi,\theta} = \cos(\theta)/\sin(\theta)
                            } - @(chtst);
    collect_components(_)
    assert(tst==0)
    print("Test 03a passed")
    
    rm:= R^{\rho}_{\sigma\mu\nu} = \partial_{\mu}{\Gamma^{\rho}_{\nu\sigma}}
                              -\partial_{\nu}{\Gamma^{\rho}_{\mu\sigma}}
                              +\Gamma^{\rho}_{\mu\lambda} \Gamma^{\lambda}_{\nu\sigma}
                              -\Gamma^{\rho}_{\nu\lambda} \Gamma^{\lambda}_{\mu\sigma};

    substitute(rm, ch)
    evaluate(rm, ss, rhsonly=True)
    
    # The Ricci tensor should be zero.
    rc:= R_{\sigma\nu} = R^{\rho}_{\sigma\rho\nu};
    substitute(rc, rm)
    evaluate(rc, ss, rhsonly=True)
    assert(rhs(rc)==0)
    print("Test 03b passed")
    
    # Finally, the Kretschmann scalar.
    K:= K = R^{\mu}_{\nu\rho\sigma} R^{\lambda}_{\kappa\gamma\chi} g_{\mu\lambda} g^{\nu\kappa} g^{\rho\gamma} g^{\sigma\chi};
    substitute(K, rm)
    evaluate(K, ss)
    tmp=rhs(K)
    tst:= 48 M**2/r**6 - @(tmp);
    simplify(tst)
    assert(tst==0)
    print("Test 03 passed")
    
test03()
    
def test04():
    __cdbkernel__=create_scope()
    {r,t,\theta,\phi}::Coordinate.
    {m,n,p,q}::Indices(position=fixed,values={t,r,\theta,\phi}).
    rl:= { X^{t} -> X^{t}, g_{t t}=-1, g_{r r}=3 };
    ex:= g_{m n} X^{n};
    evaluate(ex, rl)
    tst:= \components_{m}{ \comma{ \comma{t} = -X^{t} } } - @(ex);
    collect_components(_)
    assert(tst==0)
    print("Test 04 passed")

test04()

# Component computations leading to a scalar.

def test05():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate.
    {m,n,p}::Indices(values={r,t}).
    ex:= A_{m n}*A_{m n};
    ss:= { A_{r r} -> a+b, A_{r t} -> b, A_{t t} -> c, A_{r r t}->3, A_{t t t}->c };
    evaluate(ex, ss)
    tst:= (a+b)**2+b**2+c**2  - @(ex);
    assert(tst==0)
    print("Test 05 passed")

test05()

# The following test components of tensor outer products. The first one
# leads to a scalar multiplying the components tensor.

def test06():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate.
    {m,n}::Indices(values={t,r}).
    ex:= g_{m n} X^{n} A;
    rl:= { X^{t} -> X^{t}, g_{t t}=1, g_{r r}=3 };
    evaluate(ex,rl)
    tst:= \components_{m}{ \comma{ \comma{t}= A X^{t} } } - @(ex);
    collect_components(_)
    assert(tst==0)
    print("Test 06 passed")

test06()

 
# The second one is manifestly an outer product.

def test07():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate.
    {m,n,p}::Indices(values={t,r}).
    ex:= X^{n} X^{m} X^{p};
    rl:= { X^{t} -> T, X^{r} -> R };
    evaluate(ex,rl)
    tst:=\components^{n m p}{ {t,t,t}=T**3, {t,t,r}=R T**2, {t,r,t}=R T**2,
                            {t,r,r}=T R**2, {r,t,t}=R T**2, {r,t,r}=T R**2,
                            {r,r,t}=R**2 T, {r,r,r}=R**3 } - @(ex);
    collect_components(tst)
    assert(tst==0)
    print("Test 07 passed")

test07()                          

# More GR stuff.
# {\mu,\nu,\rho,\sigma}::Indices(position=fixed).
# \partial{#}::PartialDerivative.
# ex:= R^{\mu}_{\nu\rho\sigma};
# rl:= { R^{\mu}_{\nu\rho\sigma} -> \partial_{\rho}{\Gamma^{\mu}_{\nu\sigma}},
#         \Gamma^{\mu}_{\nu\rho} = 1/2 g^{\mu\sigma} ( \partial_{\rho}{g_{\nu\sigma}}
#                                                  +\partial_{\nu}{g_{\rho\sigma}}
#                                                  -\partial_{\sigma}{g_{\nu\rho}} )
#                                                   };
# substitute(ex, rl, repeat=True);                                                  


# -------------------------------------------

# This one does not yet work, and might be better served with a split-index
# first.
# {r,t,\phi,\theta}::Coordinate.
# {m,n}::Indices("full",values={t,r,\phi,\theta}).
# {i,j}::Indices("3d", parent="full").
# ex:= A_{m n}+A_{n m};
# rl:= { A_{t t} -> 3, A_{i j} -> \delta_{i j} };
# evaluate(ex, rl);

# Self-contracted tensors.

def test08():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate.
    {m,n,p}::Indices(values={r,t})
    ex:= A_{n}^{n} A_{m}^{m};
    rl:= { A_{t}^{r} -> S, A_{t}^{t} -> 3, A_{r}^{r} -> r };
    evaluate(ex, rl)
    tst:= (r+3)**2 - @(ex);
    simplify(tst)
    assert(tst==0)
    print("Test 08 passed")

test08()

def test09():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate.
    {m,n,p}::Indices(values={r,t})
    ex:= A_{m}^{m};
    rl:= { A_{t}^{r} -> S, A_{t}^{t} -> 3, A_{r}^{r} -> r };
    evaluate(ex, rl)
    tst:= r+3 - @(ex);
    assert(tst==0)
    print("Test 09 passed")

test09()

def test10():
    __cdbkernel__=create_scope()
    {r,t,\phi}::Coordinate.
    {m,n,p}::Indices(values={r,t,\phi}).
    ex:= A_{n}^{n p} B_{p};
    rl:= A_{r}^{r t} -> a, A_{r}^{r r} -> b, A_{r}^{t t} -> Q1, A_{t}^{r t} -> Q2, A_{t}^{r r} -> Q3,
         A_{t}^{t t}-> c, A_{t}^{t r} -> d, B_{r} -> Br, B_{t} -> Bt;
    evaluate(ex, rl)
    tst:= a Bt + c Bt + b Br + d Br - @(ex);
    assert(sympy.simplify(tst)==0)
    print("Test 10 passed")

test10()

# This does not work when 'Q' is removed.
def test11():
    __cdbkernel__=create_scope()
    {r,t,\phi}::Coordinate;
    {m,n,p}::Indices(values={r,t,\phi});
    ex:= T_{m n} = Q A_{m n};
    rl:= A_{r r} -> r, A_{t t} -> t, A_{r t} -> t r;
    evaluate(ex, rl, rhsonly=True)
    ex2:= T_{m m};
    substitute(ex2, ex)
    evaluate(ex2, rl)
    tst:= Q (r+t) - @(ex2);
    assert(tst==0)
    print("Test 11 passed")

test11()

def test12():
    __cdbkernel__=create_scope()
    {\mu,\nu,\rho,\sigma}::Indices(values={0,1,2,3});
    ex:=A_{\mu} A_{\mu};
    rl:= A_{0} -> -\xi_{0}, A_{1} -> \xi_{1}, A_{2} -> -\xi_{2}, A_{3} -> \xi_{3};
    evaluate(ex, rl)
    tst:= \xi_{0}\xi_{0} + \xi_{1}\xi_{1} + \xi_{2}\xi_{2} + \xi_{3}\xi_{3} - @(ex);
    assert(tst==0)
    print("Test 12 passed")

test12()

def test13():
    __cdbkernel__=create_scope()
    {i,j,k}::Indices(values={1,2,3});
    \epsilon^{i j k}::EpsilonTensor;
    ex:=\epsilon^{i j k};
    evaluate(ex)
    tst:= \components^{i j k}{ {1,2,3}=1, {1,3,2}=-1, {2,1,3}=-1, {2,3,1}=1, {3,1,2}=1, {3,2,1}=-1 } - @(ex);    
    collect_components(tst)
    assert(tst==0)
    print("Test 13 passed")

test13()
        
def test14():        
    __cdbkernel__=create_scope()
    {t,x,y,z}::Coordinate;        
    {\mu,\nu,\rho,\sigma}::Indices(values={t,x,y,z});
    f::Depends({t,x,y,z});
    \partial{#}::PartialDerivative;
    ex:= F^{\mu} \partial_{\mu}{ f };
    rl:= F^{t} = A, F^{x} = B, F^{z} = C;
    evaluate(ex, rl)
    canonicalise(ex)
    tst:= A \partial_{t}{f} + B \partial_{x}{f} + C \partial_{z}{f} - @(ex);
    assert(tst==0)
    print("Test 14 passed")

test14()

def test15():        
    __cdbkernel__=create_scope()
    {t,x,y,z}::Coordinate;        
    {\mu,\nu,\rho,\sigma}::Indices(values={t,x,y,z});
    f::Depends({t,x,y,z});
    \partial{#}::PartialDerivative;
    ex:= F^{\mu\nu} \partial_{\mu \nu}{ f };
    rl:= F^{t x} = A, F^{x y} = B, F^{z x} = C;
    evaluate(ex, rl)
    canonicalise(ex)
    tst:= A \partial_{t x}{f} + B \partial_{x y}{f} + C \partial_{x z}{f} - @(ex);
    assert(tst==0)
    print("Test 15 passed")

test15()

def test16():        
    __cdbkernel__=create_scope()
    {x,y,z}::Coordinate;
    f::Depends({x,y,z});
    \partial{#}::PartialDerivative;
    {i,j,k,l}::Indices(values={x,y,z}, position=free);
    ex:= 2 \partial_{i i}{3 f} + m**2 f;
    evaluate(ex)
    tst:= 6\partial_{x x}{f} + 6\partial_{y y}{f} + 6\partial_{z z}{f} + m**2 f - @(ex);
    assert(tst==0)
    print("Test 16 passed")

test16()
        
def test17():
    __cdbkernel__=create_scope()
    {x,y,z}::Coordinate;
    {i,j,k,l}::Indices(values={x,y,z}, position=free);
    Ax::Depends(y);
    Ay::Depends(z);
    Az::Depends(x);        
    \partial{#}::PartialDerivative;
    ex:= \partial_{i j}{A_{i}} + m**2 A_{j};
    evaluate(ex, $A_x=Ax, A_y=Ay, A_z=Az$)
    tst:= \components_{j}{ \comma{x}=m**2 Ax, \comma{y}=m**2 Ay, \comma{z}=m**2 Az } - @(ex);
    collect_components(tst)
    assert(tst==0)
    print("Test 17 passed")

test17()

def test18():
    __cdbkernel__=create_scope()
    {x,y,z}::Coordinate;
    {i,j,k,l}::Indices(values={x,y,z}, position=free);
    A_{i}::Depends({x,y,z});
    \partial{#}::PartialDerivative;
    ex:= \partial_{i}{A_{j}};
    evaluate(ex, $A_{z}=z$)
    tst:= \components_{j i}( \comma{ {z,z}=1 } ) - @(ex);
    collect_components(tst)
    assert(tst==0)
    print("Test 18 passed")

test18()

def test19():
    __cdbkernel__=create_scope()
    {x,y,z}::Coordinate;
    {i,j,k,l}::Indices(values={x,y,z}, position=free);
    A_{i}::Depends({x,y,z});
    \partial{#}::PartialDerivative;
    ex:= \partial_{i}{A_{i}} + m**2 f;
    evaluate(ex, $A_{z}=\sin{z}$)
    tst:= m**2 f + \cos{z} - @(ex);
    sort_product(_)
    assert(tst==0)
    print("Test 19 passed")

test19()

def test20():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;
    {a,b,c}::Indices(values={r,t});
    \partial{#}::PartialDerivative;
    ex:= A_{a} B_{b} C_{a b};
    rl:= [ A_{r} = 1, A_{t} = q, B_{t} = 2, B_{r} = w, C_{r t} = 3, C_{t r}=5 ];
    evaluate(ex, rl)
    tst:= 6 + 5 q w - @(ex);
    assert(tst==0)
    print("Test 20 passed")

test20()

def test21():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;
    {a,b,c}::Indices(values={r,t});
    \partial{#}::PartialDerivative;
    {f,g}::Depends(r);    
    ex:= A_{a} \partial_{a}{ f / g };
    rl:= { A_{r} = q };
    evaluate(ex, rl)
    tst:= q (- f \partial_{r}{g} + g \partial_{r}{f} )/g**2 - @(ex);
    assert(tst==0)
    print("Test 21 passed")

test21()

def test22():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;
    {a,b,c}::Indices(values={r,t});
    \partial{#}::PartialDerivative;
    {f,g}::Depends(r);    
    ex:= A_{a} \partial_{a}{ f * g };
    rl:= { A_{r} = q };
    evaluate(ex, rl)
    tst:= q ( f \partial_{r}{g} + g\partial_{r}{f} ) - @(ex);
    assert(tst==0)
    print("Test 22 passed")

test22()

def test23():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;        
    {a,b,c}::Indices(values={r,t}, position=fixed);
    \partial{#}::PartialDerivative;
    ex:= \partial^{a}{ A_{a} };
    rl:= A_{r} = r;
    try:
        evaluate(ex, rl);
        assert(1==0)
    except:
        print("Test 23a passed")
    ex:= \partial_{a}{ A^{a} };
    rl:= A^{r} = r;
    evaluate(ex, rl)
    tst:= 1 - @(ex);
    assert(tst==0)
    print("Test 23b passed")
        
test23()
        

# 
# {r,t}::Coordinate.    
# {a,b,c}::Indices(values={r,t});
# \partial{#}::PartialDerivative;
# A_{a}::Depends(r);
# ex:= \partial_{a}{ A_{b} };
# rl:= \partial_{r}{ A_{t} } = 1;
# evaluate(ex, rl);

def test24():
    __cdbkernel__=create_scope()
    {\theta, \varphi}::Coordinate;
    {\alpha, \beta, \gamma, \delta, \rho, \sigma, \mu, \nu, \lambda}::Indices(values={\varphi, \theta}, position=fixed);
    \partial{#}::PartialDerivative;
    g_{\alpha\beta}::Metric.
    g^{\alpha\beta}::InverseMetric.

    sphe:={ g_{\theta\theta} = r**2,
        g_{\varphi\varphi} = r**2 \sin(\theta)**2 }.
    complete(sphe, $g^{\alpha\beta}$)

    ch:= \Gamma^{\alpha}_{\mu\nu} = 1/2 g^{\alpha\beta} ( \partial_{\nu}{g_{\beta\mu}}
                                                        +\partial_{\mu}{g_{\beta\nu}}
                                                        -\partial_{\beta}{g_{\mu\nu}} );

    evaluate(ch, sphe, rhsonly=True)

    rm:= R^{\rho}_{\sigma\mu\nu} = +\partial_{\mu}{\Gamma^{\rho}_{\sigma\nu}}
           -\partial_{\nu}{\Gamma^{\rho}_{\sigma\mu}}
           +\Gamma^{\rho}_{\beta\mu} \Gamma^{\beta}_{\sigma\nu}
           -\Gamma^{\rho}_{\beta\nu} \Gamma^{\beta}_{\sigma\mu};

    substitute(rm, ch)
    evaluate(rm, sphe, rhsonly=True)

    ricci:= R_{\sigma\nu} = R^{\rho}_{\sigma\rho\nu};
    substitute(ricci, rm)
    evaluate(ricci, sphe, rhsonly=True)

    R:= R = R_{\sigma\nu} g^{\sigma\nu};
    substitute(R, ricci)
    evaluate(R, sphe, rhsonly=True)
    val = rhs(R)
    tst:= @(val) - 2/r**2;
    assert(tst==0)
    print("Test 24 passed")
        
test24()

# Evaluating with completely unspecified tensors.
#
def test25():        
    __cdbkernel__=create_scope()
    {a,b,c}::Indices(values={0,1,2,3});
    ex:= X^{a} Y_{a};
    rl:= { Y_{0} = 3, Y_{2} = -5 };
    evaluate(ex, rl)
    tst:= 3 X^{0} - 5 X^{2} - @(ex);
    assert(tst==0)
    print("Test 25 passed")

test25()
        
def test26():
    __cdbkernel__=create_scope()
    {a,b,c}::Indices(values={0,1,2});
    ex:= X^{a b} Y_{a b};
    evaluate(ex)
    tst:= X^{0 0} Y_{0 0} + X^{0 1} Y_{0 1} + X^{0 2} Y_{0 2}
        + X^{1 0} Y_{1 0} + X^{1 1} Y_{1 1} + X^{1 2} Y_{1 2}
        + X^{2 0} Y_{2 0} + X^{2 1} Y_{2 1} + X^{2 2} Y_{2 2} - @(ex):
    sort_product(tst)
    assert(tst==0)
    print("Test 26 passed")

test26()

def test27():
    __cdbkernel__=create_scope()        
    {r,t}::Coordinate;        
    {m,n}::Indices(position=fixed, values={r,t});
    {\sigma,\tau}::Coordinate;        
    X^{m}::Depends(\sigma,\tau);
    \partial{#}::PartialDerivative;
    ex:=\partial_{\tau}{X^{m}};
    evaluate(ex)
    tst:=\components^{m}{\comma{ \comma{t} = \partial_{\tau}{X^{t}} }{ \comma{r} = \partial_{\tau}{X^{r}} } } - @(ex);
    collect_components(_)
    assert(tst==0)
    print("Test 27 passed")

test27()
    
        
import cdb.relativity as rel
# the line below does not work on Travis, so we state the metric here explicitly.
#import cdb.relativity.schwarzschild as ss

def test28():
    g:={g_{t t} = -1+2M/r, g_{r r} = 1/(1-2M/r), g_{\theta\theta} = r**2, g_{\phi\phi} = r**2*sin(\theta)**2};
    complete(g,$g^{\mu\nu}$);
    ch=rel.christoffel_from_metric();
    evaluate(ch, g, rhsonly=True);
    \ddot{#}::Accent;
    \dot{#}::Accent;
    geodesic:= \ddot{X^{\mu}} + \Gamma^{\mu}_{\nu\rho} \dot{X^{\nu}} \dot{X^{\rho}} = 0;
    # Doing evaluate here messes up the components node of the \Gamma factor,
    # there's a weird \components inside a \components. Can probably be tested
    # with a simpler example.
    substitute(geodesic, ch);
    evaluate(geodesic);

#test27()
        
    
def test28():
    __cdbkernel__=create_scope()
    {t,x}::Coordinate:
    {m,n}::Indices(position=fixed, values={t,x});
    a::Depends(t,x);
    \partial{#}::PartialDerivative;
    ex:= (\partial_{t}{a})**2/a**3+a;
    evaluate(ex)
    tst:= (\partial_{t}{a})**2/a**3+a - @(ex);
    assert(tst==0)
    print("Test 28 passed")

test28()


def test29():
    __cdbkernel__=create_scope()
    {t,r}::Coordinate;
    {\mu,\nu,\rho}::Indices(values={r,t});
    ex:= T_{\mu\nu} = T_{\mu\nu};
    rl:= { T_{r t} = Q, T_{t t} = N M };
    evaluate(ex, rl, rhsonly=True)
    # Double evaluation should not introduce additional \components wrappers
    # around scalars.
    evaluate(ex, rl, rhsonly=True)
    ex2=ex[1]
    tst:= \components_{\mu\nu}{\comma{ \comma{r}{t} = Q }{ \comma{t}{t} = N M } } - @(ex2);
    collect_components(tst)        
    assert(tst==0)
    print("Test 29 passed")

test29()

def test30():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;
    A::Depends(t);        
    \partial{#}::PartialDerivative;
    ex:=\partial_{t}{A};
    evaluate(ex)
    tst:=\partial_{t}{A} - @(ex);
    assert(tst==0)
    print("Test 30a passed")
    ex2:= \partial_{t}{ A**2 };
    evaluate(ex2)
    tst2:= 2A\partial_{t}{A} - @(ex2);
    assert(tst2==0)
    print("Test 30b passed")

test30()

def test31():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;
    A::Depends(t);
    \partial{#}::PartialDerivative;
    {\mu,\nu,\rho}::Indices(values={r,t});
    ex:= T_{\mu\nu} = T_{\mu\nu};
    rl:= { T_{r t} = Q, T_{t t} = M };
    glrl:= { g_{r r} = N, g_{t t} = B };
    Rrl:= R = \partial_{t}{A};
    evaluate(ex, rl, rhsonly=True)
    ex2:= T_{\mu\nu} - g_{\mu\nu} R;
    substitute(ex2, ex)
    substitute(ex2, Rrl)
    evaluate(ex2, glrl)
    tst:= \components_{\mu\nu}{\comma{ \comma{r}{t} = Q }{ \comma{t}{t} = -B \partial_{t}{A} + M }{ \comma{r}{r} = - N \partial_{t}{A} }} - @(ex2);
    assert(tst!=0)
    collect_components(tst)
    assert(tst==0)
    print("Test 31 passed")

test31()

        

# def test20():
# __cdbkernel__=create_scope()
# {a,b,c,d}::Indices(values={0,1,2}, position=fixed);
# {a,b,c,d}::Integer(0..2);
# \Gamma{#}::GammaMatrix(metric=\eta);
# C_{a b c}::AntiSymmetric;
# ex:= C_{a b c} \Gamma^{a b c};
# rl:= [ C_{0 1 2} = \alpha ];
# evaluate(ex, rl);
# tst:= 6 \Gamma^{0 1 2} - @(ex);
# assert(tst)

# def test32():
#     # https://github.com/kpeeters/cadabra2/issues/86    
#     __cdbkernel__=create_scope()
#     {r,t}::Coordinate.
#     {m,n}::Indices(values={t,r}, position=fixed).
#     ex:= A_{m} = A_{m};
#     rl:= A_{t} = 3;
#     evaluate(ex, rl, rhsonly=True, simplify=True)
#     ex2:= A_{m};
#     evaluate(ex2, ex);
#     tst:= \components_{m}( \comma{ \comma{t} = 3  } ) - @(ex2);
#     collect_components(_)
#     assert(tst==0)
#     print("Test 32 passed")

def test32():
    __cdbkernel__=create_scope()
#kernel(scalar_backend="mathematica")
    {x,y,\xi}::Coordinate;
    {i,j,k}::Indices(values={x,y,\xi});
    \partial{#}::PartialDerivative;
    F_{i j}::Depends(x,\xi);
    ex:=\partial_{i}{F_{i k}} + m**2 A_{k};
    evaluate(ex)
    tst:=\components_{k}{ \comma{ \comma{\xi} = m**2 A_{\xi} + \partial_{x}{F_{x \xi}} + \partial_{\xi}{F_{\xi \xi}} }{ \comma{y}=m**2 A_{y} + \partial_{x}{F_{x y}} + \partial_{\xi}{F_{\xi y}}}{ \comma{x} = m**2 A_{x} + \partial_{x}{F_{x x}} + \partial_{\xi}{F_{\xi x}} } - @(ex);
    collect_components(tst)
    assert(tst==0)
    print("Test 31 passed")

test32()

def test33():
    __cdbkernel__=create_scope()
    {\sigma,\tau}::Coordinate;                          
    {a,b,c}::Indices(worldsheet, values={\sigma, \tau});
    #{\mu,\nu,\rho}::Indices(targetspace, values={0,1,2,3} );
    #{\mu,\nu,\rho}::Indices(targetspace);
    \partial{#}::PartialDerivative;
    X^{a?}::Depends(\sigma, \tau);
    X^{\mu}::Depends(\sigma, \tau);    
    ex:= \eta^{a b} \partial_{a}{ X^{\mu} } \partial_{b}{ X^{\nu} } g_{\mu\nu};
    mink:= { \eta^{\tau\tau}=-1, \eta^{\sigma\sigma}=1 };
    evaluate(ex, mink)
    tst:= - g_{\mu\nu}\partial_{\tau}{X^{\mu}}\partial_{\tau}{X^{\nu}} + g_{\mu\nu}\partial_{\sigma}{X^{\mu}}\partial_{\sigma}{X^{\nu}} - @(ex);
    assert(tst==0)
    print("Test 33 passed")

test33()
        
def test34():
    __cdbkernel__=create_scope()
    {\sigma,\tau}::Coordinate;                          
    {a,b,c}::Indices(worldsheet, values={\sigma, \tau});
    \partial{#}::PartialDerivative;
    X^{a?}::Depends(\sigma, \tau);
    X^{\mu}::Depends(\sigma, \tau);    
    ex:= \eta^{a b} \partial_{a}{ X^{\mu} } \partial_{b}{ X^{\nu} };
    mink:= { \eta^{\tau\tau}=-1, \eta^{\sigma\sigma}=1 };
    evaluate(ex, mink)
    tst:= - \partial_{\tau}{X^{\nu}}\partial_{\tau}{X^{\mu}} + \partial_{\sigma}{X^{\nu}}\partial_{\sigma}{X^{\mu}} - @(ex);
    assert(tst==0)
    print("Test 34 passed")

test34()

def test35():
    __cdbkernel__=create_scope()
    {r,t,\phi,\theta}::Coordinate.
    {\mu,\nu,\rho,\sigma,\lambda,\kappa,\gamma,\chi}::Indices(values={t,r,\phi,\theta}, position=fixed).
    \partial{#}::PartialDerivative.
    g_{\mu\nu}::Metric.
    g^{\mu\nu}::InverseMetric.         
    ss:= { g_{t t} = -(1-2 M/r),  g_{r r} = 1/(1-2 M/r),
           g_{\theta\theta} = r**2,  g_{\phi\phi}=r**2 \sin(\theta)**2 };
    complete(ss, $g^{\mu\nu}$)
    ch:= \Gamma^{\mu}_{\nu\rho} = 1/2 g^{\mu\sigma} ( \partial_{\rho}{g_{\nu\sigma}}
                                                +\partial_{\nu}{g_{\rho\sigma}}
                                                -\partial_{\sigma}{g_{\nu\rho}} );
    evaluate(ch, ss, rhsonly=True)
    comp=substitute($\Gamma^{r}_{\phi\phi}$, ch)
    tst:= (2M-r) \sin(\theta)**2 - @(comp);
    assert(tst==0)
    print("Test 35 passed")

test35()

def test36():
    __cdbkernel__=create_scope()
    {r,t}::Coordinate;
    {i,j}::Indices(values={r,t});
    F::Depends(r);
    \partial{#}::PartialDerivative;
    ex:=\partial_{i}{\exp(F)};
    evaluate(ex)
    tst:=\components_{i}( \comma{ \comma{r} = \exp(F) \partial_{r}{F}  } ) - @(ex);
    collect_components(tst)
    assert(tst==0)
    print("Test 36 passed")

test36()

def test37():
    __cdbkernel__=create_scope()
    {r,t,\phi,\theta}::Coordinate.
    {\mu,\nu,\rho,\sigma,\lambda,\kappa,\gamma,\chi}::Indices(values={t,r,\phi,\theta}, position=fixed).
    \partial{#}::PartialDerivative.
    g_{\mu\nu}::Metric.
    g^{\mu\nu}::InverseMetric.
    g::Determinant(g_{\mu\nu}).
    gt::Trace(g_{\mu\nu}).
    ss:= { g_{t t} = -(1-2 M/r),  g_{r r} = 1/(1-2 M/r),
           g_{\theta\theta} = r**2,  g_{\phi\phi}=r**2 \sin(\theta)**2 };
    complete(ss, $g$)
    complete(ss, $gt$)
    ex:= g;
    substitute(ex, ss)
    simplify(ex)
    tst:= -r**4 \sin(\theta)**2 - @(ex);
    assert(tst==0)
    print("Test 37 passed")
    ex:= gt;
    substitute(ex, ss)

test37()


def test38():
    __cdbkernel__=create_scope()
    {\mu,\nu}::Indices(values={1,2,3,4}, position=fixed);
    \partial{#}::PartialDerivative;
    {A^{1},A^{2},A^{3},A^{4}}::Depends(\partial{#});
    ex:=\partial_{\mu}{A^{\mu}};
    evaluate(ex)
    tst:= \partial_{1}{A^{1}} + \partial_{2}{A^{2}} + \partial_{3}{A^{3}} + \partial_{4}{A^{4}} - @(ex);
    assert(tst==0)
    print("Test 38 passed")

#     So this fails, because we do not check the dependence correctly.
#     But the general logic also fails if you have a \partial_{\mu}{A} \partial_{\mu}{A} node with
#     a generic dependence A::Depends(\partial{#}), because neither of the two factors will then
#         know over which values of mu to sum, and handle_derivative only sums over index values
#         for which we have a dependence.
# 
#         Whenever we encounter a depencence on \partial{#}, we need to replace that with
#             a dependence on all index values which the unique_indices->values contains.
#             Also do that when the dep is an index itself.
    

        
test38()

def test39():
    __cdbkernel__=create_scope()
    {i,j,k,l}::Indices(vector,fourD,values={0..3},position=fixed);
    {i,j,k,l}::Integer(0..3);
    \partial{#}::Derivative;
    {\kappa,\lambda,\mu,\nu}::Indices(vector, threeD,parent=fourD,values={1..3},position=fixed);
    {\kappa,\lambda,\mu,\nu}::Integer(1..3);
    \epsilon^{\lambda \mu \nu }::EpsilonTensor;
    ex:=\epsilon^{\lambda \mu \nu };
    evaluate(ex, $$);        
    assert( ex[3][1][1] == -1 )
    print("Test 39 passed")

test39()
        
print(list(map(lambda x: str(x), server.totals())))
        
