Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
from __future__ import print_function, division
from sympy.core.assumptions import StdFactKB from sympy.core.compatibility import string_types, range from .basic import Basic from .sympify import sympify from .singleton import S from .expr import Expr, AtomicExpr from .cache import cacheit from .function import FunctionClass from sympy.core.logic import fuzzy_bool from sympy.logic.boolalg import Boolean from sympy.utilities.iterables import cartes
import string import re as _re
class Symbol(AtomicExpr, Boolean): """ Assumptions: commutative = True
You can override the default assumptions in the constructor:
>>> from sympy import symbols >>> A,B = symbols('A,B', commutative = False) >>> bool(A*B != B*A) True >>> bool(A*B*2 == 2*A*B) == True # multiplication by scalars is commutative True
"""
is_comparable = False
__slots__ = ['name']
is_Symbol = True
@property def _diff_wrt(self): """Allow derivatives wrt Symbols.
Examples ========
>>> from sympy import Symbol >>> x = Symbol('x') >>> x._diff_wrt True """
@staticmethod def _sanitize(assumptions, obj=None): """Remove None, covert values to bool, check commutativity *in place*. """
# be strict about commutativity: cannot be None whose = '%s ' % obj.__name__ if obj else '' raise ValueError( '%scommutativity must be True or False.' % whose)
# sanitize other assumptions so 1 -> True and 0 -> False SymPyDeprecationWarning( feature="%s assumption" % key, useinstead="%s" % keymap[key], issue=8071, deprecated_since_version="0.7.6").warn() assumptions[keymap[key]] = assumptions[key] assumptions.pop(key) key = keymap[key]
assumptions.pop(key) continue
def __new__(cls, name, **assumptions): """Symbols are identified by name and assumptions::
>>> from sympy import Symbol >>> Symbol("x") == Symbol("x") True >>> Symbol("x", real=True) == Symbol("x", real=False) False
"""
def __new_stage2__(cls, name, **assumptions): raise TypeError("name should be a string, not %s" % repr(type(name)))
# TODO: Issue #8873: Forcing the commutative assumption here means # later code such as ``srepr()`` cannot tell whether the user # specified ``commutative=True`` or omitted it. To workaround this, # we keep a copy of the assumptions dict, then create the StdFactKB, # and finally overwrite its ``._generator`` with the dict copy. This # is a bit of a hack because we assume StdFactKB merely copies the # given dict as ``._generator``, but future modification might, e.g., # compute a minimal equivalent assumption set.
# be strict about commutativity
__xnew__ = staticmethod( __new_stage2__) # never cached (e.g. dummy) __xnew_cached_ = staticmethod( cacheit(__new_stage2__)) # symbols are always cached
def __getnewargs__(self): return (self.name,)
def __getstate__(self): return {'_assumptions': self._assumptions}
def _hashable_content(self): # Note: user-specified assumptions not hashed, just derived ones
@property def assumptions0(self): in self._assumptions.items() if value is not None)
@cacheit def sort_key(self, order=None):
def as_dummy(self): """Return a Dummy having the same name and same assumptions as self.""" return Dummy(self.name, **self._assumptions.generator)
def __call__(self, *args): from .function import Function return Function(self.name)(*args)
def as_real_imag(self, deep=True, **hints): else:
def _sage_(self): import sage.all as sage return sage.var(self.name)
def is_constant(self, *wrt, **flags): if not wrt: return False return not self in wrt
@property def free_symbols(self):
class Dummy(Symbol): """Dummy symbols are each unique, identified by an internal count index:
>>> from sympy import Dummy >>> bool(Dummy("x") == Dummy("x")) == True False
If a name is not supplied then a string value of the count index will be used. This is useful when a temporary variable is needed and the name of the variable used in the expression is not important.
>>> Dummy() #doctest: +SKIP _Dummy_10
"""
_count = 0
__slots__ = ['dummy_index']
is_Dummy = True
def __new__(cls, name=None, **assumptions):
def __getstate__(self): return {'_assumptions': self._assumptions, 'dummy_index': self.dummy_index}
@cacheit def sort_key(self, order=None): 2, (str(self), self.dummy_index)), S.One.sort_key(), S.One
def _hashable_content(self):
class Wild(Symbol): """ A Wild symbol matches anything, or anything without whatever is explicitly excluded.
Examples ========
>>> from sympy import Wild, WildFunction, cos, pi >>> from sympy.abc import x, y, z >>> a = Wild('a') >>> x.match(a) {a_: x} >>> pi.match(a) {a_: pi} >>> (3*x**2).match(a*x) {a_: 3*x} >>> cos(x).match(a) {a_: cos(x)} >>> b = Wild('b', exclude=[x]) >>> (3*x**2).match(b*x) >>> b.match(a) {a_: b_} >>> A = WildFunction('A') >>> A.match(a) {a_: A_}
Tips ====
When using Wild, be sure to use the exclude keyword to make the pattern more precise. Without the exclude pattern, you may get matches that are technically correct, but not what you wanted. For example, using the above without exclude:
>>> from sympy import symbols >>> a, b = symbols('a b', cls=Wild) >>> (2 + 3*y).match(a*x + b*y) {a_: 2/x, b_: 3}
This is technically correct, because (2/x)*x + 3*y == 2 + 3*y, but you probably wanted it to not match at all. The issue is that you really didn't want a and b to include x and y, and the exclude parameter lets you specify exactly this. With the exclude parameter, the pattern will not match.
>>> a = Wild('a', exclude=[x, y]) >>> b = Wild('b', exclude=[x, y]) >>> (2 + 3*y).match(a*x + b*y)
Exclude also helps remove ambiguity from matches.
>>> E = 2*x**3*y*z >>> a, b = symbols('a b', cls=Wild) >>> E.match(a*b) {a_: 2*y*z, b_: x**3} >>> a = Wild('a', exclude=[x, y]) >>> E.match(a*b) {a_: z, b_: 2*x**3*y} >>> a = Wild('a', exclude=[x, y, z]) >>> E.match(a*b) {a_: 2, b_: x**3*y*z}
""" is_Wild = True
__slots__ = ['exclude', 'properties']
def __new__(cls, name, exclude=(), properties=(), **assumptions):
def __getnewargs__(self): return (self.name, self.exclude, self.properties)
@staticmethod @cacheit def __xnew__(cls, name, exclude, properties, **assumptions):
def _hashable_content(self):
# TODO add check against another Wild def matches(self, expr, repl_dict={}, old=False): return None
def __call__(self, *args, **kwargs): raise TypeError("'%s' object is not callable" % type(self).__name__)
_range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])')
def symbols(names, **args): """ Transform strings into instances of :class:`Symbol` class.
:func:`symbols` function returns a sequence of symbols with names taken from ``names`` argument, which can be a comma or whitespace delimited string, or a sequence of strings::
>>> from sympy import symbols, Function
>>> x, y, z = symbols('x,y,z') >>> a, b, c = symbols('a b c')
The type of output is dependent on the properties of input arguments::
>>> symbols('x') x >>> symbols('x,') (x,) >>> symbols('x,y') (x, y) >>> symbols(('a', 'b', 'c')) (a, b, c) >>> symbols(['a', 'b', 'c']) [a, b, c] >>> symbols(set(['a', 'b', 'c'])) set([a, b, c])
If an iterable container is needed for a single symbol, set the ``seq`` argument to ``True`` or terminate the symbol name with a comma::
>>> symbols('x', seq=True) (x,)
To reduce typing, range syntax is supported to create indexed symbols. Ranges are indicated by a colon and the type of range is determined by the character to the right of the colon. If the character is a digit then all contiguous digits to the left are taken as the nonnegative starting value (or 0 if there is no digit left of the colon) and all contiguous digits to the right are taken as 1 greater than the ending value::
>>> symbols('x:10') (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
>>> symbols('x5:10') (x5, x6, x7, x8, x9) >>> symbols('x5(:2)') (x50, x51)
>>> symbols('x5:10,y:5') (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4)
>>> symbols(('x5:10', 'y:5')) ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4))
If the character to the right of the colon is a letter, then the single letter to the left (or 'a' if there is none) is taken as the start and all characters in the lexicographic range *through* the letter to the right are used as the range::
>>> symbols('x:z') (x, y, z) >>> symbols('x:c') # null range () >>> symbols('x(:c)') (xa, xb, xc)
>>> symbols(':c') (a, b, c)
>>> symbols('a:d, x:z') (a, b, c, d, x, y, z)
>>> symbols(('a:d', 'x:z')) ((a, b, c, d), (x, y, z))
Multiple ranges are supported; contiguous numerical ranges should be separated by parentheses to disambiguate the ending number of one range from the starting number of the next::
>>> symbols('x:2(1:3)') (x01, x02, x11, x12) >>> symbols(':3:2') # parsing is from left to right (00, 01, 10, 11, 20, 21)
Only one pair of parentheses surrounding ranges are removed, so to include parentheses around ranges, double them. And to include spaces, commas, or colons, escape them with a backslash::
>>> symbols('x((a:b))') (x(a), x(b)) >>> symbols('x(:1\,:2)') # or 'x((:1)\,(:2))' (x(0,0), x(0,1))
All newly created symbols have assumptions set according to ``args``::
>>> a = symbols('a', integer=True) >>> a.is_integer True
>>> x, y, z = symbols('x,y,z', real=True) >>> x.is_real and y.is_real and z.is_real True
Despite its name, :func:`symbols` can create symbol-like objects like instances of Function or Wild classes. To achieve this, set ``cls`` keyword argument to the desired type::
>>> symbols('f,g,h', cls=Function) (f, g, h)
>>> type(_[0]) <class 'sympy.core.function.UndefinedFunction'>
"""
while chr(marker) in names: marker += 1 lit_char = chr(marker) marker += 1 names = names.replace(lit, lit_char) literals.append((lit_char, lit[1:])) for c, l in literals: s = s.replace(c, l)
names = names[:-1].rstrip() raise ValueError('no symbols given')
# split on commas raise ValueError('missing symbol between commas') # split on spaces
raise ValueError('missing symbol')
# remove 1 layer of bounding parentheses around ranges split[i - 1].endswith('(') and \ split[i + 1].startswith(')'): split[i - 1] = split[i - 1][:-1] split[i + 1] = split[i + 1][1:] raise ValueError('missing end range') a = 0 if not a else int(a) b = int(b) split[i] = [str(c) for c in range(a, b)] else: string.ascii_letters.index(a), string.ascii_letters.index(b) + 1)] # inclusive break else: else: names = split[0] else: result.extend([cls(literal(s), **args) for s in names]) else:
return ()
else: for name in names: result.append(symbols(name, **args))
return type(names)(result)
def var(names, **args): """ Create symbols and inject them into the global namespace.
This calls :func:`symbols` with the same arguments and puts the results into the *global* namespace. It's recommended not to use :func:`var` in library code, where :func:`symbols` has to be used::
Examples ========
>>> from sympy import var
>>> var('x') x >>> x x
>>> var('a,ab,abc') (a, ab, abc) >>> abc abc
>>> var('x,y', real=True) (x, y) >>> x.is_real and y.is_real True
See :func:`symbol` documentation for more details on what kinds of arguments can be passed to :func:`var`.
""" def traverse(symbols, frame): """Recursively inject symbols to the global namespace. """ for symbol in symbols: if isinstance(symbol, Basic): frame.f_globals[symbol.name] = symbol elif isinstance(symbol, FunctionClass): frame.f_globals[symbol.__name__] = symbol else: traverse(symbol, frame)
from inspect import currentframe frame = currentframe().f_back
try: syms = symbols(names, **args)
if syms is not None: if isinstance(syms, Basic): frame.f_globals[syms.name] = syms elif isinstance(syms, FunctionClass): frame.f_globals[syms.__name__] = syms else: traverse(syms, frame) finally: del frame # break cyclic dependencies as stated in inspect docs
return syms |