# Revision history [back]

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 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))}
final_steps = ['log_simplify']

def apply_rules():
nonlocal E
for r in rules:
for e in E.find(r):
f = e.match(r)
E = E.substitute({e: rules[r](f)})
return E

while(E!=apply_rules()):
pass

for step in final_steps:
E = getattr(E, step)()

return E


It works as expected:

sage: custom_simplify((a1*b)^c/(a2*b)^c)
(a1/a2)^c


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))}
final_steps = ['log_simplify']

def apply_rules():
nonlocal E
for r in rules:
for e in E.find(r):
f = e.match(r)
E = E.substitute({e: rules[r](f)})
return E

while(E!=apply_rules()):
pass

for step in final_steps:
E = getattr(E, step)()

return E


It works as expected:

sage: custom_simplify((a1*b)^c/(a2*b)^c)
(a1/a2)^c


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))}
final_steps = ['log_simplify']

def apply_rules():
nonlocal E
for r in rules:
for e in E.find(r):
f = e.match(r)
E = E.substitute({e: rules[r](f)})
return E

while(E!=apply_rules()):
pass

for step in final_steps:
E = getattr(E, step)()

return E


It works as expected:

sage: custom_simplify((a1*b)^c/(a2*b)^c)
(a1/a2)^c


Edit: It's extremely overkill here, since canonicalize_radical does the work fine.

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"""
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))}
((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)})
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: It's extremely overkill here, since canonicalize_radical does the work fine.

Modified for use with assumptions for correctness, as suggested by Emmanuel Charpentier. The rules now contain a tuple, the second element being a condition that must hold for the substitution to be valid.

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 contain a tuple, the second element being a condition that must hold for the substitution to be valid.

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 contain returns a tuple, the second element being a condition that must hold for the substitution to be valid.