This code is supposed to be (if some one does the work in the future) located in sage.tensor.differential_form_element.
The code presented below is a slight modification of Joris code for differential forms manipulation on SAGE.
Needed modules
from sage.symbolic.ring import SymbolicRing, SR
from sage.rings.ring_element import RingElement
from sage.algebras.algebra_element import AlgebraElement
from sage.rings.integer import Integer
from sage.combinat.permutation import Permutation
The advantage of using this is that, tensors defined here are an Algebra element, not just a python object as in the previous code.
The sage.combinat.permutation won’t be used (yet), but could be useful if tensor symmetries are defined.
TensorFormatter
class TensorFormatter:
r"""
This class contains all the functionality to print a tensor in a
graphically pleasing way. This class is called by the ``_latex_`` and
``_repr_`` methods of the Tensor class.
"""
def __init__(self, space):
r"""
Construct a tensor formatter. See
``TensorFormatter`` for more information.
"""
self._space = space
def repr(self, comp, fun):
r"""
String representation of a primitive tensor, i.e. a function
times a tensor product of d's of the coordinate functions.
INPUT:
- ``comp`` -- a subscript of a differential form.
- ``fun`` -- the component function of this form.
EXAMPLES::
sage: from sage.tensor.tensor_element import TensorFormatter
sage: x, y, z = var('x, y, z')
sage: U = CoordinatePatch((x, y, z))
sage: D = TensorFormatter(U)
sage: D.repr((0, 1), z^3)
'z^3*dx@dy'
"""
str = "@".join( \
[('d%s' % self._space.coordinate(c).__repr__()) for c in comp])
if fun == 1 and len(comp) > 0:
# We have a non-trivial form whose component function is 1,
# so we just return the formatted form part and ignore the 1.
return str
else:
funstr = fun._repr_()
if not self._is_atomic(funstr):
funstr = '(' + funstr + ')'
if len(str) > 0:
return funstr + "*" + str
else:
return funstr
def latex(self, comp, fun):
r"""
Latex representation of a primitive differential form, i.e. a function
times a tensor product of d's of the coordinate functions.
INPUT:
- ``comp`` -- a subscript of a differential form.
- ``fun`` -- the component function of this form.
EXAMPLES::
sage: from sage.tensor.tensor_element import TensorFormatter
sage: x, y, z = var('x, y, z')
sage: U = CoordinatePatch((x, y, z))
sage: D = TensorFormatter(U)
sage: D.latex((0, 1), z^3)
'z^{3} d x \otimes d y'
"""
from sage.misc.latex import latex
str = " \otimes ".join( \
[('d %s' % latex(self._space.coordinate(c))) for c in comp])
if fun == 1 and len(comp) > 0:
return str
else:
funstr = latex(fun)
if not self._is_atomic(funstr):
funstr = '(' + funstr + ')'
return funstr + " " + str
def _is_atomic(self, str):
r"""
Helper function to check whether a given string expression
is atomic.
EXAMPLES::
sage: x, y, z = var('x, y, z')
sage: U = CoordinatePatch((x, y, z))
sage: from sage.tensor.tensor_element import TensorFormatter
sage: D = TensorFormatter(U)
sage: D._is_atomic('a + b')
False
sage: D._is_atomic('(a + b)')
True
"""
level = 0
for n, c in enumerate(str):
if c == '(':
level += 1
elif c == ')':
level -= 1
if c == '+' or c == '-':
if level == 0 and n > 0:
return False
return True
The only I’ve changed here is “DifferentialForm” by “Tensor” and “\wedge” by “\otimes”
The above code allows to write the tensor product in a basis, . The chosen symbol for denoting the tensor product was @.
Tensor Class
This code is incomplete due to:
I’ve not defined the TensorsAlgebra, which should be done in parallel.
There are a lot of attributes not presented in this class.
class Tensor(AlgebraElement):
r"""
Tensor class.
"""
def __init__(self, parent, degree, fun = None):
r"""
Construct a tensor.
INPUT:
- ``parent`` -- Parent algebra of tensors.
- ``degree`` -- Degree of the tensor.
- ``fun`` (default: None) -- Initialize this differential form with the given function. If the degree is not zero, this argument is silently ignored.
EXAMPLES::
sage: x, y, z = var('x, y, z')
sage: F = Tensors(); F
Algebra of tensors in the variables x, y, z
sage: f = Tensor(F, 0, sin(z)); f
sin(z)
"""
from sage.tensor.tensorss import Tensors
if not isinstance(parent, Tensors):
raise TypeError, "Parent not an algebra of tensors."
RingElement.__init__(self, parent)
self._degree = degree
self._components = {}
if degree == 0 and fun is not None:
self.__setitem__([], fun)
def __getitem__(self, subscript):
r"""
Return a given component of the tensor.
INPUT:
- ``subscript``: subscript of the component. Must be an integer
or a list of integers.
EXAMPLES::
sage: x, y, z = var('x, y, z')
sage: F = Tensors(); F
Algebra of tensors in the variables x, y, z
sage: f = Tensor(F, 0, sin(x*y)); f
sin(x*y)
sage: f[()]
sin(x*y)
"""
if isinstance(subscript, (Integer, int)):
subscript = (subscript, )
else:
subscript = tuple(subscript)
dim = self.parent().base_space().dim()
if any([s >= dim for s in subscript]):
raise ValueError, "Index out of bounds."
if len(subscript) != self._degree:
raise TypeError, "%s is not a subscript of degree %s" %\
(subscript, self._degree)
"""sign, subscript = sort_subscript(subscript)"""
if subscript in self._components:
return sign*self._components[subscript]
else:
return 0
def __setitem__(self, subscript, fun):
r"""
Modify a given component of the tensor.
INPUT:
- ``subscript``: subscript of the component. Must be an integer or a list of integers.
EXAMPLES::
sage: F = Tensors(); F
Algebra of tensors in the variables x, y, z
sage: f = Tensor(F, 2)
sage: f[1, 2] = x; f
x*dy@dz
"""
if isinstance(subscript, (Integer, int)):
subscript = (subscript, )
else:
subscript = tuple(subscript)
dim = self.parent().base_space().dim()
if any([s >= dim for s in subscript]):
raise ValueError, "Index out of bounds."
if len(subscript) != self._degree:
raise TypeError, "%s is not a subscript of degree %s" %\
(subscript, self._degree)
"""sign, subscript = sort_subscript(subscript)"""
self._components[subscript] = SR(fun)
Ok, so again I’ve changed “DifferentialForm(s)” by “Tensor(s)”, drop the permutation of indices (’cause tensors do not need to be neither symmetric nor anti-symmetric.
I’ll keep working with this code… It’s all by now. Oh! I’ll post next week the rest of the code based in Sergey’s GRPy.
Enjoy.
Dox
51.609574
-3.980685
Read Full Post »