Coverage for /usr/lib/python3/dist-packages/sympy/core/add.py: 48%
750 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
1from typing import Tuple as tTuple
2from collections import defaultdict
3from functools import cmp_to_key, reduce
4from operator import attrgetter
5from .basic import Basic
6from .parameters import global_parameters
7from .logic import _fuzzy_group, fuzzy_or, fuzzy_not
8from .singleton import S
9from .operations import AssocOp, AssocOpDispatcher
10from .cache import cacheit
11from .numbers import ilcm, igcd, equal_valued
12from .expr import Expr
13from .kind import UndefinedKind
14from sympy.utilities.iterables import is_sequence, sift
16# Key for sorting commutative args in canonical order
17_args_sortkey = cmp_to_key(Basic.compare)
20def _could_extract_minus_sign(expr):
21 # assume expr is Add-like
22 # We choose the one with less arguments with minus signs
23 negative_args = sum(1 for i in expr.args
24 if i.could_extract_minus_sign())
25 positive_args = len(expr.args) - negative_args
26 if positive_args > negative_args:
27 return False
28 elif positive_args < negative_args:
29 return True
30 # choose based on .sort_key() to prefer
31 # x - 1 instead of 1 - x and
32 # 3 - sqrt(2) instead of -3 + sqrt(2)
33 return bool(expr.sort_key() < (-expr).sort_key())
36def _addsort(args):
37 # in-place sorting of args
38 args.sort(key=_args_sortkey)
41def _unevaluated_Add(*args):
42 """Return a well-formed unevaluated Add: Numbers are collected and
43 put in slot 0 and args are sorted. Use this when args have changed
44 but you still want to return an unevaluated Add.
46 Examples
47 ========
49 >>> from sympy.core.add import _unevaluated_Add as uAdd
50 >>> from sympy import S, Add
51 >>> from sympy.abc import x, y
52 >>> a = uAdd(*[S(1.0), x, S(2)])
53 >>> a.args[0]
54 3.00000000000000
55 >>> a.args[1]
56 x
58 Beyond the Number being in slot 0, there is no other assurance of
59 order for the arguments since they are hash sorted. So, for testing
60 purposes, output produced by this in some other function can only
61 be tested against the output of this function or as one of several
62 options:
64 >>> opts = (Add(x, y, evaluate=False), Add(y, x, evaluate=False))
65 >>> a = uAdd(x, y)
66 >>> assert a in opts and a == uAdd(x, y)
67 >>> uAdd(x + 1, x + 2)
68 x + x + 3
69 """
70 args = list(args)
71 newargs = []
72 co = S.Zero
73 while args:
74 a = args.pop()
75 if a.is_Add:
76 # this will keep nesting from building up
77 # so that x + (x + 1) -> x + x + 1 (3 args)
78 args.extend(a.args)
79 elif a.is_Number:
80 co += a
81 else:
82 newargs.append(a)
83 _addsort(newargs)
84 if co:
85 newargs.insert(0, co)
86 return Add._from_args(newargs)
89class Add(Expr, AssocOp):
90 """
91 Expression representing addition operation for algebraic group.
93 .. deprecated:: 1.7
95 Using arguments that aren't subclasses of :class:`~.Expr` in core
96 operators (:class:`~.Mul`, :class:`~.Add`, and :class:`~.Pow`) is
97 deprecated. See :ref:`non-expr-args-deprecated` for details.
99 Every argument of ``Add()`` must be ``Expr``. Infix operator ``+``
100 on most scalar objects in SymPy calls this class.
102 Another use of ``Add()`` is to represent the structure of abstract
103 addition so that its arguments can be substituted to return different
104 class. Refer to examples section for this.
106 ``Add()`` evaluates the argument unless ``evaluate=False`` is passed.
107 The evaluation logic includes:
109 1. Flattening
110 ``Add(x, Add(y, z))`` -> ``Add(x, y, z)``
112 2. Identity removing
113 ``Add(x, 0, y)`` -> ``Add(x, y)``
115 3. Coefficient collecting by ``.as_coeff_Mul()``
116 ``Add(x, 2*x)`` -> ``Mul(3, x)``
118 4. Term sorting
119 ``Add(y, x, 2)`` -> ``Add(2, x, y)``
121 If no argument is passed, identity element 0 is returned. If single
122 element is passed, that element is returned.
124 Note that ``Add(*args)`` is more efficient than ``sum(args)`` because
125 it flattens the arguments. ``sum(a, b, c, ...)`` recursively adds the
126 arguments as ``a + (b + (c + ...))``, which has quadratic complexity.
127 On the other hand, ``Add(a, b, c, d)`` does not assume nested
128 structure, making the complexity linear.
130 Since addition is group operation, every argument should have the
131 same :obj:`sympy.core.kind.Kind()`.
133 Examples
134 ========
136 >>> from sympy import Add, I
137 >>> from sympy.abc import x, y
138 >>> Add(x, 1)
139 x + 1
140 >>> Add(x, x)
141 2*x
142 >>> 2*x**2 + 3*x + I*y + 2*y + 2*x/5 + 1.0*y + 1
143 2*x**2 + 17*x/5 + 3.0*y + I*y + 1
145 If ``evaluate=False`` is passed, result is not evaluated.
147 >>> Add(1, 2, evaluate=False)
148 1 + 2
149 >>> Add(x, x, evaluate=False)
150 x + x
152 ``Add()`` also represents the general structure of addition operation.
154 >>> from sympy import MatrixSymbol
155 >>> A,B = MatrixSymbol('A', 2,2), MatrixSymbol('B', 2,2)
156 >>> expr = Add(x,y).subs({x:A, y:B})
157 >>> expr
158 A + B
159 >>> type(expr)
160 <class 'sympy.matrices.expressions.matadd.MatAdd'>
162 Note that the printers do not display in args order.
164 >>> Add(x, 1)
165 x + 1
166 >>> Add(x, 1).args
167 (1, x)
169 See Also
170 ========
172 MatAdd
174 """
176 __slots__ = ()
178 args: tTuple[Expr, ...]
180 is_Add = True
182 _args_type = Expr
184 @classmethod
185 def flatten(cls, seq):
186 """
187 Takes the sequence "seq" of nested Adds and returns a flatten list.
189 Returns: (commutative_part, noncommutative_part, order_symbols)
191 Applies associativity, all terms are commutable with respect to
192 addition.
194 NB: the removal of 0 is already handled by AssocOp.__new__
196 See Also
197 ========
199 sympy.core.mul.Mul.flatten
201 """
202 from sympy.calculus.accumulationbounds import AccumBounds
203 from sympy.matrices.expressions import MatrixExpr
204 from sympy.tensor.tensor import TensExpr
205 rv = None
206 if len(seq) == 2:
207 a, b = seq
208 if b.is_Rational:
209 a, b = b, a
210 if a.is_Rational:
211 if b.is_Mul:
212 rv = [a, b], [], None
213 if rv:
214 if all(s.is_commutative for s in rv[0]):
215 return rv
216 return [], rv[0], None
218 terms = {} # term -> coeff
219 # e.g. x**2 -> 5 for ... + 5*x**2 + ...
221 coeff = S.Zero # coefficient (Number or zoo) to always be in slot 0
222 # e.g. 3 + ...
223 order_factors = []
225 extra = []
227 for o in seq:
229 # O(x)
230 if o.is_Order:
231 if o.expr.is_zero:
232 continue
233 for o1 in order_factors:
234 if o1.contains(o):
235 o = None
236 break
237 if o is None:
238 continue
239 order_factors = [o] + [
240 o1 for o1 in order_factors if not o.contains(o1)]
241 continue
243 # 3 or NaN
244 elif o.is_Number:
245 if (o is S.NaN or coeff is S.ComplexInfinity and
246 o.is_finite is False) and not extra:
247 # we know for sure the result will be nan
248 return [S.NaN], [], None
249 if coeff.is_Number or isinstance(coeff, AccumBounds):
250 coeff += o
251 if coeff is S.NaN and not extra:
252 # we know for sure the result will be nan
253 return [S.NaN], [], None
254 continue
256 elif isinstance(o, AccumBounds):
257 coeff = o.__add__(coeff)
258 continue
260 elif isinstance(o, MatrixExpr):
261 # can't add 0 to Matrix so make sure coeff is not 0
262 extra.append(o)
263 continue
265 elif isinstance(o, TensExpr):
266 coeff = o.__add__(coeff) if coeff else o
267 continue
269 elif o is S.ComplexInfinity:
270 if coeff.is_finite is False and not extra:
271 # we know for sure the result will be nan
272 return [S.NaN], [], None
273 coeff = S.ComplexInfinity
274 continue
276 # Add([...])
277 elif o.is_Add:
278 # NB: here we assume Add is always commutative
279 seq.extend(o.args) # TODO zerocopy?
280 continue
282 # Mul([...])
283 elif o.is_Mul:
284 c, s = o.as_coeff_Mul()
286 # check for unevaluated Pow, e.g. 2**3 or 2**(-1/2)
287 elif o.is_Pow:
288 b, e = o.as_base_exp()
289 if b.is_Number and (e.is_Integer or
290 (e.is_Rational and e.is_negative)):
291 seq.append(b**e)
292 continue
293 c, s = S.One, o
295 else:
296 # everything else
297 c = S.One
298 s = o
300 # now we have:
301 # o = c*s, where
302 #
303 # c is a Number
304 # s is an expression with number factor extracted
305 # let's collect terms with the same s, so e.g.
306 # 2*x**2 + 3*x**2 -> 5*x**2
307 if s in terms:
308 terms[s] += c
309 if terms[s] is S.NaN and not extra:
310 # we know for sure the result will be nan
311 return [S.NaN], [], None
312 else:
313 terms[s] = c
315 # now let's construct new args:
316 # [2*x**2, x**3, 7*x**4, pi, ...]
317 newseq = []
318 noncommutative = False
319 for s, c in terms.items():
320 # 0*s
321 if c.is_zero:
322 continue
323 # 1*s
324 elif c is S.One:
325 newseq.append(s)
326 # c*s
327 else:
328 if s.is_Mul:
329 # Mul, already keeps its arguments in perfect order.
330 # so we can simply put c in slot0 and go the fast way.
331 cs = s._new_rawargs(*((c,) + s.args))
332 newseq.append(cs)
333 elif s.is_Add:
334 # we just re-create the unevaluated Mul
335 newseq.append(Mul(c, s, evaluate=False))
336 else:
337 # alternatively we have to call all Mul's machinery (slow)
338 newseq.append(Mul(c, s))
340 noncommutative = noncommutative or not s.is_commutative
342 # oo, -oo
343 if coeff is S.Infinity:
344 newseq = [f for f in newseq if not (f.is_extended_nonnegative or f.is_real)]
346 elif coeff is S.NegativeInfinity:
347 newseq = [f for f in newseq if not (f.is_extended_nonpositive or f.is_real)]
349 if coeff is S.ComplexInfinity:
350 # zoo might be
351 # infinite_real + finite_im
352 # finite_real + infinite_im
353 # infinite_real + infinite_im
354 # addition of a finite real or imaginary number won't be able to
355 # change the zoo nature; adding an infinite qualtity would result
356 # in a NaN condition if it had sign opposite of the infinite
357 # portion of zoo, e.g., infinite_real - infinite_real.
358 newseq = [c for c in newseq if not (c.is_finite and
359 c.is_extended_real is not None)]
361 # process O(x)
362 if order_factors:
363 newseq2 = []
364 for t in newseq:
365 for o in order_factors:
366 # x + O(x) -> O(x)
367 if o.contains(t):
368 t = None
369 break
370 # x + O(x**2) -> x + O(x**2)
371 if t is not None:
372 newseq2.append(t)
373 newseq = newseq2 + order_factors
374 # 1 + O(1) -> O(1)
375 for o in order_factors:
376 if o.contains(coeff):
377 coeff = S.Zero
378 break
380 # order args canonically
381 _addsort(newseq)
383 # current code expects coeff to be first
384 if coeff is not S.Zero:
385 newseq.insert(0, coeff)
387 if extra:
388 newseq += extra
389 noncommutative = True
391 # we are done
392 if noncommutative:
393 return [], newseq, None
394 else:
395 return newseq, [], None
397 @classmethod
398 def class_key(cls):
399 return 3, 1, cls.__name__
401 @property
402 def kind(self):
403 k = attrgetter('kind')
404 kinds = map(k, self.args)
405 kinds = frozenset(kinds)
406 if len(kinds) != 1:
407 # Since addition is group operator, kind must be same.
408 # We know that this is unexpected signature, so return this.
409 result = UndefinedKind
410 else:
411 result, = kinds
412 return result
414 def could_extract_minus_sign(self):
415 return _could_extract_minus_sign(self)
417 @cacheit
418 def as_coeff_add(self, *deps):
419 """
420 Returns a tuple (coeff, args) where self is treated as an Add and coeff
421 is the Number term and args is a tuple of all other terms.
423 Examples
424 ========
426 >>> from sympy.abc import x
427 >>> (7 + 3*x).as_coeff_add()
428 (7, (3*x,))
429 >>> (7*x).as_coeff_add()
430 (0, (7*x,))
431 """
432 if deps:
433 l1, l2 = sift(self.args, lambda x: x.has_free(*deps), binary=True)
434 return self._new_rawargs(*l2), tuple(l1)
435 coeff, notrat = self.args[0].as_coeff_add()
436 if coeff is not S.Zero:
437 return coeff, notrat + self.args[1:]
438 return S.Zero, self.args
440 def as_coeff_Add(self, rational=False, deps=None):
441 """
442 Efficiently extract the coefficient of a summation.
443 """
444 coeff, args = self.args[0], self.args[1:]
446 if coeff.is_Number and not rational or coeff.is_Rational:
447 return coeff, self._new_rawargs(*args)
448 return S.Zero, self
450 # Note, we intentionally do not implement Add.as_coeff_mul(). Rather, we
451 # let Expr.as_coeff_mul() just always return (S.One, self) for an Add. See
452 # issue 5524.
454 def _eval_power(self, e):
455 from .evalf import pure_complex
456 from .relational import is_eq
457 if len(self.args) == 2 and any(_.is_infinite for _ in self.args):
458 if e.is_zero is False and is_eq(e, S.One) is False:
459 # looking for literal a + I*b
460 a, b = self.args
461 if a.coeff(S.ImaginaryUnit):
462 a, b = b, a
463 ico = b.coeff(S.ImaginaryUnit)
464 if ico and ico.is_extended_real and a.is_extended_real:
465 if e.is_extended_negative:
466 return S.Zero
467 if e.is_extended_positive:
468 return S.ComplexInfinity
469 return
470 if e.is_Rational and self.is_number:
471 ri = pure_complex(self)
472 if ri:
473 r, i = ri
474 if e.q == 2:
475 from sympy.functions.elementary.miscellaneous import sqrt
476 D = sqrt(r**2 + i**2)
477 if D.is_Rational:
478 from .exprtools import factor_terms
479 from sympy.functions.elementary.complexes import sign
480 from .function import expand_multinomial
481 # (r, i, D) is a Pythagorean triple
482 root = sqrt(factor_terms((D - r)/2))**e.p
483 return root*expand_multinomial((
484 # principle value
485 (D + r)/abs(i) + sign(i)*S.ImaginaryUnit)**e.p)
486 elif e == -1:
487 return _unevaluated_Mul(
488 r - i*S.ImaginaryUnit,
489 1/(r**2 + i**2))
490 elif e.is_Number and abs(e) != 1:
491 # handle the Float case: (2.0 + 4*x)**e -> 4**e*(0.5 + x)**e
492 c, m = zip(*[i.as_coeff_Mul() for i in self.args])
493 if any(i.is_Float for i in c): # XXX should this always be done?
494 big = -1
495 for i in c:
496 if abs(i) >= big:
497 big = abs(i)
498 if big > 0 and not equal_valued(big, 1):
499 from sympy.functions.elementary.complexes import sign
500 bigs = (big, -big)
501 c = [sign(i) if i in bigs else i/big for i in c]
502 addpow = Add(*[c*m for c, m in zip(c, m)])**e
503 return big**e*addpow
505 @cacheit
506 def _eval_derivative(self, s):
507 return self.func(*[a.diff(s) for a in self.args])
509 def _eval_nseries(self, x, n, logx, cdir=0):
510 terms = [t.nseries(x, n=n, logx=logx, cdir=cdir) for t in self.args]
511 return self.func(*terms)
513 def _matches_simple(self, expr, repl_dict):
514 # handle (w+3).matches('x+5') -> {w: x+2}
515 coeff, terms = self.as_coeff_add()
516 if len(terms) == 1:
517 return terms[0].matches(expr - coeff, repl_dict)
518 return
520 def matches(self, expr, repl_dict=None, old=False):
521 return self._matches_commutative(expr, repl_dict, old)
523 @staticmethod
524 def _combine_inverse(lhs, rhs):
525 """
526 Returns lhs - rhs, but treats oo like a symbol so oo - oo
527 returns 0, instead of a nan.
528 """
529 from sympy.simplify.simplify import signsimp
530 inf = (S.Infinity, S.NegativeInfinity)
531 if lhs.has(*inf) or rhs.has(*inf):
532 from .symbol import Dummy
533 oo = Dummy('oo')
534 reps = {
535 S.Infinity: oo,
536 S.NegativeInfinity: -oo}
537 ireps = {v: k for k, v in reps.items()}
538 eq = lhs.xreplace(reps) - rhs.xreplace(reps)
539 if eq.has(oo):
540 eq = eq.replace(
541 lambda x: x.is_Pow and x.base is oo,
542 lambda x: x.base)
543 rv = eq.xreplace(ireps)
544 else:
545 rv = lhs - rhs
546 srv = signsimp(rv)
547 return srv if srv.is_Number else rv
549 @cacheit
550 def as_two_terms(self):
551 """Return head and tail of self.
553 This is the most efficient way to get the head and tail of an
554 expression.
556 - if you want only the head, use self.args[0];
557 - if you want to process the arguments of the tail then use
558 self.as_coef_add() which gives the head and a tuple containing
559 the arguments of the tail when treated as an Add.
560 - if you want the coefficient when self is treated as a Mul
561 then use self.as_coeff_mul()[0]
563 >>> from sympy.abc import x, y
564 >>> (3*x - 2*y + 5).as_two_terms()
565 (5, 3*x - 2*y)
566 """
567 return self.args[0], self._new_rawargs(*self.args[1:])
569 def as_numer_denom(self):
570 """
571 Decomposes an expression to its numerator part and its
572 denominator part.
574 Examples
575 ========
577 >>> from sympy.abc import x, y, z
578 >>> (x*y/z).as_numer_denom()
579 (x*y, z)
580 >>> (x*(y + 1)/y**7).as_numer_denom()
581 (x*(y + 1), y**7)
583 See Also
584 ========
586 sympy.core.expr.Expr.as_numer_denom
587 """
588 # clear rational denominator
589 content, expr = self.primitive()
590 if not isinstance(expr, Add):
591 return Mul(content, expr, evaluate=False).as_numer_denom()
592 ncon, dcon = content.as_numer_denom()
594 # collect numerators and denominators of the terms
595 nd = defaultdict(list)
596 for f in expr.args:
597 ni, di = f.as_numer_denom()
598 nd[di].append(ni)
600 # check for quick exit
601 if len(nd) == 1:
602 d, n = nd.popitem()
603 return self.func(
604 *[_keep_coeff(ncon, ni) for ni in n]), _keep_coeff(dcon, d)
606 # sum up the terms having a common denominator
607 for d, n in nd.items():
608 if len(n) == 1:
609 nd[d] = n[0]
610 else:
611 nd[d] = self.func(*n)
613 # assemble single numerator and denominator
614 denoms, numers = [list(i) for i in zip(*iter(nd.items()))]
615 n, d = self.func(*[Mul(*(denoms[:i] + [numers[i]] + denoms[i + 1:]))
616 for i in range(len(numers))]), Mul(*denoms)
618 return _keep_coeff(ncon, n), _keep_coeff(dcon, d)
620 def _eval_is_polynomial(self, syms):
621 return all(term._eval_is_polynomial(syms) for term in self.args)
623 def _eval_is_rational_function(self, syms):
624 return all(term._eval_is_rational_function(syms) for term in self.args)
626 def _eval_is_meromorphic(self, x, a):
627 return _fuzzy_group((arg.is_meromorphic(x, a) for arg in self.args),
628 quick_exit=True)
630 def _eval_is_algebraic_expr(self, syms):
631 return all(term._eval_is_algebraic_expr(syms) for term in self.args)
633 # assumption methods
634 _eval_is_real = lambda self: _fuzzy_group(
635 (a.is_real for a in self.args), quick_exit=True)
636 _eval_is_extended_real = lambda self: _fuzzy_group(
637 (a.is_extended_real for a in self.args), quick_exit=True)
638 _eval_is_complex = lambda self: _fuzzy_group(
639 (a.is_complex for a in self.args), quick_exit=True)
640 _eval_is_antihermitian = lambda self: _fuzzy_group(
641 (a.is_antihermitian for a in self.args), quick_exit=True)
642 _eval_is_finite = lambda self: _fuzzy_group(
643 (a.is_finite for a in self.args), quick_exit=True)
644 _eval_is_hermitian = lambda self: _fuzzy_group(
645 (a.is_hermitian for a in self.args), quick_exit=True)
646 _eval_is_integer = lambda self: _fuzzy_group(
647 (a.is_integer for a in self.args), quick_exit=True)
648 _eval_is_rational = lambda self: _fuzzy_group(
649 (a.is_rational for a in self.args), quick_exit=True)
650 _eval_is_algebraic = lambda self: _fuzzy_group(
651 (a.is_algebraic for a in self.args), quick_exit=True)
652 _eval_is_commutative = lambda self: _fuzzy_group(
653 a.is_commutative for a in self.args)
655 def _eval_is_infinite(self):
656 sawinf = False
657 for a in self.args:
658 ainf = a.is_infinite
659 if ainf is None:
660 return None
661 elif ainf is True:
662 # infinite+infinite might not be infinite
663 if sawinf is True:
664 return None
665 sawinf = True
666 return sawinf
668 def _eval_is_imaginary(self):
669 nz = []
670 im_I = []
671 for a in self.args:
672 if a.is_extended_real:
673 if a.is_zero:
674 pass
675 elif a.is_zero is False:
676 nz.append(a)
677 else:
678 return
679 elif a.is_imaginary:
680 im_I.append(a*S.ImaginaryUnit)
681 elif a.is_Mul and S.ImaginaryUnit in a.args:
682 coeff, ai = a.as_coeff_mul(S.ImaginaryUnit)
683 if ai == (S.ImaginaryUnit,) and coeff.is_extended_real:
684 im_I.append(-coeff)
685 else:
686 return
687 else:
688 return
689 b = self.func(*nz)
690 if b != self:
691 if b.is_zero:
692 return fuzzy_not(self.func(*im_I).is_zero)
693 elif b.is_zero is False:
694 return False
696 def _eval_is_zero(self):
697 if self.is_commutative is False:
698 # issue 10528: there is no way to know if a nc symbol
699 # is zero or not
700 return
701 nz = []
702 z = 0
703 im_or_z = False
704 im = 0
705 for a in self.args:
706 if a.is_extended_real:
707 if a.is_zero:
708 z += 1
709 elif a.is_zero is False:
710 nz.append(a)
711 else:
712 return
713 elif a.is_imaginary:
714 im += 1
715 elif a.is_Mul and S.ImaginaryUnit in a.args:
716 coeff, ai = a.as_coeff_mul(S.ImaginaryUnit)
717 if ai == (S.ImaginaryUnit,) and coeff.is_extended_real:
718 im_or_z = True
719 else:
720 return
721 else:
722 return
723 if z == len(self.args):
724 return True
725 if len(nz) in [0, len(self.args)]:
726 return None
727 b = self.func(*nz)
728 if b.is_zero:
729 if not im_or_z:
730 if im == 0:
731 return True
732 elif im == 1:
733 return False
734 if b.is_zero is False:
735 return False
737 def _eval_is_odd(self):
738 l = [f for f in self.args if not (f.is_even is True)]
739 if not l:
740 return False
741 if l[0].is_odd:
742 return self._new_rawargs(*l[1:]).is_even
744 def _eval_is_irrational(self):
745 for t in self.args:
746 a = t.is_irrational
747 if a:
748 others = list(self.args)
749 others.remove(t)
750 if all(x.is_rational is True for x in others):
751 return True
752 return None
753 if a is None:
754 return
755 return False
757 def _all_nonneg_or_nonppos(self):
758 nn = np = 0
759 for a in self.args:
760 if a.is_nonnegative:
761 if np:
762 return False
763 nn = 1
764 elif a.is_nonpositive:
765 if nn:
766 return False
767 np = 1
768 else:
769 break
770 else:
771 return True
773 def _eval_is_extended_positive(self):
774 if self.is_number:
775 return super()._eval_is_extended_positive()
776 c, a = self.as_coeff_Add()
777 if not c.is_zero:
778 from .exprtools import _monotonic_sign
779 v = _monotonic_sign(a)
780 if v is not None:
781 s = v + c
782 if s != self and s.is_extended_positive and a.is_extended_nonnegative:
783 return True
784 if len(self.free_symbols) == 1:
785 v = _monotonic_sign(self)
786 if v is not None and v != self and v.is_extended_positive:
787 return True
788 pos = nonneg = nonpos = unknown_sign = False
789 saw_INF = set()
790 args = [a for a in self.args if not a.is_zero]
791 if not args:
792 return False
793 for a in args:
794 ispos = a.is_extended_positive
795 infinite = a.is_infinite
796 if infinite:
797 saw_INF.add(fuzzy_or((ispos, a.is_extended_nonnegative)))
798 if True in saw_INF and False in saw_INF:
799 return
800 if ispos:
801 pos = True
802 continue
803 elif a.is_extended_nonnegative:
804 nonneg = True
805 continue
806 elif a.is_extended_nonpositive:
807 nonpos = True
808 continue
810 if infinite is None:
811 return
812 unknown_sign = True
814 if saw_INF:
815 if len(saw_INF) > 1:
816 return
817 return saw_INF.pop()
818 elif unknown_sign:
819 return
820 elif not nonpos and not nonneg and pos:
821 return True
822 elif not nonpos and pos:
823 return True
824 elif not pos and not nonneg:
825 return False
827 def _eval_is_extended_nonnegative(self):
828 if not self.is_number:
829 c, a = self.as_coeff_Add()
830 if not c.is_zero and a.is_extended_nonnegative:
831 from .exprtools import _monotonic_sign
832 v = _monotonic_sign(a)
833 if v is not None:
834 s = v + c
835 if s != self and s.is_extended_nonnegative:
836 return True
837 if len(self.free_symbols) == 1:
838 v = _monotonic_sign(self)
839 if v is not None and v != self and v.is_extended_nonnegative:
840 return True
842 def _eval_is_extended_nonpositive(self):
843 if not self.is_number:
844 c, a = self.as_coeff_Add()
845 if not c.is_zero and a.is_extended_nonpositive:
846 from .exprtools import _monotonic_sign
847 v = _monotonic_sign(a)
848 if v is not None:
849 s = v + c
850 if s != self and s.is_extended_nonpositive:
851 return True
852 if len(self.free_symbols) == 1:
853 v = _monotonic_sign(self)
854 if v is not None and v != self and v.is_extended_nonpositive:
855 return True
857 def _eval_is_extended_negative(self):
858 if self.is_number:
859 return super()._eval_is_extended_negative()
860 c, a = self.as_coeff_Add()
861 if not c.is_zero:
862 from .exprtools import _monotonic_sign
863 v = _monotonic_sign(a)
864 if v is not None:
865 s = v + c
866 if s != self and s.is_extended_negative and a.is_extended_nonpositive:
867 return True
868 if len(self.free_symbols) == 1:
869 v = _monotonic_sign(self)
870 if v is not None and v != self and v.is_extended_negative:
871 return True
872 neg = nonpos = nonneg = unknown_sign = False
873 saw_INF = set()
874 args = [a for a in self.args if not a.is_zero]
875 if not args:
876 return False
877 for a in args:
878 isneg = a.is_extended_negative
879 infinite = a.is_infinite
880 if infinite:
881 saw_INF.add(fuzzy_or((isneg, a.is_extended_nonpositive)))
882 if True in saw_INF and False in saw_INF:
883 return
884 if isneg:
885 neg = True
886 continue
887 elif a.is_extended_nonpositive:
888 nonpos = True
889 continue
890 elif a.is_extended_nonnegative:
891 nonneg = True
892 continue
894 if infinite is None:
895 return
896 unknown_sign = True
898 if saw_INF:
899 if len(saw_INF) > 1:
900 return
901 return saw_INF.pop()
902 elif unknown_sign:
903 return
904 elif not nonneg and not nonpos and neg:
905 return True
906 elif not nonneg and neg:
907 return True
908 elif not neg and not nonpos:
909 return False
911 def _eval_subs(self, old, new):
912 if not old.is_Add:
913 if old is S.Infinity and -old in self.args:
914 # foo - oo is foo + (-oo) internally
915 return self.xreplace({-old: -new})
916 return None
918 coeff_self, terms_self = self.as_coeff_Add()
919 coeff_old, terms_old = old.as_coeff_Add()
921 if coeff_self.is_Rational and coeff_old.is_Rational:
922 if terms_self == terms_old: # (2 + a).subs( 3 + a, y) -> -1 + y
923 return self.func(new, coeff_self, -coeff_old)
924 if terms_self == -terms_old: # (2 + a).subs(-3 - a, y) -> -1 - y
925 return self.func(-new, coeff_self, coeff_old)
927 if coeff_self.is_Rational and coeff_old.is_Rational \
928 or coeff_self == coeff_old:
929 args_old, args_self = self.func.make_args(
930 terms_old), self.func.make_args(terms_self)
931 if len(args_old) < len(args_self): # (a+b+c).subs(b+c,x) -> a+x
932 self_set = set(args_self)
933 old_set = set(args_old)
935 if old_set < self_set:
936 ret_set = self_set - old_set
937 return self.func(new, coeff_self, -coeff_old,
938 *[s._subs(old, new) for s in ret_set])
940 args_old = self.func.make_args(
941 -terms_old) # (a+b+c+d).subs(-b-c,x) -> a-x+d
942 old_set = set(args_old)
943 if old_set < self_set:
944 ret_set = self_set - old_set
945 return self.func(-new, coeff_self, coeff_old,
946 *[s._subs(old, new) for s in ret_set])
948 def removeO(self):
949 args = [a for a in self.args if not a.is_Order]
950 return self._new_rawargs(*args)
952 def getO(self):
953 args = [a for a in self.args if a.is_Order]
954 if args:
955 return self._new_rawargs(*args)
957 @cacheit
958 def extract_leading_order(self, symbols, point=None):
959 """
960 Returns the leading term and its order.
962 Examples
963 ========
965 >>> from sympy.abc import x
966 >>> (x + 1 + 1/x**5).extract_leading_order(x)
967 ((x**(-5), O(x**(-5))),)
968 >>> (1 + x).extract_leading_order(x)
969 ((1, O(1)),)
970 >>> (x + x**2).extract_leading_order(x)
971 ((x, O(x)),)
973 """
974 from sympy.series.order import Order
975 lst = []
976 symbols = list(symbols if is_sequence(symbols) else [symbols])
977 if not point:
978 point = [0]*len(symbols)
979 seq = [(f, Order(f, *zip(symbols, point))) for f in self.args]
980 for ef, of in seq:
981 for e, o in lst:
982 if o.contains(of) and o != of:
983 of = None
984 break
985 if of is None:
986 continue
987 new_lst = [(ef, of)]
988 for e, o in lst:
989 if of.contains(o) and o != of:
990 continue
991 new_lst.append((e, o))
992 lst = new_lst
993 return tuple(lst)
995 def as_real_imag(self, deep=True, **hints):
996 """
997 Return a tuple representing a complex number.
999 Examples
1000 ========
1002 >>> from sympy import I
1003 >>> (7 + 9*I).as_real_imag()
1004 (7, 9)
1005 >>> ((1 + I)/(1 - I)).as_real_imag()
1006 (0, 1)
1007 >>> ((1 + 2*I)*(1 + 3*I)).as_real_imag()
1008 (-5, 5)
1009 """
1010 sargs = self.args
1011 re_part, im_part = [], []
1012 for term in sargs:
1013 re, im = term.as_real_imag(deep=deep)
1014 re_part.append(re)
1015 im_part.append(im)
1016 return (self.func(*re_part), self.func(*im_part))
1018 def _eval_as_leading_term(self, x, logx=None, cdir=0):
1019 from sympy.core.symbol import Dummy, Symbol
1020 from sympy.series.order import Order
1021 from sympy.functions.elementary.exponential import log
1022 from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold
1023 from .function import expand_mul
1025 o = self.getO()
1026 if o is None:
1027 o = Order(0)
1028 old = self.removeO()
1030 if old.has(Piecewise):
1031 old = piecewise_fold(old)
1033 # This expansion is the last part of expand_log. expand_log also calls
1034 # expand_mul with factor=True, which would be more expensive
1035 if any(isinstance(a, log) for a in self.args):
1036 logflags = {"deep": True, "log": True, "mul": False, "power_exp": False,
1037 "power_base": False, "multinomial": False, "basic": False, "force": False,
1038 "factor": False}
1039 old = old.expand(**logflags)
1040 expr = expand_mul(old)
1042 if not expr.is_Add:
1043 return expr.as_leading_term(x, logx=logx, cdir=cdir)
1045 infinite = [t for t in expr.args if t.is_infinite]
1047 _logx = Dummy('logx') if logx is None else logx
1048 leading_terms = [t.as_leading_term(x, logx=_logx, cdir=cdir) for t in expr.args]
1050 min, new_expr = Order(0), 0
1052 try:
1053 for term in leading_terms:
1054 order = Order(term, x)
1055 if not min or order not in min:
1056 min = order
1057 new_expr = term
1058 elif min in order:
1059 new_expr += term
1061 except TypeError:
1062 return expr
1064 if logx is None:
1065 new_expr = new_expr.subs(_logx, log(x))
1067 is_zero = new_expr.is_zero
1068 if is_zero is None:
1069 new_expr = new_expr.trigsimp().cancel()
1070 is_zero = new_expr.is_zero
1071 if is_zero is True:
1072 # simple leading term analysis gave us cancelled terms but we have to send
1073 # back a term, so compute the leading term (via series)
1074 try:
1075 n0 = min.getn()
1076 except NotImplementedError:
1077 n0 = S.One
1078 if n0.has(Symbol):
1079 n0 = S.One
1080 res = Order(1)
1081 incr = S.One
1082 while res.is_Order:
1083 res = old._eval_nseries(x, n=n0+incr, logx=logx, cdir=cdir).cancel().powsimp().trigsimp()
1084 incr *= 2
1085 return res.as_leading_term(x, logx=logx, cdir=cdir)
1087 elif new_expr is S.NaN:
1088 return old.func._from_args(infinite) + o
1090 else:
1091 return new_expr
1093 def _eval_adjoint(self):
1094 return self.func(*[t.adjoint() for t in self.args])
1096 def _eval_conjugate(self):
1097 return self.func(*[t.conjugate() for t in self.args])
1099 def _eval_transpose(self):
1100 return self.func(*[t.transpose() for t in self.args])
1102 def primitive(self):
1103 """
1104 Return ``(R, self/R)`` where ``R``` is the Rational GCD of ``self```.
1106 ``R`` is collected only from the leading coefficient of each term.
1108 Examples
1109 ========
1111 >>> from sympy.abc import x, y
1113 >>> (2*x + 4*y).primitive()
1114 (2, x + 2*y)
1116 >>> (2*x/3 + 4*y/9).primitive()
1117 (2/9, 3*x + 2*y)
1119 >>> (2*x/3 + 4.2*y).primitive()
1120 (1/3, 2*x + 12.6*y)
1122 No subprocessing of term factors is performed:
1124 >>> ((2 + 2*x)*x + 2).primitive()
1125 (1, x*(2*x + 2) + 2)
1127 Recursive processing can be done with the ``as_content_primitive()``
1128 method:
1130 >>> ((2 + 2*x)*x + 2).as_content_primitive()
1131 (2, x*(x + 1) + 1)
1133 See also: primitive() function in polytools.py
1135 """
1137 terms = []
1138 inf = False
1139 for a in self.args:
1140 c, m = a.as_coeff_Mul()
1141 if not c.is_Rational:
1142 c = S.One
1143 m = a
1144 inf = inf or m is S.ComplexInfinity
1145 terms.append((c.p, c.q, m))
1147 if not inf:
1148 ngcd = reduce(igcd, [t[0] for t in terms], 0)
1149 dlcm = reduce(ilcm, [t[1] for t in terms], 1)
1150 else:
1151 ngcd = reduce(igcd, [t[0] for t in terms if t[1]], 0)
1152 dlcm = reduce(ilcm, [t[1] for t in terms if t[1]], 1)
1154 if ngcd == dlcm == 1:
1155 return S.One, self
1156 if not inf:
1157 for i, (p, q, term) in enumerate(terms):
1158 terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term)
1159 else:
1160 for i, (p, q, term) in enumerate(terms):
1161 if q:
1162 terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term)
1163 else:
1164 terms[i] = _keep_coeff(Rational(p, q), term)
1166 # we don't need a complete re-flattening since no new terms will join
1167 # so we just use the same sort as is used in Add.flatten. When the
1168 # coefficient changes, the ordering of terms may change, e.g.
1169 # (3*x, 6*y) -> (2*y, x)
1170 #
1171 # We do need to make sure that term[0] stays in position 0, however.
1172 #
1173 if terms[0].is_Number or terms[0] is S.ComplexInfinity:
1174 c = terms.pop(0)
1175 else:
1176 c = None
1177 _addsort(terms)
1178 if c:
1179 terms.insert(0, c)
1180 return Rational(ngcd, dlcm), self._new_rawargs(*terms)
1182 def as_content_primitive(self, radical=False, clear=True):
1183 """Return the tuple (R, self/R) where R is the positive Rational
1184 extracted from self. If radical is True (default is False) then
1185 common radicals will be removed and included as a factor of the
1186 primitive expression.
1188 Examples
1189 ========
1191 >>> from sympy import sqrt
1192 >>> (3 + 3*sqrt(2)).as_content_primitive()
1193 (3, 1 + sqrt(2))
1195 Radical content can also be factored out of the primitive:
1197 >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True)
1198 (2, sqrt(2)*(1 + 2*sqrt(5)))
1200 See docstring of Expr.as_content_primitive for more examples.
1201 """
1202 con, prim = self.func(*[_keep_coeff(*a.as_content_primitive(
1203 radical=radical, clear=clear)) for a in self.args]).primitive()
1204 if not clear and not con.is_Integer and prim.is_Add:
1205 con, d = con.as_numer_denom()
1206 _p = prim/d
1207 if any(a.as_coeff_Mul()[0].is_Integer for a in _p.args):
1208 prim = _p
1209 else:
1210 con /= d
1211 if radical and prim.is_Add:
1212 # look for common radicals that can be removed
1213 args = prim.args
1214 rads = []
1215 common_q = None
1216 for m in args:
1217 term_rads = defaultdict(list)
1218 for ai in Mul.make_args(m):
1219 if ai.is_Pow:
1220 b, e = ai.as_base_exp()
1221 if e.is_Rational and b.is_Integer:
1222 term_rads[e.q].append(abs(int(b))**e.p)
1223 if not term_rads:
1224 break
1225 if common_q is None:
1226 common_q = set(term_rads.keys())
1227 else:
1228 common_q = common_q & set(term_rads.keys())
1229 if not common_q:
1230 break
1231 rads.append(term_rads)
1232 else:
1233 # process rads
1234 # keep only those in common_q
1235 for r in rads:
1236 for q in list(r.keys()):
1237 if q not in common_q:
1238 r.pop(q)
1239 for q in r:
1240 r[q] = Mul(*r[q])
1241 # find the gcd of bases for each q
1242 G = []
1243 for q in common_q:
1244 g = reduce(igcd, [r[q] for r in rads], 0)
1245 if g != 1:
1246 G.append(g**Rational(1, q))
1247 if G:
1248 G = Mul(*G)
1249 args = [ai/G for ai in args]
1250 prim = G*prim.func(*args)
1252 return con, prim
1254 @property
1255 def _sorted_args(self):
1256 from .sorting import default_sort_key
1257 return tuple(sorted(self.args, key=default_sort_key))
1259 def _eval_difference_delta(self, n, step):
1260 from sympy.series.limitseq import difference_delta as dd
1261 return self.func(*[dd(a, n, step) for a in self.args])
1263 @property
1264 def _mpc_(self):
1265 """
1266 Convert self to an mpmath mpc if possible
1267 """
1268 from .numbers import Float
1269 re_part, rest = self.as_coeff_Add()
1270 im_part, imag_unit = rest.as_coeff_Mul()
1271 if not imag_unit == S.ImaginaryUnit:
1272 # ValueError may seem more reasonable but since it's a @property,
1273 # we need to use AttributeError to keep from confusing things like
1274 # hasattr.
1275 raise AttributeError("Cannot convert Add to mpc. Must be of the form Number + Number*I")
1277 return (Float(re_part)._mpf_, Float(im_part)._mpf_)
1279 def __neg__(self):
1280 if not global_parameters.distribute:
1281 return super().__neg__()
1282 return Mul(S.NegativeOne, self)
1284add = AssocOpDispatcher('add')
1286from .mul import Mul, _keep_coeff, _unevaluated_Mul
1287from .numbers import Rational