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 eval(cls, *args): obj = Expr.__new__(cls, *args) #use dummy variables internally, just to be sure nargs = len(args) - 1 expression = args[nargs] funargs = [C.Dummy(arg.name) for arg in args[:nargs]] #probably could use something like foldl here for arg, funarg in zip(args[:nargs], funargs): expression = expression.subs(arg, funarg) funargs.append(expression) obj._args = tuple(funargs) return obj
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 fdiff(self, argindex=1): if self.nargs is not None: if isinstance(self.nargs, tuple): nargs = self.nargs[-1] else: nargs = self.nargs if not (1 <= argindex <= nargs): raise ArgumentIndexError(self, argindex) u = self.args[argindex - 1] if u.is_Symbol: uself = self else: u = C.Dummy('u') uself = self.func(u) return Derivative(uself, u, evaluate=False)
def fdiff(self, argindex=1): if self.nargs is not None: if isinstance(self.nargs, tuple): nargs = self.nargs[-1] else: nargs = self.nargs if not (1 <= argindex <= nargs): raise ArgumentIndexError(self, argindex) if not self.args[argindex - 1].is_Symbol: # See issue 1525 and issue 1620 and issue 2501 arg_dummy = C.Dummy('xi_%i' % argindex) return Subs( Derivative(self.subs(self.args[argindex - 1], arg_dummy), arg_dummy), arg_dummy, self.args[argindex - 1]) return Derivative(self, self.args[argindex - 1], evaluate=False)
def fdiff(self, argindex=1): if self.nargs is not None: if isinstance(self.nargs, tuple): nargs = self.nargs[-1] else: nargs = self.nargs if not (1<=argindex<=nargs): raise TypeError("argument index %r is out of range [1,%s]" % (argindex,nargs)) u = self.args[argindex - 1] if u.is_Symbol: uself = self else: u = C.Dummy('u') uself = self.func(u) return Derivative(uself, u, evaluate=False)
def getn(self): """ Returns the order of the expression. The order is determined either from the O(...) term. If there is no O(...) term, it returns None. Example: >>> from sympy import O >>> from sympy.abc import x >>> (1 + x + O(x**2)).getn() 2 >>> (1 + x).getn() >>> """ o = self.getO() if o is None: return None elif o.is_Order: o = o.expr if o is S.One: return S.Zero if o.is_Symbol: return S.One if o.is_Pow: return o.args[1] if o.is_Mul: # x**n*log(x)**n or x**n/log(x)**n for oi in o.args: if oi.is_Symbol: return S.One if oi.is_Pow: syms = oi.atoms(C.Symbol) if len(syms) == 1: x = syms.pop() oi = oi.subs(x, C.Dummy('x', positive=True)) if oi.base.is_Symbol and oi.exp.is_Rational: return abs(oi.exp) raise NotImplementedError('not sure of order of %s' % o)
def __eq__(self, other): if not isinstance(other, Subs): return False if (len(self.point) != len(other.point) or self.free_symbols != other.free_symbols or sorted(self.point) != sorted(other.point)): return False # non-repeated point args selfargs = [ v[0] for v in sorted(zip(self.variables, self.point), key=lambda v: v[1]) if list(self.point.args).count(v[1]) == 1 ] otherargs = [ v[0] for v in sorted(zip(other.variables, other.point), key=lambda v: v[1]) if list(other.point.args).count(v[1]) == 1 ] # find repeated point values and subs each associated variable # for a single symbol selfrepargs = [] otherrepargs = [] if uniq(self.point) != self.point: repeated = uniq( [v for v in self.point if list(self.point.args).count(v) > 1]) repswap = dict( zip(repeated, [C.Dummy() for _ in xrange(len(repeated))])) selfrepargs = [(self.variables[i], repswap[v]) for i, v in enumerate(self.point) if v in repeated] otherrepargs = [(other.variables[i], repswap[v]) for i, v in enumerate(other.point) if v in repeated] return self.expr.subs(selfrepargs) == other.expr.subs( tuple(zip(otherargs, selfargs))).subs(otherrepargs)
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