Пример #1
0
def compute_solution_for_recurrence(recurr_coeff: Expr,
                                    inhom_part_solution: Expr,
                                    initial_value: Expr):
    """
    Computes the (unique) solution to the recurrence relation:
    f(0) = initial_value; f(n+1) = recurr_coeff * f(n) + inhom_part_solution
    """
    log(
        f"Start compute solution for recurrence, { recurr_coeff }, { inhom_part_solution }, { initial_value }",
        LOG_VERBOSE)
    n = symbols('n', integer=True, positive=True)
    if recurr_coeff.is_zero:
        return expand(inhom_part_solution.xreplace({n: n - 1}))

    hom_solution = (recurr_coeff**n) * initial_value
    k = symbols('_k', integer=True, positive=True)
    summand = simplify(
        (recurr_coeff**k) * inhom_part_solution.xreplace({n: (n - 1) - k}))
    particular_solution = summation(summand, (k, 0, (n - 1)))
    particular_solution = without_piecewise(particular_solution)
    solution = simplify(hom_solution + particular_solution)
    log(
        f"End compute solution for recurrence, { recurr_coeff }, { inhom_part_solution }, { initial_value }",
        LOG_VERBOSE)
    return solution
Пример #2
0
def test_factor_nc():
    x, y = symbols('x,y')
    k = symbols('k', integer=True)
    n, m, o = symbols('n,m,o', commutative=False)

    # mul and multinomial expansion is needed
    e = x * (1 + y)**2
    assert _mexpand(e) == x + x * 2 * y + x * y**2

    def factor_nc_test(e):
        ex = _mexpand(e)
        assert ex.is_Add
        f = factor_nc(ex)
        assert not f.is_Add and _mexpand(f) == ex

    factor_nc_test(x * (1 + y))
    factor_nc_test(n * (x + 1))
    factor_nc_test(n * (x + m))
    factor_nc_test((x + m) * n)
    factor_nc_test(n * m * (x * o + n * o * m) * n)
    s = Sum(x, (x, 1, 2))
    factor_nc_test(x * (1 + s))
    factor_nc_test(x * (1 + s) * s)
    factor_nc_test(x * (1 + sin(s)))
    factor_nc_test((1 + n)**2)

    factor_nc_test((x + n) * (x + m) * (x + y))
    factor_nc_test(x * (n * m + 1))
    factor_nc_test(x * (n * m + x))
    factor_nc_test(x * (x * n * m + 1))
    factor_nc_test(x * n * (x * m + 1))
    factor_nc_test(x * (m * n + x * n * m))
    factor_nc_test(n * (1 - m) * n**2)

    factor_nc_test((n + m)**2)
    factor_nc_test((n - m) * (n + m)**2)
    factor_nc_test((n + m)**2 * (n - m))
    factor_nc_test((m - n) * (n + m)**2 * (n - m))

    assert factor_nc(n * (n + n * m)) == n**2 * (1 + m)
    assert factor_nc(m * (m * n + n * m * n**2)) == m * (m + n * m * n) * n
    eq = m * sin(n) - sin(n) * m
    assert factor_nc(eq) == eq

    eq = (sin(n) + x) * (cos(n) + x)
    assert factor_nc(eq.expand()) == eq

    # issue sympy/sympy#6534
    assert (2 * n + 2 * m).factor() == 2 * (n + m)

    # issue sympy/sympy#6701
    assert factor_nc(n**k + n**(k + 1)) == n**k * (1 + n)
    assert factor_nc((m * n)**k + (m * n)**(k + 1)) == (1 + m * n) * (m * n)**k

    # issue sympy/sympy#6918
    assert factor_nc(-n * (2 * x**2 + 2 * x)) == -2 * n * x * (x + 1)

    assert factor_nc(1 + Mul(Expr(), Expr(), evaluate=False)) == 1 + Expr()**2
Пример #3
0
def get_initial_polarity_for_expression(expression: Expr,
                                        program: Program) -> (bool, bool):
    """
    Returns a sound estimate whether a given expression can initial be positive and negative. It does so
    by substituting the variable power in the given expression with all possible combination of lower and upper
    bounds of their respective supports.
    """
    variables = expression.free_symbols.intersection(program.variables)
    # First we can replace n and all variables which are deterministic initially (meaning they have exactly one branch)
    expression = expression.xreplace(
        {symbols("n", integer=True, positive=True): 0})
    for v in variables:
        if not expression.free_symbols & variables:
            continue
        if hasattr(program.initial_values[v], "branches") and len(
                program.initial_values[v].branches) == 1:
            expression = expression.subs(
                {v: program.initial_values[v].branches[0][0]})

    variables = expression.free_symbols.intersection(program.variables)
    if not variables:
        maybePos = bool(
            expression > 0) if (expression > 0).is_Boolean else True
        maybeNeg = bool(
            expression < 0) if (expression < 0).is_Boolean else True
        return maybePos, maybeNeg

    expression = expression.as_poly(variables)
    var_powers = set()
    monoms = get_monoms(expression)
    for m in monoms:
        m = m.as_poly(variables)
        powers = m.monoms()[0]
        var_powers.update([(v, p) for v, p in zip(m.gens, powers) if p > 0])
    initial_supports = get_initial_supports_for_variable_powers(
        var_powers, program)
    possible_substitutions = flatten_substitution_choices(initial_supports)
    expression = expression.as_expr()
    possible_initial_polarities = []
    for ps in possible_substitutions:
        pos = expression.subs(ps) > 0
        if pos.is_Boolean:
            possible_initial_polarities.append(bool(pos))
        else:
            possible_initial_polarities.append(None)

    allPositive = all([v is True for v in possible_initial_polarities])
    allNegative = all([v is False for v in possible_initial_polarities])

    maybePos = not allNegative
    maybeNeg = not allPositive

    return maybePos, maybeNeg
Пример #4
0
 def _eval_evalf(self, prec):
     from mpmath import mp, workprec
     from diofant import Expr
     z = self.args[0]._to_mpmath(prec)
     with workprec(prec):
         res = mp.airybi(z, derivative=1)
     return Expr._from_mpmath(res, prec)
Пример #5
0
def is_deterministic_invariant(expression: Expr) -> bool:
    """
    Checks whether an expression only containing n eventually stays <= 0
    """
    n = symbols("n", integer=True, positive=True)
    max_0 = get_max_0(expression, n)
    return expression.subs({n: max_0 + 1}) <= 0
Пример #6
0
 def _eval_evalf(self, prec):
     from mpmath import mp, workprec
     from diofant import Expr
     a = self.args[0]._to_mpmath(prec)
     z = self.args[1]._to_mpmath(prec)
     with workprec(prec):
         res = mp.gammainc(a, z, mp.inf)
     return Expr._from_mpmath(res, prec)
Пример #7
0
    def _eval_evalf(self, prec):
        m = self.args[0]

        if m.is_Integer and m.is_nonnegative:
            from mpmath import mp
            from diofant import Expr
            m = m._to_mpmath(prec)
            with workprec(prec):
                res = mp.eulernum(m)
            return Expr._from_mpmath(res, prec)
Пример #8
0
    def _eval_evalf(self, prec):
        # The default code is insufficient for polar arguments.
        # mpmath provides an optional argument "r", which evaluates
        # G(z**(1/r)). I am not sure what its intended use is, but we hijack it
        # here in the following way: to evaluate at a number z of |argument|
        # less than (say) n*pi, we put r=1/n, compute z' = root(z, n)
        # (carefully so as not to loose the branch information), and evaluate
        # G(z'**(1/r)) = G(z'**n) = G(z).
        from diofant.functions import exp_polar, ceiling
        from diofant import Expr
        import mpmath
        z = self.argument
        znum = self.argument._eval_evalf(prec)
        if znum.has(exp_polar):
            znum, branch = znum.as_coeff_mul(exp_polar)
            if len(branch) != 1:
                return
            branch = branch[0].args[0] / I
        else:
            branch = Integer(0)
        n = ceiling(abs(branch / S.Pi)) + 1
        znum = znum**(Integer(1) / n) * exp(I * branch / n)

        # Convert all args to mpf or mpc
        try:
            [z, r, ap, bq] = [
                arg._to_mpmath(prec)
                for arg in [znum, 1 / n, self.args[0], self.args[1]]
            ]
        except ValueError:
            return

        with mpmath.workprec(prec):
            v = mpmath.meijerg(ap, bq, z, r)

        return Expr._from_mpmath(v, prec)
Пример #9
0
    def __new__(cls, *args, **kwargs):

        shape, flat_list = cls._handle_ndarray_creation_inputs(*args, **kwargs)
        shape = Tuple(*map(_sympify, shape))
        loop_size = functools.reduce(lambda x, y: x * y, shape) if shape else 0

        # Sparse array:
        if isinstance(flat_list, (dict, Dict)):
            sparse_array = Dict(flat_list)
        else:
            sparse_array = {}
            for i, el in enumerate(flatten(flat_list)):
                if el != 0:
                    sparse_array[i] = _sympify(el)

        sparse_array = Dict(sparse_array)

        self = Expr.__new__(cls, sparse_array, shape, **kwargs)
        self._shape = shape
        self._rank = len(shape)
        self._loop_size = loop_size
        self._sparse_array = sparse_array

        return self
Пример #10
0
 def __new__(cls, x):
     return Expr.__new__(cls, x)
Пример #11
0
def test_sympyissue_5486_bug():
    assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15
    pytest.raises(TypeError, lambda: Expr._from_mpmath(I, 15))
Пример #12
0
def test_issue_5486_bug():
    from diofant import I, Expr
    assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15
    pytest.raises(TypeError, lambda: Expr._from_mpmath(I, 15))
Пример #13
0
def test_diff_wrt_value():
    assert Expr()._diff_wrt is False
    assert x._diff_wrt is True
    assert f(x)._diff_wrt is True
    assert Derivative(f(x), x)._diff_wrt is True
    assert Derivative(x**2, x)._diff_wrt is False
Пример #14
0
 def __new__(cls, x):
     return Expr.__new__(cls, x)
Пример #15
0
def test_sympyissue_5486_bug():
    assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15
Пример #16
0
def jn_zeros(n, k, method="diofant", dps=15):
    """
    Zeros of the spherical Bessel function of the first kind.

    This returns an array of zeros of jn up to the k-th zero.

    * method = "diofant": uses mpmath's function ``besseljzero``
    * method = "scipy": uses the
      `SciPy's sph_jn <http://docs.scipy.org/doc/scipy/reference/generated/scipy.special.jn_zeros.html>`_
      and
      `newton <http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.newton.html>`_
      to find all
      roots, which is faster than computing the zeros using a general
      numerical solver, but it requires SciPy and only works with low
      precision floating point numbers.  [The function used with
      method="diofant" is a recent addition to mpmath, before that a general
      solver was used.]

    Examples
    ========

    >>> from diofant import jn_zeros
    >>> jn_zeros(2, 4, dps=5)
    [5.7635, 9.095, 12.323, 15.515]

    See Also
    ========

    jn, yn, besselj, besselk, bessely
    """
    from math import pi

    if method == "diofant":
        from mpmath import besseljzero
        from mpmath.libmp.libmpf import dps_to_prec
        from diofant import Expr
        prec = dps_to_prec(dps)
        return [
            Expr._from_mpmath(
                besseljzero(sympify(n + 0.5)._to_mpmath(prec), int(l)), prec)
            for l in range(1, k + 1)
        ]
    elif method == "scipy":
        from scipy.special import sph_jn
        from scipy.optimize import newton

        def f(x):
            return sph_jn(n, x)[0][-1]
    else:
        raise NotImplementedError("Unknown method.")

    def solver(f, x):
        if method == "scipy":
            root = newton(f, x)
        else:
            raise NotImplementedError("Unknown method.")
        return root

    # we need to approximate the position of the first root:
    root = n + pi
    # determine the first root exactly:
    root = solver(f, root)
    roots = [root]
    for i in range(k - 1):
        # estimate the position of the next root using the last root + pi:
        root = solver(f, root + pi)
        roots.append(root)
    return roots
Пример #17
0
def test_sympyissue_5486_bug():
    assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15
    pytest.raises(TypeError, lambda: Expr._from_mpmath(I, 15))
Пример #18
0
def test_from_mpmath():
    # issue sympy/sympy#5486
    pytest.raises(TypeError, lambda: Expr._from_mpmath(I, 15))
Пример #19
0
def test_sympyissue_5486():
    assert not cos(sqrt(0.5 + I)).evalf(strict=False).is_Function
    assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15