def powdenest(eq, force=False, polar=False): r""" Collect exponents on powers as assumptions allow. 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: eq, rep = posify(eq) return powdenest(eq, force=False).xreplace(rep) 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)))
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)))