diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 686af0d3505..445862d6795 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -647,7 +647,7 @@ def set(self, symbiform): raise TypeError("the argument must be a tensor field") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if not symbiform._domain.is_subset(self._domain): raise TypeError("the symmetric bilinear form is not defined " + @@ -2301,7 +2301,7 @@ def set(self, symbiform): "values on a parallelizable domain") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if symbiform._vmodule is not self._vmodule: raise TypeError("the symmetric bilinear form and the metric are " + @@ -2781,7 +2781,7 @@ def set(self, symbiform): raise TypeError("the argument must be a tensor field") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if not symbiform._domain.is_subset(self._domain): raise TypeError("the symmetric bilinear form is not defined " + @@ -3019,7 +3019,7 @@ def set(self, symbiform): "values on a parallelizable domain") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if symbiform._vmodule is not self._vmodule: raise TypeError("the symmetric bilinear form and the metric are " + diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index 2eaef7510c8..3aef31eb703 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -1173,7 +1173,7 @@ def ambient_second_fundamental_form(self): g.restrict(chart.domain()).contract(pf[j]) * self.scalar_field({chart: k.comp(chart.frame())[:][i, j]}) for i in range(self._dim) for j in range(self._dim)) - gam_rst._sym = [(0, 1)] + gam_rst._sym = ((0, 1),) self._ambient_second_fundamental_form.set_restriction(gam_rst) charts = iter(self.top_charts()) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index d5b63c9d81d..a2aad4d4937 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -58,6 +58,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.structure.element import ModuleElementWithMutability +from sage.tensor.modules.comp import CompWithSym from sage.tensor.modules.free_module_tensor import FreeModuleTensor from sage.tensor.modules.tensor_with_indices import TensorWithIndices @@ -495,40 +496,8 @@ def __init__( self._restrictions = {} # dict. of restrictions of self on subdomains # of self._domain, with the subdomains as keys # Treatment of symmetry declarations: - self._sym = [] - if sym is not None and sym != []: - if isinstance(sym[0], (int, Integer)): - # a single symmetry is provided as a tuple -> 1-item list: - sym = [tuple(sym)] - for isym in sym: - if len(isym) > 1: - for i in isym: - if i < 0 or i > self._tensor_rank - 1: - raise IndexError("invalid position: {}".format(i) + - " not in [0,{}]".format(self._tensor_rank-1)) - self._sym.append(tuple(isym)) - self._antisym = [] - if antisym is not None and antisym != []: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple -> 1-item list: - antisym = [tuple(antisym)] - for isym in antisym: - if len(isym) > 1: - for i in isym: - if i < 0 or i > self._tensor_rank - 1: - raise IndexError("invalid position: {}".format(i) + - " not in [0,{}]".format(self._tensor_rank-1)) - self._antisym.append(tuple(isym)) - # Final consistency check: - index_list = [] - for isym in self._sym: - index_list += isym - for isym in self._antisym: - index_list += isym - if len(index_list) != len(set(index_list)): - # There is a repeated index position: - raise IndexError("incompatible lists of symmetries: the same " + - "position appears more than once") + self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym( + self._tensor_rank, sym, antisym) # Initialization of derived quantities: self._init_derived() @@ -591,7 +560,7 @@ def _repr_(self): """ # Special cases - if self._tensor_type == (0,2) and self._sym == [(0,1)]: + if self._tensor_type == (0,2) and self._sym == ((0,1),): description = "Field of symmetric bilinear forms " if self._name is not None: description += self._name + " " @@ -957,13 +926,13 @@ def symmetries(self): elif len(self._sym) == 1: s = "symmetry: {}; ".format(self._sym[0]) else: - s = "symmetries: {}; ".format(self._sym) + s = "symmetries: {}; ".format(list(self._sym)) if not self._antisym: a = "no antisymmetry" elif len(self._antisym) == 1: a = "antisymmetry: {}".format(self._antisym[0]) else: - a = "antisymmetries: {}".format(self._antisym) + a = "antisymmetries: {}".format(list(self._antisym)) print(s + a) #### End of simple accessors ##### diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index cf3f1dc687d..393218bc7c0 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -787,7 +787,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -799,7 +799,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -2102,7 +2102,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -2114,7 +2114,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 38ee9c58601..3a33e49efd8 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1806,12 +1806,12 @@ def __mul__(self, other): "same starting index") if isinstance(other, CompWithSym): sym = [] - if other._sym != []: + if other._sym: for s in other._sym: ns = tuple(s[i]+self._nid for i in range(len(s))) sym.append(ns) antisym = [] - if other._antisym != []: + if other._antisym: for s in other._antisym: ns = tuple(s[i]+self._nid for i in range(len(s))) antisym.append(ns) @@ -3029,46 +3029,76 @@ def __init__(self, ring, frame, nb_indices, start_index=0, """ Components.__init__(self, ring, frame, nb_indices, start_index, output_formatter) - self._sym = [] - if sym is not None and sym != []: + self._sym, self._antisym = self._canonicalize_sym_antisym( + nb_indices, sym, antisym) + + @staticmethod + def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): + r""" + Bring sym and antisym into their canonical form. + + EXAMPLES:: + + sage: from sage.tensor.modules.comp import CompWithSym + sage: CompWithSym._canonicalize_sym_antisym(6, [(2, 1)]) + (((1, 2),), ()) + """ + result_sym = [] + if sym is None: + sym = [] + else: + # Handle the case that sym is an iterator + sym = list(sym) + if sym: if isinstance(sym[0], (int, Integer)): # a single symmetry is provided as a tuple or a range object; # it is converted to a 1-item list: sym = [tuple(sym)] for isym in sym: if len(isym) < 2: - raise IndexError("at least two index positions must be " + - "provided to define a symmetry") + # Drop trivial symmetry + continue for i in isym: - if i<0 or i>self._nid-1: + if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(self._nid-1) + "]") - self._sym.append(tuple(isym)) - self._antisym = [] - if antisym is not None and antisym != []: + " not in [0," + str(nb_indices-1) + "]") + result_sym.append(tuple(isym)) + result_antisym = [] + if antisym is None: + antisym = [] + else: + # Handle the case that antisym is an iterator + antisym = list(antisym) + if antisym: if isinstance(antisym[0], (int, Integer)): # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: antisym = [tuple(antisym)] for isym in antisym: if len(isym) < 2: - raise IndexError("at least two index positions must be " + - "provided to define an antisymmetry") + # Drop trivial antisymmetry + continue for i in isym: - if i<0 or i>self._nid-1: + if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(self._nid-1) + "]") - self._antisym.append(tuple(isym)) + " not in [0," + str(nb_indices - 1) + "]") + result_antisym.append(tuple(isym)) # Final consistency check: index_list = [] - for isym in self._sym: + for isym in result_sym: index_list += isym - for isym in self._antisym: + for isym in result_antisym: index_list += isym if len(index_list) != len(set(index_list)): # There is a repeated index position: raise IndexError("incompatible lists of symmetries: the same " + - "index position appears more then once") + "index position appears more than once") + # Canonicalize sort order, make tuples + result_sym = [tuple(sorted(s)) for s in result_sym] + result_antisym = [tuple(sorted(s)) for s in result_antisym] + result_sym = tuple(sorted(result_sym)) + result_antisym = tuple(sorted(result_antisym)) + return result_sym, result_antisym def _repr_symmetry(self): r""" @@ -3394,9 +3424,9 @@ def swap_adjacent_indices(self, pos1, pos2, pos3): [[0, 7, 8], [-7, 0, 9], [-8, -9, 0]]] sage: c1 = c.swap_adjacent_indices(0,1,3) sage: c._antisym # c is antisymmetric with respect to the last pair of indices... - [(1, 2)] + ((1, 2),) sage: c1._antisym #...while c1 is antisymmetric with respect to the first pair of indices - [(0, 1)] + ((0, 1),) sage: c[0,1,2] 3 sage: c1[1,2,0] @@ -3417,6 +3447,8 @@ def swap_adjacent_indices(self, pos1, pos2, pos3): for s in self._antisym: new_s = [new_lpos.index(pos) for pos in s] result._antisym.append(tuple(sorted(new_s))) + result._sym, result._antisym = self._canonicalize_sym_antisym( + self._nid, result._sym, result._antisym) # The values: for ind, val in self._comp.items(): new_ind = ind[:pos1] + ind[pos2:pos3] + ind[pos1:pos2] + ind[pos3:] @@ -3547,7 +3579,7 @@ def paral_sum(a, b, local_list_ind): com = tuple(set(isym).intersection(set(osym))) if len(com) > 1: common_antisym.append(com) - if common_sym != [] or common_antisym != []: + if common_sym or common_antisym: result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, common_sym, common_antisym) @@ -3655,11 +3687,11 @@ def __mul__(self, other): sym = list(self._sym) antisym = list(self._antisym) if isinstance(other, CompWithSym): - if other._sym != []: + if other._sym: for s in other._sym: ns = tuple(s[i]+self._nid for i in range(len(s))) sym.append(ns) - if other._antisym != []: + if other._antisym: for s in other._antisym: ns = tuple(s[i]+self._nid for i in range(len(s))) antisym.append(ns) @@ -3985,7 +4017,7 @@ def non_redundant_index_generator(self): si = self._sindex imax = self._dim - 1 + si ind = [si for k in range(self._nid)] - sym = self._sym.copy() # we may modify this in the following + sym = list(self._sym) # we may modify this in the following antisym = self._antisym for pos in range(self._nid): for isym in antisym: @@ -4161,7 +4193,7 @@ def symmetrize(self, *pos): (0, 0, 1) ], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) sage: a1._sym # a1 has two distinct symmetries: - [(0, 1), (2, 3)] + ((0, 1), (2, 3)) sage: a[0,1,2,0] == a[0,0,2,1] # a is symmetric w.r.t. positions 1 and 3 True sage: a1[0,1,2,0] == a1[0,0,2,1] # a1 is not @@ -4439,10 +4471,10 @@ def antisymmetrize(self, *pos): (1, 0, 0), (0, 1, 0), (0, 0, 1) - ], with antisymmetry on the index positions (1, 3), - with antisymmetry on the index positions (0, 2) + ], with antisymmetry on the index positions (0, 2), + with antisymmetry on the index positions (1, 3) sage: s._antisym # the antisymmetry (0,1,2) has been reduced to (0,2), since 1 is involved in the new antisymmetry (1,3): - [(1, 3), (0, 2)] + ((0, 2), (1, 3)) Partial antisymmetrization of 4-indices components with a symmetry on the first two indices:: diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index d746f922309..a08b17b1129 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -704,9 +704,8 @@ def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_ sage: M.ambient_module() is M True - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: T60M = M.tensor_module(6, 0) sage: Sym0123x45M.ambient_module() is T60M True @@ -1429,12 +1428,19 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): T^{\{2,3\}}(M) \otimes T^{\{6,7\}}(M^*) \otimes \mathrm{Sym}^{\{0,1\}}(M) \otimes \mathrm{ASym}^{\{4,5\}}(M^*) See :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule` - and :class:`~sage.tensor.modules.tensor_free_module.TensorFreeSubmodule_comp` + and :class:`~sage.tensor.modules.tensor_free_module.TensorFreeSubmodule_sym` for more documentation. + TESTS:: + + sage: M = FiniteRankFreeModule(ZZ, 2) + sage: M.tensor_module(2, 0, sym=(0,1)) is M.symmetric_power(2) + True """ + from .comp import CompWithSym, CompFullyAntiSym + + sym, antisym = CompWithSym._canonicalize_sym_antisym(k + l, sym, antisym) if sym or antisym: - # TODO: Canonicalize sym, antisym, make hashable key = (k, l, sym, antisym) else: key = (k, l) @@ -1444,8 +1450,8 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): if key == (1, 0): T = self elif sym or antisym: - from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - T = TensorFreeSubmodule_comp(self, (k, l), sym=sym, antisym=antisym) + from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym + T = TensorFreeSubmodule_sym(self, (k, l), sym=sym, antisym=antisym) else: from sage.tensor.modules.tensor_free_module import TensorFreeModule T = TensorFreeModule(self, (k, l)) @@ -2031,7 +2037,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -2043,7 +2049,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 845c9185a26..2ffa00cc476 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -309,41 +309,8 @@ def __init__( # bases, with the bases as keys (initially empty) # Treatment of symmetry declarations: - self._sym = [] - if sym is not None and sym != []: - if isinstance(sym[0], (int, Integer)): - # a single symmetry is provided as a tuple -> 1-item list: - sym = [tuple(sym)] - for isym in sym: - if len(isym) > 1: - for i in isym: - if i<0 or i>self._tensor_rank-1: - raise IndexError("invalid position: " + str(i) + - " not in [0," + str(self._tensor_rank-1) + "]") - self._sym.append(tuple(isym)) - self._antisym = [] - if antisym is not None and antisym != []: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple -> 1-item list: - antisym = [tuple(antisym)] - for isym in antisym: - if len(isym) > 1: - for i in isym: - if i<0 or i>self._tensor_rank-1: - raise IndexError("invalid position: " + str(i) + - " not in [0," + str(self._tensor_rank-1) + "]") - self._antisym.append(tuple(isym)) - - # Final consistency check: - index_list = [] - for isym in self._sym: - index_list += isym - for isym in self._antisym: - index_list += isym - if len(index_list) != len(set(index_list)): - # There is a repeated index position: - raise IndexError("incompatible lists of symmetries: the same " + - "position appears more than once") + self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym( + self._tensor_rank, sym, antisym) # Initialization of derived quantities: FreeModuleTensor._init_derived(self) @@ -405,7 +372,7 @@ def _repr_(self): """ # Special cases - if self._tensor_type == (0,2) and self._sym == [(0,1)]: + if self._tensor_type == (0,2) and self._sym == ((0,1),): description = "Symmetric bilinear form " else: # Generic case @@ -563,13 +530,13 @@ def symmetries(self): elif len(self._sym) == 1: s = "symmetry: {}; ".format(self._sym[0]) else: - s = "symmetries: {}; ".format(self._sym) + s = "symmetries: {}; ".format(list(self._sym)) if len(self._antisym) == 0: a = "no antisymmetry" elif len(self._antisym) == 1: a = "antisymmetry: {}".format(self._antisym[0]) else: - a = "antisymmetries: {}".format(self._antisym) + a = "antisymmetries: {}".format(list(self._antisym)) print(s+a) #### End of simple accessors ##### diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index d4f000d7be6..42a97d92b4b 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -66,7 +66,7 @@ from sage.tensor.modules.free_module_morphism import \ FiniteRankFreeModuleMorphism from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism -from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_comp +from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_sym class TensorFreeModule(FiniteRankFreeModule_abstract): r""" @@ -554,11 +554,10 @@ def _an_element_(self): TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: t = Sym0123x45M._an_element_() sage: t.parent() is Sym0123x45M True @@ -623,8 +622,7 @@ def _coerce_map_from_(self, other): Coercion from submodules:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: Sym01M = TensorFreeSubmodule_comp(M, (2, 0), sym=((0, 1))) + sage: Sym01M = M.tensor_module(2, 0, sym=((0, 1))) sage: M.tensor_module(2,0)._coerce_map_from_(Sym01M) True @@ -732,7 +730,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, INPUT: - - ``symbol``, ``indices`` -- passed to he base module's method + - ``symbol``, ``indices`` -- passed to the base module's method :meth:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule.basis` to select a basis of the :meth:`base_module` of ``self``, or to create it. @@ -760,8 +758,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_2⊗e^1 e_2⊗e^2 - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) + sage: Sym2M = M.tensor_module(2, 0, sym=range(2)) sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M Standard basis on the Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring @@ -773,26 +770,44 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_1⊗e_1 e_1⊗e_2 + e_2⊗e_1 e_2⊗e_2 + + sage: M = FiniteRankFreeModule(ZZ, 2) + sage: e = M.basis('e') + sage: f = M.basis('f', from_family=(-e[1], e[0])) + sage: for b in f: b.display() + f_0 = -e_1 + f_1 = e_0 + sage: S = M.tensor_module(2, 0, sym=(0,1)) + sage: fS = S.basis('f') + sage: for b in fS: b.display() + e_1⊗e_1 + -e_0⊗e_1 - e_1⊗e_0 + e_0⊗e_0 + sage: for b in fS: b.display(f) + f_0⊗f_0 + f_0⊗f_1 + f_1⊗f_0 + f_1⊗f_1 + """ - return TensorFreeSubmoduleBasis_comp(self, symbol=symbol, latex_symbol=latex_symbol, + return TensorFreeSubmoduleBasis_sym(self, symbol=symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) @cached_method - def _basis_comp(self): + def _basis_sym(self): r""" Return an instance of :class:`~sage.tensor.modules.comp.Components`. This implementation returns an instance without symmetry. - The subclass :class:`~sage.tensor.modules.tensor_free_submodule.TensorFreeSubmodule_comp` + The subclass :class:`~sage.tensor.modules.tensor_free_submodule.TensorFreeSubmodule_sym` overrides this method to encode the prescribed symmetry of the submodule. EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T = M.tensor_module(1,1) - sage: c = T._basis_comp(); c + sage: c = T._basis_sym(); c 2-indices components w.r.t. (0, 1, 2) """ diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index dc94ace3343..cfe6b09dccf 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -1,5 +1,5 @@ r""" -Free submodules of tensor products of free modules +Free submodules of tensor modules defined by monoterm symmetries """ #****************************************************************************** @@ -23,15 +23,13 @@ from .finite_rank_free_module import FiniteRankFreeModule_abstract -class TensorFreeSubmodule_comp(TensorFreeModule): +class TensorFreeSubmodule_sym(TensorFreeModule): r""" Class for free submodules of tensor products of free modules - that are defined by the symmetries of a - :class:`~sage.tensor.modules.comp.Components` object. + that are defined by some monoterm symmetries. EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0); T60M @@ -40,14 +38,14 @@ class TensorFreeSubmodule_comp(TensorFreeModule): 'T^(6, 0)(M)' sage: latex(T60M) T^{(6, 0)}\left(M\right) - sage: T40Sym45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((4, 5))); T40Sym45M + sage: T40Sym45M = M.tensor_module(6, 0, sym=((4, 5))); T40Sym45M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (4, 5) sage: T40Sym45M._name 'T^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(T40Sym45M) T^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) @@ -55,7 +53,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(Sym0123x45M) \mathrm{Sym}^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) - sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))); Sym012x345M + sage: Sym012x345M = M.tensor_module(6, 0, sym=((0, 1, 2), (3, 4, 5))); Sym012x345M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2), with symmetry on the index positions (3, 4, 5) @@ -63,7 +61,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): 'Sym^{0,1,2}(M)⊗Sym^{3,4,5}(M)' sage: latex(Sym012x345M) \mathrm{Sym}^{\{0,1,2\}}(M) \otimes \mathrm{Sym}^{\{3,4,5\}}(M) - sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))); Sym012345M + sage: Sym012345M = M.tensor_module(6, 0, sym=((0, 1, 2, 3, 4, 5))); Sym012345M Free module of fully symmetric type-(6,0) tensors on the Rank-3 free module M over the Integer Ring sage: Sym012345M._name @@ -85,7 +83,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): TESTS:: - sage: T = TensorFreeSubmodule_comp(M, (4, 4), sym=((0, 1)), antisym=((4, 5))); T + sage: T = M.tensor_module(4, 4, sym=((0, 1)), antisym=((4, 5))); T Free module of type-(4,4) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1), with antisymmetry on the index positions (4, 5) @@ -100,10 +98,9 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, r""" TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: TestSuite(Sym0123x45M).run() """ self._fmodule = fmodule @@ -113,20 +110,20 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, self._ambient_module = ambient self._sym = sym self._antisym = antisym - basis_comp = self._basis_comp() - rank = len(list(basis_comp.non_redundant_index_generator())) + basis_sym = self._basis_sym() + rank = len(list(basis_sym.non_redundant_index_generator())) if name is None and fmodule._name is not None: all_indices = tuple(range(tensor_type[0] + tensor_type[1])) - if isinstance(basis_comp, CompFullySym): + if isinstance(basis_sym, CompFullySym): sym = [all_indices] antisym = [] - elif isinstance(basis_comp, CompFullyAntiSym): + elif isinstance(basis_sym, CompFullyAntiSym): sym = [] antisym = [all_indices] - elif isinstance(basis_comp, CompWithSym): - sym = basis_comp._sym - antisym = basis_comp._antisym + elif isinstance(basis_sym, CompWithSym): + sym = basis_sym._sym + antisym = basis_sym._antisym else: sym = antisym = [] nosym_0 = [i for i in range(tensor_type[0]) @@ -178,19 +175,19 @@ def power_name(op, s, latex=False): category=category, ambient=ambient) @cached_method - def _basis_comp(self): + def _basis_sym(self): r""" Return an instance of :class:`~sage.tensor.modules.comp.Components`. - It encodes the prescribed symmetry of ``self``. + In the current implementation of :class:`~sage.tensor.modules.tensor_free_submodule.TensorFreeSubmodule_sym`, + it encodes the prescribed symmetry of ``self``. EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + 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: c = Sym2M._basis_comp(); c + sage: c = Sym2M._basis_sym(); c Fully symmetric 2-indices components w.r.t. (0, 1, 2) """ @@ -205,14 +202,13 @@ def _repr_(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + 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 """ - prefix, suffix = self._basis_comp()._repr_symmetry() + prefix, suffix = self._basis_sym()._repr_symmetry() return "Free module of {}type-({},{}) tensors on the {}{}".format( prefix.lower(), self._tensor_type[0], self._tensor_type[1], self._fmodule, suffix) @@ -226,11 +222,10 @@ def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: ten0123x45M = Sym0123x45M.an_element(); ten0123x45M Type-(6,0) tensor on the Rank-3 free module M over the Integer Ring sage: ten0123x45M.parent() @@ -242,13 +237,13 @@ def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) - sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012x345M = M.tensor_module(6, 0, sym=((0, 1, 2), (3, 4, 5))) sage: com012x345M = Sym012x345M.an_element()._components[e]; com012x345M 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2), with symmetry on the index positions (3, 4, 5) - sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym012345M = M.tensor_module(6, 0, sym=((0, 1, 2, 3, 4, 5))) sage: com012345M = Sym012345M.an_element()._components[e]; com012345M Fully symmetric 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring @@ -302,11 +297,10 @@ def _element_constructor_(self, comp=[], basis=None, name=None, r""" TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2]) Traceback (most recent call last): ... @@ -322,14 +316,14 @@ def _element_constructor_(self, comp=[], basis=None, name=None, if sym is not None or antisym is not None: # Refuse to create a tensor with finer symmetries # than those defining the subspace - if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_comp()): + if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_sym()): raise ValueError(f"cannot create a tensor with symmetries {sym=}, {antisym=} " f"as an element of {self}") if sym is None: - sym = self._basis_comp()._sym + sym = self._basis_sym()._sym if antisym is None: - antisym = self._basis_comp()._antisym + antisym = self._basis_sym()._antisym resu = super()._element_constructor_(comp=comp, basis=basis, name=name, @@ -355,12 +349,11 @@ def is_submodule(self, other): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) - sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) + sage: Sym012x345M = M.tensor_module(6, 0, sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012345M = M.tensor_module(6, 0, sym=((0, 1, 2, 3, 4, 5))) sage: Sym012345M.is_submodule(Sym012345M) True sage: Sym012345M.is_submodule(Sym0123x45M) @@ -387,8 +380,8 @@ def is_submodule(self, other): if self_tensor_type != other_tensor_type: return False - other_comp = other._basis_comp() - return self._is_symmetry_coarsening_of(self._basis_comp(), other_comp) + other_comp = other._basis_sym() + return self._is_symmetry_coarsening_of(self._basis_sym(), other_comp) @lazy_attribute def lift(self): @@ -397,9 +390,8 @@ def lift(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: Sym0123x45M.lift Generic morphism: From: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, @@ -419,7 +411,6 @@ def reduce(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(QQ, 3, name='M') sage: e = M.basis('e') sage: X = M.tensor_module(6, 0) @@ -461,8 +452,8 @@ def reduce(self): sage: all(Y.reduce(u.lift()) == 0 for u in Y.basis('e')) True """ - sym = self._basis_comp()._sym - antisym = self._basis_comp()._antisym + sym = self._basis_sym()._sym + antisym = self._basis_sym()._antisym def _reduce_element(x): if not x._components: @@ -491,7 +482,6 @@ def retract(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: X = M.tensor_module(6, 0) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index ae00f98971b..d2b60298ee0 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -1,5 +1,5 @@ r""" -Free module bases indexed by component indices +Standard bases of free submodules of tensor modules defined by some monoterm symmetries """ #****************************************************************************** @@ -14,9 +14,9 @@ from sage.tensor.modules.free_module_basis import Basis_abstract -class TensorFreeSubmoduleBasis_comp(Basis_abstract): +class TensorFreeSubmoduleBasis_sym(Basis_abstract): r""" - Standard basis of a tensor module with prescribed symmetries. + Standard basis of a free submodule of a tensor module with prescribed monoterm symmetries. EXAMPLES:: @@ -52,7 +52,7 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, latex_indices, symbol_dual, latex_symbol_dual) super().__init__(tensor_module, symbol, latex_symbol, indices, latex_indices) self._base_module_basis = base_module_basis - self._comp = tensor_module._basis_comp() + self._comp = tensor_module._basis_sym() def _repr_(self): r""" @@ -120,8 +120,8 @@ def __getitem__(self, index): sage: e11[1, 2].display() e_1⊗e^2 - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym + sage: Sym2M = TensorFreeSubmodule_sym(M, (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: eSym2M = Sym2M.basis('e') sage: eSym2M[1, 1].display()