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
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?
source to share
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.
source to share