from basic import Basic
from core import C
from sympify import sympify
from singleton import S
from expr import Expr, AtomicExpr
from cache import cacheit
from function import FunctionClass
from sympy.logic.boolalg import Boolean
import re
import warnings
[docs]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__ = ['is_commutative', 'name']
is_Symbol = True
def __new__(cls, name, commutative=True, **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
"""
if 'dummy' in assumptions:
warnings.warn(
"\nThe syntax Symbol('x', dummy=True) is deprecated and will"
"\nbe dropped in a future version of Sympy. Please use Dummy()"
"\nor symbols(..., cls=Dummy) to create dummy symbols.",
DeprecationWarning)
if assumptions.pop('dummy'):
return Dummy(name, commutative, **assumptions)
return Symbol.__xnew_cached_(cls, name, commutative, **assumptions)
def __new_stage2__(cls, name, commutative=True, **assumptions):
assert isinstance(name, str),repr(type(name))
obj = Expr.__new__(cls, **assumptions)
obj.is_commutative = commutative
obj.name = name
return obj
__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, self.is_commutative)
def _hashable_content(self):
return (self.is_commutative, self.name)
def sort_key(self, order=None):
from sympy.core import S
return self.class_key(), (1, (str(self),)), S.One.sort_key(), S.One
def as_dummy(self):
assumptions = self.assumptions0.copy()
assumptions.pop('commutative', None)
return Dummy(self.name, self.is_commutative, **assumptions)
def __call__(self, *args):
from function import Function
return Function(self.name, nargs=len(args))(*args, **self.assumptions0)
def as_real_imag(self, deep=True):
return (C.re(self), C.im(self))
def _eval_expand_complex(self, deep=True, **hints):
re, im = self.as_real_imag()
return re + im*S.ImaginaryUnit
def _sage_(self):
import sage.all as sage
return sage.var(self.name)
@property
def is_number(self):
return False
@property
def free_symbols(self):
return set([self])
[docs]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._count = 0 # /!\ this should generally not be changed; it is being
>>> Dummy() # used here to make sure that the doctest passes.
_0
"""
_count = 0
__slots__ = ['dummy_index']
is_Dummy = True
def __new__(cls, name=None, commutative=True, **assumptions):
if name is None:
name = str(Dummy._count)
obj = Symbol.__xnew__(cls, name, commutative=commutative, **assumptions)
Dummy._count += 1
obj.dummy_index = Dummy._count
return obj
def _hashable_content(self):
return Symbol._hashable_content(self) + (self.dummy_index,)
[docs]class Wild(Symbol):
"""
Wild() matches any expression but another Wild().
"""
__slots__ = ['exclude', 'properties']
is_Wild = True
def __new__(cls, name, exclude=None, properties=None, **assumptions):
if type(exclude) is list:
exclude = tuple(exclude)
if type(properties) is list:
properties = tuple(properties)
return Wild.__xnew__(cls, name, exclude, properties, **assumptions)
def __getnewargs__(self):
return (self.name, self.exclude, self.properties)
@staticmethod
@cacheit
def __xnew__(cls, name, exclude, properties, **assumptions):
obj = Symbol.__xnew__(cls, name, **assumptions)
if exclude is None:
obj.exclude = None
else:
obj.exclude = tuple([sympify(x) for x in exclude])
if properties is None:
obj.properties = None
else:
obj.properties = tuple(properties)
return obj
def _hashable_content(self):
return (self.name, self.exclude, self.properties )
# TODO add check against another Wild
def matches(self, expr, repl_dict={}, evaluate=False):
if self in repl_dict:
if repl_dict[self] == expr:
return repl_dict
else:
return None
if self.exclude:
for x in self.exclude:
if x in expr:
return None
if self.properties:
for f in self.properties:
if not f(expr):
return None
repl_dict = repl_dict.copy()
repl_dict[self] = expr
return repl_dict
def __call__(self, *args, **assumptions):
from sympy.core.function import WildFunction
return WildFunction(self.name, nargs=len(args))(*args, **assumptions)
_re_var_range = re.compile(r"^(.*?)(\d*):(\d+)$")
_re_var_scope = re.compile(r"^(.):(.)$")
_re_var_split = re.compile(r"\s*,\s*|\s+")
[docs]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::
>>> symbols('x:10')
(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
>>> symbols('x5:10')
(x5, x6, x7, x8, x9)
>>> 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))
To reduce typing even more, lexicographic range syntax is supported::
>>> symbols('x:z')
(x, y, z)
>>> symbols('a:d,x:z')
(a, b, c, d, x, y, z)
>>> symbols(('a:d', 'x:z'))
((a, b, c, d), (x, y, z))
All newly created symbols have assumptions set accordingly 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 of
other type, for example 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'>
"""
result = []
if 'each_char' in args:
warnings.warn("The each_char option to symbols() and var() is "
"deprecated. Separate symbol names by spaces or commas instead.",
DeprecationWarning)
if isinstance(names, basestring):
names = names.strip()
as_seq= names.endswith(',')
if as_seq:
names = names[:-1].rstrip()
if not names:
raise ValueError('no symbols given')
names = _re_var_split.split(names)
if args.pop('each_char', False) and not as_seq and len(names) == 1:
return symbols(tuple(names[0]), **args)
cls = args.pop('cls', Symbol)
seq = args.pop('seq', as_seq)
for name in names:
if not name:
raise ValueError('missing symbol')
if ':' not in name:
symbol = cls(name, **args)
result.append(symbol)
continue
match = _re_var_range.match(name)
if match is not None:
name, start, end = match.groups()
if not start:
start = 0
else:
start = int(start)
for i in xrange(start, int(end)):
symbol = cls("%s%i" % (name, i), **args)
result.append(symbol)
seq = True
continue
match = _re_var_scope.match(name)
if match is not None:
start, end = match.groups()
for name in xrange(ord(start), ord(end)+1):
symbol = cls(chr(name), **args)
result.append(symbol)
seq = True
continue
raise ValueError("'%s' is not a valid symbol range specification" % name)
if not seq and len(result) <= 1:
if not result:
raise ValueError('missing symbol') # should never happen
return result[0]
return tuple(result)
else:
for name in names:
result.append(symbols(name, **args))
return type(names)(result)
[docs]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::
>>> 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