Let me hint some ideas... although it is a not very helpful example.
Comment 0: I'll stick to the suggested code, and not the written line-element.
My suggestions
Firstly, let's assing some properties
{t,x,y,z}::Coordinate;
{\mu,\nu,\rho,\sigma,\lambda,\kappa,\chi,\gamma}::Indices(values={t,x,y,z},position=independent);
{i,j,k,l,m,n}::Indices(values={x,y,z},position=independent);
\partial{#}::PartialDerivative;
g_{\mu\nu}::Metric;
g^{\mu\nu}::InverseMetric;
h_{i j}::Metric;
h^{i j}::InverseMetric;
Comment 1: the separation between Latin and Greek indices.
Then, assign some dependencies,
h_{i j}::Depends(t);
N{#}::Depends(x,y,z);
Now, instead of trying to declare sets of components, like g_{0 i}=N_i
for the metric, I used a detail declaration,
ss := { g_{t t}=0,
g_{t x}=N_x,
g_{t y}=N_y,
g_{t z}=N_z,
g_{x t}=N_x,
g_{y t}=N_y,
g_{z t}=N_z,
g_{x x}=h_{x x},
g_{y y}=h_{y y},
g_{z z}=h_{z z},
g_{y z}=h_{y z},
g_{z y}=h_{y z},
};
complete(ss, $g^{\mu\nu}$);
Comment 2: for the sake of "readability" of the output, I used a simplified version of the /spacial/ submetric. If you use a complete example the output is longer.
Finally, you can define the Christoffel rule,
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}} );
and evaluate its components,
evaluate(ch, ss, rhsonly=True);
A more complete metric
Just if you want to try it
ss := { g_{t t}=N,
g_{t x}=N_x,
g_{t y}=N_y,
g_{t z}=N_z,
g_{x t}=N_x,
g_{y t}=N_y,
g_{z t}=N_z,
g_{x x}=h_{x x},
g_{y y}=h_{y y},
g_{z z}=h_{z z},
g_{x y}=h_{x y},
g_{y x}=h_{x y},
g_{x z}=h_{x z},
g_{z x}=h_{x z},
g_{y z}=h_{y z},
g_{z y}=h_{y z},
};
complete(ss, $g^{\mu\nu}$);
Additional reflexions
If you have evaluated the above code, you'll find that it is not very useful!
Really long expressions.
What if we don't give explicit expressions?
TO BE CONTINUED!
A better method
Ok, finally I came with a better solution.
Paradoxically, the best solution uses the substitute
algorithm instead of the evaluate
.
The problem with the above strategy is that the components have to be given explicitly, but we'd like to treat the indices like time-like and spacial.
Let's start with some assignation of properties:
{t,x,y,z}::Coordinate;
{\mu,\nu,\rho,\sigma,\lambda,\kappa,\chi,\gamma}::Indices(higher, values={t,x,y,z},position=independent);
{\mu,\nu,\rho,\sigma,\lambda,\kappa,\chi,\gamma}::Integer(0..3).
{i,j,k,l,m,n}::Indices(lower, values={x,y,z},position=independent);
{i,j,k,l,m,n}::Integer(1..3);
\partial{#}::PartialDerivative;
g_{\mu\nu}::Metric(higher, signature=-1);
g^{\mu\nu}::InverseMetric(higher, signature=-1);
{g^{\mu}_{\nu},g_{\mu}^{\nu}}::KroneckerDelta(higher).
h_{i j}::Metric(lower, signature=1);
h^{i j}::InverseMetric(lower, signature=1);
{h^{i}_{j},h_{i}^{j}}::KroneckerDelta(lower).
Then, let us define a substitution rule for the ADM decomposition of the metric and its inverse:
ADM := { g_{t t} = - N**2 + h_{i j} N^{i} N^{j},
g_{t i} = h_{i j} N^{j},
g_{i t} = h_{i j} N^{j},
g_{i j} = h_{i j},
g^{t t} = - 1 / N**2,
g^{t i} = N^i / N**2,
g^{i t} = N^i / N**2,
g^{i j} = h^{i j} - N^{i} N^j / N**2
};
refine := { \partial_{i?}{ h_{j}^{k} } -> 0,
\partial_{i?}{ h^{k}_{j} } -> 0,};
Note that I've defined in addition the rule refine
, which will be useful in the next step.
Finally, we want to manipulate (not calculate) each component of the metric connection. My strategy would be to loop over the values of the free indices. cadabra
uses the command Ex
to convert a (formatted python) string into a cadabra expression. Comment 3: since curly brackets are used to call a variable within a f-string, other curly brackets have to be escaped (with double curly bracket, with makes the expressions messy).
for mu in ["t", "i"]:
for nu in ["t", "j"]:
for rho in ["t", "k"]:
Ex(f"\Gamma^{{{mu}}}_{{{nu}{rho}}} = ");
foo = Ex(f"1/2 g^{{{mu} \sigma}} (\partial_{{{rho}}}{{ g_{{{nu} \sigma}} }} + \partial_{{{nu}}}{{ g_{{{rho} \sigma}} }} - \partial_{{\sigma}}{{ g_{{{nu} {rho}}} }})");
split_index(foo, $\mu,t,m$, repeat=True)
substitute(foo, ADM, repeat=True)
distribute(foo)
product_rule(foo)
distribute(foo)
eliminate_metric(foo)
eliminate_kronecker(foo)
sort_product(foo)
rename_dummies(foo)
substitute(foo, refine, repeat=True);
# meld(foo);
Hope this latter method would help you!
Cheers,
Dox.