Example #1
0
def test_apart_list():
    assert apart_list(1) == 1

    w0, w1, w2 = Symbol("w0"), Symbol("w1"), Symbol("w2")
    _a = Dummy("a")

    f = (-2*x - 2*x**2) / (3*x**2 - 6*x)
    assert (apart_list(f, x, dummies=numbered_symbols("w")) ==
            (-1, Poly(Rational(2, 3), x),
             [(Poly(w0 - 2, w0), Lambda(_a, 2), Lambda(_a, -_a + x), 1)]))

    assert (apart_list(2/(x**2-2), x, dummies=numbered_symbols("w")) ==
            (1, Poly(0, x),
             [(Poly(w0**2 - 2, w0), Lambda(_a, _a/2), Lambda(_a, -_a + x), 1)]))

    f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2)
    assert (apart_list(f, x, dummies=numbered_symbols("w")) ==
            (1, Poly(0, x),
             [(Poly(w0 - 2, w0), Lambda(_a, 4), Lambda(_a, -_a + x), 1),
              (Poly(w1**2 - 1, w1), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2),
              (Poly(w2 + 1, w2), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]))

    f = 1/(2*(x - 1)**2)
    assert (apart_list(f, x, dummies=numbered_symbols("w")) ==
            (1, Poly(0, x),
             [(Poly(2, w0), Lambda(_a, 0), Lambda(_a, x - _a), 1),
              (Poly(w1 - 1, w1), Lambda(_a, Rational(1, 2)), Lambda(_a, x - _a), 2),
              (Poly(1, w2), Lambda(_a, 0), Lambda(_a, x - _a), 1)]))
Example #2
0
def test_take():
    X = numbered_symbols()

    assert take(X, 5) == list(symbols('x0:5'))
    assert take(X, 5) == list(symbols('x5:10'))

    assert take([1, 2, 3, 4, 5], 5) == [1, 2, 3, 4, 5]
Example #3
0
def test_take():
    X = numbered_symbols()

    assert take(X, 5) == list(symbols('x0:5'))
    assert take(X, 5) == list(symbols('x5:10'))

    assert take([1, 2, 3, 4, 5], 5) == [1, 2, 3, 4, 5]
Example #4
0
def test_apart_list():
    from diofant.utilities.iterables import numbered_symbols

    assert apart_list(1) == 1

    w0, w1, w2 = Symbol("w0"), Symbol("w1"), Symbol("w2")
    _a = Dummy("a")

    f = (-2 * x - 2 * x**2) / (3 * x**2 - 6 * x)
    assert apart_list(f, x,
                      dummies=numbered_symbols("w")) == (-1,
                                                         Poly(Rational(2, 3),
                                                              x,
                                                              domain='QQ'),
                                                         [(Poly(w0 - 2,
                                                                w0,
                                                                domain='ZZ'),
                                                           Lambda(_a, 2),
                                                           Lambda(_a, -_a + x),
                                                           1)])

    assert apart_list(
        2 / (x**2 - 2), x,
        dummies=numbered_symbols("w")) == (1, Poly(0, x, domain='ZZ'), [
            (Poly(w0**2 - 2, w0,
                  domain='ZZ'), Lambda(_a, _a / 2), Lambda(_a, -_a + x), 1)
        ])

    f = 36 / (x**5 - 2 * x**4 - 2 * x**3 + 4 * x**2 + x - 2)
    assert apart_list(
        f, x, dummies=numbered_symbols("w")) == (1, Poly(0, x, domain='ZZ'), [
            (Poly(w0 - 2, w0, domain='ZZ'), Lambda(_a, 4), Lambda(_a,
                                                                  -_a + x), 1),
            (Poly(w1**2 - 1, w1,
                  domain='ZZ'), Lambda(_a, -3 * _a - 6), Lambda(_a,
                                                                -_a + x), 2),
            (Poly(w2 + 1, w2, domain='ZZ'), Lambda(_a,
                                                   -4), Lambda(_a, -_a + x), 1)
        ])
Example #5
0
def test_apart_list():
    assert apart_list(1) == 1

    w0, w1, w2 = Symbol("w0"), Symbol("w1"), Symbol("w2")
    _a = Dummy("a")

    f = (-2 * x - 2 * x**2) / (3 * x**2 - 6 * x)
    assert (apart_list(
        f, x, dummies=numbered_symbols("w")) == (-1, Poly(Rational(2, 3), x), [
            (Poly(w0 - 2, w0), Lambda(_a, 2), Lambda(_a, -_a + x), 1)
        ]))

    assert (apart_list(2 / (x**2 - 2), x,
                       dummies=numbered_symbols("w")) == (1, Poly(0, x), [
                           (Poly(w0**2 - 2,
                                 w0), Lambda(_a, _a / 2), Lambda(_a,
                                                                 -_a + x), 1)
                       ]))

    f = 36 / (x**5 - 2 * x**4 - 2 * x**3 + 4 * x**2 + x - 2)
    assert (apart_list(f, x,
                       dummies=numbered_symbols("w")) == (1, Poly(0, x), [
                           (Poly(w0 - 2,
                                 w0), Lambda(_a, 4), Lambda(_a, -_a + x), 1),
                           (Poly(w1**2 - 1, w1), Lambda(_a, -3 * _a - 6),
                            Lambda(_a, -_a + x), 2),
                           (Poly(w2 + 1,
                                 w2), Lambda(_a, -4), Lambda(_a, -_a + x), 1)
                       ]))

    f = 1 / (2 * (x - 1)**2)
    assert (apart_list(f, x,
                       dummies=numbered_symbols("w")) == (1, Poly(0, x), [
                           (Poly(2, w0), Lambda(_a, 0), Lambda(_a, x - _a), 1),
                           (Poly(w1 - 1, w1), Lambda(_a, Rational(1, 2)),
                            Lambda(_a, x - _a), 2),
                           (Poly(1, w2), Lambda(_a, 0), Lambda(_a, x - _a), 1)
                       ]))
Example #6
0
def test_numbered_symbols():
    s = numbered_symbols(cls=Dummy)
    assert isinstance(next(s), Dummy)
    assert next(numbered_symbols('C', start=1, exclude=[symbols('C1')])) == \
        symbols('C2')
Example #7
0
def test_filter_symbols():
    s = numbered_symbols()
    filtered = filter_symbols(s, symbols("x0 x2 x3"))
    assert take(filtered, 3) == list(symbols("x1 x4 x5"))
Example #8
0
def cse(exprs,
        symbols=None,
        optimizations=None,
        postprocess=None,
        order='canonical'):
    """ Perform common subexpression elimination on an expression.

    Parameters
    ==========

    exprs : list of diofant expressions, or a single diofant expression
        The expressions to reduce.
    symbols : infinite iterator yielding unique Symbols
        The symbols used to label the common subexpressions which are pulled
        out. The ``numbered_symbols`` generator is useful. The default is a
        stream of symbols of the form "x0", "x1", etc. This must be an
        infinite iterator.
    optimizations : list of (callable, callable) pairs
        The (preprocessor, postprocessor) pairs of external optimization
        functions. Optionally 'basic' can be passed for a set of predefined
        basic optimizations. Such 'basic' optimizations were used by default
        in old implementation, however they can be really slow on larger
        expressions. Now, no pre or post optimizations are made by default.
    postprocess : a function which accepts the two return values of cse and
        returns the desired form of output from cse, e.g. if you want the
        replacements reversed the function might be the following lambda:
        lambda r, e: return reversed(r), e
    order : string, 'none' or 'canonical'
        The order by which Mul and Add arguments are processed. If set to
        'canonical', arguments will be canonically ordered. If set to 'none',
        ordering will be faster but dependent on expressions hashes, thus
        machine dependent and variable. For large expressions where speed is a
        concern, use the setting order='none'.

    Returns
    =======

    replacements : list of (Symbol, expression) pairs
        All of the common subexpressions that were replaced. Subexpressions
        earlier in this list might show up in subexpressions later in this
        list.
    reduced_exprs : list of diofant expressions
        The reduced expressions with all of the replacements above.

    Examples
    ========

    >>> from diofant import cse, SparseMatrix
    >>> from diofant.abc import x, y, z, w
    >>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3)
    ([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3])

    Note that currently, y + z will not get substituted if -y - z is used.

     >>> cse(((w + x + y + z)*(w - y - z))/(w + x)**3)
     ([(x0, w + x)], [(w - y - z)*(x0 + y + z)/x0**3])

    List of expressions with recursive substitutions:

    >>> m = SparseMatrix([x + y, x + y + z])
    >>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m])
    ([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([
    [x0],
    [x1]])])

    Note: the type and mutability of input matrices is retained.

    >>> isinstance(_[1][-1], SparseMatrix)
    True
    """
    from diofant.matrices import (MatrixBase, Matrix, ImmutableMatrix,
                                  SparseMatrix, ImmutableSparseMatrix)

    # Handle the case if just one expression was passed.
    if isinstance(exprs, (Basic, MatrixBase)):
        exprs = [exprs]

    copy = exprs
    temp = []
    for e in exprs:
        if isinstance(e, (Matrix, ImmutableMatrix)):
            temp.append(Tuple(*e._mat))
        elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)):
            temp.append(Tuple(*e._smat.items()))
        else:
            temp.append(e)
    exprs = temp
    del temp

    if optimizations is None:
        optimizations = list()
    elif optimizations == 'basic':
        optimizations = basic_optimizations

    # Preprocess the expressions to give us better optimization opportunities.
    reduced_exprs = [preprocess_for_cse(e, optimizations) for e in exprs]

    excluded_symbols = set().union(
        *[expr.atoms(Symbol) for expr in reduced_exprs])

    if symbols is None:
        symbols = numbered_symbols()
    else:
        # In case we get passed an iterable with an __iter__ method instead of
        # an actual iterator.
        symbols = iter(symbols)

    symbols = filter_symbols(symbols, excluded_symbols)

    # Find other optimization opportunities.
    opt_subs = opt_cse(reduced_exprs, order)

    # Main CSE algorithm.
    replacements, reduced_exprs = tree_cse(reduced_exprs, symbols, opt_subs,
                                           order)

    # Postprocess the expressions to return the expressions to canonical form.
    exprs = copy
    for i, (sym, subtree) in enumerate(replacements):
        subtree = postprocess_for_cse(subtree, optimizations)
        replacements[i] = (sym, subtree)
    reduced_exprs = [
        postprocess_for_cse(e, optimizations) for e in reduced_exprs
    ]

    # Get the matrices back
    for i, e in enumerate(exprs):
        if isinstance(e, (Matrix, ImmutableMatrix)):
            reduced_exprs[i] = Matrix(e.rows, e.cols, reduced_exprs[i])
            if isinstance(e, ImmutableMatrix):
                reduced_exprs[i] = reduced_exprs[i].as_immutable()
        elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)):
            m = SparseMatrix(e.rows, e.cols, {})
            for k, v in reduced_exprs[i]:
                m[k] = v
            if isinstance(e, ImmutableSparseMatrix):
                m = m.as_immutable()
            reduced_exprs[i] = m

    if postprocess is None:
        return replacements, reduced_exprs

    return postprocess(replacements, reduced_exprs)
Example #9
0
def rsolve_hyper(coeffs, f, n, **hints):
    """
    Given linear recurrence operator `\operatorname{L}` of order `k`
    with polynomial coefficients and inhomogeneous equation
    `\operatorname{L} y = f` we seek for all hypergeometric solutions
    over field `K` of characteristic zero.

    The inhomogeneous part can be either hypergeometric or a sum
    of a fixed number of pairwise dissimilar hypergeometric terms.

    The algorithm performs three basic steps:

        (1) Group together similar hypergeometric terms in the
            inhomogeneous part of `\operatorname{L} y = f`, and find
            particular solution using Abramov's algorithm.

        (2) Compute generating set of `\operatorname{L}` and find basis
            in it, so that all solutions are linearly independent.

        (3) Form final solution with the number of arbitrary
            constants equal to dimension of basis of `\operatorname{L}`.

    Term `a(n)` is hypergeometric if it is annihilated by first order
    linear difference equations with polynomial coefficients or, in
    simpler words, if consecutive term ratio is a rational function.

    The output of this procedure is a linear combination of fixed
    number of hypergeometric terms. However the underlying method
    can generate larger class of solutions - D'Alembertian terms.

    Note also that this method not only computes the kernel of the
    inhomogeneous equation, but also reduces in to a basis so that
    solutions generated by this procedure are linearly independent

    Examples
    ========

    >>> from diofant.solvers import rsolve_hyper
    >>> from diofant.abc import x

    >>> rsolve_hyper([-1, -1, 1], 0, x)
    C0*(1/2 + sqrt(5)/2)**x + C1*(-sqrt(5)/2 + 1/2)**x

    >>> rsolve_hyper([-1, 1], 1 + x, x)
    C0 + x*(x + 1)/2

    References
    ==========

    .. [1] M. Petkovšek, Hypergeometric solutions of linear recurrences
           with polynomial coefficients, J. Symbolic Computation,
           14 (1992), 243-264.

    .. [2] M. Petkovšek, H. S. Wilf, D. Zeilberger, A = B, 1996.
    """
    coeffs = list(map(sympify, coeffs))

    f = sympify(f)

    r, kernel, symbols = len(coeffs) - 1, [], set()

    if not f.is_zero:
        if f.is_Add:
            similar = {}

            for g in f.expand().args:
                if not g.is_hypergeometric(n):
                    return

                for h in similar.keys():
                    if hypersimilar(g, h, n):
                        similar[h] += g
                        break
                else:
                    similar[g] = S.Zero

            inhomogeneous = []

            for g, h in similar.items():
                inhomogeneous.append(g + h)
        elif f.is_hypergeometric(n):
            inhomogeneous = [f]
        else:
            return

        for i, g in enumerate(inhomogeneous):
            coeff, polys = S.One, coeffs[:]
            denoms = [S.One] * (r + 1)

            s = hypersimp(g, n)

            for j in range(1, r + 1):
                coeff *= s.subs(n, n + j - 1)

                p, q = coeff.as_numer_denom()

                polys[j] *= p
                denoms[j] = q

            for j in range(0, r + 1):
                polys[j] *= Mul(*(denoms[:j] + denoms[j + 1:]))

            R = rsolve_ratio(polys, Mul(*denoms), n, symbols=True)
            if R is not None:
                R, syms = R
                if syms:
                    R = R.subs(zip(syms, [0] * len(syms)))

            if R:
                inhomogeneous[i] *= R
            else:
                return

            result = Add(*inhomogeneous)
            result = simplify(result)
    else:
        result = S.Zero

    Z = Dummy('Z')

    p, q = coeffs[0], coeffs[r].subs(n, n - r + 1)

    p_factors = [z for z in roots(p, n).keys()]
    q_factors = [z for z in roots(q, n).keys()]

    factors = [(S.One, S.One)]

    for p in p_factors:
        for q in q_factors:
            if p.is_integer and q.is_integer and p <= q:
                continue
            else:
                factors += [(n - p, n - q)]

    p = [(n - p, S.One) for p in p_factors]
    q = [(S.One, n - q) for q in q_factors]

    factors = p + factors + q

    for A, B in factors:
        polys, degrees = [], []
        D = A * B.subs(n, n + r - 1)

        for i in range(0, r + 1):
            a = Mul(*[A.subs(n, n + j) for j in range(0, i)])
            b = Mul(*[B.subs(n, n + j) for j in range(i, r)])

            poly = quo(coeffs[i] * a * b, D, n)
            polys.append(poly.as_poly(n))

            if not poly.is_zero:
                degrees.append(polys[i].degree())

        d, poly = max(degrees), S.Zero

        for i in range(0, r + 1):
            coeff = polys[i].nth(d)

            if coeff is not S.Zero:
                poly += coeff * Z**i

        for z in roots(poly, Z).keys():
            if z.is_zero:
                continue

            (C, s) = rsolve_poly([polys[i] * z**i for i in range(r + 1)],
                                 0,
                                 n,
                                 symbols=True)

            if C is not None and C is not S.Zero:
                symbols |= set(s)

                ratio = z * A * C.subs(n, n + 1) / B / C
                ratio = simplify(ratio)

                skip = max([-1] + [
                    v for v in roots(Mul(*ratio.as_numer_denom()), n).keys()
                    if v.is_Integer
                ]) + 1
                K = product(ratio, (n, skip, n - 1))

                if K.has(factorial, FallingFactorial, RisingFactorial):
                    K = simplify(K)

                if casoratian(kernel + [K], n, zero=False) != 0:
                    kernel.append(K)

    kernel.sort(key=default_sort_key)
    sk = list(zip(numbered_symbols('C'), kernel))

    for C, ker in sk:
        result += C * ker

    if hints.get('symbols', False):
        symbols |= {s for s, k in sk}
        return result, list(symbols)
    else:
        return result
Example #10
0
    def __init__(self,
                 args,
                 expr,
                 print_lambda=False,
                 use_evalf=False,
                 float_wrap_evalf=False,
                 complex_wrap_evalf=False,
                 use_np=False,
                 use_python_math=False,
                 use_python_cmath=False,
                 use_interval=False):

        self.print_lambda = print_lambda
        self.use_evalf = use_evalf
        self.float_wrap_evalf = float_wrap_evalf
        self.complex_wrap_evalf = complex_wrap_evalf
        self.use_np = use_np
        self.use_python_math = use_python_math
        self.use_python_cmath = use_python_cmath
        self.use_interval = use_interval

        # Constructing the argument string
        # - check
        if not all([isinstance(a, (Dummy, Symbol)) for a in args]):
            raise ValueError('The arguments must be Symbols.')
        # - use numbered symbols
        syms = numbered_symbols(exclude=expr.free_symbols)
        newargs = [next(syms) for i in args]
        expr = expr.xreplace(dict(zip(args, newargs)))
        argstr = ', '.join([str(a) for a in newargs])
        del syms, newargs, args

        # Constructing the translation dictionaries and making the translation
        self.dict_str = self.get_dict_str()
        self.dict_fun = self.get_dict_fun()
        exprstr = str(expr)
        newexpr = self.tree2str_translate(self.str2tree(exprstr))

        # Constructing the namespaces
        namespace = {}
        namespace.update(self.diofant_atoms_namespace(expr))
        namespace.update(self.diofant_expression_namespace(expr))
        # XXX Workaround
        # Ugly workaround because Pow(a,Half) prints as sqrt(a)
        # and diofant_expression_namespace can not catch it.
        from diofant import sqrt
        namespace.update({'sqrt': sqrt})
        namespace.update({'Eq': lambda x, y: x == y})
        # End workaround.
        if use_python_math:
            namespace.update({'math': __import__('math')})
        if use_python_cmath:
            namespace.update({'cmath': __import__('cmath')})
        if use_np:
            try:
                namespace.update({'np': __import__('numpy')})
            except ImportError:
                raise ImportError(
                    'experimental_lambdify failed to import numpy.')
        if use_interval:
            namespace.update({
                'imath':
                __import__('diofant.plotting.intervalmath',
                           fromlist=['intervalmath'])
            })
            namespace.update({'math': __import__('math')})

        # Construct the lambda
        if self.print_lambda:
            print(newexpr)
        eval_str = 'lambda %s : ( %s )' % (argstr, newexpr)
        exec("MYNEWLAMBDA = %s" % eval_str, namespace)
        self.lambda_func = namespace['MYNEWLAMBDA']
Example #11
0
def test_filter_symbols():
    s = numbered_symbols()
    filtered = filter_symbols(s, symbols("x0 x2 x3"))
    assert list(itertools.islice(filtered, 3)) == list(symbols("x1 x4 x5"))

    assert set(filter_symbols((), set())) == set()
Example #12
0
def test_numbered_symbols():
    s = numbered_symbols(cls=Dummy)
    assert isinstance(next(s), Dummy)
    assert next(numbered_symbols('C', start=1, exclude=[symbols('C1')])) == \
        symbols('C2')
Example #13
0
def test_filter_symbols():
    s = numbered_symbols()
    filtered = filter_symbols(s, symbols("x0 x2 x3"))
    assert take(filtered, 3) == list(symbols("x1 x4 x5"))

    assert set(filter_symbols((), set())) == set()