Esempio n. 1
0
 def linear_arg(arg):
     """ Test if arg is of form a*s+b, raise exception if not. """
     if not arg.is_polynomial(s):
         raise exception(fact)
     p = Poly(arg, s)
     if p.degree() != 1:
         raise exception(fact)
     return p.all_coeffs()
Esempio n. 2
0
 def linear_arg(arg):
     """ Test if arg is of form a*s+b, raise exception if not. """
     if not arg.is_polynomial(s):
         raise exception(fact)
     p = Poly(arg, s)
     if p.degree() != 1:
         raise exception(fact)
     return p.all_coeffs()
Esempio n. 3
0
def lower_degree_to(polynomial: Poly,
                    max_polynomial_degree: int) -> Poly:
    """
    Lowers the degree of the polynomial by using Chebyshev polynomials.

    :param polynomial: polynomial to lower the degree of
    :param max_polynomial_degree: maximum polynomial degree to lower to
    :return: polynomial with the degree less than or equal to `max_polynomial_degree`
    :rtype: Poly
    """

    while polynomial.degree() > max_polynomial_degree:
        normalised_chebyshev_polynomial = get_normalised_nth_chebyshev_polynomial(polynomial.degree())

        polynomial -= normalised_chebyshev_polynomial * polynomial.LC()

    return polynomial
Esempio n. 4
0
def fn(theta, phi, pa, tau):
    x = Symbol('x')
    pa = Symbol('pa')
    phi = Symbol('phi')
    theta = Symbol('theta')
    tau = Symbol('tau')
    f = (2 * pa * phi**2) / tau**5 + x**5 + (
        2 * pa * phi**2 * cos(theta)
    ) / tau**5 - (2 * pa**2 * phi**2 * cos(theta)) / tau**5 - (
        2 * pa * phi**2 * cos(theta)**2
    ) / tau**5 - (2 * pa * phi**2 * cos(theta)**3) / tau**5 + (
        2 * pa**2 * phi**2 * cos(theta)**3) / tau**5 + x**4 * (
            4 / tau + cos(theta) / tau -
            (2 * pa * cos(theta)) / tau - cos(theta)**2 / tau) + x * (
                tau**(-4) +
                (4 * phi**2) / tau**4 +
                (4 * pa * phi**2) / tau**4 + cos(theta) / tau**4 -
                (2 * pa * cos(theta)) / tau**4 +
                (4 * phi**2 * cos(theta)) / tau**4 -
                (2 * pa * phi**2 * cos(theta)) / tau**4 -
                (2 * pa**2 * phi**2 * cos(theta)) / tau**4 -
                cos(theta)**2 / tau**4 -
                (4 * phi**2 * cos(theta)**2) / tau**4 -
                cos(theta)**3 / tau**4 + (2 * pa * cos(theta)**3) / tau**4 -
                (4 * phi**2 * cos(theta)**3) / tau**4 +
                (6 * pa * phi**2 * cos(theta)**3) / tau**4 -
                (2 * pa**2 * phi**2 * cos(theta)**3) / tau**4) + x**2 * (
                    4 / tau**3 +
                    (8 * phi**2) / tau**3 + (2 * pa * phi**2) / tau**3 +
                    (3 * cos(theta)) / tau**3 -
                    (6 * pa * cos(theta)) / tau**3 +
                    (4 * phi**2 * cos(theta)) / tau**3 -
                    (4 * pa * phi**2 * cos(theta)) / tau**3 -
                    (3 * cos(theta)**2) / tau**3 -
                    (4 * phi**2 * cos(theta)**2) / tau**3 +
                    (2 * pa * phi**2 * cos(theta)**2) / tau**3 -
                    (2 * cos(theta)**3) / tau**3 +
                    (4 * pa * cos(theta)**3) / tau**3) + x**3 * (
                        6 / tau**2 +
                        (4 * phi**2) / tau**2 + (3 * cos(theta)) / tau**2 -
                        (6 * pa * cos(theta)) / tau**2 -
                        (3 * cos(theta)**2) / tau**2 - cos(theta)**3 / tau**2 +
                        (2 * pa * cos(theta)**3) / tau**2)

    p = Poly(f, x)
    ans = [p.root(k).evalf() for k in range(p.degree())]
    for i, a in enumerate(ans):
        print(i, a)
    return ans
Esempio n. 5
0
def check_convergence(numer, denom, n):
    """
    Returns (h, g, p) where
    -- h is:
        > 0 for convergence of rate 1/factorial(n)**h
        < 0 for divergence of rate factorial(n)**(-h)
        = 0 for geometric or polynomial convergence or divergence

    -- abs(g) is:
        > 1 for geometric convergence of rate 1/h**n
        < 1 for geometric divergence of rate h**n
        = 1 for polynomial convergence or divergence

        (g < 0 indicates an alternating series)

    -- p is:
        > 1 for polynomial convergence of rate 1/n**h
        <= 1 for polynomial divergence of rate n**(-h)

    """
    from sympy import Poly
    npol = Poly(numer, n)
    dpol = Poly(denom, n)
    p = npol.degree()
    q = dpol.degree()
    rate = q - p
    if rate:
        return rate, None, None
    constant = dpol.LC() / npol.LC()
    if abs(constant) != 1:
        return rate, constant, None
    if npol.degree() == dpol.degree() == 0:
        return rate, constant, 0
    pc = npol.all_coeffs()[1]
    qc = dpol.all_coeffs()[1]
    return rate, constant, (qc - pc) / dpol.LC()
Esempio n. 6
0
def check_convergence(numer, denom, n):
    """
    Returns (h, g, p) where
    -- h is:
        > 0 for convergence of rate 1/factorial(n)**h
        < 0 for divergence of rate factorial(n)**(-h)
        = 0 for geometric or polynomial convergence or divergence

    -- abs(g) is:
        > 1 for geometric convergence of rate 1/h**n
        < 1 for geometric divergence of rate h**n
        = 1 for polynomial convergence or divergence

        (g < 0 indicates an alternating series)

    -- p is:
        > 1 for polynomial convergence of rate 1/n**h
        <= 1 for polynomial divergence of rate n**(-h)

    """
    from sympy import Poly
    npol = Poly(numer, n)
    dpol = Poly(denom, n)
    p = npol.degree()
    q = dpol.degree()
    rate = q - p
    if rate:
        return rate, None, None
    constant = dpol.LC() / npol.LC()
    if abs(constant) != 1:
        return rate, constant, None
    if npol.degree() == dpol.degree() == 0:
        return rate, constant, 0
    pc = npol.all_coeffs()[1]
    qc = dpol.all_coeffs()[1]
    return rate, constant, (qc - pc)/dpol.LC()
Esempio n. 7
0
def simplify(polynom):
    """Simplifies a function with binary variables
    """
    polynom = Poly(polynom)
    new_polynom = 0
    variables = list(polynom.free_symbols)

    for var_i in variables:
        coefficient_i = polynom.as_expr().coeff(var_i)/2
        for degree in range(polynom.degree()-1):
            coefficient_i += polynom.as_expr().coeff(var_i ** (degree+2))
        if coefficient_i.is_Float:
            new_polynom += float(coefficient_i) * var_i
        else:
            new_polynom += float(coefficient_i.as_coefficients_dict()[1]) * var_i
        for var_j in variables:
            if var_j != var_i:
                coefficient_j = coefficient_i.coeff(var_j)
                if coefficient_j.is_Float:
                    new_polynom += float(coefficient_j) * var_i * var_j
                else:
                    new_polynom += float(coefficient_j.as_coefficients_dict()[1]) * var_i * var_j
    return new_polynom + polynom.as_expr().as_coefficients_dict()[1]
Esempio n. 8
0
def _rewrite_gamma(f, s, a, b):
    """
    Try to rewrite the product f(s) as a product of gamma functions,
    so that the inverse mellin transform of f can be expressed as a meijer
    G function.

    Return (an, ap), (bm, bq), arg, exp, fac such that
    G((an, ap), (bm, bq), arg/z**exp)*fac is the inverse mellin transform of f(s).

    Raises IntegralTransformError or MellinTransformStripError on failure.

    It is asserted that f has no poles in the fundamental strip designated by
    (a, b). One of a and b is allowed to be None. The fundamental strip is
    important, because it determines the inversion contour.

    This function can handle exponentials, linear factors, trigonometric
    functions.

    This is a helper function for inverse_mellin_transform that will not
    attempt any transformations on f.

    >>> from sympy.integrals.transforms import _rewrite_gamma
    >>> from sympy.abc import s
    >>> from sympy import oo
    >>> _rewrite_gamma(s*(s+3)*(s-1), s, -oo, oo)
    (([], [-3, 0, 1]), ([-2, 1, 2], []), 1, 1, -1)
    >>> _rewrite_gamma((s-1)**2, s, -oo, oo)
    (([], [1, 1]), ([2, 2], []), 1, 1, 1)

    Importance of the fundamental strip:

    >>> _rewrite_gamma(1/s, s, 0, oo)
    (([1], []), ([], [0]), 1, 1, 1)
    >>> _rewrite_gamma(1/s, s, None, oo)
    (([1], []), ([], [0]), 1, 1, 1)
    >>> _rewrite_gamma(1/s, s, 0, None)
    (([1], []), ([], [0]), 1, 1, 1)
    >>> _rewrite_gamma(1/s, s, -oo, 0)
    (([], [1]), ([0], []), 1, 1, -1)
    >>> _rewrite_gamma(1/s, s, None, 0)
    (([], [1]), ([0], []), 1, 1, -1)
    >>> _rewrite_gamma(1/s, s, -oo, None)
    (([], [1]), ([0], []), 1, 1, -1)

    >>> _rewrite_gamma(2**(-s+3), s, -oo, oo)
    (([], []), ([], []), 1/2, 1, 8)
    """
    from itertools import repeat
    from sympy import (Poly, gamma, Mul, re, RootOf, exp as exp_, E, expand,
                       roots, ilcm, pi, sin, cos, tan, cot, igcd, exp_polar)
    # Our strategy will be as follows:
    # 1) Guess a constant c such that the inversion integral should be
    #    performed wrt s'=c*s (instead of plain s). Write s for s'.
    # 2) Process all factors, rewrite them independently as gamma functions in
    #    argument s, or exponentials of s.
    # 3) Try to transform all gamma functions s.t. they have argument
    #    a+s or a-s.
    # 4) Check that the resulting G function parameters are valid.
    # 5) Combine all the exponentials.

    a_, b_ = S([a, b])
    def left(c, is_numer):
        """
        Decide whether pole at c lies to the left of the fundamental strip.
        """
        # heuristically, this is the best chance for us to solve the inequalities
        c = expand(re(c))
        if a_ is None:
            return c < b_
        if b_ is None:
            return c <= a_
        if (c >= b_) is True:
            return False
        if (c <= a_) is True:
            return True
        if is_numer:
            return None
        if a_.free_symbols or b_.free_symbols or c.free_symbols:
            return None # XXX
            #raise IntegralTransformError('Inverse Mellin', f,
            #                     'Could not determine position of singularity %s'
            #                     ' relative to fundamental strip' % c)
        raise MellinTransformStripError('Pole inside critical strip?')

    # 1)
    s_multipliers = []
    for g in f.atoms(gamma):
        if not g.has(s):
            continue
        arg = g.args[0]
        if arg.is_Add:
            arg = arg.as_independent(s)[1]
        coeff, _ = arg.as_coeff_mul(s)
        s_multipliers += [coeff]
    for g in f.atoms(sin, cos, tan, cot):
        if not g.has(s):
            continue
        arg = g.args[0]
        if arg.is_Add:
            arg = arg.as_independent(s)[1]
        coeff, _ = arg.as_coeff_mul(s)
        s_multipliers += [coeff/pi]
    s_multipliers = [abs(x) for x in s_multipliers if x.is_real]
    common_coefficient = S(1)
    for x in s_multipliers:
        if not x.is_Rational:
            common_coefficient = x
            break
    s_multipliers = [x/common_coefficient for x in s_multipliers]
    if any(not x.is_Rational for x in s_multipliers):
        raise NotImplementedError
    s_multiplier = common_coefficient/reduce(ilcm, [S(x.q) for x in s_multipliers], S(1))
    if s_multiplier == common_coefficient:
        if len(s_multipliers) == 0:
            s_multiplier = common_coefficient
        else:
            s_multiplier = common_coefficient \
                           *reduce(igcd, [S(x.p) for x in s_multipliers])

    exponent = S(1)
    fac = S(1)
    f = f.subs(s, s/s_multiplier)
    fac /= s_multiplier
    exponent = 1/s_multiplier
    if a_ is not None:
        a_ *= s_multiplier
    if b_ is not None:
        b_ *= s_multiplier

    # 2)
    numer, denom = f.as_numer_denom()
    numer = Mul.make_args(numer)
    denom = Mul.make_args(denom)
    args = zip(numer, repeat(True)) + zip(denom, repeat(False))

    facs = []
    dfacs = []
    # *_gammas will contain pairs (a, c) representing Gamma(a*s + c)
    numer_gammas = []
    denom_gammas = []
    # exponentials will contain bases for exponentials of s
    exponentials = []
    def exception(fact):
        return IntegralTransformError("Inverse Mellin", f, "Unrecognised form '%s'." % fact)
    while args:
        fact, is_numer = args.pop()
        if is_numer:
            ugammas, lgammas = numer_gammas, denom_gammas
            ufacs, lfacs = facs, dfacs
        else:
            ugammas, lgammas = denom_gammas, numer_gammas
            ufacs, lfacs = dfacs, facs

        def linear_arg(arg):
            """ Test if arg is of form a*s+b, raise exception if not. """
            if not arg.is_polynomial(s):
                raise exception(fact)
            p = Poly(arg, s)
            if p.degree() != 1:
                raise exception(fact)
            return p.all_coeffs()

        # constants
        if not fact.has(s):
            ufacs += [fact]
        # exponentials
        elif fact.is_Pow or isinstance(fact, exp_):
            if fact.is_Pow:
                base = fact.base
                exp  = fact.exp
            else:
                base = exp_polar(1)
                exp  = fact.args[0]
            if exp.is_Integer:
                cond = is_numer
                if exp < 0:
                    cond = not cond
                args += [(base, cond)]*abs(exp)
                continue
            elif not base.has(s):
                a, b = linear_arg(exp)
                if not is_numer:
                    base = 1/base
                exponentials += [base**a]
                facs += [base**b]
            else:
                raise exception(fact)
        # linear factors
        elif fact.is_polynomial(s):
            p = Poly(fact, s)
            if p.degree() != 1:
                # We completely factor the poly. For this we need the roots.
                # Now roots() only works in some cases (low degree), and RootOf
                # only works without parameters. So try both...
                coeff = p.LT()[1]
                rs = roots(p, s)
                if len(rs) != p.degree():
                    rs = RootOf.all_roots(p)
                ufacs += [coeff]
                args += [(s - c, is_numer) for c in rs]
                continue
            a, c = p.all_coeffs()
            ufacs += [a]
            c /= -a
            # Now need to convert s - c
            if left(c, is_numer):
                ugammas += [(S(1), -c + 1)]
                lgammas += [(S(1), -c)]
            else:
                ufacs += [-1]
                ugammas += [(S(-1), c + 1)]
                lgammas += [(S(-1), c)]
        elif isinstance(fact, gamma):
            a, b = linear_arg(fact.args[0])
            if is_numer:
                if (a > 0 and (left(-b/a, is_numer) is False)) or \
                   (a < 0 and (left(-b/a, is_numer) is True)):
                    raise NotImplementedError('Gammas partially over the strip.')
            ugammas += [(a, b)]
        elif isinstance(fact, sin):
            # We try to re-write all trigs as gammas. This is not in
            # general the best strategy, since sometimes this is impossible,
            # but rewriting as exponentials would work. However trig functions
            # in inverse mellin transforms usually all come from simplifying
            # gamma terms, so this should work.
            a = fact.args[0]
            if is_numer:
                # No problem with the poles.
                gamma1, gamma2, fac_ = gamma(a/pi), gamma(1 - a/pi), pi
            else:
                gamma1, gamma2, fac_ = _rewrite_sin(linear_arg(a), s, a_, b_)
            args += [(gamma1, not is_numer), (gamma2, not is_numer)]
            ufacs += [fac_]
        elif isinstance(fact, tan):
            a = fact.args[0]
            args += [(sin(a, evaluate=False), is_numer),
                     (sin(pi/2 - a, evaluate=False), not is_numer)]
        elif isinstance(fact, cos):
            a = fact.args[0]
            args += [(sin(pi/2 - a, evaluate=False), is_numer)]
        elif isinstance(fact, cot):
            a = fact.args[0]
            args += [(sin(pi/2 - a, evaluate=False), is_numer),
                     (sin(a, evaluate=False), not is_numer)]
        else:
            raise exception(fact)

    fac *= Mul(*facs)/Mul(*dfacs)

    # 3)
    an, ap, bm, bq = [], [], [], []
    for gammas, plus, minus, is_numer in [(numer_gammas, an, bm, True),
                                          (denom_gammas, bq, ap, False)]:
        while gammas:
            a, c = gammas.pop()
            if a != -1 and a != +1:
                # We use the gamma function multiplication theorem.
                p = abs(S(a))
                newa = a/p
                newc = c/p
                assert a.is_Integer
                for k in range(p):
                    gammas += [(newa, newc + k/p)]
                if is_numer:
                    fac *= (2*pi)**((1 - p)/2) * p**(c - S(1)/2)
                    exponentials += [p**a]
                else:
                    fac /= (2*pi)**((1 - p)/2) * p**(c - S(1)/2)
                    exponentials += [p**(-a)]
                continue
            if a == +1:
                plus.append(1 - c)
            else:
                minus.append(c)

    # 4)
    # TODO

    # 5)
    arg = Mul(*exponentials)

    # for testability, sort the arguments
    an.sort()
    ap.sort()
    bm.sort()
    bq.sort()

    return (an, ap), (bm, bq), arg, exponent, fac
Esempio n. 9
0
def _rewrite_gamma(f, s, a, b):
    """
    Try to rewrite the product f(s) as a product of gamma functions,
    so that the inverse mellin transform of f can be expressed as a meijer
    G function.

    Return (an, ap), (bm, bq), arg, exp, fac such that
    G((an, ap), (bm, bq), arg/z**exp)*fac is the inverse mellin transform of f(s).

    Raises IntegralTransformError or ValueError on failure.

    It is asserted that f has no poles in the fundamental strip designated by
    (a, b). One of a and b is allowed to be None. The fundamental strip is
    important, because it determines the inversion contour.

    This function can handle exponentials, linear factors, trigonometric
    functions.

    This is a helper function for inverse_mellin_transform that will not
    attempt any transformations on f.

    >>> from sympy.integrals.transforms import _rewrite_gamma
    >>> from sympy.abc import s
    >>> from sympy import oo
    >>> _rewrite_gamma(s*(s+3)*(s-1), s, -oo, oo)
    (([], [-3, 0, 1]), ([-2, 1, 2], []), 1, 1, -1)
    >>> _rewrite_gamma((s-1)**2, s, -oo, oo)
    (([], [1, 1]), ([2, 2], []), 1, 1, 1)

    Importance of the fundamental strip:

    >>> _rewrite_gamma(1/s, s, 0, oo)
    (([1], []), ([], [0]), 1, 1, 1)
    >>> _rewrite_gamma(1/s, s, None, oo)
    (([1], []), ([], [0]), 1, 1, 1)
    >>> _rewrite_gamma(1/s, s, 0, None)
    (([1], []), ([], [0]), 1, 1, 1)
    >>> _rewrite_gamma(1/s, s, -oo, 0)
    (([], [1]), ([0], []), 1, 1, -1)
    >>> _rewrite_gamma(1/s, s, None, 0)
    (([], [1]), ([0], []), 1, 1, -1)
    >>> _rewrite_gamma(1/s, s, -oo, None)
    (([], [1]), ([0], []), 1, 1, -1)

    >>> _rewrite_gamma(2**(-s+3), s, -oo, oo)
    (([], []), ([], []), 1/2, 1, 8)
    """
    from itertools import repeat
    from sympy import (Poly, gamma, Mul, re, RootOf, exp as exp_, E, expand,
                       roots, ilcm, pi, sin, cos, tan, cot, igcd)
    # Our strategy will be as follows:
    # 1) Guess a constant c such that the inversion integral should be
    #    performed wrt s'=c*s (instead of plain s). Write s for s'.
    # 2) Process all factors, rewrite them independently as gamma functions in
    #    argument s, or exponentials of s.
    # 3) Try to transform all gamma functions s.t. they have argument
    #    a+s or a-s.
    # 4) Check that the resulting G function parameters are valid.
    # 5) Combine all the exponentials.

    a_, b_ = S([a, b])

    def left(c, is_numer):
        """
        Decide whether pole at c lies to the left of the fundamental strip.
        """
        # heuristically, this is the best chance for us to solve the inequalities
        c = expand(re(c))
        if a_ is None:
            return c < b_
        if b_ is None:
            return c <= a_
        if (c >= b_) is True:
            return False
        if (c <= a_) is True:
            return True
        if is_numer:
            return None
        if a_.free_symbols or b_.free_symbols or c.free_symbols:
            return None  # XXX
            #raise IntegralTransformError('Inverse Mellin', f,
            #                     'Could not determine position of singularity %s'
            #                     ' relative to fundamental strip' % c)
        raise ValueError('Pole inside critical strip?')

    # 1)
    s_multipliers = []
    for g in f.atoms(gamma):
        if not g.has(s):
            continue
        arg = g.args[0]
        if arg.is_Add:
            arg = arg.as_independent(s)[1]
        coeff, _ = arg.as_coeff_mul(s)
        s_multipliers += [coeff]
    for g in f.atoms(sin, cos, tan, cot):
        if not g.has(s):
            continue
        arg = g.args[0]
        if arg.is_Add:
            arg = arg.as_independent(s)[1]
        coeff, _ = arg.as_coeff_mul(s)
        s_multipliers += [coeff / pi]
    s_multipliers = [abs(x) for x in s_multipliers if x.is_real]
    common_coefficient = S(1)
    for x in s_multipliers:
        if not x.is_Rational:
            common_coefficient = x
            break
    s_multipliers = [x / common_coefficient for x in s_multipliers]
    if any(not x.is_Rational for x in s_multipliers):
        raise NotImplementedError
    s_multiplier = common_coefficient / reduce(
        ilcm, [S(x.q) for x in s_multipliers], S(1))
    if s_multiplier == common_coefficient:
        if len(s_multipliers) == 0:
            s_multiplier = common_coefficient
        else:
            s_multiplier = common_coefficient \
                           *reduce(igcd, [S(x.p) for x in s_multipliers])

    exponent = S(1)
    fac = S(1)
    f = f.subs(s, s / s_multiplier)
    fac /= s_multiplier
    exponent = 1 / s_multiplier
    if a_ is not None:
        a_ *= s_multiplier
    if b_ is not None:
        b_ *= s_multiplier

    # 2)
    numer, denom = f.as_numer_denom()
    numer = Mul.make_args(numer)
    denom = Mul.make_args(denom)
    args = zip(numer, repeat(True)) + zip(denom, repeat(False))

    facs = []
    dfacs = []
    # *_gammas will contain pairs (a, c) representing Gamma(a*s + c)
    numer_gammas = []
    denom_gammas = []
    # exponentials will contain bases for exponentials of s
    exponentials = []

    def exception(fact):
        return IntegralTransformError("Inverse Mellin", f,
                                      "Unrecognised form '%s'." % fact)

    while args:
        fact, is_numer = args.pop()
        if is_numer:
            ugammas, lgammas = numer_gammas, denom_gammas
            ufacs, lfacs = facs, dfacs
        else:
            ugammas, lgammas = denom_gammas, numer_gammas
            ufacs, lfacs = dfacs, facs

        def linear_arg(arg):
            """ Test if arg is of form a*s+b, raise exception if not. """
            if not arg.is_polynomial(s):
                raise exception(fact)
            p = Poly(arg, s)
            if p.degree() != 1:
                raise exception(fact)
            return p.all_coeffs()

        # constants
        if not fact.has(s):
            ufacs += [fact]
        # exponentials
        elif fact.is_Pow or isinstance(fact, exp_):
            if fact.is_Pow:
                base = fact.base
                exp = fact.exp
            else:
                base = E
                exp = fact.args[0]
            if exp.is_Integer:
                cond = is_numer
                if exp < 0:
                    cond = not cond
                args += [(base, cond)] * abs(exp)
                continue
            elif not base.has(s):
                a, b = linear_arg(exp)
                if not is_numer:
                    base = 1 / base
                exponentials += [base**a]
                facs += [base**b]
            else:
                raise exception(fact)
        # linear factors
        elif fact.is_polynomial(s):
            p = Poly(fact, s)
            if p.degree() != 1:
                # We completely factor the poly. For this we need the roots.
                # Now roots() only works in some cases (low degree), and RootOf
                # only works without parameters. So try both...
                coeff = p.LT()[1]
                rs = roots(p, s)
                if len(rs) != p.degree():
                    rs = RootOf.all_roots(p)
                ufacs += [coeff]
                args += [(s - c, is_numer) for c in rs]
                continue
            a, c = p.all_coeffs()
            ufacs += [a]
            c /= -a
            # Now need to convert s - c
            if left(c, is_numer):
                ugammas += [(S(1), -c + 1)]
                lgammas += [(S(1), -c)]
            else:
                ufacs += [-1]
                ugammas += [(S(-1), c + 1)]
                lgammas += [(S(-1), c)]
        elif isinstance(fact, gamma):
            a, b = linear_arg(fact.args[0])
            if is_numer:
                if (a > 0 and (left(-b/a, is_numer) is False)) or \
                   (a < 0 and (left(-b/a, is_numer) is True)):
                    raise NotImplementedError(
                        'Gammas partially over the strip.')
            ugammas += [(a, b)]
        elif isinstance(fact, sin):
            # We try to re-write all trigs as gammas. This is not in
            # general the best strategy, since sometimes this is impossible,
            # but rewriting as exponentials would work. However trig functions
            # in inverse mellin transforms usually all come from simplifying
            # gamma terms, so this should work.
            a = fact.args[0]
            if is_numer:
                # No problem with the poles.
                gamma1, gamma2, fac_ = gamma(a / pi), gamma(1 - a / pi), pi
            else:
                gamma1, gamma2, fac_ = _rewrite_sin(linear_arg(a), s, a_, b_)
            args += [(gamma1, not is_numer), (gamma2, not is_numer)]
            ufacs += [fac_]
        elif isinstance(fact, tan):
            a = fact.args[0]
            args += [(sin(a, evaluate=False), is_numer),
                     (sin(pi / 2 - a, evaluate=False), not is_numer)]
        elif isinstance(fact, cos):
            a = fact.args[0]
            args += [(sin(pi / 2 - a, evaluate=False), is_numer)]
        elif isinstance(fact, cot):
            a = fact.args[0]
            args += [(sin(pi / 2 - a, evaluate=False), is_numer),
                     (sin(a, evaluate=False), not is_numer)]
        else:
            raise exception(fact)

    fac *= Mul(*facs) / Mul(*dfacs)

    # 3)
    an, ap, bm, bq = [], [], [], []
    for gammas, plus, minus, is_numer in [(numer_gammas, an, bm, True),
                                          (denom_gammas, bq, ap, False)]:
        while gammas:
            a, c = gammas.pop()
            if a != -1 and a != +1:
                # We use the gamma function multiplication theorem.
                p = abs(S(a))
                newa = a / p
                newc = c / p
                assert a.is_Integer
                for k in range(p):
                    gammas += [(newa, newc + k / p)]
                if is_numer:
                    fac *= (2 * pi)**((1 - p) / 2) * p**(c - S(1) / 2)
                    exponentials += [p**a]
                else:
                    fac /= (2 * pi)**((1 - p) / 2) * p**(c - S(1) / 2)
                    exponentials += [p**(-a)]
                continue
            if a == +1:
                plus.append(1 - c)
            else:
                minus.append(c)

    # 4)
    # TODO

    # 5)
    arg = Mul(*exponentials)

    # for testability, sort the arguments
    an.sort()
    ap.sort()
    bm.sort()
    bq.sort()

    return (an, ap), (bm, bq), arg, exponent, fac
Esempio n. 10
0
def _expansion_search(expr, rep_list, lib=None):
    """
    Search for and substitute terms that match a series expansion of
    fundamental math functions.

    e: expression

    rep_list: list containing dummy variables

    """
    if debug:
        print("_expansion_search: ", expr)

    try:
        if isinstance(expr, Mul):
            exprs = [expr]
        elif isinstance(expr, Add):
            exprs = expr.args
        else:
            return expr

        if lib is not None:
            fncs, series = lib
        else:
            fncs, series = _fncs, _series

        newargs = []
        for expr in exprs:
            # Try to simplify the expression
            if isinstance(expr, Mul):
                # Split the expression into a LIST of commutative and a LIST of non-commutative factor (i.e. operators).
                c, nc = expr.args_cnc()
                if nc and c:
                    # Construct an expression of commutative elements ONLY.
                    expr = Mul(*c).expand()
                    #out = find_expansion(expr, *rep_list)

                    eq = Poly(expr, *rep_list)
                    bdict = eq.as_dict()

                    if any([
                            n > 1 for n in
                        [sum([i != 0 for i in k]) for k in bdict.keys()]
                    ]):
                        raise ValueError(
                            "Expressions cross-products of symbols are not supported (yet?).."
                        )

                    # Construct the list of 'vectors'
                    vecl = []
                    fncl = []
                    for x in rep_list:
                        for n in range(3):  #range(eq.degree()-1):
                            X = pow(x, n)
                            vecl.extend([((X * p.subs(_s, x)).expand() +
                                          O(pow(x,
                                                eq.degree() + 1))).removeO()
                                         for p in series])
                            fncl.extend([X * f(x) for f in fncs])
                        vecl.extend(
                            [pow(x, n) for n in range(max(eq.degree(), 3))])
                        fncl.extend(
                            [pow(x, n) for n in range(max(eq.degree(), 3))])

                    # Create vector coefficients
                    q = symbols(f'q:{len(vecl)}')
                    # Take inner product of 'vector' list and vector coefficients
                    A = Add(*[x * y
                              for x, y in zip(q, vecl)]).as_poly(*rep_list)

                    terms = []
                    for k, eq in A.as_dict().items():
                        terms.append(eq - bdict.get(k, 0))
                    H = linsolve(terms, *q)
                    h = H.subs({k: 0 for k in q})

                    out = Add(*[c * fnc for fnc, c in zip(fncl, list(h)[0])])

                    newargs.append(out * Mul(*nc))
                else:
                    newargs.append(expr)
            else:
                newargs.append(expr)

        return Add(*newargs)

    except Exception as e:
        print("Failed to identify series expansions: " + str(e))
        return e
Esempio n. 11
0
            if len(uniq_b) == max_size:
                break
        if flag_all:
            break
    if not flag_all:
        ans.append(p)


if __name__ == '__main__':
    print('Enter the polynomial: ', end='')

    from sympy import Poly, Symbol

    polynom = Poly(input())

    d = polynom.degree() + 1
    a = Symbol('a')

    symbols = []
    for symbol in polynom.free_symbols:
        symbols.append(str(symbol))

    symbols.sort()

    replace_symbols = {}
    j = 0
    for symbol in symbols:
        replace_symbols[symbol] = a**(d**j)
        j += 1

    for symbol in replace_symbols:
Esempio n. 12
0
def sturm():
    divid = [fx, diff(fx)]  # Array where equations will be stored
    while True:
        test = Poly(divid[-1], x)
        if len(test.coeffs()) > 1:
            q, r = div(divid[-2], divid[-1],
                       x)  # Taking quotient and remainder of dividing
            divid.append(-1 * r)
        else:
            break
    print('\n Let\'s calculate dividing of a polynomials: ')
    for i in divid:
        print('f' + str(divid.index(i)) + '(x): ' + str(i))

    # Create information table
    table = [['   '], ['-inf'], ['+inf']]
    for i in divid:
        table[0].append('f' + str(divid.index(i)) +
                        '(x)')  # Better information association
        test = Poly(i, x)
        # -inf
        if (test.degree() % 2 == 0 and test.coeffs()[0] > 0) or \
                (test.degree() % 2 != 0 and test.coeffs()[0] < 0):
            table[1].append('+')
        else:
            table[1].append('-')
        # +inf
        if test.coeffs()[0] > 0:
            table[2].append('+')
        else:
            table[2].append('-')

    qwe = changes(table)
    mininf = qwe[0]
    plusinf = qwe[1]

    # Add found data to a table for better user experience
    table[0].append('Sign changes')
    table[1].append(mininf)
    table[2].append(plusinf)
    print('---------')
    print(
        '\n\n Then we need to calculate number of sign changes for (-inf) and (+inf) cases. '
    )
    print(' Let\'s create a table to visualize our results: ')

    for i in table:
        print()
        for j in i:
            if table.index(i) == 0:
                print('  ' + j, end='')
            else:
                print(j, end='     ' + ' ' * i.index(j))
    print(
        '\n\n As we see, our equation has {0} - {1} = {2} real roots.'.format(
            mininf, plusinf, mininf - plusinf))

    print('---------')
    print('\n\n Now we need to define possible intervals for roots. ')
    print(
        ' Let\'s create a table with calculated functions in possible root interval. '
    )

    # Creating a table
    results = [['    ']]
    for i in divid:
        results[0].append('f' + str(divid.index(i)) +
                          '(x) ')  # Better information association
    for i in range(floor(Rlo), ceil(Rup + 1)):
        results.append(['x = ' + str(i)])

    # Calculate value for each function and possible variable
    count = 1
    for j in range(floor(Rlo), ceil(Rup + 1)):
        for i in divid:
            if i.evalf(subs={x: j}) > 0:
                results[count].append('+')
            else:
                results[count].append('-')
        count += 1

    # Check number of sign changes
    ert = changes(results)
    results[0].append('Sign changes')
    for i in range(1, len(results)):
        results[i].append(ert[i - 1])

    # Printing table
    for i in results:
        print()
        for j in i:
            if results.index(i) == 0:
                print('  ' + j, end='')
            else:
                print(j, end='     ' + ' ' * i.index(j))

    send = []
    for i in range(1, len(results) - 1):
        if results[i][-1] != results[i + 1][-1]:
            temp = [i for i in range(floor(Rlo), ceil(Rup + 1))]
            send.append((temp[i - 1], temp[i]))

    # Check if we need extended computations
    analys = False
    for i in range(1, len(send)):
        if send[i][0] == send[i - 1][1]:
            analys = True
            break
    if len(send) != mininf - plusinf or analys is True:
        print(
            '\n\nWARNING!!! PROGRAM CALCULATE VALUES FROM {0} TO {1} with step 0.1. IT\'S NOT SHOWN IN A TABLE.'
            .format(floor(Rlo), ceil(Rup + 1)) +
            '\nIT HAPPENS BECAUSE TWO OR MORE ROOTS LIE IN INTERVAL WITH SIZE LESS THAN 1'
            +
            '\nOR THEIR INTERVALS STARTS AND BEGINS AT ONE POINT RESPECTIVELY.'
            + '\nWITHOUT THIS CHECKING CALCULATIONS WILL BE WRONG.')
        send = deepanalysis(divid)

    print('\n As we can see, roots of equation lie in intervals: ')
    for i in send:
        print(i)

    return send  # Return intervals of roots