def _sympysage_abs(self): """ EXAMPLES:: sage: from sympy import Symbol, Abs sage: assert abs(x)._sympy_() == Abs(Symbol('x')) sage: assert abs(x) == Abs(Symbol('x'))._sage_() """ from sage.functions.other import abs_symbolic return abs_symbolic(self.args[0]._sage_())
def simplify_abs_trig(expr): r""" 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) 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) Note that neither :meth:`~sage.symbolic.expression.Expression.simplify_trig` nor :meth:`~sage.symbolic.expression.Expression.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)) 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] 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)) 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) 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) TESTS: Simplification of expressions involving some symbolic derivatives:: sage: f = function('f') sage: s = abs(cos(x)) + abs(cos(y))*diff(f(x),x) + abs(cos(2*z)) sage: simplify_abs_trig(s) cos(y)*diff(f(x), x) + abs(cos(x)) - cos(2*z) sage: s = abs(sin(x))*diff(f(x),x).subs(x=y^2) + abs(cos(y)) sage: simplify_abs_trig(s) abs(sin(x))*D[0](f)(y^2) + cos(y) sage: forget() # for doctests below """ w0 = SR.wild() if expr.has(abs_symbolic(sin(w0))) or expr.has(abs_symbolic(cos(w0))): return SimplifyAbsTrig(expr)() return expr
def composition(self, ex, operator): r""" This is the only method of the base class :class:`~sage.symbolic.expression_conversions.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) :: sage: a = exp(function('f')(x)) # no abs(sin_or_cos(...)) sage: a.operator() exp sage: 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))) """ if operator is abs_symbolic: argum = ex.operands()[0] # argument of abs if argum.operator() is sin: # Case of abs(sin(...)) x = argum.operands()[0] # argument of sin w0 = SR.wild() if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic( cos(w0))): x = self(x) # treatment of nested abs(sin_or_cos(...)) # Simplifications for values of x in the range [-pi, 2*pi]: if x >= 0 and x <= pi: ex = sin(x) elif (x > pi and x <= 2 * pi) or (x >= -pi and x < 0): ex = -sin(x) return ex if argum.operator() is cos: # Case of abs(cos(...)) x = argum.operands()[0] # argument of cos w0 = SR.wild() if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic( cos(w0))): x = self(x) # treatment of nested abs(sin_or_cos(...)) # Simplifications for values of x in the range [-pi, 2*pi]: if (x >= -pi / 2 and x <= pi / 2) or (x >= 3 * pi / 2 and x <= 2 * pi): ex = cos(x) elif (x > pi / 2 and x <= 3 * pi / 2) or (x >= -pi and x < -pi / 2): ex = -cos(x) return ex # If no pattern is found, we default to ExpressionTreeWalker: return super(SimplifyAbsTrig, self).composition(ex, operator)