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:
VectorField
for vector fields (rank1 contravariant tensor fields)AutomorphismField
for fields of tangentspace automorphismsDiffForm
for differential forms (fully antisymmetric covariant tensor fields)
AUTHORS:
 Eric Gourgoulhon, Michal Bejger (20132015) : initial version
 Travis Scrimshaw (2016): review tweaks
REFERENCES:

class
sage.manifolds.differentiable.tensorfield.
TensorField
(vector_field_module, tensor_type, name=None, latex_name=None, sym=None, antisym=None, parent=None)¶ Bases:
sage.structure.element.ModuleElement
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\ \; \mbox{times}} \times \underbrace{T_q M\times\cdots\times T_q M}_{l\ \; \mbox{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
TensorFieldParal
should 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 rankname
– (default:None
) name given to the tensor fieldlatex_name
– (default:None
) LaTeX symbol to denote the tensor field; if none is provided, the LaTeX symbol is set toname
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 conventionposition = 0
for the first argument; for instance:sym = (0,1)
for a symmetry between the 1st and 2nd argumentssym = [(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 forsym
parent
– (default:None
) some specific parent (e.g. exterior power for differential forms); ifNone
,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 2dimensional 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 2dimensional differentiable manifold S^2 sage: t.parent() Module T^(0,2)(S^2) of type(0,2) tensors fields on the 2dimensional differentiable manifold S^2 sage: t.parent().category() Category of modules over Algebra of differentiable scalar fields on the 2dimensional 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
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
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
Actually, the above operation can by 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
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 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
Let us consider two vector fields, \(a\) and \(b\), on \(S^2\):
sage: a = M.vector_field(name='a') sage: a[eU,:] = [y,x] sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: a.display(eV) a = v d/du + u d/dv sage: b = M.vector_field(name='b') sage: b[eU,:] = [y,1] 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) d/du  (u^4  v^4 + 2*u*v^2)/(u^2 + v^2) d/dv
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 2dimensional differentiable manifold S^2 sage: f.display() # long time t(a,b): S^2 > R 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: s = t(a.restrict(U), b) ; s # long time Scalar field t(a,b) on the Open subset U of the 2dimensional differentiable manifold S^2 sage: s.display() # long time t(a,b): U > R (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 # long time Scalar field t(a,b) on the Open subset W of the 2dimensional differentiable manifold S^2 sage: s.display() # long time t(a,b): W > R (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 2dimensional differentiable manifold S^2 sage: s.display() # long time t(a,b): V > R (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 of type (0,2) on the 2dimensional 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 of type (0,2) on the Open subset U of the 2dimensional differentiable manifold S^2 sage: s.restrict(U) == f.restrict(U) * t.restrict(U) True

add_comp
(basis=None)¶ Return the components of
self
in 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; ifNone
, 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 2dimensional 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) 3indices components w.r.t. Coordinate frame (V, (d/du,d/dv)) sage: t.add_comp(e_uv)[1,0,1] = u+v sage: t.display(e_uv) t = (u + v) d/dv*du*dv
Setting the components in a new frame:
sage: e = V.vector_frame('e') sage: t.add_comp(e) 3indices 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
The components with respect to
e_uv
are kept:sage: t.display(e_uv) t = (u + v) d/dv*du*dv

add_comp_by_continuation
(frame, subdomain, chart=None)¶ 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 setsubdomain
– open subset of \(e\)‘s domain in which the components are known or can be evaluated from other componentschart
– (default:None
) coordinate chart on \(e\)‘s domain in which the extension of the expression of the components is to be performed; ifNone
, 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) sage: # 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('a') sage: a[eU,:] = [x, 2+y]
At this stage, the vector field has been defined only on the open subset
U
(through its components in the frameeU
):sage: a.display(eU) a = x d/dx + (y + 2) d/dy
The components with respect to the restriction of
eV
to the common subdomainW
, in terms of the(u,v)
coordinates, are obtained by a changeofframe formula onW
:sage: a.display(eV.restrict(W), c_uv.restrict(W)) a = (4*u*v  u) d/du + (2*u^2  2*v^2  v) d/dv
The continuation consists in extending the definition of the vector field to the whole open subset
V
by 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)
We have then:
sage: a.display(eV) a = (4*u*v  u) d/du + (2*u^2  2*v^2  v) d/dv
and \(a\) is defined on the entire manifold \(S^2\).

antisymmetrize
(*pos)¶ Antisymmetrization over some arguments.
INPUT:
pos
– (default:None
) list of argument positions involved in the antisymmetrization (with the conventionposition=0
for the first argument); ifNone
, 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 2dimensional nonparallelizable 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, xy), 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, name='a') sage: a[eU,:] = [[1,x], [2,y]] 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 2form on the 2dimensional 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
See also
For more details and examples, see
sage.tensor.modules.free_module_tensor.FreeModuleTensor.antisymmetrize()
.

at
(point)¶ Value of
self
at 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:
FreeModuleTensor
representing the tensor \(t(p)\) on the tangent vector space \(T_{\Phi(p)} M\)
EXAMPLES:
Tensor on a tangent space of a nonparallelizable 2dimensional 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, xy), ....: 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, name='a') sage: a[eU,:] = [[1+y,x], [0,x+y]] sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: a.display(eU) a = (y + 1) d/dx*dx + x d/dx*dy + (x + y) d/dy*dy sage: a.display(eV) a = (u + 1/2) d/du*du + (1/2*u  1/2*v + 1/2) d/du*dv + 1/2 d/dv*du + (1/2*u  1/2*v + 1/2) d/dv*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 2dimensional differentiable manifold M sage: ap.parent() Free module of type(1,1) tensors on the Tangent space at Point p on the 2dimensional differentiable manifold M sage: ap.display(eU.at(p)) a = 4 d/dx*dx + 2 d/dx*dy + 5 d/dy*dy sage: ap.display(eV.at(p)) a = 11/2 d/du*du  3/2 d/du*dv + 1/2 d/dv*du + 7/2 d/dv*dv sage: p.coord(c_uv) # to check the above expression (5, 1)

base_module
()¶ Return the vector field module on which
self
acts as a tensor.OUTPUT:
 instance of
VectorFieldModule
EXAMPLES:
The module of vector fields on the 2sphere 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 2dimensional 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
 instance of

comp
(basis=None, from_basis=None)¶ Return the components in a given vector frame.
If the components are not known already, they are computed by the tensor changeofbasis 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 framefrom_basis
– (default:None
) vector frame from which the required components are computed, via the tensor changeofbasis formula, if they are not known already in the basisbasis
OUTPUT:
 components in the vector frame
basis
, as aComponents
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, (d/dx,d/dy)) sage: V = M.open_subset('V') sage: c_uv.<u, v> = V.chart() sage: f = V.default_frame() ; f Coordinate frame (V, (d/du,d/dv)) 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) 2indices components w.r.t. Coordinate frame (U, (d/dx,d/dy)) sage: t.comp(e)[:] [y^3  x x + 2] [ 0 0] sage: t.comp(f) 2indices components w.r.t. Coordinate frame (V, (d/du,d/dv)) sage: t.comp(f)[:] [ 0 0] [ 0 u*v]
Since
e
isM
’s default frame, the argumente
can be omitted:sage: e is M.default_frame() True sage: 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, 1u]] sage: h = f.new_frame(a, 'h') sage: t.comp(h) 2indices components w.r.t. Vector frame (V, (h_0,h_1)) sage: t.comp(h)[:] [ 0 u^3*v/(v + 1)] [ 0 u*v]

contract
(*args)¶ Contraction of
self
with another tensor field on one or more indices.INPUT:
pos1
– positions of the indices in the current tensor field involved in the contraction;pos1
must be a sequence of integers, with 0 standing for the first index position, 1 for the second one, etc.; ifpos1
is not provided, a single contraction on the last index position of the tensor field is assumedother
– the tensor field to contract withpos2
– positions of the indices inother
involved in the contraction, with the same conventions as forpos1
; ifpos2
is not provided, a single contraction on the first index position ofother
is assumed
OUTPUT:
 tensor field resulting from the contraction at the positions
pos1
andpos2
of the tensor field withother
EXAMPLES:
Contractions of a type\((1,1)\) tensor field with a type\((2,0)\) one on a 2dimensional nonparallelizable 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, xy), 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, name='a') sage: a[eU,:] = [[1,x], [0,2]] sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: b = M.tensor_field(2,0, name='b') sage: b[eU,:] = [[y,1], [x+y,2]] 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 2dimensional differentiable manifold M
Check 1: components with respect to the manifold’s default frame (
eU
):sage: [[bool(s[i,j] == sum(a[i,k]*b[k,j] for k in M.irange())) ....: for j in M.irange()] for i in M.irange()] [[True, True], [True, True]]
Check 2: components with respect to the frame
eV
:sage: [[bool(s[eV,i,j] == sum(a[eV,i,k]*b[eV,k,j] ....: for k in M.irange())) ....: for j in M.irange()] for i in M.irange()] [[True, True], [True, 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
Indices not involved in the contraction may be replaced by dots:
sage: a['^._k']*b['^k.'] == s True
LaTeX notation may be used:
sage: a['^{i}_{k}']*b['^{kj}'] == s True
Contraction on the last index of
a
and last index ofb
:sage: s = a.contract(b, 1) ; s Tensor field of type (2,0) on the 2dimensional differentiable manifold M sage: a['^i_k']*b['^jk'] == s True
Contraction on the first index of
b
and the last index ofa
:sage: s = b.contract(0,a,1) ; s Tensor field of type (2,0) on the 2dimensional differentiable manifold M sage: 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 2dimensional differentiable manifold M sage: s = a.contract(bV) ; s Tensor field of type (2,0) on the Open subset V of the 2dimensional differentiable manifold M sage: s = aU.contract(bV) ; s Tensor field of type (2,0) on the Open subset W of the 2dimensional differentiable manifold M sage: s0 = a.contract(b) sage: s == s0.restrict(W) True
The contraction can be performed on more than one index:
c
being a type\((2,2)\) tensor, contracting the indices in positions 2 and 3 ofc
with respectively those in positions 0 and 1 ofb
is:sage: c = a*a ; c Tensor field of type (2,2) on the 2dimensional differentiable manifold M sage: s = c.contract(2,3, b, 0,1) ; s # long time Tensor field of type (2,0) on the 2dimensional differentiable manifold M sage: s == c['^.._kl']*b['^kl'] # the same double contraction in index notation; 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 2dimensional differentiable manifold M sage: s.symmetries() symmetry: (1, 2); no antisymmetry
Case of a scalar field result:
sage: a = M.one_form('a') sage: a[eU,:] = [y, 1+x] sage: a.add_comp_by_continuation(eV, W, chart=c_uv) sage: b = M.vector_field('b') sage: b[eU,:] = [x, y^2] 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 d/dx + y^2 d/dy sage: s = a.contract(b) ; s Scalar field on the 2dimensional differentiable manifold M sage: s.display() M > R 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
Case of a vanishing scalar field result:
sage: b = M.vector_field('b') sage: b[eU,:] = [1+x, y] sage: b.add_comp_by_continuation(eV, W, chart=c_uv) sage: s = a.contract(b) ; s Scalar field zero on the 2dimensional differentiable manifold M sage: s.display() zero: M > R on U: (x, y) > 0 on V: (u, v) > 0

copy
()¶ Return an exact copy of
self
.Note
The name and the derived quantities are not copied.
EXAMPLES:
Copy of a type\((1,1)\) tensor field on a 2dimensional 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, xy), ....: 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, 1y]] 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 2dimensional differentiable manifold M sage: s.display(e_xy) (x + y) d/dx*dx + 2 d/dy*dx + (y + 1) d/dy*dy sage: 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 = d/dx*dx + 2 d/dy*dx + (y + 1) d/dy*dy sage: s.display(e_xy) (x + y) d/dx*dx + 2 d/dy*dx + (y + 1) d/dy*dy sage: s == t False

disp
(basis=None, chart=None)¶ Display the tensor field in terms of its expansion with respect to a given vector frame.
The output is either textformatted (console mode) or LaTeXformatted (notebook mode).
INPUT:
basis
– (default:None
) vector frame with respect to which the tensor is expanded; ifNone
, the default frame of the domain of definition of the tensor field is assumedchart
– (default:None
) chart with respect to which the components of the tensor field in the selected frame are expressed; ifNone
, the default chart of the vector frame domain is assumed
EXAMPLES:
Display 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, (d/dx,d/dy)) sage: V = M.open_subset('V') sage: c_uv.<u, v> = V.chart() sage: f = V.default_frame() ; f Coordinate frame (V, (d/du,d/dv)) 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(e) t = (y^3  x) d/dx*dx + (x + 2) d/dx*dy sage: t.display(f) t = u*v d/dv*dv
Since
e
isM
’s default frame, the argumente
can be omitted:sage: e is M.default_frame() True sage: t.display() t = (y^3  x) d/dx*dx + (x + 2) d/dx*dy
Similarly, since
f
isV
’s default frame, the argumentf
can be omitted when considering the restriction oft
toV
:sage: t.restrict(V).display() t = u*v d/dv*dv
Display with respect to a frame in which
t
has not been initialized (automatic use of a changeofframe formula):sage: a = V.automorphism_field() sage: a[:] = [[1+v, u^2], [0, 1u]] sage: h = f.new_frame(a, 'h') sage: t.display(h) t = u^3*v/(v + 1) h_0*h^1  u*v h_1*h^1
A shortcut of
display()
isdisp()
:sage: t.disp(h) t = u^3*v/(v + 1) h_0*h^1  u*v h_1*h^1

display
(basis=None, chart=None)¶ Display the tensor field in terms of its expansion with respect to a given vector frame.
The output is either textformatted (console mode) or LaTeXformatted (notebook mode).
INPUT:
basis
– (default:None
) vector frame with respect to which the tensor is expanded; ifNone
, the default frame of the domain of definition of the tensor field is assumedchart
– (default:None
) chart with respect to which the components of the tensor field in the selected frame are expressed; ifNone
, the default chart of the vector frame domain is assumed
EXAMPLES:
Display 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, (d/dx,d/dy)) sage: V = M.open_subset('V') sage: c_uv.<u, v> = V.chart() sage: f = V.default_frame() ; f Coordinate frame (V, (d/du,d/dv)) 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(e) t = (y^3  x) d/dx*dx + (x + 2) d/dx*dy sage: t.display(f) t = u*v d/dv*dv
Since
e
isM
’s default frame, the argumente
can be omitted:sage: e is M.default_frame() True sage: t.display() t = (y^3  x) d/dx*dx + (x + 2) d/dx*dy
Similarly, since
f
isV
’s default frame, the argumentf
can be omitted when considering the restriction oft
toV
:sage: t.restrict(V).display() t = u*v d/dv*dv
Display with respect to a frame in which
t
has not been initialized (automatic use of a changeofframe formula):sage: a = V.automorphism_field() sage: a[:] = [[1+v, u^2], [0, 1u]] sage: h = f.new_frame(a, 'h') sage: t.display(h) t = u^3*v/(v + 1) h_0*h^1  u*v h_1*h^1
A shortcut of
display()
isdisp()
:sage: t.disp(h) t = u^3*v/(v + 1) h_0*h^1  u*v h_1*h^1

display_comp
(frame=None, chart=None, coordinate_labels=True, only_nonzero=True, only_nonredundant=False)¶ Display the tensor components with respect to a given frame, one per line.
The output is either textformatted (console mode) or LaTeXformatted (notebook mode).
INPUT:
frame
– (default:None
) vector frame with respect to which the tensor field components are defined; ifNone
, then if
chart
is notNone
, the coordinate frame associated tochart
is used  otherwise, the default basis of the vector field module on which the tensor field is defined is used
 if
chart
– (default:None
) chart specifying the coordinate expression of the components; ifNone
, the default chart of the tensor field domain is usedcoordinate_labels
– (default:True
) boolean; ifTrue
, coordinate symbols are used by default (instead of integers) as index labels wheneverframe
is a coordinate frameonly_nonzero
– (default:True
) boolean; ifTrue
, only nonzero components are displayedonly_nonredundant
– (default:False
) boolean; ifTrue
, 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
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
See documentation of
sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.display_comp()
for more options.

domain
()¶ Return the manifold on which
self
is 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() 2dimensional 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 2dimensional differentiable manifold M
 instance of class

down
(metric, pos=None)¶ Compute a metric dual of the tensor field by lowering some index with a given metric.
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 \((k1,l+1)\) whose components are\[(T^\flat)^{a_1\ldots a_{k1}}_{\qquad\ \ b_1 \ldots b_{l+1}} = g_{b_1 i} \, T^{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k1}}_{\qquad\qquad\quad\; b_2 \ldots b_{l+1}},\]\(g_{ab}\) being the components of the metric tensor.
The reverse operation is
TensorField.up()
INPUT:
metric
– metric \(g\), as an instance ofPseudoRiemannianMetric
pos
– (default:None
) position of the index (with the conventionpos=0
for the first index); ifNone
, 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 1form:
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, 1y sage: v = M.vector_field() sage: v[:] = [1,2] sage: w = v.down(g) ; w 1form on the 2dimensional differentiable manifold M sage: 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
The reverse operation:
sage: v1 = w.up(g) ; v1 Vector field on the 2dimensional differentiable manifold M sage: v1 == v True
Lowering the indices of a tensor field of type (2,0):
sage: t = M.tensor_field(2, 0) sage: t[:] = [[1,2], [3,4]] sage: td0 = t.down(g, 0) ; td0 # lowering the first index Tensor field of type (1,1) on the 2dimensional 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 2dimensional 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 2dimensional 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 2dimensional 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 2dimensional 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 2dimensional differentiable manifold M sage: uu0tdd = u0tdd.up(g) ; uu0tdd # the second index is then raised Tensor field of type (2,0) on the 2dimensional 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 2dimensional differentiable manifold M sage: uu1tdd = u1tdd.up(g) ; uu1tdd Tensor field of type (2,0) on the 2dimensional 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 2dimensional 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

lie_der
(vector)¶ Lie derivative of
self
with 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 the 2sphere:
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, xy), ....: 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, 1], [y, 0]] sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: w = M.vector_field(name='w') sage: w[e_xy,:] = [y, x] 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 2dimensional differentiable manifold M sage: lt.display(e_xy) d/dx*dx  x d/dx*dy + (y  1) d/dy*dy sage: lt.display(e_uv) 1/2*u d/du*du + (1/2*u + 1) d/du*dv + (1/2*v + 1) d/dv*du + 1/2*v d/dv*dv
The result is cached:
sage: t.lie_derivative(w) is lt True
An alias is
lie_der
:sage: t.lie_der(w) is t.lie_derivative(w) True
Lie derivative of a vector field:
sage: a = M.vector_field(name='a') sage: a[e_xy,:] = [1x, xy] sage: a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.lie_der(w) Vector field on the 2dimensional differentiable manifold M sage: a.lie_der(w).display(e_xy) x d/dx + (y  1) d/dy sage: a.lie_der(w).display(e_uv) (v  1) d/du + (u + 1) d/dv
The Lie derivative is antisymmetric:
sage: 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*x1, c_uv: 3/2*(u+v)1}) sage: a.lie_der(w)(f) == w(a(f))  a(w(f)) # long time True

lie_derivative
(vector)¶ Lie derivative of
self
with 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 the 2sphere:
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, xy), ....: 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, 1], [y, 0]] sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: w = M.vector_field(name='w') sage: w[e_xy,:] = [y, x] 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 2dimensional differentiable manifold M sage: lt.display(e_xy) d/dx*dx  x d/dx*dy + (y  1) d/dy*dy sage: lt.display(e_uv) 1/2*u d/du*du + (1/2*u + 1) d/du*dv + (1/2*v + 1) d/dv*du + 1/2*v d/dv*dv
The result is cached:
sage: t.lie_derivative(w) is lt True
An alias is
lie_der
:sage: t.lie_der(w) is t.lie_derivative(w) True
Lie derivative of a vector field:
sage: a = M.vector_field(name='a') sage: a[e_xy,:] = [1x, xy] sage: a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.lie_der(w) Vector field on the 2dimensional differentiable manifold M sage: a.lie_der(w).display(e_xy) x d/dx + (y  1) d/dy sage: a.lie_der(w).display(e_uv) (v  1) d/du + (u + 1) d/dv
The Lie derivative is antisymmetric:
sage: 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*x1, c_uv: 3/2*(u+v)1}) sage: a.lie_der(w)(f) == w(a(f))  a(w(f)) # long time True

restrict
(subdomain, dest_map=None)¶ Return the restriction of
self
to 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; ifNone
, the restriction of \(\Phi\) to \(U\) is used, \(\Phi\) being the differentiable map \(S \rightarrow M\) associated with the tensor field
OUTPUT:
TensorField
representing the restriction
EXAMPLES:
Restrictions of a vector field on the 2sphere:
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('v') sage: v.set_comp(eN)[1] = 1 # given the default settings, this can be abriged to v[1] = 1 sage: v.display() v = d/dx sage: vU = v.restrict(U) ; vU Vector field v on the Open subset U of the 2dimensional differentiable manifold S^2 sage: vU.display() v = d/dx sage: vU == eN[1] True sage: vW = v.restrict(W) ; vW Vector field v on the Open subset W of the 2dimensional differentiable manifold S^2 sage: vW.display() v = d/dx sage: vW.display(eS_W, stereoS_W) v = (u^2 + v^2) d/du  2*u*v d/dv sage: vW == eN_W[1] True
At this stage, defining the restriction of
v
to the open subsetV
fully specifiesv
: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) d/du  2*u*v d/dv sage: v.restrict(U).display() v = d/dx sage: v.restrict(V).display() v = (u^2 + v^2) d/du  2*u*v d/dv
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

set_comp
(basis=None)¶ Return the components of
self
in 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 2dimensional 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) 3indices components w.r.t. Coordinate frame (V, (d/du,d/dv)) sage: t.set_comp(e_uv)[1,0,1] = u+v sage: t.display(e_uv) t = (u + v) d/dv*du*dv
Setting the components in a new frame (
e
):sage: e = V.vector_frame('e') sage: t.set_comp(e) 3indices 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
Since the frames
e
ande_uv
are defined on the same domain, the components w.r.t.e_uv
have 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, (d/du,d/dv))

set_name
(name=None, latex_name=None)¶ Set (or change) the text name and LaTeX name of
self
.INPUT:
name
– string (default:None
); name given to the tensor fieldlatex_name
– string (default:None
); LaTeX symbol to denote the tensor field; ifNone
whilename
is provided, the LaTeX symbol is set toname
EXAMPLES:
sage: M = Manifold(2, 'M') sage: t = M.tensor_field(1, 3); t Tensor field of type (1,3) on the 2dimensional differentiable manifold M sage: t.set_name(name='t') sage: t Tensor field t of type (1,3) on the 2dimensional 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 2dimensional differentiable manifold M sage: latex(t) a

set_restriction
(rst)¶ Define a restriction of
self
to some subdomain.INPUT:
rst
–TensorField
of the same type and symmetries as the current tensor fieldself
, defined on a subdomain of the domain ofself
EXAMPLES:
sage: M = Manifold(2, 'M') # the 2dimensional 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) d/dx*dx*dy sage: t.restrict(U) == s True

symmetries
()¶ 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)]

symmetrize
(*pos)¶ Symmetrization over some arguments.
INPUT:
pos
– (default:None
) list of argument positions involved in the symmetrization (with the conventionposition=0
for the first argument); ifNone
, 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 2dimensional nonparallelizable 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, xy), 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, name='a') sage: a[eU,:] = [[1,x], [2,y]] 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 2dimensional 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
See also
For more details and examples, see
sage.tensor.modules.free_module_tensor.FreeModuleTensor.symmetrize()
.

tensor_rank
()¶ 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

tensor_type
()¶ 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)

trace
(pos1=0, pos2=1)¶ Trace (contraction) on two slots of the tensor field.
INPUT:
pos1
– (default: 0) position of the first index for the contraction, with the conventionpos1=0
for the first slotpos2
– (default: 1) position of the second index for the contraction, with the same convention as forpos1
. The variance type ofpos2
must be opposite to that ofpos1
OUTPUT:
 tensor field resulting from the
(pos1, pos2)
contraction
EXAMPLES:
Trace of a type\((1,1)\) tensor field on a 2dimensional nonparallelizable 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, xy), ....: 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 2dimensional differentiable manifold M sage: s.display() M > R 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
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 2dimensional differentiable manifold M sage: a['^i_i'] == s True
Any letter can be used to denote the repeated index:
sage: 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 2dimensional 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 1form on the 2dimensional 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
Use of the index notation:
sage: b['^k_ki'] 1form on the 2dimensional differentiable manifold M sage: 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
The symbol
^
may be omitted:sage: b['k_k.'] == s # long time True
LaTeX notations are allowed:
sage: b['^{k}_{ki}'] == s # long time True
Contraction on first and third slots:
sage: s = b.trace(0,2) ; s 1form on the 2dimensional 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
Use of index notation:
sage: b['^k_.k'] == s # long time True

up
(metric, pos=None)¶ Compute a metric dual of the tensor field by raising some index with a given metric.
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,l1)\) whose components are\[(T^\sharp)^{a_1\ldots a_{k+1}}_{\qquad\ \ b_1 \ldots b_{l1}} = g^{a_{k+1} i} \, T^{a_1\ldots a_k}_{\qquad\ b_1 \ldots b_{pk} \, i \, b_{pk+1}\ldots b_{l1}},\]\(g^{ab}\) being the components of the inverse metric.
The reverse operation is
TensorField.down()
INPUT:
metric
– metric \(g\), as an instance ofPseudoRiemannianMetric
pos
– (default:None
) position of the index (with the conventionpos=0
for the first index); ifNone
, 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 1form 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, 1y sage: w = M.one_form() sage: w[:] = [1, 2] sage: v = w.up(g) ; v Vector field on the 2dimensional differentiable manifold M sage: v.display() ((2*x  1)*y + 1)/(x^2*y^2 + (x + 1)*y  x  1) d/dx  (x*y + 2*x + 2)/(x^2*y^2 + (x + 1)*y  x  1) d/dy 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)]
Using the index notation instead of
up()
:sage: v == ig['^ab']*w['_b'] True
The reverse operation:
sage: w1 = v.down(g) ; w1 1form on the 2dimensional differentiable manifold M sage: w1.display() dx + 2 dy sage: w1 == w True
The reverse operation in index notation:
sage: g['_ab']*v['^b'] == w True
Raising the indices of a tensor field of type (0,2):
sage: t = M.tensor_field(0, 2) sage: t[:] = [[1,2], [3,4]] sage: tu0 = t.up(g, 0) ; tu0 # raising the first index Tensor field of type (1,1) on the 2dimensional 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 2dimensional 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 2dimensional 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 2dimensional 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 2dimensional 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 2dimensional differentiable manifold M sage: dd0tuu = d0tuu.down(g) ; dd0tuu # the second index is then lowered Tensor field of type (0,2) on the 2dimensional 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 2dimensional differentiable manifold M sage: dd1tuu = d1tuu.down(g) ; dd1tuu Tensor field of type (0,2) on the 2dimensional 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 2dimensional 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