def _eval_(self, f, x): """ EXAMPLES:: sage: from sage.symbolic.integration.integral import indefinite_integral sage: indefinite_integral(exp(x), x) # indirect doctest e^x sage: indefinite_integral(exp(x), x^2) 2*(x - 1)*e^x TESTS: Check that :trac:`28842` is fixed:: sage: integrate(1/(x^4 + x^3 + 1), x) integrate(1/(x^4 + x^3 + 1), x) Check that :trac:`32002` is fixed:: sage: result = integral(2*min_symbolic(x,2*x),x) ... sage: result -1/2*x^2*sgn(x) + 3/2*x^2 """ # Check for x if not is_SymbolicVariable(x): if len(x.variables()) == 1: nx = x.variables()[0] f = f * x.diff(nx) x = nx else: return None # we try all listed integration algorithms A = None for integrator in self.integrators: try: A = integrator(f, x) except (NotImplementedError, TypeError, AttributeError, RuntimeError): pass except ValueError: # maxima is telling us something raise else: if not hasattr(A, 'operator'): return A else: uneval = integral(SR.wild(0), x, hold=True) if not A.has(uneval): return A return A
def _eval_(self, f, x, a, b): """ Return the results of symbolic evaluation of the integral. EXAMPLES:: sage: from sage.symbolic.integration.integral import definite_integral sage: definite_integral(exp(x),x,0,1) # indirect doctest e - 1 TESTS: Check that :trac:`32002` is fixed:: sage: result = integral(2*min_symbolic(x,2*x),x,-1,1) ... sage: result -1 """ # Check for x if not is_SymbolicVariable(x): if len(x.variables()) == 1: nx = x.variables()[0] f = f * x.diff(nx) x = nx else: return None args = (f, x, a, b) # we try all listed integration algorithms A = None for integrator in self.integrators: try: A = integrator(*args) except (NotImplementedError, TypeError, AttributeError, RuntimeError): pass except ValueError: # maxima is telling us something raise else: if not hasattr(A, 'operator'): return A else: uneval = integral(SR.wild(0), x, a, b, hold=True) if not A.has(uneval): return A return A
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 simplify_sqrt_real(expr): r""" 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 This improves over :meth:`~sage.symbolic.expression.Expression.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 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 Again, :meth:`~sage.symbolic.expression.Expression.canonicalize_radical` fails on the last one:: sage: (sqrt(x^2 + sqrt(4*x^2) + 1)).canonicalize_radical() x - 1 TESTS: Simplification of expressions involving some symbolic derivatives:: sage: f = function('f') sage: simplify_sqrt_real( diff(f(x), x)/sqrt(x^2-2*x+1) ) # x<0 => x-1<0 -diff(f(x), x)/(x - 1) sage: g = function('g') sage: simplify_sqrt_real( sqrt(x^3*diff(f(g(x)), x)^2) ) # x<0 (-x)^(3/2)*abs(D[0](f)(g(x)))*abs(diff(g(x), x)) sage: forget() # for doctests below """ w0 = SR.wild() one_half = Rational((1, 2)) if expr.has(w0**one_half) or expr.has(w0**(-one_half)): return SimplifySqrtReal(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)
def arithmetic(self, ex, operator): r""" This is the only method of the base class :class:`~sage.symbolic.expression_conversions.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) :: sage: a = x + 1 # no square root sage: 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 """ if operator is _pow: operands = ex.operands() power = operands[1] one_half = Rational((1, 2)) minus_one_half = -one_half if (power == one_half) or (power == minus_one_half): # This is a square root or the inverse of a square root w0 = SR.wild(0) w1 = SR.wild(1) sqrt_pattern = w0**one_half inv_sqrt_pattern = w0**minus_one_half sqrt_ratio_pattern1 = w0**one_half * w1**minus_one_half sqrt_ratio_pattern2 = w0**minus_one_half * w1**one_half argum = operands[0] # the argument of sqrt if argum.has(sqrt_pattern) or argum.has(inv_sqrt_pattern): argum = self(argum) # treatment of nested sqrt's den = argum.denominator() if not (den == 1): # the argument of sqrt is a fraction # NB: after #19312 (integrated in Sage 6.10.beta7), the # above test cannot be written as "if den != 1:" num = argum.numerator() if num < 0 or den < 0: ex = sqrt(-num) / sqrt(-den) else: ex = sqrt(argum) else: ex = sqrt(argum) simpl = SR(ex._maxima_().radcan()) if (not simpl.match(sqrt_pattern) and not simpl.match(inv_sqrt_pattern) and not simpl.match(sqrt_ratio_pattern1) and not simpl.match(sqrt_ratio_pattern2)): # radcan transformed substantially the expression, # possibly getting rid of some sqrt; in order to ensure a # positive result, the absolute value of radcan's output # is taken, the call to simplify() taking care of possible # assumptions regarding signs of subexpression of simpl: simpl = abs(simpl).simplify() if power == minus_one_half: simpl = SR(1) / simpl return simpl # If operator is not a square root, we default to ExpressionTreeWalker: return super(SimplifySqrtReal, self).arithmetic(ex, operator)