Scalar Fields#

Given a topological manifold \(M\) over a topological field \(K\) (in most applications, \(K = \RR\) or \(K = \CC\)), a scalar field on \(M\) is a continuous map

\[f: M \longrightarrow K\]

Scalar fields are implemented by the class ScalarField.

AUTHORS:

  • Eric Gourgoulhon, Michal Bejger (2013-2015): initial version

  • Travis Scrimshaw (2016): review tweaks

  • Marco Mancini (2017): SymPy as an optional symbolic engine, alternative to SR

  • Florentin Jaffredo (2018) : series expansion with respect to a given parameter

  • Michael Jung (2019) : improve restrictions; make display() show all distinct expressions

REFERENCES:

class sage.manifolds.scalarfield.ScalarField(parent, coord_expression=None, chart=None, name=None, latex_name=None)[source]#

Bases: CommutativeAlgebraElement, ModuleElementWithMutability

Scalar field on a topological manifold.

Given a topological manifold \(M\) over a topological field \(K\) (in most applications, \(K = \RR\) or \(K = \CC\)), a scalar field on \(M\) is a continuous map

\[f: M \longrightarrow K.\]

A scalar field on \(M\) is an element of the commutative algebra \(C^0(M)\) (see ScalarFieldAlgebra).

INPUT:

  • parent – the algebra of scalar fields containing the scalar field (must be an instance of class ScalarFieldAlgebra)

  • coord_expression – (default: None) coordinate expression(s) of the scalar field; this can be either

    • a dictionary of coordinate expressions in various charts on the domain, with the charts as keys;

    • a single coordinate expression; if the argument chart is 'all', this expression is set to all the charts defined on the open set; otherwise, the expression is set in the specific chart provided by the argument chart

  • chart – (default: None) chart defining the coordinates used in coord_expression when the latter is a single coordinate expression; if none is provided (default), the default chart of the open set is assumed. If chart=='all', coord_expression is assumed to be independent of the chart (constant scalar field).

  • name – (default: None) string; name (symbol) given to the scalar field

  • latex_name – (default: None) string; LaTeX symbol to denote the scalar field; if none is provided, the LaTeX symbol is set to name

If coord_expression is None or incomplete, coordinate expressions can be added after the creation of the object, by means of the methods add_expr(), add_expr_by_continuation() and set_expr().

EXAMPLES:

A scalar field on the 2-sphere:

sage: M = Manifold(2, 'M', structure='topological') # 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: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), c_uv: (u^2+v^2)/(1+u^2+v^2)},
....:                    name='f') ; f
Scalar field f on the 2-dimensional topological manifold M
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological') # 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()
>>> f = M.scalar_field({c_xy: Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), c_uv: (u**Integer(2)+v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2))},
...                    name='f') ; f
Scalar field f on the 2-dimensional topological manifold M
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)

For scalar fields defined by a single coordinate expression, the latter can be passed instead of the dictionary over the charts:

sage: g = U.scalar_field(x*y, chart=c_xy, name='g') ; g
Scalar field g on the Open subset U of the 2-dimensional topological
 manifold M
>>> from sage.all import *
>>> g = U.scalar_field(x*y, chart=c_xy, name='g') ; g
Scalar field g on the Open subset U of the 2-dimensional topological
 manifold M

The above is indeed equivalent to:

sage: g = U.scalar_field({c_xy: x*y}, name='g') ; g
Scalar field g on the Open subset U of the 2-dimensional topological
 manifold M
>>> from sage.all import *
>>> g = U.scalar_field({c_xy: x*y}, name='g') ; g
Scalar field g on the Open subset U of the 2-dimensional topological
 manifold M

Since c_xy is the default chart of U, the argument chart can be skipped:

sage: g = U.scalar_field(x*y, name='g') ; g
Scalar field g on the Open subset U of the 2-dimensional topological
 manifold M
>>> from sage.all import *
>>> g = U.scalar_field(x*y, name='g') ; g
Scalar field g on the Open subset U of the 2-dimensional topological
 manifold M

The scalar field \(g\) is defined on \(U\) and has an expression in terms of the coordinates \((u,v)\) on \(W=U\cap V\):

sage: g.display()
g: U → ℝ
   (x, y) ↦ x*y
on W: (u, v) ↦ u*v/(u^4 + 2*u^2*v^2 + v^4)
>>> from sage.all import *
>>> g.display()
g: U → ℝ
   (x, y) ↦ x*y
on W: (u, v) ↦ u*v/(u^4 + 2*u^2*v^2 + v^4)

Scalar fields on \(M\) can also be declared with a single chart:

sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f') ; f
Scalar field f on the 2-dimensional topological manifold M
>>> from sage.all import *
>>> f = M.scalar_field(Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), chart=c_xy, name='f') ; f
Scalar field f on the 2-dimensional topological manifold M

Their definition must then be completed by providing the expressions on other charts, via the method add_expr(), to get a global cover of the manifold:

sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> f.add_expr((u**Integer(2)+v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2)), chart=c_uv)
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)

We can even first declare the scalar field without any coordinate expression and provide them subsequently:

sage: f = M.scalar_field(name='f')
sage: f.add_expr(1/(1+x^2+y^2), chart=c_xy)
sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> f = M.scalar_field(name='f')
>>> f.add_expr(Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), chart=c_xy)
>>> f.add_expr((u**Integer(2)+v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2)), chart=c_uv)
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)

We may also use the method add_expr_by_continuation() to complete the coordinate definition using the analytic continuation from domains in which charts overlap:

sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f') ; f
Scalar field f on the 2-dimensional topological manifold M
sage: f.add_expr_by_continuation(c_uv, U.intersection(V))
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> f = M.scalar_field(Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), chart=c_xy, name='f') ; f
Scalar field f on the 2-dimensional topological manifold M
>>> f.add_expr_by_continuation(c_uv, U.intersection(V))
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)

A scalar field can also be defined by some unspecified function of the coordinates:

sage: h = U.scalar_field(function('H')(x, y), name='h') ; h
Scalar field h on the Open subset U of the 2-dimensional topological
 manifold M
sage: h.display()
h: U → ℝ
   (x, y) ↦ H(x, y)
on W: (u, v) ↦ H(u/(u^2 + v^2), v/(u^2 + v^2))
>>> from sage.all import *
>>> h = U.scalar_field(function('H')(x, y), name='h') ; h
Scalar field h on the Open subset U of the 2-dimensional topological
 manifold M
>>> h.display()
h: U → ℝ
   (x, y) ↦ H(x, y)
on W: (u, v) ↦ H(u/(u^2 + v^2), v/(u^2 + v^2))

We may use the argument latex_name to specify the LaTeX symbol denoting the scalar field if the latter is different from name:

sage: latex(f)
f
sage: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), c_uv: (u^2+v^2)/(1+u^2+v^2)},
....:                    name='f', latex_name=r'\mathcal{F}')
sage: latex(f)
\mathcal{F}
>>> from sage.all import *
>>> latex(f)
f
>>> f = M.scalar_field({c_xy: Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), c_uv: (u**Integer(2)+v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2))},
...                    name='f', latex_name=r'\mathcal{F}')
>>> latex(f)
\mathcal{F}

The coordinate expression in a given chart is obtained via the method expr(), which returns a symbolic expression:

sage: f.expr(c_uv)
(u^2 + v^2)/(u^2 + v^2 + 1)
sage: type(f.expr(c_uv))
<class 'sage.symbolic.expression.Expression'>
>>> from sage.all import *
>>> f.expr(c_uv)
(u^2 + v^2)/(u^2 + v^2 + 1)
>>> type(f.expr(c_uv))
<class 'sage.symbolic.expression.Expression'>

The method coord_function() returns instead a function of the chart coordinates, i.e. an instance of ChartFunction:

sage: f.coord_function(c_uv)
(u^2 + v^2)/(u^2 + v^2 + 1)
sage: type(f.coord_function(c_uv))
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
sage: f.coord_function(c_uv).display()
(u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> f.coord_function(c_uv)
(u^2 + v^2)/(u^2 + v^2 + 1)
>>> type(f.coord_function(c_uv))
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
>>> f.coord_function(c_uv).display()
(u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)

The value returned by the method expr() is actually the coordinate expression of the chart function:

sage: f.expr(c_uv) is f.coord_function(c_uv).expr()
True
>>> from sage.all import *
>>> f.expr(c_uv) is f.coord_function(c_uv).expr()
True

A constant scalar field is declared by setting the argument chart to 'all':

sage: c = M.scalar_field(2, chart='all', name='c') ; c
Scalar field c on the 2-dimensional topological manifold M
sage: c.display()
c: M → ℝ
on U: (x, y) ↦ 2
on V: (u, v) ↦ 2
>>> from sage.all import *
>>> c = M.scalar_field(Integer(2), chart='all', name='c') ; c
Scalar field c on the 2-dimensional topological manifold M
>>> c.display()
c: M → ℝ
on U: (x, y) ↦ 2
on V: (u, v) ↦ 2

A shortcut is to use the method constant_scalar_field():

sage: c == M.constant_scalar_field(2)
True
>>> from sage.all import *
>>> c == M.constant_scalar_field(Integer(2))
True

The constant value can be some unspecified parameter:

sage: var('a')
a
sage: c = M.constant_scalar_field(a, name='c') ; c
Scalar field c on the 2-dimensional topological manifold M
sage: c.display()
c: M → ℝ
on U: (x, y) ↦ a
on V: (u, v) ↦ a
>>> from sage.all import *
>>> var('a')
a
>>> c = M.constant_scalar_field(a, name='c') ; c
Scalar field c on the 2-dimensional topological manifold M
>>> c.display()
c: M → ℝ
on U: (x, y) ↦ a
on V: (u, v) ↦ a

A special case of constant field is the zero scalar field:

sage: zer = M.constant_scalar_field(0) ; zer
Scalar field zero on the 2-dimensional topological manifold M
sage: zer.display()
zero: M → ℝ
on U: (x, y) ↦ 0
on V: (u, v) ↦ 0
>>> from sage.all import *
>>> zer = M.constant_scalar_field(Integer(0)) ; zer
Scalar field zero on the 2-dimensional topological manifold M
>>> zer.display()
zero: M → ℝ
on U: (x, y) ↦ 0
on V: (u, v) ↦ 0

It can be obtained directly by means of the function zero_scalar_field():

sage: zer is M.zero_scalar_field()
True
>>> from sage.all import *
>>> zer is M.zero_scalar_field()
True

A third way is to get it as the zero element of the algebra \(C^0(M)\) of scalar fields on \(M\) (see below):

sage: zer is M.scalar_field_algebra().zero()
True
>>> from sage.all import *
>>> zer is M.scalar_field_algebra().zero()
True

The constant scalar fields zero and one are immutable, and therefore their expressions cannot be changed:

sage: zer.is_immutable()
True
sage: zer.set_expr(x)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
sage: one = M.one_scalar_field()
sage: one.is_immutable()
True
sage: one.set_expr(x)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
>>> from sage.all import *
>>> zer.is_immutable()
True
>>> zer.set_expr(x)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
>>> one = M.one_scalar_field()
>>> one.is_immutable()
True
>>> one.set_expr(x)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed

Other scalar fields can be declared immutable, too:

sage: c.is_immutable()
False
sage: c.set_immutable()
sage: c.is_immutable()
True
sage: c.set_expr(y^2)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
sage: c.set_name('b')
Traceback (most recent call last):
...
ValueError: the name of an immutable element cannot be changed
>>> from sage.all import *
>>> c.is_immutable()
False
>>> c.set_immutable()
>>> c.is_immutable()
True
>>> c.set_expr(y**Integer(2))
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
>>> c.set_name('b')
Traceback (most recent call last):
...
ValueError: the name of an immutable element cannot be changed

Immutable elements are hashable and can therefore be used as keys for dictionaries:

sage: {c: 1}[c]
1
>>> from sage.all import *
>>> {c: Integer(1)}[c]
1

By definition, a scalar field acts on the manifold’s points, sending them to elements of the manifold’s base field (real numbers in the present case):

sage: N = M.point((0,0), chart=c_uv) # the North pole
sage: S = M.point((0,0), chart=c_xy) # the South pole
sage: E = M.point((1,0), chart=c_xy) # a point at the equator
sage: f(N)
0
sage: f(S)
1
sage: f(E)
1/2
sage: h(E)
H(1, 0)
sage: c(E)
a
sage: zer(E)
0
>>> from sage.all import *
>>> N = M.point((Integer(0),Integer(0)), chart=c_uv) # the North pole
>>> S = M.point((Integer(0),Integer(0)), chart=c_xy) # the South pole
>>> E = M.point((Integer(1),Integer(0)), chart=c_xy) # a point at the equator
>>> f(N)
0
>>> f(S)
1
>>> f(E)
1/2
>>> h(E)
H(1, 0)
>>> c(E)
a
>>> zer(E)
0

A scalar field can be compared to another scalar field:

sage: f == g
False
>>> from sage.all import *
>>> f == g
False

…to a symbolic expression:

sage: f == x*y
False
sage: g == x*y
True
sage: c == a
True
>>> from sage.all import *
>>> f == x*y
False
>>> g == x*y
True
>>> c == a
True

…to a number:

sage: f == 2
False
sage: zer == 0
True
>>> from sage.all import *
>>> f == Integer(2)
False
>>> zer == Integer(0)
True

…to anything else:

sage: f == M
False
>>> from sage.all import *
>>> f == M
False

Standard mathematical functions are implemented:

sage: sqrt(f)
Scalar field sqrt(f) on the 2-dimensional topological manifold M
sage: sqrt(f).display()
sqrt(f): M → ℝ
on U: (x, y) ↦ 1/sqrt(x^2 + y^2 + 1)
on V: (u, v) ↦ sqrt(u^2 + v^2)/sqrt(u^2 + v^2 + 1)
>>> from sage.all import *
>>> sqrt(f)
Scalar field sqrt(f) on the 2-dimensional topological manifold M
>>> sqrt(f).display()
sqrt(f): M → ℝ
on U: (x, y) ↦ 1/sqrt(x^2 + y^2 + 1)
on V: (u, v) ↦ sqrt(u^2 + v^2)/sqrt(u^2 + v^2 + 1)
sage: tan(f)
Scalar field tan(f) on the 2-dimensional topological manifold M
sage: tan(f).display()
tan(f): M → ℝ
on U: (x, y) ↦ sin(1/(x^2 + y^2 + 1))/cos(1/(x^2 + y^2 + 1))
on V: (u, v) ↦ sin((u^2 + v^2)/(u^2 + v^2 + 1))/cos((u^2 + v^2)/(u^2 + v^2 + 1))
>>> from sage.all import *
>>> tan(f)
Scalar field tan(f) on the 2-dimensional topological manifold M
>>> tan(f).display()
tan(f): M → ℝ
on U: (x, y) ↦ sin(1/(x^2 + y^2 + 1))/cos(1/(x^2 + y^2 + 1))
on V: (u, v) ↦ sin((u^2 + v^2)/(u^2 + v^2 + 1))/cos((u^2 + v^2)/(u^2 + v^2 + 1))

Arithmetics of scalar fields

Scalar fields on \(M\) (resp. \(U\)) belong to the algebra \(C^0(M)\) (resp. \(C^0(U)\)):

sage: f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold M
sage: f.parent() is M.scalar_field_algebra()
True
sage: g.parent()
Algebra of scalar fields on the Open subset U of the 2-dimensional
 topological manifold M
sage: g.parent() is U.scalar_field_algebra()
True
>>> from sage.all import *
>>> f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold M
>>> f.parent() is M.scalar_field_algebra()
True
>>> g.parent()
Algebra of scalar fields on the Open subset U of the 2-dimensional
 topological manifold M
>>> g.parent() is U.scalar_field_algebra()
True

Consequently, scalar fields can be added:

sage: s = f + c ; s
Scalar field f+c on the 2-dimensional topological manifold M
sage: s.display()
f+c: M → ℝ
on U: (x, y) ↦ (a*x^2 + a*y^2 + a + 1)/(x^2 + y^2 + 1)
on V: (u, v) ↦ ((a + 1)*u^2 + (a + 1)*v^2 + a)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> s = f + c ; s
Scalar field f+c on the 2-dimensional topological manifold M
>>> s.display()
f+c: M → ℝ
on U: (x, y) ↦ (a*x^2 + a*y^2 + a + 1)/(x^2 + y^2 + 1)
on V: (u, v) ↦ ((a + 1)*u^2 + (a + 1)*v^2 + a)/(u^2 + v^2 + 1)

and subtracted:

sage: s = f - c ; s
Scalar field f-c on the 2-dimensional topological manifold M
sage: s.display()
f-c: M → ℝ
on U: (x, y) ↦ -(a*x^2 + a*y^2 + a - 1)/(x^2 + y^2 + 1)
on V: (u, v) ↦ -((a - 1)*u^2 + (a - 1)*v^2 + a)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> s = f - c ; s
Scalar field f-c on the 2-dimensional topological manifold M
>>> s.display()
f-c: M → ℝ
on U: (x, y) ↦ -(a*x^2 + a*y^2 + a - 1)/(x^2 + y^2 + 1)
on V: (u, v) ↦ -((a - 1)*u^2 + (a - 1)*v^2 + a)/(u^2 + v^2 + 1)

Some tests:

sage: f + zer == f
True
sage: f - f == zer
True
sage: f + (-f) == zer
True
sage: (f+c)-f == c
True
sage: (f-c)+c == f
True
>>> from sage.all import *
>>> f + zer == f
True
>>> f - f == zer
True
>>> f + (-f) == zer
True
>>> (f+c)-f == c
True
>>> (f-c)+c == f
True

We may add a number (interpreted as a constant scalar field) to a scalar field:

sage: s = f + 1 ; s
Scalar field f+1 on the 2-dimensional topological manifold M
sage: s.display()
f+1: M → ℝ
on U: (x, y) ↦ (x^2 + y^2 + 2)/(x^2 + y^2 + 1)
on V: (u, v) ↦ (2*u^2 + 2*v^2 + 1)/(u^2 + v^2 + 1)
sage: (f+1)-1 == f
True
>>> from sage.all import *
>>> s = f + Integer(1) ; s
Scalar field f+1 on the 2-dimensional topological manifold M
>>> s.display()
f+1: M → ℝ
on U: (x, y) ↦ (x^2 + y^2 + 2)/(x^2 + y^2 + 1)
on V: (u, v) ↦ (2*u^2 + 2*v^2 + 1)/(u^2 + v^2 + 1)
>>> (f+Integer(1))-Integer(1) == f
True

The number can represented by a symbolic variable:

sage: s = a + f ; s
Scalar field on the 2-dimensional topological manifold M
sage: s == c + f
True
>>> from sage.all import *
>>> s = a + f ; s
Scalar field on the 2-dimensional topological manifold M
>>> s == c + f
True

However if the symbolic variable is a chart coordinate, the addition is performed only on the chart domain:

sage: s = f + x; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ (x^3 + x*y^2 + x + 1)/(x^2 + y^2 + 1)
on W: (u, v) ↦ (u^4 + v^4 + u^3 + (2*u^2 + u)*v^2 + u)/(u^4 + v^4 + (2*u^2 + 1)*v^2 + u^2)
sage: s = f + u; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on W: (x, y) ↦ (x^3 + (x + 1)*y^2 + x^2 + x)/(x^4 + y^4 + (2*x^2 + 1)*y^2 + x^2)
on V: (u, v) ↦ (u^3 + (u + 1)*v^2 + u^2 + u)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> s = f + x; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ (x^3 + x*y^2 + x + 1)/(x^2 + y^2 + 1)
on W: (u, v) ↦ (u^4 + v^4 + u^3 + (2*u^2 + u)*v^2 + u)/(u^4 + v^4 + (2*u^2 + 1)*v^2 + u^2)
>>> s = f + u; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on W: (x, y) ↦ (x^3 + (x + 1)*y^2 + x^2 + x)/(x^4 + y^4 + (2*x^2 + 1)*y^2 + x^2)
on V: (u, v) ↦ (u^3 + (u + 1)*v^2 + u^2 + u)/(u^2 + v^2 + 1)

The addition of two scalar fields with different domains is possible if the domain of one of them is a subset of the domain of the other; the domain of the result is then this subset:

sage: f.domain()
2-dimensional topological manifold M
sage: g.domain()
Open subset U of the 2-dimensional topological manifold M
sage: s = f + g ; s
Scalar field f+g on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.domain()
Open subset U of the 2-dimensional topological manifold M
sage: s.display()
f+g: U → ℝ
   (x, y) ↦ (x*y^3 + (x^3 + x)*y + 1)/(x^2 + y^2 + 1)
on W: (u, v) ↦ (u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6 + u*v^3
 + (u^3 + u)*v)/(u^6 + v^6 + (3*u^2 + 1)*v^4 + u^4 + (3*u^4 + 2*u^2)*v^2)
>>> from sage.all import *
>>> f.domain()
2-dimensional topological manifold M
>>> g.domain()
Open subset U of the 2-dimensional topological manifold M
>>> s = f + g ; s
Scalar field f+g on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.domain()
Open subset U of the 2-dimensional topological manifold M
>>> s.display()
f+g: U → ℝ
   (x, y) ↦ (x*y^3 + (x^3 + x)*y + 1)/(x^2 + y^2 + 1)
on W: (u, v) ↦ (u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6 + u*v^3
 + (u^3 + u)*v)/(u^6 + v^6 + (3*u^2 + 1)*v^4 + u^4 + (3*u^4 + 2*u^2)*v^2)

The operation actually performed is \(f|_U + g\):

sage: s == f.restrict(U) + g
True
>>> from sage.all import *
>>> s == f.restrict(U) + g
True

In Sage framework, the addition of \(f\) and \(g\) is permitted because there is a coercion of the parent of \(f\), namely \(C^0(M)\), to the parent of \(g\), namely \(C^0(U)\) (see ScalarFieldAlgebra):

sage: CM = M.scalar_field_algebra()
sage: CU = U.scalar_field_algebra()
sage: CU.has_coerce_map_from(CM)
True
>>> from sage.all import *
>>> CM = M.scalar_field_algebra()
>>> CU = U.scalar_field_algebra()
>>> CU.has_coerce_map_from(CM)
True

The coercion map is nothing but the restriction to domain \(U\):

sage: CU.coerce(f) == f.restrict(U)
True
>>> from sage.all import *
>>> CU.coerce(f) == f.restrict(U)
True

Since the algebra \(C^0(M)\) is a vector space over \(\RR\), scalar fields can be multiplied by a number, either an explicit one:

sage: s = 2*f ; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ 2/(x^2 + y^2 + 1)
on V: (u, v) ↦ 2*(u^2 + v^2)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> s = Integer(2)*f ; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ 2/(x^2 + y^2 + 1)
on V: (u, v) ↦ 2*(u^2 + v^2)/(u^2 + v^2 + 1)

or a symbolic one:

sage: s = a*f ; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ a/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)*a/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> s = a*f ; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ a/(x^2 + y^2 + 1)
on V: (u, v) ↦ (u^2 + v^2)*a/(u^2 + v^2 + 1)

However, if the symbolic variable is a chart coordinate, the multiplication is performed only in the corresponding chart:

sage: s = x*f; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ x/(x^2 + y^2 + 1)
on W: (u, v) ↦ u/(u^2 + v^2 + 1)
sage: s = u*f; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on W: (x, y) ↦ x/(x^4 + y^4 + (2*x^2 + 1)*y^2 + x^2)
on V: (u, v) ↦ (u^2 + v^2)*u/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> s = x*f; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ x/(x^2 + y^2 + 1)
on W: (u, v) ↦ u/(u^2 + v^2 + 1)
>>> s = u*f; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on W: (x, y) ↦ x/(x^4 + y^4 + (2*x^2 + 1)*y^2 + x^2)
on V: (u, v) ↦ (u^2 + v^2)*u/(u^2 + v^2 + 1)

Some tests:

sage: 0*f == 0
True
sage: 0*f == zer
True
sage: 1*f == f
True
sage: (-2)*f == - f - f
True
>>> from sage.all import *
>>> Integer(0)*f == Integer(0)
True
>>> Integer(0)*f == zer
True
>>> Integer(1)*f == f
True
>>> (-Integer(2))*f == - f - f
True

The ring multiplication of the algebras \(C^0(M)\) and \(C^0(U)\) is the pointwise multiplication of functions:

sage: s = f*f ; s
Scalar field f*f on the 2-dimensional topological manifold M
sage: s.display()
f*f: M → ℝ
on U: (x, y) ↦ 1/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1)
on V: (u, v) ↦ (u^4 + 2*u^2*v^2 + v^4)/(u^4 + v^4 + 2*(u^2 + 1)*v^2
 + 2*u^2 + 1)
sage: s = g*h ; s
Scalar field g*h on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
g*h: U → ℝ
   (x, y) ↦ x*y*H(x, y)
on W: (u, v) ↦ u*v*H(u/(u^2 + v^2), v/(u^2 + v^2))/(u^4 + 2*u^2*v^2 + v^4)
>>> from sage.all import *
>>> s = f*f ; s
Scalar field f*f on the 2-dimensional topological manifold M
>>> s.display()
f*f: M → ℝ
on U: (x, y) ↦ 1/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1)
on V: (u, v) ↦ (u^4 + 2*u^2*v^2 + v^4)/(u^4 + v^4 + 2*(u^2 + 1)*v^2
 + 2*u^2 + 1)
>>> s = g*h ; s
Scalar field g*h on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
g*h: U → ℝ
   (x, y) ↦ x*y*H(x, y)
on W: (u, v) ↦ u*v*H(u/(u^2 + v^2), v/(u^2 + v^2))/(u^4 + 2*u^2*v^2 + v^4)

Thanks to the coercion \(C^0(M) \to C^0(U)\) mentioned above, it is possible to multiply a scalar field defined on \(M\) by a scalar field defined on \(U\), the result being a scalar field defined on \(U\):

sage: f.domain(), g.domain()
(2-dimensional topological manifold M,
 Open subset U of the 2-dimensional topological manifold M)
sage: s = f*g ; s
Scalar field f*g on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
f*g: U → ℝ
   (x, y) ↦ x*y/(x^2 + y^2 + 1)
on W: (u, v) ↦ u*v/(u^4 + v^4 + (2*u^2 + 1)*v^2 + u^2)
sage: s == f.restrict(U)*g
True
>>> from sage.all import *
>>> f.domain(), g.domain()
(2-dimensional topological manifold M,
 Open subset U of the 2-dimensional topological manifold M)
>>> s = f*g ; s
Scalar field f*g on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
f*g: U → ℝ
   (x, y) ↦ x*y/(x^2 + y^2 + 1)
on W: (u, v) ↦ u*v/(u^4 + v^4 + (2*u^2 + 1)*v^2 + u^2)
>>> s == f.restrict(U)*g
True

Scalar fields can be divided (pointwise division):

sage: s = f/c ; s
Scalar field f/c on the 2-dimensional topological manifold M
sage: s.display()
f/c: M → ℝ
on U: (x, y) ↦ 1/(a*x^2 + a*y^2 + a)
on V: (u, v) ↦ (u^2 + v^2)/(a*u^2 + a*v^2 + a)
sage: s = g/h ; s
Scalar field g/h on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
g/h: U → ℝ
   (x, y) ↦ x*y/H(x, y)
on W: (u, v) ↦ u*v/((u^4 + 2*u^2*v^2 + v^4)*H(u/(u^2 + v^2), v/(u^2 + v^2)))
sage: s = f/g ; s
Scalar field f/g on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
f/g: U → ℝ
   (x, y) ↦ 1/(x*y^3 + (x^3 + x)*y)
on W: (u, v) ↦ (u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6)/(u*v^3 + (u^3 + u)*v)
sage: s == f.restrict(U)/g
True
>>> from sage.all import *
>>> s = f/c ; s
Scalar field f/c on the 2-dimensional topological manifold M
>>> s.display()
f/c: M → ℝ
on U: (x, y) ↦ 1/(a*x^2 + a*y^2 + a)
on V: (u, v) ↦ (u^2 + v^2)/(a*u^2 + a*v^2 + a)
>>> s = g/h ; s
Scalar field g/h on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
g/h: U → ℝ
   (x, y) ↦ x*y/H(x, y)
on W: (u, v) ↦ u*v/((u^4 + 2*u^2*v^2 + v^4)*H(u/(u^2 + v^2), v/(u^2 + v^2)))
>>> s = f/g ; s
Scalar field f/g on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
f/g: U → ℝ
   (x, y) ↦ 1/(x*y^3 + (x^3 + x)*y)
on W: (u, v) ↦ (u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6)/(u*v^3 + (u^3 + u)*v)
>>> s == f.restrict(U)/g
True

For scalar fields defined on a single chart domain, we may perform some arithmetics with symbolic expressions involving the chart coordinates:

sage: s = g + x^2 - y ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
U → ℝ
(x, y) ↦ x^2 + (x - 1)*y
on W: (u, v) ↦ -(v^3 - u^2 + (u^2 - u)*v)/(u^4 + 2*u^2*v^2 + v^4)
>>> from sage.all import *
>>> s = g + x**Integer(2) - y ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
U → ℝ
(x, y) ↦ x^2 + (x - 1)*y
on W: (u, v) ↦ -(v^3 - u^2 + (u^2 - u)*v)/(u^4 + 2*u^2*v^2 + v^4)
sage: s = g*x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
U → ℝ
(x, y) ↦ x^2*y
on W: (u, v) ↦ u^2*v/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6)
>>> from sage.all import *
>>> s = g*x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
U → ℝ
(x, y) ↦ x^2*y
on W: (u, v) ↦ u^2*v/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6)
sage: s = g/x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
U → ℝ
(x, y) ↦ y
on W: (u, v) ↦ v/(u^2 + v^2)
sage: s = x/g ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
U → ℝ
(x, y) ↦ 1/y
on W: (u, v) ↦ (u^2 + v^2)/v
>>> from sage.all import *
>>> s = g/x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
U → ℝ
(x, y) ↦ y
on W: (u, v) ↦ v/(u^2 + v^2)
>>> s = x/g ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
U → ℝ
(x, y) ↦ 1/y
on W: (u, v) ↦ (u^2 + v^2)/v

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 \(f\) as above:

sage: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), c_uv: (u^2+v^2)/(1+u^2+v^2)},
....:                    name='f') ; f
Scalar field f on the 2-dimensional topological manifold M
sage: f.display()  # notice the SymPy display of exponents
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
sage: type(f.coord_function(c_xy).expr())
<class 'sympy.core.power.Pow'>
>>> 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))/(Integer(1)+u**Integer(2)+v**Integer(2))},
...                    name='f') ; f
Scalar field f on the 2-dimensional topological manifold M
>>> f.display()  # notice the SymPy display of exponents
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
>>> type(f.coord_function(c_xy).expr())
<class 'sympy.core.power.Pow'>

The scalar field \(g\) defined on \(U\):

sage: g = U.scalar_field({c_xy: x*y}, name='g')
sage: g.display() # again notice the SymPy display of exponents
g: U → ℝ
   (x, y) ↦ x*y
on W: (u, v) ↦ u*v/(u**4 + 2*u**2*v**2 + v**4)
>>> from sage.all import *
>>> g = U.scalar_field({c_xy: x*y}, name='g')
>>> g.display() # again notice the SymPy display of exponents
g: U → ℝ
   (x, y) ↦ x*y
on W: (u, v) ↦ u*v/(u**4 + 2*u**2*v**2 + v**4)

Definition on a single chart and subsequent completion:

sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f')
sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> f = M.scalar_field(Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), chart=c_xy, name='f')
>>> f.add_expr((u**Integer(2)+v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2)), chart=c_uv)
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)

Definition without any coordinate expression and subsequent completion:

sage: f = M.scalar_field(name='f')
sage: f.add_expr(1/(1+x^2+y^2), chart=c_xy)
sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> f = M.scalar_field(name='f')
>>> f.add_expr(Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), chart=c_xy)
>>> f.add_expr((u**Integer(2)+v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2)), chart=c_uv)
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)

Use of add_expr_by_continuation():

sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f')
sage: f.add_expr_by_continuation(c_uv, U.intersection(V))
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> f = M.scalar_field(Integer(1)/(Integer(1)+x**Integer(2)+y**Integer(2)), chart=c_xy, name='f')
>>> f.add_expr_by_continuation(c_uv, U.intersection(V))
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)

A scalar field defined by some unspecified function of the coordinates:

sage: h = U.scalar_field(function('H')(x, y), name='h') ; h
Scalar field h on the Open subset U of the 2-dimensional topological
 manifold M
sage: h.display()
h: U → ℝ
   (x, y) ↦ H(x, y)
on W: (u, v) ↦ H(u/(u**2 + v**2), v/(u**2 + v**2))
>>> from sage.all import *
>>> h = U.scalar_field(function('H')(x, y), name='h') ; h
Scalar field h on the Open subset U of the 2-dimensional topological
 manifold M
>>> h.display()
h: U → ℝ
   (x, y) ↦ H(x, y)
on W: (u, v) ↦ H(u/(u**2 + v**2), v/(u**2 + v**2))

The coordinate expression in a given chart is obtained via the method expr(), which in the present context, returns a SymPy object:

sage: f.expr(c_uv)
(u**2 + v**2)/(u**2 + v**2 + 1)
sage: type(f.expr(c_uv))
<class 'sympy.core.mul.Mul'>
>>> from sage.all import *
>>> f.expr(c_uv)
(u**2 + v**2)/(u**2 + v**2 + 1)
>>> type(f.expr(c_uv))
<class 'sympy.core.mul.Mul'>

The method coord_function() returns instead a function of the chart coordinates, i.e. an instance of ChartFunction:

sage: f.coord_function(c_uv)
(u**2 + v**2)/(u**2 + v**2 + 1)
sage: type(f.coord_function(c_uv))
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
sage: f.coord_function(c_uv).display()
(u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> f.coord_function(c_uv)
(u**2 + v**2)/(u**2 + v**2 + 1)
>>> type(f.coord_function(c_uv))
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
>>> f.coord_function(c_uv).display()
(u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)

The value returned by the method expr() is actually the coordinate expression of the chart function:

sage: f.expr(c_uv) is f.coord_function(c_uv).expr()
True
>>> from sage.all import *
>>> f.expr(c_uv) is f.coord_function(c_uv).expr()
True

We may ask for the SR representation of the coordinate function:

sage: f.coord_function(c_uv).expr('SR')
(u^2 + v^2)/(u^2 + v^2 + 1)
>>> from sage.all import *
>>> f.coord_function(c_uv).expr('SR')
(u^2 + v^2)/(u^2 + v^2 + 1)

A constant scalar field with SymPy representation:

sage: c = M.constant_scalar_field(2, name='c')
sage: c.display()
c: M → ℝ
on U: (x, y) ↦ 2
on V: (u, v) ↦ 2
sage: type(c.expr(c_xy))
<class 'sympy.core.numbers.Integer'>
>>> from sage.all import *
>>> c = M.constant_scalar_field(Integer(2), name='c')
>>> c.display()
c: M → ℝ
on U: (x, y) ↦ 2
on V: (u, v) ↦ 2
>>> type(c.expr(c_xy))
<class 'sympy.core.numbers.Integer'>

The constant value can be some unspecified parameter:

sage: var('a')
a
sage: c = M.constant_scalar_field(a, name='c')
sage: c.display()
c: M → ℝ
on U: (x, y) ↦ a
on V: (u, v) ↦ a
sage: type(c.expr(c_xy))
<class 'sympy.core.symbol.Symbol'>
>>> from sage.all import *
>>> var('a')
a
>>> c = M.constant_scalar_field(a, name='c')
>>> c.display()
c: M → ℝ
on U: (x, y) ↦ a
on V: (u, v) ↦ a
>>> type(c.expr(c_xy))
<class 'sympy.core.symbol.Symbol'>

The zero scalar field:

sage: zer = M.constant_scalar_field(0) ; zer
Scalar field zero on the 2-dimensional topological manifold M
sage: zer.display()
zero: M → ℝ
on U: (x, y) ↦ 0
on V: (u, v) ↦ 0
sage: type(zer.expr(c_xy))
<class 'sympy.core.numbers.Zero'>
sage: zer is M.zero_scalar_field()
True
>>> from sage.all import *
>>> zer = M.constant_scalar_field(Integer(0)) ; zer
Scalar field zero on the 2-dimensional topological manifold M
>>> zer.display()
zero: M → ℝ
on U: (x, y) ↦ 0
on V: (u, v) ↦ 0
>>> type(zer.expr(c_xy))
<class 'sympy.core.numbers.Zero'>
>>> zer is M.zero_scalar_field()
True

Action of scalar fields on manifold’s points:

sage: N = M.point((0,0), chart=c_uv) # the North pole
sage: S = M.point((0,0), chart=c_xy) # the South pole
sage: E = M.point((1,0), chart=c_xy) # a point at the equator
sage: f(N)
0
sage: f(S)
1
sage: f(E)
1/2
sage: h(E)
H(1, 0)
sage: c(E)
a
sage: zer(E)
0
>>> from sage.all import *
>>> N = M.point((Integer(0),Integer(0)), chart=c_uv) # the North pole
>>> S = M.point((Integer(0),Integer(0)), chart=c_xy) # the South pole
>>> E = M.point((Integer(1),Integer(0)), chart=c_xy) # a point at the equator
>>> f(N)
0
>>> f(S)
1
>>> f(E)
1/2
>>> h(E)
H(1, 0)
>>> c(E)
a
>>> zer(E)
0

A scalar field can be compared to another scalar field:

sage: f == g
False
>>> from sage.all import *
>>> f == g
False

…to a symbolic expression:

sage: f == x*y
False
sage: g == x*y
True
sage: c == a
True
>>> from sage.all import *
>>> f == x*y
False
>>> g == x*y
True
>>> c == a
True

…to a number:

sage: f == 2
False
sage: zer == 0
True
>>> from sage.all import *
>>> f == Integer(2)
False
>>> zer == Integer(0)
True

…to anything else:

sage: f == M
False
>>> from sage.all import *
>>> f == M
False

Standard mathematical functions are implemented:

sage: sqrt(f)
Scalar field sqrt(f) on the 2-dimensional topological manifold M
sage: sqrt(f).display()
sqrt(f): M → ℝ
on U: (x, y) ↦ 1/sqrt(x**2 + y**2 + 1)
on V: (u, v) ↦ sqrt(u**2 + v**2)/sqrt(u**2 + v**2 + 1)
>>> from sage.all import *
>>> sqrt(f)
Scalar field sqrt(f) on the 2-dimensional topological manifold M
>>> sqrt(f).display()
sqrt(f): M → ℝ
on U: (x, y) ↦ 1/sqrt(x**2 + y**2 + 1)
on V: (u, v) ↦ sqrt(u**2 + v**2)/sqrt(u**2 + v**2 + 1)
sage: tan(f)
Scalar field tan(f) on the 2-dimensional topological manifold M
sage: tan(f).display()
tan(f): M → ℝ
on U: (x, y) ↦ tan(1/(x**2 + y**2 + 1))
on V: (u, v) ↦ tan((u**2 + v**2)/(u**2 + v**2 + 1))
>>> from sage.all import *
>>> tan(f)
Scalar field tan(f) on the 2-dimensional topological manifold M
>>> tan(f).display()
tan(f): M → ℝ
on U: (x, y) ↦ tan(1/(x**2 + y**2 + 1))
on V: (u, v) ↦ tan((u**2 + v**2)/(u**2 + v**2 + 1))

Arithmetics of scalar fields with SymPy

Scalar fields on \(M\) (resp. \(U\)) belong to the algebra \(C^0(M)\) (resp. \(C^0(U)\)):

sage: f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold M
sage: f.parent() is M.scalar_field_algebra()
True
sage: g.parent()
Algebra of scalar fields on the Open subset U of the 2-dimensional
 topological manifold M
sage: g.parent() is U.scalar_field_algebra()
True
>>> from sage.all import *
>>> f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold M
>>> f.parent() is M.scalar_field_algebra()
True
>>> g.parent()
Algebra of scalar fields on the Open subset U of the 2-dimensional
 topological manifold M
>>> g.parent() is U.scalar_field_algebra()
True

Consequently, scalar fields can be added:

sage: s = f + c ; s
Scalar field f+c on the 2-dimensional topological manifold M
sage: s.display()
f+c: M → ℝ
on U: (x, y) ↦ (a*x**2 + a*y**2 + a + 1)/(x**2 + y**2 + 1)
on V: (u, v) ↦ (a*u**2 + a*v**2 + a + u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> s = f + c ; s
Scalar field f+c on the 2-dimensional topological manifold M
>>> s.display()
f+c: M → ℝ
on U: (x, y) ↦ (a*x**2 + a*y**2 + a + 1)/(x**2 + y**2 + 1)
on V: (u, v) ↦ (a*u**2 + a*v**2 + a + u**2 + v**2)/(u**2 + v**2 + 1)

and subtracted:

sage: s = f - c ; s
Scalar field f-c on the 2-dimensional topological manifold M
sage: s.display()
f-c: M → ℝ
on U: (x, y) ↦ (-a*x**2 - a*y**2 - a + 1)/(x**2 + y**2 + 1)
on V: (u, v) ↦ (-a*u**2 - a*v**2 - a + u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> s = f - c ; s
Scalar field f-c on the 2-dimensional topological manifold M
>>> s.display()
f-c: M → ℝ
on U: (x, y) ↦ (-a*x**2 - a*y**2 - a + 1)/(x**2 + y**2 + 1)
on V: (u, v) ↦ (-a*u**2 - a*v**2 - a + u**2 + v**2)/(u**2 + v**2 + 1)

Some tests:

sage: f + zer == f
True
sage: f - f == zer
True
sage: f + (-f) == zer
True
sage: (f+c)-f == c
True
sage: (f-c)+c == f
True
>>> from sage.all import *
>>> f + zer == f
True
>>> f - f == zer
True
>>> f + (-f) == zer
True
>>> (f+c)-f == c
True
>>> (f-c)+c == f
True

We may add a number (interpreted as a constant scalar field) to a scalar field:

sage: s = f + 1 ; s
Scalar field f+1 on the 2-dimensional topological manifold M
sage: s.display()
f+1: M → ℝ
on U: (x, y) ↦ (x**2 + y**2 + 2)/(x**2 + y**2 + 1)
on V: (u, v) ↦ (2*u**2 + 2*v**2 + 1)/(u**2 + v**2 + 1)
sage: (f+1)-1 == f
True
>>> from sage.all import *
>>> s = f + Integer(1) ; s
Scalar field f+1 on the 2-dimensional topological manifold M
>>> s.display()
f+1: M → ℝ
on U: (x, y) ↦ (x**2 + y**2 + 2)/(x**2 + y**2 + 1)
on V: (u, v) ↦ (2*u**2 + 2*v**2 + 1)/(u**2 + v**2 + 1)
>>> (f+Integer(1))-Integer(1) == f
True

The number can represented by a symbolic variable:

sage: s = a + f ; s
Scalar field on the 2-dimensional topological manifold M
sage: s == c + f
True
>>> from sage.all import *
>>> s = a + f ; s
Scalar field on the 2-dimensional topological manifold M
>>> s == c + f
True

However if the symbolic variable is a chart coordinate, the addition is performed only on the chart domain:

sage: s = f + x; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ (x**3 + x*y**2 + x + 1)/(x**2 + y**2 + 1)
on W: (u, v) ↦ (u**4 + u**3 + 2*u**2*v**2 + u*v**2 + u + v**4)/(u**4 + 2*u**2*v**2 + u**2 + v**4 + v**2)
sage: s = f + u; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on W: (x, y) ↦ (x**3 + x**2 + x*y**2 + x + y**2)/(x**4 + 2*x**2*y**2 + x**2 + y**4 + y**2)
on V: (u, v) ↦ (u**3 + u**2 + u*v**2 + u + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> s = f + x; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ (x**3 + x*y**2 + x + 1)/(x**2 + y**2 + 1)
on W: (u, v) ↦ (u**4 + u**3 + 2*u**2*v**2 + u*v**2 + u + v**4)/(u**4 + 2*u**2*v**2 + u**2 + v**4 + v**2)
>>> s = f + u; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on W: (x, y) ↦ (x**3 + x**2 + x*y**2 + x + y**2)/(x**4 + 2*x**2*y**2 + x**2 + y**4 + y**2)
on V: (u, v) ↦ (u**3 + u**2 + u*v**2 + u + v**2)/(u**2 + v**2 + 1)

The addition of two scalar fields with different domains is possible if the domain of one of them is a subset of the domain of the other; the domain of the result is then this subset:

sage: f.domain()
2-dimensional topological manifold M
sage: g.domain()
Open subset U of the 2-dimensional topological manifold M
sage: s = f + g ; s
Scalar field f+g on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.domain()
Open subset U of the 2-dimensional topological manifold M
sage: s.display()
f+g: U → ℝ
   (x, y) ↦ (x**3*y + x*y**3 + x*y + 1)/(x**2 + y**2 + 1)
on W: (u, v) ↦ (u**6 + 3*u**4*v**2 + u**3*v + 3*u**2*v**4 + u*v**3 + u*v + v**6)/(u**6 + 3*u**4*v**2 + u**4 + 3*u**2*v**4 + 2*u**2*v**2 + v**6 + v**4)
>>> from sage.all import *
>>> f.domain()
2-dimensional topological manifold M
>>> g.domain()
Open subset U of the 2-dimensional topological manifold M
>>> s = f + g ; s
Scalar field f+g on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.domain()
Open subset U of the 2-dimensional topological manifold M
>>> s.display()
f+g: U → ℝ
   (x, y) ↦ (x**3*y + x*y**3 + x*y + 1)/(x**2 + y**2 + 1)
on W: (u, v) ↦ (u**6 + 3*u**4*v**2 + u**3*v + 3*u**2*v**4 + u*v**3 + u*v + v**6)/(u**6 + 3*u**4*v**2 + u**4 + 3*u**2*v**4 + 2*u**2*v**2 + v**6 + v**4)

The operation actually performed is \(f|_U + g\):

sage: s == f.restrict(U) + g
True
>>> from sage.all import *
>>> s == f.restrict(U) + g
True

Since the algebra \(C^0(M)\) is a vector space over \(\RR\), scalar fields can be multiplied by a number, either an explicit one:

sage: s = 2*f ; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ 2/(x**2 + y**2 + 1)
on V: (u, v) ↦ 2*(u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> s = Integer(2)*f ; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ 2/(x**2 + y**2 + 1)
on V: (u, v) ↦ 2*(u**2 + v**2)/(u**2 + v**2 + 1)

or a symbolic one:

sage: s = a*f ; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ a/(x**2 + y**2 + 1)
on V: (u, v) ↦ a*(u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> s = a*f ; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ a/(x**2 + y**2 + 1)
on V: (u, v) ↦ a*(u**2 + v**2)/(u**2 + v**2 + 1)

However, if the symbolic variable is a chart coordinate, the multiplication is performed only in the corresponding chart:

sage: s = x*f; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on U: (x, y) ↦ x/(x**2 + y**2 + 1)
on W: (u, v) ↦ u/(u**2 + v**2 + 1)
sage: s = u*f; s
Scalar field on the 2-dimensional topological manifold M
sage: s.display()
M → ℝ
on W: (x, y) ↦ x/(x**4 + 2*x**2*y**2 + x**2 + y**4 + y**2)
on V: (u, v) ↦ u*(u**2 + v**2)/(u**2 + v**2 + 1)
>>> from sage.all import *
>>> s = x*f; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on U: (x, y) ↦ x/(x**2 + y**2 + 1)
on W: (u, v) ↦ u/(u**2 + v**2 + 1)
>>> s = u*f; s
Scalar field on the 2-dimensional topological manifold M
>>> s.display()
M → ℝ
on W: (x, y) ↦ x/(x**4 + 2*x**2*y**2 + x**2 + y**4 + y**2)
on V: (u, v) ↦ u*(u**2 + v**2)/(u**2 + v**2 + 1)

Some tests:

sage: 0*f == 0
True
sage: 0*f == zer
True
sage: 1*f == f
True
sage: (-2)*f == - f - f
True
>>> from sage.all import *
>>> Integer(0)*f == Integer(0)
True
>>> Integer(0)*f == zer
True
>>> Integer(1)*f == f
True
>>> (-Integer(2))*f == - f - f
True

The ring multiplication of the algebras \(C^0(M)\) and \(C^0(U)\) is the pointwise multiplication of functions:

sage: s = f*f ; s
Scalar field f*f on the 2-dimensional topological manifold M
sage: s.display()
f*f: M → ℝ
on U: (x, y) ↦ 1/(x**4 + 2*x**2*y**2 + 2*x**2 + y**4 + 2*y**2 + 1)
on V: (u, v) ↦ (u**4 + 2*u**2*v**2 + v**4)/(u**4 + 2*u**2*v**2 + 2*u**2 + v**4 + 2*v**2 + 1)

sage: s = g*h ; s
Scalar field g*h on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
g*h: U → ℝ
   (x, y) ↦ x*y*H(x, y)
on W: (u, v) ↦ u*v*H(u/(u**2 + v**2), v/(u**2 + v**2))/(u**4 + 2*u**2*v**2 + v**4)
>>> from sage.all import *
>>> s = f*f ; s
Scalar field f*f on the 2-dimensional topological manifold M
>>> s.display()
f*f: M → ℝ
on U: (x, y) ↦ 1/(x**4 + 2*x**2*y**2 + 2*x**2 + y**4 + 2*y**2 + 1)
on V: (u, v) ↦ (u**4 + 2*u**2*v**2 + v**4)/(u**4 + 2*u**2*v**2 + 2*u**2 + v**4 + 2*v**2 + 1)

>>> s = g*h ; s
Scalar field g*h on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
g*h: U → ℝ
   (x, y) ↦ x*y*H(x, y)
on W: (u, v) ↦ u*v*H(u/(u**2 + v**2), v/(u**2 + v**2))/(u**4 + 2*u**2*v**2 + v**4)

Thanks to the coercion \(C^0(M) \to C^0(U)\) mentioned above, it is possible to multiply a scalar field defined on \(M\) by a scalar field defined on \(U\), the result being a scalar field defined on \(U\):

sage: f.domain(), g.domain()
(2-dimensional topological manifold M,
 Open subset U of the 2-dimensional topological manifold M)
sage: s = f*g ; s
Scalar field f*g on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
f*g: U → ℝ
   (x, y) ↦ x*y/(x**2 + y**2 + 1)
on W: (u, v) ↦ u*v/(u**4 + 2*u**2*v**2 + u**2 + v**4 + v**2)

sage: s == f.restrict(U)*g
True
>>> from sage.all import *
>>> f.domain(), g.domain()
(2-dimensional topological manifold M,
 Open subset U of the 2-dimensional topological manifold M)
>>> s = f*g ; s
Scalar field f*g on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
f*g: U → ℝ
   (x, y) ↦ x*y/(x**2 + y**2 + 1)
on W: (u, v) ↦ u*v/(u**4 + 2*u**2*v**2 + u**2 + v**4 + v**2)

>>> s == f.restrict(U)*g
True

Scalar fields can be divided (pointwise division):

sage: s = f/c ; s
Scalar field f/c on the 2-dimensional topological manifold M
sage: s.display()
f/c: M → ℝ
on U: (x, y) ↦ 1/(a*(x**2 + y**2 + 1))
on V: (u, v) ↦ (u**2 + v**2)/(a*(u**2 + v**2 + 1))
sage: s = g/h ; s
Scalar field g/h on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
g/h: U → ℝ
   (x, y) ↦ x*y/H(x, y)
on W: (u, v) ↦ u*v/((u**4 + 2*u**2*v**2 + v**4)*H(u/(u**2 + v**2), v/(u**2 + v**2)))

sage: s = f/g ; s
Scalar field f/g on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
f/g: U → ℝ
   (x, y) ↦ 1/(x*y*(x**2 + y**2 + 1))
on W: (u, v) ↦ (u**6 + 3*u**4*v**2 + 3*u**2*v**4 + v**6)/(u*v*(u**2 + v**2 + 1))
sage: s == f.restrict(U)/g
True
>>> from sage.all import *
>>> s = f/c ; s
Scalar field f/c on the 2-dimensional topological manifold M
>>> s.display()
f/c: M → ℝ
on U: (x, y) ↦ 1/(a*(x**2 + y**2 + 1))
on V: (u, v) ↦ (u**2 + v**2)/(a*(u**2 + v**2 + 1))
>>> s = g/h ; s
Scalar field g/h on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
g/h: U → ℝ
   (x, y) ↦ x*y/H(x, y)
on W: (u, v) ↦ u*v/((u**4 + 2*u**2*v**2 + v**4)*H(u/(u**2 + v**2), v/(u**2 + v**2)))

>>> s = f/g ; s
Scalar field f/g on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
f/g: U → ℝ
   (x, y) ↦ 1/(x*y*(x**2 + y**2 + 1))
on W: (u, v) ↦ (u**6 + 3*u**4*v**2 + 3*u**2*v**4 + v**6)/(u*v*(u**2 + v**2 + 1))
>>> s == f.restrict(U)/g
True

For scalar fields defined on a single chart domain, we may perform some arithmetics with symbolic expressions involving the chart coordinates:

sage: s = g + x^2 - y ; s
Scalar field on the Open subset U of the 2-dimensional topological manifold M
sage: s.display()
U → ℝ
(x, y) ↦ x**2 + x*y - y
on W: (u, v) ↦ (-u**2*v + u**2 + u*v - v**3)/(u**4 + 2*u**2*v**2 + v**4)
>>> from sage.all import *
>>> s = g + x**Integer(2) - y ; s
Scalar field on the Open subset U of the 2-dimensional topological manifold M
>>> s.display()
U → ℝ
(x, y) ↦ x**2 + x*y - y
on W: (u, v) ↦ (-u**2*v + u**2 + u*v - v**3)/(u**4 + 2*u**2*v**2 + v**4)
sage: s = g*x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
U → ℝ
(x, y) ↦ x**2*y
on W: (u, v) ↦ u**2*v/(u**6 + 3*u**4*v**2 + 3*u**2*v**4 + v**6)
>>> from sage.all import *
>>> s = g*x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
U → ℝ
(x, y) ↦ x**2*y
on W: (u, v) ↦ u**2*v/(u**6 + 3*u**4*v**2 + 3*u**2*v**4 + v**6)
sage: s = g/x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
U → ℝ
(x, y) ↦ y
on W: (u, v) ↦ v/(u**2 + v**2)
sage: s = x/g ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
sage: s.display()
U → ℝ
(x, y) ↦ 1/y
on W: (u, v) ↦ u**2/v + v
>>> from sage.all import *
>>> s = g/x ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
U → ℝ
(x, y) ↦ y
on W: (u, v) ↦ v/(u**2 + v**2)
>>> s = x/g ; s
Scalar field on the Open subset U of the 2-dimensional topological
 manifold M
>>> s.display()
U → ℝ
(x, y) ↦ 1/y
on W: (u, v) ↦ u**2/v + v

The test suite is passed:

sage: TestSuite(f).run()
sage: TestSuite(zer).run()
>>> from sage.all import *
>>> TestSuite(f).run()
>>> TestSuite(zer).run()
add_expr(coord_expression, chart=None)[source]#

Add some coordinate expression to the scalar field.

The previous expressions with respect to other charts are kept. To clear them, use set_expr() instead.

INPUT:

  • coord_expression – coordinate expression of the scalar field

  • chart – (default: None) chart in which coord_expression is defined; if None, the default chart of the scalar field’s domain is assumed

Warning

If the scalar field has already expressions in other charts, it is the user’s responsibility to make sure that the expression to be added is consistent with them.

EXAMPLES:

Adding scalar field expressions on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x^2 + 2*x*y +1)
sage: f._express
{Chart (M, (x, y)): x^2 + 2*x*y + 1}
sage: f.add_expr(3*y)
sage: f._express  # the (x,y) expression has been changed:
{Chart (M, (x, y)): 3*y}
sage: c_uv.<u,v> = M.chart()
sage: f.add_expr(cos(u)-sin(v), c_uv)
sage: f._express # random (dict. output); f has now 2 expressions:
{Chart (M, (x, y)): 3*y, Chart (M, (u, v)): cos(u) - sin(v)}
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x**Integer(2) + Integer(2)*x*y +Integer(1))
>>> f._express
{Chart (M, (x, y)): x^2 + 2*x*y + 1}
>>> f.add_expr(Integer(3)*y)
>>> f._express  # the (x,y) expression has been changed:
{Chart (M, (x, y)): 3*y}
>>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)
>>> f.add_expr(cos(u)-sin(v), c_uv)
>>> f._express # random (dict. output); f has now 2 expressions:
{Chart (M, (x, y)): 3*y, Chart (M, (u, v)): cos(u) - sin(v)}

Since zero and one are special elements, their expressions cannot be changed:

sage: z = M.zero_scalar_field()
sage: z.add_expr(cos(u)-sin(v), c_uv)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
sage: one = M.one_scalar_field()
sage: one.add_expr(cos(u)-sin(v), c_uv)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
>>> from sage.all import *
>>> z = M.zero_scalar_field()
>>> z.add_expr(cos(u)-sin(v), c_uv)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
>>> one = M.one_scalar_field()
>>> one.add_expr(cos(u)-sin(v), c_uv)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
add_expr_by_continuation(chart, subdomain)[source]#

Set coordinate expression in a chart by continuation of the coordinate expression in a subchart.

The continuation is performed by demanding that the coordinate expression is identical to that in the restriction of the chart to a given subdomain.

INPUT:

  • chart – coordinate chart \((U,(x^i))\) in which the expression of the scalar field is to set

  • subdomain – open subset \(V\subset U\) in which the expression in terms of the restriction of the coordinate chart \((U,(x^i))\) to \(V\) is already known or can be evaluated by a change of coordinates.

EXAMPLES:

Scalar field on the sphere \(S^2\):

sage: M = Manifold(2, 'S^2', structure='topological')
sage: U = M.open_subset('U') ; V = M.open_subset('V') # the complement of resp. N pole and S pole
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: 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)  # S^2 minus the two poles
sage: f = M.scalar_field(atan(x^2+y^2), chart=c_xy, name='f')
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'S^2', structure='topological')
>>> U = M.open_subset('U') ; V = M.open_subset('V') # the complement of resp. N pole and S pole
>>> 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
>>> 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)  # S^2 minus the two poles
>>> f = M.scalar_field(atan(x**Integer(2)+y**Integer(2)), chart=c_xy, name='f')

The scalar field has been defined only on the domain covered by the chart c_xy, i.e. \(U\):

sage: f.display()
f: S^2 → ℝ
on U: (x, y) ↦ arctan(x^2 + y^2)
on W: (u, v) ↦ arctan(1/(u^2 + v^2))
>>> from sage.all import *
>>> f.display()
f: S^2 → ℝ
on U: (x, y) ↦ arctan(x^2 + y^2)
on W: (u, v) ↦ arctan(1/(u^2 + v^2))

We note that on \(W = U \cap V\), the expression of \(f\) in terms of coordinates \((u,v)\) can be deduced from that in the coordinates \((x,y)\) thanks to the transition map between the two charts:

sage: f.display(c_uv.restrict(W))
f: S^2 → ℝ
on W: (u, v) ↦ arctan(1/(u^2 + v^2))
>>> from sage.all import *
>>> f.display(c_uv.restrict(W))
f: S^2 → ℝ
on W: (u, v) ↦ arctan(1/(u^2 + v^2))

We use this fact to extend the definition of \(f\) to the open subset \(V\), covered by the chart c_uv:

sage: f.add_expr_by_continuation(c_uv, W)
>>> from sage.all import *
>>> f.add_expr_by_continuation(c_uv, W)

Then, \(f\) is known on the whole sphere:

sage: f.display()
f: S^2 → ℝ
on U: (x, y) ↦ arctan(x^2 + y^2)
on V: (u, v) ↦ arctan(1/(u^2 + v^2))
>>> from sage.all import *
>>> f.display()
f: S^2 → ℝ
on U: (x, y) ↦ arctan(x^2 + y^2)
on V: (u, v) ↦ arctan(1/(u^2 + v^2))
arccos()[source]#

Arc cosine of the scalar field.

OUTPUT:

  • the scalar field \(\arccos f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = arccos(f) ; g
Scalar field arccos(f) on the 2-dimensional topological manifold M
sage: latex(g)
\arccos\left(\Phi\right)
sage: g.display()
arccos(f): M → ℝ
   (x, y) ↦ arccos(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = arccos(f) ; g
Scalar field arccos(f) on the 2-dimensional topological manifold M
>>> latex(g)
\arccos\left(\Phi\right)
>>> g.display()
arccos(f): M → ℝ
   (x, y) ↦ arccos(x*y)

The notation acos can be used as well:

sage: acos(f)
Scalar field arccos(f) on the 2-dimensional topological manifold M
sage: acos(f) == g
True
>>> from sage.all import *
>>> acos(f)
Scalar field arccos(f) on the 2-dimensional topological manifold M
>>> acos(f) == g
True

Some tests:

sage: cos(g) == f
True
sage: arccos(M.constant_scalar_field(1)) == M.zero_scalar_field()
True
sage: arccos(M.zero_scalar_field()) == M.constant_scalar_field(pi/2)
True
>>> from sage.all import *
>>> cos(g) == f
True
>>> arccos(M.constant_scalar_field(Integer(1))) == M.zero_scalar_field()
True
>>> arccos(M.zero_scalar_field()) == M.constant_scalar_field(pi/Integer(2))
True
arccosh()[source]#

Inverse hyperbolic cosine of the scalar field.

OUTPUT:

  • the scalar field \(\mathrm{arccosh}\, f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = arccosh(f) ; g
Scalar field arccosh(f) on the 2-dimensional topological manifold M
sage: latex(g)
\,\mathrm{arccosh}\left(\Phi\right)
sage: g.display()
arccosh(f): M → ℝ
   (x, y) ↦ arccosh(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = arccosh(f) ; g
Scalar field arccosh(f) on the 2-dimensional topological manifold M
>>> latex(g)
\,\mathrm{arccosh}\left(\Phi\right)
>>> g.display()
arccosh(f): M → ℝ
   (x, y) ↦ arccosh(x*y)

The notation acosh can be used as well:

sage: acosh(f)
Scalar field arccosh(f) on the 2-dimensional topological manifold M
sage: acosh(f) == g
True
>>> from sage.all import *
>>> acosh(f)
Scalar field arccosh(f) on the 2-dimensional topological manifold M
>>> acosh(f) == g
True

Some tests:

sage: cosh(g) == f
True
sage: arccosh(M.constant_scalar_field(1)) == M.zero_scalar_field()
True
>>> from sage.all import *
>>> cosh(g) == f
True
>>> arccosh(M.constant_scalar_field(Integer(1))) == M.zero_scalar_field()
True
arcsin()[source]#

Arc sine of the scalar field.

OUTPUT:

  • the scalar field \(\arcsin f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = arcsin(f) ; g
Scalar field arcsin(f) on the 2-dimensional topological manifold M
sage: latex(g)
\arcsin\left(\Phi\right)
sage: g.display()
arcsin(f): M → ℝ
   (x, y) ↦ arcsin(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = arcsin(f) ; g
Scalar field arcsin(f) on the 2-dimensional topological manifold M
>>> latex(g)
\arcsin\left(\Phi\right)
>>> g.display()
arcsin(f): M → ℝ
   (x, y) ↦ arcsin(x*y)

The notation asin can be used as well:

sage: asin(f)
Scalar field arcsin(f) on the 2-dimensional topological manifold M
sage: asin(f) == g
True
>>> from sage.all import *
>>> asin(f)
Scalar field arcsin(f) on the 2-dimensional topological manifold M
>>> asin(f) == g
True

Some tests:

sage: sin(g) == f
True
sage: arcsin(M.zero_scalar_field()) == M.zero_scalar_field()
True
sage: arcsin(M.constant_scalar_field(1)) == M.constant_scalar_field(pi/2)
True
>>> from sage.all import *
>>> sin(g) == f
True
>>> arcsin(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> arcsin(M.constant_scalar_field(Integer(1))) == M.constant_scalar_field(pi/Integer(2))
True
arcsinh()[source]#

Inverse hyperbolic sine of the scalar field.

OUTPUT:

  • the scalar field \(\mathrm{arcsinh}\, f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = arcsinh(f) ; g
Scalar field arcsinh(f) on the 2-dimensional topological manifold M
sage: latex(g)
\,\mathrm{arcsinh}\left(\Phi\right)
sage: g.display()
arcsinh(f): M → ℝ
   (x, y) ↦ arcsinh(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = arcsinh(f) ; g
Scalar field arcsinh(f) on the 2-dimensional topological manifold M
>>> latex(g)
\,\mathrm{arcsinh}\left(\Phi\right)
>>> g.display()
arcsinh(f): M → ℝ
   (x, y) ↦ arcsinh(x*y)

The notation asinh can be used as well:

sage: asinh(f)
Scalar field arcsinh(f) on the 2-dimensional topological manifold M
sage: asinh(f) == g
True
>>> from sage.all import *
>>> asinh(f)
Scalar field arcsinh(f) on the 2-dimensional topological manifold M
>>> asinh(f) == g
True

Some tests:

sage: sinh(g) == f
True
sage: arcsinh(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> from sage.all import *
>>> sinh(g) == f
True
>>> arcsinh(M.zero_scalar_field()) == M.zero_scalar_field()
True
arctan()[source]#

Arc tangent of the scalar field.

OUTPUT:

  • the scalar field \(\arctan f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = arctan(f) ; g
Scalar field arctan(f) on the 2-dimensional topological manifold M
sage: latex(g)
\arctan\left(\Phi\right)
sage: g.display()
arctan(f): M → ℝ
   (x, y) ↦ arctan(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = arctan(f) ; g
Scalar field arctan(f) on the 2-dimensional topological manifold M
>>> latex(g)
\arctan\left(\Phi\right)
>>> g.display()
arctan(f): M → ℝ
   (x, y) ↦ arctan(x*y)

The notation atan can be used as well:

sage: atan(f)
Scalar field arctan(f) on the 2-dimensional topological manifold M
sage: atan(f) == g
True
>>> from sage.all import *
>>> atan(f)
Scalar field arctan(f) on the 2-dimensional topological manifold M
>>> atan(f) == g
True

Some tests:

sage: tan(g) == f
True
sage: arctan(M.zero_scalar_field()) == M.zero_scalar_field()
True
sage: arctan(M.constant_scalar_field(1)) == M.constant_scalar_field(pi/4)
True
>>> from sage.all import *
>>> tan(g) == f
True
>>> arctan(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> arctan(M.constant_scalar_field(Integer(1))) == M.constant_scalar_field(pi/Integer(4))
True
arctanh()[source]#

Inverse hyperbolic tangent of the scalar field.

OUTPUT:

  • the scalar field \(\mathrm{arctanh}\, f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = arctanh(f) ; g
Scalar field arctanh(f) on the 2-dimensional topological manifold M
sage: latex(g)
\,\mathrm{arctanh}\left(\Phi\right)
sage: g.display()
arctanh(f): M → ℝ
   (x, y) ↦ arctanh(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = arctanh(f) ; g
Scalar field arctanh(f) on the 2-dimensional topological manifold M
>>> latex(g)
\,\mathrm{arctanh}\left(\Phi\right)
>>> g.display()
arctanh(f): M → ℝ
   (x, y) ↦ arctanh(x*y)

The notation atanh can be used as well:

sage: atanh(f)
Scalar field arctanh(f) on the 2-dimensional topological manifold M
sage: atanh(f) == g
True
>>> from sage.all import *
>>> atanh(f)
Scalar field arctanh(f) on the 2-dimensional topological manifold M
>>> atanh(f) == g
True

Some tests:

sage: tanh(g) == f
True
sage: arctanh(M.zero_scalar_field()) == M.zero_scalar_field()
True
sage: arctanh(M.constant_scalar_field(1/2)) == M.constant_scalar_field(log(3)/2)
True
>>> from sage.all import *
>>> tanh(g) == f
True
>>> arctanh(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> arctanh(M.constant_scalar_field(Integer(1)/Integer(2))) == M.constant_scalar_field(log(Integer(3))/Integer(2))
True
codomain()[source]#

Return the codomain of the scalar field.

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x+2*y)
sage: f.codomain()
Real Field with 53 bits of precision
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x+Integer(2)*y)
>>> f.codomain()
Real Field with 53 bits of precision
common_charts(other)[source]#

Find common charts for the expressions of the scalar field and other.

INPUT:

  • other – a scalar field

OUTPUT:

  • list of common charts; if no common chart is found, None is returned (instead of an empty list)

EXAMPLES:

Search for common charts on a 2-dimensional manifold with 2 overlapping domains:

sage: M = Manifold(2, 'M', structure='topological')
sage: U = M.open_subset('U')
sage: c_xy.<x,y> = U.chart()
sage: V = M.open_subset('V')
sage: c_uv.<u,v> = V.chart()
sage: M.declare_union(U,V)   # M is the union of U and V
sage: f = U.scalar_field(x^2)
sage: g = M.scalar_field(x+y)
sage: f.common_charts(g)
[Chart (U, (x, y))]
sage: g.add_expr(u, c_uv)
sage: f._express
{Chart (U, (x, y)): x^2}
sage: g._express  # random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
sage: f.common_charts(g)
[Chart (U, (x, y))]
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> U = M.open_subset('U')
>>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> V = M.open_subset('V')
>>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)
>>> M.declare_union(U,V)   # M is the union of U and V
>>> f = U.scalar_field(x**Integer(2))
>>> g = M.scalar_field(x+y)
>>> f.common_charts(g)
[Chart (U, (x, y))]
>>> g.add_expr(u, c_uv)
>>> f._express
{Chart (U, (x, y)): x^2}
>>> g._express  # random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
>>> f.common_charts(g)
[Chart (U, (x, y))]

Common charts found as subcharts: the subcharts are introduced via a transition map between charts c_xy and c_uv on the intersecting subdomain \(W = U\cap V\):

sage: trans = c_xy.transition_map(c_uv, (x+y, x-y), 'W', x<0, u+v<0)
sage: M.atlas()
[Chart (U, (x, y)), Chart (V, (u, v)), Chart (W, (x, y)),
 Chart (W, (u, v))]
sage: c_xy_W = M.atlas()[2]
sage: c_uv_W = M.atlas()[3]
sage: trans.inverse()
Change of coordinates from Chart (W, (u, v)) to Chart (W, (x, y))
sage: f.common_charts(g)
[Chart (U, (x, y))]
sage: f.expr(c_xy_W)
x^2
sage: f._express  # random (dictionary output)
{Chart (U, (x, y)): x^2, Chart (W, (x, y)): x^2}
sage: g._express  # random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
sage: g.common_charts(f)  # c_xy_W is not returned because it is subchart of 'xy'
[Chart (U, (x, y))]
sage: f.expr(c_uv_W)
1/4*u^2 + 1/2*u*v + 1/4*v^2
sage: f._express  # random (dictionary output)
{Chart (U, (x, y)): x^2, Chart (W, (x, y)): x^2,
 Chart (W, (u, v)): 1/4*u^2 + 1/2*u*v + 1/4*v^2}
sage: g._express  # random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
sage: f.common_charts(g)
[Chart (U, (x, y)), Chart (W, (u, v))]
sage: # the expressions have been updated on the subcharts
sage: g._express #  random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u,
 Chart (W, (u, v)): u}
>>> from sage.all import *
>>> trans = c_xy.transition_map(c_uv, (x+y, x-y), 'W', x<Integer(0), u+v<Integer(0))
>>> M.atlas()
[Chart (U, (x, y)), Chart (V, (u, v)), Chart (W, (x, y)),
 Chart (W, (u, v))]
>>> c_xy_W = M.atlas()[Integer(2)]
>>> c_uv_W = M.atlas()[Integer(3)]
>>> trans.inverse()
Change of coordinates from Chart (W, (u, v)) to Chart (W, (x, y))
>>> f.common_charts(g)
[Chart (U, (x, y))]
>>> f.expr(c_xy_W)
x^2
>>> f._express  # random (dictionary output)
{Chart (U, (x, y)): x^2, Chart (W, (x, y)): x^2}
>>> g._express  # random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
>>> g.common_charts(f)  # c_xy_W is not returned because it is subchart of 'xy'
[Chart (U, (x, y))]
>>> f.expr(c_uv_W)
1/4*u^2 + 1/2*u*v + 1/4*v^2
>>> f._express  # random (dictionary output)
{Chart (U, (x, y)): x^2, Chart (W, (x, y)): x^2,
 Chart (W, (u, v)): 1/4*u^2 + 1/2*u*v + 1/4*v^2}
>>> g._express  # random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
>>> f.common_charts(g)
[Chart (U, (x, y)), Chart (W, (u, v))]
>>> # the expressions have been updated on the subcharts
>>> g._express #  random (dictionary output)
{Chart (U, (x, y)): x + y, Chart (V, (u, v)): u,
 Chart (W, (u, v)): u}

Common charts found by computing some coordinate changes:

sage: W = U.intersection(V)
sage: f = W.scalar_field(x^2, c_xy_W)
sage: g = W.scalar_field(u+1, c_uv_W)
sage: f._express
{Chart (W, (x, y)): x^2}
sage: g._express
{Chart (W, (u, v)): u + 1}
sage: f.common_charts(g)
[Chart (W, (x, y)), Chart (W, (u, v))]
sage: f._express # random (dictionary output)
{Chart (W, (u, v)): 1/4*u^2 + 1/2*u*v + 1/4*v^2,
 Chart (W, (x, y)): x^2}
sage: g._express # random (dictionary output)
{Chart (W, (u, v)): u + 1, Chart (W, (x, y)): x + y + 1}
>>> from sage.all import *
>>> W = U.intersection(V)
>>> f = W.scalar_field(x**Integer(2), c_xy_W)
>>> g = W.scalar_field(u+Integer(1), c_uv_W)
>>> f._express
{Chart (W, (x, y)): x^2}
>>> g._express
{Chart (W, (u, v)): u + 1}
>>> f.common_charts(g)
[Chart (W, (x, y)), Chart (W, (u, v))]
>>> f._express # random (dictionary output)
{Chart (W, (u, v)): 1/4*u^2 + 1/2*u*v + 1/4*v^2,
 Chart (W, (x, y)): x^2}
>>> g._express # random (dictionary output)
{Chart (W, (u, v)): u + 1, Chart (W, (x, y)): x + y + 1}
coord_function(chart=None, from_chart=None)[source]#

Return the function of the coordinates representing the scalar field in a given chart.

INPUT:

  • chart – (default: None) chart with respect to which the coordinate expression is to be returned; if None, the default chart of the scalar field’s domain will be used

  • from_chart – (default: None) chart from which the required expression is computed if it is not known already in the chart chart; if None, a chart is picked in the known expressions

OUTPUT:

  • instance of ChartFunction representing the coordinate function of the scalar field in the given chart

EXAMPLES:

Coordinate function on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x*y^2)
sage: f.coord_function()
x*y^2
sage: f.coord_function(c_xy)  # equivalent form (since c_xy is the default chart)
x*y^2
sage: type(f.coord_function())
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x*y**Integer(2))
>>> f.coord_function()
x*y^2
>>> f.coord_function(c_xy)  # equivalent form (since c_xy is the default chart)
x*y^2
>>> type(f.coord_function())
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>

Expression via a change of coordinates:

sage: c_uv.<u,v> = M.chart()
sage: c_uv.transition_map(c_xy, [u+v, u-v])
Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
sage: f._express # at this stage, f is expressed only in terms of (x,y) coordinates
{Chart (M, (x, y)): x*y^2}
sage: f.coord_function(c_uv) # forces the computation of the expression of f in terms of (u,v) coordinates
u^3 - u^2*v - u*v^2 + v^3
sage: f.coord_function(c_uv) == (u+v)*(u-v)^2  # check
True
sage: f._express  # random (dict. output); f has now 2 coordinate expressions:
{Chart (M, (x, y)): x*y^2, Chart (M, (u, v)): u^3 - u^2*v - u*v^2 + v^3}
>>> from sage.all import *
>>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)
>>> c_uv.transition_map(c_xy, [u+v, u-v])
Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
>>> f._express # at this stage, f is expressed only in terms of (x,y) coordinates
{Chart (M, (x, y)): x*y^2}
>>> f.coord_function(c_uv) # forces the computation of the expression of f in terms of (u,v) coordinates
u^3 - u^2*v - u*v^2 + v^3
>>> f.coord_function(c_uv) == (u+v)*(u-v)**Integer(2)  # check
True
>>> f._express  # random (dict. output); f has now 2 coordinate expressions:
{Chart (M, (x, y)): x*y^2, Chart (M, (u, v)): u^3 - u^2*v - u*v^2 + v^3}

Usage in a physical context (simple Lorentz transformation - boost in x direction, with relative velocity v between o1 and o2 frames):

sage: M = Manifold(2, 'M', structure='topological')
sage: o1.<t,x> = M.chart()
sage: o2.<T,X> = M.chart()
sage: f = M.scalar_field(x^2 - t^2)
sage: f.coord_function(o1)
-t^2 + x^2
sage: v = var('v'); gam = 1/sqrt(1-v^2)
sage: o2.transition_map(o1, [gam*(T - v*X), gam*(X - v*T)])
Change of coordinates from Chart (M, (T, X)) to Chart (M, (t, x))
sage: f.coord_function(o2)
-T^2 + X^2
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> o1 = M.chart(names=('t', 'x',)); (t, x,) = o1._first_ngens(2)
>>> o2 = M.chart(names=('T', 'X',)); (T, X,) = o2._first_ngens(2)
>>> f = M.scalar_field(x**Integer(2) - t**Integer(2))
>>> f.coord_function(o1)
-t^2 + x^2
>>> v = var('v'); gam = Integer(1)/sqrt(Integer(1)-v**Integer(2))
>>> o2.transition_map(o1, [gam*(T - v*X), gam*(X - v*T)])
Change of coordinates from Chart (M, (T, X)) to Chart (M, (t, x))
>>> f.coord_function(o2)
-T^2 + X^2
copy(name=None, latex_name=None)[source]#

Return an exact copy of the scalar field.

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

EXAMPLES:

Copy on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x*y^2)
sage: g = f.copy()
sage: type(g)
<class 'sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra_with_category.element_class'>
sage: g.expr()
x*y^2
sage: g == f
True
sage: g is f
False
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x*y**Integer(2))
>>> g = f.copy()
>>> type(g)
<class 'sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra_with_category.element_class'>
>>> g.expr()
x*y^2
>>> g == f
True
>>> g is f
False
copy_from(other)[source]#

Make self a copy of other.

INPUT:

  • other – other scalar field, in the same module as self

Note

While the derived quantities are not copied, the name is kept.

Warning

All previous defined expressions and restrictions will be deleted!

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x*y^2, name='f')
sage: f.display()
f: M → ℝ
   (x, y) ↦ x*y^2
sage: g = M.scalar_field(name='g')
sage: g.copy_from(f)
sage: g.display()
g: M → ℝ
   (x, y) ↦ x*y^2
sage: f == g
True
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x*y**Integer(2), name='f')
>>> f.display()
f: M → ℝ
   (x, y) ↦ x*y^2
>>> g = M.scalar_field(name='g')
>>> g.copy_from(f)
>>> g.display()
g: M → ℝ
   (x, y) ↦ x*y^2
>>> f == g
True

While the original scalar field is modified, the copy is not:

sage: f.set_expr(x-y)
sage: f.display()
f: M → ℝ
   (x, y) ↦ x - y
sage: g.display()
g: M → ℝ
   (x, y) ↦ x*y^2
sage: f == g
False
>>> from sage.all import *
>>> f.set_expr(x-y)
>>> f.display()
f: M → ℝ
   (x, y) ↦ x - y
>>> g.display()
g: M → ℝ
   (x, y) ↦ x*y^2
>>> f == g
False
cos()[source]#

Cosine of the scalar field.

OUTPUT:

  • the scalar field \(\cos f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = cos(f) ; g
Scalar field cos(f) on the 2-dimensional topological manifold M
sage: latex(g)
\cos\left(\Phi\right)
sage: g.display()
cos(f): M → ℝ
   (x, y) ↦ cos(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = cos(f) ; g
Scalar field cos(f) on the 2-dimensional topological manifold M
>>> latex(g)
\cos\left(\Phi\right)
>>> g.display()
cos(f): M → ℝ
   (x, y) ↦ cos(x*y)

Some tests:

sage: cos(M.zero_scalar_field()) == M.constant_scalar_field(1)
True
sage: cos(M.constant_scalar_field(pi/2)) == M.zero_scalar_field()
True
>>> from sage.all import *
>>> cos(M.zero_scalar_field()) == M.constant_scalar_field(Integer(1))
True
>>> cos(M.constant_scalar_field(pi/Integer(2))) == M.zero_scalar_field()
True
cosh()[source]#

Hyperbolic cosine of the scalar field.

OUTPUT:

  • the scalar field \(\cosh f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = cosh(f) ; g
Scalar field cosh(f) on the 2-dimensional topological manifold M
sage: latex(g)
\cosh\left(\Phi\right)
sage: g.display()
cosh(f): M → ℝ
   (x, y) ↦ cosh(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = cosh(f) ; g
Scalar field cosh(f) on the 2-dimensional topological manifold M
>>> latex(g)
\cosh\left(\Phi\right)
>>> g.display()
cosh(f): M → ℝ
   (x, y) ↦ cosh(x*y)

Some test:

sage: cosh(M.zero_scalar_field()) == M.constant_scalar_field(1)
True
>>> from sage.all import *
>>> cosh(M.zero_scalar_field()) == M.constant_scalar_field(Integer(1))
True
disp(chart=None)[source]#

Display the expression of the scalar field in a given chart.

Without any argument, this function displays all known, distinct expressions.

INPUT:

  • chart – (default: None) chart with respect to which the coordinate expression is to be displayed; if None, the display is performed in all the greatest charts in which the coordinate expression is known

The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode).

EXAMPLES:

Various displays:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(sqrt(x+1), name='f')
sage: f.display()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)
sage: latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & \sqrt{x + 1} \end{array}
sage: g = M.scalar_field(function('G')(x, y), name='g')
sage: g.display()
g: M → ℝ
   (x, y) ↦ G(x, y)
sage: latex(g.display())
\begin{array}{llcl} g:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & G\left(x, y\right) \end{array}
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(sqrt(x+Integer(1)), name='f')
>>> f.display()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)
>>> latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & \sqrt{x + 1} \end{array}
>>> g = M.scalar_field(function('G')(x, y), name='g')
>>> g.display()
g: M → ℝ
   (x, y) ↦ G(x, y)
>>> latex(g.display())
\begin{array}{llcl} g:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & G\left(x, y\right) \end{array}

A shortcut of display() is disp():

sage: f.disp()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)
>>> from sage.all import *
>>> f.disp()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)

In case the scalar field is piecewise-defined, the display() command still outputs all expressions. Each expression displayed corresponds to the chart on the greatest domain where this particular expression is known:

sage: U = M.open_subset('U')
sage: f.set_expr(y^2, c_xy.restrict(U))
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ y^2
sage: latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array}
>>> from sage.all import *
>>> U = M.open_subset('U')
>>> f.set_expr(y**Integer(2), c_xy.restrict(U))
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ y^2
>>> latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array}
display(chart=None)[source]#

Display the expression of the scalar field in a given chart.

Without any argument, this function displays all known, distinct expressions.

INPUT:

  • chart – (default: None) chart with respect to which the coordinate expression is to be displayed; if None, the display is performed in all the greatest charts in which the coordinate expression is known

The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode).

EXAMPLES:

Various displays:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(sqrt(x+1), name='f')
sage: f.display()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)
sage: latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & \sqrt{x + 1} \end{array}
sage: g = M.scalar_field(function('G')(x, y), name='g')
sage: g.display()
g: M → ℝ
   (x, y) ↦ G(x, y)
sage: latex(g.display())
\begin{array}{llcl} g:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & G\left(x, y\right) \end{array}
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(sqrt(x+Integer(1)), name='f')
>>> f.display()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)
>>> latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & \sqrt{x + 1} \end{array}
>>> g = M.scalar_field(function('G')(x, y), name='g')
>>> g.display()
g: M → ℝ
   (x, y) ↦ G(x, y)
>>> latex(g.display())
\begin{array}{llcl} g:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & G\left(x, y\right) \end{array}

A shortcut of display() is disp():

sage: f.disp()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)
>>> from sage.all import *
>>> f.disp()
f: M → ℝ
   (x, y) ↦ sqrt(x + 1)

In case the scalar field is piecewise-defined, the display() command still outputs all expressions. Each expression displayed corresponds to the chart on the greatest domain where this particular expression is known:

sage: U = M.open_subset('U')
sage: f.set_expr(y^2, c_xy.restrict(U))
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ y^2
sage: latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array}
>>> from sage.all import *
>>> U = M.open_subset('U')
>>> f.set_expr(y**Integer(2), c_xy.restrict(U))
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ y^2
>>> latex(f.display())
\begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array}
domain()[source]#

Return the open subset on which the scalar field is defined.

OUTPUT:

  • instance of class TopologicalManifold representing the manifold’s open subset on which the scalar field is defined

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x+2*y)
sage: f.domain()
2-dimensional topological manifold M
sage: U = M.open_subset('U', coord_def={c_xy: x<0})
sage: g = f.restrict(U)
sage: g.domain()
Open subset U of the 2-dimensional topological manifold M
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x+Integer(2)*y)
>>> f.domain()
2-dimensional topological manifold M
>>> U = M.open_subset('U', coord_def={c_xy: x<Integer(0)})
>>> g = f.restrict(U)
>>> g.domain()
Open subset U of the 2-dimensional topological manifold M
exp()[source]#

Exponential of the scalar field.

OUTPUT:

  • the scalar field \(\exp f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x+y}, name='f', latex_name=r"\Phi")
sage: g = exp(f) ; g
Scalar field exp(f) on the 2-dimensional topological manifold M
sage: g.display()
exp(f): M → ℝ
   (x, y) ↦ e^(x + y)
sage: latex(g)
\exp\left(\Phi\right)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x+y}, name='f', latex_name=r"\Phi")
>>> g = exp(f) ; g
Scalar field exp(f) on the 2-dimensional topological manifold M
>>> g.display()
exp(f): M → ℝ
   (x, y) ↦ e^(x + y)
>>> latex(g)
\exp\left(\Phi\right)

Automatic simplifications occur:

sage: f = M.scalar_field({X: 2*ln(1+x^2)}, name='f')
sage: exp(f).display()
exp(f): M → ℝ
   (x, y) ↦ x^4 + 2*x^2 + 1
>>> from sage.all import *
>>> f = M.scalar_field({X: Integer(2)*ln(Integer(1)+x**Integer(2))}, name='f')
>>> exp(f).display()
exp(f): M → ℝ
   (x, y) ↦ x^4 + 2*x^2 + 1

The inverse function is log():

sage: log(exp(f)) == f
True
>>> from sage.all import *
>>> log(exp(f)) == f
True

Some tests:

sage: exp(M.zero_scalar_field()) == M.constant_scalar_field(1)
True
sage: exp(M.constant_scalar_field(1)) == M.constant_scalar_field(e)
True
>>> from sage.all import *
>>> exp(M.zero_scalar_field()) == M.constant_scalar_field(Integer(1))
True
>>> exp(M.constant_scalar_field(Integer(1))) == M.constant_scalar_field(e)
True
expr(chart=None, from_chart=None)[source]#

Return the coordinate expression of the scalar field in a given chart.

INPUT:

  • chart – (default: None) chart with respect to which the coordinate expression is required; if None, the default chart of the scalar field’s domain will be used

  • from_chart – (default: None) chart from which the required expression is computed if it is not known already in the chart chart; if None, a chart is picked in self._express

OUTPUT:

  • the coordinate expression of the scalar field in the given chart, either as a Sage’s symbolic expression or as a SymPy object, depending on the symbolic calculus method used on the chart

EXAMPLES:

Expression of a scalar field on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x*y^2)
sage: f.expr()
x*y^2
sage: f.expr(c_xy)  # equivalent form (since c_xy is the default chart)
x*y^2
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x*y**Integer(2))
>>> f.expr()
x*y^2
>>> f.expr(c_xy)  # equivalent form (since c_xy is the default chart)
x*y^2

Expression via a change of coordinates:

sage: c_uv.<u,v> = M.chart()
sage: c_uv.transition_map(c_xy, [u+v, u-v])
Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
sage: f._express # at this stage, f is expressed only in terms of (x,y) coordinates
{Chart (M, (x, y)): x*y^2}
sage: f.expr(c_uv) # forces the computation of the expression of f in terms of (u,v) coordinates
u^3 - u^2*v - u*v^2 + v^3
sage: bool( f.expr(c_uv) == (u+v)*(u-v)^2 ) # check
True
sage: f._express  # random (dict. output); f has now 2 coordinate expressions:
{Chart (M, (x, y)): x*y^2, Chart (M, (u, v)): u^3 - u^2*v - u*v^2 + v^3}
>>> from sage.all import *
>>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)
>>> c_uv.transition_map(c_xy, [u+v, u-v])
Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
>>> f._express # at this stage, f is expressed only in terms of (x,y) coordinates
{Chart (M, (x, y)): x*y^2}
>>> f.expr(c_uv) # forces the computation of the expression of f in terms of (u,v) coordinates
u^3 - u^2*v - u*v^2 + v^3
>>> bool( f.expr(c_uv) == (u+v)*(u-v)**Integer(2) ) # check
True
>>> f._express  # random (dict. output); f has now 2 coordinate expressions:
{Chart (M, (x, y)): x*y^2, Chart (M, (u, v)): u^3 - u^2*v - u*v^2 + v^3}

Note that the object returned by expr() depends on the symbolic backend used for coordinate computations:

sage: type(f.expr())
<class 'sage.symbolic.expression.Expression'>
sage: M.set_calculus_method('sympy')
sage: type(f.expr())
<class 'sympy.core.mul.Mul'>
sage: f.expr()  # note the SymPy exponent notation
x*y**2
>>> from sage.all import *
>>> type(f.expr())
<class 'sage.symbolic.expression.Expression'>
>>> M.set_calculus_method('sympy')
>>> type(f.expr())
<class 'sympy.core.mul.Mul'>
>>> f.expr()  # note the SymPy exponent notation
x*y**2
is_trivial_one()[source]#

Check if self is trivially equal to one without any simplification.

This method is supposed to be fast as compared with self == 1 and is intended to be used in library code where trying to obtain a mathematically correct result by applying potentially expensive rewrite rules is not desirable.

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: 1})
sage: f.is_trivial_one()
True
sage: f = M.scalar_field(1)
sage: f.is_trivial_one()
True
sage: M.one_scalar_field().is_trivial_one()
True
sage: f = M.scalar_field({X: x+y})
sage: f.is_trivial_one()
False
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: Integer(1)})
>>> f.is_trivial_one()
True
>>> f = M.scalar_field(Integer(1))
>>> f.is_trivial_one()
True
>>> M.one_scalar_field().is_trivial_one()
True
>>> f = M.scalar_field({X: x+y})
>>> f.is_trivial_one()
False

Scalar field defined by means of two charts:

sage: U1 = M.open_subset('U1'); X1.<x1,y1> = U1.chart()
sage: U2 = M.open_subset('U2'); X2.<x2,y2> = U2.chart()
sage: f = M.scalar_field({X1: 1, X2: 1})
sage: f.is_trivial_one()
True
sage: f = M.scalar_field({X1: 0, X2: 1})
sage: f.is_trivial_one()
False
>>> from sage.all import *
>>> U1 = M.open_subset('U1'); X1 = U1.chart(names=('x1', 'y1',)); (x1, y1,) = X1._first_ngens(2)
>>> U2 = M.open_subset('U2'); X2 = U2.chart(names=('x2', 'y2',)); (x2, y2,) = X2._first_ngens(2)
>>> f = M.scalar_field({X1: Integer(1), X2: Integer(1)})
>>> f.is_trivial_one()
True
>>> f = M.scalar_field({X1: Integer(0), X2: Integer(1)})
>>> f.is_trivial_one()
False

No simplification is attempted, so that False is returned for non-trivial cases:

sage: f = M.scalar_field({X: cos(x)^2 + sin(x)^2})
sage: f.is_trivial_one()
False
>>> from sage.all import *
>>> f = M.scalar_field({X: cos(x)**Integer(2) + sin(x)**Integer(2)})
>>> f.is_trivial_one()
False

On the contrary, the method is_zero() and the direct comparison to one involve some simplification algorithms and return True:

sage: (f - 1).is_zero()
True
sage: f == 1
True
>>> from sage.all import *
>>> (f - Integer(1)).is_zero()
True
>>> f == Integer(1)
True
is_trivial_zero()[source]#

Check if self is trivially equal to zero without any simplification.

This method is supposed to be fast as compared with self.is_zero() or self == 0 and is intended to be used in library code where trying to obtain a mathematically correct result by applying potentially expensive rewrite rules is not desirable.

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: 0})
sage: f.is_trivial_zero()
True
sage: f = M.scalar_field(0)
sage: f.is_trivial_zero()
True
sage: M.zero_scalar_field().is_trivial_zero()
True
sage: f = M.scalar_field({X: x+y})
sage: f.is_trivial_zero()
False
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: Integer(0)})
>>> f.is_trivial_zero()
True
>>> f = M.scalar_field(Integer(0))
>>> f.is_trivial_zero()
True
>>> M.zero_scalar_field().is_trivial_zero()
True
>>> f = M.scalar_field({X: x+y})
>>> f.is_trivial_zero()
False

Scalar field defined by means of two charts:

sage: U1 = M.open_subset('U1'); X1.<x1,y1> = U1.chart()
sage: U2 = M.open_subset('U2'); X2.<x2,y2> = U2.chart()
sage: f = M.scalar_field({X1: 0, X2: 0})
sage: f.is_trivial_zero()
True
sage: f = M.scalar_field({X1: 0, X2: 1})
sage: f.is_trivial_zero()
False
>>> from sage.all import *
>>> U1 = M.open_subset('U1'); X1 = U1.chart(names=('x1', 'y1',)); (x1, y1,) = X1._first_ngens(2)
>>> U2 = M.open_subset('U2'); X2 = U2.chart(names=('x2', 'y2',)); (x2, y2,) = X2._first_ngens(2)
>>> f = M.scalar_field({X1: Integer(0), X2: Integer(0)})
>>> f.is_trivial_zero()
True
>>> f = M.scalar_field({X1: Integer(0), X2: Integer(1)})
>>> f.is_trivial_zero()
False

No simplification is attempted, so that False is returned for non-trivial cases:

sage: f = M.scalar_field({X: cos(x)^2 + sin(x)^2 - 1})
sage: f.is_trivial_zero()
False
>>> from sage.all import *
>>> f = M.scalar_field({X: cos(x)**Integer(2) + sin(x)**Integer(2) - Integer(1)})
>>> f.is_trivial_zero()
False

On the contrary, the method is_zero() and the direct comparison to zero involve some simplification algorithms and return True:

sage: f.is_zero()
True
sage: f == 0
True
>>> from sage.all import *
>>> f.is_zero()
True
>>> f == Integer(0)
True
is_unit()[source]#

Return True iff self is not trivially zero in at least one of the given expressions since most scalar fields are invertible and a complete computation would take too much time.

EXAMPLES:

sage: M = Manifold(2, 'M', structure='top')
sage: one = M.scalar_field_algebra().one()
sage: one.is_unit()
True
sage: zero = M.scalar_field_algebra().zero()
sage: zero.is_unit()
False
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='top')
>>> one = M.scalar_field_algebra().one()
>>> one.is_unit()
True
>>> zero = M.scalar_field_algebra().zero()
>>> zero.is_unit()
False
log()[source]#

Natural logarithm of the scalar field.

OUTPUT:

  • the scalar field \(\ln f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x+y}, name='f', latex_name=r"\Phi")
sage: g = log(f) ; g
Scalar field ln(f) on the 2-dimensional topological manifold M
sage: g.display()
ln(f): M → ℝ
   (x, y) ↦ log(x + y)
sage: latex(g)
\ln\left(\Phi\right)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x+y}, name='f', latex_name=r"\Phi")
>>> g = log(f) ; g
Scalar field ln(f) on the 2-dimensional topological manifold M
>>> g.display()
ln(f): M → ℝ
   (x, y) ↦ log(x + y)
>>> latex(g)
\ln\left(\Phi\right)

The inverse function is exp():

sage: exp(log(f)) == f
True
>>> from sage.all import *
>>> exp(log(f)) == f
True
preimage(codomain_subset, name=None, latex_name=None)[source]#

Return the preimage of codomain_subset.

An alias is pullback().

INPUT:

  • codomain_subset – an instance of RealSet

  • name – string; name (symbol) given to the subset

  • latex_name – (default: None) string; LaTeX symbol to denote the subset; if none are provided, it is set to name

OUTPUT:

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x+y}, name='f')
sage: L = f.pullback(RealSet.point(1)); latex(L)
f^{-1}(\{1\})
sage: M((-1, 1)) in L
False
sage: M((0, 1)) in L
True

sage: M.zero_scalar_field().preimage(RealSet.point(0)) is M
True
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x+y}, name='f')
>>> L = f.pullback(RealSet.point(Integer(1))); latex(L)
f^{-1}(\{1\})
>>> M((-Integer(1), Integer(1))) in L
False
>>> M((Integer(0), Integer(1))) in L
True

>>> M.zero_scalar_field().preimage(RealSet.point(Integer(0))) is M
True
pullback(codomain_subset, name=None, latex_name=None)[source]#

Return the preimage of codomain_subset.

An alias is pullback().

INPUT:

  • codomain_subset – an instance of RealSet

  • name – string; name (symbol) given to the subset

  • latex_name – (default: None) string; LaTeX symbol to denote the subset; if none are provided, it is set to name

OUTPUT:

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x+y}, name='f')
sage: L = f.pullback(RealSet.point(1)); latex(L)
f^{-1}(\{1\})
sage: M((-1, 1)) in L
False
sage: M((0, 1)) in L
True

sage: M.zero_scalar_field().preimage(RealSet.point(0)) is M
True
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x+y}, name='f')
>>> L = f.pullback(RealSet.point(Integer(1))); latex(L)
f^{-1}(\{1\})
>>> M((-Integer(1), Integer(1))) in L
False
>>> M((Integer(0), Integer(1))) in L
True

>>> M.zero_scalar_field().preimage(RealSet.point(Integer(0))) is M
True
restrict(subdomain)[source]#

Restriction of the scalar field to an open subset of its domain of definition.

INPUT:

  • subdomain – an open subset of the scalar field’s domain

OUTPUT:

  • instance of ScalarField representing the restriction of the scalar field to subdomain

EXAMPLES:

Restriction of a scalar field defined on \(\RR^2\) to the unit open disc:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()  # Cartesian coordinates
sage: U = M.open_subset('U', coord_def={X: x^2+y^2 < 1}) # U unit open disc
sage: f = M.scalar_field(cos(x*y), name='f')
sage: f_U = f.restrict(U) ; f_U
Scalar field f on the Open subset U of the 2-dimensional
 topological manifold M
sage: f_U.display()
f: U → ℝ
   (x, y) ↦ cos(x*y)
sage: f.parent()
Algebra of scalar fields on the 2-dimensional topological
 manifold M
sage: f_U.parent()
Algebra of scalar fields on the Open subset U of the 2-dimensional
 topological manifold M
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)# Cartesian coordinates
>>> U = M.open_subset('U', coord_def={X: x**Integer(2)+y**Integer(2) < Integer(1)}) # U unit open disc
>>> f = M.scalar_field(cos(x*y), name='f')
>>> f_U = f.restrict(U) ; f_U
Scalar field f on the Open subset U of the 2-dimensional
 topological manifold M
>>> f_U.display()
f: U → ℝ
   (x, y) ↦ cos(x*y)
>>> f.parent()
Algebra of scalar fields on the 2-dimensional topological
 manifold M
>>> f_U.parent()
Algebra of scalar fields on the Open subset U of the 2-dimensional
 topological manifold M

The restriction to the whole domain is the identity:

sage: f.restrict(M) is f
True
sage: f_U.restrict(U) is f_U
True
>>> from sage.all import *
>>> f.restrict(M) is f
True
>>> f_U.restrict(U) is f_U
True

Restriction of the zero scalar field:

sage: M.zero_scalar_field().restrict(U)
Scalar field zero on the Open subset U of the 2-dimensional
 topological manifold M
sage: M.zero_scalar_field().restrict(U) is U.zero_scalar_field()
True
>>> from sage.all import *
>>> M.zero_scalar_field().restrict(U)
Scalar field zero on the Open subset U of the 2-dimensional
 topological manifold M
>>> M.zero_scalar_field().restrict(U) is U.zero_scalar_field()
True
set_calc_order(symbol, order, truncate=False)[source]#

Trigger a power series expansion with respect to a small parameter in computations involving the scalar field.

This property is propagated by usual operations. The internal representation must be SR for this to take effect.

If the small parameter is \(\epsilon\) and \(f\) is self, the power series expansion to order \(n\) is

\[f = f_0 + \epsilon f_1 + \epsilon^2 f_2 + \cdots + \epsilon^n f_n + O(\epsilon^{n+1}),\]

where \(f_0, f_1, \ldots, f_n\) are \(n+1\) scalar fields that do not depend upon \(\epsilon\).

INPUT:

  • symbol – symbolic variable (the “small parameter” \(\epsilon\)) with respect to which the coordinate expressions of self in various charts are expanded in power series (around the zero value of this variable)

  • order – integer; the order \(n\) of the expansion, defined as the degree of the polynomial representing the truncated power series in symbol

    Warning

    The order of the big \(O\) in the power series expansion is \(n+1\), where \(n\) is order.

  • truncate – (default: False) determines whether the coordinate expressions of self are replaced by their expansions to the given order

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: t = var('t')  # the small parameter
sage: f = M.scalar_field(exp(-t*x))
sage: f.expr()
e^(-t*x)
sage: f.set_calc_order(t, 2, truncate=True)
sage: f.expr()
1/2*t^2*x^2 - t*x + 1
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> t = var('t')  # the small parameter
>>> f = M.scalar_field(exp(-t*x))
>>> f.expr()
e^(-t*x)
>>> f.set_calc_order(t, Integer(2), truncate=True)
>>> f.expr()
1/2*t^2*x^2 - t*x + 1
set_expr(coord_expression, chart=None)[source]#

Set the coordinate expression of the scalar field.

The expressions with respect to other charts are deleted, in order to avoid any inconsistency. To keep them, use add_expr() instead.

INPUT:

  • coord_expression – coordinate expression of the scalar field

  • chart – (default: None) chart in which coord_expression is defined; if None, the default chart of the scalar field’s domain is assumed

EXAMPLES:

Setting scalar field expressions on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: f = M.scalar_field(x^2 + 2*x*y +1)
sage: f._express
{Chart (M, (x, y)): x^2 + 2*x*y + 1}
sage: f.set_expr(3*y)
sage: f._express  # the (x,y) expression has been changed:
{Chart (M, (x, y)): 3*y}
sage: c_uv.<u,v> = M.chart()
sage: f.set_expr(cos(u)-sin(v), c_uv)
sage: f._express # the (x,y) expression has been lost:
{Chart (M, (u, v)): cos(u) - sin(v)}
sage: f.set_expr(3*y)
sage: f._express # the (u,v) expression has been lost:
{Chart (M, (x, y)): 3*y}
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)
>>> f = M.scalar_field(x**Integer(2) + Integer(2)*x*y +Integer(1))
>>> f._express
{Chart (M, (x, y)): x^2 + 2*x*y + 1}
>>> f.set_expr(Integer(3)*y)
>>> f._express  # the (x,y) expression has been changed:
{Chart (M, (x, y)): 3*y}
>>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)
>>> f.set_expr(cos(u)-sin(v), c_uv)
>>> f._express # the (x,y) expression has been lost:
{Chart (M, (u, v)): cos(u) - sin(v)}
>>> f.set_expr(Integer(3)*y)
>>> f._express # the (u,v) expression has been lost:
{Chart (M, (x, y)): 3*y}

Since zero and one are special elements, their expressions cannot be changed:

sage: z = M.zero_scalar_field()
sage: z.set_expr(3*y)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
sage: one = M.one_scalar_field()
sage: one.set_expr(3*y)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
>>> from sage.all import *
>>> z = M.zero_scalar_field()
>>> z.set_expr(Integer(3)*y)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
>>> one = M.one_scalar_field()
>>> one.set_expr(Integer(3)*y)
Traceback (most recent call last):
...
ValueError: the expressions of an immutable element cannot be
 changed
set_immutable()[source]#

Set self and all restrictions of self immutable.

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})  # disk
sage: V = M.open_subset('U', coord_def={X: x>0})  # half plane
sage: f = M.scalar_field(x^2, name='f')
sage: fU = f.restrict(U)
sage: f.set_immutable()
sage: fU.is_immutable()
True
sage: f.restrict(V).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)})  # disk
>>> V = M.open_subset('U', coord_def={X: x>Integer(0)})  # half plane
>>> f = M.scalar_field(x**Integer(2), name='f')
>>> fU = f.restrict(U)
>>> f.set_immutable()
>>> fU.is_immutable()
True
>>> f.restrict(V).is_immutable()
True
set_name(name=None, latex_name=None)[source]#

Set (or change) the text name and LaTeX name of the scalar field.

INPUT:

  • name – (string; default: None) name given to the scalar field

  • latex_name – (string; default: None) LaTeX symbol to denote the scalar field; if None while name is provided, the LaTeX symbol is set to name

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x+y})
sage: f = M.scalar_field({X: x+y}); f
Scalar field on the 2-dimensional topological manifold M
sage: f.set_name('f'); f
Scalar field f on the 2-dimensional topological manifold M
sage: latex(f)
f
sage: f.set_name('f', latex_name=r'\Phi'); f
Scalar field f on the 2-dimensional topological manifold M
sage: latex(f)
\Phi
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x+y})
>>> f = M.scalar_field({X: x+y}); f
Scalar field on the 2-dimensional topological manifold M
>>> f.set_name('f'); f
Scalar field f on the 2-dimensional topological manifold M
>>> latex(f)
f
>>> f.set_name('f', latex_name=r'\Phi'); f
Scalar field f on the 2-dimensional topological manifold M
>>> latex(f)
\Phi
set_restriction(rst)[source]#

Define a restriction of self to some subdomain.

INPUT:

  • rstScalarField 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: f = M.scalar_field(name='f')
sage: g = U.scalar_field(x^2+y)
sage: f.set_restriction(g)
sage: f.display()
f: M → ℝ
on U: (x, y) ↦ x^2 + y
sage: f.restrict(U) == g
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
>>> f = M.scalar_field(name='f')
>>> g = U.scalar_field(x**Integer(2)+y)
>>> f.set_restriction(g)
>>> f.display()
f: M → ℝ
on U: (x, y) ↦ x^2 + y
>>> f.restrict(U) == g
True
sin()[source]#

Sine of the scalar field.

OUTPUT:

  • the scalar field \(\sin f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = sin(f) ; g
Scalar field sin(f) on the 2-dimensional topological manifold M
sage: latex(g)
\sin\left(\Phi\right)
sage: g.display()
sin(f): M → ℝ
   (x, y) ↦ sin(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = sin(f) ; g
Scalar field sin(f) on the 2-dimensional topological manifold M
>>> latex(g)
\sin\left(\Phi\right)
>>> g.display()
sin(f): M → ℝ
   (x, y) ↦ sin(x*y)

Some tests:

sage: sin(M.zero_scalar_field()) == M.zero_scalar_field()
True
sage: sin(M.constant_scalar_field(pi/2)) == M.constant_scalar_field(1)
True
>>> from sage.all import *
>>> sin(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> sin(M.constant_scalar_field(pi/Integer(2))) == M.constant_scalar_field(Integer(1))
True
sinh()[source]#

Hyperbolic sine of the scalar field.

OUTPUT:

  • the scalar field \(\sinh f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = sinh(f) ; g
Scalar field sinh(f) on the 2-dimensional topological manifold M
sage: latex(g)
\sinh\left(\Phi\right)
sage: g.display()
sinh(f): M → ℝ
   (x, y) ↦ sinh(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = sinh(f) ; g
Scalar field sinh(f) on the 2-dimensional topological manifold M
>>> latex(g)
\sinh\left(\Phi\right)
>>> g.display()
sinh(f): M → ℝ
   (x, y) ↦ sinh(x*y)

Some test:

sage: sinh(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> from sage.all import *
>>> sinh(M.zero_scalar_field()) == M.zero_scalar_field()
True
sqrt()[source]#

Square root of the scalar field.

OUTPUT:

  • the scalar field \(\sqrt f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: 1+x^2+y^2}, name='f',
....:                    latex_name=r"\Phi")
sage: g = sqrt(f) ; g
Scalar field sqrt(f) on the 2-dimensional topological manifold M
sage: latex(g)
\sqrt{\Phi}
sage: g.display()
sqrt(f): M → ℝ
   (x, y) ↦ sqrt(x^2 + y^2 + 1)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: Integer(1)+x**Integer(2)+y**Integer(2)}, name='f',
...                    latex_name=r"\Phi")
>>> g = sqrt(f) ; g
Scalar field sqrt(f) on the 2-dimensional topological manifold M
>>> latex(g)
\sqrt{\Phi}
>>> g.display()
sqrt(f): M → ℝ
   (x, y) ↦ sqrt(x^2 + y^2 + 1)

Some tests:

sage: g^2 == f
True
sage: sqrt(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> from sage.all import *
>>> g**Integer(2) == f
True
>>> sqrt(M.zero_scalar_field()) == M.zero_scalar_field()
True
tan()[source]#

Tangent of the scalar field.

OUTPUT:

  • the scalar field \(\tan f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = tan(f) ; g
Scalar field tan(f) on the 2-dimensional topological manifold M
sage: latex(g)
\tan\left(\Phi\right)
sage: g.display()
tan(f): M → ℝ
   (x, y) ↦ sin(x*y)/cos(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = tan(f) ; g
Scalar field tan(f) on the 2-dimensional topological manifold M
>>> latex(g)
\tan\left(\Phi\right)
>>> g.display()
tan(f): M → ℝ
   (x, y) ↦ sin(x*y)/cos(x*y)

Some tests:

sage: tan(f) == sin(f) / cos(f)
True
sage: tan(M.zero_scalar_field()) == M.zero_scalar_field()
True
sage: tan(M.constant_scalar_field(pi/4)) == M.constant_scalar_field(1)
True
>>> from sage.all import *
>>> tan(f) == sin(f) / cos(f)
True
>>> tan(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> tan(M.constant_scalar_field(pi/Integer(4))) == M.constant_scalar_field(Integer(1))
True
tanh()[source]#

Hyperbolic tangent of the scalar field.

OUTPUT:

  • the scalar field \(\tanh f\), where \(f\) is the current scalar field

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
sage: g = tanh(f) ; g
Scalar field tanh(f) on the 2-dimensional topological manifold M
sage: latex(g)
\tanh\left(\Phi\right)
sage: g.display()
tanh(f): M → ℝ
   (x, y) ↦ sinh(x*y)/cosh(x*y)
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'M', structure='topological')
>>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
>>> f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
>>> g = tanh(f) ; g
Scalar field tanh(f) on the 2-dimensional topological manifold M
>>> latex(g)
\tanh\left(\Phi\right)
>>> g.display()
tanh(f): M → ℝ
   (x, y) ↦ sinh(x*y)/cosh(x*y)

Some tests:

sage: tanh(f) == sinh(f) / cosh(f)
True
sage: tanh(M.zero_scalar_field()) == M.zero_scalar_field()
True
>>> from sage.all import *
>>> tanh(f) == sinh(f) / cosh(f)
True
>>> tanh(M.zero_scalar_field()) == M.zero_scalar_field()
True