Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/sage/categories/tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
# ****************************************************************************

from sage.categories.covariant_functorial_construction import CovariantFunctorialConstruction, CovariantConstructionCategory
from sage.categories.pushout import MultivariateConstructionFunctor
from sage.typeset.unicode_characters import unicode_otimes


class TensorProductFunctor(CovariantFunctorialConstruction):
class TensorProductFunctor(CovariantFunctorialConstruction, MultivariateConstructionFunctor):
"""
A singleton class for the tensor functor.

Expand Down Expand Up @@ -51,7 +52,24 @@ class TensorProductFunctor(CovariantFunctorialConstruction):
_functor_category = "TensorProducts"
symbol = " # "
unicode_symbol = f" {unicode_otimes} "
def __init__(self, category=None):
r"""
Constructor. See :class:`TensorProductFunctor` for details.

TESTS::

sage: from sage.categories.tensor import TensorProductFunctor
sage: TensorProductFunctor()
The tensor functorial construction
"""
CovariantFunctorialConstruction.__init__(self)
self._forced_category = category
from sage.categories.rings import Rings
if self._forced_category is not None:
codomain = self._forced_category
else:
codomain = Rings()
MultivariateConstructionFunctor.__init__(self, Rings(), codomain)
Comment on lines +65 to +72
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this blindly, by copy-pasting from CartesianProductFunctor. Rings() is almost certainly wrong, I have no idea how the correct category is chosen.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main thing of the _forced_category is to pass it along through the __call__ in the cartesian_product as the construction that is being used might need more conditions (e.g., if something was a ring constructed as a Cartesian product [of rings]). On its own, there isn't any use. Rings() is also too strong as a default category; Modules(base_ring.category()) is likely the best.


tensor = TensorProductFunctor()

Expand Down
12 changes: 8 additions & 4 deletions src/sage/combinat/free_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,10 +503,13 @@ def change_ring(self, R):
return self
construction = self.construction()
if construction is not None:
functor, _ = construction
functor, args = construction
from sage.categories.pushout import VectorFunctor
from sage.categories.tensor import TensorProductFunctor
if isinstance(functor, VectorFunctor):
return functor(R)
if isinstance(functor, TensorProductFunctor):
return functor([f.change_ring(R) for f in args])
raise NotImplementedError('the method change_ring() has not yet been implemented')

# For backwards compatibility
Expand Down Expand Up @@ -1259,8 +1262,8 @@ class CombinatorialFreeModule_Tensor(CombinatorialFreeModule):
Category of tensor products of
finite dimensional modules with basis over Integer Ring

sage: T.construction() # todo: not implemented
[tensor, ]
sage: T.construction()
(The tensor functorial construction, (F, G))

T is a free module, with same base ring as F and G::

Expand Down Expand Up @@ -1347,7 +1350,8 @@ def __classcall_private__(cls, modules, **options):
assert (all(module in ModulesWithBasis(R)) for module in modules)
# should check the base ring
# flatten the list of modules so that tensor(A, tensor(B,C)) gets rewritten into tensor(A, B, C)
modules = sum([module._sets if isinstance(module, CombinatorialFreeModule_Tensor) else (module,) for module in modules], ())
modules = sum([module._sets if isinstance(module, CombinatorialFreeModule_Tensor) else (module,)
for module in modules], ())
if all('FiniteDimensional' in M.category().axioms() for M in modules):
options['category'] = options['category'].FiniteDimensional()
return super(CombinatorialFreeModule.Tensor, cls).__classcall__(cls, modules, **options)
Expand Down