New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
replace(oldtype, newtype) does unexpected and superfluous constructor calls to oldtype #24460
Comments
If calling |
I guess you're referring to this: Lines 1606 to 1608 in 40b1af7
I think it's not necessarily superfluous. Applying replace to the args might mean that rv.func(*newargs) evaluates to something different affecting whether or not replace(newtype, oldtype) would succeed e.g.:
>>> exp(I*pi*exp(pi)).replace(exp, cos)
-1
>>> cos(I*pi*cos(pi))
cosh(π)
>>> exp(I*pi*cos(pi))
-1 |
I see your point: This is an "incremental" replace, i.e. doing replace from bottom up step by step, evaluating every intermediate expression (= at level of arguments), re-evaluate the expression and continue the replace in the result. Is there a replacement function in SymPy to get a usual "simultaneous replacement" that would give the result -1 in this example (I have tried xreplace and subst to no avail):
|
Maybe there should be an In [64]: with evaluate(False):
...: p3 = p2.replace(Pow, Add)
...:
In [65]: p3
Out[65]: -a + a + -a + a - 1
In [66]: p3.doit()
Out[66]: -1 |
That is really cool, and should be added to the documentation of (The "static" replacement option coded in replace directly would perhaps be slightly more efficient, but thats most probably not worth the effort and risk fiddling in core code.) |
This refers to bullet point 1.1, replacement of types, in documentation for sympy.core.basic.replace().
Situation
When replacing
oldtype
bynewtype
in an expressionexpr
,expr.replace(oldtype, newtype)
may call the constructor foroldtype
and create furtheroldtype
objects. Sinceoldtype
is to be replaced bynewtype
this objects will then immediately be replaced bynewtype
objects, so this calls are superfluous at least. Moreover they are unexpected and may have unwanted performance or other side effects.Example
Analysis
This behaviour occurs if
oldtype
is nested withinexpr
(as in the example above). In this case the statementrv = rv.func(*newargs)
in function walk() in sympy.core.basic.replace() invokes the oldtype constructor. Ifrv.func == oldtype
it should invokenewtype(*newargs)
instead.However as replace() has various usages that are all handled by this code I'm unable to verify this.
The text was updated successfully, but these errors were encountered: