def _del_derived(self): r""" Delete the derived quantities. EXAMPLES:: sage: M = FiniteRankFreeModule(QQ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism(name='a') sage: a[e,:] = [[1,0,-1], [0,3,0], [0,0,2]] sage: b = a.inverse() sage: a._inverse Automorphism a^(-1) of the 3-dimensional vector space M over the Rational Field sage: a._del_derived() sage: a._inverse # has been reset to None """ # First delete the derived quantities pertaining to FreeModuleTensor: FreeModuleTensor._del_derived(self) # Then reset the inverse automorphism to None: if self._inverse is not None: self._inverse._inverse = None # (it was set to self) self._inverse = None # and delete the matrices: self._matrices.clear()
def __init__(self, fmodule, degree, name=None, latex_name=None): r""" Initialize ``self``. TESTS:: sage: from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = FreeModuleAltForm(M, 2, name='a') sage: a[e,0,1] = 2 sage: TestSuite(a).run(skip="_test_category") # see below In the above test suite, _test_category fails because a is not an instance of a.parent().category().element_class. Actually alternating forms must be constructed via ExtPowerFreeModule.element_class and not by a direct call to FreeModuleAltForm:: sage: a1 = M.dual_exterior_power(2).element_class(M, 2, name='a') sage: a1[e,0,1] = 2 sage: TestSuite(a1).run() """ FreeModuleTensor.__init__(self, fmodule, (0,degree), name=name, latex_name=latex_name, antisym=range(degree), parent=fmodule.dual_exterior_power(degree)) FreeModuleAltForm._init_derived(self) # initialization of derived
def __init__(self, fmodule, degree, name=None, latex_name=None): r""" Initialize ``self``. TESTS:: sage: from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = AlternatingContrTensor(M, 2, name='a') sage: a[e,0,1] = 2 sage: TestSuite(a).run(skip="_test_category") # see below In the above test suite, _test_category fails because a is not an instance of a.parent().category().element_class. Actually alternating tensors must be constructed via ExtPowerFreeModule.element_class and not by a direct call to AlternatingContrTensor:: sage: a1 = M.exterior_power(2).element_class(M, 2, name='a') sage: a1[e,0,1] = 2 sage: TestSuite(a1).run() """ FreeModuleTensor.__init__(self, fmodule, (degree, 0), name=name, latex_name=latex_name, antisym=range(degree), parent=fmodule.exterior_power(degree))
def __init__(self, fmodule, degree, name=None, latex_name=None): r""" Initialize ``self``. TESTS:: sage: from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = FreeModuleAltForm(M, 2, name='a') sage: a[e,0,1] = 2 sage: TestSuite(a).run(skip="_test_category") # see below In the above test suite, _test_category fails because a is not an instance of a.parent().category().element_class. Actually alternating forms must be constructed via ExtPowerDualFreeModule.element_class and not by a direct call to FreeModuleAltForm:: sage: a1 = M.dual_exterior_power(2).element_class(M, 2, name='a') sage: a1[e,0,1] = 2 sage: TestSuite(a1).run() """ FreeModuleTensor.__init__(self, fmodule, (0,degree), name=name, latex_name=latex_name, antisym=range(degree), parent=fmodule.dual_exterior_power(degree))
def _del_derived(self): r""" Delete the derived quantities. EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: a = M.alternating_form(2) sage: a._del_derived() """ FreeModuleTensor._del_derived(self)
def _del_derived(self): r""" Delete the derived quantities. EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: a = M.alternating_form(2) sage: a._del_derived() """ FreeModuleTensor._del_derived(self)
def __init__(self, fmodule, name=None, latex_name=None, is_identity=False): r""" TESTS:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism sage: a = FreeModuleAutomorphism(M, name='a') sage: a[e,:] = [[-1,0,0],[0,1,2],[0,1,3]] sage: TestSuite(a).run(skip="_test_category") # see below In the above test suite, _test_category fails because a is not an instance of a.parent().category().element_class. Actually automorphism must be constructed via FreeModuleLinearGroup.element_class and not by a direct call to FreeModuleAutomorphism:: sage: a = M.general_linear_group().element_class(M, name='a') sage: a[e,:] = [[-1,0,0],[0,1,2],[0,1,3]] sage: TestSuite(a).run() Test suite on the identity map:: sage: id = M.general_linear_group().one() sage: TestSuite(id).run() Test suite on the automorphism obtained as GL.an_element():: sage: b = M.general_linear_group().an_element() sage: TestSuite(b).run() """ if is_identity: if name is None: name = 'Id' if latex_name is None: if name == 'Id': latex_name = r'\mathrm{Id}' else: latex_name = name FreeModuleTensor.__init__(self, fmodule, (1, 1), name=name, latex_name=latex_name, parent=fmodule.general_linear_group()) # MultiplicativeGroupElement attributes: # - none # Local attributes: self._is_identity = is_identity self._inverse = None # inverse automorphism not set yet self._matrices = {}
def __init__(self, fmodule, name=None, latex_name=None, is_identity=False): r""" TESTS:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism sage: a = FreeModuleAutomorphism(M, name='a') sage: a[e,:] = [[-1,0,0],[0,1,2],[0,1,3]] sage: TestSuite(a).run(skip="_test_category") # see below In the above test suite, _test_category fails because a is not an instance of a.parent().category().element_class. Actually automorphism must be constructed via FreeModuleLinearGroup.element_class and not by a direct call to FreeModuleAutomorphism:: sage: a = M.general_linear_group().element_class(M, name='a') sage: a[e,:] = [[-1,0,0],[0,1,2],[0,1,3]] sage: TestSuite(a).run() Test suite on the identity map:: sage: id = M.general_linear_group().one() sage: TestSuite(id).run() Test suite on the automorphism obtained as GL.an_element():: sage: b = M.general_linear_group().an_element() sage: TestSuite(b).run() """ if is_identity: if name is None: name = 'Id' if latex_name is None: if name == 'Id': latex_name = r'\mathrm{Id}' else: latex_name = name FreeModuleTensor.__init__(self, fmodule, (1,1), name=name, latex_name=latex_name, parent=fmodule.general_linear_group()) # MultiplicativeGroupElement attributes: # - none # Local attributes: self._is_identity = is_identity self._inverse = None # inverse automorphism not set yet self._matrices = {}
def __mul__(self, other): r""" Redefinition of :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.__mul__` so that * dispatches either to automorphism composition or to the tensor product. EXAMPLES: Automorphism composition:: sage: M = FiniteRankFreeModule(ZZ, 2, name='M') sage: e = M.basis('e') sage: a = M.automorphism([[1,2],[1,3]]) sage: b = M.automorphism([[3,4],[5,7]]) sage: s = a*b ; s Automorphism of the Rank-2 free module M over the Integer Ring sage: s.matrix() [13 18] [18 25] sage: s.matrix() == a.matrix() * b.matrix() True sage: s(e[0]) == a(b(e[0])) True sage: s(e[1]) == a(b(e[1])) True sage: s.display() 13 e_0*e^0 + 18 e_0*e^1 + 18 e_1*e^0 + 25 e_1*e^1 Tensor product:: sage: c = M.tensor((1,1)) ; c Type-(1,1) tensor on the Rank-2 free module M over the Integer Ring sage: c[:] = [[3,4],[5,7]] sage: c[:] == b[:] # c and b have the same components True sage: s = a*c ; s Type-(2,2) tensor on the Rank-2 free module M over the Integer Ring sage: s.display() 3 e_0*e_0*e^0*e^0 + 4 e_0*e_0*e^0*e^1 + 6 e_0*e_0*e^1*e^0 + 8 e_0*e_0*e^1*e^1 + 5 e_0*e_1*e^0*e^0 + 7 e_0*e_1*e^0*e^1 + 10 e_0*e_1*e^1*e^0 + 14 e_0*e_1*e^1*e^1 + 3 e_1*e_0*e^0*e^0 + 4 e_1*e_0*e^0*e^1 + 9 e_1*e_0*e^1*e^0 + 12 e_1*e_0*e^1*e^1 + 5 e_1*e_1*e^0*e^0 + 7 e_1*e_1*e^0*e^1 + 15 e_1*e_1*e^1*e^0 + 21 e_1*e_1*e^1*e^1 """ if isinstance(other, FreeModuleAutomorphism): return self._mul_(other) # general linear group law else: return FreeModuleTensor.__mul__(self, other) # tensor product
def __mul__(self, other): r""" Redefinition of :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.__mul__` so that * dispatches either to automorphism composition or to the tensor product. EXAMPLES: Automorphism composition:: sage: M = FiniteRankFreeModule(ZZ, 2, name='M') sage: e = M.basis('e') sage: a = M.automorphism([[1,2],[1,3]]) sage: b = M.automorphism([[3,4],[5,7]]) sage: s = a*b ; s Automorphism of the Rank-2 free module M over the Integer Ring sage: s.matrix() [13 18] [18 25] sage: s.matrix() == a.matrix() * b.matrix() True sage: s(e[0]) == a(b(e[0])) True sage: s(e[1]) == a(b(e[1])) True sage: s.display() 13 e_0*e^0 + 18 e_0*e^1 + 18 e_1*e^0 + 25 e_1*e^1 Tensor product:: sage: c = M.tensor((1,1)) ; c Type-(1,1) tensor on the Rank-2 free module M over the Integer Ring sage: c[:] = [[3,4],[5,7]] sage: c[:] == b[:] # c and b have the same components True sage: s = a*c ; s Type-(2,2) tensor on the Rank-2 free module M over the Integer Ring sage: s.display() 3 e_0*e_0*e^0*e^0 + 4 e_0*e_0*e^0*e^1 + 6 e_0*e_0*e^1*e^0 + 8 e_0*e_0*e^1*e^1 + 5 e_0*e_1*e^0*e^0 + 7 e_0*e_1*e^0*e^1 + 10 e_0*e_1*e^1*e^0 + 14 e_0*e_1*e^1*e^1 + 3 e_1*e_0*e^0*e^0 + 4 e_1*e_0*e^0*e^1 + 9 e_1*e_0*e^1*e^0 + 12 e_1*e_0*e^1*e^1 + 5 e_1*e_1*e^0*e^0 + 7 e_1*e_1*e^0*e^1 + 15 e_1*e_1*e^1*e^0 + 21 e_1*e_1*e^1*e^1 """ if isinstance(other, FreeModuleAutomorphism): return self._mul_(other) # general linear group law else: return FreeModuleTensor.__mul__(self, other) # tensor product
def _new_comp(self, basis): r""" Create some (uninitialized) components of ``self`` in a given basis. INPUT: - ``basis`` -- basis of the free module on which ``self`` is defined OUTPUT: - an instance of :class:`~sage.tensor.modules.comp.Components` or, if ``self`` is the identity, of the subclass :class:`~sage.tensor.modules.comp.KroneckerDelta` EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism() sage: a._new_comp(e) 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring sage: id = M.identity_map() sage: id._new_comp(e) Kronecker delta of size 3x3 sage: type(id._new_comp(e)) <class 'sage.tensor.modules.comp.KroneckerDelta'> """ from .comp import KroneckerDelta if self._is_identity: fmodule = self._fmodule return KroneckerDelta( fmodule._ring, basis, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter ) return FreeModuleTensor._new_comp(self, basis)
def _new_comp(self, basis): r""" Create some (uninitialized) components of ``self`` in a given basis. INPUT: - ``basis`` -- basis of the free module on which ``self`` is defined OUTPUT: - an instance of :class:`~sage.tensor.modules.comp.Components` or, if ``self`` is the identity, of the subclass :class:`~sage.tensor.modules.comp.KroneckerDelta` EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism() sage: a._new_comp(e) 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring sage: id = M.identity_map() sage: id._new_comp(e) Kronecker delta of size 3x3 sage: type(id._new_comp(e)) <class 'sage.tensor.modules.comp.KroneckerDelta'> """ from comp import KroneckerDelta if self._is_identity: fmodule = self._fmodule return KroneckerDelta(fmodule._ring, basis, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) return FreeModuleTensor._new_comp(self, basis)
def __call__(self, *arg): r""" Redefinition of :meth:`FreeModuleTensor.__call__` to allow for a single argument (module element). EXAMPLES: Call with a single argument: return a module element:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1) sage: e = M.basis('e') sage: a = M.automorphism([[-1,0,0],[0,1,2],[0,1,3]], name='a') sage: v = M([2,1,4], name='v') sage: s = a.__call__(v) ; s Element a(v) of the Rank-3 free module M over the Integer Ring sage: s.display() a(v) = -2 e_1 + 9 e_2 + 13 e_3 sage: s == a(v) True sage: s == a.contract(v) True Call with two arguments (:class:`FreeModuleTensor` behaviour): return a scalar:: sage: b = M.linear_form(name='b') sage: b[:] = 7, 0, 2 sage: a.__call__(b,v) 12 sage: a(b,v) == a.__call__(b,v) True sage: a(b,v) == s(b) True Identity map with a single argument: return a module element:: sage: id = M.identity_map() sage: s = id.__call__(v) ; s Element v of the Rank-3 free module M over the Integer Ring sage: s == v True sage: s == id(v) True sage: s == id.contract(v) True Identity map with two arguments (:class:`FreeModuleTensor` behaviour): return a scalar:: sage: id.__call__(b,v) 22 sage: id(b,v) == id.__call__(b,v) True sage: id(b,v) == b(v) True """ from .free_module_tensor import FiniteRankFreeModuleElement if len(arg) > 1: # The automorphism acting as a type-(1,1) tensor on a pair # (linear form, module element), returning a scalar: if self._is_identity: if len(arg) != 2: raise TypeError("wrong number of arguments") linform = arg[0] if linform._tensor_type != (0,1): raise TypeError("the first argument must be a linear form") vector = arg[1] if not isinstance(vector, FiniteRankFreeModuleElement): raise TypeError("the second argument must be a module" + " element") return linform(vector) else: # self is not the identity automorphism: return FreeModuleTensor.__call__(self, *arg) # The automorphism acting as such, on a module element, returning a # module element: vector = arg[0] if not isinstance(vector, FiniteRankFreeModuleElement): raise TypeError("the argument must be an element of a free module") if self._is_identity: return vector basis = self.common_basis(vector) t = self._components[basis] v = vector._components[basis] fmodule = self._fmodule result = vector._new_instance() for i in fmodule.irange(): res = 0 for j in fmodule.irange(): res += t[[i,j]]*v[[j]] result.set_comp(basis)[i] = res # Name of the output: result._name = None if self._name is not None and vector._name is not None: result._name = self._name + "(" + vector._name + ")" # LaTeX symbol for the output: result._latex_name = None if self._latex_name is not None and vector._latex_name is not None: result._latex_name = self._latex_name + r"\left(" + \ vector._latex_name + r"\right)" return result
def add_comp(self, basis=None): r""" Return the components of ``self`` w.r.t. a given module basis for assignment, keeping the components w.r.t. other bases. To delete the components w.r.t. other bases, use the method :meth:`set_comp` instead. INPUT: - ``basis`` -- (default: ``None``) basis in which the components are defined; if none is provided, the components are assumed to refer to the module's default basis .. WARNING:: If the automorphism has already components in other bases, it is the user's responsability to make sure that the components to be added are consistent with them. OUTPUT: - components in the given basis, as an instance of the class :class:`~sage.tensor.modules.comp.Components`; if such components did not exist previously, they are created EXAMPLES: Adding components to an automorphism of a rank-3 free `\ZZ`-module:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism(name='a') sage: a[e,:] = [[1,0,0],[0,-1,2],[0,1,-3]] sage: f = M.basis('f', from_family=(-e[0], 3*e[1]+4*e[2], ....: 5*e[1]+7*e[2])) ; f Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring sage: a.add_comp(f)[:] = [[1,0,0], [0, 80, 143], [0, -47, -84]] The components in basis ``e`` have been kept:: sage: a._components # random (dictionary output) {Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring, Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring} For the identity map, it is not permitted to invoke :meth:`add_comp`:: sage: id = M.identity_map() sage: id.add_comp(e) Traceback (most recent call last): ... TypeError: the components of the identity map cannot be changed Indeed, the components are automatically set by a call to :meth:`comp`:: sage: id.comp(e) Kronecker delta of size 3x3 sage: id.comp(f) Kronecker delta of size 3x3 """ if self._is_identity: raise TypeError("the components of the identity map cannot be " + "changed") else: return FreeModuleTensor.add_comp(self, basis=basis)
def set_comp(self, basis=None): r""" Return the components of ``self`` w.r.t. a given module basis for assignment. The components with respect to other bases are deleted, in order to avoid any inconsistency. To keep them, use the method :meth:`add_comp` instead. INPUT: - ``basis`` -- (default: ``None``) basis in which the components are defined; if none is provided, the components are assumed to refer to the module's default basis OUTPUT: - components in the given basis, as an instance of the class :class:`~sage.tensor.modules.comp.Components`; if such components did not exist previously, they are created. EXAMPLES: Setting the components of an automorphism of a rank-3 free `\ZZ`-module:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism(name='a') sage: a.set_comp(e) 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring sage: a.set_comp(e)[:] = [[1,0,0],[0,1,2],[0,1,3]] sage: a.matrix(e) [1 0 0] [0 1 2] [0 1 3] Since ``e`` is the module's default basis, one has:: sage: a.set_comp() is a.set_comp(e) True The method :meth:`set_comp` can be used to modify a single component:: sage: a.set_comp(e)[0,0] = -1 sage: a.matrix(e) [-1 0 0] [ 0 1 2] [ 0 1 3] A short cut to :meth:`set_comp` is the bracket operator, with the basis as first argument:: sage: a[e,:] = [[1,0,0],[0,-1,2],[0,1,-3]] sage: a.matrix(e) [ 1 0 0] [ 0 -1 2] [ 0 1 -3] sage: a[e,0,0] = -1 sage: a.matrix(e) [-1 0 0] [ 0 -1 2] [ 0 1 -3] The call to :meth:`set_comp` erases the components previously defined in other bases; to keep them, use the method :meth:`add_comp` instead:: sage: f = M.basis('f', from_family=(-e[0], 3*e[1]+4*e[2], ....: 5*e[1]+7*e[2])) ; f Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring sage: a._components {Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring} sage: a.set_comp(f)[:] = [[-1,0,0], [0,1,0], [0,0,-1]] The components w.r.t. basis ``e`` have been erased:: sage: a._components {Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring} Of course, they can be computed from those in basis ``f`` by means of a change-of-basis formula, via the method :meth:`comp` or :meth:`matrix`:: sage: a.matrix(e) [ -1 0 0] [ 0 41 -30] [ 0 56 -41] For the identity map, it is not permitted to set components:: sage: id = M.identity_map() sage: id.set_comp(e) Traceback (most recent call last): ... TypeError: the components of the identity map cannot be changed Indeed, the components are automatically set by a call to :meth:`comp`:: sage: id.comp(e) Kronecker delta of size 3x3 sage: id.comp(f) Kronecker delta of size 3x3 """ if self._is_identity: raise TypeError("the components of the identity map cannot be " + "changed") else: return FreeModuleTensor.set_comp(self, basis=basis)
def components(self, basis=None, from_basis=None): r""" Return the components of ``self`` w.r.t to a given module basis. If the components are not known already, they are computed by the tensor change-of-basis formula from components in another basis. INPUT: - ``basis`` -- (default: ``None``) basis in which the components are required; if none is provided, the components are assumed to refer to the module's default basis - ``from_basis`` -- (default: ``None``) basis from which the required components are computed, via the tensor change-of-basis formula, if they are not known already in the basis ``basis``; if none, a basis from which both the components and a change-of-basis to ``basis`` are known is selected. OUTPUT: - components in the basis ``basis``, as an instance of the class :class:`~sage.tensor.modules.comp.Components`, or, for the identity automorphism, of the subclass :class:`~sage.tensor.modules.comp.KroneckerDelta` EXAMPLES: Components of an automorphism on a rank-3 free `\ZZ`-module:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1) sage: e = M.basis('e') sage: a = M.automorphism([[-1,0,0],[0,1,2],[0,1,3]], name='a') sage: a.components(e) 2-indices components w.r.t. Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring sage: a.components(e)[:] [-1 0 0] [ 0 1 2] [ 0 1 3] Since e is the module's default basis, it can be omitted:: sage: a.components() is a.components(e) True A shortcut is ``a.comp()``:: sage: a.comp() is a.components() True sage: a.comp(e) is a.components() True Components in another basis:: sage: f1 = -e[2] sage: f2 = 4*e[1] + 3*e[3] sage: f3 = 7*e[1] + 5*e[3] sage: f = M.basis('f', from_family=(f1,f2,f3)) sage: a.components(f) 2-indices components w.r.t. Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring sage: a.components(f)[:] [ 1 -6 -10] [ -7 83 140] [ 4 -48 -81] Some check of the above matrix:: sage: a(f[1]).display(f) a(f_1) = f_1 - 7 f_2 + 4 f_3 sage: a(f[2]).display(f) a(f_2) = -6 f_1 + 83 f_2 - 48 f_3 sage: a(f[3]).display(f) a(f_3) = -10 f_1 + 140 f_2 - 81 f_3 Components of the identity map:: sage: id = M.identity_map() sage: id.components(e) Kronecker delta of size 3x3 sage: id.components(e)[:] [1 0 0] [0 1 0] [0 0 1] sage: id.components(f) Kronecker delta of size 3x3 sage: id.components(f)[:] [1 0 0] [0 1 0] [0 0 1] """ if self._is_identity: if basis is None: basis = self._fmodule._def_basis if basis not in self._components: self._components[basis] = self._new_comp(basis) return self._components[basis] else: return FreeModuleTensor.components(self, basis=basis, from_basis=from_basis)