def __new__(cls, expr, variables, point, **assumptions): if not ordered_iter(variables, Tuple): variables = [variables] variables = Tuple(*sympify(variables)) if uniq(variables) != variables: repeated = repeated = [ v for v in set(variables) if list(variables).count(v) > 1 ] raise ValueError('cannot substitute expressions %s more than ' 'once.' % repeated) if not ordered_iter(point, Tuple): point = [point] point = Tuple(*sympify(point)) if len(point) != len(variables): raise ValueError('Number of point values must be the same as ' 'the number of variables.') # it's necessary to use dummy variables internally new_variables = Tuple(*[ arg.as_dummy() if arg.is_Symbol else C.Dummy(str(arg)) for arg in variables ]) expr = sympify(expr).subs(tuple(zip(variables, new_variables))) if expr.is_commutative: assumptions['commutative'] = True obj = Expr.__new__(cls, expr, new_variables, point, **assumptions) return obj
def _symbolgen(*symbols): """ Generator of all symbols in the argument of the Derivative. Example: >> ._symbolgen(x, 3, y) (x, x, x, y) >> ._symbolgen(x, 10**6) (x, x, x, x, x, x, x, ...) The second example shows why we don't return a list, but a generator, so that the code that calls _symbolgen can return earlier for special cases, like x.diff(x, 10**6). """ last_s = sympify(symbols[len(symbols)-1]) for i in xrange(len(symbols)): s = sympify(symbols[i]) next_s = None if s != last_s: next_s = sympify(symbols[i+1]) if isinstance(s, Integer): continue elif isinstance(s, Symbol): # handle cases like (x, 3) if isinstance(next_s, Integer): # yield (x, x, x) for copy_s in repeat(s,int(next_s)): yield copy_s else: yield s else: yield s
def series(self, x, point=0, n=6, dir="+"): """ Series expansion of "self" around "point". Usage: Returns the Taylor (Laurent or generalized) series of "self" around the point "point" (default 0) with respect to "x" until the n-th term (default n is 6). For dir="+" (default) it calculates the series from the right and for dir="-" the series from the left. For smooth functions this argument doesn't matter. Notes: This method is the most high level method and it returns the series including the O(x**n) term. Internally, it executes a method nseries(), see nseries() docstring for more information. """ x = sympify(x) point = sympify(point) if dir == "+": return self.nseries(x, point, n) elif dir == "-": return self.subs(x, -x).nseries(x, -point, n).subs(x, -x) else: raise ValueError("Dir has to be '+' or '-'")
def __new__(cls, expr, *symbols, **assumptions): expr = sympify(expr) if not symbols: return expr symbols = Derivative._symbolgen(*symbols) if expr.is_commutative: assumptions['commutative'] = True evaluate = assumptions.pop('evaluate', False) if not evaluate and not isinstance(expr, Derivative): symbols = list(symbols) if len(symbols) == 0: # We make a special case for 0th derivative, because there # is no good way to unambiguously print this. return expr obj = Expr.__new__(cls, expr, *symbols, **assumptions) return obj unevaluated_symbols = [] for s in symbols: s = sympify(s) if not isinstance(s, C.Symbol): raise ValueError('Invalid literal: %s is not a valid variable' % s) obj = expr._eval_derivative(s) if obj is None: unevaluated_symbols.append(s) elif obj is S.Zero: return S.Zero else: expr = obj if not unevaluated_symbols: return expr return Expr.__new__(cls, expr, *unevaluated_symbols, **assumptions)
def as_leading_term(self, *symbols): """ Returns the leading term. Example: >>> from sympy.abc import x >>> (1+x+x**2).as_leading_term(x) 1 >>> (1/x**2+x+x**2).as_leading_term(x) x**(-2) Note: self is assumed to be the result returned by Basic.series(). """ from sympy import powsimp if len(symbols)>1: c = self for x in symbols: c = c.as_leading_term(x) return c elif not symbols: return self x = sympify(symbols[0]) assert x.is_Symbol, `x` if not self.has(x): return self obj = self._eval_as_leading_term(x) if obj is not None: return powsimp(obj, deep=True, combine='exp') raise NotImplementedError('as_leading_term(%s, %s)' % (self, x))
def has(self, *patterns): """ Return True if self has any of the patterns. Example: >>> from sympy.abc import x >>> (2*x).has(x) True >>> (2*x/x).has(x) False """ from sympy.utilities.iterables import flatten from sympy.core.symbol import Wild if len(patterns)>1: for p in patterns: if self.has(p): return True return False elif not patterns: raise TypeError("has() requires at least 1 argument (got none)") p = sympify(patterns[0]) if isinstance(p, BasicType): return bool(self.atoms(p)) if p.is_Atom and not isinstance(p, Wild): return p in self.atoms(p.func) if p.matches(self) is not None: return True for e in flatten(self.args): if isinstance(e, Basic) and e.has(p): return True return False
def _has(p): p = sympify(p) if isinstance(p, BasicType): return search(self, lambda w: isinstance(w, p), lambda w: True) if p.is_Atom and not isinstance(p, Wild): return search(self, lambda w: isinstance(w, p.func), lambda w: w in [p]) return search(self, lambda w: p.matches(w) is not None, lambda w: True)
def find(self, query, group=False): """Find all subexpressions matching a query. """ if not callable(query): query = sympify(query) if isinstance(query, type): _query = lambda expr: isinstance(expr, query) elif isinstance(query, Basic): _query = lambda expr: expr.match(query) else: _query = query results = [] def rec_find(expr): q = _query(expr) if q or q == {}: results.append(expr) for arg in expr.args: rec_find(arg) rec_find(self) if not group: return set(results) else: groups = {} for result in results: if result in groups: groups[result] += 1 else: groups[result] = 1 return groups
def matches(self, expr, repl_dict={}, evaluate=False): """ Helper method for match() - switches the pattern and expr. Can be used to solve linear equations: >>> from sympy import Symbol, Wild, Integer >>> a,b = map(Symbol, 'ab') >>> x = Wild('x') >>> (a+b*x).matches(Integer(0)) {x_: -a/b} """ if evaluate: return self.subs(repl_dict).matches(expr, repl_dict) expr = sympify(expr) if not isinstance(expr, self.__class__): return None if self == expr: return repl_dict if len(self.args) != len(expr.args): return None d = repl_dict.copy() for arg, other_arg in zip(self.args, expr.args): if arg == other_arg: continue d = arg.subs(d).matches(other_arg, d) if d is None: return None return d
def match(self, pattern): """ Pattern matching. Wild symbols match all. Return None when expression (self) does not match with pattern. Otherwise return a dictionary such that pattern.subs(self.match(pattern)) == self Example: >>> from sympy import symbols, Wild >>> from sympy.abc import x, y >>> p = Wild("p") >>> q = Wild("q") >>> r = Wild("r") >>> e = (x+y)**(x+y) >>> e.match(p**p) {p_: x + y} >>> e.match(p**q) {p_: x + y, q_: x + y} >>> e = (2*x)**2 >>> e.match(p*q**r) {p_: 4, q_: x, r_: 2} >>> (p*q**r).subs(e.match(p*q**r)) 4*x**2 """ pattern = sympify(pattern) return pattern.matches(self)
def __new__(cls, name, exclude=(), properties=(), **assumptions): exclude = tuple([sympify(x) for x in exclude]) properties = tuple(properties) is_commutative = fuzzy_bool(assumptions.get("commutative", True)) if is_commutative is None: raise ValueError("""Wild's commutativity must be True or False.""") assumptions["commutative"] = is_commutative return Wild.__xnew__(cls, name, exclude, properties, **assumptions)
def taylor_term(cls, n, x, *previous_terms): """General method for the taylor term. This method is slow, because it differentiates n-times. Subclasses can redefine it to make it faster by using the "previous_terms". """ x = sympify(x) return cls(x).diff(x, n).subs(x, 0) * x**n / C.Factorial(n)
def __sympifyit_wrapper(a, b): try: # If an external class has _op_priority, it knows how to deal # with sympy objects. Otherwise, it must be converted. if not hasattr(b, '_op_priority'): b = sympify(b, strict=True) return func(a, b) except SympifyError: return retval
def _matches(self, expr, repl_dict={}): # weed out negative one prefixes sign = 1 a, b = self.as_two_terms() if a is S.NegativeOne: if b.is_Mul: sign = -sign else: # the remainder, b, is not a Mul anymore return b.matches(-expr, repl_dict) expr = sympify(expr) if expr.is_Mul and expr.args[0] is S.NegativeOne: expr = -expr sign = -sign if not expr.is_Mul: # expr can only match if it matches b and a matches +/- 1 if len(self.args) == 2: # quickly test for equality if b == expr: return a.matches(Rational(sign), repl_dict) # do more expensive match dd = b.matches(expr, repl_dict) if dd == None: return None dd = a.matches(Rational(sign), dd) return dd return None d = repl_dict.copy() # weed out identical terms pp = list(self.args) ee = list(expr.args) for p in self.args: if p in expr.args: ee.remove(p) pp.remove(p) # only one symbol left in pattern -> match the remaining expression if len(pp) == 1 and isinstance(pp[0], C.Wild): if len(ee) == 1: d[pp[0]] = sign * ee[0] else: d[pp[0]] = sign * expr.func(*ee) return d if len(ee) != len(pp): return None for p, e in zip(pp, ee): d = p.xreplace(d).matches(e, d) if d is None: return None return d
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 as_mpmath(x, prec, options): x = sympify(x) if isinstance(x, C.Zero): return mpf(0) if isinstance(x, C.Infinity): return mpf("inf") if isinstance(x, C.NegativeInfinity): return mpf("-inf") # XXX re, im, _, _ = evalf(x, prec, options) if im: return mpc(re or fzero, im) return mpf(re)
def _match(pattern): pattern = sympify(pattern) if isinstance(pattern, BasicType): return lambda expr: (isinstance(expr, pattern) or (isinstance(expr, BasicType) and expr == pattern)) else: if pattern.is_Add or pattern.is_Mul: iterative, (c, nc) = True, _ncsplit(pattern) else: iterative, (c, nc) = False, (None, None) return lambda expr: _contains(expr, pattern, iterative, c, nc)
def expand_trig(expr, deep=True): """ Wrapper around expand that only uses the trig hint. See the expand docstring for more information. Example: >>> from sympy import * >>> x, y = symbols('xy') >>> expand_trig(sin(x+y)*(x+y)) (x + y)*(cos(x)*sin(y) + cos(y)*sin(x)) """ return sympify(expr).expand(deep=deep, trig=True, basic=False,\ log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
def expand_func(expr, deep=True): """ Wrapper around expand that only uses the func hint. See the expand docstring for more information. Example: >>> from sympy import * >>> x = Symbol('x') >>> expand_func(gamma(x + 2)) x*(1 + x)*gamma(x) """ return sympify(expr).expand(deep=deep, func=True, basic=False,\ log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
def expand_log(expr, deep=True): """ Wrapper around expand that only uses the log hint. See the expand docstring for more information. Example: >>> from sympy import * >>> x, y = symbols('xy', positive=True) >>> expand_log(exp(x+y)*(x+y)*log(x*y**2)) (x + y)*(2*log(y) + log(x))*exp(x + y) """ return sympify(expr).expand(deep=deep, log=True, mul=False,\ power_exp=False, power_base=False, multinomial=False, basic=False)
def expand_complex(expr, deep=True): """ Wrapper around expand that only uses the complex hint. See the expand docstring for more information. Example: >>> from sympy import * >>> z = Symbol('z') >>> expand_complex(z**(2*I)) I*im(z**(2*I)) + re(z**(2*I)) """ return sympify(expr).expand(deep=deep, complex=True, basic=False,\ log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
def as_coeff_exponent(self, x): """ c*x**e -> c,e where x can be any symbolic expression. """ x = sympify(x) wc = Wild('wc') we = Wild('we') p = wc*x**we from sympy import collect self = collect(self, x) d = self.match(p) if d is not None and we in d: return d[wc], d[we] return self, S.Zero
def expand_mul(expr, deep=True): """ Wrapper around expand that only uses the mul hint. See the expand docstring for more information. Example: >>> from sympy import symbols, expand_mul, exp, log >>> x, y = symbols('x,y', positive=True) >>> expand_mul(exp(x+y)*(x+y)*log(x*y**2)) x*exp(x + y)*log(x*y**2) + y*exp(x + y)*log(x*y**2) """ return sympify(expr).expand(deep=deep, mul=True, power_exp=False,\ power_base=False, basic=False, multinomial=False, log=False)
def expand_multinomial(expr, deep=True): """ Wrapper around expand that only uses the multinomial hint. See the expand docstring for more information. Example: >>> from sympy import symbols, expand_multinomial, exp >>> x, y = symbols('x y', positive=True) >>> expand_multinomial((x + exp(x + 1))**2) x**2 + 2*x*exp(1 + x) + exp(2 + 2*x) """ return sympify(expr).expand(deep=deep, mul=False, power_exp=False,\ power_base=False, basic=False, multinomial=True, log=False)
def expand_multinomial(expr, deep=True): """ Wrapper around expand that only uses the multinomial hint. See the expand docstring for more information. Example: >>> from sympy import symbols, expand_multinomial, exp >>> x, y = symbols('x y', positive=True) >>> expand_multinomial((x + exp(x + 1))**2) x**2 + 2*x*exp(x + 1) + exp(2*x + 2) """ return sympify(expr).expand(deep=deep, mul=False, power_exp=False,\ power_base=False, basic=False, multinomial=True, log=False)
def __new__(cls, variables, expr): try: variables = Tuple(*variables) except TypeError: variables = Tuple(variables) if len(variables) == 1 and variables[0] == expr: return S.IdentityFunction #use dummy variables internally, just to be sure new_variables = [C.Dummy(arg.name) for arg in variables] expr = sympify(expr).subs(tuple(zip(variables, new_variables))) obj = Expr.__new__(cls, Tuple(*new_variables), expr) return obj
def __new__(cls, *args, **options): args = (sympify(arg) for arg in args) try: _args = frozenset(cls._new_args_filter(args)) except ShortCircuit: return cls.zero if not _args: return cls.identity elif len(_args) == 1: return set(_args).pop() else: obj = Expr.__new__(cls, _args) obj._argset = _args return obj
def expand_log(expr, deep=True): """ Wrapper around expand that only uses the log hint. See the expand docstring for more information. Example: >>> from sympy import symbols, expand_log, exp, log >>> x, y = symbols('x,y', positive=True) >>> expand_log(exp(x+y)*(x+y)*log(x*y**2)) (x + y)*(log(x) + 2*log(y))*exp(x + y) """ return sympify(expr).expand(deep=deep, log=True, mul=False,\ power_exp=False, power_base=False, multinomial=False, basic=False)
def __new__(cls, *args, **assumptions): args = (sympify(arg) for arg in args) try: _args = frozenset(cls._new_args_filter(args)) except ShortCircuit: return cls.zero if not _args: return cls.identity elif len(_args) == 1: return set(_args).pop() else: obj = Expr.__new__(cls, _args, **assumptions) obj._argset = _args return obj
def expand_trig(expr, deep=True): """ Wrapper around expand that only uses the trig hint. See the expand docstring for more information. Example: >>> from sympy import expand_trig, sin, cos >>> from sympy.abc import x, y >>> expand_trig(sin(x+y)*(x+y)) (x + y)*(sin(x)*cos(y) + sin(y)*cos(x)) """ return sympify(expr).expand(deep=deep, trig=True, basic=False,\ log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
def expand_func(expr, deep=True): """ Wrapper around expand that only uses the func hint. See the expand docstring for more information. Example: >>> from sympy import expand_func, gamma >>> from sympy.abc import x >>> expand_func(gamma(x + 2)) x*(x + 1)*gamma(x) """ return sympify(expr).expand(deep=deep, func=True, basic=False,\ log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
def expand_complex(expr, deep=True): """ Wrapper around expand that only uses the complex hint. See the expand docstring for more information. Example: >>> from sympy import expand_complex, I, im, re >>> from sympy.abc import z >>> expand_complex(z**(2*I)) I*im(z**(2*I)) + re(z**(2*I)) """ return sympify(expr).expand(deep=deep, complex=True, basic=False,\ log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
def _contains(self, other): """ Tests whether an element, other, is in the set. Relies on Python's set class. This tests for object equality All inputs are sympified >>> from sympy import FiniteSet >>> 1 in FiniteSet(1, 2) True >>> 5 in FiniteSet(1, 2) False """ return sympify(other) in self.elements
def N(x, n=15, **options): """ Calls x.evalf(n, **options). Both .evalf() and N() are equivalent, use the one that you like better. Example: >>> from sympy import Sum, Symbol, oo >>> k = Symbol("k") >>> Sum(1/k**k, (k, 1, oo)) Sum(k**(-k), (k, 1, oo)) >>> N(Sum(1/k**k, (k, 1, oo)), 4) 1.291 """ return sympify(x).evalf(n, **options)
def N(x, n=15, **options): """ Calls x.evalf(n, **options). Both .evalf() and N() are equivalent, use the one that you like better. Example: >>> from sympy import Sum, Symbol, oo, N >>> from sympy.abc import k >>> Sum(1/k**k, (k, 1, oo)) Sum(k**(-k), (k, 1, oo)) >>> N(Sum(1/k**k, (k, 1, oo)), 4) 1.291 """ return sympify(x).evalf(n, **options)
def evalf_symbol(x, prec, options): val = options["subs"][x] if isinstance(val, mpf): if not val: return None, None, None, None return val._mpf_, None, prec, None else: if not "_cache" in options: options["_cache"] = {} cache = options["_cache"] cached, cached_prec = cache.get(x.name, (None, MINUS_INF)) if cached_prec >= prec: return cached v = evalf(sympify(val), prec, options) cache[x.name] = (v, prec) return v
def evalf_symbol(x, prec, options): val = options['subs'][x] if isinstance(val, mpf): if not val: return None, None, None, None return val._mpf_, None, prec, None else: if not '_cache' in options: options['_cache'] = {} cache = options['_cache'] cached, cached_prec = cache.get(x.name, (None, MINUS_INF)) if cached_prec >= prec: return cached v = evalf(sympify(val), prec, options) cache[x.name] = (v, prec) return v
def coeff(self, x, expand=True): """ Returns the coefficient of the term "x" or None if there is no "x". Optional expand keyword argument allows one to control whether the expression is expanded before terms are collected, which can be useful if the term "x" isn't nested inside of terms and you don't want the returned coefficient to be expanded. Example: >>> from sympy import symbols >>> from sympy.abc import x, y, z >>> (3+2*x+4*x**2).coeff(1) >>> (3+2*x+4*x**2).coeff(x) 2 >>> (3+2*x+4*x**2).coeff(x**2) 4 >>> (3+2*x+4*x**2).coeff(x**3) >>> (z*(x+y)**2).coeff(z) 2*x*y + x**2 + y**2 >>> (z*(x+y)**2).coeff(z, expand=False) (x + y)**2 >>> """ from sympy import collect x = sympify(x) const = x.as_coeff_mul()[0] # constant multiplying x if const != S.One: # get rid of constants result = self.coeff(x / const) if result is not None: return (result / const) else: return None if x.is_Integer: return result = self if expand: result = result.expand( ) # collect expects its arguments in expanded form result = collect(result, x, evaluate=False, exact=True) if x in result: return result[x] else: return None
def _subs_dict(self, sequence): """Performs sequential substitution. Given a collection of key, value pairs, which correspond to old and new expressions respectively, substitute all given pairs handling properly all overlapping keys (according to 'in' relation). We have to use naive O(n**2) sorting algorithm, as 'in' gives only partial order and all asymptotically faster fail (depending on the initial order). >>> from sympy import sqrt, sin, cos, exp >>> from sympy.abc import x, y >>> from sympy.abc import a, b, c, d, e >>> A = (sqrt(sin(2*x)), a) >>> B = (sin(2*x), b) >>> C = (cos(2*x), c) >>> D = (x, d) >>> E = (exp(x), e) >>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x) >>> expr._subs_dict([A,B,C,D,E]) a*c*sin(d*e) + b """ sequence = sympify(sequence) if isinstance(sequence, dict): sequence = sequence.items() subst = [] for pattern in sequence: for i, (expr, _) in enumerate(subst): if expr.has(pattern[0]): subst.insert(i, pattern) break else: subst.append(pattern) subst.reverse() return self._subs_list(subst)
def N(x, n=15, **options): """ Calls x.evalf(n, \*\*options). Both .n() and N() are equivalent to .evalf(); use the one that you like better. See also the docstring of .evalf() for information on the options. Examples ======== >>> from sympy import Sum, oo, N >>> from sympy.abc import k >>> Sum(1/k**k, (k, 1, oo)) Sum(k**(-k), (k, 1, oo)) >>> N(_, 4) 1.291 """ return sympify(x).evalf(n, **options)
def leadterm(self, x): """ Returns the leading term a*x**b as a tuple (a, b). Example: >>> from sympy.abc import x >>> (1+x+x**2).leadterm(x) (1, 0) >>> (1/x**2+x+x**2).leadterm(x) (1, -2) Note: self is assumed to be the result returned by Basic.series(). """ from sympy import powsimp x = sympify(x) c, e = self.as_leading_term(x).as_coeff_exponent(x) c = powsimp(c, deep=True, combine='exp') if not c.has(x): return c, e raise ValueError("cannot compute leadterm(%s, %s), got c=%s" % (self, x, c))
def subs(self, *args, **kwargs): """ Substitutes old for new in an expression after sympifying args. `args` is either: - two arguments, e.g. foo.subs(old, new) - one iterable argument, e.g. foo.subs(iterable). The iterable may be o an iterable container with (old, new) pairs. In this case the replacements are processed in the order given with successive patterns possibly affecting replacements already made. o a dict or set whose key/value items correspond to old/new pairs. In this case the old/new pairs will be sorted by op count and in case of a tie, by number of args and the default_sort_key. The resulting sorted list is then processed as an iterable container (see previous). If the keyword ``simultaneous`` is True, the subexpressions will not be evaluated until all the substitutions have been made. Examples ======== >>> from sympy import pi, exp >>> from sympy.abc import x, y >>> (1 + x*y).subs(x, pi) pi*y + 1 >>> (1 + x*y).subs({x:pi, y:2}) 1 + 2*pi >>> (1 + x*y).subs([(x, pi), (y, 2)]) 1 + 2*pi >>> reps = [(y, x**2), (x, 2)] >>> (x + y).subs(reps) 6 >>> (x + y).subs(reversed(reps)) x**2 + 2 >>> (x**2 + x**4).subs(x**2, y) y**2 + y To replace only the x**2 but not the x**4, use xreplace: >>> (x**2 + x**4).xreplace({x**2: y}) x**4 + y To delay evaluation until all substitutions have been made, set the keyword ``simultaneous`` to True: >>> (x/y).subs([(x, 0), (y, 0)]) 0 >>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True) nan This has the added feature of not allowing subsequent substitutions to affect those already made: >>> ((x + y)/y).subs({x + y: y, y: x + y}) 1 >>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True) y/(x + y) In order to obtain a canonical result, unordered iterables are sorted by count_op length, number of arguments and by the default_sort_key to break any ties. All other iterables are left unsorted. >>> from sympy import sqrt, sin, cos, exp >>> from sympy.abc import a, b, c, d, e >>> A = (sqrt(sin(2*x)), a) >>> B = (sin(2*x), b) >>> C = (cos(2*x), c) >>> D = (x, d) >>> E = (exp(x), e) >>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x) >>> expr.subs(dict([A,B,C,D,E])) a*c*sin(d*e) + b See Also ======== replace: replacement capable of doing wildcard-like matching, parsing of match, and conditional replacements xreplace: exact node replacement in expr tree; also capable of using matching rules """ from sympy.core.containers import Dict from sympy.utilities import default_sort_key unordered = False if len(args) == 1: sequence = args[0] if isinstance(sequence, set): unordered = True elif isinstance(sequence, (Dict, dict)): unordered = True sequence = sequence.items() elif not iterable(sequence): from sympy.utilities.misc import filldedent raise ValueError( filldedent(""" When a single argument is passed to subs it should be an iterable of (old, new) tuples.""")) elif len(args) == 2: sequence = [args] else: raise ValueError("subs accepts either 1 or 2 arguments") sequence = list(sequence) for i in range(len(sequence)): o, n = sequence[i] so, sn = sympify(o), sympify(n) if not isinstance(so, Basic): if type(o) is str: so = C.Symbol(o) sequence[i] = (so, sn) if _aresame(so, sn): sequence[i] = None continue sequence = filter(None, sequence) if unordered: sequence = dict(sequence) if not all(k.is_Atom for k in sequence): d = {} for o, n in sequence.iteritems(): try: ops = o.count_ops(), len(o.args) except TypeError: ops = (0, 0) d.setdefault(ops, []).append((o, n)) newseq = [] for k in sorted(d.keys(), reverse=True): newseq.extend( sorted([v[0] for v in d[k]], key=default_sort_key)) sequence = [(k, sequence[k]) for k in newseq] del newseq, d else: sequence = sorted([(k, v) for (k, v) in sequence.iteritems()], key=default_sort_key) if kwargs.pop('simultaneous', False): # XXX should this be the default for dict subs? reps = {} rv = self for old, new in sequence: d = C.Dummy() rv = rv._subs(old, d) reps[d] = new if not isinstance(rv, Basic): break return rv.xreplace(reps) else: rv = self for old, new in sequence: rv = rv._subs(old, new) if not isinstance(rv, Basic): break return rv
def count_ops(expr, visual=False): """ Return a representation (integer or expression) of the operations in expr. If `visual` is False (default) then the sum of the coefficients of the visual expression will be returned. If `visual` is True then the number of each type of operation is shown with the core class types (or their virtual equivalent) multiplied by the number of times they occur. If expr is an iterable, the sum of the op counts of the items will be returned. Examples: >>> from sympy.abc import a, b, x, y >>> from sympy import sin, count_ops Although there isn't a SUB object, minus signs are interpreted as either negations or subtractions: >>> (x - y).count_ops(visual=True) SUB >>> (-x).count_ops(visual=True) NEG Here, there are two Adds and a Pow: >>> (1 + a + b**2).count_ops(visual=True) POW + 2*ADD In the following, an Add, Mul, Pow and two functions: >>> (sin(x)*x + sin(x)**2).count_ops(visual=True) ADD + MUL + POW + 2*SIN for a total of 5: >>> (sin(x)*x + sin(x)**2).count_ops(visual=False) 5 Note that "what you type" is not always what you get. The expression 1/x/y is translated by sympy into 1/(x*y) so it gives a DIV and MUL rather than two DIVs: >>> (1/x/y).count_ops(visual=True) DIV + MUL The visual option can be used to demonstrate the difference in operations for expressions in different forms. Here, the Horner representation is compared with the expanded form of a polynomial: >>> eq=x*(1 + x*(2 + x*(3 + x))) >>> count_ops(eq.expand(), visual=True) - count_ops(eq, visual=True) -MUL + 3*POW The count_ops function also handles iterables: >>> count_ops([x, sin(x), None, True, x + 2], visual=False) 2 >>> count_ops([x, sin(x), None, True, x + 2], visual=True) ADD + SIN >>> count_ops({x: sin(x), x + 2: y + 1}, visual=True) SIN + 2*ADD """ from sympy.simplify.simplify import fraction expr = sympify(expr) if isinstance(expr, Expr): ops = [] args = [expr] NEG = C.Symbol('NEG') DIV = C.Symbol('DIV') SUB = C.Symbol('SUB') ADD = C.Symbol('ADD') def isneg(a): c = a.as_coeff_mul()[0] return c.is_Number and c.is_negative while args: a = args.pop() if a.is_Rational: #-1/3 = NEG + DIV if a is not S.One: if a.p < 0: ops.append(NEG) if a.q != 1: ops.append(DIV) continue elif a.is_Mul: if isneg(a): ops.append(NEG) if a.args[0] is S.NegativeOne: a = a.as_two_terms()[1] else: a = -a n, d = fraction(a) if n.is_Integer: ops.append(DIV) if n < 0: ops.append(NEG) args.append(d) continue # won't be -Mul but could be Add elif d is not S.One: if not d.is_Integer: args.append(d) ops.append(DIV) args.append(n) continue # could be -Mul elif a.is_Add: aargs = list(a.args) negs = 0 for i, ai in enumerate(aargs): if isneg(ai): negs += 1 args.append(-ai) if i > 0: ops.append(SUB) else: args.append(ai) if i > 0: ops.append(ADD) if negs == len(aargs): # -x - y = NEG + SUB ops.append(NEG) elif isneg(aargs[0] ): # -x + y = SUB, but we already recorded an ADD ops.append(SUB - ADD) continue if a.is_Pow and a.exp is S.NegativeOne: ops.append(DIV) args.append(a.base) # won't be -Mul but could be Add continue if (a.is_Mul or a.is_Pow or a.is_Function or isinstance(a, Derivative) or isinstance(a, C.Integral)): o = C.Symbol(a.func.__name__.upper()) # count the args if (a.is_Mul or isinstance(a, C.LatticeOp)): ops.append(o * (len(a.args) - 1)) else: ops.append(o) args.extend(a.args) elif type(expr) is dict: ops = [ count_ops(k, visual=visual) + count_ops(v, visual=visual) for k, v in expr.iteritems() ] elif hasattr(expr, '__iter__'): ops = [count_ops(i, visual=visual) for i in expr] elif not isinstance(expr, Basic): ops = [] else: # it's Basic not isinstance(expr, Expr): assert isinstance(expr, Basic) ops = [count_ops(a, visual=visual) for a in expr.args] if not ops: if visual: return S.Zero return 0 ops = Add(*ops) if visual: return ops if ops.is_Number: return int(ops) return sum(int((a.args or [1])[0]) for a in Add.make_args(ops))
def __new__(cls, *args, **assumptions): args = [sympify(arg) for arg in args] obj = Basic.__new__(cls, *args, **assumptions) return obj
def __pow__(self, exp): if not sympify(exp).is_Integer and exp>=0: raise ValueError("%s: Exponent must be a positive Integer"%exp) return ProductSet([self]*exp)
def __sympifyit_wrapper(a, b): return func(a, sympify(b, strict=True))
def _matches(self, expr, repl_dict={}, evaluate=False): # weed out negative one prefixes sign = 1 if self.args[0] == -1: self = -self sign = -sign if expr.is_Mul and expr.args[0] == -1: expr = -expr sign = -sign if evaluate: return self.subs(repl_dict).matches(expr, repl_dict) expr = sympify(expr) if not isinstance(expr, self.__class__): # if we can omit the first factor, we can match it to sign * one if Mul(*self.args[1:]) == expr: return self.args[0].matches(Rational(sign), repl_dict, evaluate) # two-factor product: if the 2nd factor matches, the first part must be sign * one if len(self.args[:]) == 2: dd = self.args[1].matches(expr, repl_dict, evaluate) if dd == None: return None dd = self.args[0].matches(Rational(sign), dd, evaluate) return dd return None if len(self.args[:]) == 0: if self == expr: return repl_dict return None d = repl_dict.copy() # weed out identical terms pp = list(self.args) ee = list(expr.args) for p in self.args: if p in expr.args: ee.remove(p) pp.remove(p) # only one symbol left in pattern -> match the remaining expression from symbol import Wild if len(pp) == 1 and isinstance(pp[0], Wild): if len(ee) == 1: d[pp[0]] = sign * ee[0] else: d[pp[0]] = sign * (type(expr)(*ee)) return d if len(ee) != len(pp): return None i = 0 for p, e in zip(pp, ee): if i == 0 and sign != 1: try: e = sign * e except TypeError: return None d = p.matches(e, d, evaluate=not i) i += 1 if d is None: return None return d
def _matches(self, expr, repl_dict={}, evaluate=False): if evaluate: return self.subs(repl_dict).matches(expr, repl_dict) # weed out negative one prefixes sign = 1 a, b = self.as_two_terms() if a is S.NegativeOne: if b.is_Mul: sign = -sign else: # the remainder, b, is not a Mul anymore return b.matches(-expr, repl_dict, evaluate) expr = sympify(expr) if expr.is_Mul and expr.args[0] is S.NegativeOne: expr = -expr sign = -sign if not expr.is_Mul: # expr can only match if it matches b and a matches +/- 1 if len(self.args) == 2: # quickly test for equality if b == expr: return a.matches(Rational(sign), repl_dict, evaluate) # do more expensive match dd = b.matches(expr, repl_dict, evaluate) if dd == None: return None dd = a.matches(Rational(sign), dd, evaluate) return dd return None d = repl_dict.copy() # weed out identical terms pp = list(self.args) ee = list(expr.args) for p in self.args: if p in expr.args: ee.remove(p) pp.remove(p) # only one symbol left in pattern -> match the remaining expression if len(pp) == 1 and isinstance(pp[0], C.Wild): if len(ee) == 1: d[pp[0]] = sign * ee[0] else: d[pp[0]] = sign * (type(expr)(*ee)) return d if len(ee) != len(pp): return None i = 0 for p, e in zip(pp, ee): if i == 0 and sign != 1: try: e = sign * e except TypeError: return None d = p.matches(e, d, evaluate=not i) i += 1 if d is None: return None return d
def _subs_old_new(self, old, new): """Substitutes an expression old -> new.""" old = sympify(old) new = sympify(new) return self._eval_subs(old, new)
def expand(e, deep=True, modulus=None, power_base=True, power_exp=True, \ mul=True, log=True, multinomial=True, basic=True, **hints): """ Expand an expression using methods given as hints. Hints are applied with arbitrary order so your code shouldn't depend on the way hints are passed to this method. Hints evaluated unless explicitly set to False are: basic, log, multinomial, mul, power_base, and power_exp The following hints are supported but not applied unless set to True: complex, func, and trig. basic is a generic keyword for methods that want to be expanded automatically. For example, Integral uses expand_basic to expand the integrand. If you want your class expand methods to run automatically and they don't fit one of the already automatic methods, wrap it around _eval_expand_basic. If deep is set to True, things like arguments of functions are recursively expanded. Use deep=False to only expand on the top level. Also see expand_log, expand_mul, expand_complex, expand_trig, and expand_func, which are wrappers around those expansion methods. >>> from sympy import cos, exp >>> from sympy.abc import x, y, z mul - Distributes multiplication over addition. >>> (y*(x + z)).expand(mul=True) x*y + y*z complex - Split an expression into real and imaginary parts. >>> (x+y).expand(complex=True) I*im(x) + I*im(y) + re(x) + re(y) >>> cos(x).expand(complex=True) cos(re(x))*cosh(im(x)) - I*sin(re(x))*sinh(im(x)) power_exp - Expand addition in exponents into multiplied bases. >>> exp(x+y).expand(power_exp=True) exp(x)*exp(y) >>> (2**(x+y)).expand(power_exp=True) 2**x*2**y power_base - Split powers of multiplied bases. >>> ((x*y)**z).expand(power_base=True) x**z*y**z log - Pull out power of an argument as a coefficient and split logs products into sums of logs. Note that these only work if the arguments of the log function have the proper assumptions: the arguments must be positive and the exponents must be real. >>> from sympy import log, symbols >>> log(x**2*y).expand(log=True) log(y*x**2) >>> x, y = symbols('x,y', positive=True) >>> log(x**2*y).expand(log=True) 2*log(x) + log(y) trig - Do trigonometric expansions. >>> cos(x+y).expand(trig=True) cos(x)*cos(y) - sin(x)*sin(y) func - Expand other functions. >>> from sympy import gamma >>> gamma(x+1).expand(func=True) x*gamma(x) multinomial - Expand (x + y + ...)**n where n is a positive integer. >>> ((x+y+z)**2).expand(multinomial=True) 2*x*y + 2*x*z + 2*y*z + x**2 + y**2 + z**2 You can shut off methods that you don't want. >>> (exp(x+y)*(x+y)).expand() x*exp(x)*exp(y) + y*exp(x)*exp(y) >>> (exp(x+y)*(x+y)).expand(power_exp=False) x*exp(x + y) + y*exp(x + y) >>> (exp(x+y)*(x+y)).expand(mul=False) (x + y)*exp(x)*exp(y) Use deep=False to only expand on the top level. >>> exp(x+exp(x+y)).expand() exp(x)*exp(exp(x)*exp(y)) >>> exp(x+exp(x+y)).expand(deep=False) exp(x)*exp(exp(x + y)) Note: because hints are applied in arbitrary order, some hints may prevent expansion by other hints if they are applied first. In particular, mul may distribute multiplications and prevent log and power_base from expanding them. Also, if mul is applied before multinomial, the expression might not be fully distributed. The solution is to expand with mul=False first, then run expand_mul if you need further expansion. Examples: >>> from sympy import expand_log, expand, expand_mul >>> x, y, z = symbols('x,y,z', positive=True) >> expand(log(x*(y+z))) # could be either one below log(x*y + x*z) log(x) + log(y + z) >>> expand_log(log(x*y+x*z)) log(x*y + x*z) >> expand(log(x*(y+z)), mul=False) log(x) + log(y + z) >> expand((x*(y+z))**x) # could be either one below (x*y + x*z)**x x**x*(y + z)**x >>> expand((x*(y+z))**x, mul=False) x**x*(y + z)**x >> expand(x*(y+z)**2) # could be either one below 2*x*y*z + x*y**2 + x*z**2 x*(y + z)**2 >>> expand(x*(y+z)**2, mul=False) x*(2*y*z + y**2 + z**2) >>> expand_mul(_) 2*x*y*z + x*y**2 + x*z**2 """ hints['power_base'] = power_base hints['power_exp'] = power_exp hints['mul'] = mul hints['log'] = log hints['multinomial'] = multinomial hints['basic'] = basic return sympify(e).expand(deep=deep, modulus=modulus, **hints)
def __sympifyit_wrapper(a, b): try: return func(a, sympify(b, strict=True)) except SympifyError: return retval
def extract_multiplicatively(self, c): """Return None if it's not possible to make self in the form c * something in a nice way, i.e. preserving the properties of arguments of self. >>> from sympy import symbols, Rational >>> x, y = symbols('xy', real=True) >>> ((x*y)**3).extract_multiplicatively(x**2 * y) x*y**2 >>> ((x*y)**3).extract_multiplicatively(x**4 * y) >>> (2*x).extract_multiplicatively(2) x >>> (2*x).extract_multiplicatively(3) >>> (Rational(1,2)*x).extract_multiplicatively(3) x/6 """ c = sympify(c) if c is S.One: return self elif c == self: return S.One elif c.is_Mul: x = self.extract_multiplicatively(c.as_two_terms()[0]) if x != None: return x.extract_multiplicatively(c.as_two_terms()[1]) quotient = self / c if self.is_Number: if self is S.Infinity: if c.is_positive: return S.Infinity elif self is S.NegativeInfinity: if c.is_negative: return S.Infinity elif c.is_positive: return S.NegativeInfinity elif self is S.ComplexInfinity: if not c.is_zero: return S.ComplexInfinity elif self is S.NaN: return S.NaN elif self.is_Integer: if not quotient.is_Integer: return None elif self.is_positive and quotient.is_negative: return None else: return quotient elif self.is_Rational: if not quotient.is_Rational: return None elif self.is_positive and quotient.is_negative: return None else: return quotient elif self.is_Real: if not quotient.is_Real: return None elif self.is_positive and quotient.is_negative: return None else: return quotient elif self.is_NumberSymbol or self.is_Symbol or self is S.ImaginaryUnit: if quotient.is_Mul and len(quotient.args) == 2: if quotient.args[0].is_Integer and quotient.args[0].is_positive and quotient.args[1] == self: return quotient elif quotient.is_Integer: return quotient elif self.is_Add: newargs = [] for arg in self.args: newarg = arg.extract_multiplicatively(c) if newarg != None: newargs.append(newarg) else: return None return Add(*newargs) elif self.is_Mul: for i in xrange(len(self.args)): newargs = list(self.args) del(newargs[i]) tmp = self._new_rawargs(*newargs).extract_multiplicatively(c) if tmp != None: return tmp * self.args[i] elif self.is_Pow: if c.is_Pow and c.base == self.base: new_exp = self.exp.extract_additively(c.exp) if new_exp != None: return self.base ** (new_exp) elif c == self.base: new_exp = self.exp.extract_additively(1) if new_exp != None: return self.base ** (new_exp)
def extract_additively(self, c): """Return None if it's not possible to make self in the form something + c in a nice way, i.e. preserving the properties of arguments of self. >>> from sympy import symbols >>> x, y = symbols('xy', real=True) >>> ((x*y)**3).extract_additively(1) >>> (x+1).extract_additively(x) 1 >>> (x+1).extract_additively(2*x) >>> (x+1).extract_additively(-x) 1 + 2*x >>> (-x+1).extract_additively(2*x) 1 - 3*x """ c = sympify(c) if c is S.Zero: return self elif c == self: return S.Zero elif self is S.Zero: return None elif c.is_Add: x = self.extract_additively(c.as_two_terms()[0]) if x != None: return x.extract_additively(c.as_two_terms()[1]) sub = self - c if self.is_Number: if self.is_Integer: if not sub.is_Integer: return None elif self.is_positive and sub.is_negative: return None else: return sub elif self.is_Rational: if not sub.is_Rational: return None elif self.is_positive and sub.is_negative: return None else: return sub elif self.is_Real: if not sub.is_Real: return None elif self.is_positive and sub.is_negative: return None else: return sub elif self.is_NumberSymbol or self.is_Symbol or self is S.ImaginaryUnit: if sub.is_Mul and len(sub.args) == 2: if sub.args[0].is_Integer and sub.args[0].is_positive and sub.args[1] == self: return sub elif sub.is_Integer: return sub elif self.is_Add: terms = self.as_two_terms() subs0 = terms[0].extract_additively(c) if subs0 != None: return subs0 + terms[1] else: subs1 = terms[1].extract_additively(c) if subs1 != None: return subs1 + terms[0] elif self.is_Mul: self_coeff, self_terms = self.as_coeff_mul() if c.is_Mul: c_coeff, c_terms = c.as_coeff_mul() if c_terms == self_terms: new_coeff = self_coeff.extract_additively(c_coeff) if new_coeff != None: return new_coeff * c._new_rawargs(*c_terms) elif c == self_terms: new_coeff = self_coeff.extract_additively(1) if new_coeff != None: return new_coeff * c
def matches(self, expr, repl_dict={}, evaluate=False): expr = sympify(expr) if self.is_commutative and expr.is_commutative: return AssocOp._matches_commutative(self, expr, repl_dict, evaluate) # todo for commutative parts, until then use the default matches method for non-commutative products return self._matches(expr, repl_dict, evaluate)
def __new__(cls, name, exclude=(), properties=(), **assumptions): exclude = tuple([sympify(x) for x in exclude]) properties = tuple(properties) assumptions.setdefault('commutative', True) return Wild.__xnew__(cls, name, exclude, properties, **assumptions)
def __new__(cls, name, exclude=(), properties=(), **assumptions): exclude = tuple([sympify(x) for x in exclude]) properties = tuple(properties) return Wild.__xnew__(cls, name, exclude, properties, **assumptions)
def __new__(cls, expr, *symbols, **assumptions): expr = sympify(expr) if not symbols: return expr # standardize symbols symbols = list(sympify(symbols)) if not symbols[-1].is_Integer or len(symbols) == 1: symbols.append(S.One) symbol_count = [] all_zero = True i = 0 while i < len(symbols) - 1: # process up to final Integer s, count = symbols[i:i + 2] iwas = i if s.is_Symbol: if count.is_Symbol: count = 1 i += 1 elif count.is_Integer: count = int(count) i += 2 if i == iwas: # didn't get an update because of bad input raise ValueError( 'Derivative expects Symbol [, Integer] args but got %s, %s' % (s, count)) symbol_count.append((s, count)) if all_zero and not count == 0: all_zero = False # We make a special case for 0th derivative, because there # is no good way to unambiguously print this. if all_zero: return expr evaluate = assumptions.pop('evaluate', False) # look for a quick exit if there are symbols that are not in the free symbols if evaluate: if set(sc[0] for sc in symbol_count).difference(expr.free_symbols): return S.Zero # We make a generator so as to only generate a symbol when necessary. # If a high order of derivative is requested and the expr becomes 0 # after a few differentiations, then we won't need the other symbols symbolgen = (s for s, count in symbol_count for i in xrange(count)) if expr.is_commutative: assumptions['commutative'] = True if (not (hasattr(expr, '_eval_derivative') and evaluate) and not isinstance(expr, Derivative)): symbols = list(symbolgen) obj = Expr.__new__(cls, expr, *symbols, **assumptions) return obj # compute the derivative now unevaluated_symbols = [] for s in symbolgen: obj = expr._eval_derivative(s) if obj is None: unevaluated_symbols.append(s) elif obj is S.Zero: return S.Zero else: expr = obj if not unevaluated_symbols: return expr return Expr.__new__(cls, expr, *unevaluated_symbols, **assumptions)
def __new__(cls, expr, *symbols, **assumptions): expr = sympify(expr) if not symbols: return expr symbols = Derivative._symbolgen(*symbols) if expr.is_commutative: assumptions["commutative"] = True if "evaluate" in assumptions: evaluate = assumptions["evaluate"] del assumptions["evaluate"] else: evaluate = False if not evaluate and not isinstance(expr, Derivative): obj = Basic.__new__(cls, expr, *symbols, **assumptions) return obj unevaluated_symbols = [] for s in symbols: s = sympify(s) if not isinstance(s, Symbol): raise ValueError('Invalid literal: %s is not a valid variable' % s) if not expr.has(s): return S.Zero obj = expr._eval_derivative(s) if obj is None: unevaluated_symbols.append(s) elif obj is S.Zero: return S.Zero else: expr = obj if not unevaluated_symbols: return expr return Basic.__new__(cls, expr, *unevaluated_symbols, **assumptions)