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)[source]#

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: 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
>>> 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: 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)
>>> 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: 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}
>>> 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: 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
>>> 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: 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}
>>> 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: 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}
>>> 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: 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}
>>> 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)[source]#

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: assume(pi/2<x, x<pi)
sage: a = abs(cos(x)) + abs(sin(x))
>>> from sage.all import *
>>> assume(pi/Integer(2)<x, x<pi)
>>> a = abs(cos(x)) + abs(sin(x))

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

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

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

sage: from sage.manifolds.utilities import SimplifyAbsTrig
sage: s = SimplifyAbsTrig(a)
>>> 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: s()
-cos(x) + sin(x)
>>> from sage.all import *
>>> s()
-cos(x) + sin(x)

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

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)
>>> 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)[source]#

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: 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)
>>> 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: a = exp(function('f')(x))  # no abs(sin_or_cos(...))
sage: a.operator()
exp
sage: s.composition(a, a.operator())
e^f(x)
>>> 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: 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)))
>>> 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)[source]#

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: assume(x<1)
sage: a = sqrt(x^2-2*x+1)
>>> 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: a.simplify_full()
sqrt(x^2 - 2*x + 1)
>>> 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: a.canonicalize_radical()  # wrong output!
x - 1
>>> from sage.all import *
>>> a.canonicalize_radical()  # wrong output!
x - 1

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

sage: from sage.manifolds.utilities import SimplifySqrtReal
sage: s = SimplifySqrtReal(a)
>>> 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: s()
-x + 1
>>> from sage.all import *
>>> s()
-x + 1

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

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)
>>> 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: 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)
>>> 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)[source]#

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: 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)
>>> 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: a = x + 1  # no square root
sage: s.arithmetic(a, a.operator())
x + 1
>>> from sage.all import *
>>> a = x + Integer(1)  # no square root
>>> s.arithmetic(a, a.operator())
x + 1
sage: a = x + 1 + sqrt(function('f')(x)^2)
sage: s.arithmetic(a, a.operator())
x + abs(f(x)) + 1
>>> 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)[source]#

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: 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
>>> 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: from sage.manifolds.utilities import xder
sage: df == xder(f)
True
>>> from sage.all import *
>>> from sage.manifolds.utilities import xder
>>> df == xder(f)
True

Exterior derivative of a 1-form:

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
>>> 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
sage.manifolds.utilities.set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds)[source]#

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:

  • graphGraphics3d; 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: # 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]
>>> 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)[source]#

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

EXAMPLES:

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)
>>> 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: 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)
>>> 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: s = abs(sin(x)) + abs(sin(y)) + abs(sin(3*z))
sage: s.simplify_trig()
abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
sage: s.simplify_full()
abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
>>> from sage.all import *
>>> s = abs(sin(x)) + abs(sin(y)) + abs(sin(Integer(3)*z))
>>> s.simplify_trig()
abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
>>> s.simplify_full()
abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))

despite the following assumptions hold:

sage: assumptions()
[x is real, y is real, y > 0, y < pi, z is real, z > -1/3*pi, z < 0]
>>> 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: 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))
>>> 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: 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)
>>> 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: 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)
>>> 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)[source]#

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: M = Manifold(2, 'M', structure='topological', field='complex')
sage: X.<x,y> = M.chart()
>>> 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: assumptions()
[]
>>> from sage.all import *
>>> assumptions()
[]

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

sage: from sage.manifolds.utilities import simplify_chain_generic
sage: s = sqrt(x^2)
sage: simplify_chain_generic(s)
sqrt(x^2)
>>> 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: 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
>>> 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)[source]#

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: forget()  # for doctest only
sage: M = Manifold(2, 'M', structure='topological', field='complex', calc_method='sympy')
sage: X.<x,y> = M.chart()
>>> 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: assumptions()
[]
>>> from sage.all import *
>>> assumptions()
[]

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

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)
>>> 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: 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
>>> 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)[source]#

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: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart('x:(0,1) y')
>>> 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: assumptions()
[x is real, x > 0, x < 1, y is real]
>>> from sage.all import *
>>> assumptions()
[x is real, x > 0, x < 1, y is real]

and we have:

sage: from sage.manifolds.utilities import simplify_chain_real
sage: s = sqrt(y^2)
sage: simplify_chain_real(s)
abs(y)
>>> 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: s.simplify_real()
abs(y)
sage: s.simplify_full()
abs(y)
>>> from sage.all import *
>>> s.simplify_real()
abs(y)
>>> s.simplify_full()
abs(y)

Furthermore, we have:

sage: s = sqrt(x^2-2*x+1)
sage: simplify_chain_real(s)
-x + 1
>>> 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: 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
>>> 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: s = abs(sin(pi*x))
sage: simplify_chain_real(s)  # correct output since x in (0,1)
sin(pi*x)
sage: s.simplify_real()  # unsimplified output
abs(sin(pi*x))
sage: s.simplify_full()  # unsimplified output
abs(sin(pi*x))
>>> 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()  # unsimplified output
abs(sin(pi*x))
>>> s.simplify_full()  # unsimplified output
abs(sin(pi*x))
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
>>> 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)[source]#

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: forget()  # for doctest only
sage: M = Manifold(2, 'M', structure='topological',calc_method='sympy')
sage: X.<x,y> = M.chart('x:(0,1) y')
>>> 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: assumptions()
[x is real, x > 0, x < 1, y is real]
>>> from sage.all import *
>>> assumptions()
[x is real, x > 0, x < 1, y is real]

and we have:

sage: from sage.manifolds.utilities import simplify_chain_real_sympy
sage: s = (sqrt(y^2))._sympy_()
sage: simplify_chain_real_sympy(s)
Abs(y)
>>> 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: s = (sqrt(x^2-2*x+1))._sympy_()
sage: simplify_chain_real_sympy(s)
1 - x
>>> 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: s = (abs(sin(pi*x)))._sympy_()
sage: simplify_chain_real_sympy(s)  # correct output since x in (0,1)
sin(pi*x)
>>> 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: s = (cos(y)^2 + sin(y)^2)._sympy_()
sage: simplify_chain_real_sympy(s)
1
>>> 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)[source]#

Simplify sqrt in symbolic expressions in the real domain.

EXAMPLES:

Simplifications of basic expressions:

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
>>> 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: 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
>>> 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: 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
>>> 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: (sqrt(x^2 + sqrt(4*x^2) + 1)).canonicalize_radical()
x - 1
>>> 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)[source]#

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: 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
>>> 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: from sage.manifolds.utilities import xder
sage: df == xder(f)
True
>>> from sage.all import *
>>> from sage.manifolds.utilities import xder
>>> df == xder(f)
True

Exterior derivative of a 1-form:

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
>>> 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