How do I match a pattern and change all occurrences of a subexpression in an expression?

Using sympy, I need to replace all occurrences exp(C+anything)

with C*exp(anything)

. Since it exp(C)

is a constant, I only write how C

.

I can do this for one occurrence exp

in an expression. But don't do this if there is one instance.

For example, for one instance as in x+exp(C_0+3*x)+3*y

I need to change it tox+C_0*exp(3*x)+3*y

In one case it seems to work after some trial and error

from sympy import *
x,y,C_0 = symbols('x y C_0')
expr=x+exp(C_0+3*x)+3*y
#first check if exp is in the expression
if  any([isinstance(a, exp) for a in preorder_traversal(expr)]):
    p_1=Wild('p1');p_2=Wild('p_2');p_3=Wild('p_3')
    r=(p_1+exp(C_0+p_2)+p_3).matches(expr)
    expr.subs(exp(C_0+r[p_2]),C_0*exp(r[p_2]))

      

What gives

C_0*exp(3*x) + x + 3*y

      

But what about something of the type x+exp(C_0+3*x)+3*y+exp(C_0+30*x+y)

I need to change to x+C_0*exp(3*x)+3*y+C_0*exp(30*x+y)

, I cannot do custom pattern matching for every possible case. I need a way to change all occurrences

In Mathematica, I do the following:

expr = x + Exp[c + 3*x]*3*y + 3*y + Exp[c + 30*x + y]
expr /. Exp[c + any_] :> (c Exp[any])

      

What gives

Mathematica graphics

I really prefer to tell Python to just change exp(C+anything)

to C*exp(anything)

without specifying a pattern for the generic expression, as that can change a lot.

I'm sure this is also possible in python / sympy. Any hints how to do this?

+3


source to share


1 answer


I would look for a function exp

inside an expression, check if its an argument Add

and then if it is C_0

among the arguments Add

. Then create a thing to replace exp

with. Consider the following:

from sympy import *
x, y, C_0 = symbols('x y C_0')
expr = x + exp(C_0+3*x) + 3*y + exp(y+C_0+30*x) - exp(x+y-C_0) + exp(x*y)

exp_sum = [(a, a.args[0].args) for a in preorder_traversal(expr) if a.func == exp and a.args[0].func == Add]
exp_sum = [p for p in exp_sum if C_0 in p[1]]

new_exp = [C_0*exp(Add(*[x for x in p[1] if x != C_0])) for p in exp_sum]

for (old, new) in zip(exp_sum, new_exp):
    expr = expr.subs(old[0], new)

      

Initially exp_sum

contains all parts of the form exp(Add(...))

. After that, it was filtered to the sums containing C_0

. New exponents are formed by taking all terms that are not C_0

, adding them, applying them, exp

and multiplying by C_0

. Then the replacement takes place.

To clarify this process, here's what's exp_sum

in the above example, a list of tuples (exponential and terms inside):

 [(exp(C_0 + 3*x), (C_0, 3*x)), (exp(C_0 + 30*x + y), (C_0, y, 30*x))]

      



And this new_exp

 [C_0*exp(3*x), C_0*exp(30*x + y)]

      

Finally, expr

at the end:

 C_0*exp(3*x) + C_0*exp(30*x + y) + x + 3*y + exp(x*y) - exp(-C_0 + x + y)

      

Note that changing (-C_0 ...) does not change; it is not part of the template.

+1


source







All Articles