def parameter_value(self, other, t): """Return the parameter corresponding to the given point. Evaluating an arbitrary point of the entity at this parameter value will return the given point. Examples ======== >>> from sympy import Line, Point >>> from sympy.abc import t >>> a = Point(0, 0) >>> b = Point(2, 2) >>> Line(a, b).parameter_value((1, 1), t) {t: 1/2} >>> Line(a, b).arbitrary_point(t).subs(_) Point2D(1, 1) """ from sympy.geometry.point import Point from sympy.core.symbol import Dummy from sympy.solvers.solvers import solve if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if not isinstance(other, Point): raise ValueError("other must be a point") T = Dummy('t', real=True) sol = solve(self.arbitrary_point(T) - other, T, dict=True) if not sol: raise ValueError("Given point is not on %s" % func_name(self)) return {t: sol[0][T]}
def parameter_value(self, other, u, v=None): """Return the parameter(s) corresponding to the given point. Examples ======== >>> from sympy import Plane, Point, pi >>> from sympy.abc import t, u, v >>> p = Plane((2, 0, 0), (0, 0, 1), (0, 1, 0)) By default, the parameter value returned defines a point that is a distance of 1 from the Plane's p1 value and in line with the given point: >>> on_circle = p.arbitrary_point(t).subs(t, pi/4) >>> on_circle.distance(p.p1) 1 >>> p.parameter_value(on_circle, t) {t: pi/4} Moving the point twice as far from p1 does not change the parameter value: >>> off_circle = p.p1 + (on_circle - p.p1)*2 >>> off_circle.distance(p.p1) 2 >>> p.parameter_value(off_circle, t) {t: pi/4} If the 2-value parameter is desired, supply the two parameter symbols and a replacement dictionary will be returned: >>> p.parameter_value(on_circle, u, v) {u: sqrt(10)/10, v: sqrt(10)/30} >>> p.parameter_value(off_circle, u, v) {u: sqrt(10)/5, v: sqrt(10)/15} """ from sympy.geometry.point import Point from sympy.solvers.solvers import solve if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if not isinstance(other, Point): raise ValueError("other must be a point") if other == self.p1: return other if isinstance(u, Symbol) and v is None: delta = self.arbitrary_point(u) - self.p1 eq = delta - (other - self.p1).unit sol = solve(eq, u, dict=True) elif isinstance(u, Symbol) and isinstance(v, Symbol): pt = self.arbitrary_point(u, v) sol = solve(pt - other, (u, v), dict=True) else: raise ValueError("expecting 1 or 2 symbols") if not sol: raise ValueError("Given point is not on %s" % func_name(self)) return sol[0] # {t: tval} or {u: uval, v: vval}
def decompogen(f, symbol): """ Computes General functional decomposition of ``f``. Given an expression ``f``, returns a list ``[f_1, f_2, ..., f_n]``, where:: f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) Note: This is a General decomposition function. It also decomposes Polynomials. For only Polynomial decomposition see ``decompose`` in polys. Examples ======== >>> from sympy.solvers.decompogen import decompogen >>> from sympy.abc import x >>> from sympy import sqrt, sin, cos >>> decompogen(sin(cos(x)), x) [sin(x), cos(x)] >>> decompogen(sin(x)**2 + sin(x) + 1, x) [x**2 + x + 1, sin(x)] >>> decompogen(sqrt(6*x**2 - 5), x) [sqrt(x), 6*x**2 - 5] >>> decompogen(sin(sqrt(cos(x**2 + 1))), x) [sin(x), sqrt(x), cos(x), x**2 + 1] >>> decompogen(x**4 + 2*x**3 - x - 1, x) [x**2 - x - 1, x**2 + x] """ f = sympify(f) if not isinstance(f, Expr) or isinstance(f, Relational): raise TypeError('expecting Expr but got: `%s`' % func_name(f)) if symbol not in f.free_symbols: return [f] result = [] # ===== Simple Functions ===== # if isinstance(f, (Function, Pow)): if f.args[0] == symbol: return [f] result += [f.subs(f.args[0], symbol)] + decompogen(f.args[0], symbol) return result # ===== Convert to Polynomial ===== # fp = Poly(f) gens = list(filter(lambda x: symbol in x.free_symbols, fp.gens)) if len(gens) == 1 and gens[0] != symbol: f1 = f.subs(gens[0], symbol) f2 = gens[0] result += [f1] + decompogen(f2, symbol) return result # ===== Polynomial decompose() ====== # try: result += decompose(f) return result except ValueError: return [f]
def parameter_value(self, other, u, v=None): """Return the parameter(s) corresponding to the given point. Examples ======== >>> from sympy import Plane, Point, pi >>> from sympy.abc import t, u, v >>> p = Plane((2, 0, 0), (0, 0, 1), (0, 1, 0)) By default, the parameter value returned defines a point that is a distance of 1 from the Plane's p1 value and in line with the given point: >>> on_circle = p.arbitrary_point(t).subs(t, pi/4) >>> on_circle.distance(p.p1) 1 >>> p.parameter_value(on_circle, t) {t: pi/4} Moving the point twice as far from p1 does not change the parameter value: >>> off_circle = p.p1 + (on_circle - p.p1)*2 >>> off_circle.distance(p.p1) 2 >>> p.parameter_value(off_circle, t) {t: pi/4} If the 2-value parameter is desired, supply the two parameter symbols and a replacement dictionary will be returned: >>> p.parameter_value(on_circle, u, v) {u: sqrt(10)/10, v: sqrt(10)/30} >>> p.parameter_value(off_circle, u, v) {u: sqrt(10)/5, v: sqrt(10)/15} """ from sympy.geometry.point import Point from sympy.core.symbol import Dummy from sympy.solvers.solvers import solve if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if not isinstance(other, Point): raise ValueError("other must be a point") if other == self.p1: return other if isinstance(u, Symbol) and v is None: delta = self.arbitrary_point(u) - self.p1 eq = delta - (other - self.p1).unit sol = solve(eq, u, dict=True) elif isinstance(u, Symbol) and isinstance(v, Symbol): pt = self.arbitrary_point(u, v) sol = solve(pt - other, (u, v), dict=True) else: raise ValueError('expecting 1 or 2 symbols') if not sol: raise ValueError("Given point is not on %s" % func_name(self)) return sol[0] # {t: tval} or {u: uval, v: vval}
def decompogen(f, symbol): """ Computes General functional decomposition of ``f``. Given an expression ``f``, returns a list ``[f_1, f_2, ..., f_n]``, where:: f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) Note: This is a General decomposition function. It also decomposes Polynomials. For only Polynomial decomposition see ``decompose`` in polys. Examples ======== >>> from sympy.solvers.decompogen import decompogen >>> from sympy.abc import x >>> from sympy import sqrt, sin, cos >>> decompogen(sin(cos(x)), x) [sin(x), cos(x)] >>> decompogen(sin(x)**2 + sin(x) + 1, x) [x**2 + x + 1, sin(x)] >>> decompogen(sqrt(6*x**2 - 5), x) [sqrt(x), 6*x**2 - 5] >>> decompogen(sin(sqrt(cos(x**2 + 1))), x) [sin(x), sqrt(x), cos(x), x**2 + 1] >>> decompogen(x**4 + 2*x**3 - x - 1, x) [x**2 - x - 1, x**2 + x] """ f = sympify(f) if not isinstance(f, Expr) or isinstance(f, Relational): raise TypeError('expecting Expr but got: `%s`' % func_name(f)) if symbol not in f.free_symbols: return [f] result = [] # ===== Simple Functions ===== # if isinstance(f, (Function, Pow)): if f.args[0] == symbol: return [f] result += [f.subs(f.args[0], symbol)] + decompogen(f.args[0], symbol) return result # ===== Convert to Polynomial ===== # fp = Poly(f) gens = list(filter(lambda x: symbol in x.free_symbols , fp.gens)) if len(gens) == 1 and gens[0] != symbol: f1 = f.subs(gens[0], symbol) f2 = gens[0] result += [f1] + decompogen(f2, symbol) return result # ===== Polynomial decompose() ====== # try: result += decompose(f) return result except ValueError: return [f]
def eval(cls, x, s): if not s.is_set: raise TypeError('expecting Set, not %s' % func_name(s)) ret = s.contains(x) if not isinstance(ret, Contains) and (ret in (S.true, S.false) or ret.is_set): return ret
def _contains(self, other): from sympy.matrices import Matrix from sympy.solvers.solveset import solveset, linsolve from sympy.utilities.iterables import iterable, cartes L = self.lamda if self._is_multivariate(): if not iterable(L.expr): if iterable(other): return S.false return other.as_numer_denom() in self.func( Lambda(L.variables, L.expr.as_numer_denom()), self.base_set) if len(L.expr) != len(self.lamda.variables): raise NotImplementedError(filldedent(''' Dimensions of input and output of Lambda are different.''')) eqs = [expr - val for val, expr in zip(other, L.expr)] variables = L.variables free = set(variables) if all(i.is_number for i in list(Matrix(eqs).jacobian(variables))): solns = list(linsolve([e - val for e, val in zip(L.expr, other)], variables)) else: syms = [e.free_symbols & free for e in eqs] solns = {} for i, (e, s, v) in enumerate(zip(eqs, syms, other)): if not s: if e != v: return S.false solns[vars[i]] = [v] continue elif len(s) == 1: sy = s.pop() sol = solveset(e, sy) if sol is S.EmptySet: return S.false elif isinstance(sol, FiniteSet): solns[sy] = list(sol) else: raise NotImplementedError else: raise NotImplementedError solns = cartes(*[solns[s] for s in variables]) else: # assume scalar -> scalar mapping solnsSet = solveset(L.expr - other, L.variables[0]) if solnsSet.is_FiniteSet: solns = list(solnsSet) else: raise NotImplementedError(filldedent(''' Determining whether an ImageSet contains %s has not been implemented.''' % func_name(other))) for soln in solns: try: if soln in self.base_set: return S.true except TypeError: return self.base_set.contains(soln.evalf()) return S.false
def eval(cls, x, s): assert x.is_set and s.is_set, 'expecting Set, not %s' % func_name(s) if x.is_Symbol and x.definition is not None: x = x.definition if s.is_Symbol and s.definition is not None: s = s.definition b = cls.invert_type.eval(x, s) if b is not None: return b.invert()
def eval(cls, x, s): if not s.is_set: raise TypeError('expecting Set, not %s' % func_name(s)) ret = s.contains(x) from sympy.core.sympify import sympify if not isinstance(ret, Contains) and (ret in (S.true, S.false) or ret.is_set): return sympify(not ret)
def eval(cls, x, s): from sympy.sets.sets import Set if not isinstance(s, Set): raise TypeError("expecting Set, not %s" % func_name(s)) ret = s.contains(x) if not isinstance(ret, Contains) and (ret in (S.true, S.false) or isinstance(ret, Set)): return ret
def exprcondpair_new(cls, expr, cond): expr = as_Basic(expr) if cond == True: return Tuple.__new__(cls, expr, true) elif cond == False: return Tuple.__new__(cls, expr, false) if not isinstance(cond, Boolean): raise TypeError(filldedent(''' Second argument must be a Boolean, not `%s`''' % func_name(cond))) return Tuple.__new__(cls, expr, cond)
def exprcondpair_new(cls, expr, cond): expr = as_Basic(expr) if cond == True: return Tuple.__new__(cls, expr, true) elif cond == False: return Tuple.__new__(cls, expr, false) if not isinstance(cond, Boolean): raise TypeError( filldedent(''' Second argument must be a Boolean, not `%s`''' % func_name(cond))) return Tuple.__new__(cls, expr, cond)
def __new__(cls, expr, cond): expr = as_Basic(expr) if cond == True: return Tuple.__new__(cls, expr, true) elif cond == False: return Tuple.__new__(cls, expr, false) elif isinstance(cond, Basic) and cond.has(Piecewise): cond = piecewise_fold(cond) if isinstance(cond, Piecewise): cond = cond.rewrite(ITE) if not isinstance(cond, Boolean): raise TypeError(filldedent(''' Second argument must be a Boolean, not `%s`''' % func_name(cond))) return Tuple.__new__(cls, expr, cond)
def _eval_rewrite_as_ITE(self, *args, **kwargs): byfree = {} args = list(args) default = any(c == True for b, c in args) for i, (b, c) in enumerate(args): if not isinstance(b, Boolean) and b != True: raise TypeError( filldedent(''' Expecting Boolean or bool but got `%s` ''' % func_name(b))) if c == True: break # loop over independent conditions for this b for c in c.args if isinstance(c, Or) else [c]: free = c.free_symbols x = free.pop() try: byfree[x] = byfree.setdefault(x, S.EmptySet).union(c.as_set()) except NotImplementedError: if not default: raise NotImplementedError( filldedent(''' A method to determine whether a multivariate conditional is consistent with a complete coverage of all variables has not been implemented so the rewrite is being stopped after encountering `%s`. This error would not occur if a default expression like `(foo, True)` were given. ''' % c)) if byfree[x] in (S.UniversalSet, S.Reals): # collapse the ith condition to True and break args[i] = list(args[i]) c = args[i][1] = True break if c == True: break if c != True: raise ValueError( filldedent(''' Conditions must cover all reals or a final default condition `(foo, True)` must be given. ''')) last, _ = args[i] # ignore all past ith arg for a, c in reversed(args[:i]): last = ITE(c, a, last) return _canonical(last)
def eval(cls, x, s): assert x.is_set and s.is_set, 'expecting Set, not %s' % func_name(s) if x.is_symbol and x.definition is not None: x = x.definition if s.is_symbol and s.definition is not None: s = s.definition if x == s: return S.true if s.is_Union: if x in s._argset: return S.true if x.is_Intersection: for e in x._argset: if e in s: return S.true if x == S.EmptySet: return S.true if x.is_ConditionSet: sym, condition, base_set = x.variable, x.condition, x.base_set if s.is_ConditionSet: _sym, _condition, _base_set = s.variable, s.condition, s.base_set if sym.dtype == _sym.dtype and (base_set == _base_set or base_set in _base_set): if sym != _sym: _condition = _condition._subs(_sym, sym) if condition == _condition: return S.true if condition.is_And: if _condition.is_And and all( eq in condition._argset for eq in _condition. args) or _condition in condition._argset: return S.true base_set &= sym.domain if base_set in s: return S.true if x.is_Piecewise and not s.is_Piecewise: return x.func(*((cls(e, s), c) for e, c in x.args)) if s.is_CartesianSpace: if x.is_Symbol: if x.element_type.as_Set() in s: return S.true
def _eval_rewrite_as_ITE(self, *args): byfree = {} args = list(args) default = any(c == True for b, c in args) for i, (b, c) in enumerate(args): if not isinstance(b, Boolean) and b != True: raise TypeError(filldedent(''' Expecting Boolean or bool but got `%s` ''' % func_name(b))) if c == True: break # loop over independent conditions for this b for c in c.args if isinstance(c, Or) else [c]: free = c.free_symbols x = free.pop() try: byfree[x] = byfree.setdefault( x, S.EmptySet).union(c.as_set()) except NotImplementedError: if not default: raise NotImplementedError(filldedent(''' A method to determine whether a multivariate conditional is consistent with a complete coverage of all variables has not been implemented so the rewrite is being stopped after encountering `%s`. This error would not occur if a default expression like `(foo, True)` were given. ''' % c)) if byfree[x] in (S.UniversalSet, S.Reals): # collapse the ith condition to True and break args[i] = list(args[i]) c = args[i][1] = True break if c == True: break if c != True: raise ValueError(filldedent(''' Conditions must cover all reals or a final default condition `(foo, True)` must be given. ''')) last, _ = args[i] # ignore all past ith arg for a, c in reversed(args[:i]): last = ITE(c, a, last) return _canonical(last)
def _contains(self, other): from sympy.solvers.solveset import solveset, linsolve L = self.lamda if self._is_multivariate(): solns = list(linsolve([expr - val for val, expr in zip(other, L.expr)], L.variables).args[0]) else: solnsSet = solveset(L.expr-other, L.variables[0]) if solnsSet.is_FiniteSet: solns = list(solveset(L.expr - other, L.variables[0])) else: raise NotImplementedError(filldedent(''' Determining whether an ImageSet contains %s has not been implemented.''' % func_name(other))) for soln in solns: try: if soln in self.base_set: return S.true except TypeError: return self.base_set.contains(soln.evalf()) return S.false
def _contains(self, other): from sympy.solvers.solveset import solveset, linsolve L = self.lamda if self._is_multivariate(): solns = list( linsolve([expr - val for val, expr in zip(other, L.expr)], L.variables).args[0]) else: solnsSet = solveset(L.expr - other, L.variables[0]) if solnsSet.is_FiniteSet: solns = list(solveset(L.expr - other, L.variables[0])) else: raise NotImplementedError( filldedent(''' Determining whether an ImageSet contains %s has not been implemented.''' % func_name(other))) for soln in solns: try: if soln in self.base_set: return S.true except TypeError: return self.base_set.contains(soln.evalf()) return S.false
def parse_expr(s, local_dict=None, transformations=standard_transformations, global_dict=None, evaluate=True): """Converts the string ``s`` to a SymPy expression, in ``local_dict`` Parameters ========== s : str The string to parse. local_dict : dict, optional A dictionary of local variables to use when parsing. global_dict : dict, optional A dictionary of global variables. By default, this is initialized with ``from sympy import *``; provide this parameter to override this behavior (for instance, to parse ``"Q & S"``). transformations : tuple or str, optional A tuple of transformation functions used to modify the tokens of the parsed expression before evaluation. The default transformations convert numeric literals into their SymPy equivalents, convert undefined variables into SymPy symbols, and allow the use of standard mathematical factorial notation (e.g. ``x!``). Selection via string is available (see below). evaluate : bool, optional When False, the order of the arguments will remain as they were in the string and automatic simplification that would normally occur is suppressed. (see examples) Examples ======== >>> from sympy.parsing.sympy_parser import parse_expr >>> parse_expr("1/2") 1/2 >>> type(_) <class 'sympy.core.numbers.Half'> >>> from sympy.parsing.sympy_parser import standard_transformations,\\ ... implicit_multiplication_application >>> transformations = (standard_transformations + ... (implicit_multiplication_application,)) >>> parse_expr("2x", transformations=transformations) 2*x When evaluate=False, some automatic simplifications will not occur: >>> parse_expr("2**3"), parse_expr("2**3", evaluate=False) (8, 2**3) In addition the order of the arguments will not be made canonical. This feature allows one to tell exactly how the expression was entered: >>> a = parse_expr('1 + x', evaluate=False) >>> b = parse_expr('x + 1', evaluate=0) >>> a == b False >>> a.args (1, x) >>> b.args (x, 1) Note, however, that when these expressions are printed they will appear the same: >>> assert str(a) == str(b) As a convenience, transformations can be seen by printing ``transformations``: >>> from sympy.parsing.sympy_parser import transformations >>> print(transformations) 0: lambda_notation 1: auto_symbol 2: repeated_decimals 3: auto_number 4: factorial_notation 5: implicit_multiplication_application 6: convert_xor 7: implicit_application 8: implicit_multiplication 9: convert_equals_signs 10: function_exponentiation 11: rationalize The ``T`` object provides a way to select these transformations: >>> from sympy.parsing.sympy_parser import T If you print it, you will see the same list as shown above. >>> str(T) == str(transformations) True Standard slicing will return a tuple of transformations: >>> T[:5] == standard_transformations True So ``T`` can be used to specify the parsing transformations: >>> parse_expr("2x", transformations=T[:5]) Traceback (most recent call last): ... SyntaxError: invalid syntax >>> parse_expr("2x", transformations=T[:6]) 2*x >>> parse_expr('.3', transformations=T[3, 11]) 3/10 >>> parse_expr('.3x', transformations=T[:]) 3*x/10 As a further convenience, strings 'implicit' and 'all' can be used to select 0-5 and all the transformations, respectively. >>> parse_expr('.3x', transformations='all') 3*x/10 See Also ======== stringify_expr, eval_expr, standard_transformations, implicit_multiplication_application """ if local_dict is None: local_dict = {} elif not isinstance(local_dict, dict): raise TypeError('expecting local_dict to be a dict') elif null in local_dict: raise ValueError('cannot use "" in local_dict') if global_dict is None: global_dict = {} exec('from sympy import *', global_dict) builtins_dict = vars(builtins) for name, obj in builtins_dict.items(): if isinstance(obj, types.BuiltinFunctionType): global_dict[name] = obj global_dict['max'] = Max global_dict['min'] = Min elif not isinstance(global_dict, dict): raise TypeError('expecting global_dict to be a dict') transformations = transformations or () if type(transformations) is str: if transformations == 'all': transformations = T[:] elif transformations == 'implicit': transformations = T[:6] else: raise ValueError('unknown transformation group name') if transformations: if not iterable(transformations): raise TypeError( '`transformations` should be a list of functions.') for _ in transformations: if not callable(_): raise TypeError(filldedent(''' expected a function in `transformations`, not %s''' % func_name(_))) if arity(_) != 3: raise TypeError(filldedent(''' a transformation should be function that takes 3 arguments''')) code = stringify_expr(s, local_dict, global_dict, transformations) if not evaluate: code = compile(evaluateFalse(code), '<string>', 'eval') try: rv = eval_expr(code, local_dict, global_dict) # restore neutral definitions for names for i in local_dict.pop(null, ()): local_dict[i] = null return rv except Exception as e: # restore neutral definitions for names for i in local_dict.pop(null, ()): local_dict[i] = null raise e from ValueError(f"Error from parse_expr with transformed code: {code!r}")
def is_tangent(self, o): """Is `o` tangent to the ellipse? Parameters ========== o : GeometryEntity An Ellipse, LinearEntity or Polygon Raises ====== NotImplementedError When the wrong type of argument is supplied. Returns ======= is_tangent: boolean True if o is tangent to the ellipse, False otherwise. See Also ======== tangent_lines Examples ======== >>> from sympy import Point, Ellipse, Line >>> p0, p1, p2 = Point(0, 0), Point(3, 0), Point(3, 3) >>> e1 = Ellipse(p0, 3, 2) >>> l1 = Line(p1, p2) >>> e1.is_tangent(l1) True """ if isinstance(o, Point2D): return False elif isinstance(o, Ellipse): intersect = self.intersection(o) if isinstance(intersect, Ellipse): return True elif intersect: return all((self.tangent_lines(i)[0]).equals((o.tangent_lines(i)[0])) for i in intersect) else: return False elif isinstance(o, Line2D): return len(self.intersection(o)) == 1 elif isinstance(o, Ray2D): intersect = self.intersection(o) if len(intersect) == 1: return intersect[0] != o.source and not self.encloses_point(o.source) else: return False elif isinstance(o, (Segment2D, Polygon)): all_tangents = False segments = o.sides if isinstance(o, Polygon) else [o] for segment in segments: intersect = self.intersection(segment) if len(intersect) == 1: if not any(intersect[0] in i for i in segment.points)\ and all(not self.encloses_point(i) for i in segment.points): all_tangents = True continue else: return False else: return all_tangents return all_tangents elif isinstance(o, (LinearEntity3D, Point3D)): raise TypeError('Entity must be two dimensional, not three dimensional') else: raise TypeError('Is_tangent not handled for %s' % func_name(o))
def decompogen(f, symbol): """ Computes General functional decomposition of ``f``. Given an expression ``f``, returns a list ``[f_1, f_2, ..., f_n]``, where:: f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) Note: This is a General decomposition function. It also decomposes Polynomials. For only Polynomial decomposition see ``decompose`` in polys. Examples ======== >>> from sympy.abc import x >>> from sympy import decompogen, sqrt, sin, cos >>> decompogen(sin(cos(x)), x) [sin(x), cos(x)] >>> decompogen(sin(x)**2 + sin(x) + 1, x) [x**2 + x + 1, sin(x)] >>> decompogen(sqrt(6*x**2 - 5), x) [sqrt(x), 6*x**2 - 5] >>> decompogen(sin(sqrt(cos(x**2 + 1))), x) [sin(x), sqrt(x), cos(x), x**2 + 1] >>> decompogen(x**4 + 2*x**3 - x - 1, x) [x**2 - x - 1, x**2 + x] """ f = sympify(f) if not isinstance(f, Expr) or isinstance(f, Relational): raise TypeError('expecting Expr but got: `%s`' % func_name(f)) if symbol not in f.free_symbols: return [f] # ===== Simple Functions ===== # if isinstance(f, (Function, Pow)): if f.is_Pow and f.base == S.Exp1: arg = f.exp else: arg = f.args[0] if arg == symbol: return [f] return [f.subs(arg, symbol)] + decompogen(arg, symbol) # ===== Min/Max Functions ===== # if isinstance(f, (Min, Max)): args = list(f.args) d0 = None for i, a in enumerate(args): if not a.has_free(symbol): continue d = decompogen(a, symbol) if len(d) == 1: d = [symbol] + d if d0 is None: d0 = d[1:] elif d[1:] != d0: # decomposition is not the same for each arg: # mark as having no decomposition d = [symbol] break args[i] = d[0] if d[0] == symbol: return [f] return [f.func(*args)] + d0 # ===== Convert to Polynomial ===== # fp = Poly(f) gens = list(filter(lambda x: symbol in x.free_symbols, fp.gens)) if len(gens) == 1 and gens[0] != symbol: f1 = f.subs(gens[0], symbol) f2 = gens[0] return [f1] + decompogen(f2, symbol) # ===== Polynomial decompose() ====== # try: return decompose(f) except ValueError: return [f]
def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_evaluate[0]) on_morph = kwargs.get('on_morph', 'ignore') # unpack into coords coords = args[0] if len(args) == 1 else args # check args and handle quickly handle Point instances if isinstance(coords, Point): # even if we're mutating the dimension of a point, we # don't reevaluate its coordinates evaluate = False if len(coords) == kwargs.get('dim', len(coords)): return coords if not is_sequence(coords): raise TypeError(filldedent(''' Expecting sequence of coordinates, not `{}`''' .format(func_name(coords)))) # A point where only `dim` is specified is initialized # to zeros. if len(coords) == 0 and kwargs.get('dim', None): coords = (S.Zero,)*kwargs.get('dim') coords = Tuple(*coords) dim = kwargs.get('dim', len(coords)) if len(coords) < 2: raise ValueError(filldedent(''' Point requires 2 or more coordinates or keyword `dim` > 1.''')) if len(coords) != dim: message = ("Dimension of {} needs to be changed" "from {} to {}.").format(coords, len(coords), dim) if on_morph == 'ignore': pass elif on_morph == "error": raise ValueError(message) elif on_morph == 'warn': warnings.warn(message) else: raise ValueError(filldedent(''' on_morph value should be 'error', 'warn' or 'ignore'.''')) if any(i for i in coords[dim:]): raise ValueError('Nonzero coordinates cannot be removed.') if any(a.is_number and im(a) for a in coords): raise ValueError('Imaginary coordinates are not permitted.') if not all(isinstance(a, Expr) for a in coords): raise TypeError('Coordinates must be valid SymPy expressions.') # pad with zeros appropriately coords = coords[:dim] + (S.Zero,)*(dim - len(coords)) # Turn any Floats into rationals and simplify # any expressions before we instantiate if evaluate: coords = coords.xreplace(dict( [(f, simplify(nsimplify(f, rational=True))) for f in coords.atoms(Float)])) # return 2D or 3D instances if len(coords) == 2: kwargs['_nocheck'] = True return Point2D(*coords, **kwargs) elif len(coords) == 3: kwargs['_nocheck'] = True return Point3D(*coords, **kwargs) # the general Point return GeometryEntity.__new__(cls, *coords)
def intersection(self, o): """The intersection of this ellipse and another geometrical entity `o`. Parameters ========== o : GeometryEntity Returns ======= intersection : list of GeometryEntity objects Notes ----- Currently supports intersections with Point, Line, Segment, Ray, Circle and Ellipse types. See Also ======== sympy.geometry.entity.GeometryEntity Examples ======== >>> from sympy import Ellipse, Point, Line, sqrt >>> e = Ellipse(Point(0, 0), 5, 7) >>> e.intersection(Point(0, 0)) [] >>> e.intersection(Point(5, 0)) [Point2D(5, 0)] >>> e.intersection(Line(Point(0,0), Point(0, 1))) [Point2D(0, -7), Point2D(0, 7)] >>> e.intersection(Line(Point(5,0), Point(5, 1))) [Point2D(5, 0)] >>> e.intersection(Line(Point(6,0), Point(6, 1))) [] >>> e = Ellipse(Point(-1, 0), 4, 3) >>> e.intersection(Ellipse(Point(1, 0), 4, 3)) [Point2D(0, -3*sqrt(15)/4), Point2D(0, 3*sqrt(15)/4)] >>> e.intersection(Ellipse(Point(5, 0), 4, 3)) [Point2D(2, -3*sqrt(7)/4), Point2D(2, 3*sqrt(7)/4)] >>> e.intersection(Ellipse(Point(100500, 0), 4, 3)) [] >>> e.intersection(Ellipse(Point(0, 0), 3, 4)) [Point2D(3, 0), Point2D(-363/175, -48*sqrt(111)/175), Point2D(-363/175, 48*sqrt(111)/175)] >>> e.intersection(Ellipse(Point(-1, 0), 3, 4)) [Point2D(-17/5, -12/5), Point2D(-17/5, 12/5), Point2D(7/5, -12/5), Point2D(7/5, 12/5)] """ # TODO: Replace solve with nonlinsolve, when nonlinsolve will be able to solve in real domain x = Dummy('x', real=True) y = Dummy('y', real=True) if isinstance(o, Point): if o in self: return [o] else: return [] elif isinstance(o, (Segment2D, Ray2D)): ellipse_equation = self.equation(x, y) result = solve([ellipse_equation, Line(o.points[0], o.points[1]).equation(x, y)], [x, y]) return list(ordered([Point(i) for i in result if i in o])) elif isinstance(o, Polygon): return o.intersection(self) elif isinstance(o, (Ellipse, Line2D)): if o == self: return self else: ellipse_equation = self.equation(x, y) return list(ordered([Point(i) for i in solve([ellipse_equation, o.equation(x, y)], [x, y])])) elif isinstance(o, LinearEntity3D): raise TypeError('Entity must be two dimensional, not three dimensional') else: raise TypeError('Intersection not handled for %s' % func_name(o))
def is_tangent(self, o): """Is `o` tangent to the ellipse? Parameters ========== o : GeometryEntity An Ellipse, LinearEntity or Polygon Raises ====== NotImplementedError When the wrong type of argument is supplied. Returns ======= is_tangent: boolean True if o is tangent to the ellipse, False otherwise. See Also ======== tangent_lines Examples ======== >>> from sympy import Point, Ellipse, Line >>> p0, p1, p2 = Point(0, 0), Point(3, 0), Point(3, 3) >>> e1 = Ellipse(p0, 3, 2) >>> l1 = Line(p1, p2) >>> e1.is_tangent(l1) True """ if isinstance(o, Point2D): return False elif isinstance(o, Ellipse): intersect = self.intersection(o) if isinstance(intersect, Ellipse): return True elif intersect: return all( (self.tangent_lines(i)[0]).equals((o.tangent_lines(i)[0])) for i in intersect) else: return False elif isinstance(o, Line2D): return len(self.intersection(o)) == 1 elif isinstance(o, Ray2D): intersect = self.intersection(o) if len(intersect) == 1: return intersect[0] != o.source and not self.encloses_point( o.source) else: return False elif isinstance(o, (Segment2D, Polygon)): all_tangents = False segments = o.sides if isinstance(o, Polygon) else [o] for segment in segments: intersect = self.intersection(segment) if len(intersect) == 1: if not any(intersect[0] in i for i in segment.points)\ and all(not self.encloses_point(i) for i in segment.points): all_tangents = True continue else: return False else: return all_tangents return all_tangents elif isinstance(o, (LinearEntity3D, Point3D)): raise TypeError( 'Entity must be two dimensional, not three dimensional') else: raise TypeError('Is_tangent not handled for %s' % func_name(o))
def intersection(self, o): """The intersection of this ellipse and another geometrical entity `o`. Parameters ========== o : GeometryEntity Returns ======= intersection : list of GeometryEntity objects Notes ----- Currently supports intersections with Point, Line, Segment, Ray, Circle and Ellipse types. See Also ======== sympy.geometry.entity.GeometryEntity Examples ======== >>> from sympy import Ellipse, Point, Line, sqrt >>> e = Ellipse(Point(0, 0), 5, 7) >>> e.intersection(Point(0, 0)) [] >>> e.intersection(Point(5, 0)) [Point2D(5, 0)] >>> e.intersection(Line(Point(0,0), Point(0, 1))) [Point2D(0, -7), Point2D(0, 7)] >>> e.intersection(Line(Point(5,0), Point(5, 1))) [Point2D(5, 0)] >>> e.intersection(Line(Point(6,0), Point(6, 1))) [] >>> e = Ellipse(Point(-1, 0), 4, 3) >>> e.intersection(Ellipse(Point(1, 0), 4, 3)) [Point2D(0, -3*sqrt(15)/4), Point2D(0, 3*sqrt(15)/4)] >>> e.intersection(Ellipse(Point(5, 0), 4, 3)) [Point2D(2, -3*sqrt(7)/4), Point2D(2, 3*sqrt(7)/4)] >>> e.intersection(Ellipse(Point(100500, 0), 4, 3)) [] >>> e.intersection(Ellipse(Point(0, 0), 3, 4)) [Point2D(3, 0), Point2D(-363/175, -48*sqrt(111)/175), Point2D(-363/175, 48*sqrt(111)/175)] >>> e.intersection(Ellipse(Point(-1, 0), 3, 4)) [Point2D(-17/5, -12/5), Point2D(-17/5, 12/5), Point2D(7/5, -12/5), Point2D(7/5, 12/5)] """ # TODO: Replace solve with nonlinsolve, when nonlinsolve will be able to solve in real domain x = Dummy('x', real=True) y = Dummy('y', real=True) if isinstance(o, Point): if o in self: return [o] else: return [] elif isinstance(o, (Segment2D, Ray2D)): ellipse_equation = self.equation(x, y) result = solve([ ellipse_equation, Line(o.points[0], o.points[1]).equation(x, y) ], [x, y]) return list(ordered([Point(i) for i in result if i in o])) elif isinstance(o, Polygon): return o.intersection(self) elif isinstance(o, (Ellipse, Line2D)): if o == self: return self else: ellipse_equation = self.equation(x, y) return list( ordered([ Point(i) for i in solve([ellipse_equation, o.equation(x, y)], [x, y]) ])) elif isinstance(o, LinearEntity3D): raise TypeError( 'Entity must be two dimensional, not three dimensional') else: raise TypeError('Intersection not handled for %s' % func_name(o))
def parse_expr(s, local_dict=None, transformations=standard_transformations, global_dict=None, evaluate=True): """Converts the string ``s`` to a SymPy expression, in ``local_dict`` Parameters ========== s : str The string to parse. local_dict : dict, optional A dictionary of local variables to use when parsing. global_dict : dict, optional A dictionary of global variables. By default, this is initialized with ``from sympy import *``; provide this parameter to override this behavior (for instance, to parse ``"Q & S"``). transformations : tuple, optional A tuple of transformation functions used to modify the tokens of the parsed expression before evaluation. The default transformations convert numeric literals into their SymPy equivalents, convert undefined variables into SymPy symbols, and allow the use of standard mathematical factorial notation (e.g. ``x!``). evaluate : bool, optional When False, the order of the arguments will remain as they were in the string and automatic simplification that would normally occur is suppressed. (see examples) Examples ======== >>> from sympy.parsing.sympy_parser import parse_expr >>> parse_expr("1/2") 1/2 >>> type(_) <class 'sympy.core.numbers.Half'> >>> from sympy.parsing.sympy_parser import standard_transformations,\\ ... implicit_multiplication_application >>> transformations = (standard_transformations + ... (implicit_multiplication_application,)) >>> parse_expr("2x", transformations=transformations) 2*x When evaluate=False, some automatic simplifications will not occur: >>> parse_expr("2**3"), parse_expr("2**3", evaluate=False) (8, 2**3) In addition the order of the arguments will not be made canonical. This feature allows one to tell exactly how the expression was entered: >>> a = parse_expr('1 + x', evaluate=False) >>> b = parse_expr('x + 1', evaluate=0) >>> a == b False >>> a.args (1, x) >>> b.args (x, 1) See Also ======== stringify_expr, eval_expr, standard_transformations, implicit_multiplication_application """ if local_dict is None: local_dict = {} elif not isinstance(local_dict, dict): raise TypeError('expecting local_dict to be a dict') if global_dict is None: global_dict = {} exec_('from sympy import *', global_dict) elif not isinstance(global_dict, dict): raise TypeError('expecting global_dict to be a dict') transformations = transformations or () if transformations: if not iterable(transformations): raise TypeError( '`transformations` should be a list of functions.') for _ in transformations: if not callable(_): raise TypeError(filldedent(''' expected a function in `transformations`, not %s''' % func_name(_))) if arity(_) != 3: raise TypeError(filldedent(''' a transformation should be function that takes 3 arguments''')) code = stringify_expr(s, local_dict, global_dict, transformations) if not evaluate: code = compile(evaluateFalse(code), '<string>', 'eval') return eval_expr(code, local_dict, global_dict)
_transformation = { # items can be added but never re-ordered 0: lambda_notation, 1: auto_symbol, 2: repeated_decimals, 3: auto_number, 4: factorial_notation, 5: implicit_multiplication_application, 6: convert_xor, 7: implicit_application, 8: implicit_multiplication, 9: convert_equals_signs, 10: function_exponentiation, 11: rationalize} transformations = '\n'.join('%s: %s' % (i, func_name(f)) for i, f in _transformation.items()) class _T(): """class to retrieve transformations from a given slice EXAMPLES ======== >>> from sympy.parsing.sympy_parser import T, standard_transformations >>> assert T[:5] == standard_transformations """ def __init__(self): self.N = len(_transformation) def __str__(self):
_transformation = { # items can be added but never re-ordered 0: lambda_notation, 1: auto_symbol, 2: repeated_decimals, 3: auto_number, 4: factorial_notation, 5: implicit_multiplication_application, 6: convert_xor, 7: implicit_application, 8: implicit_multiplication, 9: convert_equals_signs, 10: function_exponentiation, 11: rationalize } transformations = '\n'.join('%s: %s' % (i, func_name(f)) for i, f in _transformation.items()) class _T(): """class to retrieve transformations from a given slice EXAMPLES ======== >>> from sympy.parsing.sympy_parser import T, standard_transformations >>> assert T[:5] == standard_transformations """ def __init__(self): self.N = len(_transformation)
def parse_expr(s, local_dict=None, transformations=standard_transformations, global_dict=None, evaluate=True): """Converts the string ``s`` to a SymPy expression, in ``local_dict`` Parameters ========== s : str The string to parse. local_dict : dict, optional A dictionary of local variables to use when parsing. global_dict : dict, optional A dictionary of global variables. By default, this is initialized with ``from sympy import *``; provide this parameter to override this behavior (for instance, to parse ``"Q & S"``). transformations : tuple, optional A tuple of transformation functions used to modify the tokens of the parsed expression before evaluation. The default transformations convert numeric literals into their SymPy equivalents, convert undefined variables into SymPy symbols, and allow the use of standard mathematical factorial notation (e.g. ``x!``). evaluate : bool, optional When False, the order of the arguments will remain as they were in the string and automatic simplification that would normally occur is suppressed. (see examples) Examples ======== >>> from sympy.parsing.sympy_parser import parse_expr >>> parse_expr("1/2") 1/2 >>> type(_) <class 'sympy.core.numbers.Half'> >>> from sympy.parsing.sympy_parser import standard_transformations,\\ ... implicit_multiplication_application >>> transformations = (standard_transformations + ... (implicit_multiplication_application,)) >>> parse_expr("2x", transformations=transformations) 2*x When evaluate=False, some automatic simplifications will not occur: >>> parse_expr("2**3"), parse_expr("2**3", evaluate=False) (8, 2**3) In addition the order of the arguments will not be made canonical. This feature allows one to tell exactly how the expression was entered: >>> a = parse_expr('1 + x', evaluate=False) >>> b = parse_expr('x + 1', evaluate=0) >>> a == b False >>> a.args (1, x) >>> b.args (x, 1) See Also ======== stringify_expr, eval_expr, standard_transformations, implicit_multiplication_application """ if local_dict is None: local_dict = {} elif not isinstance(local_dict, dict): raise TypeError('expecting local_dict to be a dict') if global_dict is None: global_dict = {} exec('from sympy import *', global_dict) elif not isinstance(global_dict, dict): raise TypeError('expecting global_dict to be a dict') transformations = transformations or () if transformations: if not iterable(transformations): raise TypeError('`transformations` should be a list of functions.') for _ in transformations: if not callable(_): raise TypeError( filldedent(''' expected a function in `transformations`, not %s''' % func_name(_))) if arity(_) != 3: raise TypeError( filldedent(''' a transformation should be function that takes 3 arguments''')) code = stringify_expr(s, local_dict, global_dict, transformations) if not evaluate: code = compile(evaluateFalse(code), '<string>', 'eval') try: rv = eval_expr(code, local_dict, global_dict) # restore neutral definitions for names for i in local_dict.pop(None, ()): local_dict[i] = None return rv except Exception as e: # restore neutral definitions for names for i in local_dict.pop(None, ()): local_dict[i] = None raise e from ValueError( f"Error from parse_expr with transformed code: {code!r}")