Extending algebraic degrees in python (sympy)

I'm just wondering if there is an existing method for extending algebraic degrees, such as x**2 , to their multiplicative forms (i.e. x**2 -> x*x ) in the python Sympy module?

Thanks!

+6
source share
5 answers

There is no direct support for this. SymPy automatically combines common terms with exponentiation. The only way to do this is not to use the evaluate=False mechanism. for instance

 >>> Mul(x, x, evaluate=False) x*x 

This exact issue has recently been discussed on the SymPy mailing list (https://groups.google.com/d/topic/sympy/qaJGesRbX_0/discussion). I posted some code there that will do this. I will repeat it here:

 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,evaluate=False) for b,e in (i.as_base_exp() for i in pows))) return expr.subs(repl) 

Here how it works

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

I’ll put the same disclaimer here as on the mailing list: “Evaluate = False is a bit of a hack, so keep in mind that it is fragile. Some functions will overestimate the expression, converting it back to Pow. Will break, because the expected the invariant will be broken down into expression = False (for example, I doubt that factor () will work correctly).

+5
source

It seems that there is no such thing, she does only the opposite.

sympy always shows the result in the easiest way, so it will always say:

 (x**2).expand() -> x**2 simplify(x**2) -> x**2 
+1
source

The replacement method is well suited for this task for simple expressions:

 >>> expr = (x**2 + 1)/(x**3 - 2*x) >>> expr.replace( ... lambda x: x.is_Pow and x.exp > 0, ... lambda x: Mul(*[x.base]*x.exp, evaluate=False)) (x*x + 1)/(-2*x + x*x*x) 

To handle things like 1/x**3 or x**2*(1 + x**2) , you will need to configure. But if you expand the numerator and denominator of the expressions and process them separately, this can do what you need. And if the bases are always symbols, then this hacker symbol can do the trick even better:

 >>> def sack(expr): ... return expr.replace( ... lambda x: x.is_Pow and x.exp > 0, ... lambda x: Symbol('*'.join([x.base.name]*x.exp))) ... >>> sack(-x**2) -x*x >>> sack(x**2*(1 + x**3) x*x*(x*x*x + 1) 
+1
source

Following Aaron's answer and my comment, this is the xreplace version that I use instead of the final subs line to avoid evaluating subexpressions (and thus lose the extension of power to the multiplication chain).

 def non_eval_xreplace(expr, rule): """ Duplicate of sympy xreplace but with non-evaluate statement included """ if expr in rule: return rule[expr] elif rule: args = [] altered = False for a in expr.args: try: new_a = non_eval_xreplace(a, rule) except AttributeError: new_a = a if new_a != a: altered = True args.append(new_a) args = tuple(args) if altered: return expr.func(*args, evaluate=False) return expr 

I thought this functionality could be added to the existing xreplace in the SymPy library, allowing it to accept **kwargs that are passed to the expr.func call. Is this something that interests you, or will it be unnecessarily complicated for most users? (or did I misunderstand your comment above, and is there an easier way to do this?)

0
source

Other answers do not handle -x**2 , so I used regex instead to solve only for permissions 2. I understand this is a bit hacky, but it worked for me.

 from sympy.printing import ccode import re CPOW = re.compile(r'pow\((?P<var>[A-Za-z_]\w*)\s*,\s*2\s*\)') def to_c_code(expr): code = ccode(expr) # sympy has a hard time unsimplifying x**2 to x*x # replace all pow(var,2) with var*var code = re.sub(CPOW, r'\g<var>*\g<var>', code) return code 
0
source

All Articles