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

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 

15 

16# Key for sorting commutative args in canonical order 

17_args_sortkey = cmp_to_key(Basic.compare) 

18 

19 

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()) 

34 

35 

36def _addsort(args): 

37 # in-place sorting of args 

38 args.sort(key=_args_sortkey) 

39 

40 

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. 

45 

46 Examples 

47 ======== 

48 

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 

57 

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: 

63 

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) 

87 

88 

89class Add(Expr, AssocOp): 

90 """ 

91 Expression representing addition operation for algebraic group. 

92 

93 .. deprecated:: 1.7 

94 

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. 

98 

99 Every argument of ``Add()`` must be ``Expr``. Infix operator ``+`` 

100 on most scalar objects in SymPy calls this class. 

101 

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. 

105 

106 ``Add()`` evaluates the argument unless ``evaluate=False`` is passed. 

107 The evaluation logic includes: 

108 

109 1. Flattening 

110 ``Add(x, Add(y, z))`` -> ``Add(x, y, z)`` 

111 

112 2. Identity removing 

113 ``Add(x, 0, y)`` -> ``Add(x, y)`` 

114 

115 3. Coefficient collecting by ``.as_coeff_Mul()`` 

116 ``Add(x, 2*x)`` -> ``Mul(3, x)`` 

117 

118 4. Term sorting 

119 ``Add(y, x, 2)`` -> ``Add(2, x, y)`` 

120 

121 If no argument is passed, identity element 0 is returned. If single 

122 element is passed, that element is returned. 

123 

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. 

129 

130 Since addition is group operation, every argument should have the 

131 same :obj:`sympy.core.kind.Kind()`. 

132 

133 Examples 

134 ======== 

135 

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 

144 

145 If ``evaluate=False`` is passed, result is not evaluated. 

146 

147 >>> Add(1, 2, evaluate=False) 

148 1 + 2 

149 >>> Add(x, x, evaluate=False) 

150 x + x 

151 

152 ``Add()`` also represents the general structure of addition operation. 

153 

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'> 

161 

162 Note that the printers do not display in args order. 

163 

164 >>> Add(x, 1) 

165 x + 1 

166 >>> Add(x, 1).args 

167 (1, x) 

168 

169 See Also 

170 ======== 

171 

172 MatAdd 

173 

174 """ 

175 

176 __slots__ = () 

177 

178 args: tTuple[Expr, ...] 

179 

180 is_Add = True 

181 

182 _args_type = Expr 

183 

184 @classmethod 

185 def flatten(cls, seq): 

186 """ 

187 Takes the sequence "seq" of nested Adds and returns a flatten list. 

188 

189 Returns: (commutative_part, noncommutative_part, order_symbols) 

190 

191 Applies associativity, all terms are commutable with respect to 

192 addition. 

193 

194 NB: the removal of 0 is already handled by AssocOp.__new__ 

195 

196 See Also 

197 ======== 

198 

199 sympy.core.mul.Mul.flatten 

200 

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 

217 

218 terms = {} # term -> coeff 

219 # e.g. x**2 -> 5 for ... + 5*x**2 + ... 

220 

221 coeff = S.Zero # coefficient (Number or zoo) to always be in slot 0 

222 # e.g. 3 + ... 

223 order_factors = [] 

224 

225 extra = [] 

226 

227 for o in seq: 

228 

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 

242 

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 

255 

256 elif isinstance(o, AccumBounds): 

257 coeff = o.__add__(coeff) 

258 continue 

259 

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 

264 

265 elif isinstance(o, TensExpr): 

266 coeff = o.__add__(coeff) if coeff else o 

267 continue 

268 

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 

275 

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 

281 

282 # Mul([...]) 

283 elif o.is_Mul: 

284 c, s = o.as_coeff_Mul() 

285 

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 

294 

295 else: 

296 # everything else 

297 c = S.One 

298 s = o 

299 

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 

314 

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)) 

339 

340 noncommutative = noncommutative or not s.is_commutative 

341 

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)] 

345 

346 elif coeff is S.NegativeInfinity: 

347 newseq = [f for f in newseq if not (f.is_extended_nonpositive or f.is_real)] 

348 

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)] 

360 

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 

379 

380 # order args canonically 

381 _addsort(newseq) 

382 

383 # current code expects coeff to be first 

384 if coeff is not S.Zero: 

385 newseq.insert(0, coeff) 

386 

387 if extra: 

388 newseq += extra 

389 noncommutative = True 

390 

391 # we are done 

392 if noncommutative: 

393 return [], newseq, None 

394 else: 

395 return newseq, [], None 

396 

397 @classmethod 

398 def class_key(cls): 

399 return 3, 1, cls.__name__ 

400 

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 

413 

414 def could_extract_minus_sign(self): 

415 return _could_extract_minus_sign(self) 

416 

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. 

422 

423 Examples 

424 ======== 

425 

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 

439 

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:] 

445 

446 if coeff.is_Number and not rational or coeff.is_Rational: 

447 return coeff, self._new_rawargs(*args) 

448 return S.Zero, self 

449 

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. 

453 

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 

504 

505 @cacheit 

506 def _eval_derivative(self, s): 

507 return self.func(*[a.diff(s) for a in self.args]) 

508 

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) 

512 

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 

519 

520 def matches(self, expr, repl_dict=None, old=False): 

521 return self._matches_commutative(expr, repl_dict, old) 

522 

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 

548 

549 @cacheit 

550 def as_two_terms(self): 

551 """Return head and tail of self. 

552 

553 This is the most efficient way to get the head and tail of an 

554 expression. 

555 

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] 

562 

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:]) 

568 

569 def as_numer_denom(self): 

570 """ 

571 Decomposes an expression to its numerator part and its 

572 denominator part. 

573 

574 Examples 

575 ======== 

576 

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) 

582 

583 See Also 

584 ======== 

585 

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() 

593 

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) 

599 

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) 

605 

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) 

612 

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) 

617 

618 return _keep_coeff(ncon, n), _keep_coeff(dcon, d) 

619 

620 def _eval_is_polynomial(self, syms): 

621 return all(term._eval_is_polynomial(syms) for term in self.args) 

622 

623 def _eval_is_rational_function(self, syms): 

624 return all(term._eval_is_rational_function(syms) for term in self.args) 

625 

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) 

629 

630 def _eval_is_algebraic_expr(self, syms): 

631 return all(term._eval_is_algebraic_expr(syms) for term in self.args) 

632 

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) 

654 

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 

667 

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 

695 

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 

736 

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 

743 

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 

756 

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 

772 

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 

809 

810 if infinite is None: 

811 return 

812 unknown_sign = True 

813 

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 

826 

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 

841 

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 

856 

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 

893 

894 if infinite is None: 

895 return 

896 unknown_sign = True 

897 

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 

910 

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 

917 

918 coeff_self, terms_self = self.as_coeff_Add() 

919 coeff_old, terms_old = old.as_coeff_Add() 

920 

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) 

926 

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) 

934 

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]) 

939 

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]) 

947 

948 def removeO(self): 

949 args = [a for a in self.args if not a.is_Order] 

950 return self._new_rawargs(*args) 

951 

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) 

956 

957 @cacheit 

958 def extract_leading_order(self, symbols, point=None): 

959 """ 

960 Returns the leading term and its order. 

961 

962 Examples 

963 ======== 

964 

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)),) 

972 

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) 

994 

995 def as_real_imag(self, deep=True, **hints): 

996 """ 

997 Return a tuple representing a complex number. 

998 

999 Examples 

1000 ======== 

1001 

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)) 

1017 

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 

1024 

1025 o = self.getO() 

1026 if o is None: 

1027 o = Order(0) 

1028 old = self.removeO() 

1029 

1030 if old.has(Piecewise): 

1031 old = piecewise_fold(old) 

1032 

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) 

1041 

1042 if not expr.is_Add: 

1043 return expr.as_leading_term(x, logx=logx, cdir=cdir) 

1044 

1045 infinite = [t for t in expr.args if t.is_infinite] 

1046 

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] 

1049 

1050 min, new_expr = Order(0), 0 

1051 

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 

1060 

1061 except TypeError: 

1062 return expr 

1063 

1064 if logx is None: 

1065 new_expr = new_expr.subs(_logx, log(x)) 

1066 

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) 

1086 

1087 elif new_expr is S.NaN: 

1088 return old.func._from_args(infinite) + o 

1089 

1090 else: 

1091 return new_expr 

1092 

1093 def _eval_adjoint(self): 

1094 return self.func(*[t.adjoint() for t in self.args]) 

1095 

1096 def _eval_conjugate(self): 

1097 return self.func(*[t.conjugate() for t in self.args]) 

1098 

1099 def _eval_transpose(self): 

1100 return self.func(*[t.transpose() for t in self.args]) 

1101 

1102 def primitive(self): 

1103 """ 

1104 Return ``(R, self/R)`` where ``R``` is the Rational GCD of ``self```. 

1105 

1106 ``R`` is collected only from the leading coefficient of each term. 

1107 

1108 Examples 

1109 ======== 

1110 

1111 >>> from sympy.abc import x, y 

1112 

1113 >>> (2*x + 4*y).primitive() 

1114 (2, x + 2*y) 

1115 

1116 >>> (2*x/3 + 4*y/9).primitive() 

1117 (2/9, 3*x + 2*y) 

1118 

1119 >>> (2*x/3 + 4.2*y).primitive() 

1120 (1/3, 2*x + 12.6*y) 

1121 

1122 No subprocessing of term factors is performed: 

1123 

1124 >>> ((2 + 2*x)*x + 2).primitive() 

1125 (1, x*(2*x + 2) + 2) 

1126 

1127 Recursive processing can be done with the ``as_content_primitive()`` 

1128 method: 

1129 

1130 >>> ((2 + 2*x)*x + 2).as_content_primitive() 

1131 (2, x*(x + 1) + 1) 

1132 

1133 See also: primitive() function in polytools.py 

1134 

1135 """ 

1136 

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)) 

1146 

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) 

1153 

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) 

1165 

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) 

1181 

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. 

1187 

1188 Examples 

1189 ======== 

1190 

1191 >>> from sympy import sqrt 

1192 >>> (3 + 3*sqrt(2)).as_content_primitive() 

1193 (3, 1 + sqrt(2)) 

1194 

1195 Radical content can also be factored out of the primitive: 

1196 

1197 >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True) 

1198 (2, sqrt(2)*(1 + 2*sqrt(5))) 

1199 

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) 

1251 

1252 return con, prim 

1253 

1254 @property 

1255 def _sorted_args(self): 

1256 from .sorting import default_sort_key 

1257 return tuple(sorted(self.args, key=default_sort_key)) 

1258 

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]) 

1262 

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") 

1276 

1277 return (Float(re_part)._mpf_, Float(im_part)._mpf_) 

1278 

1279 def __neg__(self): 

1280 if not global_parameters.distribute: 

1281 return super().__neg__() 

1282 return Mul(S.NegativeOne, self) 

1283 

1284add = AssocOpDispatcher('add') 

1285 

1286from .mul import Mul, _keep_coeff, _unevaluated_Mul 

1287from .numbers import Rational