Utilities for Calculus - Manifolds

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

# Utilities for Calculus

This module defines helper functions which are used for simplifications and display of symbolic expressions.

AUTHORS:

- Michal Bejger (2015) : class `ExpressionNice`

- Eric Gourgoulhon (2015, 2017) : simplification functions

- Travis Scrimshaw (2016): review tweaks

- Marius Gerbershagen (2022) : skip simplification of expressions with a single number or symbolic variable

class sage.manifolds.utilities.ExpressionNice(ex)

  Bases: `Expression`

  Subclass of `Expression` for a “human-friendly” display of partial derivatives and the possibility to shorten the display by skipping the arguments of symbolic functions.

  INPUT:

  - `ex` – symbolic expression

  EXAMPLES:

  An expression formed with callable symbolic expressions:

  Sage

      sage: var('x y z')
      (x, y, z)
      sage: f = function('f')(x, y)
      sage: g = f.diff(y).diff(x)
      sage: h = function('h')(y, z)
      sage: k = h.diff(z)
      sage: fun = x*g + y*(k-z)^2

  Python

      >>> from sage.all import *
      >>> var('x y z')
      (x, y, z)
      >>> f = function('f')(x, y)
      >>> g = f.diff(y).diff(x)
      >>> h = function('h')(y, z)
      >>> k = h.diff(z)
      >>> fun = x*g + y*(k-z)**Integer(2)

  The standard Pynac display of partial derivatives:

  Sage

      sage: fun
      y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
      sage: latex(fun)
      y {\left(z - \frac{\partial}{\partial z}h\left(y, z\right)\right)}^{2} + x \frac{\partial^{2}}{\partial x\partial y}f\left(x, y\right)

  [Python]

      >>> from sage.all import *
      >>> fun
      y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
      >>> latex(fun)
      y {\left(z - \frac{\partial}{\partial z}h\left(y, z\right)\right)}^{2} + x \frac{\partial^{2}}{\partial x\partial y}f\left(x, y\right)

  With `ExpressionNice`, the Pynac notation `D[...]` is replaced by textbook-like notation:

  Sage

      sage: from sage.manifolds.utilities import ExpressionNice
      sage: ExpressionNice(fun)
      y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
      sage: latex(ExpressionNice(fun))
      y {\left(z - \frac{\partial\,h}{\partial z}\right)}^{2}
       + x \frac{\partial^2\,f}{\partial x\partial y}

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import ExpressionNice
      >>> ExpressionNice(fun)
      y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
      >>> latex(ExpressionNice(fun))
      y {\left(z - \frac{\partial\,h}{\partial z}\right)}^{2}
       + x \frac{\partial^2\,f}{\partial x\partial y}

  An example when function variables are themselves functions:

  Sage

      sage: f = function('f')(x, y)
      sage: g = function('g')(x, f)  # the second variable is the function f
      sage: fun = (g.diff(x))*x - x^2*f.diff(x,y)
      sage: fun
      -x^2*diff(f(x, y), x, y) + (diff(f(x, y), x)*D[1](g)(x, f(x, y)) + D[0](g)(x, f(x, y)))*x
      sage: ExpressionNice(fun)
      -x^2*d^2(f)/dxdy + (d(f)/dx*d(g)/d(f(x, y)) + d(g)/dx)*x
      sage: latex(ExpressionNice(fun))
      -x^{2} \frac{\partial^2\,f}{\partial x\partial y}
       + {\left(\frac{\partial\,f}{\partial x}
         \frac{\partial\,g}{\partial \left( f\left(x, y\right) \right)}
       + \frac{\partial\,g}{\partial x}\right)} x

  [Python]

      >>> from sage.all import *
      >>> f = function('f')(x, y)
      >>> g = function('g')(x, f)  # the second variable is the function f
      >>> fun = (g.diff(x))*x - x**Integer(2)*f.diff(x,y)
      >>> fun
      -x^2*diff(f(x, y), x, y) + (diff(f(x, y), x)*D[1](g)(x, f(x, y)) + D[0](g)(x, f(x, y)))*x
      >>> ExpressionNice(fun)
      -x^2*d^2(f)/dxdy + (d(f)/dx*d(g)/d(f(x, y)) + d(g)/dx)*x
      >>> latex(ExpressionNice(fun))
      -x^{2} \frac{\partial^2\,f}{\partial x\partial y}
       + {\left(\frac{\partial\,f}{\partial x}
         \frac{\partial\,g}{\partial \left( f\left(x, y\right) \right)}
       + \frac{\partial\,g}{\partial x}\right)} x

  Note that `D[1](g)(x, f(x,y))` is rendered as `d(g)/d(f(x, y))`.

  An example with multiple differentiations:

  Sage

      sage: fun = f.diff(x,x,y,y,x)*x
      sage: fun
      x*diff(f(x, y), x, x, x, y, y)
      sage: ExpressionNice(fun)
      x*d^5(f)/dx^3dy^2
      sage: latex(ExpressionNice(fun))
      x \frac{\partial^5\,f}{\partial x ^ 3\partial y ^ 2}

  Python

      >>> from sage.all import *
      >>> fun = f.diff(x,x,y,y,x)*x
      >>> fun
      x*diff(f(x, y), x, x, x, y, y)
      >>> ExpressionNice(fun)
      x*d^5(f)/dx^3dy^2
      >>> latex(ExpressionNice(fun))
      x \frac{\partial^5\,f}{\partial x ^ 3\partial y ^ 2}

  Parentheses are added around powers of partial derivatives to avoid any confusion:

  Sage

      sage: fun = f.diff(y)^2
      sage: fun
      diff(f(x, y), y)^2
      sage: ExpressionNice(fun)
      (d(f)/dy)^2
      sage: latex(ExpressionNice(fun))
      \left(\frac{\partial\,f}{\partial y}\right)^{2}

  [Python]

      >>> from sage.all import *
      >>> fun = f.diff(y)**Integer(2)
      >>> fun
      diff(f(x, y), y)^2
      >>> ExpressionNice(fun)
      (d(f)/dy)^2
      >>> latex(ExpressionNice(fun))
      \left(\frac{\partial\,f}{\partial y}\right)^{2}

  The explicit mention of function arguments can be omitted for the sake of brevity:

  Sage

      sage: fun = fun*f
      sage: ExpressionNice(fun)
      f(x, y)*(d(f)/dy)^2
      sage: Manifold.options.omit_function_arguments=True
      sage: ExpressionNice(fun)
      f*(d(f)/dy)^2
      sage: latex(ExpressionNice(fun))
      f \left(\frac{\partial\,f}{\partial y}\right)^{2}
      sage: Manifold.options._reset()
      sage: ExpressionNice(fun)
      f(x, y)*(d(f)/dy)^2
      sage: latex(ExpressionNice(fun))
      f\left(x, y\right) \left(\frac{\partial\,f}{\partial y}\right)^{2}

  Python

      >>> from sage.all import *
      >>> fun = fun*f
      >>> ExpressionNice(fun)
      f(x, y)*(d(f)/dy)^2
      >>> Manifold.options.omit_function_arguments=True
      >>> ExpressionNice(fun)
      f*(d(f)/dy)^2
      >>> latex(ExpressionNice(fun))
      f \left(\frac{\partial\,f}{\partial y}\right)^{2}
      >>> Manifold.options._reset()
      >>> ExpressionNice(fun)
      f(x, y)*(d(f)/dy)^2
      >>> latex(ExpressionNice(fun))
      f\left(x, y\right) \left(\frac{\partial\,f}{\partial y}\right)^{2}

class sage.manifolds.utilities.SimplifyAbsTrig(ex)

  Bases: `ExpressionTreeWalker`

  Class for simplifying absolute values of cosines or sines (in the real domain), by walking the expression tree.

  The end user interface is the function `simplify_abs_trig()`.

  INPUT:

  - `ex` – a symbolic expression

  EXAMPLES:

  Let us consider the following symbolic expression with some assumption on the range of the variable \(x\):

  Sage

      sage: assume(pi/2<x, x<pi)
      sage: a = abs(cos(x)) + abs(sin(x))

  Python

      >>> from sage.all import *
      >>> assume(pi/Integer(2)<x, x<pi)
      >>> a = abs(cos(x)) + abs(sin(x))

  The method `simplify_full()` works on such an expression:

  Sage

      sage: a.simplify_full()
      -cos(x) + sin(x)

  [Python]

      >>> from sage.all import *
      >>> a.simplify_full()
      -cos(x) + sin(x)

  We construct a `SimplifyAbsTrig` object `s` from the symbolic expression `a`:

  Sage

      sage: from sage.manifolds.utilities import SimplifyAbsTrig
      sage: s = SimplifyAbsTrig(a)

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import SimplifyAbsTrig
      >>> s = SimplifyAbsTrig(a)

  We use the `__call__` method to walk the expression tree and produce a correctly simplified expression, given that \(x\in(\pi/2, \pi)\):

  Sage

      sage: s()
      -cos(x) + sin(x)

  [Python]

      >>> from sage.all import *
      >>> s()
      -cos(x) + sin(x)

  Calling the simplifier `s` with an expression actually simplifies this expression:

  Sage

      sage: s(a)  # same as s() since s is built from a
      -cos(x) + sin(x)
      sage: s(abs(cos(x/2)) + abs(sin(x/2)))  #  pi/4 < x/2 < pi/2
      cos(1/2*x) + sin(1/2*x)
      sage: s(abs(cos(2*x)) + abs(sin(2*x)))  #  pi < 2 x < 2*pi
      abs(cos(2*x)) - sin(2*x)
      sage: s(abs(sin(2+abs(cos(x)))))  # nested abs(sin_or_cos(...))
      sin(-cos(x) + 2)

  Python

      >>> from sage.all import *
      >>> s(a)  # same as s() since s is built from a
      -cos(x) + sin(x)
      >>> s(abs(cos(x/Integer(2))) + abs(sin(x/Integer(2))))  #  pi/4 < x/2 < pi/2
      cos(1/2*x) + sin(1/2*x)
      >>> s(abs(cos(Integer(2)*x)) + abs(sin(Integer(2)*x)))  #  pi < 2 x < 2*pi
      abs(cos(2*x)) - sin(2*x)
      >>> s(abs(sin(Integer(2)+abs(cos(x)))))  # nested abs(sin_or_cos(...))
      sin(-cos(x) + 2)

  See also

  `simplify_abs_trig()` for more examples with `SimplifyAbsTrig` at work.

  composition(ex, operator)

    This is the only method of the base class `ExpressionTreeWalker` that is reimplemented, since it manages the composition of `abs` with `cos` or `sin`.

    INPUT:

    - `ex` – a symbolic expression

    - `operator` – an operator

    OUTPUT:

    - a symbolic expression, equivalent to `ex` with `abs(cos(...))` and `abs(sin(...))` simplified, according to the range of their argument.

    EXAMPLES:

    Sage

        sage: from sage.manifolds.utilities import SimplifyAbsTrig
        sage: assume(-pi/2 < x, x<0)
        sage: a = abs(sin(x))
        sage: s = SimplifyAbsTrig(a)
        sage: a.operator()
        abs
        sage: s.composition(a, a.operator())
        sin(-x)

    Python

        >>> from sage.all import *
        >>> from sage.manifolds.utilities import SimplifyAbsTrig
        >>> assume(-pi/Integer(2) < x, x<Integer(0))
        >>> a = abs(sin(x))
        >>> s = SimplifyAbsTrig(a)
        >>> a.operator()
        abs
        >>> s.composition(a, a.operator())
        sin(-x)

    Sage

        sage: a = exp(function('f')(x))  # no abs(sin_or_cos(...))
        sage: a.operator()
        exp
        sage: s.composition(a, a.operator())
        e^f(x)

    [Python]

        >>> from sage.all import *
        >>> a = exp(function('f')(x))  # no abs(sin_or_cos(...))
        >>> a.operator()
        exp
        >>> s.composition(a, a.operator())
        e^f(x)

    Sage

        sage: forget()  # no longer any assumption on x
        sage: a = abs(cos(sin(x)))  # simplifiable since -1 <= sin(x) <= 1
        sage: s.composition(a, a.operator())
        cos(sin(x))
        sage: a = abs(sin(cos(x)))  # not simplifiable
        sage: s.composition(a, a.operator())
        abs(sin(cos(x)))

    Python

        >>> from sage.all import *
        >>> forget()  # no longer any assumption on x
        >>> a = abs(cos(sin(x)))  # simplifiable since -1 <= sin(x) <= 1
        >>> s.composition(a, a.operator())
        cos(sin(x))
        >>> a = abs(sin(cos(x)))  # not simplifiable
        >>> s.composition(a, a.operator())
        abs(sin(cos(x)))

class sage.manifolds.utilities.SimplifySqrtReal(ex)

  Bases: `ExpressionTreeWalker`

  Class for simplifying square roots in the real domain, by walking the expression tree.

  The end user interface is the function `simplify_sqrt_real()`.

  INPUT:

  - `ex` – a symbolic expression

  EXAMPLES:

  Let us consider the square root of an exact square under some assumption:

  Sage

      sage: assume(x<1)
      sage: a = sqrt(x^2-2*x+1)

  Python

      >>> from sage.all import *
      >>> assume(x<Integer(1))
      >>> a = sqrt(x**Integer(2)-Integer(2)*x+Integer(1))

  The method `simplify_full()` is ineffective on such an expression:

  Sage

      sage: a.simplify_full()
      sqrt(x^2 - 2*x + 1)

  [Python]

      >>> from sage.all import *
      >>> a.simplify_full()
      sqrt(x^2 - 2*x + 1)

  and the more aggressive method `canonicalize_radical()` yields a wrong result, given that \(x<1\):

  Sage

      sage: a.canonicalize_radical()  # wrong output!
      x - 1

  Python

      >>> from sage.all import *
      >>> a.canonicalize_radical()  # wrong output!
      x - 1

  We construct a `SimplifySqrtReal` object `s` from the symbolic expression `a`:

  Sage

      sage: from sage.manifolds.utilities import SimplifySqrtReal
      sage: s = SimplifySqrtReal(a)

  [Python]

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import SimplifySqrtReal
      >>> s = SimplifySqrtReal(a)

  We use the `__call__` method to walk the expression tree and produce a correctly simplified expression:

  Sage

      sage: s()
      -x + 1

  Python

      >>> from sage.all import *
      >>> s()
      -x + 1

  Calling the simplifier `s` with an expression actually simplifies this expression:

  Sage

      sage: s(a)  # same as s() since s is built from a
      -x + 1
      sage: s(sqrt(x^2))
      abs(x)
      sage: s(sqrt(1+sqrt(x^2-2*x+1)))  # nested sqrt's
      sqrt(-x + 2)

  [Python]

      >>> from sage.all import *
      >>> s(a)  # same as s() since s is built from a
      -x + 1
      >>> s(sqrt(x**Integer(2)))
      abs(x)
      >>> s(sqrt(Integer(1)+sqrt(x**Integer(2)-Integer(2)*x+Integer(1))))  # nested sqrt's
      sqrt(-x + 2)

  Another example where both `simplify_full()` and `canonicalize_radical()` fail:

  Sage

      sage: b = sqrt((x-1)/(x-2))*sqrt(1-x)
      sage: b.simplify_full()  # does not simplify
      sqrt(-x + 1)*sqrt((x - 1)/(x - 2))
      sage: b.canonicalize_radical()  # wrong output, given that x<1
      (I*x - I)/sqrt(x - 2)
      sage: SimplifySqrtReal(b)()  # OK, given that x<1
      -(x - 1)/sqrt(-x + 2)

  Python

      >>> from sage.all import *
      >>> b = sqrt((x-Integer(1))/(x-Integer(2)))*sqrt(Integer(1)-x)
      >>> b.simplify_full()  # does not simplify
      sqrt(-x + 1)*sqrt((x - 1)/(x - 2))
      >>> b.canonicalize_radical()  # wrong output, given that x<1
      (I*x - I)/sqrt(x - 2)
      >>> SimplifySqrtReal(b)()  # OK, given that x<1
      -(x - 1)/sqrt(-x + 2)

  See also

  `simplify_sqrt_real()` for more examples with `SimplifySqrtReal` at work.

  arithmetic(ex, operator)

    This is the only method of the base class `ExpressionTreeWalker` that is reimplemented, since square roots are considered as arithmetic operations with `operator` = `pow` and `ex.operands()[1]` = `1/2` or `-1/2`.

    INPUT:

    - `ex` – a symbolic expression

    - `operator` – an arithmetic operator

    OUTPUT:

    - a symbolic expression, equivalent to `ex` with square roots simplified

    EXAMPLES:

    Sage

        sage: from sage.manifolds.utilities import SimplifySqrtReal
        sage: a = sqrt(x^2+2*x+1)
        sage: s = SimplifySqrtReal(a)
        sage: a.operator()
        <built-in function pow>
        sage: s.arithmetic(a, a.operator())
        abs(x + 1)

    Python

        >>> from sage.all import *
        >>> from sage.manifolds.utilities import SimplifySqrtReal
        >>> a = sqrt(x**Integer(2)+Integer(2)*x+Integer(1))
        >>> s = SimplifySqrtReal(a)
        >>> a.operator()
        <built-in function pow>
        >>> s.arithmetic(a, a.operator())
        abs(x + 1)

    Sage

        sage: a = x + 1  # no square root
        sage: s.arithmetic(a, a.operator())
        x + 1

    [Python]

        >>> from sage.all import *
        >>> a = x + Integer(1)  # no square root
        >>> s.arithmetic(a, a.operator())
        x + 1

    Sage

        sage: a = x + 1 + sqrt(function('f')(x)^2)
        sage: s.arithmetic(a, a.operator())
        x + abs(f(x)) + 1

    Python

        >>> from sage.all import *
        >>> a = x + Integer(1) + sqrt(function('f')(x)**Integer(2))
        >>> s.arithmetic(a, a.operator())
        x + abs(f(x)) + 1

sage.manifolds.utilities.exterior_derivative(form)

  Exterior derivative of a differential form.

  INPUT:

  - `form` – a differential form; this must an instance of either

    - `DiffScalarField` for a 0-form (scalar field)

    - `DiffFormParal` for a \(p\)-form (\(p\geq 1\)) on a parallelizable manifold

    - `DiffForm` for a a \(p\)-form (\(p\geq 1\)) on a non-parallelizable manifold

  OUTPUT:

  - the \((p+1)\)-form that is the exterior derivative of `form`

  EXAMPLES:

  Exterior derivative of a scalar field (0-form):

  Sage

      sage: from sage.manifolds.utilities import exterior_derivative
      sage: M = Manifold(3, 'M')
      sage: X.<x,y,z> = M.chart()
      sage: f = M.scalar_field({X: x+y^2+z^3}, name='f')
      sage: df = exterior_derivative(f); df
      1-form df on the 3-dimensional differentiable manifold M
      sage: df.display()
      df = dx + 2*y dy + 3*z^2 dz

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import exterior_derivative
      >>> M = Manifold(Integer(3), 'M')
      >>> X = M.chart(names=('x', 'y', 'z',)); (x, y, z,) = X._first_ngens(3)
      >>> f = M.scalar_field({X: x+y**Integer(2)+z**Integer(3)}, name='f')
      >>> df = exterior_derivative(f); df
      1-form df on the 3-dimensional differentiable manifold M
      >>> df.display()
      df = dx + 2*y dy + 3*z^2 dz

  An alias is `xder`:

  Sage

      sage: from sage.manifolds.utilities import xder
      sage: df == xder(f)
      True

  [Python]

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import xder
      >>> df == xder(f)
      True

  Exterior derivative of a 1-form:

  Sage

      sage: a = M.one_form(name='a')
      sage: a[:] = [x+y*z, x-y*z, x*y*z]
      sage: da = xder(a); da
      2-form da on the 3-dimensional differentiable manifold M
      sage: da.display()
      da = (-z + 1) dx∧dy + (y*z - y) dx∧dz + (x*z + y) dy∧dz
      sage: dda = xder(da); dda
      3-form dda on the 3-dimensional differentiable manifold M
      sage: dda.display()
      dda = 0

  Python

      >>> from sage.all import *
      >>> a = M.one_form(name='a')
      >>> a[:] = [x+y*z, x-y*z, x*y*z]
      >>> da = xder(a); da
      2-form da on the 3-dimensional differentiable manifold M
      >>> da.display()
      da = (-z + 1) dx∧dy + (y*z - y) dx∧dz + (x*z + y) dy∧dz
      >>> dda = xder(da); dda
      3-form dda on the 3-dimensional differentiable manifold M
      >>> dda.display()
      dda = 0

  See also

  `sage.manifolds.differentiable.diff_form.DiffFormParal.exterior_derivative` or `sage.manifolds.differentiable.diff_form.DiffForm.exterior_derivative` for more examples.

sage.manifolds.utilities.set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds)

  Set axes labels for a 3D graphics object `graph`.

  This is a workaround for the lack of axes labels in 3D plots. This sets the labels as `text3d()` objects at locations determined from the bounding box of the graphic object `graph`.

  INPUT:

  - `graph` – `Graphics3d`; a 3D graphic object

  - `xlabel` – string for the x-axis label

  - `ylabel` – string for the y-axis label

  - `zlabel` – string for the z-axis label

  - `**kwds` – options (e.g. color) for text3d

  OUTPUT: the 3D graphic object with text3d labels added

  EXAMPLES:

  Sage

      sage: # needs sage.plot
      sage: g = sphere()
      sage: g.all
      [Graphics3d Object]
      sage: from sage.manifolds.utilities import set_axes_labels
      sage: ga = set_axes_labels(g, 'X', 'Y', 'Z', color='red')
      sage: ga.all  # the 3D frame has now axes labels
      [Graphics3d Object, Graphics3d Object,
       Graphics3d Object, Graphics3d Object]

  Python

      >>> from sage.all import *
      >>> # needs sage.plot
      >>> g = sphere()
      >>> g.all
      [Graphics3d Object]
      >>> from sage.manifolds.utilities import set_axes_labels
      >>> ga = set_axes_labels(g, 'X', 'Y', 'Z', color='red')
      >>> ga.all  # the 3D frame has now axes labels
      [Graphics3d Object, Graphics3d Object,
       Graphics3d Object, Graphics3d Object]

sage.manifolds.utilities.simplify_abs_trig(expr)

  Simplify `abs(sin(...))` and `abs(cos(...))` in symbolic expressions.

  EXAMPLES:

  Sage

      sage: M = Manifold(3, 'M', structure='topological')
      sage: X.<x,y,z> = M.chart(r'x y:(0,pi) z:(-pi/3,0)')
      sage: X.coord_range()
      x: (-oo, +oo); y: (0, pi); z: (-1/3*pi, 0)

  Python

      >>> from sage.all import *
      >>> M = Manifold(Integer(3), 'M', structure='topological')
      >>> X = M.chart(r'x y:(0,pi) z:(-pi/3,0)', names=('x', 'y', 'z',)); (x, y, z,) = X._first_ngens(3)
      >>> X.coord_range()
      x: (-oo, +oo); y: (0, pi); z: (-1/3*pi, 0)

  Since \(x\) spans all \(\RR\), no simplification of `abs(sin(x))` occurs, while `abs(sin(y))` and `abs(sin(3*z))` are correctly simplified, given that \(y \in (0,\pi)\) and \(z \in (-\pi/3,0)\):

  Sage

      sage: from sage.manifolds.utilities import simplify_abs_trig
      sage: simplify_abs_trig( abs(sin(x)) + abs(sin(y)) + abs(sin(3*z)) )
      abs(sin(x)) + sin(y) + sin(-3*z)

  [Python]

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import simplify_abs_trig
      >>> simplify_abs_trig( abs(sin(x)) + abs(sin(y)) + abs(sin(Integer(3)*z)) )
      abs(sin(x)) + sin(y) + sin(-3*z)

  Note that neither `simplify_trig()` nor `simplify_full()` works in this case:

  Sage

      sage: s = abs(sin(x)) + abs(sin(y)) + abs(sin(3*z))
      sage: s.simplify_trig()
      -4*sin(-z)^3 + abs(sin(x)) + sin(y) + 3*sin(-z)
      sage: s.simplify_full()
      -4*sin(-z)^3 + abs(sin(x)) + sin(y) + 3*sin(-z)

  Python

      >>> from sage.all import *
      >>> s = abs(sin(x)) + abs(sin(y)) + abs(sin(Integer(3)*z))
      >>> s.simplify_trig()
      -4*sin(-z)^3 + abs(sin(x)) + sin(y) + 3*sin(-z)
      >>> s.simplify_full()
      -4*sin(-z)^3 + abs(sin(x)) + sin(y) + 3*sin(-z)

  despite the following assumptions hold:

  Sage

      sage: assumptions()
      [x is real, y is real, y > 0, y < pi, z is real, z > -1/3*pi, z < 0]

  [Python]

      >>> from sage.all import *
      >>> assumptions()
      [x is real, y is real, y > 0, y < pi, z is real, z > -1/3*pi, z < 0]

  Additional checks are:

  Sage

      sage: simplify_abs_trig( abs(sin(y/2)) )  # shall simplify
      sin(1/2*y)
      sage: simplify_abs_trig( abs(sin(2*y)) )  # must not simplify
      abs(sin(2*y))
      sage: simplify_abs_trig( abs(sin(z/2)) )  # shall simplify
      sin(-1/2*z)
      sage: simplify_abs_trig( abs(sin(4*z)) )  # must not simplify
      abs(sin(-4*z))

  Python

      >>> from sage.all import *
      >>> simplify_abs_trig( abs(sin(y/Integer(2))) )  # shall simplify
      sin(1/2*y)
      >>> simplify_abs_trig( abs(sin(Integer(2)*y)) )  # must not simplify
      abs(sin(2*y))
      >>> simplify_abs_trig( abs(sin(z/Integer(2))) )  # shall simplify
      sin(-1/2*z)
      >>> simplify_abs_trig( abs(sin(Integer(4)*z)) )  # must not simplify
      abs(sin(-4*z))

  Simplification of `abs(cos(...))`:

  Sage

      sage: forget()
      sage: M = Manifold(3, 'M', structure='topological')
      sage: X.<x,y,z> = M.chart(r'x y:(0,pi/2) z:(pi/4,3*pi/4)')
      sage: X.coord_range()
      x: (-oo, +oo); y: (0, 1/2*pi); z: (1/4*pi, 3/4*pi)
      sage: simplify_abs_trig( abs(cos(x)) + abs(cos(y)) + abs(cos(2*z)) )
      abs(cos(x)) + cos(y) - cos(2*z)

  [Python]

      >>> from sage.all import *
      >>> forget()
      >>> M = Manifold(Integer(3), 'M', structure='topological')
      >>> X = M.chart(r'x y:(0,pi/2) z:(pi/4,3*pi/4)', names=('x', 'y', 'z',)); (x, y, z,) = X._first_ngens(3)
      >>> X.coord_range()
      x: (-oo, +oo); y: (0, 1/2*pi); z: (1/4*pi, 3/4*pi)
      >>> simplify_abs_trig( abs(cos(x)) + abs(cos(y)) + abs(cos(Integer(2)*z)) )
      abs(cos(x)) + cos(y) - cos(2*z)

  Additional tests:

  Sage

      sage: simplify_abs_trig(abs(cos(y-pi/2)))  # shall simplify
      cos(-1/2*pi + y)
      sage: simplify_abs_trig(abs(cos(y+pi/2)))  # shall simplify
      -cos(1/2*pi + y)
      sage: simplify_abs_trig(abs(cos(y-pi)))  # shall simplify
      -cos(-pi + y)
      sage: simplify_abs_trig(abs(cos(2*y)))  # must not simplify
      abs(cos(2*y))
      sage: simplify_abs_trig(abs(cos(y/2)) * abs(sin(z)))  # shall simplify
      cos(1/2*y)*sin(z)

  Python

      >>> from sage.all import *
      >>> simplify_abs_trig(abs(cos(y-pi/Integer(2))))  # shall simplify
      cos(-1/2*pi + y)
      >>> simplify_abs_trig(abs(cos(y+pi/Integer(2))))  # shall simplify
      -cos(1/2*pi + y)
      >>> simplify_abs_trig(abs(cos(y-pi)))  # shall simplify
      -cos(-pi + y)
      >>> simplify_abs_trig(abs(cos(Integer(2)*y)))  # must not simplify
      abs(cos(2*y))
      >>> simplify_abs_trig(abs(cos(y/Integer(2))) * abs(sin(z)))  # shall simplify
      cos(1/2*y)*sin(z)

sage.manifolds.utilities.simplify_chain_generic(expr)

  Apply a chain of simplifications to a symbolic expression.

  This is the simplification chain used in calculus involving coordinate functions on manifolds over fields different from \(\RR\), as implemented in `ChartFunction`.

  The chain is formed by the following functions, called successively:

  1. `simplify_factorial()`

  2. `simplify_rectform()`

  3. `simplify_trig()`

  4. `simplify_rational()`

  5. `expand_sum()`

  NB: for the time being, this is identical to `simplify_full()`.

  EXAMPLES:

  We consider variables that are coordinates of a chart on a complex manifold:

  Sage

      sage: M = Manifold(2, 'M', structure='topological', field='complex')
      sage: X.<x,y> = M.chart()

  Python

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

  Then neither `x` nor `y` is assumed to be real:

  Sage

      sage: assumptions()
      []

  [Python]

      >>> from sage.all import *
      >>> assumptions()
      []

  Accordingly, `simplify_chain_generic` does not simplify `sqrt(x^2)` to `abs(x)`:

  Sage

      sage: from sage.manifolds.utilities import simplify_chain_generic
      sage: s = sqrt(x^2)
      sage: simplify_chain_generic(s)
      sqrt(x^2)

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import simplify_chain_generic
      >>> s = sqrt(x**Integer(2))
      >>> simplify_chain_generic(s)
      sqrt(x^2)

  This contrasts with the behavior of `simplify_chain_real()`.

  Other simplifications:

  Sage

      sage: s = (x+y)^2 - x^2 -2*x*y - y^2
      sage: simplify_chain_generic(s)
      0
      sage: s = (x^2 - 2*x + 1) / (x^2 -1)
      sage: simplify_chain_generic(s)
      (x - 1)/(x + 1)
      sage: s = cos(2*x) - 2*cos(x)^2 + 1
      sage: simplify_chain_generic(s)
      0

  [Python]

      >>> from sage.all import *
      >>> s = (x+y)**Integer(2) - x**Integer(2) -Integer(2)*x*y - y**Integer(2)
      >>> simplify_chain_generic(s)
      0
      >>> s = (x**Integer(2) - Integer(2)*x + Integer(1)) / (x**Integer(2) -Integer(1))
      >>> simplify_chain_generic(s)
      (x - 1)/(x + 1)
      >>> s = cos(Integer(2)*x) - Integer(2)*cos(x)**Integer(2) + Integer(1)
      >>> simplify_chain_generic(s)
      0

sage.manifolds.utilities.simplify_chain_generic_sympy(expr)

  Apply a chain of simplifications to a sympy expression.

  This is the simplification chain used in calculus involving coordinate functions on manifolds over fields different from \(\RR\), as implemented in `ChartFunction`.

  The chain is formed by the following functions, called successively:

  1. `combsimp()`

  2. `trigsimp()`

  3. `expand()`

  4. `simplify()`

  EXAMPLES:

  We consider variables that are coordinates of a chart on a complex manifold:

  Sage

      sage: forget()  # for doctest only
      sage: M = Manifold(2, 'M', structure='topological', field='complex', calc_method='sympy')
      sage: X.<x,y> = M.chart()

  Python

      >>> from sage.all import *
      >>> forget()  # for doctest only
      >>> M = Manifold(Integer(2), 'M', structure='topological', field='complex', calc_method='sympy')
      >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)

  Then neither `x` nor `y` is assumed to be real:

  Sage

      sage: assumptions()
      []

  [Python]

      >>> from sage.all import *
      >>> assumptions()
      []

  Accordingly, `simplify_chain_generic_sympy` does not simplify `sqrt(x^2)` to `abs(x)`:

  Sage

      sage: from sage.manifolds.utilities import simplify_chain_generic_sympy
      sage: s = (sqrt(x^2))._sympy_()
      sage: simplify_chain_generic_sympy(s)
      sqrt(x**2)

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import simplify_chain_generic_sympy
      >>> s = (sqrt(x**Integer(2)))._sympy_()
      >>> simplify_chain_generic_sympy(s)
      sqrt(x**2)

  This contrasts with the behavior of `simplify_chain_real_sympy()`.

  Other simplifications:

  Sage

      sage: s = ((x+y)^2 - x^2 -2*x*y - y^2)._sympy_()
      sage: simplify_chain_generic_sympy(s)
      0
      sage: s = ((x^2 - 2*x + 1) / (x^2 -1))._sympy_()
      sage: simplify_chain_generic_sympy(s)
      (x - 1)/(x + 1)
      sage: s = (cos(2*x) - 2*cos(x)^2 + 1)._sympy_()
      sage: simplify_chain_generic_sympy(s)
      0

  [Python]

      >>> from sage.all import *
      >>> s = ((x+y)**Integer(2) - x**Integer(2) -Integer(2)*x*y - y**Integer(2))._sympy_()
      >>> simplify_chain_generic_sympy(s)
      0
      >>> s = ((x**Integer(2) - Integer(2)*x + Integer(1)) / (x**Integer(2) -Integer(1)))._sympy_()
      >>> simplify_chain_generic_sympy(s)
      (x - 1)/(x + 1)
      >>> s = (cos(Integer(2)*x) - Integer(2)*cos(x)**Integer(2) + Integer(1))._sympy_()
      >>> simplify_chain_generic_sympy(s)
      0

sage.manifolds.utilities.simplify_chain_real(expr)

  Apply a chain of simplifications to a symbolic expression, assuming the real domain.

  This is the simplification chain used in calculus involving coordinate functions on real manifolds, as implemented in `ChartFunction`.

  The chain is formed by the following functions, called successively:

  1. `simplify_factorial()`

  2. `simplify_trig()`

  3. `simplify_rational()`

  4. `simplify_sqrt_real()`

  5. `simplify_abs_trig()`

  6. `canonicalize_radical()`

  7. `simplify_log()`

  8. `simplify_rational()`

  9. `simplify_trig()`

  EXAMPLES:

  We consider variables that are coordinates of a chart on a real manifold:

  Sage

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

  Python

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

  The following assumptions then hold:

  Sage

      sage: assumptions()
      [x is real, x > 0, x < 1, y is real]

  [Python]

      >>> from sage.all import *
      >>> assumptions()
      [x is real, x > 0, x < 1, y is real]

  and we have:

  Sage

      sage: from sage.manifolds.utilities import simplify_chain_real
      sage: s = sqrt(y^2)
      sage: simplify_chain_real(s)
      abs(y)

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import simplify_chain_real
      >>> s = sqrt(y**Integer(2))
      >>> simplify_chain_real(s)
      abs(y)

  The above result is correct since `y` is real. It is obtained by `simplify_real()` as well:

  Sage

      sage: s.simplify_real()
      abs(y)
      sage: s.simplify_full()
      abs(y)

  [Python]

      >>> from sage.all import *
      >>> s.simplify_real()
      abs(y)
      >>> s.simplify_full()
      abs(y)

  Furthermore, we have:

  Sage

      sage: s = sqrt(x^2-2*x+1)
      sage: simplify_chain_real(s)
      -x + 1

  Python

      >>> from sage.all import *
      >>> s = sqrt(x**Integer(2)-Integer(2)*x+Integer(1))
      >>> simplify_chain_real(s)
      -x + 1

  which is correct since \(x \in (0,1)\). On this example, neither `simplify_real()` nor `simplify_full()`, nor `canonicalize_radical()` give satisfactory results:

  Sage

      sage: s.simplify_real()  # unsimplified output
      sqrt(x^2 - 2*x + 1)
      sage: s.simplify_full()  # unsimplified output
      sqrt(x^2 - 2*x + 1)
      sage: s.canonicalize_radical()  # wrong output since x in (0,1)
      x - 1

  [Python]

      >>> from sage.all import *
      >>> s.simplify_real()  # unsimplified output
      sqrt(x^2 - 2*x + 1)
      >>> s.simplify_full()  # unsimplified output
      sqrt(x^2 - 2*x + 1)
      >>> s.canonicalize_radical()  # wrong output since x in (0,1)
      x - 1

  Other simplifications:

  Sage

      sage: s = abs(sin(pi*x))
      sage: simplify_chain_real(s)  # correct output since x in (0,1)
      sin(pi*x)
      sage: s.simplify_real()  # simplified output with maxima>=5.48
      sin(pi*x)
      sage: s.simplify_full()  # simplified output with maxima>=5.48
      sin(pi*x)

  Python

      >>> from sage.all import *
      >>> s = abs(sin(pi*x))
      >>> simplify_chain_real(s)  # correct output since x in (0,1)
      sin(pi*x)
      >>> s.simplify_real()  # simplified output with maxima>=5.48
      sin(pi*x)
      >>> s.simplify_full()  # simplified output with maxima>=5.48
      sin(pi*x)

  Sage

      sage: s = cos(y)^2 + sin(y)^2
      sage: simplify_chain_real(s)
      1
      sage: s.simplify_real()  # unsimplified output
      cos(y)^2 + sin(y)^2
      sage: s.simplify_full()  # OK
      1

  [Python]

      >>> from sage.all import *
      >>> s = cos(y)**Integer(2) + sin(y)**Integer(2)
      >>> simplify_chain_real(s)
      1
      >>> s.simplify_real()  # unsimplified output
      cos(y)^2 + sin(y)^2
      >>> s.simplify_full()  # OK
      1

sage.manifolds.utilities.simplify_chain_real_sympy(expr)

  Apply a chain of simplifications to a sympy expression, assuming the real domain.

  This is the simplification chain used in calculus involving coordinate functions on real manifolds, as implemented in `ChartFunction`.

  The chain is formed by the following functions, called successively:

  1. `combsimp()`

  2. `trigsimp()`

  3. `simplify_sqrt_real()`

  4. `simplify_abs_trig()`

  5. `expand()`

  6. `simplify()`

  EXAMPLES:

  We consider variables that are coordinates of a chart on a real manifold:

  Sage

      sage: forget()  # for doctest only
      sage: M = Manifold(2, 'M', structure='topological',calc_method='sympy')
      sage: X.<x,y> = M.chart('x:(0,1) y')

  Python

      >>> from sage.all import *
      >>> forget()  # for doctest only
      >>> M = Manifold(Integer(2), 'M', structure='topological',calc_method='sympy')
      >>> X = M.chart('x:(0,1) y', names=('x', 'y',)); (x, y,) = X._first_ngens(2)

  The following assumptions then hold:

  Sage

      sage: assumptions()
      [x is real, x > 0, x < 1, y is real]

  [Python]

      >>> from sage.all import *
      >>> assumptions()
      [x is real, x > 0, x < 1, y is real]

  and we have:

  Sage

      sage: from sage.manifolds.utilities import simplify_chain_real_sympy
      sage: s = (sqrt(y^2))._sympy_()
      sage: simplify_chain_real_sympy(s)
      Abs(y)

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import simplify_chain_real_sympy
      >>> s = (sqrt(y**Integer(2)))._sympy_()
      >>> simplify_chain_real_sympy(s)
      Abs(y)

  Furthermore, we have:

  Sage

      sage: s = (sqrt(x^2-2*x+1))._sympy_()
      sage: simplify_chain_real_sympy(s)
      1 - x

  [Python]

      >>> from sage.all import *
      >>> s = (sqrt(x**Integer(2)-Integer(2)*x+Integer(1)))._sympy_()
      >>> simplify_chain_real_sympy(s)
      1 - x

  Other simplifications:

  Sage

      sage: s = (abs(sin(pi*x)))._sympy_()
      sage: simplify_chain_real_sympy(s)  # correct output since x in (0,1)
      sin(pi*x)

  Python

      >>> from sage.all import *
      >>> s = (abs(sin(pi*x)))._sympy_()
      >>> simplify_chain_real_sympy(s)  # correct output since x in (0,1)
      sin(pi*x)

  Sage

      sage: s = (cos(y)^2 + sin(y)^2)._sympy_()
      sage: simplify_chain_real_sympy(s)
      1

  [Python]

      >>> from sage.all import *
      >>> s = (cos(y)**Integer(2) + sin(y)**Integer(2))._sympy_()
      >>> simplify_chain_real_sympy(s)
      1

sage.manifolds.utilities.simplify_sqrt_real(expr)

  Simplify `sqrt` in symbolic expressions in the real domain.

  EXAMPLES:

  Simplifications of basic expressions:

  Sage

      sage: from sage.manifolds.utilities import simplify_sqrt_real
      sage: simplify_sqrt_real( sqrt(x^2) )
      abs(x)
      sage: assume(x<0)
      sage: simplify_sqrt_real( sqrt(x^2) )
      -x
      sage: simplify_sqrt_real( sqrt(x^2-2*x+1) )
      -x + 1
      sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) )
      -2*x + 1

  Python

      >>> from sage.all import *
      >>> from sage.manifolds.utilities import simplify_sqrt_real
      >>> simplify_sqrt_real( sqrt(x**Integer(2)) )
      abs(x)
      >>> assume(x<Integer(0))
      >>> simplify_sqrt_real( sqrt(x**Integer(2)) )
      -x
      >>> simplify_sqrt_real( sqrt(x**Integer(2)-Integer(2)*x+Integer(1)) )
      -x + 1
      >>> simplify_sqrt_real( sqrt(x**Integer(2)) + sqrt(x**Integer(2)-Integer(2)*x+Integer(1)) )
      -2*x + 1

  This improves over `canonicalize_radical()`, which yields incorrect results when `x < 0`:

  Sage

      sage: forget()  # removes the assumption x<0
      sage: sqrt(x^2).canonicalize_radical()
      x
      sage: assume(x<0)
      sage: sqrt(x^2).canonicalize_radical()
      -x
      sage: sqrt(x^2-2*x+1).canonicalize_radical() # wrong output
      x - 1
      sage: ( sqrt(x^2) + sqrt(x^2-2*x+1) ).canonicalize_radical() # wrong output
      -1

  [Python]

      >>> from sage.all import *
      >>> forget()  # removes the assumption x<0
      >>> sqrt(x**Integer(2)).canonicalize_radical()
      x
      >>> assume(x<Integer(0))
      >>> sqrt(x**Integer(2)).canonicalize_radical()
      -x
      >>> sqrt(x**Integer(2)-Integer(2)*x+Integer(1)).canonicalize_radical() # wrong output
      x - 1
      >>> ( sqrt(x**Integer(2)) + sqrt(x**Integer(2)-Integer(2)*x+Integer(1)) ).canonicalize_radical() # wrong output
      -1

  Simplification of nested `sqrt`’s:

  Sage

      sage: forget()  # removes the assumption x<0
      sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
      sqrt(abs(x) + 1)
      sage: assume(x<0)
      sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
      sqrt(-x + 1)
      sage: simplify_sqrt_real( sqrt(x^2 + sqrt(4*x^2) + 1) )
      -x + 1

  Python

      >>> from sage.all import *
      >>> forget()  # removes the assumption x<0
      >>> simplify_sqrt_real( sqrt(Integer(1) + sqrt(x**Integer(2))) )
      sqrt(abs(x) + 1)
      >>> assume(x<Integer(0))
      >>> simplify_sqrt_real( sqrt(Integer(1) + sqrt(x**Integer(2))) )
      sqrt(-x + 1)
      >>> simplify_sqrt_real( sqrt(x**Integer(2) + sqrt(Integer(4)*x**Integer(2)) + Integer(1)) )
      -x + 1

  Again, `canonicalize_radical()` fails on the last one:

  Sage

      sage: (sqrt(x^2 + sqrt(4*x^2) + 1)).canonicalize_radical()
      x - 1

  [Python]

      >>> from sage.all import *
      >>> (sqrt(x**Integer(2) + sqrt(Integer(4)*x**Integer(2)) + Integer(1))).canonicalize_radical()
      x - 1

sage.manifolds.utilities.xder(form)

  alias of `exterior_derivative()`.