Ask Your Question

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.