m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1574 lines
50 KiB

6 months ago
  1. """Tools for manipulating of large commutative expressions. """
  2. from .add import Add
  3. from .mul import Mul, _keep_coeff
  4. from .power import Pow
  5. from .basic import Basic
  6. from .expr import Expr
  7. from .sympify import sympify
  8. from .numbers import Rational, Integer, Number, I
  9. from .singleton import S
  10. from .sorting import default_sort_key, ordered
  11. from .symbol import Dummy
  12. from .traversal import preorder_traversal
  13. from .coreerrors import NonCommutativeExpression
  14. from .containers import Tuple, Dict
  15. from sympy.external.gmpy import SYMPY_INTS
  16. from sympy.utilities.iterables import (common_prefix, common_suffix,
  17. variations, iterable, is_sequence)
  18. from collections import defaultdict
  19. _eps = Dummy(positive=True)
  20. def _isnumber(i):
  21. return isinstance(i, (SYMPY_INTS, float)) or i.is_Number
  22. def _monotonic_sign(self):
  23. """Return the value closest to 0 that ``self`` may have if all symbols
  24. are signed and the result is uniformly the same sign for all values of symbols.
  25. If a symbol is only signed but not known to be an
  26. integer or the result is 0 then a symbol representative of the sign of self
  27. will be returned. Otherwise, None is returned if a) the sign could be positive
  28. or negative or b) self is not in one of the following forms:
  29. - L(x, y, ...) + A: a function linear in all symbols x, y, ... with an
  30. additive constant; if A is zero then the function can be a monomial whose
  31. sign is monotonic over the range of the variables, e.g. (x + 1)**3 if x is
  32. nonnegative.
  33. - A/L(x, y, ...) + B: the inverse of a function linear in all symbols x, y, ...
  34. that does not have a sign change from positive to negative for any set
  35. of values for the variables.
  36. - M(x, y, ...) + A: a monomial M whose factors are all signed and a constant, A.
  37. - A/M(x, y, ...) + B: the inverse of a monomial and constants A and B.
  38. - P(x): a univariate polynomial
  39. Examples
  40. ========
  41. >>> from sympy.core.exprtools import _monotonic_sign as F
  42. >>> from sympy import Dummy
  43. >>> nn = Dummy(integer=True, nonnegative=True)
  44. >>> p = Dummy(integer=True, positive=True)
  45. >>> p2 = Dummy(integer=True, positive=True)
  46. >>> F(nn + 1)
  47. 1
  48. >>> F(p - 1)
  49. _nneg
  50. >>> F(nn*p + 1)
  51. 1
  52. >>> F(p2*p + 1)
  53. 2
  54. >>> F(nn - 1) # could be negative, zero or positive
  55. """
  56. if not self.is_extended_real:
  57. return
  58. if (-self).is_Symbol:
  59. rv = _monotonic_sign(-self)
  60. return rv if rv is None else -rv
  61. if not self.is_Add and self.as_numer_denom()[1].is_number:
  62. s = self
  63. if s.is_prime:
  64. if s.is_odd:
  65. return Integer(3)
  66. else:
  67. return Integer(2)
  68. elif s.is_composite:
  69. if s.is_odd:
  70. return Integer(9)
  71. else:
  72. return Integer(4)
  73. elif s.is_positive:
  74. if s.is_even:
  75. if s.is_prime is False:
  76. return Integer(4)
  77. else:
  78. return Integer(2)
  79. elif s.is_integer:
  80. return S.One
  81. else:
  82. return _eps
  83. elif s.is_extended_negative:
  84. if s.is_even:
  85. return Integer(-2)
  86. elif s.is_integer:
  87. return S.NegativeOne
  88. else:
  89. return -_eps
  90. if s.is_zero or s.is_extended_nonpositive or s.is_extended_nonnegative:
  91. return S.Zero
  92. return None
  93. # univariate polynomial
  94. free = self.free_symbols
  95. if len(free) == 1:
  96. if self.is_polynomial():
  97. from sympy.polys.polytools import real_roots
  98. from sympy.polys.polyroots import roots
  99. from sympy.polys.polyerrors import PolynomialError
  100. x = free.pop()
  101. x0 = _monotonic_sign(x)
  102. if x0 in (_eps, -_eps):
  103. x0 = S.Zero
  104. if x0 is not None:
  105. d = self.diff(x)
  106. if d.is_number:
  107. currentroots = []
  108. else:
  109. try:
  110. currentroots = real_roots(d)
  111. except (PolynomialError, NotImplementedError):
  112. currentroots = [r for r in roots(d, x) if r.is_extended_real]
  113. y = self.subs(x, x0)
  114. if x.is_nonnegative and all(
  115. (r - x0).is_nonpositive for r in currentroots):
  116. if y.is_nonnegative and d.is_positive:
  117. if y:
  118. return y if y.is_positive else Dummy('pos', positive=True)
  119. else:
  120. return Dummy('nneg', nonnegative=True)
  121. if y.is_nonpositive and d.is_negative:
  122. if y:
  123. return y if y.is_negative else Dummy('neg', negative=True)
  124. else:
  125. return Dummy('npos', nonpositive=True)
  126. elif x.is_nonpositive and all(
  127. (r - x0).is_nonnegative for r in currentroots):
  128. if y.is_nonnegative and d.is_negative:
  129. if y:
  130. return Dummy('pos', positive=True)
  131. else:
  132. return Dummy('nneg', nonnegative=True)
  133. if y.is_nonpositive and d.is_positive:
  134. if y:
  135. return Dummy('neg', negative=True)
  136. else:
  137. return Dummy('npos', nonpositive=True)
  138. else:
  139. n, d = self.as_numer_denom()
  140. den = None
  141. if n.is_number:
  142. den = _monotonic_sign(d)
  143. elif not d.is_number:
  144. if _monotonic_sign(n) is not None:
  145. den = _monotonic_sign(d)
  146. if den is not None and (den.is_positive or den.is_negative):
  147. v = n*den
  148. if v.is_positive:
  149. return Dummy('pos', positive=True)
  150. elif v.is_nonnegative:
  151. return Dummy('nneg', nonnegative=True)
  152. elif v.is_negative:
  153. return Dummy('neg', negative=True)
  154. elif v.is_nonpositive:
  155. return Dummy('npos', nonpositive=True)
  156. return None
  157. # multivariate
  158. c, a = self.as_coeff_Add()
  159. v = None
  160. if not a.is_polynomial():
  161. # F/A or A/F where A is a number and F is a signed, rational monomial
  162. n, d = a.as_numer_denom()
  163. if not (n.is_number or d.is_number):
  164. return
  165. if (
  166. a.is_Mul or a.is_Pow) and \
  167. a.is_rational and \
  168. all(p.exp.is_Integer for p in a.atoms(Pow) if p.is_Pow) and \
  169. (a.is_positive or a.is_negative):
  170. v = S.One
  171. for ai in Mul.make_args(a):
  172. if ai.is_number:
  173. v *= ai
  174. continue
  175. reps = {}
  176. for x in ai.free_symbols:
  177. reps[x] = _monotonic_sign(x)
  178. if reps[x] is None:
  179. return
  180. v *= ai.subs(reps)
  181. elif c:
  182. # signed linear expression
  183. if not any(p for p in a.atoms(Pow) if not p.is_number) and (a.is_nonpositive or a.is_nonnegative):
  184. free = list(a.free_symbols)
  185. p = {}
  186. for i in free:
  187. v = _monotonic_sign(i)
  188. if v is None:
  189. return
  190. p[i] = v or (_eps if i.is_nonnegative else -_eps)
  191. v = a.xreplace(p)
  192. if v is not None:
  193. rv = v + c
  194. if v.is_nonnegative and rv.is_positive:
  195. return rv.subs(_eps, 0)
  196. if v.is_nonpositive and rv.is_negative:
  197. return rv.subs(_eps, 0)
  198. def decompose_power(expr):
  199. """
  200. Decompose power into symbolic base and integer exponent.
  201. Explanation
  202. ===========
  203. This is strictly only valid if the exponent from which
  204. the integer is extracted is itself an integer or the
  205. base is positive. These conditions are assumed and not
  206. checked here.
  207. Examples
  208. ========
  209. >>> from sympy.core.exprtools import decompose_power
  210. >>> from sympy.abc import x, y
  211. >>> decompose_power(x)
  212. (x, 1)
  213. >>> decompose_power(x**2)
  214. (x, 2)
  215. >>> decompose_power(x**(2*y))
  216. (x**y, 2)
  217. >>> decompose_power(x**(2*y/3))
  218. (x**(y/3), 2)
  219. """
  220. base, exp = expr.as_base_exp()
  221. if exp.is_Number:
  222. if exp.is_Rational:
  223. if not exp.is_Integer:
  224. base = Pow(base, Rational(1, exp.q))
  225. exp = exp.p
  226. else:
  227. base, exp = expr, 1
  228. else:
  229. exp, tail = exp.as_coeff_Mul(rational=True)
  230. if exp is S.NegativeOne:
  231. base, exp = Pow(base, tail), -1
  232. elif exp is not S.One:
  233. tail = _keep_coeff(Rational(1, exp.q), tail)
  234. base, exp = Pow(base, tail), exp.p
  235. else:
  236. base, exp = expr, 1
  237. return base, exp
  238. def decompose_power_rat(expr):
  239. """
  240. Decompose power into symbolic base and rational exponent.
  241. """
  242. base, exp = expr.as_base_exp()
  243. if exp.is_Number:
  244. if not exp.is_Rational:
  245. base, exp = expr, 1
  246. else:
  247. exp, tail = exp.as_coeff_Mul(rational=True)
  248. if exp is S.NegativeOne:
  249. base, exp = Pow(base, tail), -1
  250. elif exp is not S.One:
  251. tail = _keep_coeff(Rational(1, exp.q), tail)
  252. base, exp = Pow(base, tail), exp.p
  253. else:
  254. base, exp = expr, 1
  255. return base, exp
  256. class Factors:
  257. """Efficient representation of ``f_1*f_2*...*f_n``."""
  258. __slots__ = ('factors', 'gens')
  259. def __init__(self, factors=None): # Factors
  260. """Initialize Factors from dict or expr.
  261. Examples
  262. ========
  263. >>> from sympy.core.exprtools import Factors
  264. >>> from sympy.abc import x
  265. >>> from sympy import I
  266. >>> e = 2*x**3
  267. >>> Factors(e)
  268. Factors({2: 1, x: 3})
  269. >>> Factors(e.as_powers_dict())
  270. Factors({2: 1, x: 3})
  271. >>> f = _
  272. >>> f.factors # underlying dictionary
  273. {2: 1, x: 3}
  274. >>> f.gens # base of each factor
  275. frozenset({2, x})
  276. >>> Factors(0)
  277. Factors({0: 1})
  278. >>> Factors(I)
  279. Factors({I: 1})
  280. Notes
  281. =====
  282. Although a dictionary can be passed, only minimal checking is
  283. performed: powers of -1 and I are made canonical.
  284. """
  285. if isinstance(factors, (SYMPY_INTS, float)):
  286. factors = S(factors)
  287. if isinstance(factors, Factors):
  288. factors = factors.factors.copy()
  289. elif factors in (None, S.One):
  290. factors = {}
  291. elif factors is S.Zero or factors == 0:
  292. factors = {S.Zero: S.One}
  293. elif isinstance(factors, Number):
  294. n = factors
  295. factors = {}
  296. if n < 0:
  297. factors[S.NegativeOne] = S.One
  298. n = -n
  299. if n is not S.One:
  300. if n.is_Float or n.is_Integer or n is S.Infinity:
  301. factors[n] = S.One
  302. elif n.is_Rational:
  303. # since we're processing Numbers, the denominator is
  304. # stored with a negative exponent; all other factors
  305. # are left .
  306. if n.p != 1:
  307. factors[Integer(n.p)] = S.One
  308. factors[Integer(n.q)] = S.NegativeOne
  309. else:
  310. raise ValueError('Expected Float|Rational|Integer, not %s' % n)
  311. elif isinstance(factors, Basic) and not factors.args:
  312. factors = {factors: S.One}
  313. elif isinstance(factors, Expr):
  314. c, nc = factors.args_cnc()
  315. i = c.count(I)
  316. for _ in range(i):
  317. c.remove(I)
  318. factors = dict(Mul._from_args(c).as_powers_dict())
  319. # Handle all rational Coefficients
  320. for f in list(factors.keys()):
  321. if isinstance(f, Rational) and not isinstance(f, Integer):
  322. p, q = Integer(f.p), Integer(f.q)
  323. factors[p] = (factors[p] if p in factors else S.Zero) + factors[f]
  324. factors[q] = (factors[q] if q in factors else S.Zero) - factors[f]
  325. factors.pop(f)
  326. if i:
  327. factors[I] = factors.get(I, S.Zero) + i
  328. if nc:
  329. factors[Mul(*nc, evaluate=False)] = S.One
  330. else:
  331. factors = factors.copy() # /!\ should be dict-like
  332. # tidy up -/+1 and I exponents if Rational
  333. handle = []
  334. for k in factors:
  335. if k is I or k in (-1, 1):
  336. handle.append(k)
  337. if handle:
  338. i1 = S.One
  339. for k in handle:
  340. if not _isnumber(factors[k]):
  341. continue
  342. i1 *= k**factors.pop(k)
  343. if i1 is not S.One:
  344. for a in i1.args if i1.is_Mul else [i1]: # at worst, -1.0*I*(-1)**e
  345. if a is S.NegativeOne:
  346. factors[a] = S.One
  347. elif a is I:
  348. factors[I] = S.One
  349. elif a.is_Pow:
  350. factors[a.base] = factors.get(a.base, S.Zero) + a.exp
  351. elif a == 1:
  352. factors[a] = S.One
  353. elif a == -1:
  354. factors[-a] = S.One
  355. factors[S.NegativeOne] = S.One
  356. else:
  357. raise ValueError('unexpected factor in i1: %s' % a)
  358. self.factors = factors
  359. keys = getattr(factors, 'keys', None)
  360. if keys is None:
  361. raise TypeError('expecting Expr or dictionary')
  362. self.gens = frozenset(keys())
  363. def __hash__(self): # Factors
  364. keys = tuple(ordered(self.factors.keys()))
  365. values = [self.factors[k] for k in keys]
  366. return hash((keys, values))
  367. def __repr__(self): # Factors
  368. return "Factors({%s})" % ', '.join(
  369. ['%s: %s' % (k, v) for k, v in ordered(self.factors.items())])
  370. @property
  371. def is_zero(self): # Factors
  372. """
  373. >>> from sympy.core.exprtools import Factors
  374. >>> Factors(0).is_zero
  375. True
  376. """
  377. f = self.factors
  378. return len(f) == 1 and S.Zero in f
  379. @property
  380. def is_one(self): # Factors
  381. """
  382. >>> from sympy.core.exprtools import Factors
  383. >>> Factors(1).is_one
  384. True
  385. """
  386. return not self.factors
  387. def as_expr(self): # Factors
  388. """Return the underlying expression.
  389. Examples
  390. ========
  391. >>> from sympy.core.exprtools import Factors
  392. >>> from sympy.abc import x, y
  393. >>> Factors((x*y**2).as_powers_dict()).as_expr()
  394. x*y**2
  395. """
  396. args = []
  397. for factor, exp in self.factors.items():
  398. if exp != 1:
  399. if isinstance(exp, Integer):
  400. b, e = factor.as_base_exp()
  401. e = _keep_coeff(exp, e)
  402. args.append(b**e)
  403. else:
  404. args.append(factor**exp)
  405. else:
  406. args.append(factor)
  407. return Mul(*args)
  408. def mul(self, other): # Factors
  409. """Return Factors of ``self * other``.
  410. Examples
  411. ========
  412. >>> from sympy.core.exprtools import Factors
  413. >>> from sympy.abc import x, y, z
  414. >>> a = Factors((x*y**2).as_powers_dict())
  415. >>> b = Factors((x*y/z).as_powers_dict())
  416. >>> a.mul(b)
  417. Factors({x: 2, y: 3, z: -1})
  418. >>> a*b
  419. Factors({x: 2, y: 3, z: -1})
  420. """
  421. if not isinstance(other, Factors):
  422. other = Factors(other)
  423. if any(f.is_zero for f in (self, other)):
  424. return Factors(S.Zero)
  425. factors = dict(self.factors)
  426. for factor, exp in other.factors.items():
  427. if factor in factors:
  428. exp = factors[factor] + exp
  429. if not exp:
  430. del factors[factor]
  431. continue
  432. factors[factor] = exp
  433. return Factors(factors)
  434. def normal(self, other):
  435. """Return ``self`` and ``other`` with ``gcd`` removed from each.
  436. The only differences between this and method ``div`` is that this
  437. is 1) optimized for the case when there are few factors in common and
  438. 2) this does not raise an error if ``other`` is zero.
  439. See Also
  440. ========
  441. div
  442. """
  443. if not isinstance(other, Factors):
  444. other = Factors(other)
  445. if other.is_zero:
  446. return (Factors(), Factors(S.Zero))
  447. if self.is_zero:
  448. return (Factors(S.Zero), Factors())
  449. self_factors = dict(self.factors)
  450. other_factors = dict(other.factors)
  451. for factor, self_exp in self.factors.items():
  452. try:
  453. other_exp = other.factors[factor]
  454. except KeyError:
  455. continue
  456. exp = self_exp - other_exp
  457. if not exp:
  458. del self_factors[factor]
  459. del other_factors[factor]
  460. elif _isnumber(exp):
  461. if exp > 0:
  462. self_factors[factor] = exp
  463. del other_factors[factor]
  464. else:
  465. del self_factors[factor]
  466. other_factors[factor] = -exp
  467. else:
  468. r = self_exp.extract_additively(other_exp)
  469. if r is not None:
  470. if r:
  471. self_factors[factor] = r
  472. del other_factors[factor]
  473. else: # should be handled already
  474. del self_factors[factor]
  475. del other_factors[factor]
  476. else:
  477. sc, sa = self_exp.as_coeff_Add()
  478. if sc:
  479. oc, oa = other_exp.as_coeff_Add()
  480. diff = sc - oc
  481. if diff > 0:
  482. self_factors[factor] -= oc
  483. other_exp = oa
  484. elif diff < 0:
  485. self_factors[factor] -= sc
  486. other_factors[factor] -= sc
  487. other_exp = oa - diff
  488. else:
  489. self_factors[factor] = sa
  490. other_exp = oa
  491. if other_exp:
  492. other_factors[factor] = other_exp
  493. else:
  494. del other_factors[factor]
  495. return Factors(self_factors), Factors(other_factors)
  496. def div(self, other): # Factors
  497. """Return ``self`` and ``other`` with ``gcd`` removed from each.
  498. This is optimized for the case when there are many factors in common.
  499. Examples
  500. ========
  501. >>> from sympy.core.exprtools import Factors
  502. >>> from sympy.abc import x, y, z
  503. >>> from sympy import S
  504. >>> a = Factors((x*y**2).as_powers_dict())
  505. >>> a.div(a)
  506. (Factors({}), Factors({}))
  507. >>> a.div(x*z)
  508. (Factors({y: 2}), Factors({z: 1}))
  509. The ``/`` operator only gives ``quo``:
  510. >>> a/x
  511. Factors({y: 2})
  512. Factors treats its factors as though they are all in the numerator, so
  513. if you violate this assumption the results will be correct but will
  514. not strictly correspond to the numerator and denominator of the ratio:
  515. >>> a.div(x/z)
  516. (Factors({y: 2}), Factors({z: -1}))
  517. Factors is also naive about bases: it does not attempt any denesting
  518. of Rational-base terms, for example the following does not become
  519. 2**(2*x)/2.
  520. >>> Factors(2**(2*x + 2)).div(S(8))
  521. (Factors({2: 2*x + 2}), Factors({8: 1}))
  522. factor_terms can clean up such Rational-bases powers:
  523. >>> from sympy import factor_terms
  524. >>> n, d = Factors(2**(2*x + 2)).div(S(8))
  525. >>> n.as_expr()/d.as_expr()
  526. 2**(2*x + 2)/8
  527. >>> factor_terms(_)
  528. 2**(2*x)/2
  529. """
  530. quo, rem = dict(self.factors), {}
  531. if not isinstance(other, Factors):
  532. other = Factors(other)
  533. if other.is_zero:
  534. raise ZeroDivisionError
  535. if self.is_zero:
  536. return (Factors(S.Zero), Factors())
  537. for factor, exp in other.factors.items():
  538. if factor in quo:
  539. d = quo[factor] - exp
  540. if _isnumber(d):
  541. if d <= 0:
  542. del quo[factor]
  543. if d >= 0:
  544. if d:
  545. quo[factor] = d
  546. continue
  547. exp = -d
  548. else:
  549. r = quo[factor].extract_additively(exp)
  550. if r is not None:
  551. if r:
  552. quo[factor] = r
  553. else: # should be handled already
  554. del quo[factor]
  555. else:
  556. other_exp = exp
  557. sc, sa = quo[factor].as_coeff_Add()
  558. if sc:
  559. oc, oa = other_exp.as_coeff_Add()
  560. diff = sc - oc
  561. if diff > 0:
  562. quo[factor] -= oc
  563. other_exp = oa
  564. elif diff < 0:
  565. quo[factor] -= sc
  566. other_exp = oa - diff
  567. else:
  568. quo[factor] = sa
  569. other_exp = oa
  570. if other_exp:
  571. rem[factor] = other_exp
  572. else:
  573. assert factor not in rem
  574. continue
  575. rem[factor] = exp
  576. return Factors(quo), Factors(rem)
  577. def quo(self, other): # Factors
  578. """Return numerator Factor of ``self / other``.
  579. Examples
  580. ========
  581. >>> from sympy.core.exprtools import Factors
  582. >>> from sympy.abc import x, y, z
  583. >>> a = Factors((x*y**2).as_powers_dict())
  584. >>> b = Factors((x*y/z).as_powers_dict())
  585. >>> a.quo(b) # same as a/b
  586. Factors({y: 1})
  587. """
  588. return self.div(other)[0]
  589. def rem(self, other): # Factors
  590. """Return denominator Factors of ``self / other``.
  591. Examples
  592. ========
  593. >>> from sympy.core.exprtools import Factors
  594. >>> from sympy.abc import x, y, z
  595. >>> a = Factors((x*y**2).as_powers_dict())
  596. >>> b = Factors((x*y/z).as_powers_dict())
  597. >>> a.rem(b)
  598. Factors({z: -1})
  599. >>> a.rem(a)
  600. Factors({})
  601. """
  602. return self.div(other)[1]
  603. def pow(self, other): # Factors
  604. """Return self raised to a non-negative integer power.
  605. Examples
  606. ========
  607. >>> from sympy.core.exprtools import Factors
  608. >>> from sympy.abc import x, y
  609. >>> a = Factors((x*y**2).as_powers_dict())
  610. >>> a**2
  611. Factors({x: 2, y: 4})
  612. """
  613. if isinstance(other, Factors):
  614. other = other.as_expr()
  615. if other.is_Integer:
  616. other = int(other)
  617. if isinstance(other, SYMPY_INTS) and other >= 0:
  618. factors = {}
  619. if other:
  620. for factor, exp in self.factors.items():
  621. factors[factor] = exp*other
  622. return Factors(factors)
  623. else:
  624. raise ValueError("expected non-negative integer, got %s" % other)
  625. def gcd(self, other): # Factors
  626. """Return Factors of ``gcd(self, other)``. The keys are
  627. the intersection of factors with the minimum exponent for
  628. each factor.
  629. Examples
  630. ========
  631. >>> from sympy.core.exprtools import Factors
  632. >>> from sympy.abc import x, y, z
  633. >>> a = Factors((x*y**2).as_powers_dict())
  634. >>> b = Factors((x*y/z).as_powers_dict())
  635. >>> a.gcd(b)
  636. Factors({x: 1, y: 1})
  637. """
  638. if not isinstance(other, Factors):
  639. other = Factors(other)
  640. if other.is_zero:
  641. return Factors(self.factors)
  642. factors = {}
  643. for factor, exp in self.factors.items():
  644. factor, exp = sympify(factor), sympify(exp)
  645. if factor in other.factors:
  646. lt = (exp - other.factors[factor]).is_negative
  647. if lt == True:
  648. factors[factor] = exp
  649. elif lt == False:
  650. factors[factor] = other.factors[factor]
  651. return Factors(factors)
  652. def lcm(self, other): # Factors
  653. """Return Factors of ``lcm(self, other)`` which are
  654. the union of factors with the maximum exponent for
  655. each factor.
  656. Examples
  657. ========
  658. >>> from sympy.core.exprtools import Factors
  659. >>> from sympy.abc import x, y, z
  660. >>> a = Factors((x*y**2).as_powers_dict())
  661. >>> b = Factors((x*y/z).as_powers_dict())
  662. >>> a.lcm(b)
  663. Factors({x: 1, y: 2, z: -1})
  664. """
  665. if not isinstance(other, Factors):
  666. other = Factors(other)
  667. if any(f.is_zero for f in (self, other)):
  668. return Factors(S.Zero)
  669. factors = dict(self.factors)
  670. for factor, exp in other.factors.items():
  671. if factor in factors:
  672. exp = max(exp, factors[factor])
  673. factors[factor] = exp
  674. return Factors(factors)
  675. def __mul__(self, other): # Factors
  676. return self.mul(other)
  677. def __divmod__(self, other): # Factors
  678. return self.div(other)
  679. def __truediv__(self, other): # Factors
  680. return self.quo(other)
  681. def __mod__(self, other): # Factors
  682. return self.rem(other)
  683. def __pow__(self, other): # Factors
  684. return self.pow(other)
  685. def __eq__(self, other): # Factors
  686. if not isinstance(other, Factors):
  687. other = Factors(other)
  688. return self.factors == other.factors
  689. def __ne__(self, other): # Factors
  690. return not self == other
  691. class Term:
  692. """Efficient representation of ``coeff*(numer/denom)``. """
  693. __slots__ = ('coeff', 'numer', 'denom')
  694. def __init__(self, term, numer=None, denom=None): # Term
  695. if numer is None and denom is None:
  696. if not term.is_commutative:
  697. raise NonCommutativeExpression(
  698. 'commutative expression expected')
  699. coeff, factors = term.as_coeff_mul()
  700. numer, denom = defaultdict(int), defaultdict(int)
  701. for factor in factors:
  702. base, exp = decompose_power(factor)
  703. if base.is_Add:
  704. cont, base = base.primitive()
  705. coeff *= cont**exp
  706. if exp > 0:
  707. numer[base] += exp
  708. else:
  709. denom[base] += -exp
  710. numer = Factors(numer)
  711. denom = Factors(denom)
  712. else:
  713. coeff = term
  714. if numer is None:
  715. numer = Factors()
  716. if denom is None:
  717. denom = Factors()
  718. self.coeff = coeff
  719. self.numer = numer
  720. self.denom = denom
  721. def __hash__(self): # Term
  722. return hash((self.coeff, self.numer, self.denom))
  723. def __repr__(self): # Term
  724. return "Term(%s, %s, %s)" % (self.coeff, self.numer, self.denom)
  725. def as_expr(self): # Term
  726. return self.coeff*(self.numer.as_expr()/self.denom.as_expr())
  727. def mul(self, other): # Term
  728. coeff = self.coeff*other.coeff
  729. numer = self.numer.mul(other.numer)
  730. denom = self.denom.mul(other.denom)
  731. numer, denom = numer.normal(denom)
  732. return Term(coeff, numer, denom)
  733. def inv(self): # Term
  734. return Term(1/self.coeff, self.denom, self.numer)
  735. def quo(self, other): # Term
  736. return self.mul(other.inv())
  737. def pow(self, other): # Term
  738. if other < 0:
  739. return self.inv().pow(-other)
  740. else:
  741. return Term(self.coeff ** other,
  742. self.numer.pow(other),
  743. self.denom.pow(other))
  744. def gcd(self, other): # Term
  745. return Term(self.coeff.gcd(other.coeff),
  746. self.numer.gcd(other.numer),
  747. self.denom.gcd(other.denom))
  748. def lcm(self, other): # Term
  749. return Term(self.coeff.lcm(other.coeff),
  750. self.numer.lcm(other.numer),
  751. self.denom.lcm(other.denom))
  752. def __mul__(self, other): # Term
  753. if isinstance(other, Term):
  754. return self.mul(other)
  755. else:
  756. return NotImplemented
  757. def __truediv__(self, other): # Term
  758. if isinstance(other, Term):
  759. return self.quo(other)
  760. else:
  761. return NotImplemented
  762. def __pow__(self, other): # Term
  763. if isinstance(other, SYMPY_INTS):
  764. return self.pow(other)
  765. else:
  766. return NotImplemented
  767. def __eq__(self, other): # Term
  768. return (self.coeff == other.coeff and
  769. self.numer == other.numer and
  770. self.denom == other.denom)
  771. def __ne__(self, other): # Term
  772. return not self == other
  773. def _gcd_terms(terms, isprimitive=False, fraction=True):
  774. """Helper function for :func:`gcd_terms`.
  775. Parameters
  776. ==========
  777. isprimitive : boolean, optional
  778. If ``isprimitive`` is True then the call to primitive
  779. for an Add will be skipped. This is useful when the
  780. content has already been extrated.
  781. fraction : boolean, optional
  782. If ``fraction`` is True then the expression will appear over a common
  783. denominator, the lcm of all term denominators.
  784. """
  785. if isinstance(terms, Basic) and not isinstance(terms, Tuple):
  786. terms = Add.make_args(terms)
  787. terms = list(map(Term, [t for t in terms if t]))
  788. # there is some simplification that may happen if we leave this
  789. # here rather than duplicate it before the mapping of Term onto
  790. # the terms
  791. if len(terms) == 0:
  792. return S.Zero, S.Zero, S.One
  793. if len(terms) == 1:
  794. cont = terms[0].coeff
  795. numer = terms[0].numer.as_expr()
  796. denom = terms[0].denom.as_expr()
  797. else:
  798. cont = terms[0]
  799. for term in terms[1:]:
  800. cont = cont.gcd(term)
  801. for i, term in enumerate(terms):
  802. terms[i] = term.quo(cont)
  803. if fraction:
  804. denom = terms[0].denom
  805. for term in terms[1:]:
  806. denom = denom.lcm(term.denom)
  807. numers = []
  808. for term in terms:
  809. numer = term.numer.mul(denom.quo(term.denom))
  810. numers.append(term.coeff*numer.as_expr())
  811. else:
  812. numers = [t.as_expr() for t in terms]
  813. denom = Term(S.One).numer
  814. cont = cont.as_expr()
  815. numer = Add(*numers)
  816. denom = denom.as_expr()
  817. if not isprimitive and numer.is_Add:
  818. _cont, numer = numer.primitive()
  819. cont *= _cont
  820. return cont, numer, denom
  821. def gcd_terms(terms, isprimitive=False, clear=True, fraction=True):
  822. """Compute the GCD of ``terms`` and put them together.
  823. Parameters
  824. ==========
  825. terms : Expr
  826. Can be an expression or a non-Basic sequence of expressions
  827. which will be handled as though they are terms from a sum.
  828. isprimitive : bool, optional
  829. If ``isprimitive`` is True the _gcd_terms will not run the primitive
  830. method on the terms.
  831. clear : bool, optional
  832. It controls the removal of integers from the denominator of an Add
  833. expression. When True (default), all numerical denominator will be cleared;
  834. when False the denominators will be cleared only if all terms had numerical
  835. denominators other than 1.
  836. fraction : bool, optional
  837. When True (default), will put the expression over a common
  838. denominator.
  839. Examples
  840. ========
  841. >>> from sympy import gcd_terms
  842. >>> from sympy.abc import x, y
  843. >>> gcd_terms((x + 1)**2*y + (x + 1)*y**2)
  844. y*(x + 1)*(x + y + 1)
  845. >>> gcd_terms(x/2 + 1)
  846. (x + 2)/2
  847. >>> gcd_terms(x/2 + 1, clear=False)
  848. x/2 + 1
  849. >>> gcd_terms(x/2 + y/2, clear=False)
  850. (x + y)/2
  851. >>> gcd_terms(x/2 + 1/x)
  852. (x**2 + 2)/(2*x)
  853. >>> gcd_terms(x/2 + 1/x, fraction=False)
  854. (x + 2/x)/2
  855. >>> gcd_terms(x/2 + 1/x, fraction=False, clear=False)
  856. x/2 + 1/x
  857. >>> gcd_terms(x/2/y + 1/x/y)
  858. (x**2 + 2)/(2*x*y)
  859. >>> gcd_terms(x/2/y + 1/x/y, clear=False)
  860. (x**2/2 + 1)/(x*y)
  861. >>> gcd_terms(x/2/y + 1/x/y, clear=False, fraction=False)
  862. (x/2 + 1/x)/y
  863. The ``clear`` flag was ignored in this case because the returned
  864. expression was a rational expression, not a simple sum.
  865. See Also
  866. ========
  867. factor_terms, sympy.polys.polytools.terms_gcd
  868. """
  869. def mask(terms):
  870. """replace nc portions of each term with a unique Dummy symbols
  871. and return the replacements to restore them"""
  872. args = [(a, []) if a.is_commutative else a.args_cnc() for a in terms]
  873. reps = []
  874. for i, (c, nc) in enumerate(args):
  875. if nc:
  876. nc = Mul(*nc)
  877. d = Dummy()
  878. reps.append((d, nc))
  879. c.append(d)
  880. args[i] = Mul(*c)
  881. else:
  882. args[i] = c
  883. return args, dict(reps)
  884. isadd = isinstance(terms, Add)
  885. addlike = isadd or not isinstance(terms, Basic) and \
  886. is_sequence(terms, include=set) and \
  887. not isinstance(terms, Dict)
  888. if addlike:
  889. if isadd: # i.e. an Add
  890. terms = list(terms.args)
  891. else:
  892. terms = sympify(terms)
  893. terms, reps = mask(terms)
  894. cont, numer, denom = _gcd_terms(terms, isprimitive, fraction)
  895. numer = numer.xreplace(reps)
  896. coeff, factors = cont.as_coeff_Mul()
  897. if not clear:
  898. c, _coeff = coeff.as_coeff_Mul()
  899. if not c.is_Integer and not clear and numer.is_Add:
  900. n, d = c.as_numer_denom()
  901. _numer = numer/d
  902. if any(a.as_coeff_Mul()[0].is_Integer
  903. for a in _numer.args):
  904. numer = _numer
  905. coeff = n*_coeff
  906. return _keep_coeff(coeff, factors*numer/denom, clear=clear)
  907. if not isinstance(terms, Basic):
  908. return terms
  909. if terms.is_Atom:
  910. return terms
  911. if terms.is_Mul:
  912. c, args = terms.as_coeff_mul()
  913. return _keep_coeff(c, Mul(*[gcd_terms(i, isprimitive, clear, fraction)
  914. for i in args]), clear=clear)
  915. def handle(a):
  916. # don't treat internal args like terms of an Add
  917. if not isinstance(a, Expr):
  918. if isinstance(a, Basic):
  919. if not a.args:
  920. return a
  921. return a.func(*[handle(i) for i in a.args])
  922. return type(a)([handle(i) for i in a])
  923. return gcd_terms(a, isprimitive, clear, fraction)
  924. if isinstance(terms, Dict):
  925. return Dict(*[(k, handle(v)) for k, v in terms.args])
  926. return terms.func(*[handle(i) for i in terms.args])
  927. def _factor_sum_int(expr, **kwargs):
  928. """Return Sum or Integral object with factors that are not
  929. in the wrt variables removed. In cases where there are additive
  930. terms in the function of the object that are independent, the
  931. object will be separated into two objects.
  932. Examples
  933. ========
  934. >>> from sympy import Sum, factor_terms
  935. >>> from sympy.abc import x, y
  936. >>> factor_terms(Sum(x + y, (x, 1, 3)))
  937. y*Sum(1, (x, 1, 3)) + Sum(x, (x, 1, 3))
  938. >>> factor_terms(Sum(x*y, (x, 1, 3)))
  939. y*Sum(x, (x, 1, 3))
  940. Notes
  941. =====
  942. If a function in the summand or integrand is replaced
  943. with a symbol, then this simplification should not be
  944. done or else an incorrect result will be obtained when
  945. the symbol is replaced with an expression that depends
  946. on the variables of summation/integration:
  947. >>> eq = Sum(y, (x, 1, 3))
  948. >>> factor_terms(eq).subs(y, x).doit()
  949. 3*x
  950. >>> eq.subs(y, x).doit()
  951. 6
  952. """
  953. result = expr.function
  954. if result == 0:
  955. return S.Zero
  956. limits = expr.limits
  957. # get the wrt variables
  958. wrt = {i.args[0] for i in limits}
  959. # factor out any common terms that are independent of wrt
  960. f = factor_terms(result, **kwargs)
  961. i, d = f.as_independent(*wrt)
  962. if isinstance(f, Add):
  963. return i * expr.func(1, *limits) + expr.func(d, *limits)
  964. else:
  965. return i * expr.func(d, *limits)
  966. def factor_terms(expr, radical=False, clear=False, fraction=False, sign=True):
  967. """Remove common factors from terms in all arguments without
  968. changing the underlying structure of the expr. No expansion or
  969. simplification (and no processing of non-commutatives) is performed.
  970. Parameters
  971. ==========
  972. radical: bool, optional
  973. If radical=True then a radical common to all terms will be factored
  974. out of any Add sub-expressions of the expr.
  975. clear : bool, optional
  976. If clear=False (default) then coefficients will not be separated
  977. from a single Add if they can be distributed to leave one or more
  978. terms with integer coefficients.
  979. fraction : bool, optional
  980. If fraction=True (default is False) then a common denominator will be
  981. constructed for the expression.
  982. sign : bool, optional
  983. If sign=True (default) then even if the only factor in common is a -1,
  984. it will be factored out of the expression.
  985. Examples
  986. ========
  987. >>> from sympy import factor_terms, Symbol
  988. >>> from sympy.abc import x, y
  989. >>> factor_terms(x + x*(2 + 4*y)**3)
  990. x*(8*(2*y + 1)**3 + 1)
  991. >>> A = Symbol('A', commutative=False)
  992. >>> factor_terms(x*A + x*A + x*y*A)
  993. x*(y*A + 2*A)
  994. When ``clear`` is False, a rational will only be factored out of an
  995. Add expression if all terms of the Add have coefficients that are
  996. fractions:
  997. >>> factor_terms(x/2 + 1, clear=False)
  998. x/2 + 1
  999. >>> factor_terms(x/2 + 1, clear=True)
  1000. (x + 2)/2
  1001. If a -1 is all that can be factored out, to *not* factor it out, the
  1002. flag ``sign`` must be False:
  1003. >>> factor_terms(-x - y)
  1004. -(x + y)
  1005. >>> factor_terms(-x - y, sign=False)
  1006. -x - y
  1007. >>> factor_terms(-2*x - 2*y, sign=False)
  1008. -2*(x + y)
  1009. See Also
  1010. ========
  1011. gcd_terms, sympy.polys.polytools.terms_gcd
  1012. """
  1013. def do(expr):
  1014. from sympy.concrete.summations import Sum
  1015. from sympy.integrals.integrals import Integral
  1016. is_iterable = iterable(expr)
  1017. if not isinstance(expr, Basic) or expr.is_Atom:
  1018. if is_iterable:
  1019. return type(expr)([do(i) for i in expr])
  1020. return expr
  1021. if expr.is_Pow or expr.is_Function or \
  1022. is_iterable or not hasattr(expr, 'args_cnc'):
  1023. args = expr.args
  1024. newargs = tuple([do(i) for i in args])
  1025. if newargs == args:
  1026. return expr
  1027. return expr.func(*newargs)
  1028. if isinstance(expr, (Sum, Integral)):
  1029. return _factor_sum_int(expr,
  1030. radical=radical, clear=clear,
  1031. fraction=fraction, sign=sign)
  1032. cont, p = expr.as_content_primitive(radical=radical, clear=clear)
  1033. if p.is_Add:
  1034. list_args = [do(a) for a in Add.make_args(p)]
  1035. # get a common negative (if there) which gcd_terms does not remove
  1036. if not any(a.as_coeff_Mul()[0].extract_multiplicatively(-1) is None
  1037. for a in list_args):
  1038. cont = -cont
  1039. list_args = [-a for a in list_args]
  1040. # watch out for exp(-(x+2)) which gcd_terms will change to exp(-x-2)
  1041. special = {}
  1042. for i, a in enumerate(list_args):
  1043. b, e = a.as_base_exp()
  1044. if e.is_Mul and e != Mul(*e.args):
  1045. list_args[i] = Dummy()
  1046. special[list_args[i]] = a
  1047. # rebuild p not worrying about the order which gcd_terms will fix
  1048. p = Add._from_args(list_args)
  1049. p = gcd_terms(p,
  1050. isprimitive=True,
  1051. clear=clear,
  1052. fraction=fraction).xreplace(special)
  1053. elif p.args:
  1054. p = p.func(
  1055. *[do(a) for a in p.args])
  1056. rv = _keep_coeff(cont, p, clear=clear, sign=sign)
  1057. return rv
  1058. expr = sympify(expr)
  1059. return do(expr)
  1060. def _mask_nc(eq, name=None):
  1061. """
  1062. Return ``eq`` with non-commutative objects replaced with Dummy
  1063. symbols. A dictionary that can be used to restore the original
  1064. values is returned: if it is None, the expression is noncommutative
  1065. and cannot be made commutative. The third value returned is a list
  1066. of any non-commutative symbols that appear in the returned equation.
  1067. Explanation
  1068. ===========
  1069. All non-commutative objects other than Symbols are replaced with
  1070. a non-commutative Symbol. Identical objects will be identified
  1071. by identical symbols.
  1072. If there is only 1 non-commutative object in an expression it will
  1073. be replaced with a commutative symbol. Otherwise, the non-commutative
  1074. entities are retained and the calling routine should handle
  1075. replacements in this case since some care must be taken to keep
  1076. track of the ordering of symbols when they occur within Muls.
  1077. Parameters
  1078. ==========
  1079. name : str
  1080. ``name``, if given, is the name that will be used with numbered Dummy
  1081. variables that will replace the non-commutative objects and is mainly
  1082. used for doctesting purposes.
  1083. Examples
  1084. ========
  1085. >>> from sympy.physics.secondquant import Commutator, NO, F, Fd
  1086. >>> from sympy import symbols
  1087. >>> from sympy.core.exprtools import _mask_nc
  1088. >>> from sympy.abc import x, y
  1089. >>> A, B, C = symbols('A,B,C', commutative=False)
  1090. One nc-symbol:
  1091. >>> _mask_nc(A**2 - x**2, 'd')
  1092. (_d0**2 - x**2, {_d0: A}, [])
  1093. Multiple nc-symbols:
  1094. >>> _mask_nc(A**2 - B**2, 'd')
  1095. (A**2 - B**2, {}, [A, B])
  1096. An nc-object with nc-symbols but no others outside of it:
  1097. >>> _mask_nc(1 + x*Commutator(A, B), 'd')
  1098. (_d0*x + 1, {_d0: Commutator(A, B)}, [])
  1099. >>> _mask_nc(NO(Fd(x)*F(y)), 'd')
  1100. (_d0, {_d0: NO(CreateFermion(x)*AnnihilateFermion(y))}, [])
  1101. Multiple nc-objects:
  1102. >>> eq = x*Commutator(A, B) + x*Commutator(A, C)*Commutator(A, B)
  1103. >>> _mask_nc(eq, 'd')
  1104. (x*_d0 + x*_d1*_d0, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1])
  1105. Multiple nc-objects and nc-symbols:
  1106. >>> eq = A*Commutator(A, B) + B*Commutator(A, C)
  1107. >>> _mask_nc(eq, 'd')
  1108. (A*_d0 + B*_d1, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1, A, B])
  1109. """
  1110. name = name or 'mask'
  1111. # Make Dummy() append sequential numbers to the name
  1112. def numbered_names():
  1113. i = 0
  1114. while True:
  1115. yield name + str(i)
  1116. i += 1
  1117. names = numbered_names()
  1118. def Dummy(*args, **kwargs):
  1119. from .symbol import Dummy
  1120. return Dummy(next(names), *args, **kwargs)
  1121. expr = eq
  1122. if expr.is_commutative:
  1123. return eq, {}, []
  1124. # identify nc-objects; symbols and other
  1125. rep = []
  1126. nc_obj = set()
  1127. nc_syms = set()
  1128. pot = preorder_traversal(expr, keys=default_sort_key)
  1129. for i, a in enumerate(pot):
  1130. if any(a == r[0] for r in rep):
  1131. pot.skip()
  1132. elif not a.is_commutative:
  1133. if a.is_symbol:
  1134. nc_syms.add(a)
  1135. pot.skip()
  1136. elif not (a.is_Add or a.is_Mul or a.is_Pow):
  1137. nc_obj.add(a)
  1138. pot.skip()
  1139. # If there is only one nc symbol or object, it can be factored regularly
  1140. # but polys is going to complain, so replace it with a Dummy.
  1141. if len(nc_obj) == 1 and not nc_syms:
  1142. rep.append((nc_obj.pop(), Dummy()))
  1143. elif len(nc_syms) == 1 and not nc_obj:
  1144. rep.append((nc_syms.pop(), Dummy()))
  1145. # Any remaining nc-objects will be replaced with an nc-Dummy and
  1146. # identified as an nc-Symbol to watch out for
  1147. nc_obj = sorted(nc_obj, key=default_sort_key)
  1148. for n in nc_obj:
  1149. nc = Dummy(commutative=False)
  1150. rep.append((n, nc))
  1151. nc_syms.add(nc)
  1152. expr = expr.subs(rep)
  1153. nc_syms = list(nc_syms)
  1154. nc_syms.sort(key=default_sort_key)
  1155. return expr, {v: k for k, v in rep}, nc_syms
  1156. def factor_nc(expr):
  1157. """Return the factored form of ``expr`` while handling non-commutative
  1158. expressions.
  1159. Examples
  1160. ========
  1161. >>> from sympy import factor_nc, Symbol
  1162. >>> from sympy.abc import x
  1163. >>> A = Symbol('A', commutative=False)
  1164. >>> B = Symbol('B', commutative=False)
  1165. >>> factor_nc((x**2 + 2*A*x + A**2).expand())
  1166. (x + A)**2
  1167. >>> factor_nc(((x + A)*(x + B)).expand())
  1168. (x + A)*(x + B)
  1169. """
  1170. expr = sympify(expr)
  1171. if not isinstance(expr, Expr) or not expr.args:
  1172. return expr
  1173. if not expr.is_Add:
  1174. return expr.func(*[factor_nc(a) for a in expr.args])
  1175. from sympy.polys.polytools import gcd, factor
  1176. expr, rep, nc_symbols = _mask_nc(expr)
  1177. if rep:
  1178. return factor(expr).subs(rep)
  1179. else:
  1180. args = [a.args_cnc() for a in Add.make_args(expr)]
  1181. c = g = l = r = S.One
  1182. hit = False
  1183. # find any commutative gcd term
  1184. for i, a in enumerate(args):
  1185. if i == 0:
  1186. c = Mul._from_args(a[0])
  1187. elif a[0]:
  1188. c = gcd(c, Mul._from_args(a[0]))
  1189. else:
  1190. c = S.One
  1191. if c is not S.One:
  1192. hit = True
  1193. c, g = c.as_coeff_Mul()
  1194. if g is not S.One:
  1195. for i, (cc, _) in enumerate(args):
  1196. cc = list(Mul.make_args(Mul._from_args(list(cc))/g))
  1197. args[i][0] = cc
  1198. for i, (cc, _) in enumerate(args):
  1199. cc[0] = cc[0]/c
  1200. args[i][0] = cc
  1201. # find any noncommutative common prefix
  1202. for i, a in enumerate(args):
  1203. if i == 0:
  1204. n = a[1][:]
  1205. else:
  1206. n = common_prefix(n, a[1])
  1207. if not n:
  1208. # is there a power that can be extracted?
  1209. if not args[0][1]:
  1210. break
  1211. b, e = args[0][1][0].as_base_exp()
  1212. ok = False
  1213. if e.is_Integer:
  1214. for t in args:
  1215. if not t[1]:
  1216. break
  1217. bt, et = t[1][0].as_base_exp()
  1218. if et.is_Integer and bt == b:
  1219. e = min(e, et)
  1220. else:
  1221. break
  1222. else:
  1223. ok = hit = True
  1224. l = b**e
  1225. il = b**-e
  1226. for _ in args:
  1227. _[1][0] = il*_[1][0]
  1228. break
  1229. if not ok:
  1230. break
  1231. else:
  1232. hit = True
  1233. lenn = len(n)
  1234. l = Mul(*n)
  1235. for _ in args:
  1236. _[1] = _[1][lenn:]
  1237. # find any noncommutative common suffix
  1238. for i, a in enumerate(args):
  1239. if i == 0:
  1240. n = a[1][:]
  1241. else:
  1242. n = common_suffix(n, a[1])
  1243. if not n:
  1244. # is there a power that can be extracted?
  1245. if not args[0][1]:
  1246. break
  1247. b, e = args[0][1][-1].as_base_exp()
  1248. ok = False
  1249. if e.is_Integer:
  1250. for t in args:
  1251. if not t[1]:
  1252. break
  1253. bt, et = t[1][-1].as_base_exp()
  1254. if et.is_Integer and bt == b:
  1255. e = min(e, et)
  1256. else:
  1257. break
  1258. else:
  1259. ok = hit = True
  1260. r = b**e
  1261. il = b**-e
  1262. for _ in args:
  1263. _[1][-1] = _[1][-1]*il
  1264. break
  1265. if not ok:
  1266. break
  1267. else:
  1268. hit = True
  1269. lenn = len(n)
  1270. r = Mul(*n)
  1271. for _ in args:
  1272. _[1] = _[1][:len(_[1]) - lenn]
  1273. if hit:
  1274. mid = Add(*[Mul(*cc)*Mul(*nc) for cc, nc in args])
  1275. else:
  1276. mid = expr
  1277. from sympy.simplify.powsimp import powsimp
  1278. # sort the symbols so the Dummys would appear in the same
  1279. # order as the original symbols, otherwise you may introduce
  1280. # a factor of -1, e.g. A**2 - B**2) -- {A:y, B:x} --> y**2 - x**2
  1281. # and the former factors into two terms, (A - B)*(A + B) while the
  1282. # latter factors into 3 terms, (-1)*(x - y)*(x + y)
  1283. rep1 = [(n, Dummy()) for n in sorted(nc_symbols, key=default_sort_key)]
  1284. unrep1 = [(v, k) for k, v in rep1]
  1285. unrep1.reverse()
  1286. new_mid, r2, _ = _mask_nc(mid.subs(rep1))
  1287. new_mid = powsimp(factor(new_mid))
  1288. new_mid = new_mid.subs(r2).subs(unrep1)
  1289. if new_mid.is_Pow:
  1290. return _keep_coeff(c, g*l*new_mid*r)
  1291. if new_mid.is_Mul:
  1292. def _pemexpand(expr):
  1293. "Expand with the minimal set of hints necessary to check the result."
  1294. return expr.expand(deep=True, mul=True, power_exp=True,
  1295. power_base=False, basic=False, multinomial=True, log=False)
  1296. # XXX TODO there should be a way to inspect what order the terms
  1297. # must be in and just select the plausible ordering without
  1298. # checking permutations
  1299. cfac = []
  1300. ncfac = []
  1301. for f in new_mid.args:
  1302. if f.is_commutative:
  1303. cfac.append(f)
  1304. else:
  1305. b, e = f.as_base_exp()
  1306. if e.is_Integer:
  1307. ncfac.extend([b]*e)
  1308. else:
  1309. ncfac.append(f)
  1310. pre_mid = g*Mul(*cfac)*l
  1311. target = _pemexpand(expr/c)
  1312. for s in variations(ncfac, len(ncfac)):
  1313. ok = pre_mid*Mul(*s)*r
  1314. if _pemexpand(ok) == target:
  1315. return _keep_coeff(c, ok)
  1316. # mid was an Add that didn't factor successfully
  1317. return _keep_coeff(c, g*l*mid*r)