Some time ago I wrote a package for tensor calculus in General Relativity. In order to make it easily accessible for others it should be slightly modified.
There are functions like i.e. Christoffel for calculation of Christoffel symbol :
Christoffel[g_, xx_] :=
Block[{ig, res, n},
n = 4;
ig = Simplify[Inverse[g]];
res = Table[(1/2)*Sum[ig[[i,s]]*(-D[g[[j,k]], xx[[s]]] + D[g[[j,s]], xx[[k]]]
+ D[g[[s,k]], xx[[j]]]), {s, 1, n}], {i, 1, n}, {j, 1, n}, {k, 1, n}];
res
]
where g and xx are metric tensor and coordinates respectively, which I define in a Mathematica session after uploading the package in a straightforward way putting for example an ansatz for a static spherically symmetric spacetime :
This way involves drawbacks since index ranges are {1, 2, 3, 4}
while the common practice in relativistic physics suggests to put {0, 1, 2, 3}
where 0 stands for timelike coordinate, and {1, 2, 3}
stand for spacelike ones.
To ilustrate the problem let's define a table where indices start from 0 , i.e.
V = Table[i - j, {i, 0, 3}, {j, 0, 3}]
{{0, -1, -2, -3}, {1, 0, -1, -2}, {2, 1, 0, -1}, {3, 2, 1, 0}}
but when I evaluate
V[[0, 0]]
I get Symbol
- the head of V,
while for V[[1, 2]]
I get -1
as it should be.
My questions are :
[0, 0]
? Part
to access tensor components 0,0
how to introduce in a package a freedom of choice of index ranges of other objects like Christoffel (let's say by default index ranges - {0, 1, 2, 3}
or if one prefers - {1, 2, 3, 4}
) ? Although these questions seem trivial at first sight but any comprehensive answers are welcome. Anyone using a package shouldn't bother his head about Mathematica subtleties.
It is not my intention to be trivial or flippant about your concern, however I am having some trouble understanding the significance of your dilemma. Mathematica, or more specifically Part
indexes from one, and that is simply the way it is. I am tempted to say use e.g. V[[n+1]]
but I have to suppose you have already considered this.
Index 0
is reserved for the head of the expression. While it is far from standard, the flexibility of Mathematica syntax actually allows for this construct:
V = 0[-1, -2, -3][{1, 0, -1, -2}, {2, 1, 0, -1}, {3, 2, 1, 0}];
V[[0,2]]
-2
This works because the heads themselves contains your data. This is not advisable, but presented for academic interest.
In specific answer to your first question, and for explanation of the trick above, you must be familiar with Mathematica heads. Every expression conceptually has a head. In the expression a + b
the head is Plus
. In {1, 2, 3}
it is List
. You can see these written out by using FullForm
. Other types also have conceptual heads, even if they are not explicit in FullForm
. You can determine these using Head
. For example:
Head /@ {"abc", 1, Pi, 3.14, 1/2}
{String, Integer, Symbol, Real, Rational}
The Part
syntax [[0, 0]]
asks for the head of the head. In the case of your array, which is a list of lists, the head is List
, and the head of List
itself is Symbol
, which defines its type.
In reply to your second question, I would define a new Part function that indexes from zero.
myPart[x_, spec__] := Part[x, ##] & @@ ({spec} /. n_Integer :> n + 1)
V = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
myPart[V, 0, 0]
1
This also works with Span
:
myPart[V, All, 0 ;; 1]
{{1, 2}, {4, 5}, {7, 8}}
(1) Mathematica list indexing, via Part ( [[]] in more common notation) starts at 1. The 0 part is the head of the expression.
(2) Can define a "function" that takes the indices you want and adds 1 to each.
xx = {t, x, \[Theta], \[Phi]};
g = {{-E^(2*\[Nu][x]), 0, 0, 0}, {0, E^(2*\[Lambda][x]), 0, 0}, {0,
0, x^2, 0}, {0, 0, 0, x^2*Sin[\[Theta]]^2}};
gg[indices___] := g[[Sequence @@ ({indices} + 1)]]
Examples:
In[121]:= gg[0]
Out[121]= {-E^(2*\[Nu][x]), 0, 0, 0}
In[123]:= gg[2, 2]
Out[123]= x^2
(3) See (2) for a possible approach. See (1) to understand that Part is NOT the direct way to go.
Daniel Lichtblau
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With