Ejemplo n.º 1
0
def _sqrtdenest34(expr):
    """Helper that denests the square root of three or four surds.

    Examples
    ========
    >>> from sympy import sqrt
    >>> from sympy.simplify.sqrtdenest import _sqrtdenest34
    >>> _sqrtdenest34(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498))
    -sqrt(10) + sqrt(2) + 9 + 9*sqrt(5)
    >>> _sqrtdenest34(sqrt(12 + 2*sqrt(6) + 2*sqrt(14) + 2*sqrt(21)))
    sqrt(2) + sqrt(3) + sqrt(7)

    References
    ==========
    - D. J. Jeffrey and A. D. Rich, 'Symplifying Square Roots of Square Roots
      by Denesting'

    """
    from sympy.simplify.simplify import radsimp
    if expr.base < 0:
        return sqrt(-1)*_sqrtdenest34(sqrt(-expr.base))
    # a should be > b so we sort; this also makes the process canonical
    args = sorted(expr.base.args, reverse=True)
    a = Add._from_args(args[:2])
    b = Add._from_args(args[2:])
    c = _sqrtdenest1(sqrt(_mexpand(a**2 - b**2)))
    if sqrt_depth(c) > 1:
        return expr
    d = _sqrtdenest1(sqrt(a + c))
    if sqrt_depth(d) > 1:
        return expr
    return _mexpand(radsimp((d/sqrt(2) + b/(sqrt(2)*d))))
Ejemplo n.º 2
0
def _sqrtdenest34(expr):
    """Helper that denests the square root of three or four surds.

    Examples
    ========
    >>> from sympy import sqrt
    >>> from sympy.simplify.sqrtdenest import _sqrtdenest34
    >>> _sqrtdenest34(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498))
    -sqrt(10) + sqrt(2) + 9 + 9*sqrt(5)
    >>> _sqrtdenest34(sqrt(12 + 2*sqrt(6) + 2*sqrt(14) + 2*sqrt(21)))
    sqrt(2) + sqrt(3) + sqrt(7)

    References
    ==========
    - D. J. Jeffrey and A. D. Rich, 'Symplifying Square Roots of Square Roots
      by Denesting'

    """
    from sympy.simplify.simplify import radsimp
    if expr.base < 0:
        return sqrt(-1) * _sqrtdenest34(sqrt(-expr.base))
    # a should be > b so we sort; this also makes the process canonical
    args = sorted(expr.base.args, reverse=True)
    a = Add._from_args(args[:2])
    b = Add._from_args(args[2:])
    c = _sqrtdenest1(sqrt(_mexpand(a**2 - b**2)))
    if sqrt_depth(c) > 1:
        return expr
    d = _sqrtdenest1(sqrt(a + c))
    if sqrt_depth(d) > 1:
        return expr
    return _mexpand(radsimp((d / sqrt(2) + b / (sqrt(2) * d))))
Ejemplo n.º 3
0
def _sqrtdenest_rec(expr):
    """Helper that denests the square root of three or more surds.

    It returns the denested expression; if it cannot be denested it
    throws SqrtdenestStopIteration

    Algorithm: expr.base is in the extension Q_m = Q(sqrt(r_1),..,sqrt(r_k));
    split expr.base = a + b*sqrt(r_k), where `a` and `b` are on
    Q_(m-1) = Q(sqrt(r_1),..,sqrt(r_(k-1))); then a**2 - b**2*r_k is
    on Q_(m-1); denest sqrt(a**2 - b**2*r_k) and so on.
    See [1], section 6.

    Examples
    ========

    >>> from sympy import sqrt
    >>> from sympy.simplify.sqrtdenest import _sqrtdenest_rec
    >>> _sqrtdenest_rec(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498))
    -sqrt(10) + sqrt(2) + 9 + 9*sqrt(5)
    >>> w=-6*sqrt(55)-6*sqrt(35)-2*sqrt(22)-2*sqrt(14)+2*sqrt(77)+6*sqrt(10)+65
    >>> _sqrtdenest_rec(sqrt(w))
    -sqrt(11) - sqrt(7) + sqrt(2) + 3*sqrt(5)
    """
    from sympy.simplify.simplify import radsimp, split_surds, rad_rationalize
    if not expr.is_Pow:
        return sqrtdenest(expr)
    if expr.base < 0:
        return sqrt(-1)*_sqrtdenest_rec(sqrt(-expr.base))
    g, a, b = split_surds(expr.base)
    a = a*sqrt(g)
    if a < b:
        a, b = b, a
    c2 = _mexpand(a**2 - b**2)
    if len(c2.args) > 2:
        g, a1, b1 = split_surds(c2)
        a1 = a1*sqrt(g)
        if a1 < b1:
            a1, b1 = b1, a1
        c2_1 = _mexpand(a1**2 - b1**2)
        c_1 = _sqrtdenest_rec(sqrt(c2_1))
        d_1 = _sqrtdenest_rec(sqrt(a1 + c_1))
        num, den = rad_rationalize(b1, d_1)
        c = _mexpand(d_1/sqrt(2) + num/(den*sqrt(2)))
    else:
        c = _sqrtdenest1(sqrt(c2))

    if sqrt_depth(c) > 1:
        raise SqrtdenestStopIteration
    ac = a + c
    if len(ac.args) >= len(expr.args):
        if count_ops(ac) >= count_ops(expr.base):
            raise SqrtdenestStopIteration
    d = sqrtdenest(sqrt(ac))
    if sqrt_depth(d) > 1:
        raise SqrtdenestStopIteration
    num, den = rad_rationalize(b, d)
    r = d/sqrt(2) + num/(den*sqrt(2))
    r = radsimp(r)
    return _mexpand(r)
Ejemplo n.º 4
0
def _sqrtdenest_rec(expr):
    """Helper that denests the square root of three or more surds.

    It returns the denested expression; if it cannot be denested it
    throws SqrtdenestStopIteration

    Algorithm: expr.base is in the extension Q_m = Q(sqrt(r_1),..,sqrt(r_k));
    split expr.base = a + b*sqrt(r_k), where `a` and `b` are on
    Q_(m-1) = Q(sqrt(r_1),..,sqrt(r_(k-1))); then a**2 - b**2*r_k is
    on Q_(m-1); denest sqrt(a**2 - b**2*r_k) and so on.
    See [1], section 6.

    Examples
    ========

    >>> from sympy import sqrt
    >>> from sympy.simplify.sqrtdenest import _sqrtdenest_rec
    >>> _sqrtdenest_rec(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498))
    -sqrt(10) + sqrt(2) + 9 + 9*sqrt(5)
    >>> w=-6*sqrt(55)-6*sqrt(35)-2*sqrt(22)-2*sqrt(14)+2*sqrt(77)+6*sqrt(10)+65
    >>> _sqrtdenest_rec(sqrt(w))
    -sqrt(11) - sqrt(7) + sqrt(2) + 3*sqrt(5)
    """
    from sympy.simplify.simplify import radsimp, split_surds, rad_rationalize
    if not expr.is_Pow:
        return sqrtdenest(expr)
    if expr.base < 0:
        return sqrt(-1)*_sqrtdenest_rec(sqrt(-expr.base))
    g, a, b = split_surds(expr.base)
    a = a*sqrt(g)
    if a < b:
        a, b = b, a
    c2 = _mexpand(a**2 - b**2)
    if len(c2.args) > 2:
        g, a1, b1 = split_surds(c2)
        a1 = a1*sqrt(g)
        if a1 < b1:
            a1, b1 = b1, a1
        c2_1 = _mexpand(a1**2 - b1**2)
        c_1 = _sqrtdenest_rec(sqrt(c2_1))
        d_1 = _sqrtdenest_rec(sqrt(a1 + c_1))
        num, den = rad_rationalize(b1, d_1)
        c = _mexpand(d_1/sqrt(2) + num/(den*sqrt(2)))
    else:
        c = _sqrtdenest1(sqrt(c2))

    if sqrt_depth(c) > 1:
        raise SqrtdenestStopIteration
    ac = a + c
    if len(ac.args) >= len(expr.args):
        if count_ops(ac) >= count_ops(expr.base):
            raise SqrtdenestStopIteration
    d = sqrtdenest(sqrt(ac))
    if sqrt_depth(d) > 1:
        raise SqrtdenestStopIteration
    num, den = rad_rationalize(b, d)
    r = d/sqrt(2) + num/(den*sqrt(2))
    r = radsimp(r)
    return _mexpand(r)
Ejemplo n.º 5
0
def _sqrtdenest1(expr, denester=True):
    """Return denested expr after denesting with simpler methods or, that
    failing, using the denester."""

    from sympy.simplify.simplify import radsimp

    if not is_sqrt(expr):
        return expr

    a = expr.base
    if a.is_Atom:
        return expr
    val = _sqrt_match(a)
    if not val:
        return expr

    a, b, r = val
    # try a quick numeric denesting
    d2 = _mexpand(a**2 - b**2 * r)
    if d2.is_Rational:
        if d2.is_positive:
            z = _sqrt_numeric_denest(a, b, r, d2)
            if z is not None:
                return z
        else:
            # fourth root case
            # sqrtdenest(sqrt(3 + 2*sqrt(3))) =
            # sqrt(2)*3**(1/4)/2 + sqrt(2)*3**(3/4)/2
            dr2 = _mexpand(-d2 * r)
            dr = sqrt(dr2)
            if dr.is_Rational:
                z = _sqrt_numeric_denest(_mexpand(b * r), a, r, dr2)
                if z is not None:
                    return z / root(r, 4)

    else:
        z = _sqrt_symbolic_denest(a, b, r)
        if z is not None:
            return z

    if not denester or not is_algebraic(expr):
        return expr

    res = sqrt_biquadratic_denest(expr, a, b, r, d2)
    if res:
        return res

    # now call to the denester
    av0 = [a, b, r, d2]
    z = _denester([radsimp(expr**2)], av0, 0, sqrt_depth(expr))[0]
    if av0[1] is None:
        return expr
    if z is not None:
        if sqrt_depth(z) == sqrt_depth(
                expr) and count_ops(z) > count_ops(expr):
            return expr
        return z
    return expr
Ejemplo n.º 6
0
def _sqrtdenest1(expr, denester=True):
    """Return denested expr after denesting with simpler methods or, that
    failing, using the denester."""

    from sympy.simplify.simplify import radsimp

    if not is_sqrt(expr):
        return expr

    a = expr.base
    if a.is_Atom:
        return expr
    val = _sqrt_match(a)
    if not val:
        return expr

    a, b, r = val
    # try a quick numeric denesting
    d2 = _mexpand(a**2 - b**2*r)
    if d2.is_Rational:
        if d2.is_positive:
            z = _sqrt_numeric_denest(a, b, r, d2)
            if z is not None:
                return z
        else:
            # fourth root case
            # sqrtdenest(sqrt(3 + 2*sqrt(3))) =
            # sqrt(2)*3**(1/4)/2 + sqrt(2)*3**(3/4)/2
            dr2 = _mexpand(-d2*r)
            dr = sqrt(dr2)
            if dr.is_Rational:
                z = _sqrt_numeric_denest(_mexpand(b*r), a, r, dr2)
                if z is not None:
                    return z/root(r, 4)

    else:
        z = _sqrt_symbolic_denest(a, b, r)
        if z is not None:
            return z

    if not denester or not is_algebraic(expr):
        return expr

    res = sqrt_biquadratic_denest(expr, a, b, r, d2)
    if res:
        return res

    # now call to the denester
    av0 = [a, b, r, d2]
    z = _denester([radsimp(expr**2)], av0, 0, sqrt_depth(expr))[0]
    if av0[1] is None:
        return expr
    if z is not None:
        if sqrt_depth(z) == sqrt_depth(expr) and count_ops(z) > count_ops(expr):
            return expr
        return z
    return expr
Ejemplo n.º 7
0
def _sqrt_numeric_denest(a, b, r, d2):
    """Helper that denest expr = a + b*sqrt(r), with d2 = a**2 - b**2*r > 0
    or returns None if not denested.
    """
    from sympy.simplify.simplify import radsimp
    depthr = sqrt_depth(r)
    d = sqrt(d2)
    vad = a + d
    # sqrt_depth(res) <= sqrt_depth(vad) + 1
    # sqrt_depth(expr) = depthr + 2
    # there is denesting if sqrt_depth(vad)+1 < depthr + 2
    # if vad**2 is Number there is a fourth root
    if sqrt_depth(vad) < depthr + 1 or (vad**2).is_Rational:
        vad1 = radsimp(1/vad)
        return (sqrt(vad/2) + sign(b)*sqrt((b**2*r*vad1/2).expand())).expand()
Ejemplo n.º 8
0
def _sqrt_numeric_denest(a, b, r, d2):
    """Helper that denest expr = a + b*sqrt(r), with d2 = a**2 - b**2*r > 0
    or returns None if not denested.
    """
    from sympy.simplify.simplify import radsimp
    depthr = sqrt_depth(r)
    d = sqrt(d2)
    vad = a + d
    # sqrt_depth(res) <= sqrt_depth(vad) + 1
    # sqrt_depth(expr) = depthr + 2
    # there is denesting if sqrt_depth(vad)+1 < depthr + 2
    # if vad**2 is Number there is a fourth root
    if sqrt_depth(vad) < depthr + 1 or (vad**2).is_Rational:
        vad1 = radsimp(1/vad)
        return (sqrt(vad/2) + sign(b)*sqrt((b**2*r*vad1/2).expand())).expand()
Ejemplo n.º 9
0
def _sqrtdenest34(expr):
    """Helper that denests the square root of three or four surds.

    Examples
    ========
    >>> from sympy import sqrt
    >>> from sympy.simplify.sqrtdenest import _sqrtdenest34
    >>> _sqrtdenest34(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498))
    -sqrt(10) + sqrt(2) + 9 + 9*sqrt(5)
    >>> _sqrtdenest34(sqrt(12 + 2*sqrt(6) + 2*sqrt(14) + 2*sqrt(21)))
    sqrt(2) + sqrt(3) + sqrt(7)

    References
    ==========
    - D. J. Jeffrey and A. D. Rich, 'Symplifying Square Roots of Square Roots
      by Denesting'

    """
    from sympy.simplify.simplify import radsimp
    if not is_sqrt(expr):
        return expr
    a_plus_b = expr.base
    if not (a_plus_b.is_Add and len(a_plus_b.args) > 2):
        return expr
    if a_plus_b < 0:
        return sqrt(-1)*_sqrtdenest34(sqrt(-a_plus_b))
    args = a_plus_b.args
    a = Add._from_args(args[:2])
    b = Add._from_args(args[2:])
    if a < b: # we want a > b; since a + b > 0 then a**2 > b**2, too
        a, b = b, a
    c = _sqrtdenest1(sqrt(_mexpand(a**2 - b**2)))
    if sqrt_depth(c) > 1:
        return expr
    d = _sqrtdenest1(sqrt(a + c))
    if sqrt_depth(d) > 1:
        return expr
    return _mexpand(radsimp((d/sqrt(2) + b/(sqrt(2)*d))))
Ejemplo n.º 10
0
def sqrt_biquadratic_denest(expr, a, b, r, d2):
    """denest expr = sqrt(a + b*sqrt(r))
    where a, b, r are linear combinations of square roots of
    positive rationals on the rationals (SQRR) and r > 0, b != 0,
    d2 = a**2 - b**2*r > 0

    If it cannot denest it returns None.

    ALGORITHM
    Search for a solution A of type SQRR of the biquadratic equation
    4*A**4 - 4*a*A**2 + b**2*r = 0                               (1)
    sqd = sqrt(a**2 - b**2*r)
    Choosing the sqrt to be positive, the possible solutions are
    A = sqrt(a/2 +/- sqd/2)
    Since a, b, r are SQRR, then a**2 - b**2*r is a SQRR,
    so if sqd can be denested, it is done by
    _sqrtdenest_rec, and the result is a SQRR.
    Similarly for A.
    Examples of solutions (in both cases a and sqd are positive):

      Example of expr with solution sqrt(a/2 + sqd/2) but not
      solution sqrt(a/2 - sqd/2):
      expr = sqrt(-sqrt(15) - sqrt(2)*sqrt(-sqrt(5) + 5) - sqrt(3) + 8)
      a = -sqrt(15) - sqrt(3) + 8; sqd = -2*sqrt(5) - 2 + 4*sqrt(3)

      Example of expr with solution sqrt(a/2 - sqd/2) but not
      solution sqrt(a/2 + sqd/2):
      w = 2 + r2 + r3 + (1 + r3)*sqrt(2 + r2 + 5*r3)
      expr = sqrt((w**2).expand())
      a = 4*sqrt(6) + 8*sqrt(2) + 47 + 28*sqrt(3)
      sqd = 29 + 20*sqrt(3)

    Define B = b/2*A; eq.(1) implies a = A**2 + B**2*r; then
    expr**2 = a + b*sqrt(r) = (A + B*sqrt(r))**2

    Examples
    ========

    >>> from sympy import sqrt
    >>> from sympy.simplify.sqrtdenest import _sqrt_match, sqrt_biquadratic_denest
    >>> z = sqrt((2*sqrt(2) + 4)*sqrt(2 + sqrt(2)) + 5*sqrt(2) + 8)
    >>> a, b, r = _sqrt_match(z**2)
    >>> d2 = a**2 - b**2*r
    >>> sqrt_biquadratic_denest(z, a, b, r, d2)
    sqrt(2) + sqrt(sqrt(2) + 2) + 2
    """
    from sympy.simplify.simplify import radsimp, rad_rationalize
    if r <= 0 or d2 < 0 or not b or sqrt_depth(expr.base) < 2:
        return None
    for x in (a, b, r):
        for y in x.args:
            y2 = y**2
            if not y2.is_Integer or not y2.is_positive:
                return None
    sqd = _mexpand(sqrtdenest(sqrt(radsimp(d2))))
    if sqrt_depth(sqd) > 1:
        return None
    x1, x2 = [a/2 + sqd/2, a/2 - sqd/2]
    # look for a solution A with depth 1
    for x in (x1, x2):
        A = sqrtdenest(sqrt(x))
        if sqrt_depth(A) > 1:
            continue
        Bn, Bd = rad_rationalize(b, _mexpand(2*A))
        B = Bn/Bd
        z = A + B*sqrt(r)
        if z < 0:
            z = -z
        return _mexpand(z)
    return None
Ejemplo n.º 11
0
def _denester(nested, av0, h, max_depth_level):
    """Denests a list of expressions that contain nested square roots.

    Algorithm based on <http://www.almaden.ibm.com/cs/people/fagin/symb85.pdf>.

    It is assumed that all of the elements of 'nested' share the same
    bottom-level radicand. (This is stated in the paper, on page 177, in
    the paragraph immediately preceding the algorithm.)

    When evaluating all of the arguments in parallel, the bottom-level
    radicand only needs to be denested once. This means that calling
    _denester with x arguments results in a recursive invocation with x+1
    arguments; hence _denester has polynomial complexity.

    However, if the arguments were evaluated separately, each call would
    result in two recursive invocations, and the algorithm would have
    exponential complexity.

    This is discussed in the paper in the middle paragraph of page 179.
    """
    from sympy.simplify.simplify import radsimp
    if h > max_depth_level:
        return None, None
    if av0[1] is None:
        return None, None
    if (av0[0] is None and
            all(n.is_Number for n in nested)):  # no arguments are nested
        for f in _subsets(len(nested)):  # test subset 'f' of nested
            p = _mexpand(Mul(*[nested[i] for i in range(len(f)) if f[i]]))
            if f.count(1) > 1 and f[-1]:
                p = -p
            sqp = sqrt(p)
            if sqp.is_Rational:
                return sqp, f  # got a perfect square so return its square root.
        # Otherwise, return the radicand from the previous invocation.
        return sqrt(nested[-1]), [0]*len(nested)
    else:
        R = None
        if av0[0] is not None:
            values = [av0[:2]]
            R = av0[2]
            nested2 = [av0[3], R]
            av0[0] = None
        else:
            values = list(filter(None, [_sqrt_match(expr) for expr in nested]))
            for v in values:
                if v[2]:  # Since if b=0, r is not defined
                    if R is not None:
                        if R != v[2]:
                            av0[1] = None
                            return None, None
                    else:
                        R = v[2]
            if R is None:
                # return the radicand from the previous invocation
                return sqrt(nested[-1]), [0]*len(nested)
            nested2 = [_mexpand(v[0]**2) -
                       _mexpand(R*v[1]**2) for v in values] + [R]
        d, f = _denester(nested2, av0, h + 1, max_depth_level)
        #d = sqrtdenest(d)
        if not f:
            return None, None
        if not any(f[i] for i in range(len(nested))):
            v = values[-1]
            return sqrt(v[0] + _mexpand(v[1]*d)), f
        else:
            p = Mul(*[nested[i] for i in range(len(nested)) if f[i]])
            v = _sqrt_match(p)
            if 1 in f and f.index(1) < len(nested) - 1 and f[len(nested) - 1]:
                v[0] = -v[0]
                v[1] = -v[1]
            if not f[len(nested)]:  # Solution denests with square roots
                vad = _mexpand(v[0] + d)
                if vad <= 0:
                    # return the radicand from the previous invocation.
                    return sqrt(nested[-1]), [0]*len(nested)
                if not(sqrt_depth(vad) <= sqrt_depth(R) + 1 or
                       (vad**2).is_Number):
                    av0[1] = None
                    return None, None

                sqvad = _sqrtdenest1(sqrt(vad), denester=False)
                if not (sqrt_depth(sqvad) <= sqrt_depth(R) + 1):
                    av0[1] = None
                    return None, None
                sqvad1 = radsimp(1/sqvad)
                res = _mexpand(sqvad/sqrt(2) + (v[1]*sqrt(R)*sqvad1/sqrt(2)))
                return res, f

                      #          sign(v[1])*sqrt(_mexpand(v[1]**2*R*vad1/2))), f
            else:  # Solution requires a fourth root
                s2 = _mexpand(v[1]*R) + d
                if s2 <= 0:
                    return sqrt(nested[-1]), [0]*len(nested)
                FR, s = root(_mexpand(R), 4), sqrt(s2)
                return _mexpand(s/(sqrt(2)*FR) + v[0]*FR/(sqrt(2)*s)), f
Ejemplo n.º 12
0
def sqrt_biquadratic_denest(expr, a, b, r, d2):
    """denest expr = sqrt(a + b*sqrt(r))
    where a, b, r are linear combinations of square roots of
    positive rationals on the rationals (SQRR) and r > 0, b != 0,
    d2 = a**2 - b**2*r > 0

    If it cannot denest it returns None.

    ALGORITHM
    Search for a solution A of type SQRR of the biquadratic equation
    4*A**4 - 4*a*A**2 + b**2*r = 0                               (1)
    sqd = sqrt(a**2 - b**2*r)
    Choosing the sqrt to be positive, the possible solutions are
    A = sqrt(a/2 +/- sqd/2)
    Since a, b, r are SQRR, then a**2 - b**2*r is a SQRR,
    so if sqd can be denested, it is done by
    _sqrtdenest_rec, and the result is a SQRR.
    Similarly for A.
    Examples of solutions (in both cases a and sqd are positive):

      Example of expr with solution sqrt(a/2 + sqd/2) but not
      solution sqrt(a/2 - sqd/2):
      expr = sqrt(-sqrt(15) - sqrt(2)*sqrt(-sqrt(5) + 5) - sqrt(3) + 8)
      a = -sqrt(15) - sqrt(3) + 8; sqd = -2*sqrt(5) - 2 + 4*sqrt(3)

      Example of expr with solution sqrt(a/2 - sqd/2) but not
      solution sqrt(a/2 + sqd/2):
      w = 2 + r2 + r3 + (1 + r3)*sqrt(2 + r2 + 5*r3)
      expr = sqrt((w**2).expand())
      a = 4*sqrt(6) + 8*sqrt(2) + 47 + 28*sqrt(3)
      sqd = 29 + 20*sqrt(3)

    Define B = b/2*A; eq.(1) implies a = A**2 + B**2*r; then
    expr**2 = a + b*sqrt(r) = (A + B*sqrt(r))**2

    Examples
    ========

    >>> from sympy import sqrt
    >>> from sympy.simplify.sqrtdenest import _sqrt_match, sqrt_biquadratic_denest
    >>> z = sqrt((2*sqrt(2) + 4)*sqrt(2 + sqrt(2)) + 5*sqrt(2) + 8)
    >>> a, b, r = _sqrt_match(z**2)
    >>> d2 = a**2 - b**2*r
    >>> sqrt_biquadratic_denest(z, a, b, r, d2)
    sqrt(2) + sqrt(sqrt(2) + 2) + 2
    """
    from sympy.simplify.simplify import radsimp, rad_rationalize
    if r <= 0 or d2 < 0 or not b or sqrt_depth(expr.base) < 2:
        return None
    for x in (a, b, r):
        for y in x.args:
            y2 = y**2
            if not y2.is_Integer or not y2.is_positive:
                return None
    sqd = _mexpand(sqrtdenest(sqrt(radsimp(d2))))
    if sqrt_depth(sqd) > 1:
        return None
    x1, x2 = [a/2 + sqd/2, a/2 - sqd/2]
    # look for a solution A with depth 1
    for x in (x1, x2):
        A = sqrtdenest(sqrt(x))
        if sqrt_depth(A) > 1:
            continue
        Bn, Bd = rad_rationalize(b, _mexpand(2*A))
        B = Bn/Bd
        z = A + B*sqrt(r)
        if z < 0:
            z = -z
        return _mexpand(z)
    return None
Ejemplo n.º 13
0
def test_H():
    "Hazony problem 5.3.a"
    s, k = symbols('s k')
    w = symbols('w', real=True)

    pprint("test_H")
    Z = (s**3 + 4 * s**2 + 5 * s + 8) / (2 * s**3 + 2 * s**2 + 20 * s + 9)
    pprint(f"Z: {Z}")

    #plot_real_part( sympy.lambdify(s, Z, "numpy"))

    real_part = cancel(sympy.re(Z.subs({s: sympy.I * w})))
    print(f"real_part: {real_part}")

    roots = sympy.solveset(real_part, w)
    print(f"roots for w: {roots}")
    #plot( sympy.lambdify(w, real_part, "numpy"))

    w0 = sympy.sqrt(6)

    target0 = radsimp(Z.subs({s: sympy.I * w0}) / (sympy.I * w0))
    print(f"target: {target0}")

    target1 = radsimp(Z.subs({s: sympy.I * w0}) * (sympy.I * w0))
    print(f"target: {target1}")

    assert target0 > 0
    eq = sympy.Eq(Z.subs({s: k}) / k, target0)
    #eq = sympy.Eq( Z.subs({s:k})*k, target1)

    print(f"eq: {eq}")

    roots = sympy.solveset(eq, k)
    print(f"roots for k: {roots}")

    k0 = Rational(1, 4) + sympy.sqrt(33) / 4
    Z_k0 = Z.subs({s: k0})
    print(k0, Z_k0)
    print(k0.evalf(), Z_k0.evalf())

    return

    f = s**2 + 6

    den = cancel((k0 * Z_k0 - s * Z) / f)
    print(f"den factored: {sympy.factor(den)}")

    num = cancel((k0 * Z - s * Z_k0) / f)
    print(f"num factored: {sympy.factor(num).evalf()}")

    print(sympy.factor(cancel(den / num)))

    return

    eta = cancel(((k0 * Z - s * Z_k0) / (k0 * Z_k0 - s * Z)).evalf())
    print(k0, Z_k0, eta)

    print(k0, Z_k0, eta.evalf())

    print("normal")
    Z0 = eta * Z_k0
    print(f"Z0: {Z0}")

    Y1 = cancel(1 / Z0 - 4)
    print(f"Y1: {Y1}")
    C = Cascade.Shunt(4)

    Z2 = cancel(1 / Y1 - s / 6 - 1 / (3 * s))
    print(f"Z2: {Z2}")
    C = C.hit(Cascade.Series(s / 6))
    C = C.hit(Cascade.Series(1 / (3 * s)))

    eta_Z_k0 = cancel(C.terminate(0))
    print(f"eta_Z_k0: {eta_Z_k0}")
    assert sympy.Eq(cancel(eta_Z_k0 - Z0), 0)

    print("recip")
    Z0 = cancel(Z_k0 / eta)
    print(f"Z0: {Z0}")

    Z1 = cancel(Z0 - 1)
    print(f"Z1: {Z1}")
    C = Cascade.Series(1)

    Y2 = cancel(1 / Z1 - 2 * s / 3 - 4 / (3 * s))
    print(f"Y2: {Y2}")

    C = C.hit(Cascade.Shunt(2 * s / 3))
    C = C.hit(Cascade.Shunt(4 / (3 * s)))
    eta_over_Z_k0 = cancel(1 / C.terminate_with_admittance(0))
    print(f"eta_over_Z_k0: {eta_over_Z_k0}")
    assert sympy.Eq(cancel(eta_over_Z_k0 - Z0), 0)

    def p(a, b):
        return 1 / (1 / a + 1 / b)

    constructed_Z = cancel(
        p(eta_Z_k0, (k0 * Z_k0) / s) + p(eta_over_Z_k0, (Z_k0 * s) / k0))
    print(f"constructed_Z: {constructed_Z}")

    assert sympy.Eq(cancel(constructed_Z - Z), 0)
Ejemplo n.º 14
0
def test_J():
    "Second problem in Guillemin"
    s, k = symbols('s k')
    w = symbols('w', real=True)

    pprint("test_I")
    Z = (s**2 + s + 8) / (s**2 + 2 * s + 2)
    pprint(f"Z: {Z}")
    Y = 1 / Z

    #plot_real_part( sympy.lambdify(s, Y, "numpy"))

    real_part = cancel(sympy.re(Y.subs({s: sympy.I * w})))
    print(f"real_part: {real_part}")

    roots = sympy.solveset(real_part, w)
    print(f"roots for w: {roots}")
    #plot( sympy.lambdify(w, real_part, "numpy"))

    w0 = 2

    target0 = radsimp(Y.subs({s: sympy.I * w0}) / (sympy.I * w0))
    print(f"target: {target0.evalf()}")
    target0 = Rational(1, 2)

    target1 = radsimp(Y.subs({s: sympy.I * w0}) * (sympy.I * w0))
    print(f"target: {target1.evalf()}")
    target1 = Rational(2, 1)

    assert target0 > 0
    eq = sympy.Eq(Y.subs({s: k}) / k, target0)
    #assert target1 > 0
    #eq = sympy.Eq( Z.subs({s:k})*k, target1)

    roots = sympy.solveset(eq, k)
    print(f"roots for k: {roots}")

    k0 = Rational(1, 1)
    Y_k0 = Y.subs({s: k0})
    print(k0, Y_k0)
    print(k0.evalf(), Y_k0.evalf())

    den = cancel((k0 * Y_k0 - s * Y))
    print(f"den factored: {sympy.factor(den)}")

    num = cancel((k0 * Y - s * Y_k0))
    print(f"num factored: {sympy.factor(num)}")

    eta = cancel(num / den)
    print(k0, Y_k0, eta)

    print("normal")
    Y0 = eta * Y_k0
    print(f"Y0: {Y0}")

    Z1 = ratsimp(1 / Y0 - 4)
    print(f"Z1: {Z1}")
    C = Cascade.Series(4)

    Y2 = ratsimp(1 / Z1)
    print(f"Y2: {Y2}")

    C = C.hit(Cascade.Shunt(s / 10))
    C = C.hit(Cascade.Shunt(2 / (5 * s)))

    eta_Y_k0 = cancel(C.terminate_with_admittance(0))
    print(f"eta_Y_k0: {eta_Y_k0}")
    assert sympy.Eq(cancel(eta_Y_k0 - Y0), 0)

    print("recip")
    Y0 = ratsimp(Y_k0 / eta)
    print(f"Y0: {Y0}")

    Y1 = ratsimp(Y0 - 1)
    print(f"Y1: {Y1}")
    C = Cascade.Shunt(1)

    Z2 = ratsimp(1 / Y1 - 2 * s / 5 - 8 / (5 * s))
    print(f"Z2: {Z2}")

    C = C.hit(Cascade.Series(2 * s / 5))
    C = C.hit(Cascade.Series(8 / (5 * s)))
    eta_over_Y_k0 = cancel(1 / C.terminate(0))

    print(f"eta_over_Y_k0: {eta_over_Y_k0}")
    assert sympy.Eq(cancel(eta_over_Y_k0 - Y0), 0)

    def p(a, b):
        return a * b / (a + b)

    constructed_Y = cancel(
        p(eta_Y_k0, (k0 * Y_k0) / s) + p(eta_over_Y_k0, (Y_k0 * s) / k0))
    print(f"constructed_Y: {constructed_Y}")

    assert sympy.Eq(cancel(constructed_Y - Y), 0)
Ejemplo n.º 15
0
def test_I():
    "Hazony problem 5.3.a"
    s, k = symbols('s k')
    w = symbols('w', real=True)

    pprint("test_I")
    Z = (s**3 + 3 * s**2 + s + 1) / (s**3 + s**2 + 3 * s + 1)
    pprint(f"Z: {Z}")

    #plot_real_part( sympy.lambdify(s, Z, "numpy"))

    real_part = cancel(sympy.re(Z.subs({s: sympy.I * w})))
    print(f"real_part: {real_part}")

    roots = sympy.solveset(real_part, w)
    print(f"roots for w: {roots}")
    #plot( sympy.lambdify(w, real_part, "numpy"))

    w0 = 1

    target0 = radsimp(Z.subs({s: sympy.I * w0}) / (sympy.I * w0))
    print(f"target: {target0}")

    target1 = radsimp(Z.subs({s: sympy.I * w0}) * (sympy.I * w0))
    print(f"target: {target1}")

    assert target0 > 0
    eq = sympy.Eq(Z.subs({s: k}) / k, target0)
    #assert target1 > 0
    #eq = sympy.Eq( Z.subs({s:k})*k, target1)

    roots = sympy.solveset(eq, k)
    print(f"roots for k: {roots}")

    k0 = Rational(1, 1)
    Z_k0 = Z.subs({s: k0})
    print(k0, Z_k0)
    print(k0.evalf(), Z_k0.evalf())

    den = cancel((k0 * Z_k0 - s * Z))
    print(f"den factored: {sympy.factor(den)}")

    num = cancel((k0 * Z - s * Z_k0))
    print(f"num factored: {sympy.factor(num)}")

    eta = cancel(num / den)
    print(k0, Z_k0, eta)

    print("normal")
    Z0 = eta * Z_k0
    print(f"Z0: {Z0}")

    Y1 = ratsimp(1 / Z0 - 1)
    print(f"Y1: {Y1}")
    C = Cascade.Shunt(1)

    Z2 = ratsimp(1 / Y1 - s / 2 - 1 / (2 * s))
    print(f"Z2: {Z2}")

    C = C.hit(Cascade.Series(s / 2))
    C = C.hit(Cascade.Series(1 / (2 * s)))

    eta_Z_k0 = cancel(C.terminate(0))
    print(f"eta_Z_k0: {eta_Z_k0}")
    assert sympy.Eq(cancel(eta_Z_k0 - Z0), 0)

    print("recip")
    Z0 = cancel(Z_k0 / eta)
    print(f"Z0: {Z0}")

    Z1 = ratsimp(Z0 - 1)
    print(f"Z1: {Z1}")
    C = Cascade.Series(1)

    Y2 = ratsimp(1 / Z1 - s / 2 - 1 / (2 * s))
    print(f"Y2: {Y2}")

    C = C.hit(Cascade.Shunt(s / 2))
    C = C.hit(Cascade.Shunt(1 / (2 * s)))
    eta_over_Z_k0 = cancel(1 / C.terminate_with_admittance(0))
    print(f"eta_over_Z_k0: {eta_over_Z_k0}")
    assert sympy.Eq(cancel(eta_over_Z_k0 - Z0), 0)

    def p(a, b):
        return a * b / (a + b)

    constructed_Z = cancel(
        p(eta_Z_k0, (k0 * Z_k0) / s) + p(eta_over_Z_k0, (Z_k0 * s) / k0))
    print(f"constructed_Z: {constructed_Z}")

    assert sympy.Eq(cancel(constructed_Z - Z), 0)
Ejemplo n.º 16
0
def _denester(nested, av0, h, max_depth_level):
    """Denests a list of expressions that contain nested square roots.

    Algorithm based on <http://www.almaden.ibm.com/cs/people/fagin/symb85.pdf>.

    It is assumed that all of the elements of 'nested' share the same
    bottom-level radicand. (This is stated in the paper, on page 177, in
    the paragraph immediately preceding the algorithm.)

    When evaluating all of the arguments in parallel, the bottom-level
    radicand only needs to be denested once. This means that calling
    _denester with x arguments results in a recursive invocation with x+1
    arguments; hence _denester has polynomial complexity.

    However, if the arguments were evaluated separately, each call would
    result in two recursive invocations, and the algorithm would have
    exponential complexity.

    This is discussed in the paper in the middle paragraph of page 179.
    """
    from sympy.simplify.simplify import radsimp
    if h > max_depth_level:
        return None, None
    if av0[1] is None:
        return None, None
    if (av0[0] is None and
        all(n.is_Number for n in nested)): # no arguments are nested
        for f in subsets(len(nested)): # test subset 'f' of nested
            p = _mexpand(Mul(*[nested[i] for i in range(len(f)) if f[i]]))
            if f.count(1) > 1 and f[-1]:
                p = -p
            sqp = sqrt(p)
            if sqp.is_Rational:
                return sqp, f # got a perfect square so return its square root.
        # Otherwise, return the radicand from the previous invocation.
        return sqrt(nested[-1]), [0]*len(nested)
    else:
        R = None
        if av0[0] is not None:
            values = [av0[:2]]
            R = av0[2]
            nested2 = [av0[3], R]
            av0[0] = None
        else:
            values = filter(None, [_sqrt_match(expr) for expr in nested])
            for v in values:
                if v[2]: #Since if b=0, r is not defined
                    if R is not None:
                        if R != v[2]:
                            av0[1] = None
                            return None, None
                    else:
                        R = v[2]
            if R is None:
                # return the radicand from the previous invocation
                return sqrt(nested[-1]), [0]*len(nested)
            nested2 = [_mexpand(v[0]**2) -
                       _mexpand(R*v[1]**2) for v in values] + [R]
        d, f = _denester(nested2, av0, h + 1, max_depth_level)
        if not f:
            return None, None
        if not any(f[i] for i in range(len(nested))):
            v = values[-1]
            return sqrt(v[0] + v[1]*d), f
        else:
            p = Mul(*[nested[i] for i in range(len(nested)) if f[i]])
            v = _sqrt_match(p)
            if 1 in f and f.index(1) < len(nested) - 1 and f[len(nested) - 1]:
                v[0] = -v[0]
                v[1] = -v[1]
            if not f[len(nested)]: #Solution denests with square roots
                vad = _mexpand(v[0] + d)
                if vad <= 0:
                    # return the radicand from the previous invocation.
                    return sqrt(nested[-1]), [0]*len(nested)
                if not(sqrt_depth(vad) < sqrt_depth(R) + 1 or
                       (vad**2).is_Number):
                    av0[1] = None
                    return None, None

                vad1 = radsimp(1/vad)
                return _mexpand(sqrt(vad/2) +
                                sign(v[1])*sqrt(_mexpand(v[1]**2*R*vad1/2))), f
            else: #Solution requires a fourth root
                s2 = _mexpand(v[1]*R) + d
                if s2 <= 0:
                    return sqrt(nested[-1]), [0]*len(nested)
                FR, s = root(_mexpand(R), 4), sqrt(s2)
                return _mexpand(s/(sqrt(2)*FR) + v[0]*FR/(sqrt(2)*s)), f
Ejemplo n.º 17
0
def test_G():
    "Hazony example 5.2.2"
    s, k = symbols('s k')

    pprint("test_G")
    Z = (s**2 + s + 1) / (s**2 + s + 4)
    pprint(f"Z: {Z}")

    #plot_real_part( sympy.lambdify(s, Z, "numpy"))

    w0 = sympy.sqrt(2)

    target = radsimp(Z.subs({s: sympy.I * w0}) / (sympy.I * w0))
    print(f"target: {target}")

    eq = sympy.Eq(Z.subs({s: k}) / k, target)

    roots = sympy.solveset(eq, k)
    if True:
        for k0 in roots:
            Z_k0 = Z.subs({s: k0})
            eta = cancel((k0 * Z - s * Z_k0) / (k0 * Z_k0 - s * Z))
            print(k0, Z_k0, eta)
            #plot_real_part( sympy.lambdify(s, eta, "numpy"))

    k0 = 1
    Z_k0 = Z.subs({s: k0})
    eta = cancel((k0 * Z - s * Z_k0) / (k0 * Z_k0 - s * Z))
    print(k0, Z_k0, eta)

    print("normal")
    Z0 = eta * Z_k0
    print(f"Z0: {Z0}")

    Y1 = cancel(1 / Z0 - 4)
    print(f"Y1: {Y1}")
    C = Cascade.Shunt(4)

    Z2 = cancel(1 / Y1 - s / 6 - 1 / (3 * s))
    print(f"Z2: {Z2}")
    C = C.hit(Cascade.Series(s / 6))
    C = C.hit(Cascade.Series(1 / (3 * s)))

    eta_Z_k0 = cancel(C.terminate(0))
    print(f"eta_Z_k0: {eta_Z_k0}")
    assert sympy.Eq(cancel(eta_Z_k0 - Z0), 0)

    print("recip")
    Z0 = cancel(Z_k0 / eta)
    print(f"Z0: {Z0}")

    Z1 = cancel(Z0 - 1)
    print(f"Z1: {Z1}")
    C = Cascade.Series(1)

    Y2 = cancel(1 / Z1 - 2 * s / 3 - 4 / (3 * s))
    print(f"Y2: {Y2}")

    C = C.hit(Cascade.Shunt(2 * s / 3))
    C = C.hit(Cascade.Shunt(4 / (3 * s)))
    eta_over_Z_k0 = cancel(1 / C.terminate_with_admittance(0))
    print(f"eta_over_Z_k0: {eta_over_Z_k0}")
    assert sympy.Eq(cancel(eta_over_Z_k0 - Z0), 0)

    def p(a, b):
        return 1 / (1 / a + 1 / b)

    constructed_Z = cancel(
        p(eta_Z_k0, (k0 * Z_k0) / s) + p(eta_over_Z_k0, (Z_k0 * s) / k0))
    print(f"constructed_Z: {constructed_Z}")

    assert sympy.Eq(cancel(constructed_Z - Z), 0)