Coverage for /usr/lib/python3/dist-packages/sympy/core/function.py: 36%
1197 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2There are three types of functions implemented in SymPy:
4 1) defined functions (in the sense that they can be evaluated) like
5 exp or sin; they have a name and a body:
6 f = exp
7 2) undefined function which have a name but no body. Undefined
8 functions can be defined using a Function class as follows:
9 f = Function('f')
10 (the result will be a Function instance)
11 3) anonymous function (or lambda function) which have a body (defined
12 with dummy variables) but have no name:
13 f = Lambda(x, exp(x)*x)
14 f = Lambda((x, y), exp(x)*y)
15 The fourth type of functions are composites, like (sin + cos)(x); these work in
16 SymPy core, but are not yet part of SymPy.
18 Examples
19 ========
21 >>> import sympy
22 >>> f = sympy.Function("f")
23 >>> from sympy.abc import x
24 >>> f(x)
25 f(x)
26 >>> print(sympy.srepr(f(x).func))
27 Function('f')
28 >>> f(x).args
29 (x,)
31"""
33from __future__ import annotations
34from typing import Any
35from collections.abc import Iterable
37from .add import Add
38from .basic import Basic, _atomic
39from .cache import cacheit
40from .containers import Tuple, Dict
41from .decorators import _sympifyit
42from .evalf import pure_complex
43from .expr import Expr, AtomicExpr
44from .logic import fuzzy_and, fuzzy_or, fuzzy_not, FuzzyBool
45from .mul import Mul
46from .numbers import Rational, Float, Integer
47from .operations import LatticeOp
48from .parameters import global_parameters
49from .rules import Transform
50from .singleton import S
51from .sympify import sympify, _sympify
53from .sorting import default_sort_key, ordered
54from sympy.utilities.exceptions import (sympy_deprecation_warning,
55 SymPyDeprecationWarning, ignore_warnings)
56from sympy.utilities.iterables import (has_dups, sift, iterable,
57 is_sequence, uniq, topological_sort)
58from sympy.utilities.lambdify import MPMATH_TRANSLATIONS
59from sympy.utilities.misc import as_int, filldedent, func_name
61import mpmath
62from mpmath.libmp.libmpf import prec_to_dps
64import inspect
65from collections import Counter
67def _coeff_isneg(a):
68 """Return True if the leading Number is negative.
70 Examples
71 ========
73 >>> from sympy.core.function import _coeff_isneg
74 >>> from sympy import S, Symbol, oo, pi
75 >>> _coeff_isneg(-3*pi)
76 True
77 >>> _coeff_isneg(S(3))
78 False
79 >>> _coeff_isneg(-oo)
80 True
81 >>> _coeff_isneg(Symbol('n', negative=True)) # coeff is 1
82 False
84 For matrix expressions:
86 >>> from sympy import MatrixSymbol, sqrt
87 >>> A = MatrixSymbol("A", 3, 3)
88 >>> _coeff_isneg(-sqrt(2)*A)
89 True
90 >>> _coeff_isneg(sqrt(2)*A)
91 False
92 """
94 if a.is_MatMul:
95 a = a.args[0]
96 if a.is_Mul:
97 a = a.args[0]
98 return a.is_Number and a.is_extended_negative
101class PoleError(Exception):
102 pass
105class ArgumentIndexError(ValueError):
106 def __str__(self):
107 return ("Invalid operation with argument number %s for Function %s" %
108 (self.args[1], self.args[0]))
111class BadSignatureError(TypeError):
112 '''Raised when a Lambda is created with an invalid signature'''
113 pass
116class BadArgumentsError(TypeError):
117 '''Raised when a Lambda is called with an incorrect number of arguments'''
118 pass
121# Python 3 version that does not raise a Deprecation warning
122def arity(cls):
123 """Return the arity of the function if it is known, else None.
125 Explanation
126 ===========
128 When default values are specified for some arguments, they are
129 optional and the arity is reported as a tuple of possible values.
131 Examples
132 ========
134 >>> from sympy import arity, log
135 >>> arity(lambda x: x)
136 1
137 >>> arity(log)
138 (1, 2)
139 >>> arity(lambda *x: sum(x)) is None
140 True
141 """
142 eval_ = getattr(cls, 'eval', cls)
144 parameters = inspect.signature(eval_).parameters.items()
145 if [p for _, p in parameters if p.kind == p.VAR_POSITIONAL]:
146 return
147 p_or_k = [p for _, p in parameters if p.kind == p.POSITIONAL_OR_KEYWORD]
148 # how many have no default and how many have a default value
149 no, yes = map(len, sift(p_or_k,
150 lambda p:p.default == p.empty, binary=True))
151 return no if not yes else tuple(range(no, no + yes + 1))
153class FunctionClass(type):
154 """
155 Base class for function classes. FunctionClass is a subclass of type.
157 Use Function('<function name>' [ , signature ]) to create
158 undefined function classes.
159 """
160 _new = type.__new__
162 def __init__(cls, *args, **kwargs):
163 # honor kwarg value or class-defined value before using
164 # the number of arguments in the eval function (if present)
165 nargs = kwargs.pop('nargs', cls.__dict__.get('nargs', arity(cls)))
166 if nargs is None and 'nargs' not in cls.__dict__:
167 for supcls in cls.__mro__:
168 if hasattr(supcls, '_nargs'):
169 nargs = supcls._nargs
170 break
171 else:
172 continue
174 # Canonicalize nargs here; change to set in nargs.
175 if is_sequence(nargs):
176 if not nargs:
177 raise ValueError(filldedent('''
178 Incorrectly specified nargs as %s:
179 if there are no arguments, it should be
180 `nargs = 0`;
181 if there are any number of arguments,
182 it should be
183 `nargs = None`''' % str(nargs)))
184 nargs = tuple(ordered(set(nargs)))
185 elif nargs is not None:
186 nargs = (as_int(nargs),)
187 cls._nargs = nargs
189 # When __init__ is called from UndefinedFunction it is called with
190 # just one arg but when it is called from subclassing Function it is
191 # called with the usual (name, bases, namespace) type() signature.
192 if len(args) == 3:
193 namespace = args[2]
194 if 'eval' in namespace and not isinstance(namespace['eval'], classmethod):
195 raise TypeError("eval on Function subclasses should be a class method (defined with @classmethod)")
197 @property
198 def __signature__(self):
199 """
200 Allow Python 3's inspect.signature to give a useful signature for
201 Function subclasses.
202 """
203 # Python 3 only, but backports (like the one in IPython) still might
204 # call this.
205 try:
206 from inspect import signature
207 except ImportError:
208 return None
210 # TODO: Look at nargs
211 return signature(self.eval)
213 @property
214 def free_symbols(self):
215 return set()
217 @property
218 def xreplace(self):
219 # Function needs args so we define a property that returns
220 # a function that takes args...and then use that function
221 # to return the right value
222 return lambda rule, **_: rule.get(self, self)
224 @property
225 def nargs(self):
226 """Return a set of the allowed number of arguments for the function.
228 Examples
229 ========
231 >>> from sympy import Function
232 >>> f = Function('f')
234 If the function can take any number of arguments, the set of whole
235 numbers is returned:
237 >>> Function('f').nargs
238 Naturals0
240 If the function was initialized to accept one or more arguments, a
241 corresponding set will be returned:
243 >>> Function('f', nargs=1).nargs
244 {1}
245 >>> Function('f', nargs=(2, 1)).nargs
246 {1, 2}
248 The undefined function, after application, also has the nargs
249 attribute; the actual number of arguments is always available by
250 checking the ``args`` attribute:
252 >>> f = Function('f')
253 >>> f(1).nargs
254 Naturals0
255 >>> len(f(1).args)
256 1
257 """
258 from sympy.sets.sets import FiniteSet
259 # XXX it would be nice to handle this in __init__ but there are import
260 # problems with trying to import FiniteSet there
261 return FiniteSet(*self._nargs) if self._nargs else S.Naturals0
263 def _valid_nargs(self, n : int) -> bool:
264 """ Return True if the specified integer is a valid number of arguments
266 The number of arguments n is guaranteed to be an integer and positive
268 """
269 if self._nargs:
270 return n in self._nargs
272 nargs = self.nargs
273 return nargs is S.Naturals0 or n in nargs
275 def __repr__(cls):
276 return cls.__name__
279class Application(Basic, metaclass=FunctionClass):
280 """
281 Base class for applied functions.
283 Explanation
284 ===========
286 Instances of Application represent the result of applying an application of
287 any type to any object.
288 """
290 is_Function = True
292 @cacheit
293 def __new__(cls, *args, **options):
294 from sympy.sets.fancysets import Naturals0
295 from sympy.sets.sets import FiniteSet
297 args = list(map(sympify, args))
298 evaluate = options.pop('evaluate', global_parameters.evaluate)
299 # WildFunction (and anything else like it) may have nargs defined
300 # and we throw that value away here
301 options.pop('nargs', None)
303 if options:
304 raise ValueError("Unknown options: %s" % options)
306 if evaluate:
307 evaluated = cls.eval(*args)
308 if evaluated is not None:
309 return evaluated
311 obj = super().__new__(cls, *args, **options)
313 # make nargs uniform here
314 sentinel = object()
315 objnargs = getattr(obj, "nargs", sentinel)
316 if objnargs is not sentinel:
317 # things passing through here:
318 # - functions subclassed from Function (e.g. myfunc(1).nargs)
319 # - functions like cos(1).nargs
320 # - AppliedUndef with given nargs like Function('f', nargs=1)(1).nargs
321 # Canonicalize nargs here
322 if is_sequence(objnargs):
323 nargs = tuple(ordered(set(objnargs)))
324 elif objnargs is not None:
325 nargs = (as_int(objnargs),)
326 else:
327 nargs = None
328 else:
329 # things passing through here:
330 # - WildFunction('f').nargs
331 # - AppliedUndef with no nargs like Function('f')(1).nargs
332 nargs = obj._nargs # note the underscore here
333 # convert to FiniteSet
334 obj.nargs = FiniteSet(*nargs) if nargs else Naturals0()
335 return obj
337 @classmethod
338 def eval(cls, *args):
339 """
340 Returns a canonical form of cls applied to arguments args.
342 Explanation
343 ===========
345 The ``eval()`` method is called when the class ``cls`` is about to be
346 instantiated and it should return either some simplified instance
347 (possible of some other class), or if the class ``cls`` should be
348 unmodified, return None.
350 Examples of ``eval()`` for the function "sign"
352 .. code-block:: python
354 @classmethod
355 def eval(cls, arg):
356 if arg is S.NaN:
357 return S.NaN
358 if arg.is_zero: return S.Zero
359 if arg.is_positive: return S.One
360 if arg.is_negative: return S.NegativeOne
361 if isinstance(arg, Mul):
362 coeff, terms = arg.as_coeff_Mul(rational=True)
363 if coeff is not S.One:
364 return cls(coeff) * cls(terms)
366 """
367 return
369 @property
370 def func(self):
371 return self.__class__
373 def _eval_subs(self, old, new):
374 if (old.is_Function and new.is_Function and
375 callable(old) and callable(new) and
376 old == self.func and len(self.args) in new.nargs):
377 return new(*[i._subs(old, new) for i in self.args])
380class Function(Application, Expr):
381 r"""
382 Base class for applied mathematical functions.
384 It also serves as a constructor for undefined function classes.
386 See the :ref:`custom-functions` guide for details on how to subclass
387 ``Function`` and what methods can be defined.
389 Examples
390 ========
392 **Undefined Functions**
394 To create an undefined function, pass a string of the function name to
395 ``Function``.
397 >>> from sympy import Function, Symbol
398 >>> x = Symbol('x')
399 >>> f = Function('f')
400 >>> g = Function('g')(x)
401 >>> f
402 f
403 >>> f(x)
404 f(x)
405 >>> g
406 g(x)
407 >>> f(x).diff(x)
408 Derivative(f(x), x)
409 >>> g.diff(x)
410 Derivative(g(x), x)
412 Assumptions can be passed to ``Function`` the same as with a
413 :class:`~.Symbol`. Alternatively, you can use a ``Symbol`` with
414 assumptions for the function name and the function will inherit the name
415 and assumptions associated with the ``Symbol``:
417 >>> f_real = Function('f', real=True)
418 >>> f_real(x).is_real
419 True
420 >>> f_real_inherit = Function(Symbol('f', real=True))
421 >>> f_real_inherit(x).is_real
422 True
424 Note that assumptions on a function are unrelated to the assumptions on
425 the variables it is called on. If you want to add a relationship, subclass
426 ``Function`` and define custom assumptions handler methods. See the
427 :ref:`custom-functions-assumptions` section of the :ref:`custom-functions`
428 guide for more details.
430 **Custom Function Subclasses**
432 The :ref:`custom-functions` guide has several
433 :ref:`custom-functions-complete-examples` of how to subclass ``Function``
434 to create a custom function.
436 """
438 @property
439 def _diff_wrt(self):
440 return False
442 @cacheit
443 def __new__(cls, *args, **options):
444 # Handle calls like Function('f')
445 if cls is Function:
446 return UndefinedFunction(*args, **options)
448 n = len(args)
450 if not cls._valid_nargs(n):
451 # XXX: exception message must be in exactly this format to
452 # make it work with NumPy's functions like vectorize(). See,
453 # for example, https://github.com/numpy/numpy/issues/1697.
454 # The ideal solution would be just to attach metadata to
455 # the exception and change NumPy to take advantage of this.
456 temp = ('%(name)s takes %(qual)s %(args)s '
457 'argument%(plural)s (%(given)s given)')
458 raise TypeError(temp % {
459 'name': cls,
460 'qual': 'exactly' if len(cls.nargs) == 1 else 'at least',
461 'args': min(cls.nargs),
462 'plural': 's'*(min(cls.nargs) != 1),
463 'given': n})
465 evaluate = options.get('evaluate', global_parameters.evaluate)
466 result = super().__new__(cls, *args, **options)
467 if evaluate and isinstance(result, cls) and result.args:
468 _should_evalf = [cls._should_evalf(a) for a in result.args]
469 pr2 = min(_should_evalf)
470 if pr2 > 0:
471 pr = max(_should_evalf)
472 result = result.evalf(prec_to_dps(pr))
474 return _sympify(result)
476 @classmethod
477 def _should_evalf(cls, arg):
478 """
479 Decide if the function should automatically evalf().
481 Explanation
482 ===========
484 By default (in this implementation), this happens if (and only if) the
485 ARG is a floating point number (including complex numbers).
486 This function is used by __new__.
488 Returns the precision to evalf to, or -1 if it should not evalf.
489 """
490 if arg.is_Float:
491 return arg._prec
492 if not arg.is_Add:
493 return -1
494 m = pure_complex(arg)
495 if m is None:
496 return -1
497 # the elements of m are of type Number, so have a _prec
498 return max(m[0]._prec, m[1]._prec)
500 @classmethod
501 def class_key(cls):
502 from sympy.sets.fancysets import Naturals0
503 funcs = {
504 'exp': 10,
505 'log': 11,
506 'sin': 20,
507 'cos': 21,
508 'tan': 22,
509 'cot': 23,
510 'sinh': 30,
511 'cosh': 31,
512 'tanh': 32,
513 'coth': 33,
514 'conjugate': 40,
515 're': 41,
516 'im': 42,
517 'arg': 43,
518 }
519 name = cls.__name__
521 try:
522 i = funcs[name]
523 except KeyError:
524 i = 0 if isinstance(cls.nargs, Naturals0) else 10000
526 return 4, i, name
528 def _eval_evalf(self, prec):
530 def _get_mpmath_func(fname):
531 """Lookup mpmath function based on name"""
532 if isinstance(self, AppliedUndef):
533 # Shouldn't lookup in mpmath but might have ._imp_
534 return None
536 if not hasattr(mpmath, fname):
537 fname = MPMATH_TRANSLATIONS.get(fname, None)
538 if fname is None:
539 return None
540 return getattr(mpmath, fname)
542 _eval_mpmath = getattr(self, '_eval_mpmath', None)
543 if _eval_mpmath is None:
544 func = _get_mpmath_func(self.func.__name__)
545 args = self.args
546 else:
547 func, args = _eval_mpmath()
549 # Fall-back evaluation
550 if func is None:
551 imp = getattr(self, '_imp_', None)
552 if imp is None:
553 return None
554 try:
555 return Float(imp(*[i.evalf(prec) for i in self.args]), prec)
556 except (TypeError, ValueError):
557 return None
559 # Convert all args to mpf or mpc
560 # Convert the arguments to *higher* precision than requested for the
561 # final result.
562 # XXX + 5 is a guess, it is similar to what is used in evalf.py. Should
563 # we be more intelligent about it?
564 try:
565 args = [arg._to_mpmath(prec + 5) for arg in args]
566 def bad(m):
567 from mpmath import mpf, mpc
568 # the precision of an mpf value is the last element
569 # if that is 1 (and m[1] is not 1 which would indicate a
570 # power of 2), then the eval failed; so check that none of
571 # the arguments failed to compute to a finite precision.
572 # Note: An mpc value has two parts, the re and imag tuple;
573 # check each of those parts, too. Anything else is allowed to
574 # pass
575 if isinstance(m, mpf):
576 m = m._mpf_
577 return m[1] !=1 and m[-1] == 1
578 elif isinstance(m, mpc):
579 m, n = m._mpc_
580 return m[1] !=1 and m[-1] == 1 and \
581 n[1] !=1 and n[-1] == 1
582 else:
583 return False
584 if any(bad(a) for a in args):
585 raise ValueError # one or more args failed to compute with significance
586 except ValueError:
587 return
589 with mpmath.workprec(prec):
590 v = func(*args)
592 return Expr._from_mpmath(v, prec)
594 def _eval_derivative(self, s):
595 # f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s)
596 i = 0
597 l = []
598 for a in self.args:
599 i += 1
600 da = a.diff(s)
601 if da.is_zero:
602 continue
603 try:
604 df = self.fdiff(i)
605 except ArgumentIndexError:
606 df = Function.fdiff(self, i)
607 l.append(df * da)
608 return Add(*l)
610 def _eval_is_commutative(self):
611 return fuzzy_and(a.is_commutative for a in self.args)
613 def _eval_is_meromorphic(self, x, a):
614 if not self.args:
615 return True
616 if any(arg.has(x) for arg in self.args[1:]):
617 return False
619 arg = self.args[0]
620 if not arg._eval_is_meromorphic(x, a):
621 return None
623 return fuzzy_not(type(self).is_singular(arg.subs(x, a)))
625 _singularities: FuzzyBool | tuple[Expr, ...] = None
627 @classmethod
628 def is_singular(cls, a):
629 """
630 Tests whether the argument is an essential singularity
631 or a branch point, or the functions is non-holomorphic.
632 """
633 ss = cls._singularities
634 if ss in (True, None, False):
635 return ss
637 return fuzzy_or(a.is_infinite if s is S.ComplexInfinity
638 else (a - s).is_zero for s in ss)
640 def as_base_exp(self):
641 """
642 Returns the method as the 2-tuple (base, exponent).
643 """
644 return self, S.One
646 def _eval_aseries(self, n, args0, x, logx):
647 """
648 Compute an asymptotic expansion around args0, in terms of self.args.
649 This function is only used internally by _eval_nseries and should not
650 be called directly; derived classes can overwrite this to implement
651 asymptotic expansions.
652 """
653 raise PoleError(filldedent('''
654 Asymptotic expansion of %s around %s is
655 not implemented.''' % (type(self), args0)))
657 def _eval_nseries(self, x, n, logx, cdir=0):
658 """
659 This function does compute series for multivariate functions,
660 but the expansion is always in terms of *one* variable.
662 Examples
663 ========
665 >>> from sympy import atan2
666 >>> from sympy.abc import x, y
667 >>> atan2(x, y).series(x, n=2)
668 atan2(0, y) + x/y + O(x**2)
669 >>> atan2(x, y).series(y, n=2)
670 -y/x + atan2(x, 0) + O(y**2)
672 This function also computes asymptotic expansions, if necessary
673 and possible:
675 >>> from sympy import loggamma
676 >>> loggamma(1/x)._eval_nseries(x,0,None)
677 -1/x - log(x)/x + log(x)/2 + O(1)
679 """
680 from .symbol import uniquely_named_symbol
681 from sympy.series.order import Order
682 from sympy.sets.sets import FiniteSet
683 args = self.args
684 args0 = [t.limit(x, 0) for t in args]
685 if any(t.is_finite is False for t in args0):
686 from .numbers import oo, zoo, nan
687 a = [t.as_leading_term(x, logx=logx) for t in args]
688 a0 = [t.limit(x, 0) for t in a]
689 if any(t.has(oo, -oo, zoo, nan) for t in a0):
690 return self._eval_aseries(n, args0, x, logx)
691 # Careful: the argument goes to oo, but only logarithmically so. We
692 # are supposed to do a power series expansion "around the
693 # logarithmic term". e.g.
694 # f(1+x+log(x))
695 # -> f(1+logx) + x*f'(1+logx) + O(x**2)
696 # where 'logx' is given in the argument
697 a = [t._eval_nseries(x, n, logx) for t in args]
698 z = [r - r0 for (r, r0) in zip(a, a0)]
699 p = [Dummy() for _ in z]
700 q = []
701 v = None
702 for ai, zi, pi in zip(a0, z, p):
703 if zi.has(x):
704 if v is not None:
705 raise NotImplementedError
706 q.append(ai + pi)
707 v = pi
708 else:
709 q.append(ai)
710 e1 = self.func(*q)
711 if v is None:
712 return e1
713 s = e1._eval_nseries(v, n, logx)
714 o = s.getO()
715 s = s.removeO()
716 s = s.subs(v, zi).expand() + Order(o.expr.subs(v, zi), x)
717 return s
718 if (self.func.nargs is S.Naturals0
719 or (self.func.nargs == FiniteSet(1) and args0[0])
720 or any(c > 1 for c in self.func.nargs)):
721 e = self
722 e1 = e.expand()
723 if e == e1:
724 #for example when e = sin(x+1) or e = sin(cos(x))
725 #let's try the general algorithm
726 if len(e.args) == 1:
727 # issue 14411
728 e = e.func(e.args[0].cancel())
729 term = e.subs(x, S.Zero)
730 if term.is_finite is False or term is S.NaN:
731 raise PoleError("Cannot expand %s around 0" % (self))
732 series = term
733 fact = S.One
735 _x = uniquely_named_symbol('xi', self)
736 e = e.subs(x, _x)
737 for i in range(1, n):
738 fact *= Rational(i)
739 e = e.diff(_x)
740 subs = e.subs(_x, S.Zero)
741 if subs is S.NaN:
742 # try to evaluate a limit if we have to
743 subs = e.limit(_x, S.Zero)
744 if subs.is_finite is False:
745 raise PoleError("Cannot expand %s around 0" % (self))
746 term = subs*(x**i)/fact
747 term = term.expand()
748 series += term
749 return series + Order(x**n, x)
750 return e1.nseries(x, n=n, logx=logx)
751 arg = self.args[0]
752 l = []
753 g = None
754 # try to predict a number of terms needed
755 nterms = n + 2
756 cf = Order(arg.as_leading_term(x), x).getn()
757 if cf != 0:
758 nterms = (n/cf).ceiling()
759 for i in range(nterms):
760 g = self.taylor_term(i, arg, g)
761 g = g.nseries(x, n=n, logx=logx)
762 l.append(g)
763 return Add(*l) + Order(x**n, x)
765 def fdiff(self, argindex=1):
766 """
767 Returns the first derivative of the function.
768 """
769 if not (1 <= argindex <= len(self.args)):
770 raise ArgumentIndexError(self, argindex)
771 ix = argindex - 1
772 A = self.args[ix]
773 if A._diff_wrt:
774 if len(self.args) == 1 or not A.is_Symbol:
775 return _derivative_dispatch(self, A)
776 for i, v in enumerate(self.args):
777 if i != ix and A in v.free_symbols:
778 # it can't be in any other argument's free symbols
779 # issue 8510
780 break
781 else:
782 return _derivative_dispatch(self, A)
784 # See issue 4624 and issue 4719, 5600 and 8510
785 D = Dummy('xi_%i' % argindex, dummy_index=hash(A))
786 args = self.args[:ix] + (D,) + self.args[ix + 1:]
787 return Subs(Derivative(self.func(*args), D), D, A)
789 def _eval_as_leading_term(self, x, logx=None, cdir=0):
790 """Stub that should be overridden by new Functions to return
791 the first non-zero term in a series if ever an x-dependent
792 argument whose leading term vanishes as x -> 0 might be encountered.
793 See, for example, cos._eval_as_leading_term.
794 """
795 from sympy.series.order import Order
796 args = [a.as_leading_term(x, logx=logx) for a in self.args]
797 o = Order(1, x)
798 if any(x in a.free_symbols and o.contains(a) for a in args):
799 # Whereas x and any finite number are contained in O(1, x),
800 # expressions like 1/x are not. If any arg simplified to a
801 # vanishing expression as x -> 0 (like x or x**2, but not
802 # 3, 1/x, etc...) then the _eval_as_leading_term is needed
803 # to supply the first non-zero term of the series,
804 #
805 # e.g. expression leading term
806 # ---------- ------------
807 # cos(1/x) cos(1/x)
808 # cos(cos(x)) cos(1)
809 # cos(x) 1 <- _eval_as_leading_term needed
810 # sin(x) x <- _eval_as_leading_term needed
811 #
812 raise NotImplementedError(
813 '%s has no _eval_as_leading_term routine' % self.func)
814 else:
815 return self.func(*args)
818class AppliedUndef(Function):
819 """
820 Base class for expressions resulting from the application of an undefined
821 function.
822 """
824 is_number = False
826 def __new__(cls, *args, **options):
827 args = list(map(sympify, args))
828 u = [a.name for a in args if isinstance(a, UndefinedFunction)]
829 if u:
830 raise TypeError('Invalid argument: expecting an expression, not UndefinedFunction%s: %s' % (
831 's'*(len(u) > 1), ', '.join(u)))
832 obj = super().__new__(cls, *args, **options)
833 return obj
835 def _eval_as_leading_term(self, x, logx=None, cdir=0):
836 return self
838 @property
839 def _diff_wrt(self):
840 """
841 Allow derivatives wrt to undefined functions.
843 Examples
844 ========
846 >>> from sympy import Function, Symbol
847 >>> f = Function('f')
848 >>> x = Symbol('x')
849 >>> f(x)._diff_wrt
850 True
851 >>> f(x).diff(x)
852 Derivative(f(x), x)
853 """
854 return True
857class UndefSageHelper:
858 """
859 Helper to facilitate Sage conversion.
860 """
861 def __get__(self, ins, typ):
862 import sage.all as sage
863 if ins is None:
864 return lambda: sage.function(typ.__name__)
865 else:
866 args = [arg._sage_() for arg in ins.args]
867 return lambda : sage.function(ins.__class__.__name__)(*args)
869_undef_sage_helper = UndefSageHelper()
871class UndefinedFunction(FunctionClass):
872 """
873 The (meta)class of undefined functions.
874 """
875 def __new__(mcl, name, bases=(AppliedUndef,), __dict__=None, **kwargs):
876 from .symbol import _filter_assumptions
877 # Allow Function('f', real=True)
878 # and/or Function(Symbol('f', real=True))
879 assumptions, kwargs = _filter_assumptions(kwargs)
880 if isinstance(name, Symbol):
881 assumptions = name._merge(assumptions)
882 name = name.name
883 elif not isinstance(name, str):
884 raise TypeError('expecting string or Symbol for name')
885 else:
886 commutative = assumptions.get('commutative', None)
887 assumptions = Symbol(name, **assumptions).assumptions0
888 if commutative is None:
889 assumptions.pop('commutative')
890 __dict__ = __dict__ or {}
891 # put the `is_*` for into __dict__
892 __dict__.update({'is_%s' % k: v for k, v in assumptions.items()})
893 # You can add other attributes, although they do have to be hashable
894 # (but seriously, if you want to add anything other than assumptions,
895 # just subclass Function)
896 __dict__.update(kwargs)
897 # add back the sanitized assumptions without the is_ prefix
898 kwargs.update(assumptions)
899 # Save these for __eq__
900 __dict__.update({'_kwargs': kwargs})
901 # do this for pickling
902 __dict__['__module__'] = None
903 obj = super().__new__(mcl, name, bases, __dict__)
904 obj.name = name
905 obj._sage_ = _undef_sage_helper
906 return obj
908 def __instancecheck__(cls, instance):
909 return cls in type(instance).__mro__
911 _kwargs: dict[str, bool | None] = {}
913 def __hash__(self):
914 return hash((self.class_key(), frozenset(self._kwargs.items())))
916 def __eq__(self, other):
917 return (isinstance(other, self.__class__) and
918 self.class_key() == other.class_key() and
919 self._kwargs == other._kwargs)
921 def __ne__(self, other):
922 return not self == other
924 @property
925 def _diff_wrt(self):
926 return False
929# XXX: The type: ignore on WildFunction is because mypy complains:
930#
931# sympy/core/function.py:939: error: Cannot determine type of 'sort_key' in
932# base class 'Expr'
933#
934# Somehow this is because of the @cacheit decorator but it is not clear how to
935# fix it.
938class WildFunction(Function, AtomicExpr): # type: ignore
939 """
940 A WildFunction function matches any function (with its arguments).
942 Examples
943 ========
945 >>> from sympy import WildFunction, Function, cos
946 >>> from sympy.abc import x, y
947 >>> F = WildFunction('F')
948 >>> f = Function('f')
949 >>> F.nargs
950 Naturals0
951 >>> x.match(F)
952 >>> F.match(F)
953 {F_: F_}
954 >>> f(x).match(F)
955 {F_: f(x)}
956 >>> cos(x).match(F)
957 {F_: cos(x)}
958 >>> f(x, y).match(F)
959 {F_: f(x, y)}
961 To match functions with a given number of arguments, set ``nargs`` to the
962 desired value at instantiation:
964 >>> F = WildFunction('F', nargs=2)
965 >>> F.nargs
966 {2}
967 >>> f(x).match(F)
968 >>> f(x, y).match(F)
969 {F_: f(x, y)}
971 To match functions with a range of arguments, set ``nargs`` to a tuple
972 containing the desired number of arguments, e.g. if ``nargs = (1, 2)``
973 then functions with 1 or 2 arguments will be matched.
975 >>> F = WildFunction('F', nargs=(1, 2))
976 >>> F.nargs
977 {1, 2}
978 >>> f(x).match(F)
979 {F_: f(x)}
980 >>> f(x, y).match(F)
981 {F_: f(x, y)}
982 >>> f(x, y, 1).match(F)
984 """
986 # XXX: What is this class attribute used for?
987 include: set[Any] = set()
989 def __init__(cls, name, **assumptions):
990 from sympy.sets.sets import Set, FiniteSet
991 cls.name = name
992 nargs = assumptions.pop('nargs', S.Naturals0)
993 if not isinstance(nargs, Set):
994 # Canonicalize nargs here. See also FunctionClass.
995 if is_sequence(nargs):
996 nargs = tuple(ordered(set(nargs)))
997 elif nargs is not None:
998 nargs = (as_int(nargs),)
999 nargs = FiniteSet(*nargs)
1000 cls.nargs = nargs
1002 def matches(self, expr, repl_dict=None, old=False):
1003 if not isinstance(expr, (AppliedUndef, Function)):
1004 return None
1005 if len(expr.args) not in self.nargs:
1006 return None
1008 if repl_dict is None:
1009 repl_dict = {}
1010 else:
1011 repl_dict = repl_dict.copy()
1013 repl_dict[self] = expr
1014 return repl_dict
1017class Derivative(Expr):
1018 """
1019 Carries out differentiation of the given expression with respect to symbols.
1021 Examples
1022 ========
1024 >>> from sympy import Derivative, Function, symbols, Subs
1025 >>> from sympy.abc import x, y
1026 >>> f, g = symbols('f g', cls=Function)
1028 >>> Derivative(x**2, x, evaluate=True)
1029 2*x
1031 Denesting of derivatives retains the ordering of variables:
1033 >>> Derivative(Derivative(f(x, y), y), x)
1034 Derivative(f(x, y), y, x)
1036 Contiguously identical symbols are merged into a tuple giving
1037 the symbol and the count:
1039 >>> Derivative(f(x), x, x, y, x)
1040 Derivative(f(x), (x, 2), y, x)
1042 If the derivative cannot be performed, and evaluate is True, the
1043 order of the variables of differentiation will be made canonical:
1045 >>> Derivative(f(x, y), y, x, evaluate=True)
1046 Derivative(f(x, y), x, y)
1048 Derivatives with respect to undefined functions can be calculated:
1050 >>> Derivative(f(x)**2, f(x), evaluate=True)
1051 2*f(x)
1053 Such derivatives will show up when the chain rule is used to
1054 evalulate a derivative:
1056 >>> f(g(x)).diff(x)
1057 Derivative(f(g(x)), g(x))*Derivative(g(x), x)
1059 Substitution is used to represent derivatives of functions with
1060 arguments that are not symbols or functions:
1062 >>> f(2*x + 3).diff(x) == 2*Subs(f(y).diff(y), y, 2*x + 3)
1063 True
1065 Notes
1066 =====
1068 Simplification of high-order derivatives:
1070 Because there can be a significant amount of simplification that can be
1071 done when multiple differentiations are performed, results will be
1072 automatically simplified in a fairly conservative fashion unless the
1073 keyword ``simplify`` is set to False.
1075 >>> from sympy import sqrt, diff, Function, symbols
1076 >>> from sympy.abc import x, y, z
1077 >>> f, g = symbols('f,g', cls=Function)
1079 >>> e = sqrt((x + 1)**2 + x)
1080 >>> diff(e, (x, 5), simplify=False).count_ops()
1081 136
1082 >>> diff(e, (x, 5)).count_ops()
1083 30
1085 Ordering of variables:
1087 If evaluate is set to True and the expression cannot be evaluated, the
1088 list of differentiation symbols will be sorted, that is, the expression is
1089 assumed to have continuous derivatives up to the order asked.
1091 Derivative wrt non-Symbols:
1093 For the most part, one may not differentiate wrt non-symbols.
1094 For example, we do not allow differentiation wrt `x*y` because
1095 there are multiple ways of structurally defining where x*y appears
1096 in an expression: a very strict definition would make
1097 (x*y*z).diff(x*y) == 0. Derivatives wrt defined functions (like
1098 cos(x)) are not allowed, either:
1100 >>> (x*y*z).diff(x*y)
1101 Traceback (most recent call last):
1102 ...
1103 ValueError: Can't calculate derivative wrt x*y.
1105 To make it easier to work with variational calculus, however,
1106 derivatives wrt AppliedUndef and Derivatives are allowed.
1107 For example, in the Euler-Lagrange method one may write
1108 F(t, u, v) where u = f(t) and v = f'(t). These variables can be
1109 written explicitly as functions of time::
1111 >>> from sympy.abc import t
1112 >>> F = Function('F')
1113 >>> U = f(t)
1114 >>> V = U.diff(t)
1116 The derivative wrt f(t) can be obtained directly:
1118 >>> direct = F(t, U, V).diff(U)
1120 When differentiation wrt a non-Symbol is attempted, the non-Symbol
1121 is temporarily converted to a Symbol while the differentiation
1122 is performed and the same answer is obtained:
1124 >>> indirect = F(t, U, V).subs(U, x).diff(x).subs(x, U)
1125 >>> assert direct == indirect
1127 The implication of this non-symbol replacement is that all
1128 functions are treated as independent of other functions and the
1129 symbols are independent of the functions that contain them::
1131 >>> x.diff(f(x))
1132 0
1133 >>> g(x).diff(f(x))
1134 0
1136 It also means that derivatives are assumed to depend only
1137 on the variables of differentiation, not on anything contained
1138 within the expression being differentiated::
1140 >>> F = f(x)
1141 >>> Fx = F.diff(x)
1142 >>> Fx.diff(F) # derivative depends on x, not F
1143 0
1144 >>> Fxx = Fx.diff(x)
1145 >>> Fxx.diff(Fx) # derivative depends on x, not Fx
1146 0
1148 The last example can be made explicit by showing the replacement
1149 of Fx in Fxx with y:
1151 >>> Fxx.subs(Fx, y)
1152 Derivative(y, x)
1154 Since that in itself will evaluate to zero, differentiating
1155 wrt Fx will also be zero:
1157 >>> _.doit()
1158 0
1160 Replacing undefined functions with concrete expressions
1162 One must be careful to replace undefined functions with expressions
1163 that contain variables consistent with the function definition and
1164 the variables of differentiation or else insconsistent result will
1165 be obtained. Consider the following example:
1167 >>> eq = f(x)*g(y)
1168 >>> eq.subs(f(x), x*y).diff(x, y).doit()
1169 y*Derivative(g(y), y) + g(y)
1170 >>> eq.diff(x, y).subs(f(x), x*y).doit()
1171 y*Derivative(g(y), y)
1173 The results differ because `f(x)` was replaced with an expression
1174 that involved both variables of differentiation. In the abstract
1175 case, differentiation of `f(x)` by `y` is 0; in the concrete case,
1176 the presence of `y` made that derivative nonvanishing and produced
1177 the extra `g(y)` term.
1179 Defining differentiation for an object
1181 An object must define ._eval_derivative(symbol) method that returns
1182 the differentiation result. This function only needs to consider the
1183 non-trivial case where expr contains symbol and it should call the diff()
1184 method internally (not _eval_derivative); Derivative should be the only
1185 one to call _eval_derivative.
1187 Any class can allow derivatives to be taken with respect to
1188 itself (while indicating its scalar nature). See the
1189 docstring of Expr._diff_wrt.
1191 See Also
1192 ========
1193 _sort_variable_count
1194 """
1196 is_Derivative = True
1198 @property
1199 def _diff_wrt(self):
1200 """An expression may be differentiated wrt a Derivative if
1201 it is in elementary form.
1203 Examples
1204 ========
1206 >>> from sympy import Function, Derivative, cos
1207 >>> from sympy.abc import x
1208 >>> f = Function('f')
1210 >>> Derivative(f(x), x)._diff_wrt
1211 True
1212 >>> Derivative(cos(x), x)._diff_wrt
1213 False
1214 >>> Derivative(x + 1, x)._diff_wrt
1215 False
1217 A Derivative might be an unevaluated form of what will not be
1218 a valid variable of differentiation if evaluated. For example,
1220 >>> Derivative(f(f(x)), x).doit()
1221 Derivative(f(x), x)*Derivative(f(f(x)), f(x))
1223 Such an expression will present the same ambiguities as arise
1224 when dealing with any other product, like ``2*x``, so ``_diff_wrt``
1225 is False:
1227 >>> Derivative(f(f(x)), x)._diff_wrt
1228 False
1229 """
1230 return self.expr._diff_wrt and isinstance(self.doit(), Derivative)
1232 def __new__(cls, expr, *variables, **kwargs):
1233 expr = sympify(expr)
1234 symbols_or_none = getattr(expr, "free_symbols", None)
1235 has_symbol_set = isinstance(symbols_or_none, set)
1237 if not has_symbol_set:
1238 raise ValueError(filldedent('''
1239 Since there are no variables in the expression %s,
1240 it cannot be differentiated.''' % expr))
1242 # determine value for variables if it wasn't given
1243 if not variables:
1244 variables = expr.free_symbols
1245 if len(variables) != 1:
1246 if expr.is_number:
1247 return S.Zero
1248 if len(variables) == 0:
1249 raise ValueError(filldedent('''
1250 Since there are no variables in the expression,
1251 the variable(s) of differentiation must be supplied
1252 to differentiate %s''' % expr))
1253 else:
1254 raise ValueError(filldedent('''
1255 Since there is more than one variable in the
1256 expression, the variable(s) of differentiation
1257 must be supplied to differentiate %s''' % expr))
1259 # Split the list of variables into a list of the variables we are diff
1260 # wrt, where each element of the list has the form (s, count) where
1261 # s is the entity to diff wrt and count is the order of the
1262 # derivative.
1263 variable_count = []
1264 array_likes = (tuple, list, Tuple)
1266 from sympy.tensor.array import Array, NDimArray
1268 for i, v in enumerate(variables):
1269 if isinstance(v, UndefinedFunction):
1270 raise TypeError(
1271 "cannot differentiate wrt "
1272 "UndefinedFunction: %s" % v)
1274 if isinstance(v, array_likes):
1275 if len(v) == 0:
1276 # Ignore empty tuples: Derivative(expr, ... , (), ... )
1277 continue
1278 if isinstance(v[0], array_likes):
1279 # Derive by array: Derivative(expr, ... , [[x, y, z]], ... )
1280 if len(v) == 1:
1281 v = Array(v[0])
1282 count = 1
1283 else:
1284 v, count = v
1285 v = Array(v)
1286 else:
1287 v, count = v
1288 if count == 0:
1289 continue
1290 variable_count.append(Tuple(v, count))
1291 continue
1293 v = sympify(v)
1294 if isinstance(v, Integer):
1295 if i == 0:
1296 raise ValueError("First variable cannot be a number: %i" % v)
1297 count = v
1298 prev, prevcount = variable_count[-1]
1299 if prevcount != 1:
1300 raise TypeError("tuple {} followed by number {}".format((prev, prevcount), v))
1301 if count == 0:
1302 variable_count.pop()
1303 else:
1304 variable_count[-1] = Tuple(prev, count)
1305 else:
1306 count = 1
1307 variable_count.append(Tuple(v, count))
1309 # light evaluation of contiguous, identical
1310 # items: (x, 1), (x, 1) -> (x, 2)
1311 merged = []
1312 for t in variable_count:
1313 v, c = t
1314 if c.is_negative:
1315 raise ValueError(
1316 'order of differentiation must be nonnegative')
1317 if merged and merged[-1][0] == v:
1318 c += merged[-1][1]
1319 if not c:
1320 merged.pop()
1321 else:
1322 merged[-1] = Tuple(v, c)
1323 else:
1324 merged.append(t)
1325 variable_count = merged
1327 # sanity check of variables of differentation; we waited
1328 # until the counts were computed since some variables may
1329 # have been removed because the count was 0
1330 for v, c in variable_count:
1331 # v must have _diff_wrt True
1332 if not v._diff_wrt:
1333 __ = '' # filler to make error message neater
1334 raise ValueError(filldedent('''
1335 Can't calculate derivative wrt %s.%s''' % (v,
1336 __)))
1338 # We make a special case for 0th derivative, because there is no
1339 # good way to unambiguously print this.
1340 if len(variable_count) == 0:
1341 return expr
1343 evaluate = kwargs.get('evaluate', False)
1345 if evaluate:
1346 if isinstance(expr, Derivative):
1347 expr = expr.canonical
1348 variable_count = [
1349 (v.canonical if isinstance(v, Derivative) else v, c)
1350 for v, c in variable_count]
1352 # Look for a quick exit if there are symbols that don't appear in
1353 # expression at all. Note, this cannot check non-symbols like
1354 # Derivatives as those can be created by intermediate
1355 # derivatives.
1356 zero = False
1357 free = expr.free_symbols
1358 from sympy.matrices.expressions.matexpr import MatrixExpr
1360 for v, c in variable_count:
1361 vfree = v.free_symbols
1362 if c.is_positive and vfree:
1363 if isinstance(v, AppliedUndef):
1364 # these match exactly since
1365 # x.diff(f(x)) == g(x).diff(f(x)) == 0
1366 # and are not created by differentiation
1367 D = Dummy()
1368 if not expr.xreplace({v: D}).has(D):
1369 zero = True
1370 break
1371 elif isinstance(v, MatrixExpr):
1372 zero = False
1373 break
1374 elif isinstance(v, Symbol) and v not in free:
1375 zero = True
1376 break
1377 else:
1378 if not free & vfree:
1379 # e.g. v is IndexedBase or Matrix
1380 zero = True
1381 break
1382 if zero:
1383 return cls._get_zero_with_shape_like(expr)
1385 # make the order of symbols canonical
1386 #TODO: check if assumption of discontinuous derivatives exist
1387 variable_count = cls._sort_variable_count(variable_count)
1389 # denest
1390 if isinstance(expr, Derivative):
1391 variable_count = list(expr.variable_count) + variable_count
1392 expr = expr.expr
1393 return _derivative_dispatch(expr, *variable_count, **kwargs)
1395 # we return here if evaluate is False or if there is no
1396 # _eval_derivative method
1397 if not evaluate or not hasattr(expr, '_eval_derivative'):
1398 # return an unevaluated Derivative
1399 if evaluate and variable_count == [(expr, 1)] and expr.is_scalar:
1400 # special hack providing evaluation for classes
1401 # that have defined is_scalar=True but have no
1402 # _eval_derivative defined
1403 return S.One
1404 return Expr.__new__(cls, expr, *variable_count)
1406 # evaluate the derivative by calling _eval_derivative method
1407 # of expr for each variable
1408 # -------------------------------------------------------------
1409 nderivs = 0 # how many derivatives were performed
1410 unhandled = []
1411 from sympy.matrices.common import MatrixCommon
1412 for i, (v, count) in enumerate(variable_count):
1414 old_expr = expr
1415 old_v = None
1417 is_symbol = v.is_symbol or isinstance(v,
1418 (Iterable, Tuple, MatrixCommon, NDimArray))
1420 if not is_symbol:
1421 old_v = v
1422 v = Dummy('xi')
1423 expr = expr.xreplace({old_v: v})
1424 # Derivatives and UndefinedFunctions are independent
1425 # of all others
1426 clashing = not (isinstance(old_v, Derivative) or \
1427 isinstance(old_v, AppliedUndef))
1428 if v not in expr.free_symbols and not clashing:
1429 return expr.diff(v) # expr's version of 0
1430 if not old_v.is_scalar and not hasattr(
1431 old_v, '_eval_derivative'):
1432 # special hack providing evaluation for classes
1433 # that have defined is_scalar=True but have no
1434 # _eval_derivative defined
1435 expr *= old_v.diff(old_v)
1437 obj = cls._dispatch_eval_derivative_n_times(expr, v, count)
1438 if obj is not None and obj.is_zero:
1439 return obj
1441 nderivs += count
1443 if old_v is not None:
1444 if obj is not None:
1445 # remove the dummy that was used
1446 obj = obj.subs(v, old_v)
1447 # restore expr
1448 expr = old_expr
1450 if obj is None:
1451 # we've already checked for quick-exit conditions
1452 # that give 0 so the remaining variables
1453 # are contained in the expression but the expression
1454 # did not compute a derivative so we stop taking
1455 # derivatives
1456 unhandled = variable_count[i:]
1457 break
1459 expr = obj
1461 # what we have so far can be made canonical
1462 expr = expr.replace(
1463 lambda x: isinstance(x, Derivative),
1464 lambda x: x.canonical)
1466 if unhandled:
1467 if isinstance(expr, Derivative):
1468 unhandled = list(expr.variable_count) + unhandled
1469 expr = expr.expr
1470 expr = Expr.__new__(cls, expr, *unhandled)
1472 if (nderivs > 1) == True and kwargs.get('simplify', True):
1473 from .exprtools import factor_terms
1474 from sympy.simplify.simplify import signsimp
1475 expr = factor_terms(signsimp(expr))
1476 return expr
1478 @property
1479 def canonical(cls):
1480 return cls.func(cls.expr,
1481 *Derivative._sort_variable_count(cls.variable_count))
1483 @classmethod
1484 def _sort_variable_count(cls, vc):
1485 """
1486 Sort (variable, count) pairs into canonical order while
1487 retaining order of variables that do not commute during
1488 differentiation:
1490 * symbols and functions commute with each other
1491 * derivatives commute with each other
1492 * a derivative does not commute with anything it contains
1493 * any other object is not allowed to commute if it has
1494 free symbols in common with another object
1496 Examples
1497 ========
1499 >>> from sympy import Derivative, Function, symbols
1500 >>> vsort = Derivative._sort_variable_count
1501 >>> x, y, z = symbols('x y z')
1502 >>> f, g, h = symbols('f g h', cls=Function)
1504 Contiguous items are collapsed into one pair:
1506 >>> vsort([(x, 1), (x, 1)])
1507 [(x, 2)]
1508 >>> vsort([(y, 1), (f(x), 1), (y, 1), (f(x), 1)])
1509 [(y, 2), (f(x), 2)]
1511 Ordering is canonical.
1513 >>> def vsort0(*v):
1514 ... # docstring helper to
1515 ... # change vi -> (vi, 0), sort, and return vi vals
1516 ... return [i[0] for i in vsort([(i, 0) for i in v])]
1518 >>> vsort0(y, x)
1519 [x, y]
1520 >>> vsort0(g(y), g(x), f(y))
1521 [f(y), g(x), g(y)]
1523 Symbols are sorted as far to the left as possible but never
1524 move to the left of a derivative having the same symbol in
1525 its variables; the same applies to AppliedUndef which are
1526 always sorted after Symbols:
1528 >>> dfx = f(x).diff(x)
1529 >>> assert vsort0(dfx, y) == [y, dfx]
1530 >>> assert vsort0(dfx, x) == [dfx, x]
1531 """
1532 if not vc:
1533 return []
1534 vc = list(vc)
1535 if len(vc) == 1:
1536 return [Tuple(*vc[0])]
1537 V = list(range(len(vc)))
1538 E = []
1539 v = lambda i: vc[i][0]
1540 D = Dummy()
1541 def _block(d, v, wrt=False):
1542 # return True if v should not come before d else False
1543 if d == v:
1544 return wrt
1545 if d.is_Symbol:
1546 return False
1547 if isinstance(d, Derivative):
1548 # a derivative blocks if any of it's variables contain
1549 # v; the wrt flag will return True for an exact match
1550 # and will cause an AppliedUndef to block if v is in
1551 # the arguments
1552 if any(_block(k, v, wrt=True)
1553 for k in d._wrt_variables):
1554 return True
1555 return False
1556 if not wrt and isinstance(d, AppliedUndef):
1557 return False
1558 if v.is_Symbol:
1559 return v in d.free_symbols
1560 if isinstance(v, AppliedUndef):
1561 return _block(d.xreplace({v: D}), D)
1562 return d.free_symbols & v.free_symbols
1563 for i in range(len(vc)):
1564 for j in range(i):
1565 if _block(v(j), v(i)):
1566 E.append((j,i))
1567 # this is the default ordering to use in case of ties
1568 O = dict(zip(ordered(uniq([i for i, c in vc])), range(len(vc))))
1569 ix = topological_sort((V, E), key=lambda i: O[v(i)])
1570 # merge counts of contiguously identical items
1571 merged = []
1572 for v, c in [vc[i] for i in ix]:
1573 if merged and merged[-1][0] == v:
1574 merged[-1][1] += c
1575 else:
1576 merged.append([v, c])
1577 return [Tuple(*i) for i in merged]
1579 def _eval_is_commutative(self):
1580 return self.expr.is_commutative
1582 def _eval_derivative(self, v):
1583 # If v (the variable of differentiation) is not in
1584 # self.variables, we might be able to take the derivative.
1585 if v not in self._wrt_variables:
1586 dedv = self.expr.diff(v)
1587 if isinstance(dedv, Derivative):
1588 return dedv.func(dedv.expr, *(self.variable_count + dedv.variable_count))
1589 # dedv (d(self.expr)/dv) could have simplified things such that the
1590 # derivative wrt things in self.variables can now be done. Thus,
1591 # we set evaluate=True to see if there are any other derivatives
1592 # that can be done. The most common case is when dedv is a simple
1593 # number so that the derivative wrt anything else will vanish.
1594 return self.func(dedv, *self.variables, evaluate=True)
1595 # In this case v was in self.variables so the derivative wrt v has
1596 # already been attempted and was not computed, either because it
1597 # couldn't be or evaluate=False originally.
1598 variable_count = list(self.variable_count)
1599 variable_count.append((v, 1))
1600 return self.func(self.expr, *variable_count, evaluate=False)
1602 def doit(self, **hints):
1603 expr = self.expr
1604 if hints.get('deep', True):
1605 expr = expr.doit(**hints)
1606 hints['evaluate'] = True
1607 rv = self.func(expr, *self.variable_count, **hints)
1608 if rv!= self and rv.has(Derivative):
1609 rv = rv.doit(**hints)
1610 return rv
1612 @_sympifyit('z0', NotImplementedError)
1613 def doit_numerically(self, z0):
1614 """
1615 Evaluate the derivative at z numerically.
1617 When we can represent derivatives at a point, this should be folded
1618 into the normal evalf. For now, we need a special method.
1619 """
1620 if len(self.free_symbols) != 1 or len(self.variables) != 1:
1621 raise NotImplementedError('partials and higher order derivatives')
1622 z = list(self.free_symbols)[0]
1624 def eval(x):
1625 f0 = self.expr.subs(z, Expr._from_mpmath(x, prec=mpmath.mp.prec))
1626 f0 = f0.evalf(prec_to_dps(mpmath.mp.prec))
1627 return f0._to_mpmath(mpmath.mp.prec)
1628 return Expr._from_mpmath(mpmath.diff(eval,
1629 z0._to_mpmath(mpmath.mp.prec)),
1630 mpmath.mp.prec)
1632 @property
1633 def expr(self):
1634 return self._args[0]
1636 @property
1637 def _wrt_variables(self):
1638 # return the variables of differentiation without
1639 # respect to the type of count (int or symbolic)
1640 return [i[0] for i in self.variable_count]
1642 @property
1643 def variables(self):
1644 # TODO: deprecate? YES, make this 'enumerated_variables' and
1645 # name _wrt_variables as variables
1646 # TODO: support for `d^n`?
1647 rv = []
1648 for v, count in self.variable_count:
1649 if not count.is_Integer:
1650 raise TypeError(filldedent('''
1651 Cannot give expansion for symbolic count. If you just
1652 want a list of all variables of differentiation, use
1653 _wrt_variables.'''))
1654 rv.extend([v]*count)
1655 return tuple(rv)
1657 @property
1658 def variable_count(self):
1659 return self._args[1:]
1661 @property
1662 def derivative_count(self):
1663 return sum([count for _, count in self.variable_count], 0)
1665 @property
1666 def free_symbols(self):
1667 ret = self.expr.free_symbols
1668 # Add symbolic counts to free_symbols
1669 for _, count in self.variable_count:
1670 ret.update(count.free_symbols)
1671 return ret
1673 @property
1674 def kind(self):
1675 return self.args[0].kind
1677 def _eval_subs(self, old, new):
1678 # The substitution (old, new) cannot be done inside
1679 # Derivative(expr, vars) for a variety of reasons
1680 # as handled below.
1681 if old in self._wrt_variables:
1682 # first handle the counts
1683 expr = self.func(self.expr, *[(v, c.subs(old, new))
1684 for v, c in self.variable_count])
1685 if expr != self:
1686 return expr._eval_subs(old, new)
1687 # quick exit case
1688 if not getattr(new, '_diff_wrt', False):
1689 # case (0): new is not a valid variable of
1690 # differentiation
1691 if isinstance(old, Symbol):
1692 # don't introduce a new symbol if the old will do
1693 return Subs(self, old, new)
1694 else:
1695 xi = Dummy('xi')
1696 return Subs(self.xreplace({old: xi}), xi, new)
1698 # If both are Derivatives with the same expr, check if old is
1699 # equivalent to self or if old is a subderivative of self.
1700 if old.is_Derivative and old.expr == self.expr:
1701 if self.canonical == old.canonical:
1702 return new
1704 # collections.Counter doesn't have __le__
1705 def _subset(a, b):
1706 return all((a[i] <= b[i]) == True for i in a)
1708 old_vars = Counter(dict(reversed(old.variable_count)))
1709 self_vars = Counter(dict(reversed(self.variable_count)))
1710 if _subset(old_vars, self_vars):
1711 return _derivative_dispatch(new, *(self_vars - old_vars).items()).canonical
1713 args = list(self.args)
1714 newargs = [x._subs(old, new) for x in args]
1715 if args[0] == old:
1716 # complete replacement of self.expr
1717 # we already checked that the new is valid so we know
1718 # it won't be a problem should it appear in variables
1719 return _derivative_dispatch(*newargs)
1721 if newargs[0] != args[0]:
1722 # case (1) can't change expr by introducing something that is in
1723 # the _wrt_variables if it was already in the expr
1724 # e.g.
1725 # for Derivative(f(x, g(y)), y), x cannot be replaced with
1726 # anything that has y in it; for f(g(x), g(y)).diff(g(y))
1727 # g(x) cannot be replaced with anything that has g(y)
1728 syms = {vi: Dummy() for vi in self._wrt_variables
1729 if not vi.is_Symbol}
1730 wrt = {syms.get(vi, vi) for vi in self._wrt_variables}
1731 forbidden = args[0].xreplace(syms).free_symbols & wrt
1732 nfree = new.xreplace(syms).free_symbols
1733 ofree = old.xreplace(syms).free_symbols
1734 if (nfree - ofree) & forbidden:
1735 return Subs(self, old, new)
1737 viter = ((i, j) for ((i, _), (j, _)) in zip(newargs[1:], args[1:]))
1738 if any(i != j for i, j in viter): # a wrt-variable change
1739 # case (2) can't change vars by introducing a variable
1740 # that is contained in expr, e.g.
1741 # for Derivative(f(z, g(h(x), y)), y), y cannot be changed to
1742 # x, h(x), or g(h(x), y)
1743 for a in _atomic(self.expr, recursive=True):
1744 for i in range(1, len(newargs)):
1745 vi, _ = newargs[i]
1746 if a == vi and vi != args[i][0]:
1747 return Subs(self, old, new)
1748 # more arg-wise checks
1749 vc = newargs[1:]
1750 oldv = self._wrt_variables
1751 newe = self.expr
1752 subs = []
1753 for i, (vi, ci) in enumerate(vc):
1754 if not vi._diff_wrt:
1755 # case (3) invalid differentiation expression so
1756 # create a replacement dummy
1757 xi = Dummy('xi_%i' % i)
1758 # replace the old valid variable with the dummy
1759 # in the expression
1760 newe = newe.xreplace({oldv[i]: xi})
1761 # and replace the bad variable with the dummy
1762 vc[i] = (xi, ci)
1763 # and record the dummy with the new (invalid)
1764 # differentiation expression
1765 subs.append((xi, vi))
1767 if subs:
1768 # handle any residual substitution in the expression
1769 newe = newe._subs(old, new)
1770 # return the Subs-wrapped derivative
1771 return Subs(Derivative(newe, *vc), *zip(*subs))
1773 # everything was ok
1774 return _derivative_dispatch(*newargs)
1776 def _eval_lseries(self, x, logx, cdir=0):
1777 dx = self.variables
1778 for term in self.expr.lseries(x, logx=logx, cdir=cdir):
1779 yield self.func(term, *dx)
1781 def _eval_nseries(self, x, n, logx, cdir=0):
1782 arg = self.expr.nseries(x, n=n, logx=logx)
1783 o = arg.getO()
1784 dx = self.variables
1785 rv = [self.func(a, *dx) for a in Add.make_args(arg.removeO())]
1786 if o:
1787 rv.append(o/x)
1788 return Add(*rv)
1790 def _eval_as_leading_term(self, x, logx=None, cdir=0):
1791 series_gen = self.expr.lseries(x)
1792 d = S.Zero
1793 for leading_term in series_gen:
1794 d = diff(leading_term, *self.variables)
1795 if d != 0:
1796 break
1797 return d
1799 def as_finite_difference(self, points=1, x0=None, wrt=None):
1800 """ Expresses a Derivative instance as a finite difference.
1802 Parameters
1803 ==========
1805 points : sequence or coefficient, optional
1806 If sequence: discrete values (length >= order+1) of the
1807 independent variable used for generating the finite
1808 difference weights.
1809 If it is a coefficient, it will be used as the step-size
1810 for generating an equidistant sequence of length order+1
1811 centered around ``x0``. Default: 1 (step-size 1)
1813 x0 : number or Symbol, optional
1814 the value of the independent variable (``wrt``) at which the
1815 derivative is to be approximated. Default: same as ``wrt``.
1817 wrt : Symbol, optional
1818 "with respect to" the variable for which the (partial)
1819 derivative is to be approximated for. If not provided it
1820 is required that the derivative is ordinary. Default: ``None``.
1823 Examples
1824 ========
1826 >>> from sympy import symbols, Function, exp, sqrt, Symbol
1827 >>> x, h = symbols('x h')
1828 >>> f = Function('f')
1829 >>> f(x).diff(x).as_finite_difference()
1830 -f(x - 1/2) + f(x + 1/2)
1832 The default step size and number of points are 1 and
1833 ``order + 1`` respectively. We can change the step size by
1834 passing a symbol as a parameter:
1836 >>> f(x).diff(x).as_finite_difference(h)
1837 -f(-h/2 + x)/h + f(h/2 + x)/h
1839 We can also specify the discretized values to be used in a
1840 sequence:
1842 >>> f(x).diff(x).as_finite_difference([x, x+h, x+2*h])
1843 -3*f(x)/(2*h) + 2*f(h + x)/h - f(2*h + x)/(2*h)
1845 The algorithm is not restricted to use equidistant spacing, nor
1846 do we need to make the approximation around ``x0``, but we can get
1847 an expression estimating the derivative at an offset:
1849 >>> e, sq2 = exp(1), sqrt(2)
1850 >>> xl = [x-h, x+h, x+e*h]
1851 >>> f(x).diff(x, 1).as_finite_difference(xl, x+h*sq2) # doctest: +ELLIPSIS
1852 2*h*((h + sqrt(2)*h)/(2*h) - (-sqrt(2)*h + h)/(2*h))*f(E*h + x)/...
1854 To approximate ``Derivative`` around ``x0`` using a non-equidistant
1855 spacing step, the algorithm supports assignment of undefined
1856 functions to ``points``:
1858 >>> dx = Function('dx')
1859 >>> f(x).diff(x).as_finite_difference(points=dx(x), x0=x-h)
1860 -f(-h + x - dx(-h + x)/2)/dx(-h + x) + f(-h + x + dx(-h + x)/2)/dx(-h + x)
1862 Partial derivatives are also supported:
1864 >>> y = Symbol('y')
1865 >>> d2fdxdy=f(x,y).diff(x,y)
1866 >>> d2fdxdy.as_finite_difference(wrt=x)
1867 -Derivative(f(x - 1/2, y), y) + Derivative(f(x + 1/2, y), y)
1869 We can apply ``as_finite_difference`` to ``Derivative`` instances in
1870 compound expressions using ``replace``:
1872 >>> (1 + 42**f(x).diff(x)).replace(lambda arg: arg.is_Derivative,
1873 ... lambda arg: arg.as_finite_difference())
1874 42**(-f(x - 1/2) + f(x + 1/2)) + 1
1877 See also
1878 ========
1880 sympy.calculus.finite_diff.apply_finite_diff
1881 sympy.calculus.finite_diff.differentiate_finite
1882 sympy.calculus.finite_diff.finite_diff_weights
1884 """
1885 from sympy.calculus.finite_diff import _as_finite_diff
1886 return _as_finite_diff(self, points, x0, wrt)
1888 @classmethod
1889 def _get_zero_with_shape_like(cls, expr):
1890 return S.Zero
1892 @classmethod
1893 def _dispatch_eval_derivative_n_times(cls, expr, v, count):
1894 # Evaluate the derivative `n` times. If
1895 # `_eval_derivative_n_times` is not overridden by the current
1896 # object, the default in `Basic` will call a loop over
1897 # `_eval_derivative`:
1898 return expr._eval_derivative_n_times(v, count)
1901def _derivative_dispatch(expr, *variables, **kwargs):
1902 from sympy.matrices.common import MatrixCommon
1903 from sympy.matrices.expressions.matexpr import MatrixExpr
1904 from sympy.tensor.array import NDimArray
1905 array_types = (MatrixCommon, MatrixExpr, NDimArray, list, tuple, Tuple)
1906 if isinstance(expr, array_types) or any(isinstance(i[0], array_types) if isinstance(i, (tuple, list, Tuple)) else isinstance(i, array_types) for i in variables):
1907 from sympy.tensor.array.array_derivatives import ArrayDerivative
1908 return ArrayDerivative(expr, *variables, **kwargs)
1909 return Derivative(expr, *variables, **kwargs)
1912class Lambda(Expr):
1913 """
1914 Lambda(x, expr) represents a lambda function similar to Python's
1915 'lambda x: expr'. A function of several variables is written as
1916 Lambda((x, y, ...), expr).
1918 Examples
1919 ========
1921 A simple example:
1923 >>> from sympy import Lambda
1924 >>> from sympy.abc import x
1925 >>> f = Lambda(x, x**2)
1926 >>> f(4)
1927 16
1929 For multivariate functions, use:
1931 >>> from sympy.abc import y, z, t
1932 >>> f2 = Lambda((x, y, z, t), x + y**z + t**z)
1933 >>> f2(1, 2, 3, 4)
1934 73
1936 It is also possible to unpack tuple arguments:
1938 >>> f = Lambda(((x, y), z), x + y + z)
1939 >>> f((1, 2), 3)
1940 6
1942 A handy shortcut for lots of arguments:
1944 >>> p = x, y, z
1945 >>> f = Lambda(p, x + y*z)
1946 >>> f(*p)
1947 x + y*z
1949 """
1950 is_Function = True
1952 def __new__(cls, signature, expr):
1953 if iterable(signature) and not isinstance(signature, (tuple, Tuple)):
1954 sympy_deprecation_warning(
1955 """
1956 Using a non-tuple iterable as the first argument to Lambda
1957 is deprecated. Use Lambda(tuple(args), expr) instead.
1958 """,
1959 deprecated_since_version="1.5",
1960 active_deprecations_target="deprecated-non-tuple-lambda",
1961 )
1962 signature = tuple(signature)
1963 sig = signature if iterable(signature) else (signature,)
1964 sig = sympify(sig)
1965 cls._check_signature(sig)
1967 if len(sig) == 1 and sig[0] == expr:
1968 return S.IdentityFunction
1970 return Expr.__new__(cls, sig, sympify(expr))
1972 @classmethod
1973 def _check_signature(cls, sig):
1974 syms = set()
1976 def rcheck(args):
1977 for a in args:
1978 if a.is_symbol:
1979 if a in syms:
1980 raise BadSignatureError("Duplicate symbol %s" % a)
1981 syms.add(a)
1982 elif isinstance(a, Tuple):
1983 rcheck(a)
1984 else:
1985 raise BadSignatureError("Lambda signature should be only tuples"
1986 " and symbols, not %s" % a)
1988 if not isinstance(sig, Tuple):
1989 raise BadSignatureError("Lambda signature should be a tuple not %s" % sig)
1990 # Recurse through the signature:
1991 rcheck(sig)
1993 @property
1994 def signature(self):
1995 """The expected form of the arguments to be unpacked into variables"""
1996 return self._args[0]
1998 @property
1999 def expr(self):
2000 """The return value of the function"""
2001 return self._args[1]
2003 @property
2004 def variables(self):
2005 """The variables used in the internal representation of the function"""
2006 def _variables(args):
2007 if isinstance(args, Tuple):
2008 for arg in args:
2009 yield from _variables(arg)
2010 else:
2011 yield args
2012 return tuple(_variables(self.signature))
2014 @property
2015 def nargs(self):
2016 from sympy.sets.sets import FiniteSet
2017 return FiniteSet(len(self.signature))
2019 bound_symbols = variables
2021 @property
2022 def free_symbols(self):
2023 return self.expr.free_symbols - set(self.variables)
2025 def __call__(self, *args):
2026 n = len(args)
2027 if n not in self.nargs: # Lambda only ever has 1 value in nargs
2028 # XXX: exception message must be in exactly this format to
2029 # make it work with NumPy's functions like vectorize(). See,
2030 # for example, https://github.com/numpy/numpy/issues/1697.
2031 # The ideal solution would be just to attach metadata to
2032 # the exception and change NumPy to take advantage of this.
2033 ## XXX does this apply to Lambda? If not, remove this comment.
2034 temp = ('%(name)s takes exactly %(args)s '
2035 'argument%(plural)s (%(given)s given)')
2036 raise BadArgumentsError(temp % {
2037 'name': self,
2038 'args': list(self.nargs)[0],
2039 'plural': 's'*(list(self.nargs)[0] != 1),
2040 'given': n})
2042 d = self._match_signature(self.signature, args)
2044 return self.expr.xreplace(d)
2046 def _match_signature(self, sig, args):
2048 symargmap = {}
2050 def rmatch(pars, args):
2051 for par, arg in zip(pars, args):
2052 if par.is_symbol:
2053 symargmap[par] = arg
2054 elif isinstance(par, Tuple):
2055 if not isinstance(arg, (tuple, Tuple)) or len(args) != len(pars):
2056 raise BadArgumentsError("Can't match %s and %s" % (args, pars))
2057 rmatch(par, arg)
2059 rmatch(sig, args)
2061 return symargmap
2063 @property
2064 def is_identity(self):
2065 """Return ``True`` if this ``Lambda`` is an identity function. """
2066 return self.signature == self.expr
2068 def _eval_evalf(self, prec):
2069 return self.func(self.args[0], self.args[1].evalf(n=prec_to_dps(prec)))
2072class Subs(Expr):
2073 """
2074 Represents unevaluated substitutions of an expression.
2076 ``Subs(expr, x, x0)`` represents the expression resulting
2077 from substituting x with x0 in expr.
2079 Parameters
2080 ==========
2082 expr : Expr
2083 An expression.
2085 x : tuple, variable
2086 A variable or list of distinct variables.
2088 x0 : tuple or list of tuples
2089 A point or list of evaluation points
2090 corresponding to those variables.
2092 Examples
2093 ========
2095 >>> from sympy import Subs, Function, sin, cos
2096 >>> from sympy.abc import x, y, z
2097 >>> f = Function('f')
2099 Subs are created when a particular substitution cannot be made. The
2100 x in the derivative cannot be replaced with 0 because 0 is not a
2101 valid variables of differentiation:
2103 >>> f(x).diff(x).subs(x, 0)
2104 Subs(Derivative(f(x), x), x, 0)
2106 Once f is known, the derivative and evaluation at 0 can be done:
2108 >>> _.subs(f, sin).doit() == sin(x).diff(x).subs(x, 0) == cos(0)
2109 True
2111 Subs can also be created directly with one or more variables:
2113 >>> Subs(f(x)*sin(y) + z, (x, y), (0, 1))
2114 Subs(z + f(x)*sin(y), (x, y), (0, 1))
2115 >>> _.doit()
2116 z + f(0)*sin(1)
2118 Notes
2119 =====
2121 ``Subs`` objects are generally useful to represent unevaluated derivatives
2122 calculated at a point.
2124 The variables may be expressions, but they are subjected to the limitations
2125 of subs(), so it is usually a good practice to use only symbols for
2126 variables, since in that case there can be no ambiguity.
2128 There's no automatic expansion - use the method .doit() to effect all
2129 possible substitutions of the object and also of objects inside the
2130 expression.
2132 When evaluating derivatives at a point that is not a symbol, a Subs object
2133 is returned. One is also able to calculate derivatives of Subs objects - in
2134 this case the expression is always expanded (for the unevaluated form, use
2135 Derivative()).
2137 In order to allow expressions to combine before doit is done, a
2138 representation of the Subs expression is used internally to make
2139 expressions that are superficially different compare the same:
2141 >>> a, b = Subs(x, x, 0), Subs(y, y, 0)
2142 >>> a + b
2143 2*Subs(x, x, 0)
2145 This can lead to unexpected consequences when using methods
2146 like `has` that are cached:
2148 >>> s = Subs(x, x, 0)
2149 >>> s.has(x), s.has(y)
2150 (True, False)
2151 >>> ss = s.subs(x, y)
2152 >>> ss.has(x), ss.has(y)
2153 (True, False)
2154 >>> s, ss
2155 (Subs(x, x, 0), Subs(y, y, 0))
2156 """
2157 def __new__(cls, expr, variables, point, **assumptions):
2158 if not is_sequence(variables, Tuple):
2159 variables = [variables]
2160 variables = Tuple(*variables)
2162 if has_dups(variables):
2163 repeated = [str(v) for v, i in Counter(variables).items() if i > 1]
2164 __ = ', '.join(repeated)
2165 raise ValueError(filldedent('''
2166 The following expressions appear more than once: %s
2167 ''' % __))
2169 point = Tuple(*(point if is_sequence(point, Tuple) else [point]))
2171 if len(point) != len(variables):
2172 raise ValueError('Number of point values must be the same as '
2173 'the number of variables.')
2175 if not point:
2176 return sympify(expr)
2178 # denest
2179 if isinstance(expr, Subs):
2180 variables = expr.variables + variables
2181 point = expr.point + point
2182 expr = expr.expr
2183 else:
2184 expr = sympify(expr)
2186 # use symbols with names equal to the point value (with prepended _)
2187 # to give a variable-independent expression
2188 pre = "_"
2189 pts = sorted(set(point), key=default_sort_key)
2190 from sympy.printing.str import StrPrinter
2191 class CustomStrPrinter(StrPrinter):
2192 def _print_Dummy(self, expr):
2193 return str(expr) + str(expr.dummy_index)
2194 def mystr(expr, **settings):
2195 p = CustomStrPrinter(settings)
2196 return p.doprint(expr)
2197 while 1:
2198 s_pts = {p: Symbol(pre + mystr(p)) for p in pts}
2199 reps = [(v, s_pts[p])
2200 for v, p in zip(variables, point)]
2201 # if any underscore-prepended symbol is already a free symbol
2202 # and is a variable with a different point value, then there
2203 # is a clash, e.g. _0 clashes in Subs(_0 + _1, (_0, _1), (1, 0))
2204 # because the new symbol that would be created is _1 but _1
2205 # is already mapped to 0 so __0 and __1 are used for the new
2206 # symbols
2207 if any(r in expr.free_symbols and
2208 r in variables and
2209 Symbol(pre + mystr(point[variables.index(r)])) != r
2210 for _, r in reps):
2211 pre += "_"
2212 continue
2213 break
2215 obj = Expr.__new__(cls, expr, Tuple(*variables), point)
2216 obj._expr = expr.xreplace(dict(reps))
2217 return obj
2219 def _eval_is_commutative(self):
2220 return self.expr.is_commutative
2222 def doit(self, **hints):
2223 e, v, p = self.args
2225 # remove self mappings
2226 for i, (vi, pi) in enumerate(zip(v, p)):
2227 if vi == pi:
2228 v = v[:i] + v[i + 1:]
2229 p = p[:i] + p[i + 1:]
2230 if not v:
2231 return self.expr
2233 if isinstance(e, Derivative):
2234 # apply functions first, e.g. f -> cos
2235 undone = []
2236 for i, vi in enumerate(v):
2237 if isinstance(vi, FunctionClass):
2238 e = e.subs(vi, p[i])
2239 else:
2240 undone.append((vi, p[i]))
2241 if not isinstance(e, Derivative):
2242 e = e.doit()
2243 if isinstance(e, Derivative):
2244 # do Subs that aren't related to differentiation
2245 undone2 = []
2246 D = Dummy()
2247 arg = e.args[0]
2248 for vi, pi in undone:
2249 if D not in e.xreplace({vi: D}).free_symbols:
2250 if arg.has(vi):
2251 e = e.subs(vi, pi)
2252 else:
2253 undone2.append((vi, pi))
2254 undone = undone2
2255 # differentiate wrt variables that are present
2256 wrt = []
2257 D = Dummy()
2258 expr = e.expr
2259 free = expr.free_symbols
2260 for vi, ci in e.variable_count:
2261 if isinstance(vi, Symbol) and vi in free:
2262 expr = expr.diff((vi, ci))
2263 elif D in expr.subs(vi, D).free_symbols:
2264 expr = expr.diff((vi, ci))
2265 else:
2266 wrt.append((vi, ci))
2267 # inject remaining subs
2268 rv = expr.subs(undone)
2269 # do remaining differentiation *in order given*
2270 for vc in wrt:
2271 rv = rv.diff(vc)
2272 else:
2273 # inject remaining subs
2274 rv = e.subs(undone)
2275 else:
2276 rv = e.doit(**hints).subs(list(zip(v, p)))
2278 if hints.get('deep', True) and rv != self:
2279 rv = rv.doit(**hints)
2280 return rv
2282 def evalf(self, prec=None, **options):
2283 return self.doit().evalf(prec, **options)
2285 n = evalf # type:ignore
2287 @property
2288 def variables(self):
2289 """The variables to be evaluated"""
2290 return self._args[1]
2292 bound_symbols = variables
2294 @property
2295 def expr(self):
2296 """The expression on which the substitution operates"""
2297 return self._args[0]
2299 @property
2300 def point(self):
2301 """The values for which the variables are to be substituted"""
2302 return self._args[2]
2304 @property
2305 def free_symbols(self):
2306 return (self.expr.free_symbols - set(self.variables) |
2307 set(self.point.free_symbols))
2309 @property
2310 def expr_free_symbols(self):
2311 sympy_deprecation_warning("""
2312 The expr_free_symbols property is deprecated. Use free_symbols to get
2313 the free symbols of an expression.
2314 """,
2315 deprecated_since_version="1.9",
2316 active_deprecations_target="deprecated-expr-free-symbols")
2317 # Don't show the warning twice from the recursive call
2318 with ignore_warnings(SymPyDeprecationWarning):
2319 return (self.expr.expr_free_symbols - set(self.variables) |
2320 set(self.point.expr_free_symbols))
2322 def __eq__(self, other):
2323 if not isinstance(other, Subs):
2324 return False
2325 return self._hashable_content() == other._hashable_content()
2327 def __ne__(self, other):
2328 return not(self == other)
2330 def __hash__(self):
2331 return super().__hash__()
2333 def _hashable_content(self):
2334 return (self._expr.xreplace(self.canonical_variables),
2335 ) + tuple(ordered([(v, p) for v, p in
2336 zip(self.variables, self.point) if not self.expr.has(v)]))
2338 def _eval_subs(self, old, new):
2339 # Subs doit will do the variables in order; the semantics
2340 # of subs for Subs is have the following invariant for
2341 # Subs object foo:
2342 # foo.doit().subs(reps) == foo.subs(reps).doit()
2343 pt = list(self.point)
2344 if old in self.variables:
2345 if _atomic(new) == {new} and not any(
2346 i.has(new) for i in self.args):
2347 # the substitution is neutral
2348 return self.xreplace({old: new})
2349 # any occurrence of old before this point will get
2350 # handled by replacements from here on
2351 i = self.variables.index(old)
2352 for j in range(i, len(self.variables)):
2353 pt[j] = pt[j]._subs(old, new)
2354 return self.func(self.expr, self.variables, pt)
2355 v = [i._subs(old, new) for i in self.variables]
2356 if v != list(self.variables):
2357 return self.func(self.expr, self.variables + (old,), pt + [new])
2358 expr = self.expr._subs(old, new)
2359 pt = [i._subs(old, new) for i in self.point]
2360 return self.func(expr, v, pt)
2362 def _eval_derivative(self, s):
2363 # Apply the chain rule of the derivative on the substitution variables:
2364 f = self.expr
2365 vp = V, P = self.variables, self.point
2366 val = Add.fromiter(p.diff(s)*Subs(f.diff(v), *vp).doit()
2367 for v, p in zip(V, P))
2369 # these are all the free symbols in the expr
2370 efree = f.free_symbols
2371 # some symbols like IndexedBase include themselves and args
2372 # as free symbols
2373 compound = {i for i in efree if len(i.free_symbols) > 1}
2374 # hide them and see what independent free symbols remain
2375 dums = {Dummy() for i in compound}
2376 masked = f.xreplace(dict(zip(compound, dums)))
2377 ifree = masked.free_symbols - dums
2378 # include the compound symbols
2379 free = ifree | compound
2380 # remove the variables already handled
2381 free -= set(V)
2382 # add back any free symbols of remaining compound symbols
2383 free |= {i for j in free & compound for i in j.free_symbols}
2384 # if symbols of s are in free then there is more to do
2385 if free & s.free_symbols:
2386 val += Subs(f.diff(s), self.variables, self.point).doit()
2387 return val
2389 def _eval_nseries(self, x, n, logx, cdir=0):
2390 if x in self.point:
2391 # x is the variable being substituted into
2392 apos = self.point.index(x)
2393 other = self.variables[apos]
2394 else:
2395 other = x
2396 arg = self.expr.nseries(other, n=n, logx=logx)
2397 o = arg.getO()
2398 terms = Add.make_args(arg.removeO())
2399 rv = Add(*[self.func(a, *self.args[1:]) for a in terms])
2400 if o:
2401 rv += o.subs(other, x)
2402 return rv
2404 def _eval_as_leading_term(self, x, logx=None, cdir=0):
2405 if x in self.point:
2406 ipos = self.point.index(x)
2407 xvar = self.variables[ipos]
2408 return self.expr.as_leading_term(xvar)
2409 if x in self.variables:
2410 # if `x` is a dummy variable, it means it won't exist after the
2411 # substitution has been performed:
2412 return self
2413 # The variable is independent of the substitution:
2414 return self.expr.as_leading_term(x)
2417def diff(f, *symbols, **kwargs):
2418 """
2419 Differentiate f with respect to symbols.
2421 Explanation
2422 ===========
2424 This is just a wrapper to unify .diff() and the Derivative class; its
2425 interface is similar to that of integrate(). You can use the same
2426 shortcuts for multiple variables as with Derivative. For example,
2427 diff(f(x), x, x, x) and diff(f(x), x, 3) both return the third derivative
2428 of f(x).
2430 You can pass evaluate=False to get an unevaluated Derivative class. Note
2431 that if there are 0 symbols (such as diff(f(x), x, 0), then the result will
2432 be the function (the zeroth derivative), even if evaluate=False.
2434 Examples
2435 ========
2437 >>> from sympy import sin, cos, Function, diff
2438 >>> from sympy.abc import x, y
2439 >>> f = Function('f')
2441 >>> diff(sin(x), x)
2442 cos(x)
2443 >>> diff(f(x), x, x, x)
2444 Derivative(f(x), (x, 3))
2445 >>> diff(f(x), x, 3)
2446 Derivative(f(x), (x, 3))
2447 >>> diff(sin(x)*cos(y), x, 2, y, 2)
2448 sin(x)*cos(y)
2450 >>> type(diff(sin(x), x))
2451 cos
2452 >>> type(diff(sin(x), x, evaluate=False))
2453 <class 'sympy.core.function.Derivative'>
2454 >>> type(diff(sin(x), x, 0))
2455 sin
2456 >>> type(diff(sin(x), x, 0, evaluate=False))
2457 sin
2459 >>> diff(sin(x))
2460 cos(x)
2461 >>> diff(sin(x*y))
2462 Traceback (most recent call last):
2463 ...
2464 ValueError: specify differentiation variables to differentiate sin(x*y)
2466 Note that ``diff(sin(x))`` syntax is meant only for convenience
2467 in interactive sessions and should be avoided in library code.
2469 References
2470 ==========
2472 .. [1] https://reference.wolfram.com/legacy/v5_2/Built-inFunctions/AlgebraicComputation/Calculus/D.html
2474 See Also
2475 ========
2477 Derivative
2478 idiff: computes the derivative implicitly
2480 """
2481 if hasattr(f, 'diff'):
2482 return f.diff(*symbols, **kwargs)
2483 kwargs.setdefault('evaluate', True)
2484 return _derivative_dispatch(f, *symbols, **kwargs)
2487def expand(e, deep=True, modulus=None, power_base=True, power_exp=True,
2488 mul=True, log=True, multinomial=True, basic=True, **hints):
2489 r"""
2490 Expand an expression using methods given as hints.
2492 Explanation
2493 ===========
2495 Hints evaluated unless explicitly set to False are: ``basic``, ``log``,
2496 ``multinomial``, ``mul``, ``power_base``, and ``power_exp`` The following
2497 hints are supported but not applied unless set to True: ``complex``,
2498 ``func``, and ``trig``. In addition, the following meta-hints are
2499 supported by some or all of the other hints: ``frac``, ``numer``,
2500 ``denom``, ``modulus``, and ``force``. ``deep`` is supported by all
2501 hints. Additionally, subclasses of Expr may define their own hints or
2502 meta-hints.
2504 The ``basic`` hint is used for any special rewriting of an object that
2505 should be done automatically (along with the other hints like ``mul``)
2506 when expand is called. This is a catch-all hint to handle any sort of
2507 expansion that may not be described by the existing hint names. To use
2508 this hint an object should override the ``_eval_expand_basic`` method.
2509 Objects may also define their own expand methods, which are not run by
2510 default. See the API section below.
2512 If ``deep`` is set to ``True`` (the default), things like arguments of
2513 functions are recursively expanded. Use ``deep=False`` to only expand on
2514 the top level.
2516 If the ``force`` hint is used, assumptions about variables will be ignored
2517 in making the expansion.
2519 Hints
2520 =====
2522 These hints are run by default
2524 mul
2525 ---
2527 Distributes multiplication over addition:
2529 >>> from sympy import cos, exp, sin
2530 >>> from sympy.abc import x, y, z
2531 >>> (y*(x + z)).expand(mul=True)
2532 x*y + y*z
2534 multinomial
2535 -----------
2537 Expand (x + y + ...)**n where n is a positive integer.
2539 >>> ((x + y + z)**2).expand(multinomial=True)
2540 x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2
2542 power_exp
2543 ---------
2545 Expand addition in exponents into multiplied bases.
2547 >>> exp(x + y).expand(power_exp=True)
2548 exp(x)*exp(y)
2549 >>> (2**(x + y)).expand(power_exp=True)
2550 2**x*2**y
2552 power_base
2553 ----------
2555 Split powers of multiplied bases.
2557 This only happens by default if assumptions allow, or if the
2558 ``force`` meta-hint is used:
2560 >>> ((x*y)**z).expand(power_base=True)
2561 (x*y)**z
2562 >>> ((x*y)**z).expand(power_base=True, force=True)
2563 x**z*y**z
2564 >>> ((2*y)**z).expand(power_base=True)
2565 2**z*y**z
2567 Note that in some cases where this expansion always holds, SymPy performs
2568 it automatically:
2570 >>> (x*y)**2
2571 x**2*y**2
2573 log
2574 ---
2576 Pull out power of an argument as a coefficient and split logs products
2577 into sums of logs.
2579 Note that these only work if the arguments of the log function have the
2580 proper assumptions--the arguments must be positive and the exponents must
2581 be real--or else the ``force`` hint must be True:
2583 >>> from sympy import log, symbols
2584 >>> log(x**2*y).expand(log=True)
2585 log(x**2*y)
2586 >>> log(x**2*y).expand(log=True, force=True)
2587 2*log(x) + log(y)
2588 >>> x, y = symbols('x,y', positive=True)
2589 >>> log(x**2*y).expand(log=True)
2590 2*log(x) + log(y)
2592 basic
2593 -----
2595 This hint is intended primarily as a way for custom subclasses to enable
2596 expansion by default.
2598 These hints are not run by default:
2600 complex
2601 -------
2603 Split an expression into real and imaginary parts.
2605 >>> x, y = symbols('x,y')
2606 >>> (x + y).expand(complex=True)
2607 re(x) + re(y) + I*im(x) + I*im(y)
2608 >>> cos(x).expand(complex=True)
2609 -I*sin(re(x))*sinh(im(x)) + cos(re(x))*cosh(im(x))
2611 Note that this is just a wrapper around ``as_real_imag()``. Most objects
2612 that wish to redefine ``_eval_expand_complex()`` should consider
2613 redefining ``as_real_imag()`` instead.
2615 func
2616 ----
2618 Expand other functions.
2620 >>> from sympy import gamma
2621 >>> gamma(x + 1).expand(func=True)
2622 x*gamma(x)
2624 trig
2625 ----
2627 Do trigonometric expansions.
2629 >>> cos(x + y).expand(trig=True)
2630 -sin(x)*sin(y) + cos(x)*cos(y)
2631 >>> sin(2*x).expand(trig=True)
2632 2*sin(x)*cos(x)
2634 Note that the forms of ``sin(n*x)`` and ``cos(n*x)`` in terms of ``sin(x)``
2635 and ``cos(x)`` are not unique, due to the identity `\sin^2(x) + \cos^2(x)
2636 = 1`. The current implementation uses the form obtained from Chebyshev
2637 polynomials, but this may change. See `this MathWorld article
2638 <https://mathworld.wolfram.com/Multiple-AngleFormulas.html>`_ for more
2639 information.
2641 Notes
2642 =====
2644 - You can shut off unwanted methods::
2646 >>> (exp(x + y)*(x + y)).expand()
2647 x*exp(x)*exp(y) + y*exp(x)*exp(y)
2648 >>> (exp(x + y)*(x + y)).expand(power_exp=False)
2649 x*exp(x + y) + y*exp(x + y)
2650 >>> (exp(x + y)*(x + y)).expand(mul=False)
2651 (x + y)*exp(x)*exp(y)
2653 - Use deep=False to only expand on the top level::
2655 >>> exp(x + exp(x + y)).expand()
2656 exp(x)*exp(exp(x)*exp(y))
2657 >>> exp(x + exp(x + y)).expand(deep=False)
2658 exp(x)*exp(exp(x + y))
2660 - Hints are applied in an arbitrary, but consistent order (in the current
2661 implementation, they are applied in alphabetical order, except
2662 multinomial comes before mul, but this may change). Because of this,
2663 some hints may prevent expansion by other hints if they are applied
2664 first. For example, ``mul`` may distribute multiplications and prevent
2665 ``log`` and ``power_base`` from expanding them. Also, if ``mul`` is
2666 applied before ``multinomial`, the expression might not be fully
2667 distributed. The solution is to use the various ``expand_hint`` helper
2668 functions or to use ``hint=False`` to this function to finely control
2669 which hints are applied. Here are some examples::
2671 >>> from sympy import expand, expand_mul, expand_power_base
2672 >>> x, y, z = symbols('x,y,z', positive=True)
2674 >>> expand(log(x*(y + z)))
2675 log(x) + log(y + z)
2677 Here, we see that ``log`` was applied before ``mul``. To get the mul
2678 expanded form, either of the following will work::
2680 >>> expand_mul(log(x*(y + z)))
2681 log(x*y + x*z)
2682 >>> expand(log(x*(y + z)), log=False)
2683 log(x*y + x*z)
2685 A similar thing can happen with the ``power_base`` hint::
2687 >>> expand((x*(y + z))**x)
2688 (x*y + x*z)**x
2690 To get the ``power_base`` expanded form, either of the following will
2691 work::
2693 >>> expand((x*(y + z))**x, mul=False)
2694 x**x*(y + z)**x
2695 >>> expand_power_base((x*(y + z))**x)
2696 x**x*(y + z)**x
2698 >>> expand((x + y)*y/x)
2699 y + y**2/x
2701 The parts of a rational expression can be targeted::
2703 >>> expand((x + y)*y/x/(x + 1), frac=True)
2704 (x*y + y**2)/(x**2 + x)
2705 >>> expand((x + y)*y/x/(x + 1), numer=True)
2706 (x*y + y**2)/(x*(x + 1))
2707 >>> expand((x + y)*y/x/(x + 1), denom=True)
2708 y*(x + y)/(x**2 + x)
2710 - The ``modulus`` meta-hint can be used to reduce the coefficients of an
2711 expression post-expansion::
2713 >>> expand((3*x + 1)**2)
2714 9*x**2 + 6*x + 1
2715 >>> expand((3*x + 1)**2, modulus=5)
2716 4*x**2 + x + 1
2718 - Either ``expand()`` the function or ``.expand()`` the method can be
2719 used. Both are equivalent::
2721 >>> expand((x + 1)**2)
2722 x**2 + 2*x + 1
2723 >>> ((x + 1)**2).expand()
2724 x**2 + 2*x + 1
2726 API
2727 ===
2729 Objects can define their own expand hints by defining
2730 ``_eval_expand_hint()``. The function should take the form::
2732 def _eval_expand_hint(self, **hints):
2733 # Only apply the method to the top-level expression
2734 ...
2736 See also the example below. Objects should define ``_eval_expand_hint()``
2737 methods only if ``hint`` applies to that specific object. The generic
2738 ``_eval_expand_hint()`` method defined in Expr will handle the no-op case.
2740 Each hint should be responsible for expanding that hint only.
2741 Furthermore, the expansion should be applied to the top-level expression
2742 only. ``expand()`` takes care of the recursion that happens when
2743 ``deep=True``.
2745 You should only call ``_eval_expand_hint()`` methods directly if you are
2746 100% sure that the object has the method, as otherwise you are liable to
2747 get unexpected ``AttributeError``s. Note, again, that you do not need to
2748 recursively apply the hint to args of your object: this is handled
2749 automatically by ``expand()``. ``_eval_expand_hint()`` should
2750 generally not be used at all outside of an ``_eval_expand_hint()`` method.
2751 If you want to apply a specific expansion from within another method, use
2752 the public ``expand()`` function, method, or ``expand_hint()`` functions.
2754 In order for expand to work, objects must be rebuildable by their args,
2755 i.e., ``obj.func(*obj.args) == obj`` must hold.
2757 Expand methods are passed ``**hints`` so that expand hints may use
2758 'metahints'--hints that control how different expand methods are applied.
2759 For example, the ``force=True`` hint described above that causes
2760 ``expand(log=True)`` to ignore assumptions is such a metahint. The
2761 ``deep`` meta-hint is handled exclusively by ``expand()`` and is not
2762 passed to ``_eval_expand_hint()`` methods.
2764 Note that expansion hints should generally be methods that perform some
2765 kind of 'expansion'. For hints that simply rewrite an expression, use the
2766 .rewrite() API.
2768 Examples
2769 ========
2771 >>> from sympy import Expr, sympify
2772 >>> class MyClass(Expr):
2773 ... def __new__(cls, *args):
2774 ... args = sympify(args)
2775 ... return Expr.__new__(cls, *args)
2776 ...
2777 ... def _eval_expand_double(self, *, force=False, **hints):
2778 ... '''
2779 ... Doubles the args of MyClass.
2780 ...
2781 ... If there more than four args, doubling is not performed,
2782 ... unless force=True is also used (False by default).
2783 ... '''
2784 ... if not force and len(self.args) > 4:
2785 ... return self
2786 ... return self.func(*(self.args + self.args))
2787 ...
2788 >>> a = MyClass(1, 2, MyClass(3, 4))
2789 >>> a
2790 MyClass(1, 2, MyClass(3, 4))
2791 >>> a.expand(double=True)
2792 MyClass(1, 2, MyClass(3, 4, 3, 4), 1, 2, MyClass(3, 4, 3, 4))
2793 >>> a.expand(double=True, deep=False)
2794 MyClass(1, 2, MyClass(3, 4), 1, 2, MyClass(3, 4))
2796 >>> b = MyClass(1, 2, 3, 4, 5)
2797 >>> b.expand(double=True)
2798 MyClass(1, 2, 3, 4, 5)
2799 >>> b.expand(double=True, force=True)
2800 MyClass(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
2802 See Also
2803 ========
2805 expand_log, expand_mul, expand_multinomial, expand_complex, expand_trig,
2806 expand_power_base, expand_power_exp, expand_func, sympy.simplify.hyperexpand.hyperexpand
2808 """
2809 # don't modify this; modify the Expr.expand method
2810 hints['power_base'] = power_base
2811 hints['power_exp'] = power_exp
2812 hints['mul'] = mul
2813 hints['log'] = log
2814 hints['multinomial'] = multinomial
2815 hints['basic'] = basic
2816 return sympify(e).expand(deep=deep, modulus=modulus, **hints)
2818# This is a special application of two hints
2820def _mexpand(expr, recursive=False):
2821 # expand multinomials and then expand products; this may not always
2822 # be sufficient to give a fully expanded expression (see
2823 # test_issue_8247_8354 in test_arit)
2824 if expr is None:
2825 return
2826 was = None
2827 while was != expr:
2828 was, expr = expr, expand_mul(expand_multinomial(expr))
2829 if not recursive:
2830 break
2831 return expr
2834# These are simple wrappers around single hints.
2837def expand_mul(expr, deep=True):
2838 """
2839 Wrapper around expand that only uses the mul hint. See the expand
2840 docstring for more information.
2842 Examples
2843 ========
2845 >>> from sympy import symbols, expand_mul, exp, log
2846 >>> x, y = symbols('x,y', positive=True)
2847 >>> expand_mul(exp(x+y)*(x+y)*log(x*y**2))
2848 x*exp(x + y)*log(x*y**2) + y*exp(x + y)*log(x*y**2)
2850 """
2851 return sympify(expr).expand(deep=deep, mul=True, power_exp=False,
2852 power_base=False, basic=False, multinomial=False, log=False)
2855def expand_multinomial(expr, deep=True):
2856 """
2857 Wrapper around expand that only uses the multinomial hint. See the expand
2858 docstring for more information.
2860 Examples
2861 ========
2863 >>> from sympy import symbols, expand_multinomial, exp
2864 >>> x, y = symbols('x y', positive=True)
2865 >>> expand_multinomial((x + exp(x + 1))**2)
2866 x**2 + 2*x*exp(x + 1) + exp(2*x + 2)
2868 """
2869 return sympify(expr).expand(deep=deep, mul=False, power_exp=False,
2870 power_base=False, basic=False, multinomial=True, log=False)
2873def expand_log(expr, deep=True, force=False, factor=False):
2874 """
2875 Wrapper around expand that only uses the log hint. See the expand
2876 docstring for more information.
2878 Examples
2879 ========
2881 >>> from sympy import symbols, expand_log, exp, log
2882 >>> x, y = symbols('x,y', positive=True)
2883 >>> expand_log(exp(x+y)*(x+y)*log(x*y**2))
2884 (x + y)*(log(x) + 2*log(y))*exp(x + y)
2886 """
2887 from sympy.functions.elementary.exponential import log
2888 if factor is False:
2889 def _handle(x):
2890 x1 = expand_mul(expand_log(x, deep=deep, force=force, factor=True))
2891 if x1.count(log) <= x.count(log):
2892 return x1
2893 return x
2895 expr = expr.replace(
2896 lambda x: x.is_Mul and all(any(isinstance(i, log) and i.args[0].is_Rational
2897 for i in Mul.make_args(j)) for j in x.as_numer_denom()),
2898 _handle)
2900 return sympify(expr).expand(deep=deep, log=True, mul=False,
2901 power_exp=False, power_base=False, multinomial=False,
2902 basic=False, force=force, factor=factor)
2905def expand_func(expr, deep=True):
2906 """
2907 Wrapper around expand that only uses the func hint. See the expand
2908 docstring for more information.
2910 Examples
2911 ========
2913 >>> from sympy import expand_func, gamma
2914 >>> from sympy.abc import x
2915 >>> expand_func(gamma(x + 2))
2916 x*(x + 1)*gamma(x)
2918 """
2919 return sympify(expr).expand(deep=deep, func=True, basic=False,
2920 log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
2923def expand_trig(expr, deep=True):
2924 """
2925 Wrapper around expand that only uses the trig hint. See the expand
2926 docstring for more information.
2928 Examples
2929 ========
2931 >>> from sympy import expand_trig, sin
2932 >>> from sympy.abc import x, y
2933 >>> expand_trig(sin(x+y)*(x+y))
2934 (x + y)*(sin(x)*cos(y) + sin(y)*cos(x))
2936 """
2937 return sympify(expr).expand(deep=deep, trig=True, basic=False,
2938 log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
2941def expand_complex(expr, deep=True):
2942 """
2943 Wrapper around expand that only uses the complex hint. See the expand
2944 docstring for more information.
2946 Examples
2947 ========
2949 >>> from sympy import expand_complex, exp, sqrt, I
2950 >>> from sympy.abc import z
2951 >>> expand_complex(exp(z))
2952 I*exp(re(z))*sin(im(z)) + exp(re(z))*cos(im(z))
2953 >>> expand_complex(sqrt(I))
2954 sqrt(2)/2 + sqrt(2)*I/2
2956 See Also
2957 ========
2959 sympy.core.expr.Expr.as_real_imag
2960 """
2961 return sympify(expr).expand(deep=deep, complex=True, basic=False,
2962 log=False, mul=False, power_exp=False, power_base=False, multinomial=False)
2965def expand_power_base(expr, deep=True, force=False):
2966 """
2967 Wrapper around expand that only uses the power_base hint.
2969 A wrapper to expand(power_base=True) which separates a power with a base
2970 that is a Mul into a product of powers, without performing any other
2971 expansions, provided that assumptions about the power's base and exponent
2972 allow.
2974 deep=False (default is True) will only apply to the top-level expression.
2976 force=True (default is False) will cause the expansion to ignore
2977 assumptions about the base and exponent. When False, the expansion will
2978 only happen if the base is non-negative or the exponent is an integer.
2980 >>> from sympy.abc import x, y, z
2981 >>> from sympy import expand_power_base, sin, cos, exp, Symbol
2983 >>> (x*y)**2
2984 x**2*y**2
2986 >>> (2*x)**y
2987 (2*x)**y
2988 >>> expand_power_base(_)
2989 2**y*x**y
2991 >>> expand_power_base((x*y)**z)
2992 (x*y)**z
2993 >>> expand_power_base((x*y)**z, force=True)
2994 x**z*y**z
2995 >>> expand_power_base(sin((x*y)**z), deep=False)
2996 sin((x*y)**z)
2997 >>> expand_power_base(sin((x*y)**z), force=True)
2998 sin(x**z*y**z)
3000 >>> expand_power_base((2*sin(x))**y + (2*cos(x))**y)
3001 2**y*sin(x)**y + 2**y*cos(x)**y
3003 >>> expand_power_base((2*exp(y))**x)
3004 2**x*exp(y)**x
3006 >>> expand_power_base((2*cos(x))**y)
3007 2**y*cos(x)**y
3009 Notice that sums are left untouched. If this is not the desired behavior,
3010 apply full ``expand()`` to the expression:
3012 >>> expand_power_base(((x+y)*z)**2)
3013 z**2*(x + y)**2
3014 >>> (((x+y)*z)**2).expand()
3015 x**2*z**2 + 2*x*y*z**2 + y**2*z**2
3017 >>> expand_power_base((2*y)**(1+z))
3018 2**(z + 1)*y**(z + 1)
3019 >>> ((2*y)**(1+z)).expand()
3020 2*2**z*y**(z + 1)
3022 The power that is unexpanded can be expanded safely when
3023 ``y != 0``, otherwise different values might be obtained for the expression:
3025 >>> prev = _
3027 If we indicate that ``y`` is positive but then replace it with
3028 a value of 0 after expansion, the expression becomes 0:
3030 >>> p = Symbol('p', positive=True)
3031 >>> prev.subs(y, p).expand().subs(p, 0)
3032 0
3034 But if ``z = -1`` the expression would not be zero:
3036 >>> prev.subs(y, 0).subs(z, -1)
3037 1
3039 See Also
3040 ========
3042 expand
3044 """
3045 return sympify(expr).expand(deep=deep, log=False, mul=False,
3046 power_exp=False, power_base=True, multinomial=False,
3047 basic=False, force=force)
3050def expand_power_exp(expr, deep=True):
3051 """
3052 Wrapper around expand that only uses the power_exp hint.
3054 See the expand docstring for more information.
3056 Examples
3057 ========
3059 >>> from sympy import expand_power_exp, Symbol
3060 >>> from sympy.abc import x, y
3061 >>> expand_power_exp(3**(y + 2))
3062 9*3**y
3063 >>> expand_power_exp(x**(y + 2))
3064 x**(y + 2)
3066 If ``x = 0`` the value of the expression depends on the
3067 value of ``y``; if the expression were expanded the result
3068 would be 0. So expansion is only done if ``x != 0``:
3070 >>> expand_power_exp(Symbol('x', zero=False)**(y + 2))
3071 x**2*x**y
3072 """
3073 return sympify(expr).expand(deep=deep, complex=False, basic=False,
3074 log=False, mul=False, power_exp=True, power_base=False, multinomial=False)
3077def count_ops(expr, visual=False):
3078 """
3079 Return a representation (integer or expression) of the operations in expr.
3081 Parameters
3082 ==========
3084 expr : Expr
3085 If expr is an iterable, the sum of the op counts of the
3086 items will be returned.
3088 visual : bool, optional
3089 If ``False`` (default) then the sum of the coefficients of the
3090 visual expression will be returned.
3091 If ``True`` then the number of each type of operation is shown
3092 with the core class types (or their virtual equivalent) multiplied by the
3093 number of times they occur.
3095 Examples
3096 ========
3098 >>> from sympy.abc import a, b, x, y
3099 >>> from sympy import sin, count_ops
3101 Although there is not a SUB object, minus signs are interpreted as
3102 either negations or subtractions:
3104 >>> (x - y).count_ops(visual=True)
3105 SUB
3106 >>> (-x).count_ops(visual=True)
3107 NEG
3109 Here, there are two Adds and a Pow:
3111 >>> (1 + a + b**2).count_ops(visual=True)
3112 2*ADD + POW
3114 In the following, an Add, Mul, Pow and two functions:
3116 >>> (sin(x)*x + sin(x)**2).count_ops(visual=True)
3117 ADD + MUL + POW + 2*SIN
3119 for a total of 5:
3121 >>> (sin(x)*x + sin(x)**2).count_ops(visual=False)
3122 5
3124 Note that "what you type" is not always what you get. The expression
3125 1/x/y is translated by sympy into 1/(x*y) so it gives a DIV and MUL rather
3126 than two DIVs:
3128 >>> (1/x/y).count_ops(visual=True)
3129 DIV + MUL
3131 The visual option can be used to demonstrate the difference in
3132 operations for expressions in different forms. Here, the Horner
3133 representation is compared with the expanded form of a polynomial:
3135 >>> eq=x*(1 + x*(2 + x*(3 + x)))
3136 >>> count_ops(eq.expand(), visual=True) - count_ops(eq, visual=True)
3137 -MUL + 3*POW
3139 The count_ops function also handles iterables:
3141 >>> count_ops([x, sin(x), None, True, x + 2], visual=False)
3142 2
3143 >>> count_ops([x, sin(x), None, True, x + 2], visual=True)
3144 ADD + SIN
3145 >>> count_ops({x: sin(x), x + 2: y + 1}, visual=True)
3146 2*ADD + SIN
3148 """
3149 from .relational import Relational
3150 from sympy.concrete.summations import Sum
3151 from sympy.integrals.integrals import Integral
3152 from sympy.logic.boolalg import BooleanFunction
3153 from sympy.simplify.radsimp import fraction
3155 expr = sympify(expr)
3156 if isinstance(expr, Expr) and not expr.is_Relational:
3158 ops = []
3159 args = [expr]
3160 NEG = Symbol('NEG')
3161 DIV = Symbol('DIV')
3162 SUB = Symbol('SUB')
3163 ADD = Symbol('ADD')
3164 EXP = Symbol('EXP')
3165 while args:
3166 a = args.pop()
3168 # if the following fails because the object is
3169 # not Basic type, then the object should be fixed
3170 # since it is the intention that all args of Basic
3171 # should themselves be Basic
3172 if a.is_Rational:
3173 #-1/3 = NEG + DIV
3174 if a is not S.One:
3175 if a.p < 0:
3176 ops.append(NEG)
3177 if a.q != 1:
3178 ops.append(DIV)
3179 continue
3180 elif a.is_Mul or a.is_MatMul:
3181 if _coeff_isneg(a):
3182 ops.append(NEG)
3183 if a.args[0] is S.NegativeOne:
3184 a = a.as_two_terms()[1]
3185 else:
3186 a = -a
3187 n, d = fraction(a)
3188 if n.is_Integer:
3189 ops.append(DIV)
3190 if n < 0:
3191 ops.append(NEG)
3192 args.append(d)
3193 continue # won't be -Mul but could be Add
3194 elif d is not S.One:
3195 if not d.is_Integer:
3196 args.append(d)
3197 ops.append(DIV)
3198 args.append(n)
3199 continue # could be -Mul
3200 elif a.is_Add or a.is_MatAdd:
3201 aargs = list(a.args)
3202 negs = 0
3203 for i, ai in enumerate(aargs):
3204 if _coeff_isneg(ai):
3205 negs += 1
3206 args.append(-ai)
3207 if i > 0:
3208 ops.append(SUB)
3209 else:
3210 args.append(ai)
3211 if i > 0:
3212 ops.append(ADD)
3213 if negs == len(aargs): # -x - y = NEG + SUB
3214 ops.append(NEG)
3215 elif _coeff_isneg(aargs[0]): # -x + y = SUB, but already recorded ADD
3216 ops.append(SUB - ADD)
3217 continue
3218 if a.is_Pow and a.exp is S.NegativeOne:
3219 ops.append(DIV)
3220 args.append(a.base) # won't be -Mul but could be Add
3221 continue
3222 if a == S.Exp1:
3223 ops.append(EXP)
3224 continue
3225 if a.is_Pow and a.base == S.Exp1:
3226 ops.append(EXP)
3227 args.append(a.exp)
3228 continue
3229 if a.is_Mul or isinstance(a, LatticeOp):
3230 o = Symbol(a.func.__name__.upper())
3231 # count the args
3232 ops.append(o*(len(a.args) - 1))
3233 elif a.args and (
3234 a.is_Pow or
3235 a.is_Function or
3236 isinstance(a, Derivative) or
3237 isinstance(a, Integral) or
3238 isinstance(a, Sum)):
3239 # if it's not in the list above we don't
3240 # consider a.func something to count, e.g.
3241 # Tuple, MatrixSymbol, etc...
3242 if isinstance(a.func, UndefinedFunction):
3243 o = Symbol("FUNC_" + a.func.__name__.upper())
3244 else:
3245 o = Symbol(a.func.__name__.upper())
3246 ops.append(o)
3248 if not a.is_Symbol:
3249 args.extend(a.args)
3251 elif isinstance(expr, Dict):
3252 ops = [count_ops(k, visual=visual) +
3253 count_ops(v, visual=visual) for k, v in expr.items()]
3254 elif iterable(expr):
3255 ops = [count_ops(i, visual=visual) for i in expr]
3256 elif isinstance(expr, (Relational, BooleanFunction)):
3257 ops = []
3258 for arg in expr.args:
3259 ops.append(count_ops(arg, visual=True))
3260 o = Symbol(func_name(expr, short=True).upper())
3261 ops.append(o)
3262 elif not isinstance(expr, Basic):
3263 ops = []
3264 else: # it's Basic not isinstance(expr, Expr):
3265 if not isinstance(expr, Basic):
3266 raise TypeError("Invalid type of expr")
3267 else:
3268 ops = []
3269 args = [expr]
3270 while args:
3271 a = args.pop()
3273 if a.args:
3274 o = Symbol(type(a).__name__.upper())
3275 if a.is_Boolean:
3276 ops.append(o*(len(a.args)-1))
3277 else:
3278 ops.append(o)
3279 args.extend(a.args)
3281 if not ops:
3282 if visual:
3283 return S.Zero
3284 return 0
3286 ops = Add(*ops)
3288 if visual:
3289 return ops
3291 if ops.is_Number:
3292 return int(ops)
3294 return sum(int((a.args or [1])[0]) for a in Add.make_args(ops))
3297def nfloat(expr, n=15, exponent=False, dkeys=False):
3298 """Make all Rationals in expr Floats except those in exponents
3299 (unless the exponents flag is set to True) and those in undefined
3300 functions. When processing dictionaries, do not modify the keys
3301 unless ``dkeys=True``.
3303 Examples
3304 ========
3306 >>> from sympy import nfloat, cos, pi, sqrt
3307 >>> from sympy.abc import x, y
3308 >>> nfloat(x**4 + x/2 + cos(pi/3) + 1 + sqrt(y))
3309 x**4 + 0.5*x + sqrt(y) + 1.5
3310 >>> nfloat(x**4 + sqrt(y), exponent=True)
3311 x**4.0 + y**0.5
3313 Container types are not modified:
3315 >>> type(nfloat((1, 2))) is tuple
3316 True
3317 """
3318 from sympy.matrices.matrices import MatrixBase
3320 kw = {"n": n, "exponent": exponent, "dkeys": dkeys}
3322 if isinstance(expr, MatrixBase):
3323 return expr.applyfunc(lambda e: nfloat(e, **kw))
3325 # handling of iterable containers
3326 if iterable(expr, exclude=str):
3327 if isinstance(expr, (dict, Dict)):
3328 if dkeys:
3329 args = [tuple((nfloat(i, **kw) for i in a))
3330 for a in expr.items()]
3331 else:
3332 args = [(k, nfloat(v, **kw)) for k, v in expr.items()]
3333 if isinstance(expr, dict):
3334 return type(expr)(args)
3335 else:
3336 return expr.func(*args)
3337 elif isinstance(expr, Basic):
3338 return expr.func(*[nfloat(a, **kw) for a in expr.args])
3339 return type(expr)([nfloat(a, **kw) for a in expr])
3341 rv = sympify(expr)
3343 if rv.is_Number:
3344 return Float(rv, n)
3345 elif rv.is_number:
3346 # evalf doesn't always set the precision
3347 rv = rv.n(n)
3348 if rv.is_Number:
3349 rv = Float(rv.n(n), n)
3350 else:
3351 pass # pure_complex(rv) is likely True
3352 return rv
3353 elif rv.is_Atom:
3354 return rv
3355 elif rv.is_Relational:
3356 args_nfloat = (nfloat(arg, **kw) for arg in rv.args)
3357 return rv.func(*args_nfloat)
3360 # watch out for RootOf instances that don't like to have
3361 # their exponents replaced with Dummies and also sometimes have
3362 # problems with evaluating at low precision (issue 6393)
3363 from sympy.polys.rootoftools import RootOf
3364 rv = rv.xreplace({ro: ro.n(n) for ro in rv.atoms(RootOf)})
3366 from .power import Pow
3367 if not exponent:
3368 reps = [(p, Pow(p.base, Dummy())) for p in rv.atoms(Pow)]
3369 rv = rv.xreplace(dict(reps))
3370 rv = rv.n(n)
3371 if not exponent:
3372 rv = rv.xreplace({d.exp: p.exp for p, d in reps})
3373 else:
3374 # Pow._eval_evalf special cases Integer exponents so if
3375 # exponent is suppose to be handled we have to do so here
3376 rv = rv.xreplace(Transform(
3377 lambda x: Pow(x.base, Float(x.exp, n)),
3378 lambda x: x.is_Pow and x.exp.is_Integer))
3380 return rv.xreplace(Transform(
3381 lambda x: x.func(*nfloat(x.args, n, exponent)),
3382 lambda x: isinstance(x, Function) and not isinstance(x, AppliedUndef)))
3385from .symbol import Dummy, Symbol