Cadabra Q&A - Recent questions and answers in General questions
https://cadabra.science/qa/qa/general-questions
Powered by Question2AnswerAnswered: Christoffel symbols computation in $d$ dimensions with split indices
https://cadabra.science/qa/2851/christoffel-symbols-computation-dimensions-split-indices?show=2861#a2861
<p>Hi again raulastur.</p>
<p>Perhaps this would be repetitive, since Arina already post an answer to your question... but Ok, we learn by asymptotic approximation!</p>
<h2>Modifications to your work</h2>
<p>As usual, you have to declare the objects and properties</p>
<pre><code>{\mu,\nu,\rho,\sigma,\kappa,\lambda,\eta,\chi#}::Indices(full, position=fixed, values={1,2,3,4}).
{A,B,C,D}::Indices(subspace, position=fixed, parent=full, values={2,3,4}).
{i,j, m,n,p,q,r,v#}::Indices(subspace2, position=fixed, parent=subspace, values={2,3}).
{s1,s2,s3}::Indices(subspace1, position=fixed, parent=subspace, values={4}).
\partial{#}::PartialDerivative.
g_{\mu\nu}::Metric.
g^{\mu\nu}::InverseMetric.
g_{\mu? \nu?}::Symmetric.
g^{\mu? \nu?}::Symmetric.
b_{i j}::Metric.
b^{i j}::InverseMetric.
{\delta^{\mu?}_{\nu?},\delta_{\mu?}^{\nu?}}::KroneckerDelta.
{b_{i j},b^{i j}}::Depends(\partial{#}).</code></pre>
<p>I wanted to keep your definitions almost untouched. </p>
<p>I've added the dependence of the $b$ field on the partial derivative (although it is not important in the following code.</p>
<p>Then, I assume that the long sequence of substitutions would be applied to other expressions as well, so instead of your approach, I prefer to define a set of substitution rules</p>
<pre><code>rl := { g_{1 m} -> 0, g_{1 4} -> 1, g_{m 1} -> 0, g_{m n} -> b_{m n}, g_{m 4} -> U_{m}, g^{4 1} -> 1,
g_{4 m} -> U_{m}, g_{4 4} -> f, g^{1 1} -> U_{m} b^{m n} U_{n} - f, g^{1 m} -> - U_{n} b^{n m}, g^{1 4} -> 1,
g^{m 1} -> - U_{n} b^{n m}, g^{m n} -> b^{n m}, g^{m 4} -> 0, g^{4 1} -> 1, g^{4 m} -> 0, g^{4 4} -> 0,
\partial_{1}{U_{m}} -> 0, \partial_{1 \mu?}{U_{m}} -> 0,
\partial_{\mu? 1}{U_{m}} -> 0, \partial_{\mu? 1}{b_{i j}} -> 0};</code></pre>
<p>Above, I changed the substitutions that used double question marks, <code>U??</code> or other.</p>
<p>Also include the Christoffel definition</p>
<pre><code>Gtog:= \Gamma^{\lambda?}_{\mu? \nu?} = (1/2) * g^{\lambda? \kappa} (\partial_{\nu?}{ g_{\kappa \mu?}}
+ \partial_{\mu?}{g_{\kappa \nu?}} + \partial_{\kappa}{g_{\mu? \nu?} } );</code></pre>
<p>Note that the summed index has to run over the <code>full</code> space, while the other indices have the question mark (<code>?</code>) to ensure that the rule could be applied to whatever type of index (like <code>4</code>).</p>
<p>Now, I define the expression to be manipulated,</p>
<pre><code>Gamma4ij := \Gamma^{4}_{i j};</code></pre>
<p>and expand the indices</p>
<pre><code>substitute(Gamma4ij, Gtog)
split_index(Gamma4ij, $\mu, 1, A$, repeat=True)
split_index(Gamma4ij, $A, i, 4$, repeat=True);</code></pre>
<p>Finally, I use the substitution rule <code>rl</code> to obtain the result:</p>
<pre><code>substitute(Gamma4ij, rl, repeat=True);</code></pre>
<p>The result I obtain is $\partial<em>1 b</em>{i j}$.</p>
<h3>Why?</h3>
<p>When you used the double question mark notation, <code>U??</code>, in the substitution rule, it would substitute not just the variable called <code>U</code>, but <em>any</em> variable. Look at this example:</p>
<pre><code>ex:=A_{m n} + B_{m n};
substitute(_, $A? + B? -> 0$ );
substitute(_, $M?? + N?? -> 0$ );</code></pre>
<p>Hope this would help you.</p>
<p>Dox</p>General questionshttps://cadabra.science/qa/2851/christoffel-symbols-computation-dimensions-split-indices?show=2861#a2861Fri, 17 May 2024 09:45:10 +0000Why does evaluate of metric eating vector shows only non-zero components.
https://cadabra.science/qa/2855/does-evaluate-metric-eating-vector-shows-only-zero-components
<p>I do not understand why g(.,v) only shows non-zero components after evaluation.</p>
<pre><code>{m,n,a,b,c,r,s}::Indices(values={0,1,2,3}).
#
g_{a b}::Metric.
g^{a b}::InverseMetric.
#
g:=[g_{0 0}=-1, g_{0 1}=0, g_{0 2}=1, g_{0 3}=0, g_{1 0}=0, g_{1 1}=1, g_{1 2}=0, g_{1 3}=0, g_{2 0}=1, g_{2 1}=0, g_{2 2}=1, g_{2 3}=0, g_{3 0}=0, g_{3 1}=0, g_{3 2}=0, g_{3 3}=1].
v:=[v^{0}=1, v^{1}=1, v^{2}=1, v^{3}=1];
display(v)
ex:=g_{a b} v^{a};
evaluate(ex,join(g,v), rhsonly=True);</code></pre>
<pre><code>OUTPUT gives
□_{b}
{1} = 1
{2} = 2
{3} = 1</code></pre>
<p>Setting g00=1 (tather than -1 above) gives </p>
<pre><code>□_{b}
{0} = 2
{1} = 1
{2} = 2
{3} = 1</code></pre>General questionshttps://cadabra.science/qa/2855/does-evaluate-metric-eating-vector-shows-only-zero-componentsTue, 14 May 2024 20:17:56 +0000Answered: How can I store the result of evaluating g(.,v) as a co-vector?
https://cadabra.science/qa/2852/how-can-i-store-the-result-of-evaluating-g-v-as-a-co-vector?show=2853#a2853
<p>Hi, Paul
If you write something like:</p>
<pre><code>ex:= v_{b} = g_{a b} v^{a};
gv = evaluate(ex,join(g,v), rhsonly=True);
wb = comp.components_to_subrule(gv);</code></pre>
<p>You get a list consisting of the components of the v_b co-vector.</p>General questionshttps://cadabra.science/qa/2852/how-can-i-store-the-result-of-evaluating-g-v-as-a-co-vector?show=2853#a2853Tue, 14 May 2024 17:53:21 +0000Answered: why can't cadabra find cdb.sympy.calculus?
https://cadabra.science/qa/2845/why-cant-cadabra-find-cdb-sympy-calculus?show=2846#a2846
<p>Similar issue to your other question: upgrade to a more recent version.</p>General questionshttps://cadabra.science/qa/2845/why-cant-cadabra-find-cdb-sympy-calculus?show=2846#a2846Tue, 07 May 2024 21:00:04 +0000Answered: how to compute metric(vector,vector) or g(v,w) where g,v,w already defined without haqving to repeat the definitions.
https://cadabra.science/qa/2839/compute-metric-already-defined-without-haqving-definitions?show=2840#a2840
<p>If you have the rules <code>g</code> and <code>v</code> which define the component values, you can feed those into <code>evaluate</code>. For example, to compute $g_{a b} v^{a} v^{b}$ with the values of your example, do</p>
<pre><code>{m,n,a,b,c,d,q,r,s}::Indices(values={0,1}).
g_{a b}::Metric.
g^{a b}::InverseMetric.
g:={g_{0 0}=28, g_{0 1}=2, g_{1 0}=3, g_{1 1}=-1};
v:={v^{0}=12, v^{1}=-11};
ex:=g_{a b} v^{a} v^{b};
evaluate(ex, join(g,v));</code></pre>
<p>Does that answer your question?</p>General questionshttps://cadabra.science/qa/2839/compute-metric-already-defined-without-haqving-definitions?show=2840#a2840Tue, 07 May 2024 14:40:18 +0000Answered: How to calculate Christoffel symbols with metric defined by abstract matrices?
https://cadabra.science/qa/2780/calculate-christoffel-symbols-defined-abstract-matrices?show=2836#a2836
<p>Let me hint some ideas... although it is a not very helpful example.</p>
<p><strong>Comment 0:</strong> I'll stick to the suggested code, and not the written line-element.</p>
<h2>My suggestions</h2>
<p>Firstly, let's assing some properties</p>
<pre><code>{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;</code></pre>
<p><strong>Comment 1:</strong> the separation between Latin and Greek indices.</p>
<p>Then, assign some dependencies,</p>
<pre><code>h_{i j}::Depends(t);
N{#}::Depends(x,y,z);</code></pre>
<p>Now, instead of trying to declare sets of components, like <code>g_{0 i}=N_i</code> for the metric, I used a detail declaration,</p>
<pre><code>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}$);</code></pre>
<p><strong>Comment 2:</strong> 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.</p>
<p>Finally, you can define the Christoffel rule,</p>
<pre><code>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}} );</code></pre>
<p>and evaluate its components,</p>
<pre><code>evaluate(ch, ss, rhsonly=True);</code></pre>
<h3>A more complete metric</h3>
<p>Just if you want to try it</p>
<pre><code>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}$);</code></pre>
<h2>Additional reflexions</h2>
<p>If you have evaluated the above code, you'll find that it is not very useful! </p>
<p><em>Really long expressions.</em></p>
<p>What if we don't give explicit expressions?</p>
<p><strong>TO BE CONTINUED!</strong></p>General questionshttps://cadabra.science/qa/2780/calculate-christoffel-symbols-defined-abstract-matrices?show=2836#a2836Fri, 26 Apr 2024 09:19:59 +0000convert other format to cadabra2 format
https://cadabra.science/qa/2833/convert-other-format-to-cadabra2-format
<p>From <a rel="nofollow" href="https://cadabra.science/notebooks/scalar_manipulations.html">Using Cadabra and Sympy together</a>, I learn how to convert cadabra2 format to sympy format, but how to do the reverse operation? I.e. How to convert other formals, e.g. sympy format, to cadabra2 format?</p>General questionshttps://cadabra.science/qa/2833/convert-other-format-to-cadabra2-formatWed, 24 Apr 2024 13:31:05 +0000Answered: function expand_power not work for fractional power
https://cadabra.science/qa/2804/function-expand_power-not-work-for-fractional-power?show=2832#a2832
<p>I found a way to do it. One can use function <code>refine</code> in sympy, for example,</p>
<pre><code>from sympy import refine, sqrt, Q
from sympy.abc import L
ex:=(\lambda**{-2})**{1/2};
substitute(_,$\lambda->L$);
refine(_._sympy_(), Q.positive(L));</code></pre>
<p>But there is an another question: How to transform sympy expression to cadabra2 expression?</p>General questionshttps://cadabra.science/qa/2804/function-expand_power-not-work-for-fractional-power?show=2832#a2832Wed, 24 Apr 2024 13:16:26 +0000question about keep_weight
https://cadabra.science/qa/2814/question-about-keep_weight
<p>In the following code,</p>
<pre><code>{u,v,x}::Coordinate.
f::Coordinate.
{a,b,c,d,e,g,h,p,r#}::Indices(full,values={u,v,x},position=independent).
\partial{#}::PartialDerivative.
\nabla{#}::Derivative.
g_{a b}::Metric.
g^{a b}::InverseMetric.
g_a^b::KroneckerDelta.
g^a_b::KroneckerDelta.
g^{a b}::Symmetric.
g_{a b}::Symmetric.
{n_u,n_v,\gamma,w,\alpha,\lambda,A,B,C}::Depends({u,v,f,x}).
{u,v}::Weight(label=field,value=1);
{f}::Weight(label=field,value=2);
metric:={g_{u v}=1,
g_{v u}=1,g_{v v}=-u**2\alpha,g_{v x}=u w,
g_{x v}=u w,g_{x x}=\gamma};
complete(_,$g^{a b}$);
from cdb.sympy.calculus import *
lamb:=(g^{a b}\partial_a{u v}\partial_b{u v})**{-1/2} ;
evaluate(_,metric,rhsonly=True);
substitute(_,$v->f/u$)
simplify(_);
substitute(_,$\alpha->a,w**2\gamma**{-1}->b$);
series(_,$f$,0,5/2);
substitute(_,$\bigO(A??)->0$)
keep_weight(_,$field=1$);</code></pre>
<p>The final result is not right. There seems to be something wrong here.</p>General questionshttps://cadabra.science/qa/2814/question-about-keep_weightFri, 19 Apr 2024 03:46:06 +0000Answered: Error printing as mma format
https://cadabra.science/qa/2776/error-printing-as-mma-format?show=2798#a2798
<p>As I said, the MicroTeX branch is work in progress.</p>
<p>You can always copy an expression to the clipboard by using the <code>pyperclip</code> package. For instance,</p>
<pre><code>import pyperclip
ex:=A_{m n};
pyperclip.copy( ex.mma_form() )</code></pre>General questionshttps://cadabra.science/qa/2776/error-printing-as-mma-format?show=2798#a2798Thu, 18 Apr 2024 09:01:10 +0000Answered: Formula rendering in jupyter notebook 7 and jupyter lab
https://cadabra.science/qa/2773/formula-rendering-in-jupyter-notebook-7-and-jupyter-lab?show=2779#a2779
<p>According to <a rel="nofollow" href="https://docs.mathjax.org/en/latest/output/linebreaks.html">https://docs.mathjax.org/en/latest/output/linebreaks.html</a>, automatic line breaking is not yet implemented in MathJax 3. I do not know if that web page is the current status, but it would explain why formulas do not wrap.</p>General questionshttps://cadabra.science/qa/2773/formula-rendering-in-jupyter-notebook-7-and-jupyter-lab?show=2779#a2779Sat, 13 Apr 2024 13:04:45 +0000Question about Gaussian normal coordinate
https://cadabra.science/qa/2774/question-about-gaussian-normal-coordinate
<p>When I do calculation under Gaussian normal coordinate:</p>
<p>$$
d s^2=-2 d u d v-u^2\alpha(x) d v^2-2u w_i(x) dv dx^i+\gamma_{ij}(x) d x^i d x^j\,\quad x=(uv\,,x^i)
$$</p>
<p>How to get inverse metric and others directly? I don't know how to deal with $w_i$ and $\gamma_{ij}$.</p>General questionshttps://cadabra.science/qa/2774/question-about-gaussian-normal-coordinateThu, 11 Apr 2024 07:20:30 +0000Answered: The Solution of Einstein's Equation in General Dimensions
https://cadabra.science/qa/2492/the-solution-of-einsteins-equation-in-general-dimensions?show=2760#a2760
<p>The following code should be useful:</p>
<pre><code>{M,N,O,P,Q,R,S}::Indices(full, position=independent);
{\alpha,\beta,\mu,\nu,\sigma,\gamma,\lambda}::Indices(subspace1, position=independent, parent=full);
{\alpha,\beta,\mu,\nu,\sigma,\gamma,\lambda}::Integer(0..d-1).
w::Coordinate;
g_{\mu\nu}::Metric.
g^{\mu\nu}::InverseMetric.
g_{\mu\nu}::Symmetric.
g^{\mu\nu}::Symmetric.
g^{\mu}_{\nu}::KroneckerDelta.
g_{\mu}^{\nu}::KroneckerDelta.
from cdb.utils.indices import *
ex:=g_{M N} g^{M O} P^N;
replace_index(_,r"g",r'O',r'\mu');
split_index(_, $M,\mu,w$,repeat=True);
eliminate_metric(_);
eliminate_kronecker(_);
substitute(_,$P^w->A$);</code></pre>General questionshttps://cadabra.science/qa/2492/the-solution-of-einsteins-equation-in-general-dimensions?show=2760#a2760Thu, 21 Mar 2024 09:13:37 +0000Answered: how to swap indices for partial derivatives
https://cadabra.science/qa/2750/how-to-swap-indices-for-partial-derivatives?show=2751#a2751
<p>Hi bin_go.</p>
<p>I'm noting there is plenty of space in your code to improve, but I'm not here for that (in particular because I don't know your workcase scenario).</p>
<p>So, let me illustrate the use of the algorithm <code>indexsort</code> with an example inspired in your code.</p>
<h2>My example</h2>
<p>First, I'll define the indices and the symbol for the partial derivative.</p>
<pre><code>{a,b,c,d}::Indices("flat",position = free).
{a,b,c,d}::Integer(1..N).
\partial{#}::PartialDerivative.</code></pre>
<p>In this example, I'd define some functions of the "coordinates", but saying that they depends on the derivative</p>
<pre><code>{z,w,v{#}}::Depends(\partial{#});</code></pre>
<p>Define the expression</p>
<pre><code> ex := 2 \chi w**(3) M**(\xi+1) \delta{z}
\partial_{a b}{z} \partial_{a c d}{z} v_{b} v_{c} v_{d} -
2 \chi w**(3) M**(\xi+1) \delta{z}
\partial_{a b}{z} \partial_{c d a}{z} v_{b} v_{c} v_{d};</code></pre>
<p>Note that the result is not simplified, unless we sort the indices</p>
<pre><code> indexsort(ex);</code></pre>
<p>Hope this would help.</p>
<p>Cheers,
Dox.</p>General questionshttps://cadabra.science/qa/2750/how-to-swap-indices-for-partial-derivatives?show=2751#a2751Wed, 20 Mar 2024 08:25:07 +0000Answered: Hello i am a beginner in using Cadabra 2
https://cadabra.science/qa/2747/hello-i-am-a-beginner-in-using-cadabra-2?show=2748#a2748
<p>This means that the indices on the left-hand side and the right-hand side of a replacement rule do not match. For instance,</p>
<pre><code>ex:=A_{m n};
substitute(ex, $A_{m n} = B_{m}$);</code></pre>
<p>You would mess up your equations if it would allow such substitutions.</p>
<p>You <em>can</em> do this if you really want to, by using the <code>-></code> notation,</p>
<pre><code>substitute(ex, $A_{m n} -> B_{m}$);</code></pre>
<p>This will work (but may of course still be wrong).</p>
<p>If you don't get the error from something like this, please post a minimal example.</p>General questionshttps://cadabra.science/qa/2747/hello-i-am-a-beginner-in-using-cadabra-2?show=2748#a2748Sat, 16 Mar 2024 19:45:48 +0000How to create derivatives of coordinates with indices?
https://cadabra.science/qa/2738/how-to-create-derivatives-of-coordinates-with-indices
<p>I have two sets of coordinates, and two partial derivatives which can act on these coordinates. These should work in a way such that:</p>
<p>$$
\partial_{x^{\mu}} x^{\nu} = \delta_{\mu}^{\nu} = \partial_{a<em>{\nu}} a\</em>{\mu}.
$$</p>
<p>How would I go about implementing this in Cadabra? I've tried defining partial derivatives of corresponding coordinates directly, I've tried using notation like DX and DA to differentiate between the two and then using LaTeXform to make it more tidy but I inadvertently run into a stop of some sort. </p>
<p>Any and all help will be greatly appreciated!</p>General questionshttps://cadabra.science/qa/2738/how-to-create-derivatives-of-coordinates-with-indicesThu, 15 Feb 2024 17:28:42 +0000Answered: derivatives with two indices
https://cadabra.science/qa/2729/derivatives-with-two-indices?show=2732#a2732
<p>If <code>\partial_{G P}{...}</code> really indicates a single derivative (e.g. <code>G</code> and <code>P</code> are spinor indices obtained from a vector index with the use of a Pauli matrix or something like that), then it may make sense to revert to single-index notation temporarily.</p>
<p>Alternatively, just write a substitution rule, e.g.</p>
<pre><code>{G,P,M,N,K,L}::Indices;
\partial{#}::PartialDerivative;
test:=\partial_{G P}{A_{M N}*A^{K L}};
pr:= \partial_{G P}{A?? B??} = \partial_{G P}{A??} B??
+ A?? \partial_{G P}{B??};
substitute(test, pr);</code></pre>
<p>Cadabra does not have functionality to treat multiple indices as one out-of-the-box at the moment.</p>General questionshttps://cadabra.science/qa/2729/derivatives-with-two-indices?show=2732#a2732Thu, 18 Jan 2024 11:23:35 +0000Answered: evaluate() returns RuntimeError when using the explicit value of an index
https://cadabra.science/qa/2710/evaluate-returns-runtimeerror-using-explicit-value-index?show=2720#a2720
<p>In line with Kasper's comment, here is a solution with all index locations filled with indices, not values. I post it here in the hope it helps someone else, until the issue is fixed.</p>
<p>Instead of calculating explcitly the <code>K_1 e_1</code> multiplication do the more general <code>K_i e_j</code> multiplication, as follows:</p>
<pre><code>d = 3
{i,j,k,l,m,n}::Indices(rotation, values={1..3}).
\epsilon{#}::EpsilonTensor.
ex := K_{i j m} = \epsilon_{i m n} e_{j}_{n};
s = 'e_{1}_{1} = 1, e_{1}_{2} = 0, e_{1}_{3} = 0,' + \
'e_{2}_{1} = 0, e_{2}_{2} = 1, e_{2}_{3} = 0,' + \
'e_{3}_{1} = 0, e_{3}_{2} = 0, e_{3}_{3} = 1'
Ex(s);
evaluate(ex, Ex(s), rhsonly=True);</code></pre>
<p>This works and you can then pick out the <code>K_1 e_1</code> matrix elements: they are the <code>1,m,1</code> elements in the result (with <code>m</code> any of <code>{1,2,3}</code>). (as it happens, they vanish, which is the correct result).</p>
<p>GPN</p>General questionshttps://cadabra.science/qa/2710/evaluate-returns-runtimeerror-using-explicit-value-index?show=2720#a2720Tue, 09 Jan 2024 09:34:59 +0000Answered: How do I use object properties in a python executable?
https://cadabra.science/qa/2711/how-do-i-use-object-properties-in-a-python-executable?show=2712#a2712
<p>Use the following:</p>
<pre><code>import cadabra2 as cad
cad.Indices(cad.Ex("[a,b,c,d]"),
cad.Ex("name=spacetime, position=independent"))</code></pre>
<p>The <code>Indices</code> function takes two Cadabra expression <code>Ex</code> objects. The first is the list of indices, the second all the arguments.</p>General questionshttps://cadabra.science/qa/2711/how-do-i-use-object-properties-in-a-python-executable?show=2712#a2712Sat, 06 Jan 2024 12:12:11 +0000Answered: Simplification of sum of terms r a^m + s a^m to (r+s)a^m
https://cadabra.science/qa/2707/simplification-of-sum-of-terms-r-a-m-s-a-m-to-r-s-a-m?show=2708#a2708
<p>The problem in your code arises because <code>b^{4}</code> is not the same as <code>b**4</code>. If you do <code>print(tree(ex))</code> on the output, you can see that one of the terms has <code>b^{4}</code> and the other <code>b**4</code> (represented as <code>\pow{b}{4}</code>.</p>
<p>You can solve this in various ways. One way is to convert the <code>b**4</code> to <code>b^{4}</code> with another rule. But since you really mean a power, perhaps a quicker way to achieve the wanted result is to use powers everywhere, not superscripts:</p>
<pre><code>a::Symbol;
b::Symbol;
{a**m?, b**n?, a, b}::NonCommuting;
{m,n,r,s}::Integer.
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)
return ex
act($a b**5$);</code></pre>
<p>I have cut out a few other unnecessary steps in your <code>act</code> function (you don't need to call <code>collect_terms</code> to collect terms in an exponent, and you also never need to call the brute force hammer <code>simplify</code> unless you need a simplification for which SymPy is needed).</p>General questionshttps://cadabra.science/qa/2707/simplification-of-sum-of-terms-r-a-m-s-a-m-to-r-s-a-m?show=2708#a2708Mon, 01 Jan 2024 20:59:09 +0000Answered: Display "hand-made" latex
https://cadabra.science/qa/2702/display-hand-made-latex?show=2703#a2703
<p>Timely question ;-) I have <em>just</em> pushed a change to github which allows you to do</p>
<pre><code>s = LaTeXString(
r'\begin{array}{lll}'
r' 0 & 0 & 0 \\'
r' 0 & 0 & 1 \\'
r' 0 & -1 & 0'
r'\end{array}'
)
s;</code></pre>
<p>which will then show (in cadabra2-gtk and the jupyter frontend) the typeset result. </p>
<p>In other words, this is like a normal string, but with information that the content can be processed as LaTeX.</p>General questionshttps://cadabra.science/qa/2702/display-hand-made-latex?show=2703#a2703Fri, 29 Dec 2023 14:10:52 +0000Answered: Replacing expressions in a matrix
https://cadabra.science/qa/2700/replacing-expressions-in-a-matrix?show=2701#a2701
<p>Some answers I gathered in the hope they help others.</p>
<p>Answer #1:</p>
<p>The following code isn't pretty, but it solves issue #1 by creating a python matrix and storing values into that matrix..</p>
<pre><code>from cdb.core.component import *
from cdb.utils.node import *
d = 3
{k,l,m,n}::Indices(rotation, values={1..3}).
\epsilon{#}::EpsilonTensor.
Kl := (K_{l})_{m n} = \epsilon_{l m n};
evaluate(Kl, rhsonly=True);
mat = [[0 for _ in range(d)] for _ in range(d)]
for ex in Kl[r'\equals']:
lhs = get_lhs(ex.ex())
rhs = get_rhs(ex.ex())
if ${a?,b?,c?}$.matches(lhs):
n = int(str(nth_arg(lhs,0)))
if n == 1:
i = int(str(nth_arg(lhs,1)))
j = int(str(nth_arg(lhs,2)))
mat[i-1][j-1] = str(rhs)</code></pre>
<p>After this, depending on your use case, you can, e.g. turn the matrix into a string and display the string in a LaTeX format, as follows.</p>
<p>Answer #2: beginning in version <code>2.4.5.2</code>, the following (using the new feature <code>LaTeXString</code>) works:</p>
<pre><code>K1 = r'\left[ \begin{array}{cc} '
for i in range(d):
for j in range(d):
if j%d > 0: K1 += ' & '
K1 += str(mat[i][j])
if i%d < d-1: K1 += r' \\'
K1 += r' '
else:
K1 += r'\end{array} \right]'
LaTeXString(K1);</code></pre>
<p>Good luck</p>General questionshttps://cadabra.science/qa/2700/replacing-expressions-in-a-matrix?show=2701#a2701Wed, 27 Dec 2023 19:54:04 +0000Answered: Displaying a matrix with matplotlib error "non-GUI backend"
https://cadabra.science/qa/2698/displaying-a-matrix-with-matplotlib-error-non-gui-backend?show=2699#a2699
<p>Cadabra doesn't use <code>plt.show()</code>. Just display the <code>fig</code> object with</p>
<pre><code>fig;</code></pre>
<p>or</p>
<pre><code>display(fig)</code></pre>General questionshttps://cadabra.science/qa/2698/displaying-a-matrix-with-matplotlib-error-non-gui-backend?show=2699#a2699Mon, 25 Dec 2023 18:48:01 +0000Answered: Displaying components of the epsilon matrix
https://cadabra.science/qa/2696/displaying-components-of-the-epsilon-matrix?show=2697#a2697
<p>Tensors do not have component values by default in Cadabra. You typically write down some tensor expression in abstract form (like that <code>Ki</code> line of yours) and then <code>evaluate</code> the components of that expression by making use of implicit or explicit rules about the components of the tensors that make up this expression.</p>
<p>In your case, try something like</p>
<pre><code>from cdb.core.component import *
{i,j,k,l,m,n}::Indices(topological, values={1,2,3}).
\epsilon{#}::EpsilonTensor.
Ki := (K_{i})_{m n} = \epsilon_{i m n}.
evaluate(Ki, rhsonly=True);
get_component(Ki, $1, 2, 3$);</code></pre>
<p>Note that I have also added the range of the indices.</p>
<p>There isn't anything simple at the moment to get a two-index object in the form of a matrix, unfortunately.</p>General questionshttps://cadabra.science/qa/2696/displaying-components-of-the-epsilon-matrix?show=2697#a2697Sun, 24 Dec 2023 23:16:23 +0000Answered: LaTeXForm expansion fails with "free indices do not match"
https://cadabra.science/qa/2692/latexform-expansion-fails-with-free-indices-do-not-match?show=2693#a2693
<p>That message says that the left-hand side ($\sigma_{\beta}$) does not have the same free indices as the right-hand side. As it stands, the right-hand side does not have any free indices, as functional arguments (things which do not have a sub- or super-script symbol) do not propagate their indices outside the function. </p>
<p>If you add</p>
<pre><code>inner{a?? b??}::IndexInherit.</code></pre>
<p>then the index $\beta$ on the $e_\beta$ inside <code>inner</code> will be 'visible' on the outside of <code>inner</code>, and things match up.</p>General questionshttps://cadabra.science/qa/2692/latexform-expansion-fails-with-free-indices-do-not-match?show=2693#a2693Fri, 22 Dec 2023 13:31:08 +0000Answered: How to collect terms containing derivatives
https://cadabra.science/qa/2680/how-to-collect-terms-containing-derivatives?show=2691#a2691
<p>Hi alonli!</p>
<p>The notation you're using makes me think that you've read our article. If so, thank you very much! It is awesome to note that our work benefits other researchers.</p>
<p>Now, I understand that what you're providing in the question is (probably) a simple example of what you really want to do. However, there are many manipulations that are doing nothing (including the indiscriminate use of the algorithm <code>canonicalise</code>, which is slow because it tries many "simplification" algorithms).</p>
<p>I came out with a shorter list of algorithms that work better in your example (you might have to modify it to fit your necessities):</p>
<pre><code>{a#,b#}::Indices.
\delta{#}::KroneckerDelta.
{a#,b#}::Integer(0..3)
\partial{#}::PartialDerivative.
\epsilon{#}::EpsilonTensor(delta=-\delta).
h_{a1 b1}::Symmetric.
toh := {h_{a1 a1} = h, h_{a1}^{a1} = h}.
def LLmanip(ex):
expand_delta(ex)
distribute(ex)
eliminate_kronecker(ex)
substitute(ex, toh)
sort_product(ex)
rename_dummies(ex)
lower_free_indices(ex)
meld(ex)
rename_dummies(ex)
return ex
LL := \delta^{a1 b1 a2 b2 a3 b3 a4 b4} \partial_{a1}{h_{a2 b2}} \partial_{b1}{h_{a3 b3}} h_{a4 b4};
LLmanip(LL);</code></pre>
<p>I want to drive your attention to the single use of the algorithm <code>meld</code> intead of several <code>canonicalise</code>, single <code>sort_product</code> and <code>rename_dummies</code>, and the lack of the <code>sort_sum</code> (perhaps you might still want it there).</p>
<p>I know that it is useful to define functions for general purpose manipulations, but it is important to keep them "optimal", because once your expressions start to get a bit complex, the functions become very time consuming.</p>
<p>Cheers,
Dox.</p>General questionshttps://cadabra.science/qa/2680/how-to-collect-terms-containing-derivatives?show=2691#a2691Mon, 18 Dec 2023 09:30:53 +0000Answered: Partial derivative of a vector
https://cadabra.science/qa/2669/partial-derivative-of-a-vector?show=2670#a2670
<p>Whenever you <code>evaluate</code>, the expression should not contain derivatives, otherwise simplification by sympy will throw that error. But you can turn that off, so the following does what you want:</p>
<pre><code>\partial{#}::PartialDerivative;
{t,x,y,z}::Coordinate;
{\mu, \nu}::Indices(values={t,x,y,z});
A^{\mu}::Depends(\partial{#});
dA:=\partial_{\mu}{ A^{\mu} };
evaluate(dA, simplify=False);</code></pre>
<p>If you replace the last two lines with</p>
<pre><code>dA:=\partial_{\mu}{ A^{\nu} };
evaluate(dA, simplify=False);</code></pre>
<p>you get that 2x2 expression.</p>General questionshttps://cadabra.science/qa/2669/partial-derivative-of-a-vector?show=2670#a2670Wed, 06 Dec 2023 14:09:56 +0000Answered: A vector-field basis of derivatives?
https://cadabra.science/qa/2665/a-vector-field-basis-of-derivatives?show=2667#a2667
<p>@dbutter thank you! I applied your advice and here is what I got. I think some useful ideas are:</p>
<ul>
<li>define a new class <code>VectorField</code></li>
<li>define the operation <code>v(f)</code>, where <code>v</code> is a vector field and <code>f</code> is a scalar field, as a python <code>__call__</code></li>
</ul>
<p>I hope this helps someone additional.</p>
<pre><code>from cdb.core.manip import multiply_through
\partial{#}::PartialDerivative;
{\mu,\nu}::Indices(spacetime,position=fixed);
{f,}::Depends(\partial{#});
{u^{\mu},v^{\mu}, \partial_{\nu}{f}, \partial_{\mu\nu}{f}, e_{\nu}, f, (1/f)}::SortOrder;
def find_first_index(v):
for ix in v.top().free_indices():
if ix.parent_rel==super:
return ix
raise TypeError(f'{0} has no contravariant index')
class VectorField:
def __init__(self, v: Ex):
self.v = v
def __call__(self, s: Ex):
return self.of_scalar(s)
def of_scalar(self,s):
ix = find_first_index(self.v)
ex = self.v
return $@(ex) \partial_{@(ix)}{@(s)}$
u = VectorField($u^{\mu}$)
v = VectorField($v^{\mu}$)
f := f.
lhs := \commutator{u}{v} f ;
rhs = u(v(f)) - v(u(f));
ex := @(lhs) = @(rhs);
product_rule(ex);
distribute(ex);
sort_product(ex);
meld(ex);
factor_out(ex,$\partial_{\nu}{f}$, right=True);
substitute(ex, $\partial_{\nu}{f} -> e_{\nu} f$);
multiply_through(ex, $1/f$)
collect_factors(ex);</code></pre>
<p>Thanks
GPN</p>General questionshttps://cadabra.science/qa/2665/a-vector-field-basis-of-derivatives?show=2667#a2667Tue, 05 Dec 2023 10:41:44 +0000Answered: Is eliminate_metric supposed to move partial derivative indices?
https://cadabra.science/qa/2508/eliminate_metric-supposed-move-partial-derivative-indices?show=2664#a2664
<p>I did not find a way to do exactly what you want. But here is an alternative. Define <code>\nabla</code> as a <code>Derivative</code> or <code>PartialDerivative</code>.</p>
<pre><code>{\mu, \nu}::Indices(position=independent).
\partial{#}::PartialDerivative.
g_{\mu \nu}::Metric.
g^{\mu \nu}::InverseMetric.
g_{\mu}^{\nu}::KroneckerDelta.
g^{\mu}_{\nu}::KroneckerDelta.
g_{\mu \nu}::Depends(\partial{#}).
g^{\mu \nu}::Depends(\partial{#}).
\nabla{#}::PartialDerivative.
\nabla{#}::Depends(\partial{#}).
expr:=g^{\mu \nu}\nabla_{\nu}{A_{\mu}};
eliminate_metric(_);</code></pre>
<p>The crucial point is that the covariant derivative of the metric is 0, so you do <em>not</em> need to add</p>
<pre><code>g_{\mu \nu}::Depends(\nabla{#}).
g^{\mu \nu}::Depends(\nabla{#}).
</code></pre>
<p>As a result the metric "passes through" the <code>\nabla</code> derivative operator. I hope this helps.</p>
<p>GPN</p>General questionshttps://cadabra.science/qa/2508/eliminate_metric-supposed-move-partial-derivative-indices?show=2664#a2664Mon, 04 Dec 2023 22:15:18 +0000Answered: Avoiding index classes when handling ExNodes
https://cadabra.science/qa/2653/avoiding-index-classes-when-handling-exnodes?show=2661#a2661
<p>Here is a solution that solves some of these issues:</p>
<pre><code>{a,b,c,d,a#}::Indices(vector).
{i,j,k,l,i#}::Indices(isospin).
\nabla{#}::Derivative.
\partial{#}::PartialDerivative.
def expand_nabla(ex):
for nabla in ex[r'\nabla']:
nabla.name=r'\partial'
dindex = nabla.indices().__next__()
for arg in nabla.args():
ret:=0;
for index in arg.free_indices():
indexprop = Indices.get(index, ignore_parent_rel = True)
if indexprop.set_name == 'vector':
t2:= @(arg);
dummy = indexprop.get_dummy(ex)
if index.parent_rel==sub:
t1:= -\Gamma^{@(dummy)}_{@(dindex) @(index)};
t2[index]:= _{@(dummy)};
else:
t1:= \Gamma^{@(index)}_{@(dindex) @(dummy)};
t2[index]:= ^{@(dummy)};
ret += Ex(str(nabla.multiplier)) * t1 * t2
nabla += ret
return ex</code></pre>
<p>This version grabs a dummy index by looking at the entire expression tree, while in practice, we might just want to look at the term in the top-level sum. It knows to ignore isospin indices and only grab vector indices. We also need \nabla and \partial to have IndexInherit (inherited from Derivative). </p>General questionshttps://cadabra.science/qa/2653/avoiding-index-classes-when-handling-exnodes?show=2661#a2661Sun, 03 Dec 2023 14:22:53 +0000Answered: How to get the `weight` value of an object?
https://cadabra.science/qa/2440/how-to-get-the-weight-value-of-an-object?show=2652#a2652
<p>I have pushed a fix based on dbutter's suggestion, so in short, you can now do</p>
<pre><code>x::Weight(value=1, label=field);
weight = Weight.get($x$, label="field").value("field")</code></pre>
<p>to get the weight on the Python side.</p>General questionshttps://cadabra.science/qa/2440/how-to-get-the-weight-value-of-an-object?show=2652#a2652Fri, 01 Dec 2023 20:13:45 +0000Efficiency in python vs cadabra for long substitution rules
https://cadabra.science/qa/2643/efficiency-in-python-vs-cadabra-for-long-substitution-rules
<p>I am applying a list of complicated substitution rules in cadabra. Schematically, these rules look like A_{i} -> (long expression) for some number (say 100) of the A_i. But the expression is very long.</p>
<p>I find that there is a surprising amount of time communicating with the Cadabra server in trying to apply these rules, versus looking for the rule myself.</p>
<p>Here is a sample code:</p>
<pre><code>megasum := x+y.
for i in range(10000):
megasum.top().append_child(Ex( r'B'+str(i) ))
rules = []
for i in range(100):
rules.append(Ex( r'A'+str(i)+'-> @(megasum)' ))
cdbrules = ListToExList(rules)</code></pre>
<p>All the rules in lst are of the form A_i (from A0 to A99) going to the same giant sum. Then I use my Python function ListToExList to convert a Python list to a cadabra list.</p>
<p>On my laptop, the command</p>
<pre><code>substitute($A0$, cdbrules)</code></pre>
<p>requires about 600,000 us to run, and it appears independent of whether I give it A0 to act on or A99.</p>
<p>On the other hand, if on the Python side, I manually search the list for a rule that applies, it seems to run in about 60,000 us (in the worst case) and 5,000 us (in the best case) depending on if I find the rule quickly or not. A simple implementation:</p>
<pre><code>ex := A0.
for i in range(len(keys)):
if keys[i].matches(ex):
substitute(ex, rules[i])
break
</code></pre>
<p>where keys is a list of the LHS of the rules.</p>
<p>I'm trying to understand where the hangup is. My first thought is that Python has to be communicating the entire gargantuan cdbrules, and this is the bottleneck. However, I had the sense from the code that pointers are being used (or aliases to the objects) so that no actual copying is occurring. Does anyone have any ideas?</p>
<p>Apologies in advance for the rather ill-defined question...</p>General questionshttps://cadabra.science/qa/2643/efficiency-in-python-vs-cadabra-for-long-substitution-rulesThu, 30 Nov 2023 19:00:07 +0000Answered: Trigonometric and hyperbolic functions
https://cadabra.science/qa/2635/trigonometric-and-hyperbolic-functions?show=2641#a2641
<p>Hi Ariana,</p>
<p>In principle the manipulation of functions within <code>cadabra</code> is made through <code>SymPy</code>. Hence, one could use (supposedly) any function recognised by <code>SymPy</code>, e.g. <code>\sinh</code>, <code>\cosh</code>, <code>\tanh</code>, etc.</p>
<p>However, <code>cadabra</code> does not necessarily know how to handle the output returned by <code>SymPy</code>, particularly because <code>cadabra</code> expressions are rendered as <code>LaTeX</code> expressions... translated by a "dictionary". If the "dictionary" does not have the function you want, you'll get errors in your notebook.</p>
<p>So, the manipulation of functions is limited by the size of the "dictionary".</p>
<p>I recommend you to see the GitHub page of <a rel="nofollow" href="https://github.com/kpeeters/cadabra2/blob/master/core/DisplaySympy.cc">DisplaySympy</a>, in particular the definition <code>DisplaySympy::DisplaySympy</code></p>
<p>Dox.</p>General questionshttps://cadabra.science/qa/2635/trigonometric-and-hyperbolic-functions?show=2641#a2641Thu, 30 Nov 2023 08:37:08 +0000Hodge dual in exterior calculus
https://cadabra.science/qa/2637/hodge-dual-in-exterior-calculus
<p>I am new to Cadabra and want to derive the Maxwell equations using exterior calculus. I've looked at the tutorials and searched the reference manual but I cannot figure out how to express the Hodge dual.</p>
<p>-erik</p>General questionshttps://cadabra.science/qa/2637/hodge-dual-in-exterior-calculusWed, 29 Nov 2023 18:40:35 +0000Answered: How AntiCommuting information is stored
https://cadabra.science/qa/2609/how-anticommuting-information-is-stored?show=2610#a2610
<p>None of the above ;-) </p>
<p>First, remember that this is all stored on the C++ side. All properties are stored in two ways: a map from patterns to property objects, and a map from property objects to patterns. So for</p>
<p><code>{F1, F2, F3}::AntiCommuting</code></p>
<p>there is a map <code>props</code> which contains</p>
<pre><code>F1 -> A1
F2 -> A1
F3 -> A1</code></pre>
<p>where <code>A1</code> is an instance of the property object <code>AntiCommuting</code>. And there is a map <code>pats</code> which contains</p>
<pre><code>A1 -> F1
A1 -> F2
A1 -> F3</code></pre>
<p>(so an ordered multi-map, to be precise). </p>
<p>Now the <code>properties</code> object which contains all this has methods to find a shared <code>AntiCommuting</code> object for two given patterns. So you can ask it "Do F1 and F2 have an AntiCommuting property in common?". </p>
<p>(This all looks terribly complicated until you start to build in property inheritance and the like, when simpler solutions tend to be insufficient). </p>
<p>Now most of this is not easily accessible on the Python side because it was written long before I added the Python wrapper on top of the C++ core. Your solution (of repeating the list property declaration) is by far the simplest. Of course if you run into something that cannot be done that way.</p>
<p>Unfortunately, while there is a way to retrieve property information for an expression using <code>[PropertyName].get(...)</code>, you cannot use this to check whether to elements are in the same list (yet). So if you do</p>
<pre><code>{F1, F2}::AntiCommuting;
p1 = AntiCommuting.get($F1$)
p2 = AntiCommuting.get($F2$)
p1 == p2</code></pre>
<p>you get <code>False</code>, and there is no</p>
<pre><code>p = AntiCommuting($F1$, $F2$)</code></pre>
<p>yet either (which would probably be the easiest way out).</p>General questionshttps://cadabra.science/qa/2609/how-anticommuting-information-is-stored?show=2610#a2610Tue, 21 Nov 2023 15:04:28 +0000Answered: Differentiate a propagator
https://cadabra.science/qa/2605/differentiate-a-propagator?show=2606#a2606
<p>I now tried</p>
<pre><code>from cdb.sympy.calculus import *
\partial{#}::PartialDerivative;
x^{\rho}::Depends(\partial{#});
diff($1/(\eta_{\mu\nu} x^{\mu}x^{\nu})$, $x^{\rho}$);</code></pre>
<p>which gave the error message</p>
<pre><code>File "/home/gpn/.config/cadabra_packages/cdb/sympy/calculus.py", line 20, in diff
dvars.append( sbtmp.to_sympy() )
RuntimeError: Dependencies on derivatives are not yet handled in the SymPy bridge</code></pre>
<p>so I conclude this is not yet possible in cdb.
If anyone has a better answer please let me know.</p>
<p>Thanks
GPN</p>General questionshttps://cadabra.science/qa/2605/differentiate-a-propagator?show=2606#a2606Sat, 18 Nov 2023 13:46:11 +0000Answered: eliminate_vielbein "eliminates" with a Minkowski metric
https://cadabra.science/qa/2586/eliminate_vielbein-eliminates-with-a-minkowski-metric?show=2604#a2604
<p>In the hope it helps someone else:</p>
<p>I found no way to tell Cadabra that the Minkowski metric is "special". In the case I gave above, "swallowing" the Vielbein into the metric is just the Cadabra behavior.</p>
<p>In cases where I needed to eliminate Vielbein with each other, I could use <code>eliminate_vielbein</code>:</p>
<pre><code>{a,b,c,d}::Indices(flat, position=fixed).
V^{a}_{\mu}::Vielbein.
V_{a}^{\mu}::InverseVielbein.
V^{a}_{b}::KroneckerDelta.
V_{a}^{b}::KroneckerDelta.
ex := V_{a}^{\rho} V^{c}_{\rho} V_{c}^{\sigma};
eliminate_vielbein(ex);
eliminate_kronecker(ex);</code></pre>General questionshttps://cadabra.science/qa/2586/eliminate_vielbein-eliminates-with-a-minkowski-metric?show=2604#a2604Thu, 16 Nov 2023 21:47:40 +0000Answered: How to implement a zoom-sensitive algorithm
https://cadabra.science/qa/2595/how-to-implement-a-zoom-sensitive-algorithm?show=2597#a2597
<p>Good one. Everything which is hidden by <code>zoom</code> is wrapped inside an <code>\ldots{...}</code> node. So in principle you can avoid acting on those hidden terms by checking whether your node has an <code>\ldots</code> parent node.</p>
<p>Unfortunately, there isn't really anything that helps with that, unless you want to give up the simple way of walking the expression tree as in that covariant derivative example.</p>
<p>Fortunately, this was trivial to add on the C++ side. I have just pushed 2.4.5 which does the right thing and makes <code>ExNode</code> iterators jump over hidden nodes. Can you let me know if that works for you? (or let me know if you need a binary package if you cannot build from source).</p>General questionshttps://cadabra.science/qa/2595/how-to-implement-a-zoom-sensitive-algorithm?show=2597#a2597Mon, 13 Nov 2023 20:06:15 +0000Answered: How could the partial derivatives be sorted?
https://cadabra.science/qa/2579/how-could-the-partial-derivatives-be-sorted?show=2585#a2585
<p>This works in most cases:</p>
<pre><code>{i,j,k,l}::Indices(space, position=free).
{t, \tau}::Indices(time, position=free).
{i,j,k,l,t}::SortOrder;
\partial{#}::PartialDerivative;
ex := \partial_{t i}{ T^{j} };
canonicalise(ex);
ex := \partial_{t i j}{ T^{j} };
canonicalise(ex);
ex := \partial_{t i t j}{ T^{k} };
canonicalise(ex);</code></pre>
<p>The only case which is not exactly what you want is when an index is summed according to the Einstein convention; the summation and canonicalization have the effect of raising one of the indices.</p>
<p>The following is another variant, which also has an issue when an index is summed according to the Einstein convention, it's just a different issue:</p>
<pre><code>{i,j,k,l}::Indices(space, position=independent).
{t, \tau}::Indices(time, position=independent).
{i,j,k,l,t}::SortOrder;
\partial{#}::PartialDerivative;
ex := \partial_{t i}{ T^{j} };
canonicalise(ex);
ex := \partial_{t i j}{ T^{j} };
canonicalise(ex);
ex := \partial_{t i t j}{ T^{k} };
canonicalise(ex);</code></pre>General questionshttps://cadabra.science/qa/2579/how-could-the-partial-derivatives-be-sorted?show=2585#a2585Fri, 10 Nov 2023 07:59:46 +0000Answered: How to calculate the determinant of a tensor density?
https://cadabra.science/qa/2574/how-to-calculate-the-determinant-of-a-tensor-density?show=2581#a2581
<p>Hi GPN.</p>
<p>To the extend of my knowledge <code>cadabra</code> does not calculate... I would say manipulate expressions (you assign properties to "objects" and use algorithms to manipulate them).</p>
<p><code>cadabra2.x</code> comunicates with <code>SymPy</code> to evaluate expressions (in other word, calculate!). However, the comunication is not "bijective" (it is somehow incomplete), and there is a possibility that the dictionary doesn't translate the operation <code>\det</code>.</p>
<p>If you ask me... I would use <code>substitute</code>! (unless it is not possible)</p>
<p>Cheers,
Dox.</p>General questionshttps://cadabra.science/qa/2574/how-to-calculate-the-determinant-of-a-tensor-density?show=2581#a2581Thu, 09 Nov 2023 08:50:43 +0000Answered: Expansion of covariant derivative
https://cadabra.science/qa/2041/expansion-of-covariant-derivative?show=2578#a2578
<p>The answer I'm posting (after two years) is based on an idea by @dominicprice (former student of Kasper, and developer of many aspects of <code>cadabra</code>).</p>
<h1>The code</h1>
<pre><code>def expand_nabla(ex, *, index_name=None, index_set=None):
if index_name is None:
index_name = "expandnablaidx"
Indices($expandnablaidx, expandnablaidx#$, $expandnablaindices$)
index_counter = 1
for nabla in ex[r'\nabla']:
nabla.name=r'\partial'
dindex = nabla.indices().__next__()
for arg in nabla.args():
ret:=0;
for index in arg.free_indices():
t2:= @(arg);
newidx = Ex(index_name + str(index_counter))
index_counter += 1
if index.parent_rel==sub:
t1:= -\Gamma^{@(newidx)}_{@(dindex) @(index)};
t2[index]:= _{@(newidx)};
else:
t1:= \Gamma^{@(index)}_{@(dindex) @(newidx)};
t2[index]:= ^{@(newidx)};
ret += Ex(str(nabla.multiplier)) * t1 * t2
nabla += ret
distribute(ex, repeat=True)
if index_set is not None:
rename_dummies(ex, "expandnablaindices", index_set)
return ex</code></pre>
<h1>How does it work?</h1>
<p>The problem I found with the algorithm <code>expand_nabla</code> reported in the cadabra book <a rel="nofollow" href="https://cadabra.science/notebooks/ref_programming.html">https://cadabra.science/notebooks/ref_programming.html</a>, was that when considering higher order derivatives, the name of the dummy index wouldn't change, resulting in a "repeated indices" error.</p>
<p>It is desirable that the algorithm could use one of the declared indices!</p>
<p>Therefore, we have to give a name to the set of indices:</p>
<pre><code>\nabla{#}::Derivative.
\partial{#}::PartialDerivative.
{a, b, c, d, e, f, g, h, i, j, k ,l}::Indices(space, position=fixed).
{\mu,\nu,\lambda,\rho}::Indices(spacetime, position=fixed).</code></pre>
<p><strong>NOTE:</strong> there are two types of indices: <code>space</code> and <code>spacetime</code>.</p>
<p>Now, we declare an expression and expand the nabla operator (covariant derivative).</p>
<pre><code>foo := \nabla_{c}{ h^{a}_{b} };
expand_nabla(_, index_set="space");</code></pre>
<p>Since we have asked to expand with dummy indices of type <code>space</code>, the result is</p>
<p>$$\partial<em>{c}{h^{a},</em>{b}}+\Gamma^{a},<em>{c d} h^{d},</em>{b}-\Gamma^{d},<em>{c b} h^{a},</em>{d}$$</p>
<p>However, if we expand indices of type <code>spacetime</code>, we get</p>
<p>$$\partial<em>{c}{h^{a}\,</em>{b}}+\Gamma^{a}\,<em>{c \mu} h^{\mu}\,</em>{b}-\Gamma^{\mu}\,<em>{c b} h^{a}\,</em>{\mu}$$</p>
<h2>Higher orders</h2>
<p>Higher orders (I was able to calculate up to third order) can be computed with ease, for example:</p>
<pre><code>foo := \nabla_{e}{\nabla_{d}{\nabla_{c}{ h^{a}_{b} }}};
#expand_nabla(_, index_set="vector");
expand_nabla(_, index_name=r'\lambda');</code></pre>
<p>The <code>index_name=r'\lambda'</code> ask the algorithm to use the name <code>\lambda</code> to expand the dummy indices.</p>General questionshttps://cadabra.science/qa/2041/expansion-of-covariant-derivative?show=2578#a2578Wed, 08 Nov 2023 08:54:16 +0000Answered: How to change the order of two indexes in a complex statement
https://cadabra.science/qa/2568/how-to-change-the-order-of-two-indexes-in-a-complex-statement?show=2572#a2572
<p>Thanks @doxdrum</p>
<p>I found a workaround, using <code>substitute()</code>:</p>
<pre><code>ex1 := g_{\mu\kappa} \partial_{\nu}{g^{\rho\kappa}} ->
-g^{\rho\kappa} \partial_{\nu}{g_{\mu\kappa}};
ex2 := g_{\mu\kappa} \partial_{\nu}{g^{\kappa\rho}} ->
-g^{\rho\kappa} \partial_{\nu}{g_{\mu\kappa}};
substitute(ex1, $_{\kappa}^{\rho\kappa} -> _{\sigma}^{\sigma\rho}$);
ex1;
ex2;</code></pre>
<p>You will notice that the only change this does - is a change to the order of the indexes - which is what I needed.</p>
<p>However to achieve this I also needed to change the name of the indexes. It is a workable solution.</p>
<p>Many thanks for your attention.
GPN</p>General questionshttps://cadabra.science/qa/2568/how-to-change-the-order-of-two-indexes-in-a-complex-statement?show=2572#a2572Wed, 25 Oct 2023 17:24:48 +0000Answered: Zooming in on a specific term and applying a rule
https://cadabra.science/qa/2553/zooming-in-on-a-specific-term-and-applying-a-rule?show=2558#a2558
<p>Hi GPN.</p>
<p>You posed a very interesting question. I got a bit further in the direction you wanted. Let me explain.</p>
<p>Following your example, I stated with these definitions (<code>properties</code>):</p>
<pre><code>from cdb.relativity.abstract import christoffel_from_metric
g_{\mu\nu}::Metric.
g_{\mu\nu}::Depends(\partial{#}).
g^{\mu\nu}::InverseMetric.
g^{\mu\nu}::Depends(\partial{#}).
\Gamma^{\mu}_{\nu\rho}::Depends(\partial{#}).
ch = christoffel_from_metric()</code></pre>
<p>Now, the expression to manipulate is the following:</p>
<pre><code>ch_2 := \Gamma^{\rho}_{\nu\sigma}\Gamma^{\sigma}_{\rho\mu};
substitute(ch_2,ch)
distribute(ch_2);</code></pre>
<p>Let's say that you want to manipulate the fourth term. My approach is to define a new expression using the target term</p>
<pre><code>old = ch_2[3]
old := 4 @(old);</code></pre>
<p><strong>BEWARE:</strong></p>
<ul>
<li>In the last code block the first definition of the variable <code>old</code> is a python command (note the assignation through the equal sign (without colon), so it don't require to end in semi-colon.</li>
<li>The re-definition of <code>old</code> is a cadabra expression (uses the <code>:=</code>) whose purpose is to eliminate the numerical factor, which raises an error in the next step.</li>
</ul>
<p>Next, I define a <code>new</code> expression which might be a copy of <code>old</code>, i.e. <code>new := @(old)</code> to be manipulated through cadabra algorithms, or just a hand-made expression. The goal is to define a substitution rule.</p>
<p>In the code block below I use the second scenario:</p>
<pre><code>new := A_{\mu \nu};
rl := @(old) -> @(new);</code></pre>
<p>Finally, I apply the substitution rule to the original expression <code>ch_2</code>:</p>
<pre><code>substitute(ch_2, rl);</code></pre>
<p>Hope this could be useful for your case!
Dox.</p>General questionshttps://cadabra.science/qa/2553/zooming-in-on-a-specific-term-and-applying-a-rule?show=2558#a2558Fri, 20 Oct 2023 17:22:25 +0000Answered: Getting two terms with derivatives to form a product
https://cadabra.science/qa/2549/getting-two-terms-with-derivatives-to-form-a-product?show=2551#a2551
<p>Hi GPN,</p>
<p>Thanks for sharing your doubts and ideas. I found your solution very useful, and it inspired me to try a different approach.</p>
<p>My solutions uses the algorithm <code>isolate</code> from the library <code>manip</code>, so the notebook starts like:</p>
<pre><code>import cdb.core.manip as manip</code></pre>
<p>Then, I modify your approach (in particular the notation of the inverse, and taking care of the space between the operators <code>A</code> and <code>G</code>):</p>
<pre><code>\partial{#}::PartialDerivative.
ex := \partial{A} + B + A (G**(-1) \partial{G}) + C.
sort_product(ex);</code></pre>
<p>The algorithm <code>sort_product</code> will ensure the same order of the factors (the usefulness wuold be seen shortly.</p>
<p>Then, I define the <code>contracted</code> expression</p>
<pre><code>contracted := G**(-1) \partial{(G A)};</code></pre>
<p>and the <code>expanded</code> one. Following your idea, I manipulate the <code>expanded</code> expression and define a substitution rule</p>
<pre><code>expanded := @(contracted);
product_rule(expanded)
distribute(expanded)
collect_factors(expanded)
sort_product(expanded)
contraction_rule := @(expanded) = @(contracted);</code></pre>
<p>Note the appearance of <code>sort_product</code> again. Since the desired expression to substitute is not isolated on the left-hand-side of the substitution rule, we use <code>isolate</code> to isolate it:</p>
<pre><code>manip.isolate(contraction_rule, $A \partial{G} G**(-1)$);</code></pre>
<p>And finally we use the <code>contraction_rule</code> on the original expression <code>ex</code>:</p>
<pre><code>substitute(ex, contraction_rule);</code></pre>
<p>Hope you find this aproach useful!
Dox.</p>General questionshttps://cadabra.science/qa/2549/getting-two-terms-with-derivatives-to-form-a-product?show=2551#a2551Tue, 17 Oct 2023 12:56:23 +0000Answered: symmetrise slots function
https://cadabra.science/qa/2538/symmetrise-slots-function?show=2540#a2540
<p>As an alternative to doxdrum's answer, if you know the names of the indices, you can use <code>sym</code>, e.g.</p>
<pre><code>ex:= R_{a b} R_{c d} h_{s w} h^{a c} h^{b d};
sym(ex, $_{s}, _{w}$);</code></pre>
<p>There is also <code>asym</code> for anti-symmetrisation.</p>General questionshttps://cadabra.science/qa/2538/symmetrise-slots-function?show=2540#a2540Fri, 15 Sep 2023 07:59:25 +0000Lie derivative in Cadabra
https://cadabra.science/qa/2533/lie-derivative-in-cadabra
<p>Hi,
I couldn't find any mention of the Lie derivative in any documentation of Cadabra (this website, github, additional literature).
I'm trying to write a method that expands the expression Lie_V{\<tensor-with_free_indices>} into the formula of the <a rel="nofollow" href="https://en.wikipedia.org/wiki/Lie_derivative#Coordinate_expressions">Lie derivative with partial derivatives</a>. The method will be something like
expand_Lie(ex,$V$,$m$)
The first argument is some expression that has inside "L{...}", the second argument is the vector, and the third argument is for a dummy index.</p>
<p>I started working with the code in p.36 of "The Cadabra Book.pdf" (by Peeters) - this implements expansion of the covariant derivative (nabla).</p>
<p>I need help to add a dummy index to the first term (replacing "L{..}") and multiplying it by the vector. My code currently changes the name "L" into the "v^{p} \partial_{p}" but I think this is incorrect.</p>
<pre><code>def expand_Lie(ex,v,dummy):
for Lie in ex["L"]:
Lie.name=r"v^{p} \partial_{p}"
#Lie.indices().add(@(dummy)})
#Lie *= v^{@(dummy)}
for arg in Lie.args():
ret:=0;
for index in arg.free_indices():
t2:= @(arg);
if index.parent_rel==sub:
t1:= \partial_{@(index)}{v^{@(dummy)}};
t2[index]:= _{@(dummy)};
else:
t1:= -\partial_{@(dummy)}{v^{@(index)}};
t2[index]:= ^{@(dummy)};
ret += Ex(str(Lie.multiplier)) * t1 * t2
Lie += ret
return ex</code></pre>
<p>`</p>General questionshttps://cadabra.science/qa/2533/lie-derivative-in-cadabraTue, 22 Aug 2023 20:29:20 +0000Answered: Why doesn't distribute() completely expand products involving sums of kronecker deltas?
https://cadabra.science/qa/2518/doesnt-distribute-completely-products-involving-kronecker?show=2527#a2527
<p>I think the solution is actually very simple: you are missing a space between the <code>X_{c d}</code> and the opening bracket. This means that Cadabra interprets this as a tensor with argument given by whatever is in the brackets, <strong>not</strong> as a product of two tensors.</p>General questionshttps://cadabra.science/qa/2518/doesnt-distribute-completely-products-involving-kronecker?show=2527#a2527Tue, 20 Jun 2023 11:54:40 +0000Unexpected behaviour of zoom()
https://cadabra.science/qa/2513/unexpected-behaviour-of-zoom
<p>I'm trying to use the zoom command to focus on some terms in an expression. Strangely enough it only picks out one of the two terms that contain the piece that I want to zoom in on in one case. And it doesn't pick out the only term that fits my criterion in the other case. What am I doing wrong?</p>
<p>Here's my example code. In one case, I tried to zoom in on terms that contain <code>\delta(g)^{\mu \nu}</code> of which there are two but it only returns one of them. In the other case, I tried to zoom in on the lone term containing a <code>\delta(F)_{\mu \nu}</code> but it returns nothing.</p>
<pre><code>{ \alpha, \beta, \mu, \nu, \lambda, \kappa, \rho, \sigma, \sigma# }::Indices(total, position=independent).
\partial{#}::PartialDerivative.
{\nabla{#}, \delta{#}}::Derivative.
g_{ \mu \nu }::Metric.
g^{ \mu \nu }::InverseMetric.
g_{ \mu? \nu? }::Symmetric.
g^{ \mu? \nu? }::Symmetric.
g{#}::Depends(\nabla{#}, \partial{#}, \delta{#}).
\delta(g)^{\mu \nu}::Symmetric.
F_{\mu? \nu?}::AntiSymmetric.
F^{\mu? \nu?}::AntiSymmetric.
\delta{F}_{\nu? \rho?}::AntiSymmetric.
F{#}::Depends(\nabla{#}, \partial{#}, \delta{#}).
ex:= L = - \sqrt{g} \frac{1}{4} g^{\mu \alpha} g^{\nu \beta} F_{\alpha \beta} F_{\mu \nu} ;
varyex:= \delta{L}.
substitute(varyex, ex)
product_rule(varyex, repeat=True)
sort_product(varyex, repeat=True)
rename_dummies(varyex)
distribute(varyex, repeat=True)
collect_factors(varyex, repeat=True)
substitute(varyex, $\delta(g) -> - g (g_{\mu \nu} \delta(g)^{\mu \nu})$, repeat=True)
collect_factors(varyex, repeat=True)
meld(_, repeat=True);
zoom(_, $\delta(g)^{\mu? \nu?} Q??$);
unzoom(_)
zoom(_, $\delta(F)_{\mu \nu} Q??$);
unzoom(_)</code></pre>General questionshttps://cadabra.science/qa/2513/unexpected-behaviour-of-zoomSat, 03 Jun 2023 10:13:12 +0000Maxwell equations in curved space
https://cadabra.science/qa/2509/maxwell-equations-in-curved-space
<p>I'm trying to derive Maxwell equations in general curved space. I run into a very specific issue that's not related to this example but I couldn't find a simpler example to illustrate the issue. Here's my attempt:</p>
<pre><code>{ \alpha, \beta, \mu, \nu, \lambda, \kappa, \rho, \sigma, \sigma# }::Indices(spacetime, position=independent).
\partial{#}::PartialDerivative.
{\nabla{#}, \delta{#}}::Derivative.
g_{ \mu \nu }::Metric.
g^{ \mu \nu }::InverseMetric.
g_{ \mu \nu }::Symmetric.
g^{ \mu \nu }::Symmetric.
g{#}::Depends(\nabla{#}, \partial{#}).
\Gamma^{\mu?}_{\nu? \rho?}::TableauSymmetry(shape={2}, indices={1,2}).
A{#}::Depends(\nabla{#}, \partial{#}).
ex:= L = - \sqrt{(- g)} (\frac{1}{4} g^{\mu \alpha} g^{\nu \beta} (\nabla_{\alpha}{A_{\beta}} - \nabla_{\beta}{A_{\alpha}})(\nabla_{\mu}{A_{\nu}} - \nabla_{\nu}{A_{\mu}}));
varyex:= \delta{L}.
substitute(varyex, ex);
distribute(varyex, repeat=True)
product_rule(varyex, repeat=True)
distribute(varyex, repeat=True)
substitute(varyex, $\delta{ \nabla_{\mu}{ A_{\nu} } } -> \nabla_{\mu}{ \delta{ A }_{\nu} } - \delta{\Gamma}^{\rho}_{\mu \nu} A_{\rho}$, repeat=True);
distribute(varyex, repeat=True)
canonicalise(varyex, repeat=True);
zoom(_, $Q?? \delta{\Gamma}^{\rho}_{\mu \nu}$);</code></pre>
<p>You see at the end that there are four terms that should visibly cancel between each other. But I'm not sure what I should be doing to cancel them out. <code>canonicalise</code> doesn't seem to do the job. I tried using <code>factor_out</code> to pull out some pieces to see if the rest of it cancels. But nothing has worked yet. </p>
<p>Any suggestions?</p>General questionshttps://cadabra.science/qa/2509/maxwell-equations-in-curved-spaceWed, 31 May 2023 18:31:47 +0000Question about manip.apply_through()
https://cadabra.science/qa/2494/question-about-manip-apply_through
<p>I'm confused about how to use the manip.apply_through() function. </p>
<p>The following attempt</p>
<p><code>ex := A_{\mu \nu} = B_{\mu \nu};</code></p>
<p><code>manip.apply_through(ex, \partial_{\rho}{#});</code></p>
<p>or some variations thereof seem to throw an error. What's the correct way to do this? </p>General questionshttps://cadabra.science/qa/2494/question-about-manip-apply_throughSun, 23 Apr 2023 20:30:32 +0000