Skip to content

Commit

Permalink
Trac #34474: Make FiniteRankFreeModule.tensor_module(0, 1) return the…
Browse files Browse the repository at this point in the history
… dual

In Sage 9.7.rc0, we have
{{{
sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
sage: M.tensor_module(0, 1) is M.dual()
False
}}}
The identity of the two objects, which is mathematically exact, is
implemented here. This also simplifies some coercion maps.

URL: https://trac.sagemath.org/34474
Reported by: egourgoulhon
Ticket author(s): Eric Gourgoulhon
Reviewer(s): Matthias Koeppe
  • Loading branch information
Release Manager committed Sep 20, 2022
2 parents 5a41c49 + 803f7e4 commit 857f16c
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 109 deletions.
74 changes: 3 additions & 71 deletions src/sage/tensor/modules/ext_pow_free_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,21 +573,12 @@ class ExtPowerDualFreeModule(FiniteRankFreeModule_abstract):
sage: latex(M.dual())
M^*
Since any tensor of type (0,1) is a linear form, there is a coercion map
from the set `T^{(0,1)}(M)` of such tensors to `M^*`::
It also coincides with the module of type-`(0,1)` tensors::
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: M.dual().has_coerce_map_from(T01)
True
There is also a coercion map in the reverse direction::
sage: T01.has_coerce_map_from(M.dual())
sage: M.dual_exterior_power(1) is M.tensor_module(0,1)
True
For a degree `p\geq 2`, the coercion holds only in the direction
For a degree `p\geq 2`, there is a coercion map
`\Lambda^p(M^*)\rightarrow T^{(0,p)}(M)`::
sage: T02 = M.tensor_module(0,2) ; T02
Expand All @@ -598,24 +589,6 @@ class ExtPowerDualFreeModule(FiniteRankFreeModule_abstract):
sage: A.has_coerce_map_from(T02)
False
The coercion map `T^{(0,1)}(M) \rightarrow M^*` in action::
sage: b = T01([-2,1,4], basis=e, name='b') ; b
Type-(0,1) tensor b on the Rank-3 free module M over the Integer Ring
sage: b.display(e)
b = -2 e^0 + e^1 + 4 e^2
sage: lb = M.dual()(b) ; lb
Linear form b on the Rank-3 free module M over the Integer Ring
sage: lb.display(e)
b = -2 e^0 + e^1 + 4 e^2
The coercion map `M^* \rightarrow T^{(0,1)}(M)` in action::
sage: tlb = T01(lb) ; tlb
Type-(0,1) tensor b on the Rank-3 free module M over the Integer Ring
sage: tlb == b
True
The coercion map `\Lambda^2(M^*)\rightarrow T^{(0,2)}(M)` in action::
sage: ta = T02(a) ; ta
Expand Down Expand Up @@ -783,47 +756,6 @@ def _an_element_(self):
resu.set_comp()[ind] = self._fmodule._ring.an_element()
return resu

def _coerce_map_from_(self, other):
r"""
Determine whether coercion to ``self`` exists from other parent.
EXAMPLES:
Sets of type-`(0,1)` tensors coerce to ``self`` if the degree is 1::
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
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: L1._coerce_map_from_(T01)
True
Of course, coercions from other tensor types are meaningless::
sage: L1._coerce_map_from_(M.tensor_module(1,0))
False
sage: L1._coerce_map_from_(M.tensor_module(0,2))
False
If the degree is larger than 1, there is no coercion::
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: L2._coerce_map_from_(M.tensor_module(0,2))
False
"""
from sage.tensor.modules.tensor_free_module import TensorFreeModule
if isinstance(other, TensorFreeModule):
# coercion of a type-(0,1) tensor to a linear form
if self._fmodule is other._fmodule and self._degree == 1 and \
other.tensor_type() == (0,1):
return True
return False

#### End of parent methods

@cached_method
Expand Down
9 changes: 8 additions & 1 deletion src/sage/tensor/modules/finite_rank_free_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -1195,11 +1195,16 @@ def tensor_module(self, k, l):
sage: M.tensor_module(1,2) is T
True
The base module is itself the module of all type-`(1,0)` tensors::
The module of type-`(1,0)` tensors is the base module itself::
sage: M.tensor_module(1,0) is M
True
while the module of type-`(0,1)` tensors is the dual of the base module::
sage: M.tensor_module(0, 1) is M.dual()
True
See :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule`
for more documentation.
Expand All @@ -1209,6 +1214,8 @@ def tensor_module(self, k, l):
except KeyError:
if (k, l) == (1, 0):
T = self
elif (k, l) == (0, 1):
T = self.dual()
else:
from sage.tensor.modules.tensor_free_module import TensorFreeModule
T = TensorFreeModule(self, (k,l))
Expand Down
41 changes: 4 additions & 37 deletions src/sage/tensor/modules/tensor_free_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,39 +237,11 @@ class TensorFreeModule(FiniteRankFreeModule_abstract):
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::
For the degree `p=1`, we have the identity `\Lambda^1(M^*) = T^{(0,1)}(M) = M^*`::
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)
sage: M.dual_exterior_power(1) is M.tensor_module(0,1)
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
sage: M.tensor_module(0,1) is M.dual()
True
There is a canonical identification between tensors of type `(1,1)` and
Expand Down Expand Up @@ -571,7 +543,7 @@ def _coerce_map_from_(self, other):
but not to tensor modules of other types::
sage: M.tensor_module(0,1)._coerce_map_from_(End(M))
sage: M.tensor_module(0,2)._coerce_map_from_(End(M))
False
and not to type-`(1,1)` tensor modules defined on another free module::
Expand All @@ -597,8 +569,6 @@ def _coerce_map_from_(self, other):
Coercion from alternating forms::
sage: M.tensor_module(0,1)._coerce_map_from_(M.dual_exterior_power(1))
True
sage: M.tensor_module(0,2)._coerce_map_from_(M.dual_exterior_power(2))
True
sage: M.tensor_module(0,2)._coerce_map_from_(M.dual_exterior_power(3))
Expand Down Expand Up @@ -645,9 +615,6 @@ def _repr_(self):
sage: M.tensor_module(1,1)
Free module of type-(1,1) tensors on the 2-dimensional vector space
M over the Rational Field
sage: M.tensor_module(0,1)
Free module of type-(0,1) tensors on the 2-dimensional vector space
M over the Rational Field
"""
description = "Free module of type-({},{}) tensors on the {}".format(
Expand Down

0 comments on commit 857f16c

Please sign in to comment.