Chart Functions - Manifolds

Skip to content
Back to top
View this page
Edit this page

# Chart Functions

In the context of a topological manifold \(M\) over a topological field \(K\), a chart function is a function from a chart codomain to \(K\). In other words, a chart function is a \(K\)-valued function of the coordinates associated to some chart. The internal coordinate expressions of chart functions and calculus on them are taken in charge by different calculus methods, at the choice of the user:

- Sage’s default symbolic engine (Pynac + Maxima), implemented via the Symbolic Ring (`SR`)

- SymPy engine, denoted `sympy` hereafter

See `CalculusMethod` for details.

AUTHORS:

- Marco Mancini (2017) : initial version

- Eric Gourgoulhon (2015) : for a previous class implementing only SR calculus (CoordFunctionSymb)

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

class sage.manifolds.chart_func.ChartFunction(parent, expression=None, calc_method=None, expansion_symbol=None, order=None)

  Bases: `AlgebraElement`, `ModuleElementWithMutability`

  Function of coordinates of a given chart.

  If \((U, \varphi)\) is a chart on a topological manifold \(M\) of dimension \(n\) over a topological field \(K\), a chart function associated to \((U, \varphi)\) is a map

  \[\begin{split}\begin{array}{llcl} f:& V \subset K^n & \longrightarrow & K \\ & (x^1, \ldots, x^n) & \longmapsto & f(x^1, \ldots, x^n), \end{array}\end{split}\]

  where \(V\) is the codomain of \(\varphi\). In other words, \(f\) is a \(K\)-valued function of the coordinates associated to the chart \((U, \varphi)\).

  The chart function \(f\) can be represented by expressions pertaining to different calculus methods; the currently implemented ones are

  - `SR` (Sage’s Symbolic Ring)

  - `SymPy`

  See `expr()` for details.

  INPUT:

  - `parent` – the algebra of chart functions on the chart \((U, \varphi)\)

  - `expression` – (default: `None`) a symbolic expression representing \(f(x^1, \ldots, x^n)\), where \((x^1, \ldots, x^n)\) are the coordinates of the chart \((U, \varphi)\)

  - `calc_method` – string (default: `None`); the calculus method with respect to which the internal expression of `self` must be initialized from `expression`. One of

    - `'SR'`: Sage’s default symbolic engine (Symbolic Ring)

    - `'sympy'`: SymPy

    - `None`: the chart current calculus method is assumed

  - `expansion_symbol` – (default: `None`) symbolic variable (the “small parameter”) with respect to which the coordinate expression is expanded in power series (around the zero value of this variable)

  - `order` – integer (default: `None`); the order of the expansion if `expansion_symbol` is not `None`; the order is defined as the degree of the polynomial representing the truncated power series in `expansion_symbol`

    Warning

    The value of `order` is \(n-1\), where \(n\) is the order of the big \(O\) in the power series expansion

  EXAMPLES:

  A symbolic chart function on a 2-dimensional manifold:

  Sage

      sage: M = Manifold(2, 'M', structure='topological')
      sage: X.<x,y> = M.chart()
      sage: f = X.function(x^2+3*y+1)
      sage: type(f)
      <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
      sage: f.display()
      (x, y) ↦ x^2 + 3*y + 1
      sage: f(x,y)
      x^2 + 3*y + 1

  Python

      >>> from sage.all import *
      >>> M = Manifold(Integer(2), 'M', structure='topological')
      >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
      >>> f = X.function(x**Integer(2)+Integer(3)*y+Integer(1))
      >>> type(f)
      <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
      >>> f.display()
      (x, y) ↦ x^2 + 3*y + 1
      >>> f(x,y)
      x^2 + 3*y + 1

  The symbolic expression is returned when asking for the direct display of the function:

  Sage

      sage: f
      x^2 + 3*y + 1
      sage: latex(f)
      x^{2} + 3 \, y + 1

  [Python]

      >>> from sage.all import *
      >>> f
      x^2 + 3*y + 1
      >>> latex(f)
      x^{2} + 3 \, y + 1

  A similar output is obtained by means of the method `expr()`:

  Sage

      sage: f.expr()
      x^2 + 3*y + 1

  Python

      >>> from sage.all import *
      >>> f.expr()
      x^2 + 3*y + 1

  The expression returned by `expr()` is by default a Sage symbolic expression:

  Sage

      sage: type(f.expr())
      <class 'sage.symbolic.expression.Expression'>

  [Python]

      >>> from sage.all import *
      >>> type(f.expr())
      <class 'sage.symbolic.expression.Expression'>

  A SymPy expression can also be asked for:

  Sage

      sage: f.expr('sympy')
      x**2 + 3*y + 1
      sage: type(f.expr('sympy'))
      <class 'sympy.core.add.Add'>

  Python

      >>> from sage.all import *
      >>> f.expr('sympy')
      x**2 + 3*y + 1
      >>> type(f.expr('sympy'))
      <class 'sympy.core.add.Add'>

  The value of the function at specified coordinates is obtained by means of the standard parentheses notation:

  Sage

      sage: f(2,-1)
      2
      sage: var('a b')
      (a, b)
      sage: f(a,b)
      a^2 + 3*b + 1

  [Python]

      >>> from sage.all import *
      >>> f(Integer(2),-Integer(1))
      2
      >>> var('a b')
      (a, b)
      >>> f(a,b)
      a^2 + 3*b + 1

  An unspecified chart function:

  Sage

      sage: g = X.function(function('G')(x, y))
      sage: g
      G(x, y)
      sage: g.display()
      (x, y) ↦ G(x, y)
      sage: g.expr()
      G(x, y)
      sage: g(2,3)
      G(2, 3)

  Python

      >>> from sage.all import *
      >>> g = X.function(function('G')(x, y))
      >>> g
      G(x, y)
      >>> g.display()
      (x, y) ↦ G(x, y)
      >>> g.expr()
      G(x, y)
      >>> g(Integer(2),Integer(3))
      G(2, 3)

  Coordinate functions can be compared to other values:

  Sage

      sage: f = X.function(x^2+3*y+1)
      sage: f == 2
      False
      sage: f == x^2 + 3*y + 1
      True
      sage: g = X.function(x*y)
      sage: f == g
      False
      sage: h = X.function(x^2+3*y+1)
      sage: f == h
      True

  [Python]

      >>> from sage.all import *
      >>> f = X.function(x**Integer(2)+Integer(3)*y+Integer(1))
      >>> f == Integer(2)
      False
      >>> f == x**Integer(2) + Integer(3)*y + Integer(1)
      True
      >>> g = X.function(x*y)
      >>> f == g
      False
      >>> h = X.function(x**Integer(2)+Integer(3)*y+Integer(1))
      >>> f == h
      True

  A coercion by means of the restriction is implemented:

  Sage

      sage: D = M.open_subset('D')
      sage: X_D = X.restrict(D, x^2+y^2<1)  # open disk
      sage: c = X_D.function(x^2)
      sage: c + f
      2*x^2 + 3*y + 1

  Python

      >>> from sage.all import *
      >>> D = M.open_subset('D')
      >>> X_D = X.restrict(D, x**Integer(2)+y**Integer(2)<Integer(1))  # open disk
      >>> c = X_D.function(x**Integer(2))
      >>> c + f
      2*x^2 + 3*y + 1

  Expansion to a given order with respect to a small parameter:

  Sage

      sage: t = var('t')  # the small parameter
      sage: f = X.function(cos(t)*x*y, expansion_symbol=t, order=2)

  [Python]

      >>> from sage.all import *
      >>> t = var('t')  # the small parameter
      >>> f = X.function(cos(t)*x*y, expansion_symbol=t, order=Integer(2))

  The expansion is triggered by the call to `simplify()`:

  Sage

      sage: f
      x*y*cos(t)
      sage: f.simplify()
      -1/2*t^2*x*y + x*y

  Python

      >>> from sage.all import *
      >>> f
      x*y*cos(t)
      >>> f.simplify()
      -1/2*t^2*x*y + x*y

  Differences between `ChartFunction` and callable symbolic expressions

  Callable symbolic expressions are defined directly from symbolic expressions of the coordinates:

  Sage

      sage: f0(x,y) = x^2 + 3*y + 1
      sage: type(f0)
      <class 'sage.symbolic.expression.Expression'>
      sage: f0
      (x, y) |--> x^2 + 3*y + 1
      sage: f0(x,y)
      x^2 + 3*y + 1

  [Python]

      >>> from sage.all import *
      >>> __tmp__=var("x,y"); f0 = symbolic_expression(x**Integer(2) + Integer(3)*y + Integer(1)).function(x,y)
      >>> type(f0)
      <class 'sage.symbolic.expression.Expression'>
      >>> f0
      (x, y) |--> x^2 + 3*y + 1
      >>> f0(x,y)
      x^2 + 3*y + 1

  To get an output similar to that of `f0` for a chart function, we must use the method `display()`:

  Sage

      sage: f = X.function(x^2+3*y+1)
      sage: f
      x^2 + 3*y + 1
      sage: f.display()
      (x, y) ↦ x^2 + 3*y + 1
      sage: f(x,y)
      x^2 + 3*y + 1

  Python

      >>> from sage.all import *
      >>> f = X.function(x**Integer(2)+Integer(3)*y+Integer(1))
      >>> f
      x^2 + 3*y + 1
      >>> f.display()
      (x, y) ↦ x^2 + 3*y + 1
      >>> f(x,y)
      x^2 + 3*y + 1

  More importantly, instances of `ChartFunction` differ from callable symbolic expression by the automatic simplifications in all operations. For instance, adding the two callable symbolic expressions:

  Sage

      sage: f0(x,y,z) = cos(x)^2 ; g0(x,y,z) = sin(x)^2

  [Python]

      >>> from sage.all import *
      >>> __tmp__=var("x,y,z"); f0 = symbolic_expression(cos(x)**Integer(2) ).function(x,y,z); __tmp__=var("x,y,z"); g0 = symbolic_expression(sin(x)**Integer(2)).function(x,y,z)

  results in:

  Sage

      sage: f0 + g0
      (x, y, z) |--> cos(x)^2 + sin(x)^2

  Python

      >>> from sage.all import *
      >>> f0 + g0
      (x, y, z) |--> cos(x)^2 + sin(x)^2

  To get \(1\), one has to call `simplify_trig()`:

  Sage

      sage: (f0 + g0).simplify_trig()
      (x, y, z) |--> 1

  [Python]

      >>> from sage.all import *
      >>> (f0 + g0).simplify_trig()
      (x, y, z) |--> 1

  On the contrary, the sum of the corresponding `ChartFunction` instances is automatically simplified (see `simplify_chain_real()` and `simplify_chain_generic()` for details):

  Sage

      sage: f = X.function(cos(x)^2) ; g = X.function(sin(x)^2)
      sage: f + g
      1

  Python

      >>> from sage.all import *
      >>> f = X.function(cos(x)**Integer(2)) ; g = X.function(sin(x)**Integer(2))
      >>> f + g
      1

  Another difference regards the display of partial derivatives: for callable symbolic functions, it involves `diff`:

  Sage

      sage: g = function('g')(x, y)
      sage: f0(x,y) = diff(g, x) + diff(g, y)
      sage: f0
      (x, y) |--> diff(g(x, y), x) + diff(g(x, y), y)

  [Python]

      >>> from sage.all import *
      >>> g = function('g')(x, y)
      >>> __tmp__=var("x,y"); f0 = symbolic_expression(diff(g, x) + diff(g, y)).function(x,y)
      >>> f0
      (x, y) |--> diff(g(x, y), x) + diff(g(x, y), y)

  while for chart functions, the display is more “textbook” like:

  Sage

      sage: f = X.function(diff(g, x) + diff(g, y))
      sage: f
      d(g)/dx + d(g)/dy

  Python

      >>> from sage.all import *
      >>> f = X.function(diff(g, x) + diff(g, y))
      >>> f
      d(g)/dx + d(g)/dy

  The difference is even more dramatic on LaTeX outputs:

  Sage

      sage: latex(f0)
      \left( x, y \right) \ {\mapsto} \ \frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
      sage: latex(f)
      \frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}

  [Python]

      >>> from sage.all import *
      >>> latex(f0)
      \left( x, y \right) \ {\mapsto} \ \frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
      >>> latex(f)
      \frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}

  Note that this regards only the display of coordinate functions: internally, the `diff` notation is still used, as we can check by asking for the symbolic expression stored in `f`:

  Sage

      sage: f.expr()
      diff(g(x, y), x) + diff(g(x, y), y)

  Python

      >>> from sage.all import *
      >>> f.expr()
      diff(g(x, y), x) + diff(g(x, y), y)

  One can switch to Pynac notation by changing the options:

  Sage

      sage: Manifold.options.textbook_output=False
      sage: latex(f)
      \frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
      sage: Manifold.options._reset()
      sage: latex(f)
      \frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}

  [Python]

      >>> from sage.all import *
      >>> Manifold.options.textbook_output=False
      >>> latex(f)
      \frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
      >>> Manifold.options._reset()
      >>> latex(f)
      \frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}

  Another difference between `ChartFunction` and callable symbolic expression is the possibility to switch off the display of the arguments of unspecified functions. Consider for instance:

  Sage

      sage: f = X.function(function('u')(x, y) * function('v')(x, y))
      sage: f
      u(x, y)*v(x, y)
      sage: f0(x,y) = function('u')(x, y) * function('v')(x, y)
      sage: f0
      (x, y) |--> u(x, y)*v(x, y)

  Python

      >>> from sage.all import *
      >>> f = X.function(function('u')(x, y) * function('v')(x, y))
      >>> f
      u(x, y)*v(x, y)
      >>> __tmp__=var("x,y"); f0 = symbolic_expression(function('u')(x, y) * function('v')(x, y)).function(x,y)
      >>> f0
      (x, y) |--> u(x, y)*v(x, y)

  If there is a clear understanding that \(u\) and \(v\) are functions of \((x,y)\), the explicit mention of the latter can be cumbersome in lengthy tensor expressions. We can switch it off by:

  Sage

      sage: Manifold.options.omit_function_arguments=True
      sage: f
      u*v

  [Python]

      >>> from sage.all import *
      >>> Manifold.options.omit_function_arguments=True
      >>> f
      u*v

  Note that neither the callable symbolic expression `f0` nor the internal expression of `f` is affected by the above command:

  Sage

      sage: f0
      (x, y) |--> u(x, y)*v(x, y)
      sage: f.expr()
      u(x, y)*v(x, y)

  Python

      >>> from sage.all import *
      >>> f0
      (x, y) |--> u(x, y)*v(x, y)
      >>> f.expr()
      u(x, y)*v(x, y)

  We revert to the default behavior by:

  Sage

      sage: Manifold.options._reset()
      sage: f
      u(x, y)*v(x, y)

  [Python]

      >>> from sage.all import *
      >>> Manifold.options._reset()
      >>> f
      u(x, y)*v(x, y)

  __call__(*coords, **options)

    Compute the value of the function at specified coordinates.

    INPUT:

    - `*coords` – list of coordinates \((x^1, \ldots, x^n)\), where the function \(f\) is to be evaluated

    - `**options` – allows to pass `simplify=False` to disable the call of the simplification chain on the result

    OUTPUT:

    - the value \(f(x^1, \ldots, x^n)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(sin(x*y))
        sage: f.__call__(-2, 3)
        -sin(6)
        sage: f(-2, 3)
        -sin(6)
        sage: var('a b')
        (a, b)
        sage: f.__call__(a, b)
        sin(a*b)
        sage: f(a,b)
        sin(a*b)
        sage: f.__call__(pi, 1)
        0
        sage: f.__call__(pi, 1/2)
        1

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(sin(x*y))
        >>> f.__call__(-Integer(2), Integer(3))
        -sin(6)
        >>> f(-Integer(2), Integer(3))
        -sin(6)
        >>> var('a b')
        (a, b)
        >>> f.__call__(a, b)
        sin(a*b)
        >>> f(a,b)
        sin(a*b)
        >>> f.__call__(pi, Integer(1))
        0
        >>> f.__call__(pi, Integer(1)/Integer(2))
        1

    With SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f(-2,3)
        -sin(6)
        sage: type(f(-2,3))
        <class 'sympy.core.mul.Mul'>
        sage: f(a,b)
        sin(a*b)
        sage: type(f(a,b))
        sin
        sage: type(f(pi,1))
        <class 'sympy.core.numbers.Zero'>
        sage: f(pi, 1/2)
        1
        sage: type(f(pi, 1/2))
        <class 'sympy.core.numbers.One'>

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f(-Integer(2),Integer(3))
        -sin(6)
        >>> type(f(-Integer(2),Integer(3)))
        <class 'sympy.core.mul.Mul'>
        >>> f(a,b)
        sin(a*b)
        >>> type(f(a,b))
        sin
        >>> type(f(pi,Integer(1)))
        <class 'sympy.core.numbers.Zero'>
        >>> f(pi, Integer(1)/Integer(2))
        1
        >>> type(f(pi, Integer(1)/Integer(2)))
        <class 'sympy.core.numbers.One'>

  arccos()

    Arc cosine of `self`.

    OUTPUT:

    - chart function \(\arccos(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.arccos()
        arccos(x*y)
        sage: arccos(f)  # equivalent to f.arccos()
        arccos(x*y)
        sage: acos(f)  # equivalent to f.arccos()
        arccos(x*y)
        sage: arccos(f).display()
        (x, y) ↦ arccos(x*y)
        sage: arccos(X.zero_function()).display()
        (x, y) ↦ 1/2*pi

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.arccos()
        arccos(x*y)
        >>> arccos(f)  # equivalent to f.arccos()
        arccos(x*y)
        >>> acos(f)  # equivalent to f.arccos()
        arccos(x*y)
        >>> arccos(f).display()
        (x, y) ↦ arccos(x*y)
        >>> arccos(X.zero_function()).display()
        (x, y) ↦ 1/2*pi

    The same test with SymPy:

    Sage

        sage: M.set_calculus_method('sympy')
        sage: f = X.function(x*y)
        sage: f.arccos()
        acos(x*y)
        sage: arccos(f)  # equivalent to f.arccos()
        acos(x*y)
        sage: acos(f)  # equivalent to f.arccos()
        acos(x*y)
        sage: arccos(f).display()
        (x, y) ↦ acos(x*y)

    [Python]

        >>> from sage.all import *
        >>> M.set_calculus_method('sympy')
        >>> f = X.function(x*y)
        >>> f.arccos()
        acos(x*y)
        >>> arccos(f)  # equivalent to f.arccos()
        acos(x*y)
        >>> acos(f)  # equivalent to f.arccos()
        acos(x*y)
        >>> arccos(f).display()
        (x, y) ↦ acos(x*y)

  arccosh()

    Inverse hyperbolic cosine of `self`.

    OUTPUT:

    - chart function \(\mathrm{arccosh}(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.arccosh()
        arccosh(x*y)
        sage: arccosh(f)  # equivalent to f.arccosh()
        arccosh(x*y)
        sage: acosh(f)  # equivalent to f.arccosh()
        arccosh(x*y)
        sage: arccosh(f).display()
        (x, y) ↦ arccosh(x*y)
        sage: arccosh(X.function(1)) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.arccosh()
        arccosh(x*y)
        >>> arccosh(f)  # equivalent to f.arccosh()
        arccosh(x*y)
        >>> acosh(f)  # equivalent to f.arccosh()
        arccosh(x*y)
        >>> arccosh(f).display()
        (x, y) ↦ arccosh(x*y)
        >>> arccosh(X.function(Integer(1))) == X.zero_function()
        True

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.arccosh()
        acosh(x*y)
        sage: arccosh(f)  # equivalent to f.arccosh()
        acosh(x*y)
        sage: acosh(f)  # equivalent to f.arccosh()
        acosh(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.arccosh()
        acosh(x*y)
        >>> arccosh(f)  # equivalent to f.arccosh()
        acosh(x*y)
        >>> acosh(f)  # equivalent to f.arccosh()
        acosh(x*y)

  arcsin()

    Arc sine of `self`.

    OUTPUT:

    - chart function \(\arcsin(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.arcsin()
        arcsin(x*y)
        sage: arcsin(f)  # equivalent to f.arcsin()
        arcsin(x*y)
        sage: asin(f)  # equivalent to f.arcsin()
        arcsin(x*y)
        sage: arcsin(f).display()
        (x, y) ↦ arcsin(x*y)
        sage: arcsin(X.zero_function()) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.arcsin()
        arcsin(x*y)
        >>> arcsin(f)  # equivalent to f.arcsin()
        arcsin(x*y)
        >>> asin(f)  # equivalent to f.arcsin()
        arcsin(x*y)
        >>> arcsin(f).display()
        (x, y) ↦ arcsin(x*y)
        >>> arcsin(X.zero_function()) == X.zero_function()
        True

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.arcsin()
        asin(x*y)
        sage: arcsin(f)  # equivalent to f.arcsin()
        asin(x*y)
        sage: asin(f)  # equivalent to f.arcsin()
        asin(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.arcsin()
        asin(x*y)
        >>> arcsin(f)  # equivalent to f.arcsin()
        asin(x*y)
        >>> asin(f)  # equivalent to f.arcsin()
        asin(x*y)

  arcsinh()

    Inverse hyperbolic sine of `self`.

    OUTPUT:

    - chart function \(\mathrm{arcsinh}(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.arcsinh()
        arcsinh(x*y)
        sage: arcsinh(f)  # equivalent to f.arcsinh()
        arcsinh(x*y)
        sage: asinh(f)  # equivalent to f.arcsinh()
        arcsinh(x*y)
        sage: arcsinh(f).display()
        (x, y) ↦ arcsinh(x*y)
        sage: arcsinh(X.zero_function()) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.arcsinh()
        arcsinh(x*y)
        >>> arcsinh(f)  # equivalent to f.arcsinh()
        arcsinh(x*y)
        >>> asinh(f)  # equivalent to f.arcsinh()
        arcsinh(x*y)
        >>> arcsinh(f).display()
        (x, y) ↦ arcsinh(x*y)
        >>> arcsinh(X.zero_function()) == X.zero_function()
        True

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.arcsinh()
        asinh(x*y)
        sage: arcsinh(f)  # equivalent to f.arcsinh()
        asinh(x*y)
        sage: asinh(f)  # equivalent to f.arcsinh()
        asinh(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.arcsinh()
        asinh(x*y)
        >>> arcsinh(f)  # equivalent to f.arcsinh()
        asinh(x*y)
        >>> asinh(f)  # equivalent to f.arcsinh()
        asinh(x*y)

  arctan()

    Arc tangent of `self`.

    OUTPUT:

    - chart function \(\arctan(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.arctan()
        arctan(x*y)
        sage: arctan(f)  # equivalent to f.arctan()
        arctan(x*y)
        sage: atan(f)  # equivalent to f.arctan()
        arctan(x*y)
        sage: arctan(f).display()
        (x, y) ↦ arctan(x*y)
        sage: arctan(X.zero_function()) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.arctan()
        arctan(x*y)
        >>> arctan(f)  # equivalent to f.arctan()
        arctan(x*y)
        >>> atan(f)  # equivalent to f.arctan()
        arctan(x*y)
        >>> arctan(f).display()
        (x, y) ↦ arctan(x*y)
        >>> arctan(X.zero_function()) == X.zero_function()
        True

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.arctan()
        atan(x*y)
        sage: arctan(f)  # equivalent to f.arctan()
        atan(x*y)
        sage: atan(f)  # equivalent to f.arctan()
        atan(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.arctan()
        atan(x*y)
        >>> arctan(f)  # equivalent to f.arctan()
        atan(x*y)
        >>> atan(f)  # equivalent to f.arctan()
        atan(x*y)

  arctanh()

    Inverse hyperbolic tangent of `self`.

    OUTPUT:

    - chart function \(\mathrm{arctanh}(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.arctanh()
        arctanh(x*y)
        sage: arctanh(f)  # equivalent to f.arctanh()
        arctanh(x*y)
        sage: atanh(f)  # equivalent to f.arctanh()
        arctanh(x*y)
        sage: arctanh(f).display()
        (x, y) ↦ arctanh(x*y)
        sage: arctanh(X.zero_function()) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.arctanh()
        arctanh(x*y)
        >>> arctanh(f)  # equivalent to f.arctanh()
        arctanh(x*y)
        >>> atanh(f)  # equivalent to f.arctanh()
        arctanh(x*y)
        >>> arctanh(f).display()
        (x, y) ↦ arctanh(x*y)
        >>> arctanh(X.zero_function()) == X.zero_function()
        True

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.arctanh()
        atanh(x*y)
        sage: arctanh(f)  # equivalent to f.arctanh()
        atanh(x*y)
        sage: atanh(f)  # equivalent to f.arctanh()
        atanh(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.arctanh()
        atanh(x*y)
        >>> arctanh(f)  # equivalent to f.arctanh()
        atanh(x*y)
        >>> atanh(f)  # equivalent to f.arctanh()
        atanh(x*y)

  chart()

    Return the chart with respect to which `self` is defined.

    OUTPUT: a `Chart`

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(1+x+y^2)
        sage: f.chart()
        Chart (M, (x, y))
        sage: f.chart() is X
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(Integer(1)+x+y**Integer(2))
        >>> f.chart()
        Chart (M, (x, y))
        >>> f.chart() is X
        True

  collect(s)

    Collect the coefficients of \(s\) in the expression of `self` into a group.

    INPUT:

    - `s` – the symbol whose coefficients will be collected

    OUTPUT:

    - `self` with the coefficients of `s` grouped in its expression

    EXAMPLES:

    Action on a 2-dimensional chart function:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x^2*y + x*y + (x*y)^2)
        sage: f.display()
        (x, y) ↦ x^2*y^2 + x^2*y + x*y
        sage: f.collect(y)
        x^2*y^2 + (x^2 + x)*y

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x**Integer(2)*y + x*y + (x*y)**Integer(2))
        >>> f.display()
        (x, y) ↦ x^2*y^2 + x^2*y + x*y
        >>> f.collect(y)
        x^2*y^2 + (x^2 + x)*y

    The method `collect()` has changed the expression of `f`:

    Sage

        sage: f.display()
        (x, y) ↦ x^2*y^2 + (x^2 + x)*y

    [Python]

        >>> from sage.all import *
        >>> f.display()
        (x, y) ↦ x^2*y^2 + (x^2 + x)*y

    The same test with SymPy

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f = X.function(x^2*y + x*y + (x*y)^2)
        sage: f.display()
        (x, y) ↦ x**2*y**2 + x**2*y + x*y
        sage: f.collect(y)
        x**2*y**2 + y*(x**2 + x)

    Python

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f = X.function(x**Integer(2)*y + x*y + (x*y)**Integer(2))
        >>> f.display()
        (x, y) ↦ x**2*y**2 + x**2*y + x*y
        >>> f.collect(y)
        x**2*y**2 + y*(x**2 + x)

  collect_common_factors()

    Collect common factors in the expression of `self`.

    This method does not perform a full factorization but only looks for factors which are already explicitly present.

    OUTPUT:

    - `self` with the common factors collected in its expression

    EXAMPLES:

    Action on a 2-dimensional chart function:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x/(x^2*y + x*y))
        sage: f.display()
        (x, y) ↦ x/(x^2*y + x*y)
        sage: f.collect_common_factors()
        1/((x + 1)*y)

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x/(x**Integer(2)*y + x*y))
        >>> f.display()
        (x, y) ↦ x/(x^2*y + x*y)
        >>> f.collect_common_factors()
        1/((x + 1)*y)

    The method `collect_common_factors()` has changed the expression of `f`:

    Sage

        sage: f.display()
        (x, y) ↦ 1/((x + 1)*y)

    [Python]

        >>> from sage.all import *
        >>> f.display()
        (x, y) ↦ 1/((x + 1)*y)

    The same test with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: g = X.function(x/(x^2*y + x*y))
        sage: g.display()
        (x, y) ↦ x/(x**2*y + x*y)
        sage: g.collect_common_factors()
        1/(y*(x + 1))

    Python

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> g = X.function(x/(x**Integer(2)*y + x*y))
        >>> g.display()
        (x, y) ↦ x/(x**2*y + x*y)
        >>> g.collect_common_factors()
        1/(y*(x + 1))

  copy()

    Return an exact copy of the object.

    OUTPUT: a `ChartFunctionSymb`

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x+y^2)
        sage: g = f.copy(); g
        y^2 + x

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x+y**Integer(2))
        >>> g = f.copy(); g
        y^2 + x

    By construction, `g` is identical to `f`:

    Sage

        sage: type(g) == type(f)
        True
        sage: g == f
        True

    [Python]

        >>> from sage.all import *
        >>> type(g) == type(f)
        True
        >>> g == f
        True

    but it is not the same object:

    Sage

        sage: g is f
        False

    Python

        >>> from sage.all import *
        >>> g is f
        False

  cos()

    Cosine of `self`.

    OUTPUT:

    - chart function \(\cos(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.cos()
        cos(x*y)
        sage: cos(f)  # equivalent to f.cos()
        cos(x*y)
        sage: cos(f).display()
        (x, y) ↦ cos(x*y)
        sage: cos(X.zero_function()).display()
        (x, y) ↦ 1

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.cos()
        cos(x*y)
        >>> cos(f)  # equivalent to f.cos()
        cos(x*y)
        >>> cos(f).display()
        (x, y) ↦ cos(x*y)
        >>> cos(X.zero_function()).display()
        (x, y) ↦ 1

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.cos()
        cos(x*y)
        sage: cos(f)  # equivalent to f.cos()
        cos(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.cos()
        cos(x*y)
        >>> cos(f)  # equivalent to f.cos()
        cos(x*y)

  cosh()

    Hyperbolic cosine of `self`.

    OUTPUT:

    - chart function \(\cosh(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.cosh()
        cosh(x*y)
        sage: cosh(f)  # equivalent to f.cosh()
        cosh(x*y)
        sage: cosh(f).display()
        (x, y) ↦ cosh(x*y)
        sage: cosh(X.zero_function()).display()
        (x, y) ↦ 1

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.cosh()
        cosh(x*y)
        >>> cosh(f)  # equivalent to f.cosh()
        cosh(x*y)
        >>> cosh(f).display()
        (x, y) ↦ cosh(x*y)
        >>> cosh(X.zero_function()).display()
        (x, y) ↦ 1

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.cosh()
        cosh(x*y)
        sage: cosh(f)  # equivalent to f.cosh()
        cosh(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.cosh()
        cosh(x*y)
        >>> cosh(f)  # equivalent to f.cosh()
        cosh(x*y)

  derivative(coord)

    Partial derivative with respect to a coordinate.

    INPUT:

    - `coord` – either the coordinate \(x^i\) with respect to which the derivative of the chart function \(f\) is to be taken, or the index \(i\) labelling this coordinate (with the index convention defined on the chart domain via the parameter `start_index`)

    OUTPUT:

    - a `ChartFunction` representing the partial derivative \(\frac{\partial f}{\partial x^i}\)

    EXAMPLES:

    Partial derivatives of a 2-dimensional chart function:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart(calc_method='SR')
        sage: f = X.function(x^2+3*y+1); f
        x^2 + 3*y + 1
        sage: f.derivative(x)
        2*x
        sage: f.derivative(y)
        3

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(calc_method='SR', names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x**Integer(2)+Integer(3)*y+Integer(1)); f
        x^2 + 3*y + 1
        >>> f.derivative(x)
        2*x
        >>> f.derivative(y)
        3

    An alias is `diff`:

    Sage

        sage: f.diff(x)
        2*x

    [Python]

        >>> from sage.all import *
        >>> f.diff(x)
        2*x

    Each partial derivative is itself a chart function:

    Sage

        sage: type(f.diff(x))
        <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>

    Python

        >>> from sage.all import *
        >>> type(f.diff(x))
        <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>

    The same result is returned by the function `diff`:

    Sage

        sage: diff(f, x)
        2*x

    [Python]

        >>> from sage.all import *
        >>> diff(f, x)
        2*x

    An index can be used instead of the coordinate symbol:

    Sage

        sage: f.diff(0)
        2*x
        sage: diff(f, 1)
        3

    Python

        >>> from sage.all import *
        >>> f.diff(Integer(0))
        2*x
        >>> diff(f, Integer(1))
        3

    The index range depends on the convention used on the chart’s domain:

    Sage

        sage: M = Manifold(2, 'M', structure='topological', start_index=1)
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x^2+3*y+1)
        sage: f.diff(0)
        Traceback (most recent call last):
        ...
        ValueError: coordinate index out of range
        sage: f.diff(1)
        2*x
        sage: f.diff(2)
        3

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological', start_index=Integer(1))
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x**Integer(2)+Integer(3)*y+Integer(1))
        >>> f.diff(Integer(0))
        Traceback (most recent call last):
        ...
        ValueError: coordinate index out of range
        >>> f.diff(Integer(1))
        2*x
        >>> f.diff(Integer(2))
        3

    The same test with SymPy:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart(calc_method='sympy')
        sage: f = X.function(x^2+3*y+1); f
        x**2 + 3*y + 1
        sage: f.diff(x)
        2*x
        sage: f.diff(y)
        3

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(calc_method='sympy', names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x**Integer(2)+Integer(3)*y+Integer(1)); f
        x**2 + 3*y + 1
        >>> f.diff(x)
        2*x
        >>> f.diff(y)
        3

  diff(coord)

    alias of `derivative()`.

  disp()

    alias of `display()`.

  display()

    Display `self` in arrow notation. For display the standard `SR` representation is used.

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

    EXAMPLES:

    Coordinate function on a 2-dimensional manifold:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(cos(x*y/2))
        sage: f.display()
        (x, y) ↦ cos(1/2*x*y)
        sage: latex(f.display())
        \left(x, y\right) \mapsto \cos\left(\frac{1}{2} \, x y\right)

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(cos(x*y/Integer(2)))
        >>> f.display()
        (x, y) ↦ cos(1/2*x*y)
        >>> latex(f.display())
        \left(x, y\right) \mapsto \cos\left(\frac{1}{2} \, x y\right)

    A shortcut is `disp()`:

    Sage

        sage: f.disp()
        (x, y) ↦ cos(1/2*x*y)

    [Python]

        >>> from sage.all import *
        >>> f.disp()
        (x, y) ↦ cos(1/2*x*y)

    Display of the zero function:

    Sage

        sage: X.zero_function().display()
        (x, y) ↦ 0

    Python

        >>> from sage.all import *
        >>> X.zero_function().display()
        (x, y) ↦ 0

  exp()

    Exponential of `self`.

    OUTPUT:

    - chart function \(\exp(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x+y)
        sage: f.exp()
        e^(x + y)
        sage: exp(f) # equivalent to f.exp()
        e^(x + y)
        sage: exp(f).display()
        (x, y) ↦ e^(x + y)
        sage: exp(X.zero_function())
        1

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x+y)
        >>> f.exp()
        e^(x + y)
        >>> exp(f) # equivalent to f.exp()
        e^(x + y)
        >>> exp(f).display()
        (x, y) ↦ e^(x + y)
        >>> exp(X.zero_function())
        1

    The same test with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f = X.function(x+y)
        sage: f.exp()
        exp(x + y)
        sage: exp(f) # equivalent to f.exp()
        exp(x + y)
        sage: exp(f).display()
        (x, y) ↦ exp(x + y)
        sage: exp(X.zero_function())
        1

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f = X.function(x+y)
        >>> f.exp()
        exp(x + y)
        >>> exp(f) # equivalent to f.exp()
        exp(x + y)
        >>> exp(f).display()
        (x, y) ↦ exp(x + y)
        >>> exp(X.zero_function())
        1

  expand()

    Expand the coordinate expression of `self`.

    OUTPUT: `self` with its expression expanded

    EXAMPLES:

    Expanding a 2-dimensional chart function:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function((x - y)^2)
        sage: f.display()
        (x, y) ↦ (x - y)^2
        sage: f.expand()
        x^2 - 2*x*y + y^2

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function((x - y)**Integer(2))
        >>> f.display()
        (x, y) ↦ (x - y)^2
        >>> f.expand()
        x^2 - 2*x*y + y^2

    The method `expand()` has changed the expression of `f`:

    Sage

        sage: f.display()
        (x, y) ↦ x^2 - 2*x*y + y^2

    [Python]

        >>> from sage.all import *
        >>> f.display()
        (x, y) ↦ x^2 - 2*x*y + y^2

    The same test with SymPy

    Sage

        sage: X.calculus_method().set('sympy')
        sage: g = X.function((x - y)^2)
        sage: g.expand()
        x**2 - 2*x*y + y**2

    Python

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> g = X.function((x - y)**Integer(2))
        >>> g.expand()
        x**2 - 2*x*y + y**2

  expr(method=None)

    Return the symbolic expression of `self` in terms of the chart coordinates, as an object of a specified calculus method.

    INPUT:

    - `method` – string (default: `None`); the calculus method which the returned expression belongs to. One of

      - `'SR'`: Sage’s default symbolic engine (Symbolic Ring)

      - `'sympy'`: SymPy

      - `None`: the chart current calculus method is assumed

    OUTPUT:

    - a `Sage symbolic expression` if `method` is `'SR'`

    - a SymPy object if `method` is `'sympy'`

    EXAMPLES:

    Chart function on a 2-dimensional manifold:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x^2+y)
        sage: f.expr()
        x^2 + y
        sage: type(f.expr())
        <class 'sage.symbolic.expression.Expression'>

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x**Integer(2)+y)
        >>> f.expr()
        x^2 + y
        >>> type(f.expr())
        <class 'sage.symbolic.expression.Expression'>

    Asking for the SymPy expression:

    Sage

        sage: f.expr('sympy')
        x**2 + y
        sage: type(f.expr('sympy'))
        <class 'sympy.core.add.Add'>

    [Python]

        >>> from sage.all import *
        >>> f.expr('sympy')
        x**2 + y
        >>> type(f.expr('sympy'))
        <class 'sympy.core.add.Add'>

    The default corresponds to the current calculus method, here the one based on the Symbolic Ring `SR`:

    Sage

        sage: f.expr() is f.expr('SR')
        True

    Python

        >>> from sage.all import *
        >>> f.expr() is f.expr('SR')
        True

    If we change the current calculus method on chart `X`, we change the default:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.expr()
        x**2 + y
        sage: f.expr() is f.expr('sympy')
        True
        sage: X.calculus_method().set('SR')  # revert back to SR

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.expr()
        x**2 + y
        >>> f.expr() is f.expr('sympy')
        True
        >>> X.calculus_method().set('SR')  # revert back to SR

    Internally, the expressions corresponding to various calculus methods are stored in the dictionary `_express`:

    Sage

        sage: for method in sorted(f._express):
        ....:     print("'{}': {}".format(method, f._express[method]))
        ....:
        'SR': x^2 + y
        'sympy': x**2 + y

    Python

        >>> from sage.all import *
        >>> for method in sorted(f._express):
        ...     print("'{}': {}".format(method, f._express[method]))
        ....:
        'SR': x^2 + y
        'sympy': x**2 + y

    The method `expr()` is useful for accessing to all the symbolic expression functionalities in Sage; for instance:

    Sage

        sage: var('a')
        a
        sage: f = X.function(a*x*y); f.display()
        (x, y) ↦ a*x*y
        sage: f.expr()
        a*x*y
        sage: f.expr().subs(a=2)
        2*x*y

    [Python]

        >>> from sage.all import *
        >>> var('a')
        a
        >>> f = X.function(a*x*y); f.display()
        (x, y) ↦ a*x*y
        >>> f.expr()
        a*x*y
        >>> f.expr().subs(a=Integer(2))
        2*x*y

    Note that for substituting the value of a coordinate, the function call can be used as well:

    Sage

        sage: f(x,3)
        3*a*x
        sage: bool( f(x,3) == f.expr().subs(y=3) )
        True

    Python

        >>> from sage.all import *
        >>> f(x,Integer(3))
        3*a*x
        >>> bool( f(x,Integer(3)) == f.expr().subs(y=Integer(3)) )
        True

  factor()

    Factorize the coordinate expression of `self`.

    OUTPUT: `self` with its expression factorized

    EXAMPLES:

    Factorization of a 2-dimensional chart function:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x^2 + 2*x*y + y^2)
        sage: f.display()
        (x, y) ↦ x^2 + 2*x*y + y^2
        sage: f.factor()
        (x + y)^2

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x**Integer(2) + Integer(2)*x*y + y**Integer(2))
        >>> f.display()
        (x, y) ↦ x^2 + 2*x*y + y^2
        >>> f.factor()
        (x + y)^2

    The method `factor()` has changed the expression of `f`:

    Sage

        sage: f.display()
        (x, y) ↦ (x + y)^2

    [Python]

        >>> from sage.all import *
        >>> f.display()
        (x, y) ↦ (x + y)^2

    The same test with SymPy

    Sage

        sage: X.calculus_method().set('sympy')
        sage: g = X.function(x^2 + 2*x*y + y^2)
        sage: g.display()
        (x, y) ↦ x**2 + 2*x*y + y**2
        sage: g.factor()
        (x + y)**2

    Python

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> g = X.function(x**Integer(2) + Integer(2)*x*y + y**Integer(2))
        >>> g.display()
        (x, y) ↦ x**2 + 2*x*y + y**2
        >>> g.factor()
        (x + y)**2

  is_trivial_one()

    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

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(1)
        sage: f.is_trivial_one()
        True
        sage: f = X.function(float(1.0))
        sage: f.is_trivial_one()
        True
        sage: f = X.function(x-x+1)
        sage: f.is_trivial_one()
        True
        sage: X.one_function().is_trivial_one()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(Integer(1))
        >>> f.is_trivial_one()
        True
        >>> f = X.function(float(RealNumber('1.0')))
        >>> f.is_trivial_one()
        True
        >>> f = X.function(x-x+Integer(1))
        >>> f.is_trivial_one()
        True
        >>> X.one_function().is_trivial_one()
        True

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

    Sage

        sage: f = X.function(cos(x)^2 + sin(x)^2)
        sage: f.is_trivial_one()
        False

    [Python]

        >>> from sage.all import *
        >>> f = X.function(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

        sage: (f - 1).is_zero()
        True
        sage: f == 1
        True

    Python

        >>> from sage.all import *
        >>> (f - Integer(1)).is_zero()
        True
        >>> f == Integer(1)
        True

  is_trivial_zero()

    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

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(0)
        sage: f.is_trivial_zero()
        True
        sage: f = X.function(float(0.0))
        sage: f.is_trivial_zero()
        True
        sage: f = X.function(x-x)
        sage: f.is_trivial_zero()
        True
        sage: X.zero_function().is_trivial_zero()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(Integer(0))
        >>> f.is_trivial_zero()
        True
        >>> f = X.function(float(RealNumber('0.0')))
        >>> f.is_trivial_zero()
        True
        >>> f = X.function(x-x)
        >>> f.is_trivial_zero()
        True
        >>> X.zero_function().is_trivial_zero()
        True

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

    Sage

        sage: f = X.function(cos(x)^2 + sin(x)^2 - 1)
        sage: f.is_trivial_zero()
        False

    [Python]

        >>> from sage.all import *
        >>> f = X.function(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

        sage: f.is_zero()
        True
        sage: f == 0
        True

    Python

        >>> from sage.all import *
        >>> f.is_zero()
        True
        >>> f == Integer(0)
        True

  is_unit()

    Return `True` iff `self` is not trivially zero since most chart functions are invertible and an actual computation would take too much time.

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x^2+3*y+1)
        sage: f.is_unit()
        True
        sage: zero = X.function(0)
        sage: zero.is_unit()
        False

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x**Integer(2)+Integer(3)*y+Integer(1))
        >>> f.is_unit()
        True
        >>> zero = X.function(Integer(0))
        >>> zero.is_unit()
        False

  log(base=None)

    Logarithm of `self`.

    INPUT:

    - `base` – (default: `None`) base of the logarithm; if `None`, the natural logarithm (i.e. logarithm to base \(e\)) is returned

    OUTPUT:

    - chart function \(\log_a(f)\), where \(f\) is the current chart function and \(a\) is the base

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x+y)
        sage: f.log()
        log(x + y)
        sage: log(f) # equivalent to f.log()
        log(x + y)
        sage: log(f).display()
        (x, y) ↦ log(x + y)
        sage: f.log(2)
        log(x + y)/log(2)
        sage: log(f, 2)
        log(x + y)/log(2)

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x+y)
        >>> f.log()
        log(x + y)
        >>> log(f) # equivalent to f.log()
        log(x + y)
        >>> log(f).display()
        (x, y) ↦ log(x + y)
        >>> f.log(Integer(2))
        log(x + y)/log(2)
        >>> log(f, Integer(2))
        log(x + y)/log(2)

    The same test with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f = X.function(x+y)
        sage: f.log()
        log(x + y)
        sage: log(f) # equivalent to f.log()
        log(x + y)
        sage: log(f).display()
        (x, y) ↦ log(x + y)
        sage: f.log(2)
        log(x + y)/log(2)
        sage: log(f, 2)
        log(x + y)/log(2)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f = X.function(x+y)
        >>> f.log()
        log(x + y)
        >>> log(f) # equivalent to f.log()
        log(x + y)
        >>> log(f).display()
        (x, y) ↦ log(x + y)
        >>> f.log(Integer(2))
        log(x + y)/log(2)
        >>> log(f, Integer(2))
        log(x + y)/log(2)

  scalar_field(name=None, latex_name=None)

    Construct the scalar field that has `self` as coordinate expression.

    The domain of the scalar field is the open subset covered by the chart on which `self` is defined.

    INPUT:

    - `name` – (default: `None`) name given to the scalar field

    - `latex_name` – (default: `None`) LaTeX symbol to denote the scalar field; if `None`, the LaTeX symbol is set to `name`

    OUTPUT: a `ScalarField`

    EXAMPLES:

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

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: c_xy.<x,y> = M.chart()
        sage: fc = c_xy.function(x+2*y^3)
        sage: f = fc.scalar_field() ; f
        Scalar field on the 2-dimensional topological manifold M
        sage: f.display()
        M → ℝ
        (x, y) ↦ 2*y^3 + x
        sage: f.coord_function(c_xy) is fc
        True

    Python

        >>> 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)
        >>> fc = c_xy.function(x+Integer(2)*y**Integer(3))
        >>> f = fc.scalar_field() ; f
        Scalar field on the 2-dimensional topological manifold M
        >>> f.display()
        M → ℝ
        (x, y) ↦ 2*y^3 + x
        >>> f.coord_function(c_xy) is fc
        True

  set_expr(calc_method, expression)

    Add an expression in a particular calculus method `self`. Some control is done to verify the consistency between the different representations of the same expression.

    INPUT:

    - `calc_method` – calculus method

    - `expression` – symbolic expression

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(1+x^2)
        sage: f._repr_()
        'x^2 + 1'
        sage: f.set_expr('sympy','x**2+1')
        sage: f  # indirect doctest
        x^2 + 1

        sage: g = X.function(1+x^3)
        sage: g._repr_()
        'x^3 + 1'
        sage: g.set_expr('sympy','x**2+y')
        Traceback (most recent call last):
        ...
        ValueError: Expressions are not equal

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(Integer(1)+x**Integer(2))
        >>> f._repr_()
        'x^2 + 1'
        >>> f.set_expr('sympy','x**2+1')
        >>> f  # indirect doctest
        x^2 + 1

        >>> g = X.function(Integer(1)+x**Integer(3))
        >>> g._repr_()
        'x^3 + 1'
        >>> g.set_expr('sympy','x**2+y')
        Traceback (most recent call last):
        ...
        ValueError: Expressions are not equal

  simplify()

    Simplify the coordinate expression of `self`.

    For details about the employed chain of simplifications for the `SR` calculus method, see `simplify_chain_real()` for chart functions on real manifolds and `simplify_chain_generic()` for the generic case.

    If `self` has been defined with the small parameter `expansion_symbol` and some truncation order, the coordinate expression of `self` will be expanded in power series of that parameter and truncated to the given order.

    OUTPUT: `self` with its coordinate expression simplified

    EXAMPLES:

    Simplification of a chart function on a 2-dimensional manifold:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(cos(x)^2 + sin(x)^2 + sqrt(x^2))
        sage: f.display()
        (x, y) ↦ cos(x)^2 + sin(x)^2 + abs(x)
        sage: f.simplify()
        abs(x) + 1

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(cos(x)**Integer(2) + sin(x)**Integer(2) + sqrt(x**Integer(2)))
        >>> f.display()
        (x, y) ↦ cos(x)^2 + sin(x)^2 + abs(x)
        >>> f.simplify()
        abs(x) + 1

    The method `simplify()` has changed the expression of `f`:

    Sage

        sage: f.display()
        (x, y) ↦ abs(x) + 1

    [Python]

        >>> from sage.all import *
        >>> f.display()
        (x, y) ↦ abs(x) + 1

    Another example:

    Sage

        sage: f = X.function((x^2-1)/(x+1)); f
        (x^2 - 1)/(x + 1)
        sage: f.simplify()
        x - 1

    Python

        >>> from sage.all import *
        >>> f = X.function((x**Integer(2)-Integer(1))/(x+Integer(1))); f
        (x^2 - 1)/(x + 1)
        >>> f.simplify()
        x - 1

    Examples taking into account the declared range of a coordinate:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart('x:(1,+oo) y')
        sage: f = X.function(sqrt(x^2-2*x+1)); f
        sqrt(x^2 - 2*x + 1)
        sage: f.simplify()
        x - 1

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart('x:(1,+oo) y', names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(sqrt(x**Integer(2)-Integer(2)*x+Integer(1))); f
        sqrt(x^2 - 2*x + 1)
        >>> f.simplify()
        x - 1

    Sage

        sage: forget()  # to clear the previous assumption on x
        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart('x:(-oo,0) y')
        sage: f = X.function(sqrt(x^2-2*x+1)); f
        sqrt(x^2 - 2*x + 1)
        sage: f.simplify()
        -x + 1

    Python

        >>> from sage.all import *
        >>> forget()  # to clear the previous assumption on x
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart('x:(-oo,0) y', names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(sqrt(x**Integer(2)-Integer(2)*x+Integer(1))); f
        sqrt(x^2 - 2*x + 1)
        >>> f.simplify()
        -x + 1

    The same tests with SymPy:

    Sage

        sage: forget()  # to clear the previous assumption on x
        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart(calc_method='sympy')
        sage: f = X.function(cos(x)^2 + sin(x)^2 + sqrt(x^2)); f
        sin(x)**2 + cos(x)**2 + Abs(x)
        sage: f.simplify()
        Abs(x) + 1

    [Python]

        >>> from sage.all import *
        >>> forget()  # to clear the previous assumption on x
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(calc_method='sympy', names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(cos(x)**Integer(2) + sin(x)**Integer(2) + sqrt(x**Integer(2))); f
        sin(x)**2 + cos(x)**2 + Abs(x)
        >>> f.simplify()
        Abs(x) + 1

    Sage

        sage: f = X.function((x^2-1)/(x+1)); f
        (x**2 - 1)/(x + 1)
        sage: f.simplify()
        x - 1

    Python

        >>> from sage.all import *
        >>> f = X.function((x**Integer(2)-Integer(1))/(x+Integer(1))); f
        (x**2 - 1)/(x + 1)
        >>> f.simplify()
        x - 1

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart('x:(1,+oo) y', calc_method='sympy')
        sage: f = X.function(sqrt(x^2-2*x+1)); f
        sqrt(x**2 - 2*x + 1)
        sage: f.simplify()
        x - 1

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart('x:(1,+oo) y', calc_method='sympy', names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(sqrt(x**Integer(2)-Integer(2)*x+Integer(1))); f
        sqrt(x**2 - 2*x + 1)
        >>> f.simplify()
        x - 1

    Sage

        sage: forget()  # to clear the previous assumption on x
        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart('x:(-oo,0) y', calc_method='sympy')
        sage: f = X.function(sqrt(x^2-2*x+1)); f
        sqrt(x**2 - 2*x + 1)
        sage: f.simplify()
        1 - x

    Python

        >>> from sage.all import *
        >>> forget()  # to clear the previous assumption on x
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart('x:(-oo,0) y', calc_method='sympy', names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(sqrt(x**Integer(2)-Integer(2)*x+Integer(1))); f
        sqrt(x**2 - 2*x + 1)
        >>> f.simplify()
        1 - x

    Power series expansion with respect to a small parameter \(t\) (at the moment, this is implemented only for the `SR` calculus backend, hence the first line below):

    Sage

        sage: X.calculus_method().set('SR')
        sage: t = var('t')
        sage: f = X.function(exp(t*x), expansion_symbol=t, order=3)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('SR')
        >>> t = var('t')
        >>> f = X.function(exp(t*x), expansion_symbol=t, order=Integer(3))

    At this stage, \(f\) is not expanded in power series:

    Sage

        sage: f
        e^(t*x)

    Python

        >>> from sage.all import *
        >>> f
        e^(t*x)

    Invoking `simplify()` triggers the expansion to the given order:

    Sage

        sage: f.simplify()
        1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1
        sage: f.display()
        (x, y) ↦ 1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1

    [Python]

        >>> from sage.all import *
        >>> f.simplify()
        1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1
        >>> f.display()
        (x, y) ↦ 1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1

  sin()

    Sine of `self`.

    OUTPUT:

    - chart function \(\sin(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.sin()
        sin(x*y)
        sage: sin(f)  # equivalent to f.sin()
        sin(x*y)
        sage: sin(f).display()
        (x, y) ↦ sin(x*y)
        sage: sin(X.zero_function()) == X.zero_function()
        True
        sage: f = X.function(2-cos(x)^2+y)
        sage: g = X.function(-sin(x)^2+y)
        sage: (f+g).simplify()
        2*y + 1

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.sin()
        sin(x*y)
        >>> sin(f)  # equivalent to f.sin()
        sin(x*y)
        >>> sin(f).display()
        (x, y) ↦ sin(x*y)
        >>> sin(X.zero_function()) == X.zero_function()
        True
        >>> f = X.function(Integer(2)-cos(x)**Integer(2)+y)
        >>> g = X.function(-sin(x)**Integer(2)+y)
        >>> (f+g).simplify()
        2*y + 1

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f = X.function(x*y)
        sage: f.sin()
        sin(x*y)
        sage: sin(f)  # equivalent to f.sin()
        sin(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f = X.function(x*y)
        >>> f.sin()
        sin(x*y)
        >>> sin(f)  # equivalent to f.sin()
        sin(x*y)

  sinh()

    Hyperbolic sine of `self`.

    OUTPUT:

    - chart function \(\sinh(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.sinh()
        sinh(x*y)
        sage: sinh(f)  # equivalent to f.sinh()
        sinh(x*y)
        sage: sinh(f).display()
        (x, y) ↦ sinh(x*y)
        sage: sinh(X.zero_function()) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.sinh()
        sinh(x*y)
        >>> sinh(f)  # equivalent to f.sinh()
        sinh(x*y)
        >>> sinh(f).display()
        (x, y) ↦ sinh(x*y)
        >>> sinh(X.zero_function()) == X.zero_function()
        True

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.sinh()
        sinh(x*y)
        sage: sinh(f)  # equivalent to f.sinh()
        sinh(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.sinh()
        sinh(x*y)
        >>> sinh(f)  # equivalent to f.sinh()
        sinh(x*y)

  sqrt()

    Square root of `self`.

    OUTPUT:

    - chart function \(\sqrt{f}\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x+y)
        sage: f.sqrt()
        sqrt(x + y)
        sage: sqrt(f)  # equivalent to f.sqrt()
        sqrt(x + y)
        sage: sqrt(f).display()
        (x, y) ↦ sqrt(x + y)
        sage: sqrt(X.zero_function()).display()
        (x, y) ↦ 0

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x+y)
        >>> f.sqrt()
        sqrt(x + y)
        >>> sqrt(f)  # equivalent to f.sqrt()
        sqrt(x + y)
        >>> sqrt(f).display()
        (x, y) ↦ sqrt(x + y)
        >>> sqrt(X.zero_function()).display()
        (x, y) ↦ 0

  tan()

    Tangent of `self`.

    OUTPUT:

    - chart function \(\tan(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.tan()
        sin(x*y)/cos(x*y)
        sage: tan(f)  # equivalent to f.tan()
        sin(x*y)/cos(x*y)
        sage: tan(f).display()
        (x, y) ↦ sin(x*y)/cos(x*y)
        sage: tan(X.zero_function()) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.tan()
        sin(x*y)/cos(x*y)
        >>> tan(f)  # equivalent to f.tan()
        sin(x*y)/cos(x*y)
        >>> tan(f).display()
        (x, y) ↦ sin(x*y)/cos(x*y)
        >>> tan(X.zero_function()) == X.zero_function()
        True

    The same test with SymPy:

    Sage

        sage: M.set_calculus_method('sympy')
        sage: g = X.function(x*y)
        sage: g.tan()
        tan(x*y)
        sage: tan(g)  # equivalent to g.tan()
        tan(x*y)
        sage: tan(g).display()
        (x, y) ↦ tan(x*y)

    [Python]

        >>> from sage.all import *
        >>> M.set_calculus_method('sympy')
        >>> g = X.function(x*y)
        >>> g.tan()
        tan(x*y)
        >>> tan(g)  # equivalent to g.tan()
        tan(x*y)
        >>> tan(g).display()
        (x, y) ↦ tan(x*y)

  tanh()

    Hyperbolic tangent of `self`.

    OUTPUT:

    - chart function \(\tanh(f)\), where \(f\) is the current chart function

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.function(x*y)
        sage: f.tanh()
        sinh(x*y)/cosh(x*y)
        sage: tanh(f)  # equivalent to f.tanh()
        sinh(x*y)/cosh(x*y)
        sage: tanh(f).display()
        (x, y) ↦ sinh(x*y)/cosh(x*y)
        sage: tanh(X.zero_function()) == X.zero_function()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.function(x*y)
        >>> f.tanh()
        sinh(x*y)/cosh(x*y)
        >>> tanh(f)  # equivalent to f.tanh()
        sinh(x*y)/cosh(x*y)
        >>> tanh(f).display()
        (x, y) ↦ sinh(x*y)/cosh(x*y)
        >>> tanh(X.zero_function()) == X.zero_function()
        True

    The same tests with SymPy:

    Sage

        sage: X.calculus_method().set('sympy')
        sage: f.tanh()
        tanh(x*y)
        sage: tanh(f)  # equivalent to f.tanh()
        tanh(x*y)

    [Python]

        >>> from sage.all import *
        >>> X.calculus_method().set('sympy')
        >>> f.tanh()
        tanh(x*y)
        >>> tanh(f)  # equivalent to f.tanh()
        tanh(x*y)

class sage.manifolds.chart_func.ChartFunctionRing(chart)

  Bases: `Parent`, `UniqueRepresentation`

  Ring of all chart functions on a chart.

  INPUT:

  - `chart` – a coordinate chart, as an instance of class `Chart`

  EXAMPLES:

  The ring of all chart functions w.r.t. to a chart:

  Sage

      sage: M = Manifold(2, 'M', structure='topological')
      sage: X.<x,y> = M.chart()
      sage: FR = X.function_ring(); FR
      Ring of chart functions on Chart (M, (x, y))
      sage: type(FR)
      <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category'>
      sage: FR.category()
      Category of commutative algebras over Symbolic Ring

  Python

      >>> from sage.all import *
      >>> M = Manifold(Integer(2), 'M', structure='topological')
      >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
      >>> FR = X.function_ring(); FR
      Ring of chart functions on Chart (M, (x, y))
      >>> type(FR)
      <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category'>
      >>> FR.category()
      Category of commutative algebras over Symbolic Ring

  Coercions by means of restrictions are implemented:

  Sage

      sage: FR_X = X.function_ring()
      sage: D = M.open_subset('D')
      sage: X_D = X.restrict(D, x^2+y^2<1)  # open disk
      sage: FR_X_D = X_D.function_ring()
      sage: FR_X_D.has_coerce_map_from(FR_X)
      True

  [Python]

      >>> from sage.all import *
      >>> FR_X = X.function_ring()
      >>> D = M.open_subset('D')
      >>> X_D = X.restrict(D, x**Integer(2)+y**Integer(2)<Integer(1))  # open disk
      >>> FR_X_D = X_D.function_ring()
      >>> FR_X_D.has_coerce_map_from(FR_X)
      True

  But only if the charts are compatible:

  Sage

      sage: Y.<t,z> = D.chart()
      sage: FR_Y = Y.function_ring()
      sage: FR_Y.has_coerce_map_from(FR_X)
      False

  Python

      >>> from sage.all import *
      >>> Y = D.chart(names=('t', 'z',)); (t, z,) = Y._first_ngens(2)
      >>> FR_Y = Y.function_ring()
      >>> FR_Y.has_coerce_map_from(FR_X)
      False

  Element

    alias of `ChartFunction`

  is_field(proof=True)

    alias of `is_integral_domain()`.

  is_integral_domain(proof=True)

    Return `False` as `self` is not an integral domain.

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: FR = X.function_ring()
        sage: FR.is_integral_domain()
        False
        sage: FR.is_field()
        False

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> FR = X.function_ring()
        >>> FR.is_integral_domain()
        False
        >>> FR.is_field()
        False

  one()

    Return the constant function \(1\) in `self`.

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: FR = X.function_ring()
        sage: FR.one()
        1

        sage: M = Manifold(2, 'M', structure='topological', field=Qp(5))
        sage: X.<x,y> = M.chart()
        sage: X.function_ring().one()
        1 + O(5^20)

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> FR = X.function_ring()
        >>> FR.one()
        1

        >>> M = Manifold(Integer(2), 'M', structure='topological', field=Qp(Integer(5)))
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> X.function_ring().one()
        1 + O(5^20)

  zero()

    Return the constant function \(0\) in `self`.

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: FR = X.function_ring()
        sage: FR.zero()
        0

        sage: M = Manifold(2, 'M', structure='topological', field=Qp(5))
        sage: X.<x,y> = M.chart()
        sage: X.function_ring().zero()
        0

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> FR = X.function_ring()
        >>> FR.zero()
        0

        >>> M = Manifold(Integer(2), 'M', structure='topological', field=Qp(Integer(5)))
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> X.function_ring().zero()
        0

class sage.manifolds.chart_func.MultiCoordFunction(chart, expressions)

  Bases: `SageObject`, `Mutability`

  Coordinate function to some Cartesian power of the base field.

  If \(n\) and \(m\) are two positive integers and \((U, \varphi)\) is a chart on a topological manifold \(M\) of dimension \(n\) over a topological field \(K\), a multi-coordinate function associated to \((U, \varphi)\) is a map

  \[\begin{split}\begin{array}{llcl} f:& V \subset K^n & \longrightarrow & K^m \\ & (x^1, \ldots, x^n) & \longmapsto & (f_1(x^1, \ldots, x^n), \ldots, f_m(x^1, \ldots, x^n)), \end{array}\end{split}\]

  where \(V\) is the codomain of \(\varphi\). In other words, \(f\) is a \(K^m\)-valued function of the coordinates associated to the chart \((U, \varphi)\). Each component \(f_i\) (\(1 \leq i \leq m\)) is a coordinate function and is therefore stored as a `ChartFunction`.

  INPUT:

  - `chart` – the chart \((U, \varphi)\)

  - `expressions` – list (or tuple) of length \(m\) of elements to construct the coordinate functions \(f_i\) (\(1 \leq i \leq m\)); for symbolic coordinate functions, this must be symbolic expressions involving the chart coordinates, while for numerical coordinate functions, this must be data file names

  EXAMPLES:

  A function \(f: V \subset \RR^2 \longrightarrow \RR^3\):

  Sage

      sage: forget()  # to clear the previous assumption on x
      sage: M = Manifold(2, 'M', structure='topological')
      sage: X.<x,y> = M.chart()
      sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y)); f
      Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))
      sage: type(f)
      <class 'sage.manifolds.chart_func.MultiCoordFunction'>
      sage: f(x,y)
      (x - y, x*y, cos(x)*e^y)
      sage: latex(f)
      \left(x - y, x y, \cos\left(x\right) e^{y}\right)

  Python

      >>> from sage.all import *
      >>> forget()  # to clear the previous assumption on x
      >>> M = Manifold(Integer(2), 'M', structure='topological')
      >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
      >>> f = X.multifunction(x-y, x*y, cos(x)*exp(y)); f
      Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))
      >>> type(f)
      <class 'sage.manifolds.chart_func.MultiCoordFunction'>
      >>> f(x,y)
      (x - y, x*y, cos(x)*e^y)
      >>> latex(f)
      \left(x - y, x y, \cos\left(x\right) e^{y}\right)

  Each real-valued function \(f_i\) (\(1 \leq i \leq m\)) composing \(f\) can be accessed via the square-bracket operator, by providing \(i-1\) as an argument:

  Sage

      sage: f[0]
      x - y
      sage: f[1]
      x*y
      sage: f[2]
      cos(x)*e^y

  [Python]

      >>> from sage.all import *
      >>> f[Integer(0)]
      x - y
      >>> f[Integer(1)]
      x*y
      >>> f[Integer(2)]
      cos(x)*e^y

  We can give a more verbose explanation of each function:

  Sage

      sage: f[0].display()
      (x, y) ↦ x - y

  Python

      >>> from sage.all import *
      >>> f[Integer(0)].display()
      (x, y) ↦ x - y

  Each `f[i-1]` is an instance of `ChartFunction`:

  Sage

      sage: isinstance(f[0], sage.manifolds.chart_func.ChartFunction)
      True

  [Python]

      >>> from sage.all import *
      >>> isinstance(f[Integer(0)], sage.manifolds.chart_func.ChartFunction)
      True

  A class `MultiCoordFunction` can represent a real-valued function (case \(m = 1\)), although one should rather employ the class `ChartFunction` for this purpose:

  Sage

      sage: g = X.multifunction(x*y^2)
      sage: g(x,y)
      (x*y^2,)

  Python

      >>> from sage.all import *
      >>> g = X.multifunction(x*y**Integer(2))
      >>> g(x,y)
      (x*y^2,)

  Evaluating the functions at specified coordinates:

  Sage

      sage: f(1,2)
      (-1, 2, cos(1)*e^2)
      sage: var('a b')
      (a, b)
      sage: f(a,b)
      (a - b, a*b, cos(a)*e^b)
      sage: g(1,2)
      (4,)

  [Python]

      >>> from sage.all import *
      >>> f(Integer(1),Integer(2))
      (-1, 2, cos(1)*e^2)
      >>> var('a b')
      (a, b)
      >>> f(a,b)
      (a - b, a*b, cos(a)*e^b)
      >>> g(Integer(1),Integer(2))
      (4,)

  chart()

    Return the chart with respect to which `self` is defined.

    OUTPUT: a `Chart`

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
        sage: f.chart()
        Chart (M, (x, y))
        sage: f.chart() is X
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.multifunction(x-y, x*y, cos(x)*exp(y))
        >>> f.chart()
        Chart (M, (x, y))
        >>> f.chart() is X
        True

  expr(method=None)

    Return a tuple of data, the item no. \(i\) being sufficient to reconstruct the coordinate function no. \(i\).

    In other words, if `f` is a multi-coordinate function, then `f.chart().multifunction(*(f.expr()))` results in a multi-coordinate function identical to `f`.

    INPUT:

    - `method` – string (default: `None`); the calculus method which the returned expressions belong to. One of

      - `'SR'`: Sage’s default symbolic engine (Symbolic Ring)

      - `'sympy'`: SymPy

      - `None`: the chart current calculus method is assumed

    OUTPUT:

    - a tuple of the symbolic expressions of the chart functions composing `self`

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
        sage: f.expr()
        (x - y, x*y, cos(x)*e^y)
        sage: type(f.expr()[0])
        <class 'sage.symbolic.expression.Expression'>

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.multifunction(x-y, x*y, cos(x)*exp(y))
        >>> f.expr()
        (x - y, x*y, cos(x)*e^y)
        >>> type(f.expr()[Integer(0)])
        <class 'sage.symbolic.expression.Expression'>

    A SymPy output:

    Sage

        sage: f.expr('sympy')
        (x - y, x*y, exp(y)*cos(x))
        sage: type(f.expr('sympy')[0])
        <class 'sympy.core.add.Add'>

    [Python]

        >>> from sage.all import *
        >>> f.expr('sympy')
        (x - y, x*y, exp(y)*cos(x))
        >>> type(f.expr('sympy')[Integer(0)])
        <class 'sympy.core.add.Add'>

    One shall always have:

    Sage

        sage: f.chart().multifunction(*(f.expr())) == f
        True

    Python

        >>> from sage.all import *
        >>> f.chart().multifunction(*(f.expr())) == f
        True

  jacobian()

    Return the Jacobian matrix of the system of coordinate functions.

    `jacobian()` is a 2-dimensional array of size \(m \times n\), where \(m\) is the number of functions and \(n\) the number of coordinates, the generic element being \(J_{ij} = \frac{\partial f_i}{\partial x^j}\) with \(1 \leq i \leq m\) (row index) and \(1 \leq j \leq n\) (column index).

    OUTPUT:

    - Jacobian matrix as a 2-dimensional array `J` of coordinate functions with `J[i-1][j-1]` being \(J_{ij} = \frac{\partial f_i}{\partial x^j}\) for \(1 \leq i \leq m\) and \(1 \leq j \leq n\)

    EXAMPLES:

    Jacobian of a set of 3 functions of 2 coordinates:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.multifunction(x-y, x*y, y^3*cos(x))
        sage: f.jacobian()
        [           1           -1]
        [           y            x]
        [ -y^3*sin(x) 3*y^2*cos(x)]

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.multifunction(x-y, x*y, y**Integer(3)*cos(x))
        >>> f.jacobian()
        [           1           -1]
        [           y            x]
        [ -y^3*sin(x) 3*y^2*cos(x)]

    Each element of the result is a `chart function`:

    Sage

        sage: type(f.jacobian()[2,0])
        <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
        sage: f.jacobian()[2,0].display()
        (x, y) ↦ -y^3*sin(x)

    [Python]

        >>> from sage.all import *
        >>> type(f.jacobian()[Integer(2),Integer(0)])
        <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
        >>> f.jacobian()[Integer(2),Integer(0)].display()
        (x, y) ↦ -y^3*sin(x)

    Test of the computation:

    Sage

        sage: [[f.jacobian()[i,j] == f[i].diff(j) for j in range(2)] for i in range(3)]
        [[True, True], [True, True], [True, True]]

    Python

        >>> from sage.all import *
        >>> [[f.jacobian()[i,j] == f[i].diff(j) for j in range(Integer(2))] for i in range(Integer(3))]
        [[True, True], [True, True], [True, True]]

    Test with `start_index = 1`:

    Sage

        sage: M = Manifold(2, 'M', structure='topological', start_index=1)
        sage: X.<x,y> = M.chart()
        sage: f = X.multifunction(x-y, x*y, y^3*cos(x))
        sage: f.jacobian()
        [           1           -1]
        [           y            x]
        [ -y^3*sin(x) 3*y^2*cos(x)]
        sage: [[f.jacobian()[i,j] == f[i].diff(j+1) for j in range(2)]  # note the j+1
        ....:                                         for i in range(3)]
        [[True, True], [True, True], [True, True]]

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological', start_index=Integer(1))
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.multifunction(x-y, x*y, y**Integer(3)*cos(x))
        >>> f.jacobian()
        [           1           -1]
        [           y            x]
        [ -y^3*sin(x) 3*y^2*cos(x)]
        >>> [[f.jacobian()[i,j] == f[i].diff(j+Integer(1)) for j in range(Integer(2))]  # note the j+1
        ...                                         for i in range(Integer(3))]
        [[True, True], [True, True], [True, True]]

  jacobian_det()

    Return the Jacobian determinant of the system of functions.

    The number \(m\) of coordinate functions must equal the number \(n\) of coordinates.

    OUTPUT: a `ChartFunction` representing the determinant

    EXAMPLES:

    Jacobian determinant of a set of 2 functions of 2 coordinates:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: f = X.multifunction(x-y, x*y)
        sage: f.jacobian_det()
        x + y

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> f = X.multifunction(x-y, x*y)
        >>> f.jacobian_det()
        x + y

    The output of `jacobian_det()` is an instance of `ChartFunction` and can therefore be called on specific values of the coordinates, e.g. \((x,y) = (1,2)\):

    Sage

        sage: type(f.jacobian_det())
        <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
        sage: f.jacobian_det().display()
        (x, y) ↦ x + y
        sage: f.jacobian_det()(1,2)
        3

    [Python]

        >>> from sage.all import *
        >>> type(f.jacobian_det())
        <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
        >>> f.jacobian_det().display()
        (x, y) ↦ x + y
        >>> f.jacobian_det()(Integer(1),Integer(2))
        3

    The result is cached:

    Sage

        sage: f.jacobian_det() is f.jacobian_det()
        True

    Python

        >>> from sage.all import *
        >>> f.jacobian_det() is f.jacobian_det()
        True

    We verify the determinant of the Jacobian:

    Sage

        sage: f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(2)]
        ....:                                 for i in range(2)]))
        True

    [Python]

        >>> from sage.all import *
        >>> f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(Integer(2))]
        ...                                 for i in range(Integer(2))]))
        True

    An example using SymPy:

    Sage

        sage: M.set_calculus_method('sympy')
        sage: g = X.multifunction(x*y^3, e^x)
        sage: g.jacobian_det()
        -3*x*y**2*exp(x)
        sage: type(g.jacobian_det().expr())
        <class 'sympy.core.mul.Mul'>

    Python

        >>> from sage.all import *
        >>> M.set_calculus_method('sympy')
        >>> g = X.multifunction(x*y**Integer(3), e**x)
        >>> g.jacobian_det()
        -3*x*y**2*exp(x)
        >>> type(g.jacobian_det().expr())
        <class 'sympy.core.mul.Mul'>

    Jacobian determinant of a set of 3 functions of 3 coordinates:

    Sage

        sage: M = Manifold(3, 'M', structure='topological')
        sage: X.<x,y,z> = M.chart()
        sage: f = X.multifunction(x*y+z^2, z^2*x+y^2*z, (x*y*z)^3)
        sage: f.jacobian_det().display()
        (x, y, z) ↦ 6*x^3*y^5*z^3 - 3*x^4*y^3*z^4 - 12*x^2*y^4*z^5 + 6*x^3*y^2*z^6

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(3), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y', 'z',)); (x, y, z,) = X._first_ngens(3)
        >>> f = X.multifunction(x*y+z**Integer(2), z**Integer(2)*x+y**Integer(2)*z, (x*y*z)**Integer(3))
        >>> f.jacobian_det().display()
        (x, y, z) ↦ 6*x^3*y^5*z^3 - 3*x^4*y^3*z^4 - 12*x^2*y^4*z^5 + 6*x^3*y^2*z^6

    We verify the determinant of the Jacobian:

    Sage

        sage: f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(3)]
        ....:                                 for i in range(3)]))
        True

    Python

        >>> from sage.all import *
        >>> f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(Integer(3))]
        ...                                 for i in range(Integer(3))]))
        True

  set_immutable()

    Set `self` and all chart functions of `self` immutable.

    EXAMPLES:

    Declare a coordinate function immutable:

    Sage

        sage: M = Manifold(3, 'M', structure='topological')
        sage: X.<x,y,z> = M.chart()
        sage: f = X.multifunction(x+y+z, x*y*z)
        sage: f.is_immutable()
        False
        sage: f.set_immutable()
        sage: f.is_immutable()
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(3), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y', 'z',)); (x, y, z,) = X._first_ngens(3)
        >>> f = X.multifunction(x+y+z, x*y*z)
        >>> f.is_immutable()
        False
        >>> f.set_immutable()
        >>> f.is_immutable()
        True

    The chart functions are now immutable, too:

    Sage

        sage: f[0].parent()
        Ring of chart functions on Chart (M, (x, y, z))
        sage: f[0].is_immutable()
        True

    [Python]

        >>> from sage.all import *
        >>> f[Integer(0)].parent()
        Ring of chart functions on Chart (M, (x, y, z))
        >>> f[Integer(0)].is_immutable()
        True