Basic work on tensor components

My SageManifolds notebooks typically start with a bunch of home made function designed to access components of tensors. But they are based on a common hacky function relying on very shallow understanding of the internals of SageManifolds. Am I missing some builtin equivalent? What is the proper way of doing this?

def maps(fun, tensor):
""" Applies fun to all components of a copy of tensor """
res = tensor.copy()
if tensor.tensor_type() == (0, 0):
for k, v in res._express.items():
res._express[k] = k.function(fun(v.expr()))
else:
for k, v in res.comp()._comp.items():
res.comp()._comp[k] = res.domain().scalar_field(fun(v.expr()))
return res

def simp(tensor):
return maps(lambda f: simplify(f), tensor)

def dev(tensor):
return maps(lambda f: expand(f), tensor)

def factorize(tensor):
return maps(lambda f: factor(f), tensor)

def subs(tensor, d):
return maps(lambda f: f.subs(d), tensor)

`

edit retag close merge delete

Sort by » oldest newest most voted

For the moment, there is no builtin equivalent. Your way of implementing this is basically correct. However, I would not perform the loop on res but rather on tensor, in order to avoid looping on the items of a dictionary while modifying it, especially when items() becomes an iterator in Python3. Moreover, one can replace

res._express[k] = k.function(fun(v.expr()))

by

and one can use recursivity to simplify the tensor part, i.e. replace

res.comp()._comp[k] = res.domain().scalar_field(fun(v.expr()))

by

res.comp()._comp[k] = maps(fun, v)

Finally, the tensor part of your code is valid only for the manifold's default frame (because res.comp() returns the components with respect to that frame). It can easily be generalized to any frame by adding the argument frame=None to maps and replacing comp() by comp(frame).

With the above changes, the code becomes:

def maps(fun, tensor, frame=None):
""" Applies fun to all components of a copy of tensor """
res = tensor.copy()
if tensor.tensor_type() == (0, 0):
for k, v in tensor._express.items():
else:
for k, v in tensor.comp(frame)._comp.items():
res.comp(frame)._comp[k] = maps(fun, v)
return res
more

Thank you very much! I think it would make sense to add this to the lib (as well as a method doing this in place instead of a root namespace function returning a new object). I use SageManifolds only when computations are complicated, and then I always need simplify and his friends expand and factor.

Indeed, this would make sense. Note that internally, all tensor computations use simplifications according to this simplifying sequence. But this does not involve factor for instance, nor any specific substitution. Would you agree to create a ticket implementing this? (see e.g. these possible guide lines)