When Sage doesn't want to simplify my expressions, I do it myself.
I wrote a function to do that some time ago, and I just need to change the rules (I already used the same function to solve this other question).
Here I use the rule $a^b\to e^{b \log a}$, defined on the third line (holding the result, otherwise it immediatly goes back to $a^b$). The function will try to apply this rule everywhere, then finish with one step of log_simplify
.
def custom_simplify(E):
"""Apply some rules on expression E as long as it changes, then apply some final steps."""
w = [SR.wild(i) for i in (0, .., 10)]
rules = {w[0]^w[1]: lambda f: ((exp(f[w[1]]*log(f[w[0]]), hold=True)), f[w[0]]>0),}
final_steps = ['log_simplify']
def apply_rules():
nonlocal E
for r in rules:
for e in E.find(r):
f = e.match(r)
if rules[r](f)[1]:
E = E.substitute({e: rules[r](f)[0]})
return E
while(E!=apply_rules()):
pass
for step in final_steps:
E = getattr(E, step)()
return E
It works as expected:
sage: assume(a1>0, a2>0, b>0)
sage: custom_simplify((a1*b)^c/(a2*b)^c)
(a1/a2)^c
Edit: Modified for use with assumptions for correctness, as suggested by Emmanuel Charpentier. The rules now returns a tuple, the second element being a condition that must hold for the substitution to be valid.
There may be a simplification in Sage Maths, but it doesn't look easy to find anyway. In any case, me too I was not able to found it!