Tensor Fields¶
The class TensorField implements tensor fields on differentiable
manifolds. The derived class
TensorFieldParal
is devoted to tensor fields with values on parallelizable manifolds.
Various derived classes of TensorField are devoted to specific tensor
fields:
- VectorFieldfor vector fields (rank-1 contravariant tensor fields)
- AutomorphismFieldfor fields of tangent-space automorphisms
- DiffFormfor differential forms (fully antisymmetric covariant tensor fields)
- MultivectorFieldfor multivector fields (fully antisymmetric contravariant tensor fields)
AUTHORS:
- Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version 
- Travis Scrimshaw (2016): review tweaks 
- Eric Gourgoulhon (2018): operators divergence, Laplacian and d’Alembertian; method - TensorField.along()
- Florentin Jaffredo (2018) : series expansion with respect to a given parameter 
- Michael Jung (2019): improve treatment of the zero element; add method - TensorField.copy_from()
- Eric Gourgoulhon (2020): add method - TensorField.apply_map()
REFERENCES:
- class sage.manifolds.differentiable.tensorfield.TensorField(vector_field_module: VectorFieldModule, tensor_type: TensorType, name: str | None = None, latex_name: str | None = None, sym=None, antisym=None, parent=None)[source]¶
- Bases: - ModuleElementWithMutability- Tensor field along a differentiable manifold. - An instance of this class is a tensor field along a differentiable manifold \(U\) with values on a differentiable manifold \(M\), via a differentiable map \(\Phi: U \rightarrow M\). More precisely, given two nonnegative integers \(k\) and \(l\) and a differentiable map \[\Phi:\ U \longrightarrow M,\]- a tensor field of type \((k,l)\) along \(U\) with values on \(M\) is a differentiable map \[t:\ U \longrightarrow T^{(k,l)}M\]- (where \(T^{(k,l)}M\) is the tensor bundle of type \((k,l)\) over \(M\)) such that \[\forall p \in U,\ t(p) \in T^{(k,l)}(T_q M)\]- i.e. \(t(p)\) is a tensor of type \((k,l)\) on the tangent space \(T_q M\) at the point \(q = \Phi(p)\), that is to say a multilinear map \[t(p):\ \underbrace{T_q^*M\times\cdots\times T_q^*M}_{k\ \; \text{times}} \times \underbrace{T_q M\times\cdots\times T_q M}_{l\ \; \text{times}} \longrightarrow K,\]- where \(T_q^* M\) is the dual vector space to \(T_q M\) and \(K\) is the topological field over which the manifold \(M\) is defined. The integer \(k+l\) is called the tensor rank. - The standard case of a tensor field on a differentiable manifold corresponds to \(U=M\) and \(\Phi = \mathrm{Id}_M\). Other common cases are \(\Phi\) being an immersion and \(\Phi\) being a curve in \(M\) (\(U\) is then an open interval of \(\RR\)). - If \(M\) is parallelizable, the class - TensorFieldParalshould be used instead.- This is a Sage element class, the corresponding parent class being - TensorFieldModule.- INPUT: - vector_field_module– module \(\mathfrak{X}(U,\Phi)\) of vector fields along \(U\) associated with the map \(\Phi: U \rightarrow M\) (cf.- VectorFieldModule)
- tensor_type– pair \((k,l)\) with \(k\) being the contravariant rank and \(l\) the covariant rank
- name– (default:- None) name given to the tensor field
- latex_name– (default:- None) LaTeX symbol to denote the tensor field; if none is provided, the LaTeX symbol is set to- name
- sym– (default:- None) a symmetry or a list of symmetries among the tensor arguments: each symmetry is described by a tuple containing the positions of the involved arguments, with the convention- position = 0for the first argument; for instance:- sym = (0,1)for a symmetry between the 1st and 2nd arguments
- sym = [(0,2), (1,3,4)]for a symmetry between the 1st and 3rd arguments and a symmetry between the 2nd, 4th and 5th arguments.
 
- antisym– (default:- None) antisymmetry or list of antisymmetries among the arguments, with the same convention as for- sym
- parent– (default:- None) some specific parent (e.g. exterior power for differential forms); if- None,- vector_field_module.tensor_module(k,l)is used
 - EXAMPLES: - Tensor field of type (0,2) on the sphere \(S^2\): - sage: M = Manifold(2, 'S^2') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole sage: V = M.open_subset('V') # complement of the South pole sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), ....: intersection_name='W', restrictions1= x^2+y^2!=0, ....: restrictions2= u^2+v^2!=0) sage: uv_to_xy = xy_to_uv.inverse() sage: W = U.intersection(V) sage: t = M.tensor_field(0,2, name='t') ; t Tensor field t of type (0,2) on the 2-dimensional differentiable manifold S^2 sage: t.parent() Module T^(0,2)(S^2) of type-(0,2) tensors fields on the 2-dimensional differentiable manifold S^2 sage: t.parent().category() Category of tensor products of modules over Algebra of differentiable scalar fields on the 2-dimensional differentiable manifold S^2 - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2') # the 2-dimensional sphere S^2 >>> U = M.open_subset('U') # complement of the North pole >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole >>> V = M.open_subset('V') # complement of the South pole >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole >>> M.declare_union(U,V) # S^2 is the union of U and V >>> xy_to_uv = c_xy.transition_map(c_uv, (x/(x**Integer(2)+y**Integer(2)), y/(x**Integer(2)+y**Integer(2))), ... intersection_name='W', restrictions1= x**Integer(2)+y**Integer(2)!=Integer(0), ... restrictions2= u**Integer(2)+v**Integer(2)!=Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> W = U.intersection(V) >>> t = M.tensor_field(Integer(0),Integer(2), name='t') ; t Tensor field t of type (0,2) on the 2-dimensional differentiable manifold S^2 >>> t.parent() Module T^(0,2)(S^2) of type-(0,2) tensors fields on the 2-dimensional differentiable manifold S^2 >>> t.parent().category() Category of tensor products of modules over Algebra of differentiable scalar fields on the 2-dimensional differentiable manifold S^2 - The parent of \(t\) is not a free module, for the sphere \(S^2\) is not parallelizable: - sage: isinstance(t.parent(), FiniteRankFreeModule) False - >>> from sage.all import * >>> isinstance(t.parent(), FiniteRankFreeModule) False - To fully define \(t\), we have to specify its components in some vector frames defined on subsets of \(S^2\); let us start by the open subset \(U\): - sage: eU = c_xy.frame() sage: t[eU,:] = [[1,0], [-2,3]] sage: t.display(eU) t = dx⊗dx - 2 dy⊗dx + 3 dy⊗dy - >>> from sage.all import * >>> eU = c_xy.frame() >>> t[eU,:] = [[Integer(1),Integer(0)], [-Integer(2),Integer(3)]] >>> t.display(eU) t = dx⊗dx - 2 dy⊗dx + 3 dy⊗dy - To set the components of \(t\) on \(V\) consistently, we copy the expressions of the components in the common subset \(W\): - sage: eV = c_uv.frame() sage: eVW = eV.restrict(W) sage: c_uvW = c_uv.restrict(W) sage: t[eV,0,0] = t[eVW,0,0,c_uvW].expr() # long time sage: t[eV,0,1] = t[eVW,0,1,c_uvW].expr() # long time sage: t[eV,1,0] = t[eVW,1,0,c_uvW].expr() # long time sage: t[eV,1,1] = t[eVW,1,1,c_uvW].expr() # long time - >>> from sage.all import * >>> eV = c_uv.frame() >>> eVW = eV.restrict(W) >>> c_uvW = c_uv.restrict(W) >>> t[eV,Integer(0),Integer(0)] = t[eVW,Integer(0),Integer(0),c_uvW].expr() # long time >>> t[eV,Integer(0),Integer(1)] = t[eVW,Integer(0),Integer(1),c_uvW].expr() # long time >>> t[eV,Integer(1),Integer(0)] = t[eVW,Integer(1),Integer(0),c_uvW].expr() # long time >>> t[eV,Integer(1),Integer(1)] = t[eVW,Integer(1),Integer(1),c_uvW].expr() # long time - Actually, the above operation can be performed in a single line by means of the method - add_comp_by_continuation():- sage: t.add_comp_by_continuation(eV, W, chart=c_uv) # long time - >>> from sage.all import * >>> t.add_comp_by_continuation(eV, W, chart=c_uv) # long time - At this stage, \(t\) is fully defined, having components in frames eU and eV and the union of the domains of eU and eV being the whole manifold: - sage: t.display(eV) # long time t = (u^4 - 4*u^3*v + 10*u^2*v^2 + 4*u*v^3 + v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du⊗du - 4*(u^3*v + 2*u^2*v^2 - u*v^3)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du⊗dv + 2*(u^4 - 2*u^3*v - 2*u^2*v^2 + 2*u*v^3 + v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv⊗du + (3*u^4 + 4*u^3*v - 2*u^2*v^2 - 4*u*v^3 + 3*v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv⊗dv - >>> from sage.all import * >>> t.display(eV) # long time t = (u^4 - 4*u^3*v + 10*u^2*v^2 + 4*u*v^3 + v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du⊗du - 4*(u^3*v + 2*u^2*v^2 - u*v^3)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du⊗dv + 2*(u^4 - 2*u^3*v - 2*u^2*v^2 + 2*u*v^3 + v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv⊗du + (3*u^4 + 4*u^3*v - 2*u^2*v^2 - 4*u*v^3 + 3*v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv⊗dv - Let us consider two vector fields, \(a\) and \(b\), on \(S^2\): - sage: a = M.vector_field({eU: [-y, x]}, name='a') sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: a.display(eV) a = -v ∂/∂u + u ∂/∂v sage: b = M.vector_field({eU: [y, -1]}, name='b') sage: b.add_comp_by_continuation(eV, W, chart=c_uv) sage: b.display(eV) b = ((2*u + 1)*v^3 + (2*u^3 - u^2)*v)/(u^2 + v^2) ∂/∂u - (u^4 - v^4 + 2*u*v^2)/(u^2 + v^2) ∂/∂v - >>> from sage.all import * >>> a = M.vector_field({eU: [-y, x]}, name='a') >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> a.display(eV) a = -v ∂/∂u + u ∂/∂v >>> b = M.vector_field({eU: [y, -Integer(1)]}, name='b') >>> b.add_comp_by_continuation(eV, W, chart=c_uv) >>> b.display(eV) b = ((2*u + 1)*v^3 + (2*u^3 - u^2)*v)/(u^2 + v^2) ∂/∂u - (u^4 - v^4 + 2*u*v^2)/(u^2 + v^2) ∂/∂v - As a tensor field of type \((0,2)\), \(t\) acts on the pair \((a,b)\), resulting in a scalar field: - sage: f = t(a,b); f Scalar field t(a,b) on the 2-dimensional differentiable manifold S^2 sage: f.display() # long time t(a,b): S^2 → ℝ on U: (x, y) ↦ -2*x*y - y^2 - 3*x on V: (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) - >>> from sage.all import * >>> f = t(a,b); f Scalar field t(a,b) on the 2-dimensional differentiable manifold S^2 >>> f.display() # long time t(a,b): S^2 → ℝ on U: (x, y) ↦ -2*x*y - y^2 - 3*x on V: (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) - The vectors can be defined only on subsets of \(S^2\), the domain of the result is then the common subset: - sage: # long time sage: s = t(a.restrict(U), b) ; s Scalar field t(a,b) on the Open subset U of the 2-dimensional differentiable manifold S^2 sage: s.display() t(a,b): U → ℝ (x, y) ↦ -2*x*y - y^2 - 3*x on W: (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) sage: s = t(a.restrict(U), b.restrict(W)) ; s Scalar field t(a,b) on the Open subset W of the 2-dimensional differentiable manifold S^2 sage: s.display() t(a,b): W → ℝ (x, y) ↦ -2*x*y - y^2 - 3*x (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) - >>> from sage.all import * >>> # long time >>> s = t(a.restrict(U), b) ; s Scalar field t(a,b) on the Open subset U of the 2-dimensional differentiable manifold S^2 >>> s.display() t(a,b): U → ℝ (x, y) ↦ -2*x*y - y^2 - 3*x on W: (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) >>> s = t(a.restrict(U), b.restrict(W)) ; s Scalar field t(a,b) on the Open subset W of the 2-dimensional differentiable manifold S^2 >>> s.display() t(a,b): W → ℝ (x, y) ↦ -2*x*y - y^2 - 3*x (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) - The tensor itself can be defined only on some open subset of \(S^2\), yielding a result whose domain is this subset: - sage: s = t.restrict(V)(a,b); s # long time Scalar field t(a,b) on the Open subset V of the 2-dimensional differentiable manifold S^2 sage: s.display() # long time t(a,b): V → ℝ (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) on W: (x, y) ↦ -2*x*y - y^2 - 3*x - >>> from sage.all import * >>> s = t.restrict(V)(a,b); s # long time Scalar field t(a,b) on the Open subset V of the 2-dimensional differentiable manifold S^2 >>> s.display() # long time t(a,b): V → ℝ (u, v) ↦ -(3*u^3 + (3*u + 1)*v^2 + 2*u*v)/(u^4 + 2*u^2*v^2 + v^4) on W: (x, y) ↦ -2*x*y - y^2 - 3*x - Tests regarding the multiplication by a scalar field: - sage: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), ....: c_uv: (u^2 + v^2)/(u^2 + v^2 + 1)}, name='f') sage: t.parent().base_ring() is f.parent() True sage: s = f*t; s # long time Tensor field f*t of type (0,2) on the 2-dimensional differentiable manifold S^2 sage: s[[0,0]] == f*t[[0,0]] # long time True sage: s.restrict(U) == f.restrict(U) * t.restrict(U) # long time True sage: s = f*t.restrict(U); s Tensor field f*t of type (0,2) on the Open subset U of the 2-dimensional differentiable manifold S^2 sage: s.restrict(U) == f.restrict(U) * t.restrict(U) True - >>> from sage.all import * >>> f = M.scalar_field({c_xy: Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), ... c_uv: (u**Integer(2) + v**Integer(2))/(u**Integer(2) + v**Integer(2) + Integer(1))}, name='f') >>> t.parent().base_ring() is f.parent() True >>> s = f*t; s # long time Tensor field f*t of type (0,2) on the 2-dimensional differentiable manifold S^2 >>> s[[Integer(0),Integer(0)]] == f*t[[Integer(0),Integer(0)]] # long time True >>> s.restrict(U) == f.restrict(U) * t.restrict(U) # long time True >>> s = f*t.restrict(U); s Tensor field f*t of type (0,2) on the Open subset U of the 2-dimensional differentiable manifold S^2 >>> s.restrict(U) == f.restrict(U) * t.restrict(U) True - Same examples with SymPy as the symbolic engine - From now on, we ask that all symbolic calculus on manifold \(M\) are performed by SymPy: - sage: M.set_calculus_method('sympy') - >>> from sage.all import * >>> M.set_calculus_method('sympy') - We define the tensor \(t\) as above: - sage: t = M.tensor_field(0, 2, {eU: [[1,0], [-2,3]]}, name='t') sage: t.display(eU) t = dx⊗dx - 2 dy⊗dx + 3 dy⊗dy sage: t.add_comp_by_continuation(eV, W, chart=c_uv) # long time sage: t.display(eV) # long time t = (u**4 - 4*u**3*v + 10*u**2*v**2 + 4*u*v**3 + v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) du⊗du + 4*u*v*(-u**2 - 2*u*v + v**2)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) du⊗dv + 2*(u**4 - 2*u**3*v - 2*u**2*v**2 + 2*u*v**3 + v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) dv⊗du + (3*u**4 + 4*u**3*v - 2*u**2*v**2 - 4*u*v**3 + 3*v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) dv⊗dv - >>> from sage.all import * >>> t = M.tensor_field(Integer(0), Integer(2), {eU: [[Integer(1),Integer(0)], [-Integer(2),Integer(3)]]}, name='t') >>> t.display(eU) t = dx⊗dx - 2 dy⊗dx + 3 dy⊗dy >>> t.add_comp_by_continuation(eV, W, chart=c_uv) # long time >>> t.display(eV) # long time t = (u**4 - 4*u**3*v + 10*u**2*v**2 + 4*u*v**3 + v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) du⊗du + 4*u*v*(-u**2 - 2*u*v + v**2)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) du⊗dv + 2*(u**4 - 2*u**3*v - 2*u**2*v**2 + 2*u*v**3 + v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) dv⊗du + (3*u**4 + 4*u**3*v - 2*u**2*v**2 - 4*u*v**3 + 3*v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) dv⊗dv - The default coordinate representations of tensor components are now SymPy objects: - sage: t[eV,1,1,c_uv].expr() # long time (3*u**4 + 4*u**3*v - 2*u**2*v**2 - 4*u*v**3 + 3*v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) sage: type(t[eV,1,1,c_uv].expr()) # long time <class 'sympy.core.mul.Mul'> - >>> from sage.all import * >>> t[eV,Integer(1),Integer(1),c_uv].expr() # long time (3*u**4 + 4*u**3*v - 2*u**2*v**2 - 4*u*v**3 + 3*v**4)/(u**8 + 4*u**6*v**2 + 6*u**4*v**4 + 4*u**2*v**6 + v**8) >>> type(t[eV,Integer(1),Integer(1),c_uv].expr()) # long time <class 'sympy.core.mul.Mul'> - Let us consider two vector fields, \(a\) and \(b\), on \(S^2\): - sage: a = M.vector_field({eU: [-y, x]}, name='a') sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: a.display(eV) a = -v ∂/∂u + u ∂/∂v sage: b = M.vector_field({eU: [y, -1]}, name='b') sage: b.add_comp_by_continuation(eV, W, chart=c_uv) sage: b.display(eV) b = v*(2*u**3 - u**2 + 2*u*v**2 + v**2)/(u**2 + v**2) ∂/∂u + (-u**4 - 2*u*v**2 + v**4)/(u**2 + v**2) ∂/∂v - >>> from sage.all import * >>> a = M.vector_field({eU: [-y, x]}, name='a') >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> a.display(eV) a = -v ∂/∂u + u ∂/∂v >>> b = M.vector_field({eU: [y, -Integer(1)]}, name='b') >>> b.add_comp_by_continuation(eV, W, chart=c_uv) >>> b.display(eV) b = v*(2*u**3 - u**2 + 2*u*v**2 + v**2)/(u**2 + v**2) ∂/∂u + (-u**4 - 2*u*v**2 + v**4)/(u**2 + v**2) ∂/∂v - As a tensor field of type \((0,2)\), \(t\) acts on the pair \((a,b)\), resulting in a scalar field: - sage: f = t(a,b) sage: f.display() # long time t(a,b): S^2 → ℝ on U: (x, y) ↦ -2*x*y - 3*x - y**2 on V: (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) - >>> from sage.all import * >>> f = t(a,b) >>> f.display() # long time t(a,b): S^2 → ℝ on U: (x, y) ↦ -2*x*y - 3*x - y**2 on V: (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) - The vectors can be defined only on subsets of \(S^2\), the domain of the result is then the common subset: - sage: s = t(a.restrict(U), b) sage: s.display() # long time t(a,b): U → ℝ (x, y) ↦ -2*x*y - 3*x - y**2 on W: (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) sage: s = t(a.restrict(U), b.restrict(W)) # long time sage: s.display() # long time t(a,b): W → ℝ (x, y) ↦ -2*x*y - 3*x - y**2 (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) - >>> from sage.all import * >>> s = t(a.restrict(U), b) >>> s.display() # long time t(a,b): U → ℝ (x, y) ↦ -2*x*y - 3*x - y**2 on W: (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) >>> s = t(a.restrict(U), b.restrict(W)) # long time >>> s.display() # long time t(a,b): W → ℝ (x, y) ↦ -2*x*y - 3*x - y**2 (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) - The tensor itself can be defined only on some open subset of \(S^2\), yielding a result whose domain is this subset: - sage: s = t.restrict(V)(a,b) # long time sage: s.display() # long time t(a,b): V → ℝ (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) on W: (x, y) ↦ -2*x*y - 3*x - y**2 - >>> from sage.all import * >>> s = t.restrict(V)(a,b) # long time >>> s.display() # long time t(a,b): V → ℝ (u, v) ↦ (-3*u**3 - 3*u*v**2 - 2*u*v - v**2)/(u**4 + 2*u**2*v**2 + v**4) on W: (x, y) ↦ -2*x*y - 3*x - y**2 - Tests regarding the multiplication by a scalar field: - sage: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), ....: c_uv: (u^2 + v^2)/(u^2 + v^2 + 1)}, name='f') sage: s = f*t # long time sage: s[[0,0]] == f*t[[0,0]] # long time True sage: s.restrict(U) == f.restrict(U) * t.restrict(U) # long time True sage: s = f*t.restrict(U) sage: s.restrict(U) == f.restrict(U) * t.restrict(U) True - >>> from sage.all import * >>> f = M.scalar_field({c_xy: Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), ... c_uv: (u**Integer(2) + v**Integer(2))/(u**Integer(2) + v**Integer(2) + Integer(1))}, name='f') >>> s = f*t # long time >>> s[[Integer(0),Integer(0)]] == f*t[[Integer(0),Integer(0)]] # long time True >>> s.restrict(U) == f.restrict(U) * t.restrict(U) # long time True >>> s = f*t.restrict(U) >>> s.restrict(U) == f.restrict(U) * t.restrict(U) True - Notice that the zero tensor field is immutable, and therefore its components cannot be changed: - sage: zer = M.tensor_field_module((1, 1)).zero() sage: zer.is_immutable() True sage: zer.set_comp() Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed - >>> from sage.all import * >>> zer = M.tensor_field_module((Integer(1), Integer(1))).zero() >>> zer.is_immutable() True >>> zer.set_comp() Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed - Other tensor fields can be declared immutable, too: - sage: t.is_immutable() False sage: t.set_immutable() sage: t.is_immutable() True sage: t.set_comp() Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed sage: t.set_name('b') Traceback (most recent call last): ... ValueError: the name of an immutable element cannot be changed - >>> from sage.all import * >>> t.is_immutable() False >>> t.set_immutable() >>> t.is_immutable() True >>> t.set_comp() Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed >>> t.set_name('b') Traceback (most recent call last): ... ValueError: the name of an immutable element cannot be changed - add_comp(basis=None)[source]¶
- Return the components of - selfin a given vector frame for assignment.- The components with respect to other frames having the same domain as the provided vector frame are kept. To delete them, use the method - set_comp()instead.- INPUT: - basis– (default:- None) vector frame in which the components are defined; if- None, the components are assumed to refer to the tensor field domain’s default frame
 - OUTPUT: - components in the given frame, as a - Components; if such components did not exist previously, they are created
 - EXAMPLES: - sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole sage: V = M.open_subset('V') # complement of the South pole sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: e_uv = c_uv.frame() sage: t = M.tensor_field(1, 2, name='t') sage: t.add_comp(e_uv) 3-indices components w.r.t. Coordinate frame (V, (∂/∂u,∂/∂v)) sage: t.add_comp(e_uv)[1,0,1] = u+v sage: t.display(e_uv) t = (u + v) ∂/∂v⊗du⊗dv - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') # the 2-dimensional sphere S^2 >>> U = M.open_subset('U') # complement of the North pole >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole >>> V = M.open_subset('V') # complement of the South pole >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole >>> M.declare_union(U,V) # S^2 is the union of U and V >>> e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1), Integer(2), name='t') >>> t.add_comp(e_uv) 3-indices components w.r.t. Coordinate frame (V, (∂/∂u,∂/∂v)) >>> t.add_comp(e_uv)[Integer(1),Integer(0),Integer(1)] = u+v >>> t.display(e_uv) t = (u + v) ∂/∂v⊗du⊗dv - Setting the components in a new frame: - sage: e = V.vector_frame('e') sage: t.add_comp(e) 3-indices components w.r.t. Vector frame (V, (e_0,e_1)) sage: t.add_comp(e)[0,1,1] = u*v sage: t.display(e) t = u*v e_0⊗e^1⊗e^1 - >>> from sage.all import * >>> e = V.vector_frame('e') >>> t.add_comp(e) 3-indices components w.r.t. Vector frame (V, (e_0,e_1)) >>> t.add_comp(e)[Integer(0),Integer(1),Integer(1)] = u*v >>> t.display(e) t = u*v e_0⊗e^1⊗e^1 - The components with respect to - e_uvare kept:- sage: t.display(e_uv) t = (u + v) ∂/∂v⊗du⊗dv - >>> from sage.all import * >>> t.display(e_uv) t = (u + v) ∂/∂v⊗du⊗dv - Since zero is a special element, its components cannot be changed: - sage: z = M.tensor_field_module((1, 1)).zero() sage: z.add_comp(e_uv)[1, 1] = u^2 Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed - >>> from sage.all import * >>> z = M.tensor_field_module((Integer(1), Integer(1))).zero() >>> z.add_comp(e_uv)[Integer(1), Integer(1)] = u**Integer(2) Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed 
 - add_comp_by_continuation(frame, subdomain, chart=None)[source]¶
- Set components with respect to a vector frame by continuation of the coordinate expression of the components in a subframe. - The continuation is performed by demanding that the components have the same coordinate expression as those on the restriction of the frame to a given subdomain. - INPUT: - frame– vector frame \(e\) in which the components are to be set
- subdomain– open subset of \(e\)’s domain in which the components are known or can be evaluated from other components
- chart– (default:- None) coordinate chart on \(e\)’s domain in which the extension of the expression of the components is to be performed; if- None, the default’s chart of \(e\)’s domain is assumed
 - EXAMPLES: - Components of a vector field on the sphere \(S^2\): - sage: M = Manifold(2, 'S^2', start_index=1) - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2', start_index=Integer(1)) - The two open subsets covered by stereographic coordinates (North and South): - sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # S^2 is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() # stereographic coordinates sage: transf = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), ....: intersection_name='W', restrictions1= x^2+y^2!=0, ....: restrictions2= u^2+v^2!=0) sage: inv = transf.inverse() sage: W = U.intersection(V) # The complement of the two poles sage: eU = c_xy.frame() ; eV = c_uv.frame() sage: a = M.vector_field({eU: [x, 2+y]}, name='a') - >>> from sage.all import * >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # S^2 is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates >>> transf = c_xy.transition_map(c_uv, (x/(x**Integer(2)+y**Integer(2)), y/(x**Integer(2)+y**Integer(2))), ... intersection_name='W', restrictions1= x**Integer(2)+y**Integer(2)!=Integer(0), ... restrictions2= u**Integer(2)+v**Integer(2)!=Integer(0)) >>> inv = transf.inverse() >>> W = U.intersection(V) # The complement of the two poles >>> eU = c_xy.frame() ; eV = c_uv.frame() >>> a = M.vector_field({eU: [x, Integer(2)+y]}, name='a') - At this stage, the vector field has been defined only on the open subset - U(through its components in the frame- eU):- sage: a.display(eU) a = x ∂/∂x + (y + 2) ∂/∂y - >>> from sage.all import * >>> a.display(eU) a = x ∂/∂x + (y + 2) ∂/∂y - The components with respect to the restriction of - eVto the common subdomain- W, in terms of the- (u,v)coordinates, are obtained by a change-of-frame formula on- W:- sage: a.display(eV.restrict(W), c_uv.restrict(W)) a = (-4*u*v - u) ∂/∂u + (2*u^2 - 2*v^2 - v) ∂/∂v - >>> from sage.all import * >>> a.display(eV.restrict(W), c_uv.restrict(W)) a = (-4*u*v - u) ∂/∂u + (2*u^2 - 2*v^2 - v) ∂/∂v - The continuation consists in extending the definition of the vector field to the whole open subset - Vby demanding that the components in the frame eV have the same coordinate expression as the above one:- sage: a.add_comp_by_continuation(eV, W, chart=c_uv) - >>> from sage.all import * >>> a.add_comp_by_continuation(eV, W, chart=c_uv) - We have then: - sage: a.display(eV) a = (-4*u*v - u) ∂/∂u + (2*u^2 - 2*v^2 - v) ∂/∂v - >>> from sage.all import * >>> a.display(eV) a = (-4*u*v - u) ∂/∂u + (2*u^2 - 2*v^2 - v) ∂/∂v - and \(a\) is defined on the entire manifold \(S^2\). 
 - add_expr_from_subdomain(frame, subdomain)[source]¶
- Add an expression to an existing component from a subdomain. - INPUT: - frame– vector frame \(e\) in which the components are to be set
- subdomain– open subset of \(e\)’s domain in which the components have additional expressions
 - EXAMPLES: - We are going to consider a vector field in \(\RR^3\) along the 2-sphere: - sage: M = Manifold(3, 'M', structure='Riemannian') sage: S = Manifold(2, 'S', structure='Riemannian') sage: E.<X,Y,Z> = M.chart() - >>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='Riemannian') >>> S = Manifold(Integer(2), 'S', structure='Riemannian') >>> E = M.chart(names=('X', 'Y', 'Z',)); (X, Y, Z,) = E._first_ngens(3) - Let us define - Sin terms of stereographic charts:- sage: U = S.open_subset('U') sage: V = S.open_subset('V') sage: S.declare_union(U,V) sage: stereoN.<x,y> = U.chart() sage: stereoS.<xp,yp> = V.chart("xp:x' yp:y'") sage: stereoN_to_S = stereoN.transition_map(stereoS, ....: (x/(x^2+y^2), y/(x^2+y^2)), ....: intersection_name='W', ....: restrictions1= x^2+y^2!=0, ....: restrictions2= xp^2+yp^2!=0) sage: stereoS_to_N = stereoN_to_S.inverse() sage: W = U.intersection(V) sage: stereoN_W = stereoN.restrict(W) sage: stereoS_W = stereoS.restrict(W) - >>> from sage.all import * >>> U = S.open_subset('U') >>> V = S.open_subset('V') >>> S.declare_union(U,V) >>> stereoN = U.chart(names=('x', 'y',)); (x, y,) = stereoN._first_ngens(2) >>> stereoS = V.chart("xp:x' yp:y'", names=('xp', 'yp',)); (xp, yp,) = stereoS._first_ngens(2) >>> stereoN_to_S = stereoN.transition_map(stereoS, ... (x/(x**Integer(2)+y**Integer(2)), y/(x**Integer(2)+y**Integer(2))), ... intersection_name='W', ... restrictions1= x**Integer(2)+y**Integer(2)!=Integer(0), ... restrictions2= xp**Integer(2)+yp**Integer(2)!=Integer(0)) >>> stereoS_to_N = stereoN_to_S.inverse() >>> W = U.intersection(V) >>> stereoN_W = stereoN.restrict(W) >>> stereoS_W = stereoS.restrict(W) - The embedding of \(S^2\) in \(\RR^3\): - sage: phi = S.diff_map(M, {(stereoN, E): [2*x/(1+x^2+y^2), ....: 2*y/(1+x^2+y^2), ....: (x^2+y^2-1)/(1+x^2+y^2)], ....: (stereoS, E): [2*xp/(1+xp^2+yp^2), ....: 2*yp/(1+xp^2+yp^2), ....: (1-xp^2-yp^2)/(1+xp^2+yp^2)]}, ....: name='Phi', latex_name=r'\Phi') - >>> from sage.all import * >>> phi = S.diff_map(M, {(stereoN, E): [Integer(2)*x/(Integer(1)+x**Integer(2)+y**Integer(2)), ... Integer(2)*y/(Integer(1)+x**Integer(2)+y**Integer(2)), ... (x**Integer(2)+y**Integer(2)-Integer(1))/(Integer(1)+x**Integer(2)+y**Integer(2))], ... (stereoS, E): [Integer(2)*xp/(Integer(1)+xp**Integer(2)+yp**Integer(2)), ... Integer(2)*yp/(Integer(1)+xp**Integer(2)+yp**Integer(2)), ... (Integer(1)-xp**Integer(2)-yp**Integer(2))/(Integer(1)+xp**Integer(2)+yp**Integer(2))]}, ... name='Phi', latex_name=r'\Phi') - To define a vector field - valong- Staking its values in- M, we first set the components on- U:- sage: v = M.vector_field(name='v').along(phi) sage: vU = v.restrict(U) sage: vU[:] = [x,y,x**2+y**2] - >>> from sage.all import * >>> v = M.vector_field(name='v').along(phi) >>> vU = v.restrict(U) >>> vU[:] = [x,y,x**Integer(2)+y**Integer(2)] - But because - Mis parallelizable, these components can be extended to- Sitself:- sage: v.add_comp_by_continuation(E.frame().along(phi), U) - >>> from sage.all import * >>> v.add_comp_by_continuation(E.frame().along(phi), U) - One can see that - vis not yet fully defined: the components (scalar fields) do not have values on the whole manifold:- sage: sorted(v._components.values())[0]._comp[(0,)].display() S → ℝ on U: (x, y) ↦ x on W: (xp, yp) ↦ xp/(xp^2 + yp^2) - >>> from sage.all import * >>> sorted(v._components.values())[Integer(0)]._comp[(Integer(0),)].display() S → ℝ on U: (x, y) ↦ x on W: (xp, yp) ↦ xp/(xp^2 + yp^2) - To fix that, we first extend the components from - Wto- Vusing- add_comp_by_continuation():- sage: v.add_comp_by_continuation(E.frame().along(phi).restrict(V), ....: W, stereoS) - >>> from sage.all import * >>> v.add_comp_by_continuation(E.frame().along(phi).restrict(V), ... W, stereoS) - Then, the expression on the subdomain - Vis added to the already known components on- Sby:- sage: v.add_expr_from_subdomain(E.frame().along(phi), V) - >>> from sage.all import * >>> v.add_expr_from_subdomain(E.frame().along(phi), V) - The definition of - vis now complete:- sage: sorted(v._components.values())[0]._comp[(2,)].display() S → ℝ on U: (x, y) ↦ x^2 + y^2 on V: (xp, yp) ↦ 1/(xp^2 + yp^2) - >>> from sage.all import * >>> sorted(v._components.values())[Integer(0)]._comp[(Integer(2),)].display() S → ℝ on U: (x, y) ↦ x^2 + y^2 on V: (xp, yp) ↦ 1/(xp^2 + yp^2) 
 - along(mapping)[source]¶
- Return the tensor field deduced from - selfvia a differentiable map, the codomain of which is included in the domain of- self.- More precisely, if - selfis a tensor field \(t\) on \(M\) and if \(\Phi: U \rightarrow M\) is a differentiable map from some differentiable manifold \(U\) to \(M\), the returned object is a tensor field \(\tilde t\) along \(U\) with values on \(M\) such that\[\forall p \in U,\ \tilde t(p) = t(\Phi(p)).\]- INPUT: - mapping– differentiable map \(\Phi: U \rightarrow M\)
 - OUTPUT: tensor field \(\tilde t\) along \(U\) defined above - EXAMPLES: - Let us consider the 2-dimensional sphere \(S^2\): - sage: M = Manifold(2, 'S^2') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole sage: V = M.open_subset('V') # complement of the South pole sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), ....: intersection_name='W', restrictions1= x^2+y^2!=0, ....: restrictions2= u^2+v^2!=0) sage: uv_to_xy = xy_to_uv.inverse() sage: W = U.intersection(V) - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2') # the 2-dimensional sphere S^2 >>> U = M.open_subset('U') # complement of the North pole >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole >>> V = M.open_subset('V') # complement of the South pole >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole >>> M.declare_union(U,V) # S^2 is the union of U and V >>> xy_to_uv = c_xy.transition_map(c_uv, (x/(x**Integer(2)+y**Integer(2)), y/(x**Integer(2)+y**Integer(2))), ... intersection_name='W', restrictions1= x**Integer(2)+y**Integer(2)!=Integer(0), ... restrictions2= u**Integer(2)+v**Integer(2)!=Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> W = U.intersection(V) - and the following map from the open interval \((0,5\pi/2)\) to \(S^2\), the image of it being the great circle \(x=0\), \(u=0\), which goes through the North and South poles: - sage: I.<t> = manifolds.OpenInterval(0, 5*pi/2) sage: J = I.open_interval(0, 3*pi/2) sage: K = I.open_interval(pi, 5*pi/2) sage: c_J = J.canonical_chart(); c_K = K.canonical_chart() sage: Phi = I.diff_map(M, {(c_J, c_xy): ....: (0, sgn(pi-t)*sqrt((1+cos(t))/(1-cos(t)))), ....: (c_K, c_uv): ....: (0, sgn(t-2*pi)*sqrt((1-cos(t))/(1+cos(t))))}, ....: name='Phi') - >>> from sage.all import * >>> I = manifolds.OpenInterval(Integer(0), Integer(5)*pi/Integer(2), names=('t',)); (t,) = I._first_ngens(1) >>> J = I.open_interval(Integer(0), Integer(3)*pi/Integer(2)) >>> K = I.open_interval(pi, Integer(5)*pi/Integer(2)) >>> c_J = J.canonical_chart(); c_K = K.canonical_chart() >>> Phi = I.diff_map(M, {(c_J, c_xy): ... (Integer(0), sgn(pi-t)*sqrt((Integer(1)+cos(t))/(Integer(1)-cos(t)))), ... (c_K, c_uv): ... (Integer(0), sgn(t-Integer(2)*pi)*sqrt((Integer(1)-cos(t))/(Integer(1)+cos(t))))}, ... name='Phi') - Let us consider a vector field on \(S^2\): - sage: eU = c_xy.frame(); eV = c_uv.frame() sage: w = M.vector_field(name='w') sage: w[eU,0] = 1 sage: w.add_comp_by_continuation(eV, W, chart=c_uv) sage: w.display(eU) w = ∂/∂x sage: w.display(eV) w = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v - >>> from sage.all import * >>> eU = c_xy.frame(); eV = c_uv.frame() >>> w = M.vector_field(name='w') >>> w[eU,Integer(0)] = Integer(1) >>> w.add_comp_by_continuation(eV, W, chart=c_uv) >>> w.display(eU) w = ∂/∂x >>> w.display(eV) w = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v - We have then: - sage: wa = w.along(Phi); wa Vector field w along the Real interval (0, 5/2*pi) with values on the 2-dimensional differentiable manifold S^2 sage: wa.display(eU.along(Phi)) w = ∂/∂x sage: wa.display(eV.along(Phi)) w = -(cos(t) - 1)*sgn(-2*pi + t)^2/(cos(t) + 1) ∂/∂u - >>> from sage.all import * >>> wa = w.along(Phi); wa Vector field w along the Real interval (0, 5/2*pi) with values on the 2-dimensional differentiable manifold S^2 >>> wa.display(eU.along(Phi)) w = ∂/∂x >>> wa.display(eV.along(Phi)) w = -(cos(t) - 1)*sgn(-2*pi + t)^2/(cos(t) + 1) ∂/∂u - Some tests: - sage: p = K.an_element() sage: wa.at(p) == w.at(Phi(p)) True sage: wa.at(J(4*pi/3)) == wa.at(K(4*pi/3)) True sage: wa.at(I(4*pi/3)) == wa.at(K(4*pi/3)) True sage: wa.at(K(7*pi/4)) == eU[0].at(Phi(I(7*pi/4))) # since eU[0]=∂/∂x True - >>> from sage.all import * >>> p = K.an_element() >>> wa.at(p) == w.at(Phi(p)) True >>> wa.at(J(Integer(4)*pi/Integer(3))) == wa.at(K(Integer(4)*pi/Integer(3))) True >>> wa.at(I(Integer(4)*pi/Integer(3))) == wa.at(K(Integer(4)*pi/Integer(3))) True >>> wa.at(K(Integer(7)*pi/Integer(4))) == eU[Integer(0)].at(Phi(I(Integer(7)*pi/Integer(4)))) # since eU[0]=∂/∂x True 
 - antisymmetrize(*pos)[source]¶
- Antisymmetrization over some arguments. - INPUT: - pos– (default:- None) list of argument positions involved in the antisymmetrization (with the convention- position=0for the first argument); if- None, the antisymmetrization is performed over all the arguments
 - OUTPUT: - the antisymmetrized tensor field (instance of - TensorField)
 - EXAMPLES: - Antisymmetrization of a type-\((0,2)\) tensor field on a 2-dimensional non-parallelizable manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ....: restrictions1= x>0, restrictions2= u+v>0) sage: inv = transf.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_uv.frame() sage: a = M.tensor_field(0,2, {eU: [[1,x], [2,y]]}, name='a') sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: a[eV,:] [ 1/4*u + 3/4 -1/4*u + 3/4] [ 1/4*v - 1/4 -1/4*v - 1/4] sage: s = a.antisymmetrize() ; s 2-form on the 2-dimensional differentiable manifold M sage: s[eU,:] [ 0 1/2*x - 1] [-1/2*x + 1 0] sage: s[eV,:] [ 0 -1/8*u - 1/8*v + 1/2] [ 1/8*u + 1/8*v - 1/2 0] sage: s == a.antisymmetrize(0,1) # explicit positions True sage: s == a.antisymmetrize(1,0) # the order of positions does not matter True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ... restrictions1= x>Integer(0), restrictions2= u+v>Integer(0)) >>> inv = transf.inverse() >>> W = U.intersection(V) >>> eU = c_xy.frame() ; eV = c_uv.frame() >>> a = M.tensor_field(Integer(0),Integer(2), {eU: [[Integer(1),x], [Integer(2),y]]}, name='a') >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> a[eV,:] [ 1/4*u + 3/4 -1/4*u + 3/4] [ 1/4*v - 1/4 -1/4*v - 1/4] >>> s = a.antisymmetrize() ; s 2-form on the 2-dimensional differentiable manifold M >>> s[eU,:] [ 0 1/2*x - 1] [-1/2*x + 1 0] >>> s[eV,:] [ 0 -1/8*u - 1/8*v + 1/2] [ 1/8*u + 1/8*v - 1/2 0] >>> s == a.antisymmetrize(Integer(0),Integer(1)) # explicit positions True >>> s == a.antisymmetrize(Integer(1),Integer(0)) # the order of positions does not matter True - See also - For more details and examples, see - sage.tensor.modules.free_module_tensor.FreeModuleTensor.antisymmetrize().
 - apply_map(fun, frame=None, chart=None, keep_other_components=False)[source]¶
- Apply a function to the coordinate expressions of all components of - selfin a given vector frame.- This method allows operations like factorization, expansion, simplification or substitution to be performed on all components of - selfin a given vector frame (see examples below).- INPUT: - fun– function to be applied to the coordinate expressions of the components
- frame– (default:- None) vector frame defining the components on which the operation- funis to be performed; if- None, the default frame of the domain of- selfis assumed
- chart– (default:- None) coordinate chart; if specified, the operation- funis performed only on the coordinate expressions with respect to- chartof the components w.r.t.- frame; if- None, the operation- funis performed on all available coordinate expressions
- keep_other_components– boolean (default:- False); determine whether the components with respect to vector frames distinct from- frameand having the same domain as- frameare kept. If- funis non-destructive,- keep_other_componentscan be set to- True; otherwise, it is advised to set it to- False(the default) in order to avoid any inconsistency between the various sets of components
 - EXAMPLES: - Factorizing all components in the default frame of a vector field: - sage: M = Manifold(2, 'M') sage: X.<x,y> = M.chart() sage: a, b = var('a b') sage: v = M.vector_field(x^2 - y^2, a*(b^2 - b)*x) sage: v.display() (x^2 - y^2) ∂/∂x + (b^2 - b)*a*x ∂/∂y sage: v.apply_map(factor) sage: v.display() (x + y)*(x - y) ∂/∂x + a*(b - 1)*b*x ∂/∂y - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> a, b = var('a b') >>> v = M.vector_field(x**Integer(2) - y**Integer(2), a*(b**Integer(2) - b)*x) >>> v.display() (x^2 - y^2) ∂/∂x + (b^2 - b)*a*x ∂/∂y >>> v.apply_map(factor) >>> v.display() (x + y)*(x - y) ∂/∂x + a*(b - 1)*b*x ∂/∂y - Performing a substitution in all components in the default frame: - sage: v.apply_map(lambda f: f.subs({a: 2})) sage: v.display() (x + y)*(x - y) ∂/∂x + 2*(b - 1)*b*x ∂/∂y - >>> from sage.all import * >>> v.apply_map(lambda f: f.subs({a: Integer(2)})) >>> v.display() (x + y)*(x - y) ∂/∂x + 2*(b - 1)*b*x ∂/∂y - Specifying the vector frame via the argument - frame:- sage: P.<p, q> = M.chart() sage: X_to_P = X.transition_map(P, [x + 1, y - 1]) sage: P_to_X = X_to_P.inverse() sage: v.display(P) (p^2 - q^2 - 2*p - 2*q) ∂/∂p + (-2*b^2 + 2*(b^2 - b)*p + 2*b) ∂/∂q sage: v.apply_map(lambda f: f.subs({b: pi}), frame=P.frame()) sage: v.display(P) (p^2 - q^2 - 2*p - 2*q) ∂/∂p + (2*pi - 2*pi^2 - 2*(pi - pi^2)*p) ∂/∂q - >>> from sage.all import * >>> P = M.chart(names=('p', 'q',)); (p, q,) = P._first_ngens(2) >>> X_to_P = X.transition_map(P, [x + Integer(1), y - Integer(1)]) >>> P_to_X = X_to_P.inverse() >>> v.display(P) (p^2 - q^2 - 2*p - 2*q) ∂/∂p + (-2*b^2 + 2*(b^2 - b)*p + 2*b) ∂/∂q >>> v.apply_map(lambda f: f.subs({b: pi}), frame=P.frame()) >>> v.display(P) (p^2 - q^2 - 2*p - 2*q) ∂/∂p + (2*pi - 2*pi^2 - 2*(pi - pi^2)*p) ∂/∂q - Note that the required operation has been performed in all charts: - sage: v.display(P.frame(), P) (p^2 - q^2 - 2*p - 2*q) ∂/∂p + (2*pi - 2*pi^2 - 2*(pi - pi^2)*p) ∂/∂q sage: v.display(P.frame(), X) (x + y)*(x - y) ∂/∂p + 2*pi*(pi - 1)*x ∂/∂q - >>> from sage.all import * >>> v.display(P.frame(), P) (p^2 - q^2 - 2*p - 2*q) ∂/∂p + (2*pi - 2*pi^2 - 2*(pi - pi^2)*p) ∂/∂q >>> v.display(P.frame(), X) (x + y)*(x - y) ∂/∂p + 2*pi*(pi - 1)*x ∂/∂q - By default, the components of - vin frames distinct from the specified one have been deleted:- sage: X.frame() in v._components False - >>> from sage.all import * >>> X.frame() in v._components False - When requested, they are recomputed by change-of-frame formulas, thereby enforcing the consistency between the representations in various vector frames. In particular, we can check that the substitution of - bby- pi, which was asked in- P.frame(), is effective in- X.frame()as well:- sage: v.display(X.frame(), X) (x + y)*(x - y) ∂/∂x + 2*pi*(pi - 1)*x ∂/∂y - >>> from sage.all import * >>> v.display(X.frame(), X) (x + y)*(x - y) ∂/∂x + 2*pi*(pi - 1)*x ∂/∂y - When the requested operation does not change the value of the tensor field, one can use the keyword argument - keep_other_components=True, in order to avoid the recomputation of the components in other frames:- sage: v.apply_map(factor, keep_other_components=True) sage: v.display() (x + y)*(x - y) ∂/∂x + 2*pi*(pi - 1)*x ∂/∂y - >>> from sage.all import * >>> v.apply_map(factor, keep_other_components=True) >>> v.display() (x + y)*(x - y) ∂/∂x + 2*pi*(pi - 1)*x ∂/∂y - The components with respect to - P.frame()have been kept:- sage: P.frame() in v._components True - >>> from sage.all import * >>> P.frame() in v._components True - One can restrict the operation to expressions in a given chart, via the argument - chart:- sage: v.display(X.frame(), P) (p + q)*(p - q - 2) ∂/∂x + 2*pi*(pi - 1)*(p - 1) ∂/∂y sage: v.apply_map(expand, chart=P) sage: v.display(X.frame(), P) (p^2 - q^2 - 2*p - 2*q) ∂/∂x + (2*pi + 2*pi^2*p - 2*pi^2 - 2*pi*p) ∂/∂y sage: v.display(X.frame(), X) (x + y)*(x - y) ∂/∂x + 2*pi*(pi - 1)*x ∂/∂y - >>> from sage.all import * >>> v.display(X.frame(), P) (p + q)*(p - q - 2) ∂/∂x + 2*pi*(pi - 1)*(p - 1) ∂/∂y >>> v.apply_map(expand, chart=P) >>> v.display(X.frame(), P) (p^2 - q^2 - 2*p - 2*q) ∂/∂x + (2*pi + 2*pi^2*p - 2*pi^2 - 2*pi*p) ∂/∂y >>> v.display(X.frame(), X) (x + y)*(x - y) ∂/∂x + 2*pi*(pi - 1)*x ∂/∂y 
 - at(point)[source]¶
- Value of - selfat a point of its domain.- If the current tensor field is \[t:\ U \longrightarrow T^{(k,l)} M\]- associated with the differentiable map \[\Phi:\ U \longrightarrow M,\]- where \(U\) and \(M\) are two manifolds (possibly \(U = M\) and \(\Phi = \mathrm{Id}_M\)), then for any point \(p \in U\), \(t(p)\) is a tensor on the tangent space to \(M\) at the point \(\Phi(p)\). - INPUT: - point–- ManifoldPoint; point \(p\) in the domain of the tensor field \(U\)
 - OUTPUT: - FreeModuleTensorrepresenting the tensor \(t(p)\) on the tangent vector space \(T_{\Phi(p)} M\)
 - EXAMPLES: - Tensor on a tangent space of a non-parallelizable 2-dimensional manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: inv = transf.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_uv.frame() sage: a = M.tensor_field(1, 1, {eU: [[1+y,x], [0,x+y]]}, name='a') sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: a.display(eU) a = (y + 1) ∂/∂x⊗dx + x ∂/∂x⊗dy + (x + y) ∂/∂y⊗dy sage: a.display(eV) a = (u + 1/2) ∂/∂u⊗du + (-1/2*u - 1/2*v + 1/2) ∂/∂u⊗dv + 1/2 ∂/∂v⊗du + (1/2*u - 1/2*v + 1/2) ∂/∂v⊗dv sage: p = M.point((2,3), chart=c_xy, name='p') sage: ap = a.at(p) ; ap Type-(1,1) tensor a on the Tangent space at Point p on the 2-dimensional differentiable manifold M sage: ap.parent() Free module of type-(1,1) tensors on the Tangent space at Point p on the 2-dimensional differentiable manifold M sage: ap.display(eU.at(p)) a = 4 ∂/∂x⊗dx + 2 ∂/∂x⊗dy + 5 ∂/∂y⊗dy sage: ap.display(eV.at(p)) a = 11/2 ∂/∂u⊗du - 3/2 ∂/∂u⊗dv + 1/2 ∂/∂v⊗du + 7/2 ∂/∂v⊗dv sage: p.coord(c_uv) # to check the above expression (5, -1) - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> transf = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> inv = transf.inverse() >>> W = U.intersection(V) >>> eU = c_xy.frame() ; eV = c_uv.frame() >>> a = M.tensor_field(Integer(1), Integer(1), {eU: [[Integer(1)+y,x], [Integer(0),x+y]]}, name='a') >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> a.display(eU) a = (y + 1) ∂/∂x⊗dx + x ∂/∂x⊗dy + (x + y) ∂/∂y⊗dy >>> a.display(eV) a = (u + 1/2) ∂/∂u⊗du + (-1/2*u - 1/2*v + 1/2) ∂/∂u⊗dv + 1/2 ∂/∂v⊗du + (1/2*u - 1/2*v + 1/2) ∂/∂v⊗dv >>> p = M.point((Integer(2),Integer(3)), chart=c_xy, name='p') >>> ap = a.at(p) ; ap Type-(1,1) tensor a on the Tangent space at Point p on the 2-dimensional differentiable manifold M >>> ap.parent() Free module of type-(1,1) tensors on the Tangent space at Point p on the 2-dimensional differentiable manifold M >>> ap.display(eU.at(p)) a = 4 ∂/∂x⊗dx + 2 ∂/∂x⊗dy + 5 ∂/∂y⊗dy >>> ap.display(eV.at(p)) a = 11/2 ∂/∂u⊗du - 3/2 ∂/∂u⊗dv + 1/2 ∂/∂v⊗du + 7/2 ∂/∂v⊗dv >>> p.coord(c_uv) # to check the above expression (5, -1) 
 - base_module()[source]¶
- Return the vector field module on which - selfacts as a tensor.- OUTPUT: - instance of - VectorFieldModule
 - EXAMPLES: - The module of vector fields on the 2-sphere as a “base module”: - sage: M = Manifold(2, 'S^2') sage: t = M.tensor_field(0,2) sage: t.base_module() Module X(S^2) of vector fields on the 2-dimensional differentiable manifold S^2 sage: t.base_module() is M.vector_field_module() True sage: XM = M.vector_field_module() sage: XM.an_element().base_module() is XM True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2') >>> t = M.tensor_field(Integer(0),Integer(2)) >>> t.base_module() Module X(S^2) of vector fields on the 2-dimensional differentiable manifold S^2 >>> t.base_module() is M.vector_field_module() True >>> XM = M.vector_field_module() >>> XM.an_element().base_module() is XM True 
 - comp(basis=None, from_basis=None)[source]¶
- Return the components in a given vector frame. - If the components are not known already, they are computed by the tensor change-of-basis formula from components in another vector frame. - INPUT: - basis– (default:- None) vector frame in which the components are required; if none is provided, the components are assumed to refer to the tensor field domain’s default frame
- from_basis– (default:- None) vector frame from which the required components are computed, via the tensor change-of-basis formula, if they are not known already in the basis- basis
 - OUTPUT: - components in the vector frame - basis, as a- Components
 - EXAMPLES: - Components of a type-\((1,1)\) tensor field defined on two open subsets: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') sage: c_xy.<x, y> = U.chart() sage: e = U.default_frame() ; e Coordinate frame (U, (∂/∂x,∂/∂y)) sage: V = M.open_subset('V') sage: c_uv.<u, v> = V.chart() sage: f = V.default_frame() ; f Coordinate frame (V, (∂/∂u,∂/∂v)) sage: M.declare_union(U,V) # M is the union of U and V sage: t = M.tensor_field(1,1, name='t') sage: t[e,0,0] = - x + y^3 sage: t[e,0,1] = 2+x sage: t[f,1,1] = - u*v sage: t.comp(e) 2-indices components w.r.t. Coordinate frame (U, (∂/∂x,∂/∂y)) sage: t.comp(e)[:] [y^3 - x x + 2] [ 0 0] sage: t.comp(f) 2-indices components w.r.t. Coordinate frame (V, (∂/∂u,∂/∂v)) sage: t.comp(f)[:] [ 0 0] [ 0 -u*v] - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> e = U.default_frame() ; e Coordinate frame (U, (∂/∂x,∂/∂y)) >>> V = M.open_subset('V') >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> f = V.default_frame() ; f Coordinate frame (V, (∂/∂u,∂/∂v)) >>> M.declare_union(U,V) # M is the union of U and V >>> t = M.tensor_field(Integer(1),Integer(1), name='t') >>> t[e,Integer(0),Integer(0)] = - x + y**Integer(3) >>> t[e,Integer(0),Integer(1)] = Integer(2)+x >>> t[f,Integer(1),Integer(1)] = - u*v >>> t.comp(e) 2-indices components w.r.t. Coordinate frame (U, (∂/∂x,∂/∂y)) >>> t.comp(e)[:] [y^3 - x x + 2] [ 0 0] >>> t.comp(f) 2-indices components w.r.t. Coordinate frame (V, (∂/∂u,∂/∂v)) >>> t.comp(f)[:] [ 0 0] [ 0 -u*v] - Since - eis- M’s default frame, the argument- ecan be omitted:- sage: e is M.default_frame() True sage: t.comp() is t.comp(e) True - >>> from sage.all import * >>> e is M.default_frame() True >>> t.comp() is t.comp(e) True - Example of computation of the components via a change of frame: - sage: a = V.automorphism_field() sage: a[:] = [[1+v, -u^2], [0, 1-u]] sage: h = f.new_frame(a, 'h') sage: t.comp(h) 2-indices components w.r.t. Vector frame (V, (h_0,h_1)) sage: t.comp(h)[:] [ 0 -u^3*v/(v + 1)] [ 0 -u*v] - >>> from sage.all import * >>> a = V.automorphism_field() >>> a[:] = [[Integer(1)+v, -u**Integer(2)], [Integer(0), Integer(1)-u]] >>> h = f.new_frame(a, 'h') >>> t.comp(h) 2-indices components w.r.t. Vector frame (V, (h_0,h_1)) >>> t.comp(h)[:] [ 0 -u^3*v/(v + 1)] [ 0 -u*v] 
 - contract(*args)[source]¶
- Contraction of - selfwith another tensor field on one or more indices.- INPUT: - pos1– positions of the indices in the current tensor field involved in the contraction;- pos1must be a sequence of integers, with 0 standing for the first index position, 1 for the second one, etc.; if- pos1is not provided, a single contraction on the last index position of the tensor field is assumed
- other– the tensor field to contract with
- pos2– positions of the indices in- otherinvolved in the contraction, with the same conventions as for- pos1; if- pos2is not provided, a single contraction on the first index position of- otheris assumed
 - OUTPUT: - tensor field resulting from the contraction at the positions - pos1and- pos2of the tensor field with- other
 - EXAMPLES: - Contractions of a type-\((1,1)\) tensor field with a type-\((2,0)\) one on a 2-dimensional non-parallelizable manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ....: restrictions1= x>0, restrictions2= u+v>0) sage: inv = transf.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_uv.frame() sage: a = M.tensor_field(1, 1, {eU: [[1, x], [0, 2]]}, name='a') sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: b = M.tensor_field(2, 0, {eU: [[y, -1], [x+y, 2]]}, name='b') sage: b.add_comp_by_continuation(eV, W, chart=c_uv) sage: s = a.contract(b) ; s # contraction on last index of a and first one of b Tensor field of type (2,0) on the 2-dimensional differentiable manifold M - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ... restrictions1= x>Integer(0), restrictions2= u+v>Integer(0)) >>> inv = transf.inverse() >>> W = U.intersection(V) >>> eU = c_xy.frame() ; eV = c_uv.frame() >>> a = M.tensor_field(Integer(1), Integer(1), {eU: [[Integer(1), x], [Integer(0), Integer(2)]]}, name='a') >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> b = M.tensor_field(Integer(2), Integer(0), {eU: [[y, -Integer(1)], [x+y, Integer(2)]]}, name='b') >>> b.add_comp_by_continuation(eV, W, chart=c_uv) >>> s = a.contract(b) ; s # contraction on last index of a and first one of b Tensor field of type (2,0) on the 2-dimensional differentiable manifold M - Check 1: components with respect to the manifold’s default frame ( - eU):- sage: all(bool(s[i,j] == sum(a[i,k]*b[k,j] for k in M.irange())) ....: for i in M.irange() for j in M.irange()) True - >>> from sage.all import * >>> all(bool(s[i,j] == sum(a[i,k]*b[k,j] for k in M.irange())) ... for i in M.irange() for j in M.irange()) True - Check 2: components with respect to the frame - eV:- sage: all(bool(s[eV,i,j] == sum(a[eV,i,k]*b[eV,k,j] ....: for k in M.irange())) ....: for i in M.irange() for j in M.irange()) True - >>> from sage.all import * >>> all(bool(s[eV,i,j] == sum(a[eV,i,k]*b[eV,k,j] ... for k in M.irange())) ... for i in M.irange() for j in M.irange()) True - Instead of the explicit call to the method - contract(), one may use the index notation with Einstein convention (summation over repeated indices); it suffices to pass the indices as a string inside square brackets:- sage: a['^i_k']*b['^kj'] == s True - >>> from sage.all import * >>> a['^i_k']*b['^kj'] == s True - Indices not involved in the contraction may be replaced by dots: - sage: a['^._k']*b['^k.'] == s True - >>> from sage.all import * >>> a['^._k']*b['^k.'] == s True - LaTeX notation may be used: - sage: a['^{i}_{k}']*b['^{kj}'] == s True - >>> from sage.all import * >>> a['^{i}_{k}']*b['^{kj}'] == s True - Contraction on the last index of - aand last index of- b:- sage: s = a.contract(b, 1) ; s Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: a['^i_k']*b['^jk'] == s True - >>> from sage.all import * >>> s = a.contract(b, Integer(1)) ; s Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> a['^i_k']*b['^jk'] == s True - Contraction on the first index of - band the last index of- a:- sage: s = b.contract(0,a,1) ; s Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: b['^ki']*a['^j_k'] == s True - >>> from sage.all import * >>> s = b.contract(Integer(0),a,Integer(1)) ; s Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> b['^ki']*a['^j_k'] == s True - The domain of the result is the intersection of the domains of the two tensor fields: - sage: aU = a.restrict(U) ; bV = b.restrict(V) sage: s = aU.contract(b) ; s Tensor field of type (2,0) on the Open subset U of the 2-dimensional differentiable manifold M sage: s = a.contract(bV) ; s Tensor field of type (2,0) on the Open subset V of the 2-dimensional differentiable manifold M sage: s = aU.contract(bV) ; s Tensor field of type (2,0) on the Open subset W of the 2-dimensional differentiable manifold M sage: s0 = a.contract(b) sage: s == s0.restrict(W) True - >>> from sage.all import * >>> aU = a.restrict(U) ; bV = b.restrict(V) >>> s = aU.contract(b) ; s Tensor field of type (2,0) on the Open subset U of the 2-dimensional differentiable manifold M >>> s = a.contract(bV) ; s Tensor field of type (2,0) on the Open subset V of the 2-dimensional differentiable manifold M >>> s = aU.contract(bV) ; s Tensor field of type (2,0) on the Open subset W of the 2-dimensional differentiable manifold M >>> s0 = a.contract(b) >>> s == s0.restrict(W) True - The contraction can be performed on more than one index: - cbeing a type-\((2,2)\) tensor, contracting the indices in positions 2 and 3 of- cwith respectively those in positions 0 and 1 of- bis:- sage: c = a*a ; c Tensor field of type (2,2) on the 2-dimensional differentiable manifold M sage: s = c.contract(2,3, b, 0,1) ; s # long time Tensor field of type (2,0) on the 2-dimensional differentiable manifold M - >>> from sage.all import * >>> c = a*a ; c Tensor field of type (2,2) on the 2-dimensional differentiable manifold M >>> s = c.contract(Integer(2),Integer(3), b, Integer(0),Integer(1)) ; s # long time Tensor field of type (2,0) on the 2-dimensional differentiable manifold M - The same double contraction using index notation: - sage: s == c['^.._kl']*b['^kl'] # long time True - >>> from sage.all import * >>> s == c['^.._kl']*b['^kl'] # long time True - The symmetries are either conserved or destroyed by the contraction: - sage: c = c.symmetrize(0,1).antisymmetrize(2,3) sage: c.symmetries() symmetry: (0, 1); antisymmetry: (2, 3) sage: s = b.contract(0, c, 2) ; s Tensor field of type (3,1) on the 2-dimensional differentiable manifold M sage: s.symmetries() symmetry: (1, 2); no antisymmetry - >>> from sage.all import * >>> c = c.symmetrize(Integer(0),Integer(1)).antisymmetrize(Integer(2),Integer(3)) >>> c.symmetries() symmetry: (0, 1); antisymmetry: (2, 3) >>> s = b.contract(Integer(0), c, Integer(2)) ; s Tensor field of type (3,1) on the 2-dimensional differentiable manifold M >>> s.symmetries() symmetry: (1, 2); no antisymmetry - Case of a scalar field result: - sage: a = M.one_form({eU: [y, 1+x]}, name='a') sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: b = M.vector_field({eU: [x, y^2]}, name='b') sage: b.add_comp_by_continuation(eV, W, chart=c_uv) sage: a.display(eU) a = y dx + (x + 1) dy sage: b.display(eU) b = x ∂/∂x + y^2 ∂/∂y sage: s = a.contract(b) ; s Scalar field on the 2-dimensional differentiable manifold M sage: s.display() M → ℝ on U: (x, y) ↦ (x + 1)*y^2 + x*y on V: (u, v) ↦ 1/8*u^3 - 1/8*u*v^2 + 1/8*v^3 + 1/2*u^2 - 1/8*(u^2 + 4*u)*v sage: s == a['_i']*b['^i'] # use of index notation True sage: s == b.contract(a) True - >>> from sage.all import * >>> a = M.one_form({eU: [y, Integer(1)+x]}, name='a') >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> b = M.vector_field({eU: [x, y**Integer(2)]}, name='b') >>> b.add_comp_by_continuation(eV, W, chart=c_uv) >>> a.display(eU) a = y dx + (x + 1) dy >>> b.display(eU) b = x ∂/∂x + y^2 ∂/∂y >>> s = a.contract(b) ; s Scalar field on the 2-dimensional differentiable manifold M >>> s.display() M → ℝ on U: (x, y) ↦ (x + 1)*y^2 + x*y on V: (u, v) ↦ 1/8*u^3 - 1/8*u*v^2 + 1/8*v^3 + 1/2*u^2 - 1/8*(u^2 + 4*u)*v >>> s == a['_i']*b['^i'] # use of index notation True >>> s == b.contract(a) True - Case of a vanishing scalar field result: - sage: b = M.vector_field({eU: [1+x, -y]}, name='b') sage: b.add_comp_by_continuation(eV, W, chart=c_uv) sage: s = a.contract(b) ; s Scalar field zero on the 2-dimensional differentiable manifold M sage: s.display() zero: M → ℝ on U: (x, y) ↦ 0 on V: (u, v) ↦ 0 - >>> from sage.all import * >>> b = M.vector_field({eU: [Integer(1)+x, -y]}, name='b') >>> b.add_comp_by_continuation(eV, W, chart=c_uv) >>> s = a.contract(b) ; s Scalar field zero on the 2-dimensional differentiable manifold M >>> s.display() zero: M → ℝ on U: (x, y) ↦ 0 on V: (u, v) ↦ 0 
 - copy(name=None, latex_name=None)[source]¶
- Return an exact copy of - self.- INPUT: - name– (default:- None) name given to the copy
- latex_name– (default:- None) LaTeX symbol to denote the copy; if none is provided, the LaTeX symbol is set to- name
 - Note - The name and the derived quantities are not copied. - EXAMPLES: - Copy of a type-\((1,1)\) tensor field on a 2-dimensional manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() sage: t = M.tensor_field(1, 1, name='t') sage: t[e_xy,:] = [[x+y, 0], [2, 1-y]] sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: s = t.copy(); s Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: s.display(e_xy) (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy sage: s == t True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> e_xy = c_xy.frame(); e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1), Integer(1), name='t') >>> t[e_xy,:] = [[x+y, Integer(0)], [Integer(2), Integer(1)-y]] >>> t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> s = t.copy(); s Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> s.display(e_xy) (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy >>> s == t True - If the original tensor field is modified, the copy is not: - sage: t[e_xy,0,0] = -1 sage: t.display(e_xy) t = -∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy sage: s.display(e_xy) (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy sage: s == t False - >>> from sage.all import * >>> t[e_xy,Integer(0),Integer(0)] = -Integer(1) >>> t.display(e_xy) t = -∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy >>> s.display(e_xy) (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy >>> s == t False 
 - copy_from(other)[source]¶
- Make - selfa copy of- other.- INPUT: - other– other tensor field, in the same module as- self
 - Note - While the derived quantities are not copied, the name is kept. - Warning - All previous defined components and restrictions will be deleted! - EXAMPLES: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() sage: t = M.tensor_field(1, 1, name='t') sage: t[e_xy,:] = [[x+y, 0], [2, 1-y]] sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: s = M.tensor_field(1, 1, name='s') sage: s.copy_from(t) sage: s.display(e_xy) s = (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy sage: s == t True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> e_xy = c_xy.frame(); e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1), Integer(1), name='t') >>> t[e_xy,:] = [[x+y, Integer(0)], [Integer(2), Integer(1)-y]] >>> t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> s = M.tensor_field(Integer(1), Integer(1), name='s') >>> s.copy_from(t) >>> s.display(e_xy) s = (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy >>> s == t True - While the original tensor field is modified, the copy is not: - sage: t[e_xy,0,0] = -1 sage: t.display(e_xy) t = -∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy sage: s.display(e_xy) s = (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy sage: s == t False - >>> from sage.all import * >>> t[e_xy,Integer(0),Integer(0)] = -Integer(1) >>> t.display(e_xy) t = -∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy >>> s.display(e_xy) s = (x + y) ∂/∂x⊗dx + 2 ∂/∂y⊗dx + (-y + 1) ∂/∂y⊗dy >>> s == t False 
 - dalembertian(metric=None)[source]¶
- Return the d’Alembertian of - selfwith respect to a given Lorentzian metric.- The d’Alembertian of a tensor field \(t\) with respect to a Lorentzian metric \(g\) is nothing but the Laplace-Beltrami operator of \(g\) applied to \(t\) (see - laplacian()); if- selfa tensor field \(t\) of type \((k,l)\), the d’Alembertian of \(t\) with respect to \(g\) is then the tensor field of type \((k,l)\) defined by\[(\Box t)^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\,{b_1\ldots b_k}} = \nabla_i \nabla^i t^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\,{b_1\ldots b_k}},\]- where \(\nabla\) is the Levi-Civita connection of \(g\) (cf. - LeviCivitaConnection) and \(\nabla^i := g^{ij} \nabla_j\).- Note - If the metric \(g\) is not Lorentzian, the name d’Alembertian is not appropriate and one should use - laplacian()instead.- INPUT: - metric– (default:- None) the Lorentzian metric \(g\) involved in the definition of the d’Alembertian; if none is provided, the domain of- selfis supposed to be endowed with a default Lorentzian metric (i.e. is supposed to be Lorentzian manifold, see- PseudoRiemannianManifold) and the latter is used to define the d’Alembertian
 - OUTPUT: - instance of - TensorFieldrepresenting the d’Alembertian of- self
 - EXAMPLES: - d’Alembertian of a vector field in Minkowski spacetime, representing the electric field of a simple plane electromagnetic wave: - sage: M = Manifold(4, 'M', structure='Lorentzian') sage: X.<t,x,y,z> = M.chart() sage: g = M.metric() sage: g[0,0], g[1,1], g[2,2], g[3,3] = -1, 1, 1, 1 sage: e = M.vector_field(name='e') sage: e[1] = cos(t-z) sage: e.display() # plane wave propagating in the z direction e = cos(t - z) ∂/∂x sage: De = e.dalembertian(); De # long time Vector field Box(e) on the 4-dimensional Lorentzian manifold M - >>> from sage.all import * >>> M = Manifold(Integer(4), 'M', structure='Lorentzian') >>> X = M.chart(names=('t', 'x', 'y', 'z',)); (t, x, y, z,) = X._first_ngens(4) >>> g = M.metric() >>> g[Integer(0),Integer(0)], g[Integer(1),Integer(1)], g[Integer(2),Integer(2)], g[Integer(3),Integer(3)] = -Integer(1), Integer(1), Integer(1), Integer(1) >>> e = M.vector_field(name='e') >>> e[Integer(1)] = cos(t-z) >>> e.display() # plane wave propagating in the z direction e = cos(t - z) ∂/∂x >>> De = e.dalembertian(); De # long time Vector field Box(e) on the 4-dimensional Lorentzian manifold M - The function - dalembertian()from the- operatorsmodule can be used instead of the method- dalembertian():- sage: from sage.manifolds.operators import dalembertian sage: dalembertian(e) == De # long time True - >>> from sage.all import * >>> from sage.manifolds.operators import dalembertian >>> dalembertian(e) == De # long time True - We check that the electric field obeys the wave equation: - sage: De.display() # long time Box(e) = 0 - >>> from sage.all import * >>> De.display() # long time Box(e) = 0 
 - disp(frame=None, chart=None)[source]¶
- Display the tensor field in terms of its expansion with respect to a given vector frame. - The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode). - INPUT: - frame– (default:- None) vector frame with respect to which the tensor is expanded; if- frameis- Noneand- chartis not- None, the coordinate frame associated with- chartis assumed; if both- frameand- chartare- None, the default frame of the domain of definition of the tensor field is assumed
- chart– (default:- None) chart with respect to which the components of the tensor field in the selected frame are expressed; if- None, the default chart of the vector frame domain is assumed
 - EXAMPLES: - Display of a type-\((1,1)\) tensor field on a 2-dimensional manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: W = U.intersection(V) sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() sage: t = M.tensor_field(1,1, name='t') sage: t[e_xy,:] = [[x, 1], [y, 0]] sage: t.add_comp_by_continuation(e_uv, W, c_uv) sage: t.display(e_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx sage: t.display(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> W = U.intersection(V) >>> e_xy = c_xy.frame(); e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1),Integer(1), name='t') >>> t[e_xy,:] = [[x, Integer(1)], [y, Integer(0)]] >>> t.add_comp_by_continuation(e_uv, W, c_uv) >>> t.display(e_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx >>> t.display(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - Since - e_xyis- M’s default frame, the argument- e_xycan be omitted:- sage: e_xy is M.default_frame() True sage: t.display() t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx - >>> from sage.all import * >>> e_xy is M.default_frame() True >>> t.display() t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx - Similarly, since - e_uvis- V’s default frame, the argument- e_uvcan be omitted when considering the restriction of- tto- V:- sage: t.restrict(V).display() t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.restrict(V).display() t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - If the coordinate expression of the components are to be displayed in a chart distinct from the default one on the considered domain, then the chart has to be passed as the second argument of - display. For instance, on \(W = U \cap V\), two charts are available:- c_xy.restrict(W)(the default one) and- c_uv.restrict(W). Accordingly, one can have two views of the expansion of- tin the same vector frame- e_uv.restrict(W):- sage: t.display(e_uv.restrict(W)) # W's default chart assumed t = (1/2*x + 1/2*y + 1/2) ∂/∂u⊗du + (1/2*x + 1/2*y - 1/2) ∂/∂u⊗dv + (1/2*x - 1/2*y + 1/2) ∂/∂v⊗du + (1/2*x - 1/2*y - 1/2) ∂/∂v⊗dv sage: t.display(e_uv.restrict(W), c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.display(e_uv.restrict(W)) # W's default chart assumed t = (1/2*x + 1/2*y + 1/2) ∂/∂u⊗du + (1/2*x + 1/2*y - 1/2) ∂/∂u⊗dv + (1/2*x - 1/2*y + 1/2) ∂/∂v⊗du + (1/2*x - 1/2*y - 1/2) ∂/∂v⊗dv >>> t.display(e_uv.restrict(W), c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - As a shortcut, one can pass just a chart to - display. It is then understood that the expansion is to be performed with respect to the coordinate frame associated with this chart. Therefore the above command can be abridged to:- sage: t.display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - and one has: - sage: t.display(c_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx sage: t.display(c_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv sage: t.display(c_xy.restrict(W)) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx sage: t.restrict(W).display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.display(c_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx >>> t.display(c_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv >>> t.display(c_xy.restrict(W)) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx >>> t.restrict(W).display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - One can ask for the display with respect to a frame in which - thas not been initialized yet (this will automatically trigger the use of the change-of-frame formula for tensors):- sage: a = V.automorphism_field() sage: a[:] = [[1+v, -u^2], [0, 1-u]] sage: f = e_uv.new_frame(a, 'f') sage: [f[i].display() for i in M.irange()] [f_0 = (v + 1) ∂/∂u, f_1 = -u^2 ∂/∂u + (-u + 1) ∂/∂v] sage: t.display(f) t = -1/2*(u^2*v + 1)/(u - 1) f_0⊗f^0 - 1/2*(2*u^3 - 5*u^2 - (u^4 + u^3 - u^2)*v + 3*u - 1)/((u - 1)*v + u - 1) f_0⊗f^1 - 1/2*(v^2 + 2*v + 1)/(u - 1) f_1⊗f^0 + 1/2*(u^2 + (u^2 + u - 1)*v - u + 1)/(u - 1) f_1⊗f^1 - >>> from sage.all import * >>> a = V.automorphism_field() >>> a[:] = [[Integer(1)+v, -u**Integer(2)], [Integer(0), Integer(1)-u]] >>> f = e_uv.new_frame(a, 'f') >>> [f[i].display() for i in M.irange()] [f_0 = (v + 1) ∂/∂u, f_1 = -u^2 ∂/∂u + (-u + 1) ∂/∂v] >>> t.display(f) t = -1/2*(u^2*v + 1)/(u - 1) f_0⊗f^0 - 1/2*(2*u^3 - 5*u^2 - (u^4 + u^3 - u^2)*v + 3*u - 1)/((u - 1)*v + u - 1) f_0⊗f^1 - 1/2*(v^2 + 2*v + 1)/(u - 1) f_1⊗f^0 + 1/2*(u^2 + (u^2 + u - 1)*v - u + 1)/(u - 1) f_1⊗f^1 - A shortcut of - display()is- disp():- sage: t.disp(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.disp(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv 
 - display(frame=None, chart=None)[source]¶
- Display the tensor field in terms of its expansion with respect to a given vector frame. - The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode). - INPUT: - frame– (default:- None) vector frame with respect to which the tensor is expanded; if- frameis- Noneand- chartis not- None, the coordinate frame associated with- chartis assumed; if both- frameand- chartare- None, the default frame of the domain of definition of the tensor field is assumed
- chart– (default:- None) chart with respect to which the components of the tensor field in the selected frame are expressed; if- None, the default chart of the vector frame domain is assumed
 - EXAMPLES: - Display of a type-\((1,1)\) tensor field on a 2-dimensional manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: W = U.intersection(V) sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() sage: t = M.tensor_field(1,1, name='t') sage: t[e_xy,:] = [[x, 1], [y, 0]] sage: t.add_comp_by_continuation(e_uv, W, c_uv) sage: t.display(e_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx sage: t.display(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> W = U.intersection(V) >>> e_xy = c_xy.frame(); e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1),Integer(1), name='t') >>> t[e_xy,:] = [[x, Integer(1)], [y, Integer(0)]] >>> t.add_comp_by_continuation(e_uv, W, c_uv) >>> t.display(e_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx >>> t.display(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - Since - e_xyis- M’s default frame, the argument- e_xycan be omitted:- sage: e_xy is M.default_frame() True sage: t.display() t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx - >>> from sage.all import * >>> e_xy is M.default_frame() True >>> t.display() t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx - Similarly, since - e_uvis- V’s default frame, the argument- e_uvcan be omitted when considering the restriction of- tto- V:- sage: t.restrict(V).display() t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.restrict(V).display() t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - If the coordinate expression of the components are to be displayed in a chart distinct from the default one on the considered domain, then the chart has to be passed as the second argument of - display. For instance, on \(W = U \cap V\), two charts are available:- c_xy.restrict(W)(the default one) and- c_uv.restrict(W). Accordingly, one can have two views of the expansion of- tin the same vector frame- e_uv.restrict(W):- sage: t.display(e_uv.restrict(W)) # W's default chart assumed t = (1/2*x + 1/2*y + 1/2) ∂/∂u⊗du + (1/2*x + 1/2*y - 1/2) ∂/∂u⊗dv + (1/2*x - 1/2*y + 1/2) ∂/∂v⊗du + (1/2*x - 1/2*y - 1/2) ∂/∂v⊗dv sage: t.display(e_uv.restrict(W), c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.display(e_uv.restrict(W)) # W's default chart assumed t = (1/2*x + 1/2*y + 1/2) ∂/∂u⊗du + (1/2*x + 1/2*y - 1/2) ∂/∂u⊗dv + (1/2*x - 1/2*y + 1/2) ∂/∂v⊗du + (1/2*x - 1/2*y - 1/2) ∂/∂v⊗dv >>> t.display(e_uv.restrict(W), c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - As a shortcut, one can pass just a chart to - display. It is then understood that the expansion is to be performed with respect to the coordinate frame associated with this chart. Therefore the above command can be abridged to:- sage: t.display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - and one has: - sage: t.display(c_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx sage: t.display(c_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv sage: t.display(c_xy.restrict(W)) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx sage: t.restrict(W).display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.display(c_xy) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx >>> t.display(c_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv >>> t.display(c_xy.restrict(W)) t = x ∂/∂x⊗dx + ∂/∂x⊗dy + y ∂/∂y⊗dx >>> t.restrict(W).display(c_uv.restrict(W)) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - One can ask for the display with respect to a frame in which - thas not been initialized yet (this will automatically trigger the use of the change-of-frame formula for tensors):- sage: a = V.automorphism_field() sage: a[:] = [[1+v, -u^2], [0, 1-u]] sage: f = e_uv.new_frame(a, 'f') sage: [f[i].display() for i in M.irange()] [f_0 = (v + 1) ∂/∂u, f_1 = -u^2 ∂/∂u + (-u + 1) ∂/∂v] sage: t.display(f) t = -1/2*(u^2*v + 1)/(u - 1) f_0⊗f^0 - 1/2*(2*u^3 - 5*u^2 - (u^4 + u^3 - u^2)*v + 3*u - 1)/((u - 1)*v + u - 1) f_0⊗f^1 - 1/2*(v^2 + 2*v + 1)/(u - 1) f_1⊗f^0 + 1/2*(u^2 + (u^2 + u - 1)*v - u + 1)/(u - 1) f_1⊗f^1 - >>> from sage.all import * >>> a = V.automorphism_field() >>> a[:] = [[Integer(1)+v, -u**Integer(2)], [Integer(0), Integer(1)-u]] >>> f = e_uv.new_frame(a, 'f') >>> [f[i].display() for i in M.irange()] [f_0 = (v + 1) ∂/∂u, f_1 = -u^2 ∂/∂u + (-u + 1) ∂/∂v] >>> t.display(f) t = -1/2*(u^2*v + 1)/(u - 1) f_0⊗f^0 - 1/2*(2*u^3 - 5*u^2 - (u^4 + u^3 - u^2)*v + 3*u - 1)/((u - 1)*v + u - 1) f_0⊗f^1 - 1/2*(v^2 + 2*v + 1)/(u - 1) f_1⊗f^0 + 1/2*(u^2 + (u^2 + u - 1)*v - u + 1)/(u - 1) f_1⊗f^1 - A shortcut of - display()is- disp():- sage: t.disp(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv - >>> from sage.all import * >>> t.disp(e_uv) t = (1/2*u + 1/2) ∂/∂u⊗du + (1/2*u - 1/2) ∂/∂u⊗dv + (1/2*v + 1/2) ∂/∂v⊗du + (1/2*v - 1/2) ∂/∂v⊗dv 
 - display_comp(frame=None, chart=None, coordinate_labels=True, only_nonzero=True, only_nonredundant=False)[source]¶
- Display the tensor components with respect to a given frame, one per line. - The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode). - INPUT: - frame– (default:- None) vector frame with respect to which the tensor field components are defined; if- None, then- if - chartis not- None, the coordinate frame associated to- chartis used
- otherwise, the default basis of the vector field module on which the tensor field is defined is used 
 
- chart– (default:- None) chart specifying the coordinate expression of the components; if- None, the default chart of the tensor field domain is used
- coordinate_labels– boolean (default:- True); if- True, coordinate symbols are used by default (instead of integers) as index labels whenever- frameis a coordinate frame
- only_nonzero– boolean (default:- True); if- True, only nonzero components are displayed
- only_nonredundant– boolean (default:- False); if- True, only nonredundant components are displayed in case of symmetries
 - EXAMPLES: - Display of the components of a type-\((1,1)\) tensor field defined on two open subsets: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') sage: c_xy.<x, y> = U.chart() sage: e = U.default_frame() sage: V = M.open_subset('V') sage: c_uv.<u, v> = V.chart() sage: f = V.default_frame() sage: M.declare_union(U,V) # M is the union of U and V sage: t = M.tensor_field(1,1, name='t') sage: t[e,0,0] = - x + y^3 sage: t[e,0,1] = 2+x sage: t[f,1,1] = - u*v sage: t.display_comp(e) t^x_x = y^3 - x t^x_y = x + 2 sage: t.display_comp(f) t^v_v = -u*v - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> e = U.default_frame() >>> V = M.open_subset('V') >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> f = V.default_frame() >>> M.declare_union(U,V) # M is the union of U and V >>> t = M.tensor_field(Integer(1),Integer(1), name='t') >>> t[e,Integer(0),Integer(0)] = - x + y**Integer(3) >>> t[e,Integer(0),Integer(1)] = Integer(2)+x >>> t[f,Integer(1),Integer(1)] = - u*v >>> t.display_comp(e) t^x_x = y^3 - x t^x_y = x + 2 >>> t.display_comp(f) t^v_v = -u*v - Components in a chart frame: - sage: t.display_comp(chart=c_xy) t^x_x = y^3 - x t^x_y = x + 2 sage: t.display_comp(chart=c_uv) t^v_v = -u*v - >>> from sage.all import * >>> t.display_comp(chart=c_xy) t^x_x = y^3 - x t^x_y = x + 2 >>> t.display_comp(chart=c_uv) t^v_v = -u*v - See documentation of - sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.display_comp()for more options.
 - div(metric=None)[source]¶
- Return the divergence of - self(with respect to a given metric).- The divergence is taken on the last index: if - selfis a tensor field \(t\) of type \((k,0)\) with \(k\geq 1\), the divergence of \(t\) with respect to the metric \(g\) is the tensor field of type \((k-1,0)\) defined by\[(\mathrm{div}\, t)^{a_1\ldots a_{k-1}} = \nabla_i t^{a_1\ldots a_{k-1} i} = (\nabla t)^{a_1\ldots a_{k-1} i}_{\phantom{a_1\ldots a_{k-1} i}\, i},\]- where \(\nabla\) is the Levi-Civita connection of \(g\) (cf. - LeviCivitaConnection).- This definition is extended to tensor fields of type \((k,l)\) with \(k\geq 0\) and \(l\geq 1\), by raising the last index with the metric \(g\): \(\mathrm{div}\, t\) is then the tensor field of type \((k,l-1)\) defined by \[(\mathrm{div}\, t)^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\, b_1 \ldots b_{l-1}} = \nabla_i (g^{ij} t^{a_1\ldots a_k}_{\phantom{a_1 \ldots a_k}\, b_1\ldots b_{l-1} j}) = (\nabla t^\sharp)^{a_1\ldots a_k i}_{\phantom{a_1\ldots a_k i}\, b_1\ldots b_{l-1} i},\]- where \(t^\sharp\) is the tensor field deduced from \(t\) by raising the last index with the metric \(g\) (see - up()).- INPUT: - metric– (default:- None) the pseudo-Riemannian metric \(g\) involved in the definition of the divergence; if none is provided, the domain of- selfis supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see- PseudoRiemannianManifold) and the latter is used to define the divergence.
 - OUTPUT: - instance of either - DiffScalarFieldif \((k,l)=(1,0)\) (- selfis a vector field) or \((k,l)=(0,1)\) (- selfis a 1-form) or of- TensorFieldif \(k+l\geq 2\) representing the divergence of- selfwith respect to- metric
 - EXAMPLES: - Divergence of a vector field in the Euclidean plane: - sage: M.<x,y> = EuclideanSpace() sage: v = M.vector_field(x, y, name='v') sage: s = v.divergence(); s Scalar field div(v) on the Euclidean plane E^2 sage: s.display() div(v): E^2 → ℝ (x, y) ↦ 2 - >>> from sage.all import * >>> M = EuclideanSpace(names=('x', 'y',)); (x, y,) = M._first_ngens(2) >>> v = M.vector_field(x, y, name='v') >>> s = v.divergence(); s Scalar field div(v) on the Euclidean plane E^2 >>> s.display() div(v): E^2 → ℝ (x, y) ↦ 2 - A shortcut alias of - divergenceis- div:- sage: v.div() == s True - >>> from sage.all import * >>> v.div() == s True - The function - div()from the- operatorsmodule can be used instead of the method- divergence():- sage: from sage.manifolds.operators import div sage: div(v) == s True - >>> from sage.all import * >>> from sage.manifolds.operators import div >>> div(v) == s True - The divergence can be taken with respect to a metric tensor that is not the default one: - sage: h = M.lorentzian_metric('h') sage: h[1,1], h[2,2] = -1, 1/(1+x^2+y^2) sage: s = v.div(h); s Scalar field div_h(v) on the Euclidean plane E^2 sage: s.display() div_h(v): E^2 → ℝ (x, y) ↦ (x^2 + y^2 + 2)/(x^2 + y^2 + 1) - >>> from sage.all import * >>> h = M.lorentzian_metric('h') >>> h[Integer(1),Integer(1)], h[Integer(2),Integer(2)] = -Integer(1), Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)) >>> s = v.div(h); s Scalar field div_h(v) on the Euclidean plane E^2 >>> s.display() div_h(v): E^2 → ℝ (x, y) ↦ (x^2 + y^2 + 2)/(x^2 + y^2 + 1) - The standard formula \[\mathrm{div}_h \, v = \frac{1}{\sqrt{|\det h|}} \frac{\partial}{\partial x^i} \left( \sqrt{|\det h|} \, v^i \right)\]- is checked as follows: - sage: sqrth = h.sqrt_abs_det().expr(); sqrth 1/sqrt(x^2 + y^2 + 1) sage: s == 1/sqrth * sum( (sqrth*v[i]).diff(i) for i in M.irange()) True - >>> from sage.all import * >>> sqrth = h.sqrt_abs_det().expr(); sqrth 1/sqrt(x^2 + y^2 + 1) >>> s == Integer(1)/sqrth * sum( (sqrth*v[i]).diff(i) for i in M.irange()) True - A divergence-free vector: - sage: w = M.vector_field(-y, x, name='w') sage: w.div().display() div(w): E^2 → ℝ (x, y) ↦ 0 sage: w.div(h).display() div_h(w): E^2 → ℝ (x, y) ↦ 0 - >>> from sage.all import * >>> w = M.vector_field(-y, x, name='w') >>> w.div().display() div(w): E^2 → ℝ (x, y) ↦ 0 >>> w.div(h).display() div_h(w): E^2 → ℝ (x, y) ↦ 0 - Divergence of a type- - (2,0)tensor field:- sage: t = v*w; t Tensor field v⊗w of type (2,0) on the Euclidean plane E^2 sage: s = t.div(); s Vector field div(v⊗w) on the Euclidean plane E^2 sage: s.display() div(v⊗w) = -y e_x + x e_y - >>> from sage.all import * >>> t = v*w; t Tensor field v⊗w of type (2,0) on the Euclidean plane E^2 >>> s = t.div(); s Vector field div(v⊗w) on the Euclidean plane E^2 >>> s.display() div(v⊗w) = -y e_x + x e_y 
 - divergence(metric=None)[source]¶
- Return the divergence of - self(with respect to a given metric).- The divergence is taken on the last index: if - selfis a tensor field \(t\) of type \((k,0)\) with \(k\geq 1\), the divergence of \(t\) with respect to the metric \(g\) is the tensor field of type \((k-1,0)\) defined by\[(\mathrm{div}\, t)^{a_1\ldots a_{k-1}} = \nabla_i t^{a_1\ldots a_{k-1} i} = (\nabla t)^{a_1\ldots a_{k-1} i}_{\phantom{a_1\ldots a_{k-1} i}\, i},\]- where \(\nabla\) is the Levi-Civita connection of \(g\) (cf. - LeviCivitaConnection).- This definition is extended to tensor fields of type \((k,l)\) with \(k\geq 0\) and \(l\geq 1\), by raising the last index with the metric \(g\): \(\mathrm{div}\, t\) is then the tensor field of type \((k,l-1)\) defined by \[(\mathrm{div}\, t)^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\, b_1 \ldots b_{l-1}} = \nabla_i (g^{ij} t^{a_1\ldots a_k}_{\phantom{a_1 \ldots a_k}\, b_1\ldots b_{l-1} j}) = (\nabla t^\sharp)^{a_1\ldots a_k i}_{\phantom{a_1\ldots a_k i}\, b_1\ldots b_{l-1} i},\]- where \(t^\sharp\) is the tensor field deduced from \(t\) by raising the last index with the metric \(g\) (see - up()).- INPUT: - metric– (default:- None) the pseudo-Riemannian metric \(g\) involved in the definition of the divergence; if none is provided, the domain of- selfis supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see- PseudoRiemannianManifold) and the latter is used to define the divergence.
 - OUTPUT: - instance of either - DiffScalarFieldif \((k,l)=(1,0)\) (- selfis a vector field) or \((k,l)=(0,1)\) (- selfis a 1-form) or of- TensorFieldif \(k+l\geq 2\) representing the divergence of- selfwith respect to- metric
 - EXAMPLES: - Divergence of a vector field in the Euclidean plane: - sage: M.<x,y> = EuclideanSpace() sage: v = M.vector_field(x, y, name='v') sage: s = v.divergence(); s Scalar field div(v) on the Euclidean plane E^2 sage: s.display() div(v): E^2 → ℝ (x, y) ↦ 2 - >>> from sage.all import * >>> M = EuclideanSpace(names=('x', 'y',)); (x, y,) = M._first_ngens(2) >>> v = M.vector_field(x, y, name='v') >>> s = v.divergence(); s Scalar field div(v) on the Euclidean plane E^2 >>> s.display() div(v): E^2 → ℝ (x, y) ↦ 2 - A shortcut alias of - divergenceis- div:- sage: v.div() == s True - >>> from sage.all import * >>> v.div() == s True - The function - div()from the- operatorsmodule can be used instead of the method- divergence():- sage: from sage.manifolds.operators import div sage: div(v) == s True - >>> from sage.all import * >>> from sage.manifolds.operators import div >>> div(v) == s True - The divergence can be taken with respect to a metric tensor that is not the default one: - sage: h = M.lorentzian_metric('h') sage: h[1,1], h[2,2] = -1, 1/(1+x^2+y^2) sage: s = v.div(h); s Scalar field div_h(v) on the Euclidean plane E^2 sage: s.display() div_h(v): E^2 → ℝ (x, y) ↦ (x^2 + y^2 + 2)/(x^2 + y^2 + 1) - >>> from sage.all import * >>> h = M.lorentzian_metric('h') >>> h[Integer(1),Integer(1)], h[Integer(2),Integer(2)] = -Integer(1), Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)) >>> s = v.div(h); s Scalar field div_h(v) on the Euclidean plane E^2 >>> s.display() div_h(v): E^2 → ℝ (x, y) ↦ (x^2 + y^2 + 2)/(x^2 + y^2 + 1) - The standard formula \[\mathrm{div}_h \, v = \frac{1}{\sqrt{|\det h|}} \frac{\partial}{\partial x^i} \left( \sqrt{|\det h|} \, v^i \right)\]- is checked as follows: - sage: sqrth = h.sqrt_abs_det().expr(); sqrth 1/sqrt(x^2 + y^2 + 1) sage: s == 1/sqrth * sum( (sqrth*v[i]).diff(i) for i in M.irange()) True - >>> from sage.all import * >>> sqrth = h.sqrt_abs_det().expr(); sqrth 1/sqrt(x^2 + y^2 + 1) >>> s == Integer(1)/sqrth * sum( (sqrth*v[i]).diff(i) for i in M.irange()) True - A divergence-free vector: - sage: w = M.vector_field(-y, x, name='w') sage: w.div().display() div(w): E^2 → ℝ (x, y) ↦ 0 sage: w.div(h).display() div_h(w): E^2 → ℝ (x, y) ↦ 0 - >>> from sage.all import * >>> w = M.vector_field(-y, x, name='w') >>> w.div().display() div(w): E^2 → ℝ (x, y) ↦ 0 >>> w.div(h).display() div_h(w): E^2 → ℝ (x, y) ↦ 0 - Divergence of a type- - (2,0)tensor field:- sage: t = v*w; t Tensor field v⊗w of type (2,0) on the Euclidean plane E^2 sage: s = t.div(); s Vector field div(v⊗w) on the Euclidean plane E^2 sage: s.display() div(v⊗w) = -y e_x + x e_y - >>> from sage.all import * >>> t = v*w; t Tensor field v⊗w of type (2,0) on the Euclidean plane E^2 >>> s = t.div(); s Vector field div(v⊗w) on the Euclidean plane E^2 >>> s.display() div(v⊗w) = -y e_x + x e_y 
 - domain()[source]¶
- Return the manifold on which - selfis defined.- OUTPUT: - instance of class - DifferentiableManifold
 - EXAMPLES: - sage: M = Manifold(2, 'M') sage: c_xy.<x,y> = M.chart() sage: t = M.tensor_field(1,2) sage: t.domain() 2-dimensional differentiable manifold M sage: U = M.open_subset('U', coord_def={c_xy: x<0}) sage: h = t.restrict(U) sage: h.domain() Open subset U of the 2-dimensional differentiable manifold M - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> t = M.tensor_field(Integer(1),Integer(2)) >>> t.domain() 2-dimensional differentiable manifold M >>> U = M.open_subset('U', coord_def={c_xy: x<Integer(0)}) >>> h = t.restrict(U) >>> h.domain() Open subset U of the 2-dimensional differentiable manifold M 
 - down(non_degenerate_form, pos=None)[source]¶
- Compute a dual of the tensor field by lowering some index with a given non-degenerate form (pseudo-Riemannian metric or symplectic form). - If \(T\) is the tensor field, \((k,l)\) its type and \(p\) the position of a contravariant index (i.e. \(0\leq p < k\)), this method called with - pos\(=p\) yields the tensor field \(T^\flat\) of type \((k-1,l+1)\) whose components are\[(T^\flat)^{a_1\ldots a_{k-1}}_{\phantom{a_1\ldots a_{k-1}} \, b_1 \ldots b_{l+1}} = g_{i b_1} \, T^{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k-1}}_{\phantom{a_1 \ldots a_{p} \, i \, a_{p+1}\ldots a_{k-1}}\, b_2 \ldots b_{l+1}},\]- \(g_{ab}\) being the components of the metric tensor or the symplectic form, respectively. - The reverse operation is - TensorField.up().- INPUT: - non_degenerate_form– non-degenerate form \(g\)
- pos– (default:- None) position of the index (with the convention- pos=0for the first index); if- None, the lowering is performed over all the contravariant indices, starting from the last one
 - OUTPUT: - the tensor field \(T^\flat\) resulting from the index lowering operation 
 - EXAMPLES: - Lowering the index of a vector field results in a 1-form: - sage: M = Manifold(2, 'M', start_index=1) sage: c_xy.<x,y> = M.chart() sage: g = M.metric('g') sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-y sage: v = M.vector_field(-1, 2) sage: w = v.down(g) ; w 1-form on the 2-dimensional differentiable manifold M sage: w.display() (2*x*y - x - 1) dx + (-(x + 2)*y + 2) dy - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M', start_index=Integer(1)) >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> g = M.metric('g') >>> g[Integer(1),Integer(1)], g[Integer(1),Integer(2)], g[Integer(2),Integer(2)] = Integer(1)+x, x*y, Integer(1)-y >>> v = M.vector_field(-Integer(1), Integer(2)) >>> w = v.down(g) ; w 1-form on the 2-dimensional differentiable manifold M >>> w.display() (2*x*y - x - 1) dx + (-(x + 2)*y + 2) dy - Using the index notation instead of - down():- sage: w == g['_ab']*v['^b'] True - >>> from sage.all import * >>> w == g['_ab']*v['^b'] True - The reverse operation: - sage: v1 = w.up(g) ; v1 Vector field on the 2-dimensional differentiable manifold M sage: v1 == v True - >>> from sage.all import * >>> v1 = w.up(g) ; v1 Vector field on the 2-dimensional differentiable manifold M >>> v1 == v True - Lowering the indices of a tensor field of type (2,0): - sage: t = M.tensor_field(2, 0, [[1,2], [3,4]]) sage: td0 = t.down(g, 0) ; td0 # lowering the first index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: td0 == g['_ac']*t['^cb'] # the same operation in index notation True sage: td0[:] [ 3*x*y + x + 1 (x - 3)*y + 3] [4*x*y + 2*x + 2 2*(x - 2)*y + 4] sage: tdd0 = td0.down(g) ; tdd0 # the two indices have been lowered, starting from the first one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M sage: tdd0 == g['_ac']*td0['^c_b'] # the same operation in index notation True sage: tdd0[:] [ 4*x^2*y^2 + x^2 + 5*(x^2 + x)*y + 2*x + 1 2*(x^2 - 2*x)*y^2 + (x^2 + 2*x - 3)*y + 3*x + 3] [(3*x^2 - 4*x)*y^2 + (x^2 + 3*x - 2)*y + 2*x + 2 (x^2 - 5*x + 4)*y^2 + (5*x - 8)*y + 4] sage: td1 = t.down(g, 1) ; td1 # lowering the second index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: td1 == g['_ac']*t['^bc'] # the same operation in index notation True sage: td1[:] [ 2*x*y + x + 1 (x - 2)*y + 2] [4*x*y + 3*x + 3 (3*x - 4)*y + 4] sage: tdd1 = td1.down(g) ; tdd1 # the two indices have been lowered, starting from the second one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M sage: tdd1 == g['_ac']*td1['^c_b'] # the same operation in index notation True sage: tdd1[:] [ 4*x^2*y^2 + x^2 + 5*(x^2 + x)*y + 2*x + 1 (3*x^2 - 4*x)*y^2 + (x^2 + 3*x - 2)*y + 2*x + 2] [2*(x^2 - 2*x)*y^2 + (x^2 + 2*x - 3)*y + 3*x + 3 (x^2 - 5*x + 4)*y^2 + (5*x - 8)*y + 4] sage: tdd1 == tdd0 # the order of index lowering is important False sage: tdd = t.down(g) ; tdd # both indices are lowered, starting from the last one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M sage: tdd[:] [ 4*x^2*y^2 + x^2 + 5*(x^2 + x)*y + 2*x + 1 (3*x^2 - 4*x)*y^2 + (x^2 + 3*x - 2)*y + 2*x + 2] [2*(x^2 - 2*x)*y^2 + (x^2 + 2*x - 3)*y + 3*x + 3 (x^2 - 5*x + 4)*y^2 + (5*x - 8)*y + 4] sage: tdd0 == tdd # to get tdd0, indices have been lowered from the first one, contrary to tdd False sage: tdd1 == tdd # the same order for index lowering has been applied True sage: u0tdd = tdd.up(g, 0) ; u0tdd # the first index is raised again Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: uu0tdd = u0tdd.up(g) ; uu0tdd # the second index is then raised Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: u1tdd = tdd.up(g, 1) ; u1tdd # raising operation, starting from the last index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: uu1tdd = u1tdd.up(g) ; uu1tdd Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: uutdd = tdd.up(g) ; uutdd # both indices are raised, starting from the first one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: uutdd == t # should be true True sage: uu0tdd == t # should be true True sage: uu1tdd == t # not true, because of the order of index raising to get uu1tdd False - >>> from sage.all import * >>> t = M.tensor_field(Integer(2), Integer(0), [[Integer(1),Integer(2)], [Integer(3),Integer(4)]]) >>> td0 = t.down(g, Integer(0)) ; td0 # lowering the first index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> td0 == g['_ac']*t['^cb'] # the same operation in index notation True >>> td0[:] [ 3*x*y + x + 1 (x - 3)*y + 3] [4*x*y + 2*x + 2 2*(x - 2)*y + 4] >>> tdd0 = td0.down(g) ; tdd0 # the two indices have been lowered, starting from the first one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M >>> tdd0 == g['_ac']*td0['^c_b'] # the same operation in index notation True >>> tdd0[:] [ 4*x^2*y^2 + x^2 + 5*(x^2 + x)*y + 2*x + 1 2*(x^2 - 2*x)*y^2 + (x^2 + 2*x - 3)*y + 3*x + 3] [(3*x^2 - 4*x)*y^2 + (x^2 + 3*x - 2)*y + 2*x + 2 (x^2 - 5*x + 4)*y^2 + (5*x - 8)*y + 4] >>> td1 = t.down(g, Integer(1)) ; td1 # lowering the second index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> td1 == g['_ac']*t['^bc'] # the same operation in index notation True >>> td1[:] [ 2*x*y + x + 1 (x - 2)*y + 2] [4*x*y + 3*x + 3 (3*x - 4)*y + 4] >>> tdd1 = td1.down(g) ; tdd1 # the two indices have been lowered, starting from the second one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M >>> tdd1 == g['_ac']*td1['^c_b'] # the same operation in index notation True >>> tdd1[:] [ 4*x^2*y^2 + x^2 + 5*(x^2 + x)*y + 2*x + 1 (3*x^2 - 4*x)*y^2 + (x^2 + 3*x - 2)*y + 2*x + 2] [2*(x^2 - 2*x)*y^2 + (x^2 + 2*x - 3)*y + 3*x + 3 (x^2 - 5*x + 4)*y^2 + (5*x - 8)*y + 4] >>> tdd1 == tdd0 # the order of index lowering is important False >>> tdd = t.down(g) ; tdd # both indices are lowered, starting from the last one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M >>> tdd[:] [ 4*x^2*y^2 + x^2 + 5*(x^2 + x)*y + 2*x + 1 (3*x^2 - 4*x)*y^2 + (x^2 + 3*x - 2)*y + 2*x + 2] [2*(x^2 - 2*x)*y^2 + (x^2 + 2*x - 3)*y + 3*x + 3 (x^2 - 5*x + 4)*y^2 + (5*x - 8)*y + 4] >>> tdd0 == tdd # to get tdd0, indices have been lowered from the first one, contrary to tdd False >>> tdd1 == tdd # the same order for index lowering has been applied True >>> u0tdd = tdd.up(g, Integer(0)) ; u0tdd # the first index is raised again Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> uu0tdd = u0tdd.up(g) ; uu0tdd # the second index is then raised Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> u1tdd = tdd.up(g, Integer(1)) ; u1tdd # raising operation, starting from the last index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> uu1tdd = u1tdd.up(g) ; uu1tdd Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> uutdd = tdd.up(g) ; uutdd # both indices are raised, starting from the first one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> uutdd == t # should be true True >>> uu0tdd == t # should be true True >>> uu1tdd == t # not true, because of the order of index raising to get uu1tdd False 
 - laplacian(metric=None)[source]¶
- Return the Laplacian of - selfwith respect to a given metric (Laplace-Beltrami operator).- If - selfis a tensor field \(t\) of type \((k,l)\), the Laplacian of \(t\) with respect to the metric \(g\) is the tensor field of type \((k,l)\) defined by\[(\Delta t)^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\,{b_1\ldots b_k}} = \nabla_i \nabla^i t^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\,{b_1\ldots b_k}},\]- where \(\nabla\) is the Levi-Civita connection of \(g\) (cf. - LeviCivitaConnection) and \(\nabla^i := g^{ij} \nabla_j\). The operator \(\Delta = \nabla_i \nabla^i\) is called the Laplace-Beltrami operator of metric \(g\).- INPUT: - metric– (default:- None) the pseudo-Riemannian metric \(g\) involved in the definition of the Laplacian; if none is provided, the domain of- selfis supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see- PseudoRiemannianManifold) and the latter is used to define the Laplacian
 - OUTPUT: - instance of - TensorFieldrepresenting the Laplacian of- self
 - EXAMPLES: - Laplacian of a vector field in the Euclidean plane: - sage: M.<x,y> = EuclideanSpace() sage: v = M.vector_field(x^3 + y^2, x*y, name='v') sage: Dv = v.laplacian(); Dv Vector field Delta(v) on the Euclidean plane E^2 sage: Dv.display() Delta(v) = (6*x + 2) e_x - >>> from sage.all import * >>> M = EuclideanSpace(names=('x', 'y',)); (x, y,) = M._first_ngens(2) >>> v = M.vector_field(x**Integer(3) + y**Integer(2), x*y, name='v') >>> Dv = v.laplacian(); Dv Vector field Delta(v) on the Euclidean plane E^2 >>> Dv.display() Delta(v) = (6*x + 2) e_x - The function - laplacian()from the- operatorsmodule can be used instead of the method- laplacian():- sage: from sage.manifolds.operators import laplacian sage: laplacian(v) == Dv True - >>> from sage.all import * >>> from sage.manifolds.operators import laplacian >>> laplacian(v) == Dv True - In the present case (Euclidean metric and Cartesian coordinates), the components of the Laplacian are the Laplacians of the components: - sage: all(Dv[[i]] == laplacian(v[[i]]) for i in M.irange()) True - >>> from sage.all import * >>> all(Dv[[i]] == laplacian(v[[i]]) for i in M.irange()) True - The Laplacian can be taken with respect to a metric tensor that is not the default one: - sage: h = M.lorentzian_metric('h') sage: h[1,1], h[2,2] = -1, 1+x^2 sage: Dv = v.laplacian(h); Dv Vector field Delta_h(v) on the Euclidean plane E^2 sage: Dv.display() Delta_h(v) = -(8*x^5 - 2*x^4 - x^2*y^2 + 15*x^3 - 4*x^2 + 6*x - 2)/(x^4 + 2*x^2 + 1) e_x - 3*x^3*y/(x^4 + 2*x^2 + 1) e_y - >>> from sage.all import * >>> h = M.lorentzian_metric('h') >>> h[Integer(1),Integer(1)], h[Integer(2),Integer(2)] = -Integer(1), Integer(1)+x**Integer(2) >>> Dv = v.laplacian(h); Dv Vector field Delta_h(v) on the Euclidean plane E^2 >>> Dv.display() Delta_h(v) = -(8*x^5 - 2*x^4 - x^2*y^2 + 15*x^3 - 4*x^2 + 6*x - 2)/(x^4 + 2*x^2 + 1) e_x - 3*x^3*y/(x^4 + 2*x^2 + 1) e_y 
 - lie_der(vector)[source]¶
- Lie derivative of - selfwith respect to a vector field.- INPUT: - vector– vector field with respect to which the Lie derivative is to be taken
 - OUTPUT: - the tensor field that is the Lie derivative of the current tensor field with respect to - vector
 - EXAMPLES: - Lie derivative of a type-\((1,1)\) tensor field along a vector field on a non-parallelizable 2-dimensional manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() sage: t = M.tensor_field(1, 1, {e_xy: [[x, 1], [y, 0]]}, name='t') sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: w = M.vector_field({e_xy: [-y, x]}, name='w') sage: w.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: lt = t.lie_derivative(w); lt Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: lt.display(e_xy) ∂/∂x⊗dx - x ∂/∂x⊗dy + (-y - 1) ∂/∂y⊗dy sage: lt.display(e_uv) -1/2*u ∂/∂u⊗du + (1/2*u + 1) ∂/∂u⊗dv + (-1/2*v + 1) ∂/∂v⊗du + 1/2*v ∂/∂v⊗dv - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> e_xy = c_xy.frame(); e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1), Integer(1), {e_xy: [[x, Integer(1)], [y, Integer(0)]]}, name='t') >>> t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> w = M.vector_field({e_xy: [-y, x]}, name='w') >>> w.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> lt = t.lie_derivative(w); lt Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> lt.display(e_xy) ∂/∂x⊗dx - x ∂/∂x⊗dy + (-y - 1) ∂/∂y⊗dy >>> lt.display(e_uv) -1/2*u ∂/∂u⊗du + (1/2*u + 1) ∂/∂u⊗dv + (-1/2*v + 1) ∂/∂v⊗du + 1/2*v ∂/∂v⊗dv - The result is cached: - sage: t.lie_derivative(w) is lt True - >>> from sage.all import * >>> t.lie_derivative(w) is lt True - An alias is - lie_der:- sage: t.lie_der(w) is t.lie_derivative(w) True - >>> from sage.all import * >>> t.lie_der(w) is t.lie_derivative(w) True - Lie derivative of a vector field: - sage: a = M.vector_field({e_xy: [1-x, x-y]}, name='a') sage: a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.lie_der(w) Vector field on the 2-dimensional differentiable manifold M sage: a.lie_der(w).display(e_xy) x ∂/∂x + (-y - 1) ∂/∂y sage: a.lie_der(w).display(e_uv) (v - 1) ∂/∂u + (u + 1) ∂/∂v - >>> from sage.all import * >>> a = M.vector_field({e_xy: [Integer(1)-x, x-y]}, name='a') >>> a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> a.lie_der(w) Vector field on the 2-dimensional differentiable manifold M >>> a.lie_der(w).display(e_xy) x ∂/∂x + (-y - 1) ∂/∂y >>> a.lie_der(w).display(e_uv) (v - 1) ∂/∂u + (u + 1) ∂/∂v - The Lie derivative is antisymmetric: - sage: a.lie_der(w) == - w.lie_der(a) True - >>> from sage.all import * >>> a.lie_der(w) == - w.lie_der(a) True - and it coincides with the commutator of the two vector fields: - sage: f = M.scalar_field({c_xy: 3*x-1, c_uv: 3/2*(u+v)-1}) sage: a.lie_der(w)(f) == w(a(f)) - a(w(f)) # long time True - >>> from sage.all import * >>> f = M.scalar_field({c_xy: Integer(3)*x-Integer(1), c_uv: Integer(3)/Integer(2)*(u+v)-Integer(1)}) >>> a.lie_der(w)(f) == w(a(f)) - a(w(f)) # long time True 
 - lie_derivative(vector)[source]¶
- Lie derivative of - selfwith respect to a vector field.- INPUT: - vector– vector field with respect to which the Lie derivative is to be taken
 - OUTPUT: - the tensor field that is the Lie derivative of the current tensor field with respect to - vector
 - EXAMPLES: - Lie derivative of a type-\((1,1)\) tensor field along a vector field on a non-parallelizable 2-dimensional manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() sage: t = M.tensor_field(1, 1, {e_xy: [[x, 1], [y, 0]]}, name='t') sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: w = M.vector_field({e_xy: [-y, x]}, name='w') sage: w.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: lt = t.lie_derivative(w); lt Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: lt.display(e_xy) ∂/∂x⊗dx - x ∂/∂x⊗dy + (-y - 1) ∂/∂y⊗dy sage: lt.display(e_uv) -1/2*u ∂/∂u⊗du + (1/2*u + 1) ∂/∂u⊗dv + (-1/2*v + 1) ∂/∂v⊗du + 1/2*v ∂/∂v⊗dv - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> e_xy = c_xy.frame(); e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1), Integer(1), {e_xy: [[x, Integer(1)], [y, Integer(0)]]}, name='t') >>> t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> w = M.vector_field({e_xy: [-y, x]}, name='w') >>> w.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> lt = t.lie_derivative(w); lt Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> lt.display(e_xy) ∂/∂x⊗dx - x ∂/∂x⊗dy + (-y - 1) ∂/∂y⊗dy >>> lt.display(e_uv) -1/2*u ∂/∂u⊗du + (1/2*u + 1) ∂/∂u⊗dv + (-1/2*v + 1) ∂/∂v⊗du + 1/2*v ∂/∂v⊗dv - The result is cached: - sage: t.lie_derivative(w) is lt True - >>> from sage.all import * >>> t.lie_derivative(w) is lt True - An alias is - lie_der:- sage: t.lie_der(w) is t.lie_derivative(w) True - >>> from sage.all import * >>> t.lie_der(w) is t.lie_derivative(w) True - Lie derivative of a vector field: - sage: a = M.vector_field({e_xy: [1-x, x-y]}, name='a') sage: a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.lie_der(w) Vector field on the 2-dimensional differentiable manifold M sage: a.lie_der(w).display(e_xy) x ∂/∂x + (-y - 1) ∂/∂y sage: a.lie_der(w).display(e_uv) (v - 1) ∂/∂u + (u + 1) ∂/∂v - >>> from sage.all import * >>> a = M.vector_field({e_xy: [Integer(1)-x, x-y]}, name='a') >>> a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) >>> a.lie_der(w) Vector field on the 2-dimensional differentiable manifold M >>> a.lie_der(w).display(e_xy) x ∂/∂x + (-y - 1) ∂/∂y >>> a.lie_der(w).display(e_uv) (v - 1) ∂/∂u + (u + 1) ∂/∂v - The Lie derivative is antisymmetric: - sage: a.lie_der(w) == - w.lie_der(a) True - >>> from sage.all import * >>> a.lie_der(w) == - w.lie_der(a) True - and it coincides with the commutator of the two vector fields: - sage: f = M.scalar_field({c_xy: 3*x-1, c_uv: 3/2*(u+v)-1}) sage: a.lie_der(w)(f) == w(a(f)) - a(w(f)) # long time True - >>> from sage.all import * >>> f = M.scalar_field({c_xy: Integer(3)*x-Integer(1), c_uv: Integer(3)/Integer(2)*(u+v)-Integer(1)}) >>> a.lie_der(w)(f) == w(a(f)) - a(w(f)) # long time True 
 - restrict(subdomain, dest_map=None)[source]¶
- Return the restriction of - selfto some subdomain.- If the restriction has not been defined yet, it is constructed here. - INPUT: - subdomain–- DifferentiableManifold; open subset \(U\) of the tensor field domain \(S\)
- dest_map–- DiffMap(default:- None); destination map \(\Psi:\ U \rightarrow V\), where \(V\) is an open subset of the manifold \(M\) where the tensor field takes it values; if- None, the restriction of \(\Phi\) to \(U\) is used, \(\Phi\) being the differentiable map \(S \rightarrow M\) associated with the tensor field
 - OUTPUT: - TensorFieldrepresenting the restriction- EXAMPLES: - Restrictions of a vector field on the 2-sphere: - sage: M = Manifold(2, 'S^2', start_index=1) sage: U = M.open_subset('U') # the complement of the North pole sage: stereoN.<x,y> = U.chart() # stereographic coordinates from the North pole sage: eN = stereoN.frame() # the associated vector frame sage: V = M.open_subset('V') # the complement of the South pole sage: stereoS.<u,v> = V.chart() # stereographic coordinates from the South pole sage: eS = stereoS.frame() # the associated vector frame sage: transf = stereoN.transition_map(stereoS, (x/(x^2+y^2), y/(x^2+y^2)), ....: intersection_name='W', restrictions1= x^2+y^2!=0, ....: restrictions2= u^2+v^2!=0) sage: inv = transf.inverse() # transformation from stereoS to stereoN sage: W = U.intersection(V) # the complement of the North and South poles sage: stereoN_W = W.atlas()[0] # restriction of stereographic coord. from North pole to W sage: stereoS_W = W.atlas()[1] # restriction of stereographic coord. from South pole to W sage: eN_W = stereoN_W.frame() ; eS_W = stereoS_W.frame() sage: v = M.vector_field({eN: [1, 0]}, name='v') sage: v.display() v = ∂/∂x sage: vU = v.restrict(U) ; vU Vector field v on the Open subset U of the 2-dimensional differentiable manifold S^2 sage: vU.display() v = ∂/∂x sage: vU == eN[1] True sage: vW = v.restrict(W) ; vW Vector field v on the Open subset W of the 2-dimensional differentiable manifold S^2 sage: vW.display() v = ∂/∂x sage: vW.display(eS_W, stereoS_W) v = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v sage: vW == eN_W[1] True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2', start_index=Integer(1)) >>> U = M.open_subset('U') # the complement of the North pole >>> stereoN = U.chart(names=('x', 'y',)); (x, y,) = stereoN._first_ngens(2)# stereographic coordinates from the North pole >>> eN = stereoN.frame() # the associated vector frame >>> V = M.open_subset('V') # the complement of the South pole >>> stereoS = V.chart(names=('u', 'v',)); (u, v,) = stereoS._first_ngens(2)# stereographic coordinates from the South pole >>> eS = stereoS.frame() # the associated vector frame >>> transf = stereoN.transition_map(stereoS, (x/(x**Integer(2)+y**Integer(2)), y/(x**Integer(2)+y**Integer(2))), ... intersection_name='W', restrictions1= x**Integer(2)+y**Integer(2)!=Integer(0), ... restrictions2= u**Integer(2)+v**Integer(2)!=Integer(0)) >>> inv = transf.inverse() # transformation from stereoS to stereoN >>> W = U.intersection(V) # the complement of the North and South poles >>> stereoN_W = W.atlas()[Integer(0)] # restriction of stereographic coord. from North pole to W >>> stereoS_W = W.atlas()[Integer(1)] # restriction of stereographic coord. from South pole to W >>> eN_W = stereoN_W.frame() ; eS_W = stereoS_W.frame() >>> v = M.vector_field({eN: [Integer(1), Integer(0)]}, name='v') >>> v.display() v = ∂/∂x >>> vU = v.restrict(U) ; vU Vector field v on the Open subset U of the 2-dimensional differentiable manifold S^2 >>> vU.display() v = ∂/∂x >>> vU == eN[Integer(1)] True >>> vW = v.restrict(W) ; vW Vector field v on the Open subset W of the 2-dimensional differentiable manifold S^2 >>> vW.display() v = ∂/∂x >>> vW.display(eS_W, stereoS_W) v = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v >>> vW == eN_W[Integer(1)] True - At this stage, defining the restriction of - vto the open subset- Vfully specifies- v:- sage: v.restrict(V)[1] = vW[eS_W, 1, stereoS_W].expr() # note that eS is the default frame on V sage: v.restrict(V)[2] = vW[eS_W, 2, stereoS_W].expr() sage: v.display(eS, stereoS) v = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v sage: v.restrict(U).display() v = ∂/∂x sage: v.restrict(V).display() v = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v - >>> from sage.all import * >>> v.restrict(V)[Integer(1)] = vW[eS_W, Integer(1), stereoS_W].expr() # note that eS is the default frame on V >>> v.restrict(V)[Integer(2)] = vW[eS_W, Integer(2), stereoS_W].expr() >>> v.display(eS, stereoS) v = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v >>> v.restrict(U).display() v = ∂/∂x >>> v.restrict(V).display() v = (-u^2 + v^2) ∂/∂u - 2*u*v ∂/∂v - The restriction of the vector field to its own domain is of course itself: - sage: v.restrict(M) is v True sage: vU.restrict(U) is vU True - >>> from sage.all import * >>> v.restrict(M) is v True >>> vU.restrict(U) is vU True 
 - set_calc_order(symbol, order, truncate=False)[source]¶
- Trigger a series expansion with respect to a small parameter in computations involving the tensor field. - This property is propagated by usual operations. The internal representation must be - SRfor this to take effect.- If the small parameter is \(\epsilon\) and \(T\) is - self, the power series expansion to order \(n\) is\[T = T_0 + \epsilon T_1 + \epsilon^2 T_2 + \cdots + \epsilon^n T_n + O(\epsilon^{n+1}),\]- where \(T_0, T_1, \ldots, T_n\) are \(n+1\) tensor fields of the same tensor type as - selfand do not depend upon \(\epsilon\).- INPUT: - symbol– symbolic variable (the “small parameter” \(\epsilon\)) with respect to which the components of- selfare expanded in power series
- order– integer; the order \(n\) of the expansion, defined as the degree of the polynomial representing the truncated power series in- symbol
- truncate– boolean (default:- False); determines whether the components of- selfare replaced by their expansions to the given order
 - EXAMPLES: - Let us consider two vector fields depending on a small parameter \(h\) on a non-parallelizable manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ....: restrictions1= x>0, restrictions2= u+v>0) sage: inv = transf.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_uv.frame() sage: a = M.vector_field() sage: h = var('h', domain='real') sage: a[eU,:] = (cos(h*x), -y) sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: b = M.vector_field() sage: b[eU,:] = (exp(h*x), exp(h*y)) sage: b.add_comp_by_continuation(eV, W, chart=c_uv) - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ... restrictions1= x>Integer(0), restrictions2= u+v>Integer(0)) >>> inv = transf.inverse() >>> W = U.intersection(V) >>> eU = c_xy.frame() ; eV = c_uv.frame() >>> a = M.vector_field() >>> h = var('h', domain='real') >>> a[eU,:] = (cos(h*x), -y) >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> b = M.vector_field() >>> b[eU,:] = (exp(h*x), exp(h*y)) >>> b.add_comp_by_continuation(eV, W, chart=c_uv) - If we set the calculus order on one of the vector fields, any operation involving both of them is performed to that order: - sage: a.set_calc_order(h, 2) sage: s = a + b sage: s[eU,:] [h*x + 2, 1/2*h^2*y^2 + h*y - y + 1] sage: s[eV,:] [1/8*(u^2 - 2*u*v + v^2)*h^2 + h*u - 1/2*u + 1/2*v + 3, -1/8*(u^2 - 2*u*v + v^2)*h^2 + h*v + 1/2*u - 1/2*v + 1] - >>> from sage.all import * >>> a.set_calc_order(h, Integer(2)) >>> s = a + b >>> s[eU,:] [h*x + 2, 1/2*h^2*y^2 + h*y - y + 1] >>> s[eV,:] [1/8*(u^2 - 2*u*v + v^2)*h^2 + h*u - 1/2*u + 1/2*v + 3, -1/8*(u^2 - 2*u*v + v^2)*h^2 + h*v + 1/2*u - 1/2*v + 1] - Note that the components of - ahave not been affected by the above call to- set_calc_order:- sage: a[eU,:] [cos(h*x), -y] sage: a[eV,:] [cos(1/2*h*u)*cos(1/2*h*v) - sin(1/2*h*u)*sin(1/2*h*v) - 1/2*u + 1/2*v, cos(1/2*h*u)*cos(1/2*h*v) - sin(1/2*h*u)*sin(1/2*h*v) + 1/2*u - 1/2*v] - >>> from sage.all import * >>> a[eU,:] [cos(h*x), -y] >>> a[eV,:] [cos(1/2*h*u)*cos(1/2*h*v) - sin(1/2*h*u)*sin(1/2*h*v) - 1/2*u + 1/2*v, cos(1/2*h*u)*cos(1/2*h*v) - sin(1/2*h*u)*sin(1/2*h*v) + 1/2*u - 1/2*v] - To have - set_calc_orderact on them, set the optional argument- truncateto- True:- sage: a.set_calc_order(h, 2, truncate=True) sage: a[eU,:] [-1/2*h^2*x^2 + 1, -y] sage: a[eV,:] [-1/8*(u^2 + 2*u*v + v^2)*h^2 - 1/2*u + 1/2*v + 1, -1/8*(u^2 + 2*u*v + v^2)*h^2 + 1/2*u - 1/2*v + 1] - >>> from sage.all import * >>> a.set_calc_order(h, Integer(2), truncate=True) >>> a[eU,:] [-1/2*h^2*x^2 + 1, -y] >>> a[eV,:] [-1/8*(u^2 + 2*u*v + v^2)*h^2 - 1/2*u + 1/2*v + 1, -1/8*(u^2 + 2*u*v + v^2)*h^2 + 1/2*u - 1/2*v + 1] 
 - set_comp(basis=None)[source]¶
- Return the components of - selfin a given vector frame for assignment.- The components with respect to other frames having the same domain as the provided vector frame are deleted, in order to avoid any inconsistency. To keep them, use the method - add_comp()instead.- INPUT: - basis– (default:- None) vector frame in which the components are defined; if none is provided, the components are assumed to refer to the tensor field domain’s default frame
 - OUTPUT: - components in the given frame, as a - Components; if such components did not exist previously, they are created
 - EXAMPLES: - sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole sage: V = M.open_subset('V') # complement of the South pole sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: e_uv = c_uv.frame() sage: t = M.tensor_field(1, 2, name='t') sage: t.set_comp(e_uv) 3-indices components w.r.t. Coordinate frame (V, (∂/∂u,∂/∂v)) sage: t.set_comp(e_uv)[1,0,1] = u+v sage: t.display(e_uv) t = (u + v) ∂/∂v⊗du⊗dv - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') # the 2-dimensional sphere S^2 >>> U = M.open_subset('U') # complement of the North pole >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole >>> V = M.open_subset('V') # complement of the South pole >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole >>> M.declare_union(U,V) # S^2 is the union of U and V >>> e_uv = c_uv.frame() >>> t = M.tensor_field(Integer(1), Integer(2), name='t') >>> t.set_comp(e_uv) 3-indices components w.r.t. Coordinate frame (V, (∂/∂u,∂/∂v)) >>> t.set_comp(e_uv)[Integer(1),Integer(0),Integer(1)] = u+v >>> t.display(e_uv) t = (u + v) ∂/∂v⊗du⊗dv - Setting the components in a new frame ( - e):- sage: e = V.vector_frame('e') sage: t.set_comp(e) 3-indices components w.r.t. Vector frame (V, (e_0,e_1)) sage: t.set_comp(e)[0,1,1] = u*v sage: t.display(e) t = u*v e_0⊗e^1⊗e^1 - >>> from sage.all import * >>> e = V.vector_frame('e') >>> t.set_comp(e) 3-indices components w.r.t. Vector frame (V, (e_0,e_1)) >>> t.set_comp(e)[Integer(0),Integer(1),Integer(1)] = u*v >>> t.display(e) t = u*v e_0⊗e^1⊗e^1 - Since the frames - eand- e_uvare defined on the same domain, the components w.r.t.- e_uvhave been erased:- sage: t.display(c_uv.frame()) Traceback (most recent call last): ... ValueError: no basis could be found for computing the components in the Coordinate frame (V, (∂/∂u,∂/∂v)) - >>> from sage.all import * >>> t.display(c_uv.frame()) Traceback (most recent call last): ... ValueError: no basis could be found for computing the components in the Coordinate frame (V, (∂/∂u,∂/∂v)) - Since zero is an immutable, its components cannot be changed: - sage: z = M.tensor_field_module((1, 1)).zero() sage: z.set_comp(e)[0,1] = u*v Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed - >>> from sage.all import * >>> z = M.tensor_field_module((Integer(1), Integer(1))).zero() >>> z.set_comp(e)[Integer(0),Integer(1)] = u*v Traceback (most recent call last): ... ValueError: the components of an immutable element cannot be changed 
 - set_immutable()[source]¶
- Set - selfand all restrictions of- selfimmutable.- EXAMPLES: - sage: M = Manifold(2, 'M') sage: X.<x,y> = M.chart() sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}) sage: a = M.tensor_field(1, 1, [[1+y,x], [0,x+y]], name='a') sage: aU = a.restrict(U) sage: a.set_immutable() sage: aU.is_immutable() True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> U = M.open_subset('U', coord_def={X: x**Integer(2)+y**Integer(2)<Integer(1)}) >>> a = M.tensor_field(Integer(1), Integer(1), [[Integer(1)+y,x], [Integer(0),x+y]], name='a') >>> aU = a.restrict(U) >>> a.set_immutable() >>> aU.is_immutable() True 
 - set_name(name=None, latex_name=None)[source]¶
- Set (or change) the text name and LaTeX name of - self.- INPUT: - name– string (default:- None); name given to the tensor field
- latex_name– string (default:- None); LaTeX symbol to denote the tensor field; if- Nonewhile- nameis provided, the LaTeX symbol is set to- name
 - EXAMPLES: - sage: M = Manifold(2, 'M') sage: t = M.tensor_field(1, 3); t Tensor field of type (1,3) on the 2-dimensional differentiable manifold M sage: t.set_name(name='t') sage: t Tensor field t of type (1,3) on the 2-dimensional differentiable manifold M sage: latex(t) t sage: t.set_name(latex_name=r'\tau') sage: latex(t) \tau sage: t.set_name(name='a') sage: t Tensor field a of type (1,3) on the 2-dimensional differentiable manifold M sage: latex(t) a - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> t = M.tensor_field(Integer(1), Integer(3)); t Tensor field of type (1,3) on the 2-dimensional differentiable manifold M >>> t.set_name(name='t') >>> t Tensor field t of type (1,3) on the 2-dimensional differentiable manifold M >>> latex(t) t >>> t.set_name(latex_name=r'\tau') >>> latex(t) \tau >>> t.set_name(name='a') >>> t Tensor field a of type (1,3) on the 2-dimensional differentiable manifold M >>> latex(t) a 
 - set_restriction(rst)[source]¶
- Define a restriction of - selfto some subdomain.- INPUT: - rst–- TensorFieldof the same type and symmetries as the current tensor field- self, defined on a subdomain of the domain of- self
 - EXAMPLES: - sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole sage: V = M.open_subset('V') # complement of the South pole sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: t = M.tensor_field(1, 2, name='t') sage: s = U.tensor_field(1, 2) sage: s[0,0,1] = x+y sage: t.set_restriction(s) sage: t.display(c_xy.frame()) t = (x + y) ∂/∂x⊗dx⊗dy sage: t.restrict(U) == s True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') # the 2-dimensional sphere S^2 >>> U = M.open_subset('U') # complement of the North pole >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole >>> V = M.open_subset('V') # complement of the South pole >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole >>> M.declare_union(U,V) # S^2 is the union of U and V >>> t = M.tensor_field(Integer(1), Integer(2), name='t') >>> s = U.tensor_field(Integer(1), Integer(2)) >>> s[Integer(0),Integer(0),Integer(1)] = x+y >>> t.set_restriction(s) >>> t.display(c_xy.frame()) t = (x + y) ∂/∂x⊗dx⊗dy >>> t.restrict(U) == s True - If the restriction is defined on the very same domain, the tensor field becomes a copy of it (see - copy_from()):- sage: v = M.tensor_field(1, 2, name='v') sage: v.set_restriction(t) sage: v.restrict(U) == t.restrict(U) True - >>> from sage.all import * >>> v = M.tensor_field(Integer(1), Integer(2), name='v') >>> v.set_restriction(t) >>> v.restrict(U) == t.restrict(U) True 
 - symmetries()[source]¶
- Print the list of symmetries and antisymmetries. - EXAMPLES: - sage: M = Manifold(2, 'S^2') sage: t = M.tensor_field(1,2) sage: t.symmetries() no symmetry; no antisymmetry sage: t = M.tensor_field(1,2, sym=(1,2)) sage: t.symmetries() symmetry: (1, 2); no antisymmetry sage: t = M.tensor_field(2,2, sym=(0,1), antisym=(2,3)) sage: t.symmetries() symmetry: (0, 1); antisymmetry: (2, 3) sage: t = M.tensor_field(2,2, antisym=[(0,1),(2,3)]) sage: t.symmetries() no symmetry; antisymmetries: [(0, 1), (2, 3)] - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2') >>> t = M.tensor_field(Integer(1),Integer(2)) >>> t.symmetries() no symmetry; no antisymmetry >>> t = M.tensor_field(Integer(1),Integer(2), sym=(Integer(1),Integer(2))) >>> t.symmetries() symmetry: (1, 2); no antisymmetry >>> t = M.tensor_field(Integer(2),Integer(2), sym=(Integer(0),Integer(1)), antisym=(Integer(2),Integer(3))) >>> t.symmetries() symmetry: (0, 1); antisymmetry: (2, 3) >>> t = M.tensor_field(Integer(2),Integer(2), antisym=[(Integer(0),Integer(1)),(Integer(2),Integer(3))]) >>> t.symmetries() no symmetry; antisymmetries: [(0, 1), (2, 3)] 
 - symmetrize(*pos)[source]¶
- Symmetrization over some arguments. - INPUT: - pos– (default:- None) list of argument positions involved in the symmetrization (with the convention- position=0for the first argument); if- None, the symmetrization is performed over all the arguments
 - OUTPUT: - the symmetrized tensor field (instance of - TensorField)
 - EXAMPLES: - Symmetrization of a type-\((0,2)\) tensor field on a 2-dimensional non-parallelizable manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ....: restrictions1= x>0, restrictions2= u+v>0) sage: inv = transf.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_uv.frame() sage: a = M.tensor_field(0,2, {eU: [[1,x], [2,y]]}, name='a') sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: a[eV,:] [ 1/4*u + 3/4 -1/4*u + 3/4] [ 1/4*v - 1/4 -1/4*v - 1/4] sage: s = a.symmetrize() ; s Field of symmetric bilinear forms on the 2-dimensional differentiable manifold M sage: s[eU,:] [ 1 1/2*x + 1] [1/2*x + 1 y] sage: s[eV,:] [ 1/4*u + 3/4 -1/8*u + 1/8*v + 1/4] [-1/8*u + 1/8*v + 1/4 -1/4*v - 1/4] sage: s == a.symmetrize(0,1) # explicit positions True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W', ... restrictions1= x>Integer(0), restrictions2= u+v>Integer(0)) >>> inv = transf.inverse() >>> W = U.intersection(V) >>> eU = c_xy.frame() ; eV = c_uv.frame() >>> a = M.tensor_field(Integer(0),Integer(2), {eU: [[Integer(1),x], [Integer(2),y]]}, name='a') >>> a.add_comp_by_continuation(eV, W, chart=c_uv) >>> a[eV,:] [ 1/4*u + 3/4 -1/4*u + 3/4] [ 1/4*v - 1/4 -1/4*v - 1/4] >>> s = a.symmetrize() ; s Field of symmetric bilinear forms on the 2-dimensional differentiable manifold M >>> s[eU,:] [ 1 1/2*x + 1] [1/2*x + 1 y] >>> s[eV,:] [ 1/4*u + 3/4 -1/8*u + 1/8*v + 1/4] [-1/8*u + 1/8*v + 1/4 -1/4*v - 1/4] >>> s == a.symmetrize(Integer(0),Integer(1)) # explicit positions True - See also - For more details and examples, see - sage.tensor.modules.free_module_tensor.FreeModuleTensor.symmetrize().
 - tensor_rank()[source]¶
- Return the tensor rank of - self.- OUTPUT: - integer \(k+l\), where \(k\) is the contravariant rank and \(l\) is the covariant rank 
 - EXAMPLES: - sage: M = Manifold(2, 'S^2') sage: t = M.tensor_field(1,2) sage: t.tensor_rank() 3 sage: v = M.vector_field() sage: v.tensor_rank() 1 - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2') >>> t = M.tensor_field(Integer(1),Integer(2)) >>> t.tensor_rank() 3 >>> v = M.vector_field() >>> v.tensor_rank() 1 
 - tensor_type()[source]¶
- Return the tensor type of - self.- OUTPUT: - pair \((k,l)\), where \(k\) is the contravariant rank and \(l\) is the covariant rank 
 - EXAMPLES: - sage: M = Manifold(2, 'S^2') sage: t = M.tensor_field(1,2) sage: t.tensor_type() (1, 2) sage: v = M.vector_field() sage: v.tensor_type() (1, 0) - >>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2') >>> t = M.tensor_field(Integer(1),Integer(2)) >>> t.tensor_type() (1, 2) >>> v = M.vector_field() >>> v.tensor_type() (1, 0) 
 - trace(pos1=0, pos2=1, using=None)[source]¶
- Trace (contraction) on two slots of the tensor field. - If a non-degenerate form is provided, the trace of a \((0,2)\) tensor field is computed by first raising the last index. - INPUT: - pos1– (default: 0) position of the first index for the contraction, with the convention- pos1=0for the first slot
- pos2– (default: 1) position of the second index for the contraction, with the same convention as for- pos1. The variance type of- pos2must be opposite to that of- pos1
- using– (default:- None) a non-degenerate form
 - OUTPUT: - tensor field resulting from the - (pos1, pos2)contraction
 - EXAMPLES: - Trace of a type-\((1,1)\) tensor field on a 2-dimensional non-parallelizable manifold: - sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ....: intersection_name='W', restrictions1= x>0, ....: restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() sage: W = U.intersection(V) sage: a = M.tensor_field(1,1, name='a') sage: a[e_xy,:] = [[1,x], [2,y]] sage: a.add_comp_by_continuation(e_uv, W, chart=c_uv) sage: s = a.trace() ; s Scalar field on the 2-dimensional differentiable manifold M sage: s.display() M → ℝ on U: (x, y) ↦ y + 1 on V: (u, v) ↦ 1/2*u - 1/2*v + 1 sage: s == a.trace(0,1) # explicit mention of the positions True - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M') >>> U = M.open_subset('U') ; V = M.open_subset('V') >>> M.declare_union(U,V) # M is the union of U and V >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), ... intersection_name='W', restrictions1= x>Integer(0), ... restrictions2= u+v>Integer(0)) >>> uv_to_xy = xy_to_uv.inverse() >>> e_xy = c_xy.frame(); e_uv = c_uv.frame() >>> W = U.intersection(V) >>> a = M.tensor_field(Integer(1),Integer(1), name='a') >>> a[e_xy,:] = [[Integer(1),x], [Integer(2),y]] >>> a.add_comp_by_continuation(e_uv, W, chart=c_uv) >>> s = a.trace() ; s Scalar field on the 2-dimensional differentiable manifold M >>> s.display() M → ℝ on U: (x, y) ↦ y + 1 on V: (u, v) ↦ 1/2*u - 1/2*v + 1 >>> s == a.trace(Integer(0),Integer(1)) # explicit mention of the positions True - The trace of a type-\((0,2)\) tensor field using a metric: - sage: g = M.metric('g') sage: g[0,0], g[0,1], g[1,1] = 1, 0, 1 sage: g.trace(using=g).display() M → ℝ on U: (x, y) ↦ 2 on W: (u, v) ↦ 2 - >>> from sage.all import * >>> g = M.metric('g') >>> g[Integer(0),Integer(0)], g[Integer(0),Integer(1)], g[Integer(1),Integer(1)] = Integer(1), Integer(0), Integer(1) >>> g.trace(using=g).display() M → ℝ on U: (x, y) ↦ 2 on W: (u, v) ↦ 2 - Instead of the explicit call to the method - trace(), one may use the index notation with Einstein convention (summation over repeated indices); it suffices to pass the indices as a string inside square brackets:- sage: a['^i_i'] Scalar field on the 2-dimensional differentiable manifold M sage: a['^i_i'] == s True - >>> from sage.all import * >>> a['^i_i'] Scalar field on the 2-dimensional differentiable manifold M >>> a['^i_i'] == s True - Any letter can be used to denote the repeated index: - sage: a['^b_b'] == s True - >>> from sage.all import * >>> a['^b_b'] == s True - Trace of a type-\((1,2)\) tensor field: - sage: b = M.tensor_field(1,2, name='b') ; b Tensor field b of type (1,2) on the 2-dimensional differentiable manifold M sage: b[e_xy,:] = [[[0,x+y], [y,0]], [[0,2], [3*x,-2]]] sage: b.add_comp_by_continuation(e_uv, W, chart=c_uv) # long time sage: s = b.trace(0,1) ; s # contraction on first and second slots 1-form on the 2-dimensional differentiable manifold M sage: s.display(e_xy) 3*x dx + (x + y - 2) dy sage: s.display(e_uv) # long time (5/4*u + 3/4*v - 1) du + (1/4*u + 3/4*v + 1) dv - >>> from sage.all import * >>> b = M.tensor_field(Integer(1),Integer(2), name='b') ; b Tensor field b of type (1,2) on the 2-dimensional differentiable manifold M >>> b[e_xy,:] = [[[Integer(0),x+y], [y,Integer(0)]], [[Integer(0),Integer(2)], [Integer(3)*x,-Integer(2)]]] >>> b.add_comp_by_continuation(e_uv, W, chart=c_uv) # long time >>> s = b.trace(Integer(0),Integer(1)) ; s # contraction on first and second slots 1-form on the 2-dimensional differentiable manifold M >>> s.display(e_xy) 3*x dx + (x + y - 2) dy >>> s.display(e_uv) # long time (5/4*u + 3/4*v - 1) du + (1/4*u + 3/4*v + 1) dv - Use of the index notation: - sage: b['^k_ki'] 1-form on the 2-dimensional differentiable manifold M sage: b['^k_ki'] == s # long time True - >>> from sage.all import * >>> b['^k_ki'] 1-form on the 2-dimensional differentiable manifold M >>> b['^k_ki'] == s # long time True - Indices not involved in the contraction may be replaced by dots: - sage: b['^k_k.'] == s # long time True - >>> from sage.all import * >>> b['^k_k.'] == s # long time True - The symbol - ^may be omitted:- sage: b['k_k.'] == s # long time True - >>> from sage.all import * >>> b['k_k.'] == s # long time True - LaTeX notations are allowed: - sage: b['^{k}_{ki}'] == s # long time True - >>> from sage.all import * >>> b['^{k}_{ki}'] == s # long time True - Contraction on first and third slots: - sage: s = b.trace(0,2) ; s 1-form on the 2-dimensional differentiable manifold M sage: s.display(e_xy) 2 dx + (y - 2) dy sage: s.display(e_uv) # long time (1/4*u - 1/4*v) du + (-1/4*u + 1/4*v + 2) dv - >>> from sage.all import * >>> s = b.trace(Integer(0),Integer(2)) ; s 1-form on the 2-dimensional differentiable manifold M >>> s.display(e_xy) 2 dx + (y - 2) dy >>> s.display(e_uv) # long time (1/4*u - 1/4*v) du + (-1/4*u + 1/4*v + 2) dv - Use of index notation: - sage: b['^k_.k'] == s # long time True - >>> from sage.all import * >>> b['^k_.k'] == s # long time True 
 - up(non_degenerate_form, pos=None)[source]¶
- Compute a dual of the tensor field by raising some index with the given tensor field (usually, a pseudo-Riemannian metric, a symplectic form or a Poisson tensor). - If \(T\) is the tensor field, \((k,l)\) its type and \(p\) the position of a covariant index (i.e. \(k\leq p < k+l\)), this method called with - pos\(=p\) yields the tensor field \(T^\sharp\) of type \((k+1,l-1)\) whose components are\[(T^\sharp)^{a_1\ldots a_{k+1}}_{\phantom{a_1\ldots a_{k+1}}\, b_1 \ldots b_{l-1}} = g^{a_{k+1} i} \, T^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\, b_1 \ldots b_{p-k} \, i \, b_{p-k+1}\ldots b_{l-1}},\]- \(g^{ab}\) being the components of the inverse metric or the Poisson tensor, respectively. - The reverse operation is - TensorField.down().- INPUT: - non_degenerate_form– non-degenerate form \(g\), or a Poisson tensor
- pos– (default:- None) position of the index (with the convention- pos=0for the first index); if- None, the raising is performed over all the covariant indices, starting from the first one
 - OUTPUT: - the tensor field \(T^\sharp\) resulting from the index raising operation 
 - EXAMPLES: - Raising the index of a 1-form results in a vector field: - sage: M = Manifold(2, 'M', start_index=1) sage: c_xy.<x,y> = M.chart() sage: g = M.metric('g') sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-y sage: w = M.one_form(-1, 2) sage: v = w.up(g) ; v Vector field on the 2-dimensional differentiable manifold M sage: v.display() ((2*x - 1)*y + 1)/(x^2*y^2 + (x + 1)*y - x - 1) ∂/∂x - (x*y + 2*x + 2)/(x^2*y^2 + (x + 1)*y - x - 1) ∂/∂y sage: ig = g.inverse(); ig[:] [ (y - 1)/(x^2*y^2 + (x + 1)*y - x - 1) x*y/(x^2*y^2 + (x + 1)*y - x - 1)] [ x*y/(x^2*y^2 + (x + 1)*y - x - 1) -(x + 1)/(x^2*y^2 + (x + 1)*y - x - 1)] - >>> from sage.all import * >>> M = Manifold(Integer(2), 'M', start_index=Integer(1)) >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> g = M.metric('g') >>> g[Integer(1),Integer(1)], g[Integer(1),Integer(2)], g[Integer(2),Integer(2)] = Integer(1)+x, x*y, Integer(1)-y >>> w = M.one_form(-Integer(1), Integer(2)) >>> v = w.up(g) ; v Vector field on the 2-dimensional differentiable manifold M >>> v.display() ((2*x - 1)*y + 1)/(x^2*y^2 + (x + 1)*y - x - 1) ∂/∂x - (x*y + 2*x + 2)/(x^2*y^2 + (x + 1)*y - x - 1) ∂/∂y >>> ig = g.inverse(); ig[:] [ (y - 1)/(x^2*y^2 + (x + 1)*y - x - 1) x*y/(x^2*y^2 + (x + 1)*y - x - 1)] [ x*y/(x^2*y^2 + (x + 1)*y - x - 1) -(x + 1)/(x^2*y^2 + (x + 1)*y - x - 1)] - Using the index notation instead of - up():- sage: v == ig['^ab']*w['_b'] True - >>> from sage.all import * >>> v == ig['^ab']*w['_b'] True - The reverse operation: - sage: w1 = v.down(g) ; w1 1-form on the 2-dimensional differentiable manifold M sage: w1.display() -dx + 2 dy sage: w1 == w True - >>> from sage.all import * >>> w1 = v.down(g) ; w1 1-form on the 2-dimensional differentiable manifold M >>> w1.display() -dx + 2 dy >>> w1 == w True - The reverse operation in index notation: - sage: g['_ab']*v['^b'] == w True - >>> from sage.all import * >>> g['_ab']*v['^b'] == w True - Raising the indices of a tensor field of type (0,2): - sage: t = M.tensor_field(0, 2, [[1,2], [3,4]]) sage: tu0 = t.up(g, 0) ; tu0 # raising the first index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: tu0[:] [ ((3*x + 1)*y - 1)/(x^2*y^2 + (x + 1)*y - x - 1) 2*((2*x + 1)*y - 1)/(x^2*y^2 + (x + 1)*y - x - 1)] [ (x*y - 3*x - 3)/(x^2*y^2 + (x + 1)*y - x - 1) 2*(x*y - 2*x - 2)/(x^2*y^2 + (x + 1)*y - x - 1)] sage: tu0 == ig['^ac']*t['_cb'] # the same operation in index notation True sage: tuu0 = tu0.up(g) ; tuu0 # the two indices have been raised, starting from the first one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: tuu0 == tu0['^a_c']*ig['^cb'] # the same operation in index notation True sage: tu1 = t.up(g, 1) ; tu1 # raising the second index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: tu1 == ig['^ac']*t['_bc'] # the same operation in index notation True sage: tu1[:] [((2*x + 1)*y - 1)/(x^2*y^2 + (x + 1)*y - x - 1) ((4*x + 3)*y - 3)/(x^2*y^2 + (x + 1)*y - x - 1)] [ (x*y - 2*x - 2)/(x^2*y^2 + (x + 1)*y - x - 1) (3*x*y - 4*x - 4)/(x^2*y^2 + (x + 1)*y - x - 1)] sage: tuu1 = tu1.up(g) ; tuu1 # the two indices have been raised, starting from the second one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: tuu1 == tu1['^a_c']*ig['^cb'] # the same operation in index notation True sage: tuu0 == tuu1 # the order of index raising is important False sage: tuu = t.up(g) ; tuu # both indices are raised, starting from the first one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M sage: tuu0 == tuu # the same order for index raising has been applied True sage: tuu1 == tuu # to get tuu1, indices have been raised from the last one, contrary to tuu False sage: d0tuu = tuu.down(g, 0) ; d0tuu # the first index is lowered again Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: dd0tuu = d0tuu.down(g) ; dd0tuu # the second index is then lowered Tensor field of type (0,2) on the 2-dimensional differentiable manifold M sage: d1tuu = tuu.down(g, 1) ; d1tuu # lowering operation, starting from the last index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M sage: dd1tuu = d1tuu.down(g) ; dd1tuu Tensor field of type (0,2) on the 2-dimensional differentiable manifold M sage: ddtuu = tuu.down(g) ; ddtuu # both indices are lowered, starting from the last one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M sage: ddtuu == t # should be true True sage: dd0tuu == t # not true, because of the order of index lowering to get dd0tuu False sage: dd1tuu == t # should be true True - >>> from sage.all import * >>> t = M.tensor_field(Integer(0), Integer(2), [[Integer(1),Integer(2)], [Integer(3),Integer(4)]]) >>> tu0 = t.up(g, Integer(0)) ; tu0 # raising the first index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> tu0[:] [ ((3*x + 1)*y - 1)/(x^2*y^2 + (x + 1)*y - x - 1) 2*((2*x + 1)*y - 1)/(x^2*y^2 + (x + 1)*y - x - 1)] [ (x*y - 3*x - 3)/(x^2*y^2 + (x + 1)*y - x - 1) 2*(x*y - 2*x - 2)/(x^2*y^2 + (x + 1)*y - x - 1)] >>> tu0 == ig['^ac']*t['_cb'] # the same operation in index notation True >>> tuu0 = tu0.up(g) ; tuu0 # the two indices have been raised, starting from the first one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> tuu0 == tu0['^a_c']*ig['^cb'] # the same operation in index notation True >>> tu1 = t.up(g, Integer(1)) ; tu1 # raising the second index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> tu1 == ig['^ac']*t['_bc'] # the same operation in index notation True >>> tu1[:] [((2*x + 1)*y - 1)/(x^2*y^2 + (x + 1)*y - x - 1) ((4*x + 3)*y - 3)/(x^2*y^2 + (x + 1)*y - x - 1)] [ (x*y - 2*x - 2)/(x^2*y^2 + (x + 1)*y - x - 1) (3*x*y - 4*x - 4)/(x^2*y^2 + (x + 1)*y - x - 1)] >>> tuu1 = tu1.up(g) ; tuu1 # the two indices have been raised, starting from the second one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> tuu1 == tu1['^a_c']*ig['^cb'] # the same operation in index notation True >>> tuu0 == tuu1 # the order of index raising is important False >>> tuu = t.up(g) ; tuu # both indices are raised, starting from the first one Tensor field of type (2,0) on the 2-dimensional differentiable manifold M >>> tuu0 == tuu # the same order for index raising has been applied True >>> tuu1 == tuu # to get tuu1, indices have been raised from the last one, contrary to tuu False >>> d0tuu = tuu.down(g, Integer(0)) ; d0tuu # the first index is lowered again Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> dd0tuu = d0tuu.down(g) ; dd0tuu # the second index is then lowered Tensor field of type (0,2) on the 2-dimensional differentiable manifold M >>> d1tuu = tuu.down(g, Integer(1)) ; d1tuu # lowering operation, starting from the last index Tensor field of type (1,1) on the 2-dimensional differentiable manifold M >>> dd1tuu = d1tuu.down(g) ; dd1tuu Tensor field of type (0,2) on the 2-dimensional differentiable manifold M >>> ddtuu = tuu.down(g) ; ddtuu # both indices are lowered, starting from the last one Tensor field of type (0,2) on the 2-dimensional differentiable manifold M >>> ddtuu == t # should be true True >>> dd0tuu == t # not true, because of the order of index lowering to get dd0tuu False >>> dd1tuu == t # should be true True