1 | initial version |

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
```

2 | No.2 Revision |

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
```

3 | No.3 Revision |

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.

4 | No.4 Revision |

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).

`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.

5 | No.5 Revision |

When Sage doesn't want to simplify my expressions, I do it myself.

`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.

6 | No.6 Revision |

When Sage doesn't want to simplify my expressions, I do it myself.

`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.

Copyright Sage, 2010. Some rights reserved under creative commons license. Content on this site is licensed under a Creative Commons Attribution Share Alike 3.0 license.