예제 #1
0
    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)