# Tensor products of free modules¶

The class TensorFreeModule implements tensor products of the type

$T^{(k,l)}(M) = \underbrace{M\otimes\cdots\otimes M}_{k\ \; \mbox{times}} \otimes \underbrace{M^*\otimes\cdots\otimes M^*}_{l\ \; \mbox{times}},$

where $$M$$ is a free module of finite rank over a commutative ring $$R$$ and $$M^*=\mathrm{Hom}_R(M,R)$$ is the dual of $$M$$. Note that $$T^{(1,0)}(M) = M$$ and $$T^{(0,1)}(M) = M^*$$.

Thanks to the canonical isomorphism $$M^{**} \simeq M$$ (which holds since $$M$$ is a free module of finite rank), $$T^{(k,l)}(M)$$ can be identified with the set of tensors of type $$(k,l)$$ defined as multilinear maps

$\underbrace{M^*\times\cdots\times M^*}_{k\ \; \mbox{times}} \times \underbrace{M\times\cdots\times M}_{l\ \; \mbox{times}} \longrightarrow R$

Accordingly, TensorFreeModule is a Sage parent class, whose element class is FreeModuleTensor.

$$T^{(k,l)}(M)$$ is itself a free module over $$R$$, of rank $$n^{k+l}$$, $$n$$ being the rank of $$M$$. Accordingly the class TensorFreeModule inherits from the class FiniteRankFreeModule.

Todo

implement more general tensor products, i.e. tensor product of the type $$M_1\otimes\cdots\otimes M_n$$, where the $$M_i$$’s are $$n$$ free modules of finite rank over the same ring $$R$$.

AUTHORS:

• Eric Gourgoulhon, Michal Bejger (2014-2015): initial version

REFERENCES:

class sage.tensor.modules.tensor_free_module.TensorFreeModule(fmodule, tensor_type, name=None, latex_name=None)

Class for the free modules over a commutative ring $$R$$ that are tensor products of a given free module $$M$$ over $$R$$ with itself and its dual $$M^*$$:

$T^{(k,l)}(M) = \underbrace{M\otimes\cdots\otimes M}_{k\ \; \mbox{times}} \otimes \underbrace{M^*\otimes\cdots\otimes M^*}_{l\ \; \mbox{times}}$

As recalled above, $$T^{(k,l)}(M)$$ can be canonically identified with the set of tensors of type $$(k,l)$$ on $$M$$.

This is a Sage parent class, whose element class is FreeModuleTensor.

INPUT:

• fmodule – free module $$M$$ of finite rank over a commutative ring $$R$$, as an instance of FiniteRankFreeModule
• 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 module
• latex_name – (default: None) string; LaTeX symbol to denote the tensor module; if none is provided, it is set to name

EXAMPLES:

Set of tensors of type $$(1,2)$$ on a free $$\ZZ$$-module of rank 3:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: from sage.tensor.modules.tensor_free_module import TensorFreeModule
sage: T = TensorFreeModule(M, (1,2)) ; T
Free module of type-(1,2) tensors on the
Rank-3 free module M over the Integer Ring


Instead of importing TensorFreeModule in the global name space, it is recommended to use the module’s method tensor_module():

sage: T = M.tensor_module(1,2) ; T
Free module of type-(1,2) tensors on the
Rank-3 free module M over the Integer Ring
sage: latex(T)
T^{(1, 2)}\left(M\right)


The module M itself is considered as the set of tensors of type $$(1,0)$$:

sage: M is M.tensor_module(1,0)
True


T is a module (actually a free module) over $$\ZZ$$:

sage: T.category()
Category of finite dimensional modules over Integer Ring
sage: T in Modules(ZZ)
True
sage: T.rank()
27
sage: T.base_ring()
Integer Ring
sage: T.base_module()
Rank-3 free module M over the Integer Ring


T is a parent object, whose elements are instances of FreeModuleTensor:

sage: t = T.an_element() ; t
Type-(1,2) tensor on the Rank-3 free module M over the Integer Ring
sage: from sage.tensor.modules.free_module_tensor import FreeModuleTensor
sage: isinstance(t, FreeModuleTensor)
True
sage: t in T
True
sage: T.is_parent_of(t)
True


Elements can be constructed from T. In particular, 0 yields the zero element of T:

sage: T(0)
Type-(1,2) tensor zero on the Rank-3 free module M over the Integer Ring
sage: T(0) is T.zero()
True


while non-zero elements are constructed by providing their components in a given basis:

sage: e
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
sage: comp = [[[i-j+k for k in range(3)] for j in range(3)] for i in range(3)]
sage: t = T(comp, basis=e, name='t') ; t
Type-(1,2) tensor t on the Rank-3 free module M over the Integer Ring
sage: t.comp(e)[:]
[[[0, 1, 2], [-1, 0, 1], [-2, -1, 0]],
[[1, 2, 3], [0, 1, 2], [-1, 0, 1]],
[[2, 3, 4], [1, 2, 3], [0, 1, 2]]]
sage: t.display(e)
t = e_0*e^0*e^1 + 2 e_0*e^0*e^2 - e_0*e^1*e^0 + e_0*e^1*e^2
- 2 e_0*e^2*e^0 - e_0*e^2*e^1 + e_1*e^0*e^0 + 2 e_1*e^0*e^1
+ 3 e_1*e^0*e^2 + e_1*e^1*e^1 + 2 e_1*e^1*e^2 - e_1*e^2*e^0
+ e_1*e^2*e^2 + 2 e_2*e^0*e^0 + 3 e_2*e^0*e^1 + 4 e_2*e^0*e^2
+ e_2*e^1*e^0 + 2 e_2*e^1*e^1 + 3 e_2*e^1*e^2 + e_2*e^2*e^1
+ 2 e_2*e^2*e^2


An alternative is to construct the tensor from an empty list of components and to set the nonzero components afterwards:

sage: t = T([], name='t')
sage: t.set_comp(e)[0,1,1] = -3
sage: t.set_comp(e)[2,0,1] = 4
sage: t.display(e)
t = -3 e_0*e^1*e^1 + 4 e_2*e^0*e^1


See the documentation of FreeModuleTensor for the full list of arguments that can be provided to the __call__ operator. For instance, to construct a tensor symmetric with respect to the last two indices:

sage: t = T([], name='t', sym=(1,2))
sage: t.set_comp(e)[0,1,1] = -3
sage: t.set_comp(e)[2,0,1] = 4
sage: t.display(e)  # notice that t^2_{10} has be set equal to t^2_{01} by symmetry
t = -3 e_0*e^1*e^1 + 4 e_2*e^0*e^1 + 4 e_2*e^1*e^0


The tensor modules over a given module $$M$$ are unique:

sage: T is M.tensor_module(1,2)
True


There is a coercion map from $$\Lambda^p(M^*)$$, the set of alternating forms of degree $$p$$, to $$T^{(0,p)}(M)$$:

sage: L2 = M.dual_exterior_power(2) ; L2
2nd exterior power of the dual of the Rank-3 free module M over the
Integer Ring
sage: T02 = M.tensor_module(0,2) ; T02
Free module of type-(0,2) tensors on the Rank-3 free module M over the
Integer Ring
sage: T02.has_coerce_map_from(L2)
True


Of course, for $$p\geq 2$$, there is no coercion in the reverse direction, since not every tensor of type $$(0,p)$$ is alternating:

sage: L2.has_coerce_map_from(T02)
False


The coercion map $$\Lambda^2(M^*)\rightarrow T^{(0,2)}(M)$$ in action:

sage: a = M.alternating_form(2, name='a') ; a
Alternating form a of degree 2 on the Rank-3 free module M over the
Integer Ring
sage: a[0,1], a[1,2] = 4, -3
sage: a.display(e)
a = 4 e^0/\e^1 - 3 e^1/\e^2
sage: a.parent() is L2
True
sage: ta = T02(a) ; ta
Type-(0,2) tensor a on the Rank-3 free module M over the Integer Ring
sage: ta.display(e)
a = 4 e^0*e^1 - 4 e^1*e^0 - 3 e^1*e^2 + 3 e^2*e^1
sage: ta.symmetries() # the antisymmetry is of course preserved
no symmetry;  antisymmetry: (0, 1)


For the degree $$p=1$$, there is a coercion in both directions:

sage: L1 = M.dual_exterior_power(1) ; L1
Dual of the Rank-3 free module M over the Integer Ring
sage: T01 = M.tensor_module(0,1) ; T01
Free module of type-(0,1) tensors on the Rank-3 free module M over the
Integer Ring
sage: T01.has_coerce_map_from(L1)
True
sage: L1.has_coerce_map_from(T01)
True


The coercion map $$\Lambda^1(M^*)\rightarrow T^{(0,1)}(M)$$ in action:

sage: a = M.linear_form('a')
sage: a[:] = -2, 4, 1 ; a.display(e)
a = -2 e^0 + 4 e^1 + e^2
sage: a.parent() is L1
True
sage: ta = T01(a) ; ta
Type-(0,1) tensor a on the Rank-3 free module M over the Integer Ring
sage: ta.display(e)
a = -2 e^0 + 4 e^1 + e^2


The coercion map $$T^{(0,1)}(M) \rightarrow \Lambda^1(M^*)$$ in action:

sage: ta.parent() is T01
True
sage: lta = L1(ta) ; lta
Linear form a on the Rank-3 free module M over the Integer Ring
sage: lta.display(e)
a = -2 e^0 + 4 e^1 + e^2
sage: lta == a
True


There is a canonical identification between tensors of type $$(1,1)$$ and endomorphisms of module $$M$$. Accordingly, coercion maps have been implemented between $$T^{(1,1)}(M)$$ and $$\mathrm{End}(M)$$ (the module of all endomorphisms of $$M$$, see FreeModuleHomset):

sage: T11 = M.tensor_module(1,1) ; T11
Free module of type-(1,1) tensors on the Rank-3 free module M over the
Integer Ring
sage: End(M)
Set of Morphisms from Rank-3 free module M over the Integer Ring
to Rank-3 free module M over the Integer Ring
in Category of finite dimensional modules over Integer Ring
sage: T11.has_coerce_map_from(End(M))
True
sage: End(M).has_coerce_map_from(T11)
True


The coercion map $$\mathrm{End}(M)\rightarrow T^{(1,1)}(M)$$ in action:

sage: phi = End(M).an_element() ; phi
Generic endomorphism of Rank-3 free module M over the Integer Ring
sage: phi.matrix(e)
[1 1 1]
[1 1 1]
[1 1 1]
sage: tphi = T11(phi) ; tphi # image of phi by the coercion map
Type-(1,1) tensor on the Rank-3 free module M over the Integer Ring
sage: tphi[:]
[1 1 1]
[1 1 1]
[1 1 1]
sage: t = M.tensor((1,1))
sage: t[0,0], t[1,1], t[2,2] = -1,-2,-3
sage: t[:]
[-1  0  0]
[ 0 -2  0]
[ 0  0 -3]
sage: s = t + phi ; s  # phi is coerced to a type-(1,1) tensor prior to the addition
Type-(1,1) tensor on the Rank-3 free module M over the Integer Ring
sage: s[:]
[ 0  1  1]
[ 1 -1  1]
[ 1  1 -2]


The coercion map $$T^{(1,1)}(M) \rightarrow \mathrm{End}(M)$$ in action:

sage: phi1 = End(M)(tphi) ; phi1
Generic endomorphism of Rank-3 free module M over the Integer Ring
sage: phi1 == phi
True
sage: s = phi + t ; s  # t is coerced to an endomorphism prior to the addition
Generic endomorphism of Rank-3 free module M over the Integer Ring
sage: s.matrix(e)
[ 0  1  1]
[ 1 -1  1]
[ 1  1 -2]


There is a coercion $$\mathrm{GL}(M)\rightarrow T^{(1,1)}(M)$$, i.e. from automorphisms of $$M$$ to type-$$(1,1)$$ tensors on $$M$$:

sage: GL = M.general_linear_group() ; GL
General linear group of the Rank-3 free module M over the Integer Ring
sage: T11.has_coerce_map_from(GL)
True


The coercion map $$\mathrm{GL}(M)\rightarrow T^{(1,1)}(M)$$ in action:

sage: a = GL.an_element() ; a
Automorphism of the Rank-3 free module M over the Integer Ring
sage: a.matrix(e)
[ 1  0  0]
[ 0 -1  0]
[ 0  0  1]
sage: ta = T11(a) ; ta
Type-(1,1) tensor on the Rank-3 free module M over the Integer Ring
sage: ta.display(e)
e_0*e^0 - e_1*e^1 + e_2*e^2
sage: a.display(e)
e_0*e^0 - e_1*e^1 + e_2*e^2


Of course, there is no coercion in the reverse direction, since not every type-$$(1,1)$$ tensor is invertible:

sage: GL.has_coerce_map_from(T11)
False

Element
base_module()

Return the free module on which self is constructed.

OUTPUT:

EXAMPLES:

Base module of a type-$$(1,2)$$ tensor module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: T = M.tensor_module(1,2)
sage: T.base_module()
Rank-3 free module M over the Integer Ring
sage: T.base_module() is M
True

tensor_type()

Return the tensor type of self.

OUTPUT:

• pair $$(k,l)$$ such that self is the module tensor product $$T^{(k,l)}(M)$$

EXAMPLES:

sage: M = FiniteRankFreeModule(ZZ, 3)
sage: T = M.tensor_module(1,2)
sage: T.tensor_type()
(1, 2)

zero()

Return the zero of self.

EXAMPLES:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: T11 = M.tensor_module(1,1)
sage: T11.zero()
Type-(1,1) tensor zero on the Rank-3 free module M over the Integer
Ring


The zero element is cached:

sage: T11.zero() is T11(0)
True