A few days ago I post in sage-devel google group my desire of contribute in the development of a general relativity (perhaps beyond) module.
A search in Google leads me to a class, named GRPy, created by Sergei Ossokine. My experience with it was not as pleasant as I’d like, but it’s a beginning for starting my own Module. 🙂 Yeah!!!
However, since I’m not a programmer, there are lot of things to learn in the way.
The requirements
We are suppose to do symbolic calculations, so a requirement is the python package for doing so, say sympy
import sympy
For managing arrays, one of the most useful packages is numpy, so we could call it,
import numpy as np
this line does not import the module… but if we want to use a command of the module, i.e. array, we should call it as, np.array.
I just learnt that there exist a module for iterate, and in particular allows to define Cartesian products. It is called itertools. Let’s import it,
import itertools
Finally, from the copy module, let call the deepcopy function,
from copy import deepcopy
which copy and object and all structures inside it!
Define a Tensor Class
I’ll follow to Sergei at the beginning… so let’s start as he did.
A tensor is an object, so is should inherit the characteristics of one. Moreover, a tensor has an identifier symbol, and a rank
class formalTensor(object):
... def __init__(self,symbol,rank):
... self.symbol = sympy.Symbol(symbol)
... self.rank = rank
I still don’t now how useful is to define this formalTensor class. But the next one is the really important,
class Tensor(object): '''A class to represent a tensor in a particular basis''' def __init__(self,symbol,rank,shape,sym=None,coords=None,**args): self.symbol = sympy.Symbol(symbol) # The symbol to represent this Tensor self.coords = coords # The coordinate system we are using for the representation self.shape = shape # The shape of the tensor, for example (-1,1) for k_{a}^{b self.rank = rank # Rank self.contr = rank[0] self.cov = rank[1] # We need to know the dimensionality of our spacetime. For the moment # we will deduce it from the coordinates provide, or if none are given, then # the assumption will be made that it's stored in the optional arguments if coords is not None: self.dim = len(self.coords) else: self.dim = args['dim'] if coords is not None: self.allocate(rank) self.rep = True self.symbolic = formalTensor(symbol,rank) def __setitem__(self,idx,val): self.components[idx]=val def __getitem__(self,idx): return self.components[idx] def allocate(self,rank): '''Allocate the dictionary(hash table) necessary to store the components Note that covariant indices are negative! (except for 0 of course)''' n = rank[0] + rank[1] indc = list(itertools.product(range(self.dim),repeat=n)) mastr=[] for i in range(len(indc)): temp=[] for k in range(len(indc[i])): if self.shape[k] == -1: temp.append(-indc[i][k]) else: temp.append(indc[i][k]) mastr.append(tuple(temp)) self.components = dict(zip(mastr,[0 for i in range(len(indc))])) def _dictkeycopy(self, hay): keys = hay.keys() return dict(zip(keys,[0]*len(keys))) def getNonZero(self): '''Returns only non-zero components of the tensor, if the coordinate system is provided''' if self.rep: nonzerok =[] nonzerov = [] for key in self.components.keys(): if self.components[key] !=0: nonzerok.append(key) nonzerov.append(self.components[key]) d = dict(zip(nonzerok,nonzerov)) keys = d.keys() keys.sort() self.nonzero = [(key,d[key]) for key in keys] return self.nonzero else: print "Attempted to get components that have not been initialized!" def __str__(self): '''Print a "nice" human - readable representation of the tensor''' self.getNonZero() # We will print only non-zero components unless all the components are zero ttl="" if self.nonzero: for i in range(len(self.nonzero)): ttl += str(self.nonzero[i][0]) + " "+str(self.nonzero[i][1])+"\n" else: ttl ="All the components of the tensor are 0!" return ttl
WOW… long way to go explain!
Tensors have,
The constructor
Any class has a constructor named __init__, where the variables of the object are defined and initialized. Additionally, one should call the variables using the prefix self. For a nice introduction to classes see for example A primer on scientific programming with Python.
Said so, the first few line can be followed, let’s jump to the first non-so-trivial thing.
Special Methods
Methods are the possible actions defined for objects in our class. Those methods whose names start with underscore are known as special methods.
Above, two of these are used.
Ok, it’s midnight in UK and I’m really tired.
Tomorrow I’ll explain the allocate method.
I’m uploading the python file to my page (as usual… at the end of the page, in the attachment section).
So far… GR-module.py (version 1)
Enjoy!
DOX.
Hi, it would be very interesting having a gr module but I thik it would be a better way having an interface to cadabra which is a research level symbolic algebra system designed for using it with tensors.
Hi Paco.
Somehow I agree with you, I’m not aware whether Cadabra can calculate with tensors, I know you can manipulate them… but so far I’ve never seen a calculation of Einstein equations given a metric ansatz.
Of course, it would be perfect if we can integrate Cadabra manipulations with a GR-module. By the way, I saw there is a experimental Cadabra package for SAGE (I’ve not used it yet).
Finally, If you have some experience with Cadabra, let me know and we could try to integrate GR-module and Cadabra. 🙂
Cheers.
[…] This post was mentioned on Twitter by Sander Demeester, sagemath.org. sagemath.org said: SAGE tip: GR-module. Day 01 https://doxdrum.wordpress.com/2011/02/05/sage-tip-gr-module-day-01/ #sageprimer http://fb.me/Rlx38RI7 […]