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
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)]
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