Re: [sympy] Expand squared terms into multiplication

558 views
Skip to first unread message

Aaron Meurer

unread,
Jun 27, 2012, 9:41:04 PM6/27/12
to sy...@googlegroups.com
I don't think there's a built-in function to do this, but it shouldn't be too hard to write your own, using .atoms to find the Pow's and .xreplace (or .subs if you are not using the development version) to replace them.  Note that SymPy automatically converts a*a to a**2, so to keep it as a*a, you have to use Mul(a, a, evaluate=False).  

evaluate=False is somewhat of a hack, so be aware that it is fragile.  Some functions will reevaluate the expression, converting it back to Pow.  Other functions will break because some expected invariant will be broken by the evaluate=False expression (e.g., I doubt factor() would work correctly).  So I would not do this until the very end, before you send it to SQL.

Something like this should work:

def pow_to_mul(expr):
    """
    Convert integer powers in an expression to Muls, like a**2 => a*a.
    """
    pows = list(expr.atoms(Pow))
    if any(not e.is_Integer for b, e in i.as_base_exp() for i in pows):
        raise ValueError("A power contains a non-integer exponent")
    repl = zip(pows, (Mul(*([b]*e for b, e in i.as_base_exp()), evaluate=False) for i in pows)
    return expr.subs(repl)
    # Or, in the development version, a better way is
    # return expr.xreplace(dict(repl))

Disclaimer: I typed the above function on my iPad without even checking if the syntax was correct.  It should work, though, assuming I remembered all my interfaces correctly and didn't forget something.

Aaron Meurer

On Jun 27, 2012, at 7:09 PM, Spencer Ogden <spence...@gmail.com> wrote:

I'm trying to use sympy to expand matrix math into valid SQL code. SQL doesn't support ** of course, so I would like to expand terms like a**2 to a*a. In the general context of a CAS, this is a silly thing to do, so I haven't been able to locate a function that would do this (expand, replace, rewrite).

Is this possible?

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sympy/-/mTnzsoyEj1UJ.
To post to this group, send email to sy...@googlegroups.com.
To unsubscribe from this group, send email to sympy+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sympy?hl=en.

Spencer Ogden

unread,
Jun 28, 2012, 10:53:57 AM6/28/12
to sy...@googlegroups.com
Aaron,

Thanks for your lead on evaluate=False and the example function. Very close for iPad typing and no error checking. I switched around the list comprehensions a bit and got it working this way:

from sympy import Symbol, Mul, Pow, pprint, Matrix, symbols

a = Symbol('a')
exp = a**2
print(exp)


def pow_to_mul(expr):
    """
    Convert integer powers in an expression to Muls, like a**2 => a*a.
    """
    pows = list(expr.atoms(Pow))
    if any(not e.is_Integer for b, e in (i.as_base_exp() for i in pows)):

        raise ValueError("A power contains a non-integer exponent")
    #repl = zip(pows, (Mul(*list([b]*e for b, e in i.as_base_exp()), evaluate=False) for i in pows))
    repl = zip(pows, (Mul(*[b]*e,evaluate=False) for b,e in (i.as_base_exp() for i in pows)))
    return expr.subs(repl)

print(pow_to_mul(exp))

This outputs:
a**2
a*a

Thanks again, just what I needed,

Spencer
To unsubscribe from this group, send email to sympy+unsubscribe@googlegroups.com.

Stewart Martin-Haugh

unread,
Oct 9, 2013, 10:27:19 AM10/9/13
to sy...@googlegroups.com
Hi,
This function is really useful, but I'm having problems with combinations of sqrt and pow: is there any way to keep the sqrts as they are, but expand integer pows?

Thanks,
Stewart
To unsubscribe from this group, send email to sympy+un...@googlegroups.com.

Aaron Meurer

unread,
Oct 10, 2013, 10:01:51 PM10/10/13
to sy...@googlegroups.com
I guess you just need to modify the "if any(...)" line. Currently it
raises ValueError, but I guess what you really want to do is skip
those powers with non-integer exponents.

I guess you also should check if the power is nonnegative, as
otherwise things like 1/x won't do the right thing.

Aaron Meurer
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sympy+un...@googlegroups.com.
>
> To post to this group, send email to sy...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sympy.
> For more options, visit https://groups.google.com/groups/opt_out.
Reply all
Reply to author
Forward
0 new messages