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 ab→ebloga, defined on the third line (holding the result, otherwise it immediatly goes back to ab). 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!