예제 #1
0
    def is_scalar_multiple(self, p):
        """Returns whether each coordinate of `self` is a scalar
        multiple of the corresponding coordinate in point p.
        """
        s, o = Point._normalize_dimension(self, Point(p))
        # 2d points happen a lot, so optimize this function call
        if s.ambient_dimension == 2:
            (x1, y1), (x2, y2) = s.args, o.args
            rv = (x1*y2 - x2*y1).equals(0)
            if rv is None:
                raise Undecidable(filldedent(
                    '''can't determine if %s is a scalar multiple of
                    %s''' % (s, o)))

        # if the vectors p1 and p2 are linearly dependent, then they must
        # be scalar multiples of each other
        m = Matrix([s.args, o.args])
        return m.rank() < 2
예제 #2
0
    def intersection(self, o):
        """ The intersection with other geometrical entity.

        Parameters
        ==========

        Point, Point3D, LinearEntity, LinearEntity3D, Plane

        Returns
        =======

        List

        Examples
        ========

        >>> from sympy 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 sympy.geometry.line import LinearEntity, LinearEntity3D

        if not isinstance(o, GeometryEntity):
            o = Point(o, dim=3)
        if isinstance(o, Point):
            if o in self:
                return [o]
            else:
                return []
        if isinstance(o, (LinearEntity, LinearEntity3D)):
            # recast to 3D
            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)
            if o in self:
                return [o]
            else:
                t = Dummy()  # unnamed else it may clash with a symbol in o
                a = Point3D(o.arbitrary_point(t))
                p1, n = self.p1, Point3D(self.normal_vector)

                # TODO: Replace solve with solveset, when this line is tested
                c = solve((a - p1).dot(n), t)
                if not c:
                    return []
                else:
                    c = [i for i in c if i.is_real is not False]
                    if len(c) > 1:
                        c = [i for i in c if i.is_real]
                    if len(c) != 1:
                        raise Undecidable("not sure which point is real")
                    p = a.subs(t, c[0])
                    if p not in o:
                        return []  # e.g. a segment might not intersect a plane
                    return [p]
        if isinstance(o, Plane):
            if self.equals(o):
                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)
                result = list(linsolve([d, e], x, y, z))[0]
                for i in (x, y, z):
                    result = result.subs(i, 0)
                return [Line3D(Point3D(result), direction_ratio=c)]
예제 #3
0
    def _intervals(self, sym):
        """Return a list of tuples, (a, b, e, i), where a and b
        are the lower and upper bounds in which the expression e
        of argument i in self is defined.

        If there are any relationals not involving sym, or
        any relational cannot be solved for sym,
        NotImplementedError is raised. The evaluated conditions will
        be returned as ranges. Discontinuous ranges will be
        returned separately with identical expressions and
        the first condition that evaluates to True will be
        returned as the last tuple with a, b = -oo, oo.
        """
        from sympy.solvers.inequalities import _solve_inequality
        from sympy.logic.boolalg import to_cnf, distribute_or_over_and

        assert isinstance(self, Piecewise)

        def _solve_relational(r):
            rv = _solve_inequality(r, sym)
            if isinstance(rv, Relational) and \
                    sym in rv.free_symbols:
                if rv.args[0] != sym:
                    raise NotImplementedError(
                        filldedent('''
                        Unable to solve relational
                        %s for %s.''' % (r, sym)))
                if rv.rel_op == '!=':
                    try:
                        rv = Or(sym < rv.rhs, sym > rv.rhs)
                    except TypeError:
                        # e.g. x != I ==> all real x satisfy
                        rv = S.true
            if rv == (S.NegativeInfinity < sym) & (sym < S.Infinity):
                rv = S.true
            return rv

        def nonsymfail(cond):
            raise NotImplementedError(
                filldedent('''
                A condition not involving
                %s appeared: %s''' % (sym, cond)))

        # make self canonical wrt Relationals
        reps = dict([(r, _solve_relational(r))
                     for r in self.atoms(Relational)])
        # process args individually so if any evaluate, their position
        # in the original Piecewise will be known
        args = [i.xreplace(reps) for i in self.args]

        # precondition args
        expr_cond = []
        default = idefault = None
        for i, (expr, cond) in enumerate(args):
            if cond == False:
                continue
            elif cond == True:
                default = expr
                idefault = i
                break
            elif sym not in cond.free_symbols:
                nonsymfail(cond)

            cond = to_cnf(cond)
            if isinstance(cond, And):
                cond = distribute_or_over_and(cond)

            if isinstance(cond, Or):
                expr_cond.extend([(i, expr, o) for o in cond.args])
            elif cond != False:
                expr_cond.append((i, expr, cond))

        # determine intervals represented by conditions
        int_expr = []
        for iarg, expr, cond in expr_cond:
            if isinstance(cond, Equality):
                if cond.lhs == sym:
                    v = cond.rhs
                    int_expr.append((v, v, expr.subs(sym, v), iarg))
                    continue
                else:
                    nonsymfail(cond)

            if isinstance(cond, And):
                lower = S.NegativeInfinity
                upper = S.Infinity
                nonsym = False
                rhs = None
                for cond2 in cond.args:
                    if isinstance(cond2, Equality):
                        # all relationals were solved and
                        # only sym-dependent ones made it to here
                        assert cond2.lhs == sym
                        assert sym not in cond2.rhs.free_symbols
                        if rhs is None:
                            rhs = cond2.rhs
                        else:
                            same = Eq(cond2.rhs, rhs)
                            if same == False:
                                cond = S.false
                                break
                            elif same != True:
                                raise Undecidable('%s did not evaluate' % same)
                    elif cond2.lts == sym:
                        upper = Min(cond2.gts, upper)
                    elif cond2.gts == sym:
                        lower = Max(cond2.lts, lower)
                    else:
                        # mark but don't fail until later
                        nonsym = cond2
                if rhs is not None and cond not in (S.true, S.false):
                    lower = upper = rhs
                    cond = cond.subs(sym, lower)
                # cond might have evaluated b/c of an Eq
                if cond is S.true:
                    default = expr
                    continue
                elif cond is S.false:
                    continue
                elif nonsym is not False:
                    nonsymfail(nonsym)
                else:
                    pass  # for coverage
            elif isinstance(cond, Relational):
                lower, upper = cond.lts, cond.gts  # part 1: initialize with givens
                if cond.lts == sym:  # part 1a: expand the side ...
                    lower = S.NegativeInfinity  # e.g. x <= 0 ---> -oo <= 0
                elif cond.gts == sym:  # part 1a: ... that can be expanded
                    upper = S.Infinity  # e.g. x >= 0 --->  oo >= 0
                else:
                    nonsymfail(cond)
            else:
                raise NotImplementedError('unrecognized condition: %s' % cond)

            lower, upper = lower, Max(lower, upper)
            if (lower > upper) is not S.true:
                int_expr.append((lower, upper, expr, iarg))

        if default is not None:
            int_expr.append(
                (S.NegativeInfinity, S.Infinity, default, idefault))

        return int_expr