Example #1
0
    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]}
Example #2
0
    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]}
Example #3
0
    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}
Example #4
0
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]
Example #5
0
    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}
Example #6
0
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]
Example #7
0
    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
Example #8
0
 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
Example #9
0
 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()
Example #10
0
    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)
Example #11
0
    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
Example #12
0
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)
Example #13
0
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)
Example #14
0
    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)
Example #15
0
    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)
Example #16
0
 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)
Example #17
0
    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
Example #18
0
 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)
Example #19
0
 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
Example #20
0
 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
Example #21
0
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}")
Example #22
0
    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))
Example #23
0
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]
Example #24
0
    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)
Example #25
0
    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))
Example #26
0
    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))
Example #27
0
    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)
Example #28
0
    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))
Example #29
0
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)
Example #30
0
_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):
Example #31
0
_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)
Example #32
0
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}")