Esempio n. 1
0
    def contains(self, other):
        """
        Is the other GeometryEntity contained within this Segment?

        Examples
        ========

        >>> from diofant import Point, Segment
        >>> p1, p2 = Point(0, 1), Point(3, 4)
        >>> s = Segment(p1, p2)
        >>> s2 = Segment(p2, p1)
        >>> s.contains(s2)
        True
        """
        if isinstance(other, Segment):
            return other.p1 in self and other.p2 in self
        elif isinstance(other, Point):
            if Point.is_collinear(self.p1, self.p2, other):
                t = Dummy('t')
                x, y = self.arbitrary_point(t).args
                if self.p1.x != self.p2.x:
                    ti = solve(x - other.x, t)[0]
                else:
                    ti = solve(y - other.y, t)[0]
                if ti.is_number:
                    return 0 <= ti <= 1
                return

        return False
Esempio n. 2
0
def singularities(f, x):
    """Find singularities of real-valued function `f` with respect to `x`.

    Examples
    ========

    >>> from diofant import Symbol, exp, log
    >>> from diofant.abc import x

    >>> singularities(1/(1 + x), x) == {-1}
    True

    >>> singularities(exp(1/x) + log(x + 1), x) == {-1, 0}
    True

    >>> singularities(exp(1/log(x + 1)), x) == {0}
    True

    Notes
    =====

    Removable singularities are not supported now.

    References
    ==========

    .. [1] http://en.wikipedia.org/wiki/Mathematical_singularity
    """
    f, x = sympify(f), sympify(x)
    guess, res = set(), set()

    assert x.is_Symbol

    if f.is_number:
        return set()
    elif f.is_polynomial(x):
        return set()
    elif f.func in (Add, Mul):
        guess = guess.union(*[singularities(a, x) for a in f.args])
    elif f.func is Pow:
        if f.exp.is_number and f.exp.is_negative:
            guess = {v for v in solve(f.base, x) if v.is_real}
        else:
            guess |= singularities(log(f.base)*f.exp, x)
    elif f.func in (log, sign) and len(f.args) == 1:
        guess |= singularities(f.args[0], x)
        guess |= {v for v in solve(f.args[0], x) if v.is_real}
    else:  # pragma: no cover
        raise NotImplementedError

    for s in guess:
        l = Limit(f, x, s, dir="real")
        try:
            r = l.doit()
            if r == l or f.subs(x, s) != r:  # pragma: no cover
                raise NotImplementedError
        except PoleError:
            res.add(s)

    return res
Esempio n. 3
0
def test_nfloat():
    x = Symbol("x")
    eq = x**Rational(4, 3) + 4*cbrt(x)/3
    assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0/3)*cbrt(x))
    assert _aresame(nfloat(eq, exponent=True), x**(4.0/3) + (4.0/3)*x**(1.0/3))
    eq = x**Rational(4, 3) + 4*x**(x/3)/3
    assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0/3)*x**(x/3))
    big = 12345678901234567890
    # specify precision to match value used in nfloat
    Float_big = Float(big, 15)
    assert _aresame(nfloat(big), Float_big)
    assert _aresame(nfloat(big*x), Float_big*x)
    assert _aresame(nfloat(x**big, exponent=True), x**Float_big)
    assert nfloat({x: sqrt(2)}) == {x: nfloat(sqrt(2))}
    assert nfloat({sqrt(2): x}) == {sqrt(2): x}
    assert nfloat(cos(x + sqrt(2))) == cos(x + nfloat(sqrt(2)))

    # issue sympy/sympy#6342
    lamda = Symbol('lamda')
    f = x*lamda + lamda**3*(x/2 + Rational(1, 2)) + lamda**2 + Rational(1, 4)
    assert not any(a[lamda].free_symbols
                   for a in solve(f.subs({x: -0.139})))

    # issue sympy/sympy#6632
    assert nfloat(-100000*sqrt(2500000001) + 5000000001) == \
        9.99999999800000e-11

    # issue sympy/sympy#7122
    eq = cos(3*x**4 + y)*RootOf(x**5 + 3*x**3 + 1, 0)
    assert str(nfloat(eq, exponent=False, n=1)) == '-0.7*cos(3.0*x**4 + y)'
Esempio n. 4
0
def test_nfloat():
    x = Symbol("x")
    eq = x**Rational(4, 3) + 4 * cbrt(x) / 3
    assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0 / 3) * cbrt(x))
    assert _aresame(nfloat(eq, exponent=True),
                    x**(4.0 / 3) + (4.0 / 3) * x**(1.0 / 3))
    eq = x**Rational(4, 3) + 4 * x**(x / 3) / 3
    assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0 / 3) * x**(x / 3))
    big = 12345678901234567890
    # specify precision to match value used in nfloat
    Float_big = Float(big, 15)
    assert _aresame(nfloat(big), Float_big)
    assert _aresame(nfloat(big * x), Float_big * x)
    assert _aresame(nfloat(x**big, exponent=True), x**Float_big)
    assert nfloat({x: sqrt(2)}) == {x: nfloat(sqrt(2))}
    assert nfloat({sqrt(2): x}) == {sqrt(2): x}
    assert nfloat(cos(x + sqrt(2))) == cos(x + nfloat(sqrt(2)))

    # issue sympy/sympy#6342
    lamda = Symbol('lamda')
    f = x * lamda + lamda**3 * (x / 2 + Rational(1, 2)) + lamda**2 + Rational(
        1, 4)
    assert not any(a[lamda].free_symbols for a in solve(f.subs({x: -0.139})))

    # issue sympy/sympy#6632
    assert nfloat(-100000*sqrt(2500000001) + 5000000001) == \
        9.99999999800000e-11

    # issue sympy/sympy#7122
    eq = cos(3 * x**4 + y) * RootOf(x**5 + 3 * x**3 + 1, 0)
    assert str(nfloat(eq, exponent=False, n=1)) == '-0.7*cos(3.0*x**4 + y)'
Esempio n. 5
0
    def arbitrary_point(self, t=None):
        """ Returns an arbitrary point on the Plane; varying `t` from 0 to 2*pi
        will move the point in a circle of radius 1 about p1 of the Plane.

        Examples
        ========

        >>> from diofant.geometry.plane import Plane
        >>> from diofant.abc import t
        >>> p = Plane((0, 0, 0), (0, 0, 1), (0, 1, 0))
        >>> p.arbitrary_point(t)
        Point3D(0, cos(t), sin(t))
        >>> _.distance(p.p1).simplify()
        1

        Returns
        =======

        Point3D

        """
        from diofant import cos, sin
        t = t or Dummy('t')
        x, y, z = self.normal_vector
        a, b, c = self.p1.args
        if x == y == 0:
            return Point3D(a + cos(t), b + sin(t), c)
        elif x == z == 0:
            return Point3D(a + cos(t), b, c + sin(t))
        elif y == z == 0:
            return Point3D(a, b + cos(t), c + sin(t))
        m = Dummy()
        p = self.projection(
            Point3D(self.p1.x + cos(t), self.p1.y + sin(t), 0) * m)
        return p.xreplace({m: solve(p.distance(self.p1) - 1, m)[0]})
Esempio n. 6
0
def minimize_univariate(f, x, dom):
    extr = {}

    if dom.is_Union:
        for d in dom.args:
            fp, r = minimize_univariate(f, x, d)
            extr[r[x]] = fp
    elif dom.is_Interval:
        if not dom.left_open:
            extr[dom.start] = limit(f, x, dom.start)
        if not dom.right_open:
            extr[dom.end] = limit(f, x, dom.end, dir="-")
        for s in singularities(f, x):
            if s in dom:
                m = Min(limit(f, x, s), limit(f, x, s, dir="-"))
                if m is -oo:
                    return -oo, dict({x: s})
                else:
                    extr[s] = m

        for p in solve(diff(f, x), x):
            if p in dom:
                extr[p] = f.subs(x, p)
    elif dom.is_FiniteSet:
        for p in dom.args:
            extr[p] = f.subs(x, p)
    else:  # pragma: no cover
        raise NotImplementedError

    if extr:
        min, point = oo, nan
        for p, fp in sorted(extr.items()):
            if fp < min:
                point, min = p, fp
        return min, dict({x: point})
Esempio n. 7
0
def _remove_multiple_delta(expr):
    """Evaluate products of KroneckerDelta's. """
    from diofant.solvers import solve
    if expr.is_Add:
        return expr.func(*list(map(_remove_multiple_delta, expr.args)))
    if not expr.is_Mul:
        return expr
    eqs = []
    newargs = []
    for arg in expr.args:
        if isinstance(arg, KroneckerDelta):
            eqs.append(arg.args[0] - arg.args[1])
        else:
            newargs.append(arg)
    if not eqs:
        return expr
    solns = solve(eqs, dict=True)
    if len(solns) == 0:
        return S.Zero
    elif len(solns) == 1:
        for key in solns[0].keys():
            newargs.append(KroneckerDelta(key, solns[0][key]))
        expr2 = expr.func(*newargs)
        if expr != expr2:
            return _remove_multiple_delta(expr2)
    return expr
Esempio n. 8
0
 def _eval_subs(self, old, new):
     if old in self.variables:
         newexpr = self.expr.subs(old, new)
         i = self.variables.index(old)
         newvars = list(self.variables)
         newpt = list(self.point)
         if new.is_Symbol:
             newvars[i] = new
         else:
             syms = new.free_symbols
             if len(syms) == 1 or old in syms:
                 if old in syms:
                     var = self.variables[i]
                 else:
                     var = syms.pop()
                 # First, try to substitute self.point in the "new"
                 # expr to see if this is a fixed point.
                 # E.g.  O(y).subs(y, sin(x))
                 point = new.subs(var, self.point[i])
                 if point != self.point[i]:
                     from diofant.solvers import solve
                     d = Dummy()
                     res = solve(old - new.subs(var, d), d, dict=True)
                     point = d.subs(res[0]).limit(old, self.point[i])
                 newvars[i] = var
                 newpt[i] = point
             elif old not in syms:
                 del newvars[i], newpt[i]
                 if not syms and new == self.point[i]:
                     newvars.extend(syms)
                     newpt.extend([S.Zero]*len(syms))
             else:
                 return
         return Order(newexpr, *zip(newvars, newpt))
Esempio n. 9
0
    def _contains(self, other):
        from diofant.solvers import solve
        L = self.lamda
        if self._is_multivariate():
            solns = solve([expr - val for val, expr in zip(other, L.expr)],
                          L.variables)
        else:
            solns = solve(L.expr - other, L.variables[0])

        for soln in solns:
            try:
                if soln in self.base_set:
                    return S.true
            except TypeError:
                if soln.evalf() in self.base_set:
                    return S.true
        return S.false
Esempio n. 10
0
    def perpendicular_segment(self, p):
        """Create a perpendicular line segment from `p` to this line.

        The enpoints of the segment are ``p`` and the closest point in
        the line containing self. (If self is not a line, the point might
        not be in self.)

        Parameters
        ==========

        p : Point3D

        Returns
        =======

        segment : Segment3D

        Notes
        =====

        Returns `p` itself if `p` is on this linear entity.

        See Also
        ========

        perpendicular_line

        Examples
        ========

        >>> from diofant import Point3D, Line3D
        >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(0, 2, 0)
        >>> l1 = Line3D(p1, p2)
        >>> s1 = l1.perpendicular_segment(p3)
        >>> l1.is_perpendicular(s1)
        True
        >>> p3 in s1
        True
        >>> l1.perpendicular_segment(Point3D(4, 0, 0))
        Segment3D(Point3D(4/3, 4/3, 4/3), Point3D(4, 0, 0))

        """
        p = Point3D(p)
        if p in self:
            raise NotImplementedError("Given point should not be on the line")
        t = Dummy()
        a = self.arbitrary_point(t)
        b = [i - j for i, j in zip(p.args, a.args)]
        c = sum(i * j for i, j in zip(b, self.direction_ratio))
        d = solve(c, t)
        e = a.subs(t, d[0])
        return Segment3D(p, e)
Esempio n. 11
0
    def _do_ellipse_intersection(self, o):
        """The intersection of an ellipse with another ellipse or a circle.

        Private helper method for `intersection`.

        """

        x = Dummy('x', extended_real=True)
        y = Dummy('y', extended_real=True)
        seq = self.equation(x, y)
        oeq = o.equation(x, y)
        result = solve([seq, oeq], [x, y])
        return [Point(*r) for r in list(uniq(result))]
Esempio n. 12
0
def _simplify_delta(expr):
    """Rewrite a KroneckerDelta's indices in its simplest form. """
    from diofant.solvers import solve
    if isinstance(expr, KroneckerDelta):
        try:
            slns = solve(expr.args[0] - expr.args[1], dict=True)
            if slns and len(slns) == 1:
                return Mul(*[
                    KroneckerDelta(*(key, value))
                    for key, value in slns[0].items()
                ])
        except NotImplementedError:
            pass
    return expr
Esempio n. 13
0
    def contains(self, o):
        """
        Return True if o is on this Line, or False otherwise.

        Examples
        ========

        >>> from diofant import Line,Point
        >>> p1, p2 = Point(0, 1), Point(3, 4)
        >>> l = Line(p1, p2)
        >>> l.contains(p1)
        True
        >>> l.contains((0, 1))
        True
        >>> l.contains((0, 0))
        False
        """
        if is_sequence(o):
            o = Point(o)
        if isinstance(o, Point):
            o = o.func(*[simplify(i) for i in o.args])
            x, y = Dummy(), Dummy()
            eq = self.equation(x, y)
            if not eq.has(y):
                return (solve(eq, x)[0] - o.x).equals(0)
            if not eq.has(x):
                return (solve(eq, y)[0] - o.y).equals(0)
            return (solve(eq.subs(x, o.x), y)[0] - o.y).equals(0)
        elif not isinstance(o, LinearEntity):
            return False
        elif isinstance(o, Line):
            return self.equal(o)
        elif not self.is_similar(o):
            return False
        else:
            return o.p1 in self and o.p2 in self
Esempio n. 14
0
def minimize(f, *v):
    """Minimizes `f` with respect to given variables `v`.

    Examples
    ========

    >>> from diofant.calculus import minimize
    >>> from diofant.abc import x
    >>> minimize(x**2, x)
    (0, {x: 0})

    >>> minimize([x**2, x >= 1], x)
    (1, {x: 1})
    >>> minimize([-x**2, x >= -2, x <= 1], x)
    (-4, {x: -2})

    See Also
    ========

    maximize
    """
    f = set(map(sympify, f if is_sequence(f) else [f]))

    constr = {c for c in f if c.is_Relational}

    assert len(f - constr) == 1

    f = (f - constr).pop()

    if not v:
        v = f.free_symbols
        if not v:
            return f, dict()
        v = tuple(v)

    assert all(x.is_Symbol for x in v)

    if constr:
        dom = solve(constr, *v).as_set()
    else:
        dom = Interval(-oo, oo, True, True)**len(v)

    if len(v) == 1:
        return minimize_univariate(f, v[0], dom)
    else:  # pragma: no cover
        return NotImplementedError
Esempio n. 15
0
def telescopic(L, R, limits):
    '''Tries to perform the summation using the telescopic property

    return None if not possible
    '''
    (i, a, b) = limits
    if L.is_Add or R.is_Add:
        return

    # We want to solve(L.subs(i, i + m) + R, m)
    # First we try a simple match since this does things that
    # solve doesn't do, e.g. solve(f(k+m)-f(k), m) fails

    k = Wild("k")
    sol = (-R).match(L.subs(i, i + k))
    s = None
    if sol and k in sol:
        s = sol[k]
        if not (s.is_Integer and L.subs(i, i + s) == -R):
            # sometimes match fail(f(x+2).match(-f(x+k))->{k: -2 - 2x}))
            s = None

    # But there are things that match doesn't do that solve
    # can do, e.g. determine that 1/(x + m) = 1/(1 - x) when m = 1

    if s is None:
        m = Dummy('m')
        try:
            sol = solve(L.subs(i, i + m) + R, m) or []
        except NotImplementedError:
            return
        sol = [
            si for si in sol
            if si.is_Integer and (L.subs(i, i + si) + R).expand().is_zero
        ]
        if len(sol) != 1:
            return
        s = sol[0]

    if s < 0:
        return telescopic_direct(R, L, abs(s), (i, a, b))
    elif s > 0:
        return telescopic_direct(L, R, s, (i, a, b))
Esempio n. 16
0
    def perpendicular_line(self, p):
        """Create a new Line perpendicular to this linear entity which passes
        through the point `p`.

        Parameters
        ==========

        p : Point3D

        Returns
        =======

        line : Line3D

        See Also
        ========

        is_perpendicular, perpendicular_segment

        Examples
        ========

        >>> from diofant import Point3D, Line3D
        >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(2, 3, 4), Point3D(-2, 2, 0)
        >>> l1 = Line3D(p1, p2)
        >>> l2 = l1.perpendicular_line(p3)
        >>> p3 in l2
        True
        >>> l1.is_perpendicular(l2)
        True

        """
        p = Point3D(p)
        if p in self:
            raise NotImplementedError("Given point should not be on the line")
        t = Dummy()
        a = self.arbitrary_point(t)
        b = [i - j for i, j in zip(p.args, a.args)]
        c = sum(i * j for i, j in zip(b, self.direction_ratio))
        d = solve(c, t)
        e = a.subs(t, d[0])
        return Line3D(p, e)
Esempio n. 17
0
def _nthroot_solve(p, n, prec):
    """
     helper function for ``nthroot``
     It denests ``p**Rational(1, n)`` using its minimal polynomial
    """
    from diofant.polys.numberfields import _minimal_polynomial_sq
    from diofant.solvers import solve
    while n % 2 == 0:
        p = sqrtdenest(sqrt(p))
        n = n // 2
    if n == 1:
        return p
    pn = p**Rational(1, n)
    x = Symbol('x')
    f = _minimal_polynomial_sq(p, n, x)
    if f is None:
        return
    sols = solve(f, x)
    for sol in sols:
        if abs(sol - pn).n() < 1. / 10**prec:
            sol = sqrtdenest(sol)
            if _mexpand(sol**n) == p:
                return sol
Esempio n. 18
0
def apart_undetermined_coeffs(P, Q):
    """Partial fractions via method of undetermined coefficients. """
    X = numbered_symbols(cls=Dummy)
    partial, symbols = [], []

    _, factors = Q.factor_list()

    for f, k in factors:
        n, q = f.degree(), Q

        for i in range(1, k + 1):
            coeffs, q = take(X, n), q.quo(f)
            partial.append((coeffs, q, f, i))
            symbols.extend(coeffs)

    dom = Q.get_domain().inject(*symbols)
    F = Poly(0, Q.gen, domain=dom)

    for i, (coeffs, q, f, k) in enumerate(partial):
        h = Poly(coeffs, Q.gen, domain=dom)
        partial[i] = (h, f, k)
        q = q.set_domain(dom)
        F += h * q

    system, result = [], Integer(0)

    for (k, ), coeff in F.terms():
        system.append(coeff - P.nth(k))

    from diofant.solvers import solve
    solution = solve(system, symbols)

    for h, f, k in partial:
        h = h.as_expr().subs(solution)
        result += h / f.as_expr()**k

    return result
Esempio n. 19
0
def deltasummation(f, limit, no_piecewise=False):
    """Handle summations containing a KroneckerDelta.

    The idea for summation is the following:

    - If we are dealing with a KroneckerDelta expression, i.e. KroneckerDelta(g(x), j),
      we try to simplify it.

      If we could simplify it, then we sum the resulting expression.
      We already know we can sum a simplified expression, because only
      simple KroneckerDelta expressions are involved.

      If we couldn't simplify it, there are two cases:

      1) The expression is a simple expression: we return the summation,
         taking care if we are dealing with a Derivative or with a proper
         KroneckerDelta.

      2) The expression is not simple (i.e. KroneckerDelta(cos(x))): we can do
         nothing at all.

    - If the expr is a multiplication expr having a KroneckerDelta term:

      First we expand it.

      If the expansion did work, then we try to sum the expansion.

      If not, we try to extract a simple KroneckerDelta term, then we have two
      cases:

      1) We have a simple KroneckerDelta term, so we return the summation.

      2) We didn't have a simple term, but we do have an expression with
         simplified KroneckerDelta terms, so we sum this expression.

    Examples
    ========

    >>> from diofant import oo, symbols
    >>> from diofant.abc import k
    >>> i, j = symbols('i, j', integer=True, finite=True)
    >>> from diofant import KroneckerDelta, Piecewise
    >>> deltasummation(KroneckerDelta(i, k), (k, -oo, oo))
    1
    >>> deltasummation(KroneckerDelta(i, k), (k, 0, oo))
    Piecewise((1, 0 <= i), (0, true))
    >>> deltasummation(KroneckerDelta(i, k), (k, 1, 3))
    Piecewise((1, And(1 <= i, i <= 3)), (0, true))
    >>> deltasummation(k*KroneckerDelta(i, j)*KroneckerDelta(j, k), (k, -oo, oo))
    j*KroneckerDelta(i, j)
    >>> deltasummation(j*KroneckerDelta(i, j), (j, -oo, oo))
    i
    >>> deltasummation(i*KroneckerDelta(i, j), (i, -oo, oo))
    j

    See Also
    ========

    deltaproduct
    diofant.functions.special.tensor_functions.KroneckerDelta
    diofant.concrete.sums.summation
    """
    from diofant.concrete.summations import summation
    from diofant.solvers import solve

    if ((limit[2] - limit[1]) < 0) is S.true:
        return S.Zero

    if not f.has(KroneckerDelta):
        return summation(f, limit)

    x = limit[0]

    g = _expand_delta(f, x)
    if g.is_Add:
        return piecewise_fold(
            g.func(*[deltasummation(h, limit, no_piecewise) for h in g.args]))

    # try to extract a simple KroneckerDelta term
    delta, expr = _extract_delta(g, x)

    if not delta:
        return summation(f, limit)

    solns = solve(delta.args[0] - delta.args[1], x)
    if len(solns) == 0:
        return S.Zero
    elif len(solns) != 1:
        return Sum(f, limit)
    value = solns[0]
    if no_piecewise:
        return expr.subs(x, value)
    return Piecewise(
        (expr.subs(x, value), Interval(*limit[1:3]).as_relational(value)),
        (S.Zero, True))
Esempio n. 20
0
def parametric_log_deriv_heu(fa, fd, wa, wd, DE, c1=None):
    """
    Parametric logarithmic derivative heuristic.

    Given a derivation D on k[t], f in k(t), and a hyperexponential monomial
    theta over k(t), raises either NotImplementedError, in which case the
    heuristic failed, or returns None, in which case it has proven that no
    solution exists, or returns a solution (n, m, v) of the equation
    n*f == Dv/v + m*Dtheta/theta, with v in k(t)* and n, m in ZZ with n != 0.

    If this heuristic fails, the structure theorem approach will need to be
    used.

    The argument w == Dtheta/theta
    """
    # TODO: finish writing this and write tests
    c1 = c1 or Dummy('c1')

    p, a = fa.div(fd)
    q, b = wa.div(wd)

    B = max(0, derivation(DE.t, DE).degree(DE.t) - 1)
    C = max(p.degree(DE.t), q.degree(DE.t))

    if q.degree(DE.t) > B:
        eqs = [p.nth(i) - c1*q.nth(i) for i in range(B + 1, C + 1)]
        s = solve(eqs, c1)
        if not s or not s[c1].is_Rational:
            # deg(q) > B, no solution for c.
            return

        N, M = s[c1].as_numer_denom()  # N and M are integers
        N, M = Poly(N, DE.t), Poly(M, DE.t)

        nfmwa = N*fa*wd - M*wa*fd
        nfmwd = fd*wd
        Qv = is_log_deriv_k_t_radical_in_field(N*fa*wd - M*wa*fd, fd*wd, DE,
            'auto')
        if Qv is None:
            # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical.
            return

        Q, e, v = Qv
        if e != 1:
            return

        if Q.is_zero or v.is_zero:
            return

        return Q*N, Q*M, v

    if p.degree(DE.t) > B:
        return

    c = lcm(fd.as_poly(DE.t).LC(), wd.as_poly(DE.t).LC())
    l = fd.monic().lcm(wd.monic())*Poly(c, DE.t)
    ln, ls = splitfactor(l, DE)
    z = ls*ln.gcd(ln.diff(DE.t))

    if not z.has(DE.t):
        raise NotImplementedError("parametric_log_deriv_heu() "
            "heuristic failed: z in k.")

    u1, r1 = (fa*l.quo(fd)).div(z)  # (l*f).div(z)
    u2, r2 = (wa*l.quo(wd)).div(z)  # (l*w).div(z)

    eqs = [r1.nth(i) - c1*r2.nth(i) for i in range(z.degree(DE.t))]
    s = solve(eqs, c1)
    if not s or not s[c1].is_Rational:
        # deg(q) <= B, no solution for c.
        return

    M, N = s[c1].as_numer_denom()

    nfmwa = N.as_poly(DE.t)*fa*wd - M.as_poly(DE.t)*wa*fd
    nfmwd = fd*wd
    Qv = is_log_deriv_k_t_radical_in_field(nfmwa, nfmwd, DE)
    if Qv is None:
        # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical.
        return

    Q, v = Qv

    if Q.is_zero or v.is_zero:
        return

    return Q*N, Q*M, v
Esempio n. 21
0
    def tangent_lines(self, p):
        """Tangent lines between `p` and the ellipse.

        If `p` is on the ellipse, returns the tangent line through point `p`.
        Otherwise, returns the tangent line(s) from `p` to the ellipse, or
        None if no tangent line is possible (e.g., `p` inside ellipse).

        Parameters
        ==========

        p : Point

        Returns
        =======

        tangent_lines : list with 1 or 2 Lines

        Raises
        ======

        NotImplementedError
            Can only find tangent lines for a point, `p`, on the ellipse.

        See Also
        ========

        diofant.geometry.point.Point, diofant.geometry.line.Line

        Examples
        ========

        >>> from diofant import Point, Ellipse
        >>> e1 = Ellipse(Point(0, 0), 3, 2)
        >>> e1.tangent_lines(Point(3, 0))
        [Line(Point2D(3, 0), Point2D(3, -12))]
        """
        p = Point(p)
        if self.encloses_point(p):
            return []

        if p in self:
            delta = self.center - p
            rise = (self.vradius**2) * delta.x
            run = -(self.hradius**2) * delta.y
            p2 = Point(simplify(p.x + run), simplify(p.y + rise))
            return [Line(p, p2)]
        else:
            if len(self.foci) == 2:
                f1, f2 = self.foci
                maj = self.hradius
                test = (2 * maj - Point.distance(f1, p) -
                        Point.distance(f2, p))
            else:
                test = self.radius - Point.distance(self.center, p)
            if test.is_number and test.is_positive:
                return []
            # else p is outside the ellipse or we can't tell. In case of the
            # latter, the solutions returned will only be valid if
            # the point is not inside the ellipse; if it is, nan will result.
            x, y = Dummy('x'), Dummy('y')
            eq = self.equation(x, y)
            dydx = idiff(eq, y, x)
            slope = Line(p, Point(x, y)).slope
            tangent_points = solve([slope - dydx, eq], [x, y])

            # handle horizontal and vertical tangent lines
            if len(tangent_points) == 1:
                assert tangent_points[0][0] == p.x or tangent_points[0][
                    1] == p.y
                return [Line(p, p + Point(1, 0)), Line(p, p + Point(0, 1))]

            # others
            return [Line(p, tangent_points[0]), Line(p, tangent_points[1])]
Esempio n. 22
0
    def normal_lines(self, p, prec=None):
        """Normal lines between `p` and the ellipse.

        Parameters
        ==========

        p : Point

        Returns
        =======

        normal_lines : list with 1, 2 or 4 Lines

        Examples
        ========

        >>> from diofant import Line, Point, Ellipse
        >>> e = Ellipse((0, 0), 2, 3)
        >>> c = e.center
        >>> e.normal_lines(c + Point(1, 0))
        [Line(Point2D(0, 0), Point2D(1, 0))]
        >>> e.normal_lines(c)
        [Line(Point2D(0, 0), Point2D(0, 1)), Line(Point2D(0, 0), Point2D(1, 0))]

        Off-axis points require the solution of a quartic equation. This
        often leads to very large expressions that may be of little practical
        use. An approximate solution of `prec` digits can be obtained by
        passing in the desired value:

        >>> e.normal_lines((3, 3), prec=2)
        [Line(Point2D(-38/47, -85/31), Point2D(9/47, -21/17)),
        Line(Point2D(19/13, -43/21), Point2D(32/13, -8/3))]

        Whereas the above solution has an operation count of 12, the exact
        solution has an operation count of 2020.
        """
        p = Point(p)

        # XXX change True to something like self.angle == 0 if the arbitrarily
        # rotated ellipse is introduced.
        # https://github.com/sympy/sympy/issues/2815)
        if True:
            rv = []
            if p.x == self.center.x:
                rv.append(Line(self.center, slope=oo))
            if p.y == self.center.y:
                rv.append(Line(self.center, slope=0))
            if rv:
                # at these special orientations of p either 1 or 2 normals
                # exist and we are done
                return rv

        # find the 4 normal points and construct lines through them with
        # the corresponding slope
        x, y = Dummy('x', extended_real=True), Dummy('y', extended_real=True)
        eq = self.equation(x, y)
        dydx = idiff(eq, y, x)
        norm = -1 / dydx
        slope = Line(p, (x, y)).slope
        seq = slope - norm
        yis = solve(seq, y)[0]
        xeq = eq.subs(y, yis).as_numer_denom()[0].expand()
        if len(xeq.free_symbols) == 1:
            try:
                # this is so much faster, it's worth a try
                xsol = Poly(xeq, x).real_roots()
            except (DomainError, PolynomialError, NotImplementedError):
                xsol = _nsort(solve(xeq, x), separated=True)[0]
            points = [Point(i, solve(eq.subs(x, i), y)[0]) for i in xsol]
        else:
            raise NotImplementedError(
                'intersections for the general ellipse are not supported')
        slopes = [norm.subs(zip((x, y), pt.args)) for pt in points]
        if prec is not None:
            points = [pt.n(prec) for pt in points]
            slopes = [i if _not_a_coeff(i) else i.n(prec) for i in slopes]
        return [Line(pt, slope=s) for pt, s in zip(points, slopes)]
Esempio n. 23
0
    def intersection(self, o):
        """ The intersection with other geometrical entity.

        Parameters
        ==========

        Point, Point3D, LinearEntity, LinearEntity3D, Plane

        Returns
        =======

        List

        Examples
        ========

        >>> from diofant import Point, Point3D, Line, Line3D, Plane
        >>> a = Plane(Point3D(1, 2, 3), normal_vector=(1, 1, 1))
        >>> b = Point3D(1, 2, 3)
        >>> a.intersection(b)
        [Point3D(1, 2, 3)]
        >>> c = Line3D(Point3D(1, 4, 7), Point3D(2, 2, 2))
        >>> a.intersection(c)
        [Point3D(2, 2, 2)]
        >>> d = Plane(Point3D(6, 0, 0), normal_vector=(2, -5, 3))
        >>> e = Plane(Point3D(2, 0, 0), normal_vector=(3, 4, -3))
        >>> d.intersection(e)
        [Line3D(Point3D(78/23, -24/23, 0), Point3D(147/23, 321/23, 23))]

        """
        from diofant.geometry.line3d import LinearEntity3D
        from diofant.geometry.line import LinearEntity
        if isinstance(o, (Point, Point3D)):
            if o in self:
                return [Point3D(o)]
            else:
                return []
        if isinstance(o, (LinearEntity, LinearEntity3D)):
            if o in self:
                p1, p2 = o.p1, o.p2
                if isinstance(o, Segment):
                    o = Segment3D(p1, p2)
                elif isinstance(o, Ray):
                    o = Ray3D(p1, p2)
                elif isinstance(o, Line):
                    o = Line3D(p1, p2)
                else:
                    raise ValueError('unhandled linear entity: %s' % o.func)
                return [o]
            else:
                x, y, z = map(Dummy, 'xyz')
                t = Dummy()  # unnamed else it may clash with a symbol in o
                a = Point3D(o.arbitrary_point(t))
                b = self.equation(x, y, z)
                c = solve(b.subs(list(zip((x, y, z), a.args))), t)
                if not c:
                    return []
                else:
                    p = a.subs(t, c[0])
                    if p not in self:
                        return []  # e.g. a segment might not intersect a plane
                    return [p]
        if isinstance(o, Plane):
            if o == self:
                return [self]
            if self.is_parallel(o):
                return []
            else:
                x, y, z = map(Dummy, 'xyz')
                a, b = Matrix([self.normal_vector]), Matrix([o.normal_vector])
                c = list(a.cross(b))
                d = self.equation(x, y, z)
                e = o.equation(x, y, z)
                f = solve((d.subs(z, 0), e.subs(z, 0)), [x, y])
                if len(f) == 2:
                    return [Line3D(Point3D(f[x], f[y], 0), direction_ratio=c)]
                g = solve((d.subs(y, 0), e.subs(y, 0)), [x, z])
                if len(g) == 2:
                    return [Line3D(Point3D(g[x], 0, g[z]), direction_ratio=c)]
                h = solve((d.subs(x, 0), e.subs(x, 0)), [y, z])
                if len(h) == 2:
                    return [Line3D(Point3D(0, h[y], h[z]), direction_ratio=c)]
Esempio n. 24
0
def deltaintegrate(f, x):
    """
    deltaintegrate(f, x)

    The idea for integration is the following:

    - If we are dealing with a DiracDelta expression, i.e. DiracDelta(g(x)),
      we try to simplify it.

      If we could simplify it, then we integrate the resulting expression.
      We already know we can integrate a simplified expression, because only
      simple DiracDelta expressions are involved.

      If we couldn't simplify it, there are two cases:

      1) The expression is a simple expression: we return the integral,
         taking care if we are dealing with a Derivative or with a proper
         DiracDelta.

      2) The expression is not simple (i.e. DiracDelta(cos(x))): we can do
         nothing at all.

    - If the node is a multiplication node having a DiracDelta term:

      First we expand it.

      If the expansion did work, the we try to integrate the expansion.

      If not, we try to extract a simple DiracDelta term, then we have two
      cases:

      1) We have a simple DiracDelta term, so we return the integral.

      2) We didn't have a simple term, but we do have an expression with
         simplified DiracDelta terms, so we integrate this expression.

    Examples
    ========

        >>> from diofant.abc import x, y, z
        >>> from diofant.integrals.deltafunctions import deltaintegrate
        >>> from diofant import sin, cos, DiracDelta, Heaviside
        >>> deltaintegrate(x*sin(x)*cos(x)*DiracDelta(x - 1), x)
        sin(1)*cos(1)*Heaviside(x - 1)
        >>> deltaintegrate(y**2*DiracDelta(x - z)*DiracDelta(y - z), y)
        z**2*DiracDelta(x - z)*Heaviside(y - z)

    See Also
    ========

    diofant.functions.special.delta_functions.DiracDelta
    diofant.integrals.integrals.Integral
    """
    if not f.has(DiracDelta):
        return

    from diofant.integrals import Integral, integrate
    from diofant.solvers import solve

    # g(x) = DiracDelta(h(x))
    if f.func == DiracDelta:
        h = f.simplify(x)
        if h == f:  # can't simplify the expression
            # FIXME: the second term tells whether is DeltaDirac or Derivative
            # For integrating derivatives of DiracDelta we need the chain rule
            if f.is_simple(x):
                if (len(f.args) <= 1 or f.args[1] == 0):
                    return Heaviside(f.args[0])
                else:
                    return (DiracDelta(f.args[0], f.args[1] - 1) /
                            f.args[0].as_poly().LC())
        else:  # let's try to integrate the simplified expression
            fh = integrate(h, x)
            return fh
    elif f.is_Mul or f.is_Pow:  # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e
        g = f.expand()
        if f != g:  # the expansion worked
            fh = integrate(g, x)
            if fh is not None and not isinstance(fh, Integral):
                return fh
        else:
            # no expansion performed, try to extract a simple DiracDelta term
            dg, rest_mult = change_mul(f, x)

            if not dg:
                if rest_mult:
                    fh = integrate(rest_mult, x)
                    return fh
            else:
                dg = dg.simplify(x)
                if dg.is_Mul:  # Take out any extracted factors
                    dg, rest_mult_2 = change_mul(dg, x)
                    rest_mult = rest_mult * rest_mult_2
                point = solve(dg.args[0], x)[0]
                return (rest_mult.subs(x, point) * Heaviside(x - point))
    return
Esempio n. 25
0
def continued_fraction_reduce(cf):
    """Reduce a continued fraction to a rational or quadratic irrational.

    Compute the rational or quadratic irrational number from its
    terminating or periodic continued fraction expansion.  The
    continued fraction expansion (cf) should be supplied as a
    terminating iterator supplying the terms of the expansion.  For
    terminating continued fractions, this is equivalent to
    ``list(continued_fraction_convergents(cf))[-1]``, only a little more
    efficient.  If the expansion has a repeating part, a list of the
    repeating terms should be returned as the last element from the
    iterator.  This is the format returned by
    continued_fraction_periodic.

    For quadratic irrationals, returns the largest solution found,
    which is generally the one sought, if the fraction is in canonical
    form (all terms positive except possibly the first).

    Examples
    ========

    >>> from diofant.ntheory.continued_fraction import continued_fraction_reduce
    >>> continued_fraction_reduce([1, 2, 3, 4, 5])
    225/157
    >>> continued_fraction_reduce([-2, 1, 9, 7, 1, 2])
    -256/233
    >>> continued_fraction_reduce([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8]).n(10)
    2.718281835
    >>> continued_fraction_reduce([1, 4, 2, [3, 1]])
    (sqrt(21) + 287)/238
    >>> continued_fraction_reduce([[1]])
    1/2 + sqrt(5)/2
    >>> from diofant.ntheory.continued_fraction import continued_fraction_periodic
    >>> continued_fraction_reduce(continued_fraction_periodic(8, 5, 13))
    (sqrt(13) + 8)/5

    See Also
    ========

    continued_fraction_periodic
    """
    from diofant.core.symbol import Dummy
    from diofant.solvers import solve

    period = []
    x = Dummy('x')

    def untillist(cf):
        for nxt in cf:
            if isinstance(nxt, list):
                period.extend(nxt)
                yield x
                break
            yield nxt

    a = Integer(0)
    for a in continued_fraction_convergents(untillist(cf)):
        pass

    if period:
        y = Dummy('y')
        solns = solve(continued_fraction_reduce(period + [y]) - y, y)
        solns.sort()
        pure = solns[-1]
        return a.subs(x, pure).radsimp()
    else:
        return a
Esempio n. 26
0
def rsolve_poly(coeffs, f, n, **hints):
    """
    Given linear recurrence operator `\operatorname{L}` of order
    `k` with polynomial coefficients and inhomogeneous equation
    `\operatorname{L} y = f`, where `f` is a polynomial, we seek for
    all polynomial solutions over field `K` of characteristic zero.

    The algorithm performs two basic steps:

        (1) Compute degree `N` of the general polynomial solution.
        (2) Find all polynomials of degree `N` or less
            of `\operatorname{L} y = f`.

    There are two methods for computing the polynomial solutions.
    If the degree bound is relatively small, i.e. it's smaller than
    or equal to the order of the recurrence, then naive method of
    undetermined coefficients is being used. This gives system
    of algebraic equations with `N+1` unknowns.

    In the other case, the algorithm performs transformation of the
    initial equation to an equivalent one, for which the system of
    algebraic equations has only `r` indeterminates. This method is
    quite sophisticated (in comparison with the naive one) and was
    invented together by Abramov, Bronstein and Petkovšek.

    It is possible to generalize the algorithm implemented here to
    the case of linear q-difference and differential equations.

    Lets say that we would like to compute `m`-th Bernoulli polynomial
    up to a constant. For this we can use `b(n+1) - b(n) = m n^{m-1}`
    recurrence, which has solution `b(n) = B_m + C`. For example:

    >>> from diofant import Symbol, rsolve_poly
    >>> n = Symbol('n', integer=True)

    >>> rsolve_poly([-1, 1], 4*n**3, n)
    C0 + n**4 - 2*n**3 + n**2

    References
    ==========

    .. [1] S. A. Abramov, M. Bronstein and M. Petkovšek, On polynomial
           solutions of linear operator equations, in: T. Levelt, ed.,
           Proc. ISSAC '95, ACM Press, New York, 1995, 290-296.

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

    .. [3] M. Petkovšek, H. S. Wilf, D. Zeilberger, A = B, 1996.

    """
    f = sympify(f)

    if not f.is_polynomial(n):
        return

    homogeneous = f.is_zero

    r = len(coeffs) - 1

    coeffs = [Poly(coeff, n) for coeff in coeffs]

    g = gcd_list(coeffs + [f], n, polys=True)
    if not g.is_ground:
        coeffs = [quo(c, g, n, polys=False) for c in coeffs]
        f = quo(f, g, n, polys=False)

    polys = [Poly(0, n)] * (r + 1)
    terms = [(S.Zero, S.NegativeInfinity)] * (r + 1)

    for i in range(0, r + 1):
        for j in range(i, r + 1):
            polys[i] += coeffs[j] * binomial(j, i)

        if not polys[i].is_zero:
            (exp, ), coeff = polys[i].LT()
            terms[i] = (coeff, exp)

    d = b = terms[0][1]

    for i in range(1, r + 1):
        if terms[i][1] > d:
            d = terms[i][1]

        if terms[i][1] - i > b:
            b = terms[i][1] - i

    d, b = int(d), int(b)

    x = Dummy('x')

    degree_poly = S.Zero

    for i in range(0, r + 1):
        if terms[i][1] - i == b:
            degree_poly += terms[i][0] * FallingFactorial(x, i)

    nni_roots = list(
        roots(degree_poly, x, filter='Z', predicate=lambda r: r >= 0).keys())

    if nni_roots:
        N = [max(nni_roots)]
    else:
        N = []

    if homogeneous:
        N += [-b - 1]
    else:
        N += [f.as_poly(n).degree() - b, -b - 1]

    N = int(max(N))

    if N < 0:
        if homogeneous:
            if hints.get('symbols', False):
                return S.Zero, []
            else:
                return S.Zero
        else:
            return

    if N <= r:
        C = []
        y = E = S.Zero

        for i in range(0, N + 1):
            C.append(Symbol('C' + str(i)))
            y += C[i] * n**i

        for i in range(0, r + 1):
            E += coeffs[i].as_expr() * y.subs(n, n + i)

        solutions = solve_undetermined_coeffs(E - f, C, n)

        if solutions is not None:
            C = [c for c in C if (c not in solutions)]
            result = y.subs(solutions)
        else:
            return  # TBD
    else:
        A = r
        U = N + A + b + 1

        nni_roots = list(
            roots(polys[r], filter='Z', predicate=lambda r: r >= 0).keys())

        if nni_roots != []:
            a = max(nni_roots) + 1
        else:
            a = S.Zero

        def _zero_vector(k):
            return [S.Zero] * k

        def _one_vector(k):
            return [S.One] * k

        def _delta(p, k):
            B = S.One
            D = p.subs(n, a + k)

            for i in range(1, k + 1):
                B *= -Rational(k - i + 1, i)
                D += B * p.subs(n, a + k - i)

            return D

        alpha = {}

        for i in range(-A, d + 1):
            I = _one_vector(d + 1)

            for k in range(1, d + 1):
                I[k] = I[k - 1] * (x + i - k + 1) / k

            alpha[i] = S.Zero

            for j in range(0, A + 1):
                for k in range(0, d + 1):
                    B = binomial(k, i + j)
                    D = _delta(polys[j].as_expr(), k)

                    alpha[i] += I[k] * B * D

        V = Matrix(U, A, lambda i, j: int(i == j))

        if homogeneous:
            for i in range(A, U):
                v = _zero_vector(A)

                for k in range(1, A + b + 1):
                    if i - k < 0:
                        break

                    B = alpha[k - A].subs(x, i - k)

                    for j in range(0, A):
                        v[j] += B * V[i - k, j]

                denom = alpha[-A].subs(x, i)

                for j in range(0, A):
                    V[i, j] = -v[j] / denom
        else:
            G = _zero_vector(U)

            for i in range(A, U):
                v = _zero_vector(A)
                g = S.Zero

                for k in range(1, A + b + 1):
                    if i - k < 0:
                        break

                    B = alpha[k - A].subs(x, i - k)

                    for j in range(0, A):
                        v[j] += B * V[i - k, j]

                    g += B * G[i - k]

                denom = alpha[-A].subs(x, i)

                for j in range(0, A):
                    V[i, j] = -v[j] / denom

                G[i] = (_delta(f, i - A) - g) / denom

        P, Q = _one_vector(U), _zero_vector(A)

        for i in range(1, U):
            P[i] = (P[i - 1] * (n - a - i + 1) / i).expand()

        for i in range(0, A):
            Q[i] = Add(*[(v * p).expand() for v, p in zip(V[:, i], P)])

        if not homogeneous:
            h = Add(*[(g * p).expand() for g, p in zip(G, P)])

        C = [Symbol('C' + str(i)) for i in range(0, A)]

        def g(i):
            return Add(*[c * _delta(q, i) for c, q in zip(C, Q)])

        if homogeneous:
            E = [g(i) for i in range(N + 1, U)]
        else:
            E = [g(i) + _delta(h, i) for i in range(N + 1, U)]

        if E != []:
            solutions = solve(E, *C)

            if not solutions:
                if homogeneous:
                    if hints.get('symbols', False):
                        return S.Zero, []
                    else:
                        return S.Zero
                else:
                    return
        else:
            solutions = {}

        if homogeneous:
            result = S.Zero
        else:
            result = h

        for c, q in list(zip(C, Q)):
            if c in solutions:
                s = solutions[c] * q
                C.remove(c)
            else:
                s = c * q

            result += s.expand()

    if hints.get('symbols', False):
        return result, C
    else:
        return result
Esempio n. 27
0
    def findrecur(self, F=Function('F'), n=None):
        """Find a recurrence formula for the summand of the sum.

        Given a sum `f(n) = \sum_k F(n, k)`, where `F(n, k)` is
        doubly hypergeometric (that's, both `F(n + 1, k)/F(n, k)`
        and `F(n, k + 1)/F(n, k)` are rational functions of `n` and `k`),
        we find a recurrence for the summand `F(n, k)` of the form

            .. math:: \sum_{i=0}^I\sum_{j=0}^J a_{i,j}F(n - j, k - i) = 0

        Examples
        ========

        >>> from diofant import symbols, factorial, oo

        >>> n, k = symbols('n, k', integer=True)
        >>> s = Sum(factorial(n)/(factorial(k)*factorial(n - k)), (k, 0, oo))
        >>> s.findrecur()
        -F(n, k) + F(n - 1, k) + F(n - 1, k - 1)

        Notes
        =====

        We use Sister Celine's algorithm, see [1]_.

        References
        ==========

        .. [1] M. Petkovšek, H. S. Wilf, D. Zeilberger, A = B, 1996, Ch. 4.
        """
        from diofant import expand_func, gamma, factor, Mul
        from diofant.polys import together
        from diofant.simplify import collect

        if len(self.variables) > 1:
            raise ValueError
        else:
            if self.limits[0][1:] != (S.Zero, S.Infinity):
                raise ValueError
            k = self.variables[0]

        if not n:
            try:
                n = (self.function.free_symbols - {k}).pop()
            except KeyError:
                raise ValueError

        a = Function('a')

        def f(i, j):
            return self.function.subs([(n, i), (k, j)])

        I, J, step = 0, 1, 1
        y, x, sols = S.Zero, [], {}

        while not any(v for a, v in sols.items()):
            if step % 2 != 0:
                dy = sum(a(I, j) * f(n - j, k - I) / f(n, k) for j in range(J))
                dx = [a(I, j) for j in range(J)]
                I += 1
            else:
                dy = sum(a(i, J) * f(n - J, k - i) / f(n, k) for i in range(I))
                dx = [a(i, J) for i in range(I)]
                J += 1
            step += 1
            y += expand_func(dy.rewrite(gamma))
            x += dx

            t = together(y)
            numer = t.as_numer_denom()[0]
            numer = Mul(
                *[t for t in factor(numer).as_coeff_mul()[1] if t.has(a)])

            if not numer.is_rational_function(n, k):
                raise ValueError()

            z = collect(numer, k)
            eq = z.as_poly(k).all_coeffs()
            sols = dict(solve(eq, *x))

        y = sum(a(i, j) * F(n - j, k - i) for i in range(I) for j in range(J))
        y = y.subs(sols).subs(map(lambda a: (a, 1), x))

        return y if y else None
Esempio n. 28
0
    def intersection(self, o):
        """The intersection with another geometrical entity.

        Parameters
        ==========

        o : Point or LinearEntity3D

        Returns
        =======

        intersection : list of geometrical entities

        See Also
        ========

        diofant.geometry.point.Point3D

        Examples
        ========

        >>> from diofant import Point3D, Line3D, Segment3D
        >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(7, 7, 7)
        >>> l1 = Line3D(p1, p2)
        >>> l1.intersection(p3)
        [Point3D(7, 7, 7)]

        >>> l1 = Line3D(Point3D(4,19,12), Point3D(5,25,17))
        >>> l2 = Line3D(Point3D(-3, -15, -19), direction_ratio=[2,8,8])
        >>> l1.intersection(l2)
        [Point3D(1, 1, -3)]

        >>> p6, p7 = Point3D(0, 5, 2), Point3D(2, 6, 3)
        >>> s1 = Segment3D(p6, p7)
        >>> l1.intersection(s1)
        []

        """
        if isinstance(o, Point3D):
            if o in self:
                return [o]
            else:
                return []

        elif isinstance(o, LinearEntity3D):
            if self == o:
                return [self]
            elif self.is_parallel(o):
                if isinstance(self, Line3D):
                    if o.p1 in self:
                        return [o]
                    return []
                elif isinstance(self, Ray3D):
                    if isinstance(o, Ray3D):
                        # case 1, rays in the same direction
                        if self.xdirection == o.xdirection and \
                                self.ydirection == o.ydirection and \
                                self.zdirection == o.zdirection:
                            return [self] if (self.source in o) else [o]
                        # case 2, rays in the opposite directions
                        else:
                            if o.source in self:
                                if self.source == o.source:
                                    return [self.source]
                                return [Segment3D(o.source, self.source)]
                            return []
                    elif isinstance(o, Segment3D):
                        if o.p1 in self:
                            if o.p2 in self:
                                return [o]
                            return [Segment3D(o.p1, self.source)]
                        elif o.p2 in self:
                            return [Segment3D(o.p2, self.source)]
                        return []
                elif isinstance(self, Segment3D):
                    if isinstance(o, Segment3D):
                        # A reminder that the points of Segments are ordered
                        # in such a way that the following works. See
                        # Segment3D.__new__ for details on the ordering.
                        if self.p1 not in o:
                            if self.p2 not in o:
                                # Neither of the endpoints are in o so either
                                # o is contained in this segment or it isn't
                                if o in self:
                                    return [o]
                                return []
                            else:
                                # p1 not in o but p2 is. Either there is a
                                # segment as an intersection, or they only
                                # intersect at an endpoint
                                if self.p2 == o.p1:
                                    return [o.p1]
                                return [Segment3D(o.p1, self.p2)]
                        elif self.p2 not in o:
                            # p2 not in o but p1 is. Either there is a
                            # segment as an intersection, or they only
                            # intersect at an endpoint
                            if self.p1 == o.p2:
                                return [o.p2]
                            return [Segment3D(o.p2, self.p1)]

                        # Both points of self in o so the whole segment
                        # is in o
                        return [self]

                else:  # unrecognized LinearEntity
                    raise NotImplementedError

            else:
                # If the lines are not parallel then solve their arbitrary points
                # to obtain the point of intersection
                t = t1, t2 = Dummy(), Dummy()
                a = self.arbitrary_point(t1)
                b = o.arbitrary_point(t2)
                dx = a.x - b.x
                c = solve([dx, a.y - b.y], t)
                d = solve([dx, a.z - b.z], t)
                if len(c) == 1 and len(d) == 1:
                    return []
                e = a.subs(t1, c[t1])
                if e in self and e in o:
                    return [e]
                else:
                    return []

        return o.intersection(self)
Esempio n. 29
0
def rsolve(f, y, init=None):
    """
    Solve univariate recurrence with rational coefficients.

    Given `k`-th order linear recurrence `\operatorname{L} y = f`,
    or equivalently:

    .. math:: a_{k}(n) y(n+k) + a_{k-1}(n) y(n+k-1) +
              \ldots + a_{0}(n) y(n) = f(n)

    where `a_{i}(n)`, for `i=0, \ldots, k`, are polynomials or rational
    functions in `n`, and `f` is a hypergeometric function or a sum
    of a fixed number of pairwise dissimilar hypergeometric terms in
    `n`, finds all solutions or returns ``None``, if none were found.

    Initial conditions can be given as a dictionary in two forms:

        (1) ``{   n_0  : v_0,   n_1  : v_1, ...,   n_m  : v_m }``
        (2) ``{ y(n_0) : v_0, y(n_1) : v_1, ..., y(n_m) : v_m }``

    or as a list ``L`` of values:

        ``L = [ v_0, v_1, ..., v_m ]``

    where ``L[i] = v_i``, for `i=0, \ldots, m`, maps to `y(n_i)`.

    Examples
    ========

    Lets consider the following recurrence:

    .. math:: (n - 1) y(n + 2) - (n^2 + 3 n - 2) y(n + 1) +
              2 n (n + 1) y(n) = 0

    >>> from diofant import Function, rsolve
    >>> from diofant.abc import n
    >>> y = Function('y')

    >>> f = (n - 1)*y(n + 2) - (n**2 + 3*n - 2)*y(n + 1) + 2*n*(n + 1)*y(n)

    >>> rsolve(f, y(n))
    2**n*C0 + C1*factorial(n)

    >>> rsolve(f, y(n), { y(0):0, y(1):3 })
    3*2**n - 3*factorial(n)

    See Also
    ========

    rsolve_poly, rsolve_ratio, rsolve_hyper

    """
    if isinstance(f, Equality):
        f = f.lhs - f.rhs
    f = f.expand()

    n = y.args[0]

    h_part = defaultdict(lambda: S.Zero)
    i_part = S.Zero

    for h, c in f.collect(y.func(Wild('n')), evaluate=False).items():
        if h.func == y.func:
            k = Wild('k', exclude=(n, ))
            r = h.args[0].match(n + k)
            if r:
                c = simplify(c)
                if not c.is_rational_function(n):
                    raise ValueError(
                        "Rational function of '%s' expected, got '%s'" %
                        (n, c))
                h_part[int(r[k])] = c
            else:
                raise ValueError("'%s(%s + Integer)' expected, got '%s'" %
                                 (y.func, n, h))
        else:
            i_term = h * c
            if i_term.find(y.func(Wild('k'))):
                raise ValueError(
                    "Linear recurrence for '%s' expected, got '%s'" %
                    (y.func, f))
            i_part -= i_term

    if not i_part.is_rational_function(n):
        raise ValueError(
            "Inhomogeneous part should be a rational function of '%s', got '%s'"
            % (n, i_part))

    k_min, k_max = min(h_part.keys()), max(h_part.keys())

    if k_min < 0:
        return rsolve(f.subs(n, n + abs(k_min)), y, init)

    i_numer, i_denom = i_part.as_numer_denom()

    common = lcm_list([x.as_numer_denom()[1]
                       for x in h_part.values()] + [i_denom])

    if common is not S.One:
        for k, coeff in h_part.items():
            numer, denom = coeff.as_numer_denom()
            h_part[k] = numer * quo(common, denom, n)

        i_part = i_numer * quo(common, i_denom, n)

    coeffs = [h_part[i] for i in range(k_max + 1)]

    result = rsolve_hyper(coeffs, i_part, n, symbols=True)

    if result is None:
        return

    solution, symbols = result

    if init == {} or init == []:
        init = None

    if symbols and init is not None:
        if type(init) is list:
            init = {i: init[i] for i in range(len(init))}

        equations = []

        for k, v in init.items():
            try:
                i = int(k)
            except TypeError:
                if k.is_Function and k.func == y.func:
                    i = int(k.args[0])
                else:
                    raise ValueError(
                        "Integer or term '%s(Integer)' expected, got '%s'" %
                        (y.func, k))
            try:
                eq = solution.limit(n, i) - v
            except NotImplementedError:
                eq = solution.subs(n, i) - v
            equations.append(eq)

        result = solve(equations, *symbols)

        if not result:
            return
        else:
            solution = solution.subs(result)

    return solution