123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- from collections import defaultdict
- from functools import reduce
- from sympy.core.function import expand_log, count_ops, _coeff_isneg
- from sympy.core import sympify, Basic, Dummy, S, Add, Mul, Pow, expand_mul, factor_terms
- from sympy.core.sorting import ordered, default_sort_key
- from sympy.core.numbers import Integer, Rational
- from sympy.core.mul import prod, _keep_coeff
- from sympy.core.rules import Transform
- from sympy.functions import exp_polar, exp, log, root, polarify, unpolarify
- from sympy.polys import lcm, gcd
- from sympy.ntheory.factor_ import multiplicity
- def powsimp(expr, deep=False, combine='all', force=False, measure=count_ops):
- """
- reduces expression by combining powers with similar bases and exponents.
- Explanation
- ===========
- If ``deep`` is ``True`` then powsimp() will also simplify arguments of
- functions. By default ``deep`` is set to ``False``.
- If ``force`` is ``True`` then bases will be combined without checking for
- assumptions, e.g. sqrt(x)*sqrt(y) -> sqrt(x*y) which is not true
- if x and y are both negative.
- You can make powsimp() only combine bases or only combine exponents by
- changing combine='base' or combine='exp'. By default, combine='all',
- which does both. combine='base' will only combine::
- a a a 2x x
- x * y => (x*y) as well as things like 2 => 4
- and combine='exp' will only combine
- ::
- a b (a + b)
- x * x => x
- combine='exp' will strictly only combine exponents in the way that used
- to be automatic. Also use deep=True if you need the old behavior.
- When combine='all', 'exp' is evaluated first. Consider the first
- example below for when there could be an ambiguity relating to this.
- This is done so things like the second example can be completely
- combined. If you want 'base' combined first, do something like
- powsimp(powsimp(expr, combine='base'), combine='exp').
- Examples
- ========
- >>> from sympy import powsimp, exp, log, symbols
- >>> from sympy.abc import x, y, z, n
- >>> powsimp(x**y*x**z*y**z, combine='all')
- x**(y + z)*y**z
- >>> powsimp(x**y*x**z*y**z, combine='exp')
- x**(y + z)*y**z
- >>> powsimp(x**y*x**z*y**z, combine='base', force=True)
- x**y*(x*y)**z
- >>> powsimp(x**z*x**y*n**z*n**y, combine='all', force=True)
- (n*x)**(y + z)
- >>> powsimp(x**z*x**y*n**z*n**y, combine='exp')
- n**(y + z)*x**(y + z)
- >>> powsimp(x**z*x**y*n**z*n**y, combine='base', force=True)
- (n*x)**y*(n*x)**z
- >>> x, y = symbols('x y', positive=True)
- >>> powsimp(log(exp(x)*exp(y)))
- log(exp(x)*exp(y))
- >>> powsimp(log(exp(x)*exp(y)), deep=True)
- x + y
- Radicals with Mul bases will be combined if combine='exp'
- >>> from sympy import sqrt
- >>> x, y = symbols('x y')
- Two radicals are automatically joined through Mul:
- >>> a=sqrt(x*sqrt(y))
- >>> a*a**3 == a**4
- True
- But if an integer power of that radical has been
- autoexpanded then Mul does not join the resulting factors:
- >>> a**4 # auto expands to a Mul, no longer a Pow
- x**2*y
- >>> _*a # so Mul doesn't combine them
- x**2*y*sqrt(x*sqrt(y))
- >>> powsimp(_) # but powsimp will
- (x*sqrt(y))**(5/2)
- >>> powsimp(x*y*a) # but won't when doing so would violate assumptions
- x*y*sqrt(x*sqrt(y))
- """
- from sympy.matrices.expressions.matexpr import MatrixSymbol
- def recurse(arg, **kwargs):
- _deep = kwargs.get('deep', deep)
- _combine = kwargs.get('combine', combine)
- _force = kwargs.get('force', force)
- _measure = kwargs.get('measure', measure)
- return powsimp(arg, _deep, _combine, _force, _measure)
- expr = sympify(expr)
- if (not isinstance(expr, Basic) or isinstance(expr, MatrixSymbol) or (
- expr.is_Atom or expr in (exp_polar(0), exp_polar(1)))):
- return expr
- if deep or expr.is_Add or expr.is_Mul and _y not in expr.args:
- expr = expr.func(*[recurse(w) for w in expr.args])
- if expr.is_Pow:
- return recurse(expr*_y, deep=False)/_y
- if not expr.is_Mul:
- return expr
- # handle the Mul
- if combine in ('exp', 'all'):
- # Collect base/exp data, while maintaining order in the
- # non-commutative parts of the product
- c_powers = defaultdict(list)
- nc_part = []
- newexpr = []
- coeff = S.One
- for term in expr.args:
- if term.is_Rational:
- coeff *= term
- continue
- if term.is_Pow:
- term = _denest_pow(term)
- if term.is_commutative:
- b, e = term.as_base_exp()
- if deep:
- b, e = [recurse(i) for i in [b, e]]
- if b.is_Pow or isinstance(b, exp):
- # don't let smthg like sqrt(x**a) split into x**a, 1/2
- # or else it will be joined as x**(a/2) later
- b, e = b**e, S.One
- c_powers[b].append(e)
- else:
- # This is the logic that combines exponents for equal,
- # but non-commutative bases: A**x*A**y == A**(x+y).
- if nc_part:
- b1, e1 = nc_part[-1].as_base_exp()
- b2, e2 = term.as_base_exp()
- if (b1 == b2 and
- e1.is_commutative and e2.is_commutative):
- nc_part[-1] = Pow(b1, Add(e1, e2))
- continue
- nc_part.append(term)
- # add up exponents of common bases
- for b, e in ordered(iter(c_powers.items())):
- # allow 2**x/4 -> 2**(x - 2); don't do this when b and e are
- # Numbers since autoevaluation will undo it, e.g.
- # 2**(1/3)/4 -> 2**(1/3 - 2) -> 2**(1/3)/4
- if (b and b.is_Rational and not all(ei.is_Number for ei in e) and \
- coeff is not S.One and
- b not in (S.One, S.NegativeOne)):
- m = multiplicity(abs(b), abs(coeff))
- if m:
- e.append(m)
- coeff /= b**m
- c_powers[b] = Add(*e)
- if coeff is not S.One:
- if coeff in c_powers:
- c_powers[coeff] += S.One
- else:
- c_powers[coeff] = S.One
- # convert to plain dictionary
- c_powers = dict(c_powers)
- # check for base and inverted base pairs
- be = list(c_powers.items())
- skip = set() # skip if we already saw them
- for b, e in be:
- if b in skip:
- continue
- bpos = b.is_positive or b.is_polar
- if bpos:
- binv = 1/b
- if b != binv and binv in c_powers:
- if b.as_numer_denom()[0] is S.One:
- c_powers.pop(b)
- c_powers[binv] -= e
- else:
- skip.add(binv)
- e = c_powers.pop(binv)
- c_powers[b] -= e
- # check for base and negated base pairs
- be = list(c_powers.items())
- _n = S.NegativeOne
- for b, e in be:
- if (b.is_Symbol or b.is_Add) and -b in c_powers and b in c_powers:
- if (b.is_positive is not None or e.is_integer):
- if e.is_integer or b.is_negative:
- c_powers[-b] += c_powers.pop(b)
- else: # (-b).is_positive so use its e
- e = c_powers.pop(-b)
- c_powers[b] += e
- if _n in c_powers:
- c_powers[_n] += e
- else:
- c_powers[_n] = e
- # filter c_powers and convert to a list
- c_powers = [(b, e) for b, e in c_powers.items() if e]
- # ==============================================================
- # check for Mul bases of Rational powers that can be combined with
- # separated bases, e.g. x*sqrt(x*y)*sqrt(x*sqrt(x*y)) ->
- # (x*sqrt(x*y))**(3/2)
- # ---------------- helper functions
- def ratq(x):
- '''Return Rational part of x's exponent as it appears in the bkey.
- '''
- return bkey(x)[0][1]
- def bkey(b, e=None):
- '''Return (b**s, c.q), c.p where e -> c*s. If e is not given then
- it will be taken by using as_base_exp() on the input b.
- e.g.
- x**3/2 -> (x, 2), 3
- x**y -> (x**y, 1), 1
- x**(2*y/3) -> (x**y, 3), 2
- exp(x/2) -> (exp(a), 2), 1
- '''
- if e is not None: # coming from c_powers or from below
- if e.is_Integer:
- return (b, S.One), e
- elif e.is_Rational:
- return (b, Integer(e.q)), Integer(e.p)
- else:
- c, m = e.as_coeff_Mul(rational=True)
- if c is not S.One:
- if m.is_integer:
- return (b, Integer(c.q)), m*Integer(c.p)
- return (b**m, Integer(c.q)), Integer(c.p)
- else:
- return (b**e, S.One), S.One
- else:
- return bkey(*b.as_base_exp())
- def update(b):
- '''Decide what to do with base, b. If its exponent is now an
- integer multiple of the Rational denominator, then remove it
- and put the factors of its base in the common_b dictionary or
- update the existing bases if necessary. If it has been zeroed
- out, simply remove the base.
- '''
- newe, r = divmod(common_b[b], b[1])
- if not r:
- common_b.pop(b)
- if newe:
- for m in Mul.make_args(b[0]**newe):
- b, e = bkey(m)
- if b not in common_b:
- common_b[b] = 0
- common_b[b] += e
- if b[1] != 1:
- bases.append(b)
- # ---------------- end of helper functions
- # assemble a dictionary of the factors having a Rational power
- common_b = {}
- done = []
- bases = []
- for b, e in c_powers:
- b, e = bkey(b, e)
- if b in common_b:
- common_b[b] = common_b[b] + e
- else:
- common_b[b] = e
- if b[1] != 1 and b[0].is_Mul:
- bases.append(b)
- bases.sort(key=default_sort_key) # this makes tie-breaking canonical
- bases.sort(key=measure, reverse=True) # handle longest first
- for base in bases:
- if base not in common_b: # it may have been removed already
- continue
- b, exponent = base
- last = False # True when no factor of base is a radical
- qlcm = 1 # the lcm of the radical denominators
- while True:
- bstart = b
- qstart = qlcm
- bb = [] # list of factors
- ee = [] # (factor's expo. and it's current value in common_b)
- for bi in Mul.make_args(b):
- bib, bie = bkey(bi)
- if bib not in common_b or common_b[bib] < bie:
- ee = bb = [] # failed
- break
- ee.append([bie, common_b[bib]])
- bb.append(bib)
- if ee:
- # find the number of integral extractions possible
- # e.g. [(1, 2), (2, 2)] -> min(2/1, 2/2) -> 1
- min1 = ee[0][1]//ee[0][0]
- for i in range(1, len(ee)):
- rat = ee[i][1]//ee[i][0]
- if rat < 1:
- break
- min1 = min(min1, rat)
- else:
- # update base factor counts
- # e.g. if ee = [(2, 5), (3, 6)] then min1 = 2
- # and the new base counts will be 5-2*2 and 6-2*3
- for i in range(len(bb)):
- common_b[bb[i]] -= min1*ee[i][0]
- update(bb[i])
- # update the count of the base
- # e.g. x**2*y*sqrt(x*sqrt(y)) the count of x*sqrt(y)
- # will increase by 4 to give bkey (x*sqrt(y), 2, 5)
- common_b[base] += min1*qstart*exponent
- if (last # no more radicals in base
- or len(common_b) == 1 # nothing left to join with
- or all(k[1] == 1 for k in common_b) # no rad's in common_b
- ):
- break
- # see what we can exponentiate base by to remove any radicals
- # so we know what to search for
- # e.g. if base were x**(1/2)*y**(1/3) then we should
- # exponentiate by 6 and look for powers of x and y in the ratio
- # of 2 to 3
- qlcm = lcm([ratq(bi) for bi in Mul.make_args(bstart)])
- if qlcm == 1:
- break # we are done
- b = bstart**qlcm
- qlcm *= qstart
- if all(ratq(bi) == 1 for bi in Mul.make_args(b)):
- last = True # we are going to be done after this next pass
- # this base no longer can find anything to join with and
- # since it was longer than any other we are done with it
- b, q = base
- done.append((b, common_b.pop(base)*Rational(1, q)))
- # update c_powers and get ready to continue with powsimp
- c_powers = done
- # there may be terms still in common_b that were bases that were
- # identified as needing processing, so remove those, too
- for (b, q), e in common_b.items():
- if (b.is_Pow or isinstance(b, exp)) and \
- q is not S.One and not b.exp.is_Rational:
- b, be = b.as_base_exp()
- b = b**(be/q)
- else:
- b = root(b, q)
- c_powers.append((b, e))
- check = len(c_powers)
- c_powers = dict(c_powers)
- assert len(c_powers) == check # there should have been no duplicates
- # ==============================================================
- # rebuild the expression
- newexpr = expr.func(*(newexpr + [Pow(b, e) for b, e in c_powers.items()]))
- if combine == 'exp':
- return expr.func(newexpr, expr.func(*nc_part))
- else:
- return recurse(expr.func(*nc_part), combine='base') * \
- recurse(newexpr, combine='base')
- elif combine == 'base':
- # Build c_powers and nc_part. These must both be lists not
- # dicts because exp's are not combined.
- c_powers = []
- nc_part = []
- for term in expr.args:
- if term.is_commutative:
- c_powers.append(list(term.as_base_exp()))
- else:
- nc_part.append(term)
- # Pull out numerical coefficients from exponent if assumptions allow
- # e.g., 2**(2*x) => 4**x
- for i in range(len(c_powers)):
- b, e = c_powers[i]
- if not (all(x.is_nonnegative for x in b.as_numer_denom()) or e.is_integer or force or b.is_polar):
- continue
- exp_c, exp_t = e.as_coeff_Mul(rational=True)
- if exp_c is not S.One and exp_t is not S.One:
- c_powers[i] = [Pow(b, exp_c), exp_t]
- # Combine bases whenever they have the same exponent and
- # assumptions allow
- # first gather the potential bases under the common exponent
- c_exp = defaultdict(list)
- for b, e in c_powers:
- if deep:
- e = recurse(e)
- if e.is_Add and (b.is_positive or e.is_integer):
- e = factor_terms(e)
- if _coeff_isneg(e):
- e = -e
- b = 1/b
- c_exp[e].append(b)
- del c_powers
- # Merge back in the results of the above to form a new product
- c_powers = defaultdict(list)
- for e in c_exp:
- bases = c_exp[e]
- # calculate the new base for e
- if len(bases) == 1:
- new_base = bases[0]
- elif e.is_integer or force:
- new_base = expr.func(*bases)
- else:
- # see which ones can be joined
- unk = []
- nonneg = []
- neg = []
- for bi in bases:
- if bi.is_negative:
- neg.append(bi)
- elif bi.is_nonnegative:
- nonneg.append(bi)
- elif bi.is_polar:
- nonneg.append(
- bi) # polar can be treated like non-negative
- else:
- unk.append(bi)
- if len(unk) == 1 and not neg or len(neg) == 1 and not unk:
- # a single neg or a single unk can join the rest
- nonneg.extend(unk + neg)
- unk = neg = []
- elif neg:
- # their negative signs cancel in groups of 2*q if we know
- # that e = p/q else we have to treat them as unknown
- israt = False
- if e.is_Rational:
- israt = True
- else:
- p, d = e.as_numer_denom()
- if p.is_integer and d.is_integer:
- israt = True
- if israt:
- neg = [-w for w in neg]
- unk.extend([S.NegativeOne]*len(neg))
- else:
- unk.extend(neg)
- neg = []
- del israt
- # these shouldn't be joined
- for b in unk:
- c_powers[b].append(e)
- # here is a new joined base
- new_base = expr.func(*(nonneg + neg))
- # if there are positive parts they will just get separated
- # again unless some change is made
- def _terms(e):
- # return the number of terms of this expression
- # when multiplied out -- assuming no joining of terms
- if e.is_Add:
- return sum([_terms(ai) for ai in e.args])
- if e.is_Mul:
- return prod([_terms(mi) for mi in e.args])
- return 1
- xnew_base = expand_mul(new_base, deep=False)
- if len(Add.make_args(xnew_base)) < _terms(new_base):
- new_base = factor_terms(xnew_base)
- c_powers[new_base].append(e)
- # break out the powers from c_powers now
- c_part = [Pow(b, ei) for b, e in c_powers.items() for ei in e]
- # we're done
- return expr.func(*(c_part + nc_part))
- else:
- raise ValueError("combine must be one of ('all', 'exp', 'base').")
- def powdenest(eq, force=False, polar=False):
- r"""
- Collect exponents on powers as assumptions allow.
- Explanation
- ===========
- Given ``(bb**be)**e``, this can be simplified as follows:
- * if ``bb`` is positive, or
- * ``e`` is an integer, or
- * ``|be| < 1`` then this simplifies to ``bb**(be*e)``
- Given a product of powers raised to a power, ``(bb1**be1 *
- bb2**be2...)**e``, simplification can be done as follows:
- - if e is positive, the gcd of all bei can be joined with e;
- - all non-negative bb can be separated from those that are negative
- and their gcd can be joined with e; autosimplification already
- handles this separation.
- - integer factors from powers that have integers in the denominator
- of the exponent can be removed from any term and the gcd of such
- integers can be joined with e
- Setting ``force`` to ``True`` will make symbols that are not explicitly
- negative behave as though they are positive, resulting in more
- denesting.
- Setting ``polar`` to ``True`` will do simplifications on the Riemann surface of
- the logarithm, also resulting in more denestings.
- When there are sums of logs in exp() then a product of powers may be
- obtained e.g. ``exp(3*(log(a) + 2*log(b)))`` - > ``a**3*b**6``.
- Examples
- ========
- >>> from sympy.abc import a, b, x, y, z
- >>> from sympy import Symbol, exp, log, sqrt, symbols, powdenest
- >>> powdenest((x**(2*a/3))**(3*x))
- (x**(2*a/3))**(3*x)
- >>> powdenest(exp(3*x*log(2)))
- 2**(3*x)
- Assumptions may prevent expansion:
- >>> powdenest(sqrt(x**2))
- sqrt(x**2)
- >>> p = symbols('p', positive=True)
- >>> powdenest(sqrt(p**2))
- p
- No other expansion is done.
- >>> i, j = symbols('i,j', integer=True)
- >>> powdenest((x**x)**(i + j)) # -X-> (x**x)**i*(x**x)**j
- x**(x*(i + j))
- But exp() will be denested by moving all non-log terms outside of
- the function; this may result in the collapsing of the exp to a power
- with a different base:
- >>> powdenest(exp(3*y*log(x)))
- x**(3*y)
- >>> powdenest(exp(y*(log(a) + log(b))))
- (a*b)**y
- >>> powdenest(exp(3*(log(a) + log(b))))
- a**3*b**3
- If assumptions allow, symbols can also be moved to the outermost exponent:
- >>> i = Symbol('i', integer=True)
- >>> powdenest(((x**(2*i))**(3*y))**x)
- ((x**(2*i))**(3*y))**x
- >>> powdenest(((x**(2*i))**(3*y))**x, force=True)
- x**(6*i*x*y)
- >>> powdenest(((x**(2*a/3))**(3*y/i))**x)
- ((x**(2*a/3))**(3*y/i))**x
- >>> powdenest((x**(2*i)*y**(4*i))**z, force=True)
- (x*y**2)**(2*i*z)
- >>> n = Symbol('n', negative=True)
- >>> powdenest((x**i)**y, force=True)
- x**(i*y)
- >>> powdenest((n**i)**x, force=True)
- (n**i)**x
- """
- from sympy.simplify.simplify import posify
- if force:
- def _denest(b, e):
- if not isinstance(b, (Pow, exp)):
- return b.is_positive, Pow(b, e, evaluate=False)
- return _denest(b.base, b.exp*e)
- reps = []
- for p in eq.atoms(Pow, exp):
- if isinstance(p.base, (Pow, exp)):
- ok, dp = _denest(*p.args)
- if ok is not False:
- reps.append((p, dp))
- if reps:
- eq = eq.subs(reps)
- eq, reps = posify(eq)
- return powdenest(eq, force=False, polar=polar).xreplace(reps)
- if polar:
- eq, rep = polarify(eq)
- return unpolarify(powdenest(unpolarify(eq, exponents_only=True)), rep)
- new = powsimp(sympify(eq))
- return new.xreplace(Transform(
- _denest_pow, filter=lambda m: m.is_Pow or isinstance(m, exp)))
- _y = Dummy('y')
- def _denest_pow(eq):
- """
- Denest powers.
- This is a helper function for powdenest that performs the actual
- transformation.
- """
- from sympy.simplify.simplify import logcombine
- b, e = eq.as_base_exp()
- if b.is_Pow or isinstance(b, exp) and e != 1:
- new = b._eval_power(e)
- if new is not None:
- eq = new
- b, e = new.as_base_exp()
- # denest exp with log terms in exponent
- if b is S.Exp1 and e.is_Mul:
- logs = []
- other = []
- for ei in e.args:
- if any(isinstance(ai, log) for ai in Add.make_args(ei)):
- logs.append(ei)
- else:
- other.append(ei)
- logs = logcombine(Mul(*logs))
- return Pow(exp(logs), Mul(*other))
- _, be = b.as_base_exp()
- if be is S.One and not (b.is_Mul or
- b.is_Rational and b.q != 1 or
- b.is_positive):
- return eq
- # denest eq which is either pos**e or Pow**e or Mul**e or
- # Mul(b1**e1, b2**e2)
- # handle polar numbers specially
- polars, nonpolars = [], []
- for bb in Mul.make_args(b):
- if bb.is_polar:
- polars.append(bb.as_base_exp())
- else:
- nonpolars.append(bb)
- if len(polars) == 1 and not polars[0][0].is_Mul:
- return Pow(polars[0][0], polars[0][1]*e)*powdenest(Mul(*nonpolars)**e)
- elif polars:
- return Mul(*[powdenest(bb**(ee*e)) for (bb, ee) in polars]) \
- *powdenest(Mul(*nonpolars)**e)
- if b.is_Integer:
- # use log to see if there is a power here
- logb = expand_log(log(b))
- if logb.is_Mul:
- c, logb = logb.args
- e *= c
- base = logb.args[0]
- return Pow(base, e)
- # if b is not a Mul or any factor is an atom then there is nothing to do
- if not b.is_Mul or any(s.is_Atom for s in Mul.make_args(b)):
- return eq
- # let log handle the case of the base of the argument being a Mul, e.g.
- # sqrt(x**(2*i)*y**(6*i)) -> x**i*y**(3**i) if x and y are positive; we
- # will take the log, expand it, and then factor out the common powers that
- # now appear as coefficient. We do this manually since terms_gcd pulls out
- # fractions, terms_gcd(x+x*y/2) -> x*(y + 2)/2 and we don't want the 1/2;
- # gcd won't pull out numerators from a fraction: gcd(3*x, 9*x/2) -> x but
- # we want 3*x. Neither work with noncommutatives.
- def nc_gcd(aa, bb):
- a, b = [i.as_coeff_Mul() for i in [aa, bb]]
- c = gcd(a[0], b[0]).as_numer_denom()[0]
- g = Mul(*(a[1].args_cnc(cset=True)[0] & b[1].args_cnc(cset=True)[0]))
- return _keep_coeff(c, g)
- glogb = expand_log(log(b))
- if glogb.is_Add:
- args = glogb.args
- g = reduce(nc_gcd, args)
- if g != 1:
- cg, rg = g.as_coeff_Mul()
- glogb = _keep_coeff(cg, rg*Add(*[a/g for a in args]))
- # now put the log back together again
- if isinstance(glogb, log) or not glogb.is_Mul:
- if glogb.args[0].is_Pow or isinstance(glogb.args[0], exp):
- glogb = _denest_pow(glogb.args[0])
- if (abs(glogb.exp) < 1) == True:
- return Pow(glogb.base, glogb.exp*e)
- return eq
- # the log(b) was a Mul so join any adds with logcombine
- add = []
- other = []
- for a in glogb.args:
- if a.is_Add:
- add.append(a)
- else:
- other.append(a)
- return Pow(exp(logcombine(Mul(*add))), e*Mul(*other))
|