Skip to content

Commit

Permalink
Trac #34448: Put tensor modules of FiniteRankFreeModule in Modules().…
Browse files Browse the repository at this point in the history
…TensorProducts()

... and add the method `tensor_factors` (#34393)

also add construction functors for tensor modules, extending #30235.

URL: https://trac.sagemath.org/34448
Reported by: mkoeppe
Ticket author(s): Matthias Koeppe
Reviewer(s): Eric Gourgoulhon
  • Loading branch information
Release Manager committed Sep 28, 2022
2 parents eafc6c7 + e10f9cf commit 3bf2df7
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 38 deletions.
6 changes: 3 additions & 3 deletions src/sage/manifolds/differentiable/manifold.py
Original file line number Diff line number Diff line change
Expand Up @@ -1438,9 +1438,9 @@ def tensor_field_module(self, tensor_type, dest_map=None):
Free module T^(2,1)(U) of type-(2,1) tensors fields on the Open
subset U of the 3-dimensional differentiable manifold M
sage: TU.category()
Category of finite dimensional modules over Algebra of
differentiable scalar fields on the Open subset U of the
3-dimensional differentiable manifold M
Category of tensor products of finite dimensional modules
over Algebra of differentiable scalar fields
on the Open subset U of the 3-dimensional differentiable manifold M
sage: TU.base_ring()
Algebra of differentiable scalar fields on the Open subset U of
the 3-dimensional differentiable manifold M
Expand Down
4 changes: 2 additions & 2 deletions src/sage/manifolds/differentiable/tensorfield_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,8 +652,8 @@ class TensorFieldFreeModule(TensorFreeModule):
`T^{(2,0)}(\RR^3)` is a module over the algebra `C^k(\RR^3)`::
sage: T20.category()
Category of finite dimensional modules over Algebra of differentiable
scalar fields on the 3-dimensional differentiable manifold R^3
Category of tensor products of finite dimensional modules over
Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold R^3
sage: T20.base_ring() is M.scalar_field_algebra()
True
Expand Down
10 changes: 7 additions & 3 deletions src/sage/manifolds/differentiable/vectorfield_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ def destination_map(self):
"""
return self._dest_map

def tensor_module(self, k, l):
def tensor_module(self, k, l, *, sym=None, antisym=None):
r"""
Return the module of type-`(k,l)` tensors on ``self``.
Expand Down Expand Up @@ -552,6 +552,8 @@ def tensor_module(self, k, l):
for more examples and documentation.
"""
if sym or antisym:
raise NotImplementedError
try:
return self._tensor_modules[(k,l)]
except KeyError:
Expand Down Expand Up @@ -1731,7 +1733,7 @@ def destination_map(self) -> DiffMap:
"""
return self._dest_map

def tensor_module(self, k, l):
def tensor_module(self, k, l, *, sym=None, antisym=None):
r"""
Return the free module of all tensors of type `(k, l)` defined
on ``self``.
Expand Down Expand Up @@ -1780,6 +1782,8 @@ def tensor_module(self, k, l):
for more examples and documentation.
"""
if sym or antisym:
raise NotImplementedError
try:
return self._tensor_modules[(k,l)]
except KeyError:
Expand Down Expand Up @@ -2031,7 +2035,7 @@ def basis(self, symbol=None, latex_symbol=None, from_frame=None,
symbol_dual=symbol_dual,
latex_symbol_dual=latex_symbol_dual)

def tensor(self, tensor_type, name=None, latex_name=None, sym=None,
def _tensor(self, tensor_type, name=None, latex_name=None, sym=None,
antisym=None, specific_type=None):
r"""
Construct a tensor on ``self``.
Expand Down
121 changes: 100 additions & 21 deletions src/sage/tensor/modules/finite_rank_free_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,28 @@ def map_isym(isym):
result._index_maps = tuple(index_maps)
return result

def tensor(self, *args, **kwds):
# Until https://trac.sagemath.org/ticket/30373 is done,
# TensorProductFunctor._functor_name is "tensor", so here we delegate.
r"""
Return the tensor product of ``self`` and ``others``.
This method is invoked when :class:`~sage.categories.tensor.TensorProductFunctor`
is applied to parents.
It just delegates to :meth:`tensor_product`.
EXAMPLES::
sage: M = FiniteRankFreeModule(QQ, 2); M
2-dimensional vector space over the Rational Field
sage: M20 = M.tensor_module(2, 0); M20
Free module of type-(2,0) tensors on the 2-dimensional vector space over the Rational Field
sage: tensor([M20, M20])
Free module of type-(4,0) tensors on the 2-dimensional vector space over the Rational Field
"""
return self.tensor_product(*args, **kwds)

def rank(self) -> int:
r"""
Return the rank of the free module ``self``.
Expand Down Expand Up @@ -2122,7 +2144,7 @@ def _test_basis(self, tester=None, **options):
TestSuite(b).run(verbose=tester._verbose, prefix=tester._prefix + " ",
raise_on_failure=is_sub_testsuite)

def tensor(self, tensor_type, name=None, latex_name=None, sym=None,
def _tensor(self, tensor_type, name=None, latex_name=None, sym=None,
antisym=None):
r"""
Construct a tensor on the free module ``self``.
Expand All @@ -2131,10 +2153,81 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None,
- ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the
contravariant rank and ``l`` the covariant rank
- ``name`` -- (default: ``None``) string; name given to the tensor
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
denote the tensor; if none is provided, the LaTeX symbol is set
to ``name``
- ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries
among the tensor arguments: each symmetry is described by a tuple
containing the positions of the involved arguments, with the
convention ``position = 0`` for the first argument. For instance:
* ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments
* ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd
arguments and a symmetry between the 2nd, 4th and 5th arguments.
- ``antisym`` -- (default: ``None``) antisymmetry or iterable of
antisymmetries among the arguments, with the same convention
as for ``sym``
OUTPUT:
- instance of
:class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`
representing the tensor defined on ``self`` with the provided
characteristics
EXAMPLES:
Tensors on a rank-3 free module::
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: t = M._tensor((1,0), name='t') ; t
Element t of the Rank-3 free module M over the Integer Ring
"""
from .comp import CompWithSym
sym, antisym = CompWithSym._canonicalize_sym_antisym(
tensor_type[0] + tensor_type[1], sym, antisym)
# Special cases:
if tensor_type == (1,0):
return self.element_class(self, name=name, latex_name=latex_name)
elif tensor_type == (0,1):
return self.linear_form(name=name, latex_name=latex_name)
elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym:
if len(antisym[0]) == tensor_type[1]:
return self.alternating_form(tensor_type[1], name=name,
latex_name=latex_name)
elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym:
if len(antisym[0]) == tensor_type[0]:
return self.alternating_contravariant_tensor(tensor_type[0],
name=name, latex_name=latex_name)
# Generic case:
return self.tensor_module(*tensor_type).element_class(self,
tensor_type, name=name, latex_name=latex_name,
sym=sym, antisym=antisym)

def tensor(self, *args, **kwds):
r"""
Construct a tensor on the free module ``self`` or a tensor product with other modules.
If ``args`` consist of other parents, just delegate to :meth:`tensor_product`.
Otherwise, construct a tensor from the following input.
INPUT:
- ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the
contravariant rank and ``l`` the covariant rank
- ``name`` -- (default: ``None``) string; name given to the tensor
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
denote the tensor; if none is provided, the LaTeX symbol is set
to ``name``
- ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries
among the tensor arguments: each symmetry is described by a tuple
containing the positions of the involved arguments, with the
Expand Down Expand Up @@ -2189,26 +2282,12 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None,
sage: M.tensor((3,0), antisym=[[]])
Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring
"""
from .comp import CompWithSym
sym, antisym = CompWithSym._canonicalize_sym_antisym(
tensor_type[0] + tensor_type[1], sym, antisym)
# Special cases:
if tensor_type == (1,0):
return self.element_class(self, name=name, latex_name=latex_name)
elif tensor_type == (0,1):
return self.linear_form(name=name, latex_name=latex_name)
elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym:
if len(antisym[0]) == tensor_type[1]:
return self.alternating_form(tensor_type[1], name=name,
latex_name=latex_name)
elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym:
if len(antisym[0]) == tensor_type[0]:
return self.alternating_contravariant_tensor(tensor_type[0],
name=name, latex_name=latex_name)
# Generic case:
return self.tensor_module(*tensor_type).element_class(self,
tensor_type, name=name, latex_name=latex_name,
sym=sym, antisym=antisym)
# Until https://trac.sagemath.org/ticket/30373 is done,
# TensorProductFunctor._functor_name is "tensor", so this method
# also needs to double as the tensor product construction
if isinstance(args[0], Parent):
return self.tensor_product(*args, **kwds)
return self._tensor(*args, **kwds)

def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None):
r"""
Expand Down
33 changes: 24 additions & 9 deletions src/sage/tensor/modules/tensor_free_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
# http://www.gnu.org/licenses/
#******************************************************************************

from sage.categories.modules import Modules
from sage.misc.cachefunc import cached_method
from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule_abstract
from sage.tensor.modules.free_module_tensor import FreeModuleTensor
Expand Down Expand Up @@ -126,7 +127,7 @@ class TensorFreeModule(FiniteRankFreeModule_abstract):
``T`` is a module (actually a free module) over `\ZZ`::
sage: T.category()
Category of finite dimensional modules over Integer Ring
Category of tensor products of finite dimensional modules over Integer Ring
sage: T in Modules(ZZ)
True
sage: T.rank()
Expand Down Expand Up @@ -336,7 +337,7 @@ class TensorFreeModule(FiniteRankFreeModule_abstract):

Element = FreeModuleTensor

def __init__(self, fmodule, tensor_type, name=None, latex_name=None):
def __init__(self, fmodule, tensor_type, name=None, latex_name=None, category=None):
r"""
TESTS::
Expand All @@ -347,33 +348,47 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None):
"""
self._fmodule = fmodule
self._tensor_type = tuple(tensor_type)
ring = fmodule._ring
rank = pow(fmodule._rank, tensor_type[0] + tensor_type[1])
if self._tensor_type == (0,1): # case of the dual
category = Modules(ring).FiniteDimensional().or_subcategory(category)
if name is None and fmodule._name is not None:
name = fmodule._name + '*'
if latex_name is None and fmodule._latex_name is not None:
latex_name = fmodule._latex_name + r'^*'
else:
category = Modules(ring).FiniteDimensional().TensorProducts().or_subcategory(category)
if name is None and fmodule._name is not None:
name = 'T^' + str(self._tensor_type) + '(' + fmodule._name + \
')'
if latex_name is None and fmodule._latex_name is not None:
latex_name = r'T^{' + str(self._tensor_type) + r'}\left(' + \
fmodule._latex_name + r'\right)'
super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name)
super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name, category=category)
fmodule._all_modules.add(self)

def construction(self):
def tensor_factors(self):
r"""
TESTS::
Return the tensor factors of this tensor module.
EXAMPLES::
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: T = M.tensor_module(2, 3)
sage: T.construction() is None
True
sage: T.tensor_factors()
[Rank-3 free module M over the Integer Ring,
Rank-3 free module M over the Integer Ring,
Dual of the Rank-3 free module M over the Integer Ring,
Dual of the Rank-3 free module M over the Integer Ring,
Dual of the Rank-3 free module M over the Integer Ring]
"""
# No construction until https://trac.sagemath.org/ticket/31276 provides tensor_product methods
return None
if self._tensor_type == (0,1): # case of the dual
raise NotImplementedError
factors = [self._fmodule] * self._tensor_type[0]
dmodule = self._fmodule.dual()
if self._tensor_type[1]:
factors += [dmodule] * self._tensor_type[1]
return factors

#### Parent Methods

Expand Down
18 changes: 18 additions & 0 deletions src/sage/tensor/modules/tensor_free_submodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,24 @@ def power_name(op, s, latex=False):
latex_name=latex_name,
category=category, ambient=ambient)

def construction(self):
# TODO: Define the symmetry group and its action (https://trac.sagemath.org/ticket/34495),
# return the construction functor for invariant subobjects.
r"""
Return the functorial construction of ``self``.
This implementation just returns ``None``.
EXAMPLES::
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: Sym2M = M.tensor_module(2, 0, sym=range(2)); Sym2M
Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring
sage: Sym2M.construction() is None
True
"""
return None

@cached_method
def _basis_sym(self):
r"""
Expand Down

0 comments on commit 3bf2df7

Please sign in to comment.