-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Fixed solveset and added tests for already solved issues #21925
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
Conversation
✅ Hi, I am the SymPy bot (v161). I'm here to help you write a release notes entry. Please read the guide on how to write release notes. Your release notes are in good order. Here is what the release notes will look like: This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.10. Click here to see the pull request description that was parsed.
Update The release notes on the wiki have been updated. |
sympy/solvers/tests/test_solveset.py
Outdated
@@ -1724,6 +1731,130 @@ def test_solve_nonlinear_trans(): | |||
assert nonlinsolve([x**2 - y**2/exp(x)], [x, y]) == soln4 | |||
|
|||
|
|||
def test_issue_14642(): | |||
x = symbols('x',dtype = complex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does dtype=complex
do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea. The original code was like this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it is supposed to be complex=True
or something. It should be removed though because it doesn't do anything (ideally this would raise an error).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK! Will do!
b3549e1
to
2fe7df5
Compare
I've updated the tests and original comment so that the status is correct. |
Benchmark results from GitHub Actions Lower numbers are good, higher numbers are bad. A ratio less than 1 Significantly changed benchmark results (PR vs master) Significantly changed benchmark results (master vs previous release) Full benchmark results can be found as artifacts in GitHub Actions |
sympy/solvers/tests/test_solveset.py
Outdated
sol = Union(FiniteSet(Integer(0)), Intersection(S.Reals, FiniteSet(Pow(Add(Mul(Integer(-1), | ||
Pow(x, Integer(2))), zoo), Rational(1, 2)), Mul(Integer(-1), | ||
Pow(Add(Mul(Integer(-1), Pow(x, Integer(2))), zoo), Rational(1, 2)))))) | ||
|
||
# Should work, but will not. See #21943 | ||
assert solveset(expr, y, domain=S.Reals) == sol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think evaluate=False just needs to be used somewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Problem is that the args are flipped in zoo - x**2
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that the cause of the problem is evaluate=False being used somewhere...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to rewrite the expressions some time ago, but couldn't figure out where to put the evaluate=False
. May have another go, but indeed it would be better to only get one solution...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To recreate the output of solveset
we need evaluate=False
for the Add
in zoo - x**2
:
In [15]: sol = Union(FiniteSet(Integer(0)), Intersection(S.Reals, FiniteSet(Pow(Add(Mul(Integer(-1),
...: Pow(x, Integer(2))), zoo, evaluate=False), Rational(1, 2)), Mul(Integer(-1),
...: Pow(Add(Mul(Integer(-1), Pow(x, Integer(2))), zoo, evaluate=False), Rational(1, 2))))))
...:
...: expr = -2*y*exp(-x**2 - y**2)*Abs(x)
...:
...: print(solveset(expr, y, Reals) == sol)
True
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the 2-arg Mul:
In [6]: e = zoo - x**2
In [7]: e.args
Out[7]:
⎛ 2⎞
⎝zoo, -x ⎠
In [8]: e2 = -1 * e
In [9]: e2
Out[9]:
2
x + zoo
In [10]: e2.args
Out[10]:
⎛ 2 ⎞
⎝x , zoo⎠
In [11]: e2 == e2.func(*e2.args)
Out[11]: False
It can be fixed with
diff --git a/sympy/core/mul.py b/sympy/core/mul.py
index 9933eb601a..960b5baf25 100644
--- a/sympy/core/mul.py
+++ b/sympy/core/mul.py
@@ -281,7 +281,7 @@ def flatten(cls, seq):
ar = a*r
if ar:
bargs.insert(0, ar)
- bargs = [Add._from_args(bargs)]
+ bargs = [Add(*bargs)]
rv = bargs, [], None
if rv:
return rv
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe _unevaluated_Add(*args)
-- I read the issue but am not seeing enough context to understand the problem. Add._from_args
is much faster than Add
and since you are making this change in core it makes me nervous.
I added the Didn't want to change the core mul-code... |
I have fixed the Also fixed solving
where the first ConditionSet is identical to x being real. On the other hand,
|
sympy/solvers/solveset.py
Outdated
# Some inverse functions evaluate to zoo, remove if present | ||
fs = FiniteSet(S.ComplexInfinity) | ||
if fs.is_subset(g_ys): | ||
g_ys -= fs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this does fix things in a more general way. It removes zoo but loses the reason for removing zoo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the option is to check each and every inverse function that the input will not lead to zoo as you suggested. I cannot really see that keeps the reason better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that once the function class is identified it will in almost all cases call _invert_real
again with an evaluated version of the inverse function. So rather than checking for every evaluation if the input may yield zoo
, which is a bit of a hassle and cases will have to be added once identified, it seems more general to check if the input to (the next call of) _invert_real
is zoo
. The only possible way that this may not work is if there are some functions that map zoo
back to reals in a "controlled" way (not just inverting again). It doesn't seem to be any of those cases in the tests so far.
I added a test when I wrote this code to illustrate the point:
assert solveset(atan(x**2 - y**2)-pi/2, y, S.Reals) == EmptySet()
which currently returns Intersection({-sqrt(x**2 + zoo), sqrt(x**2 + zoo)}, Reals)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better if invert_real
only returned sets that are strictly contained in the domain of a function. There are other ways this can go wrong like if if the subset
test is indeterminate then a zoo case is not removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better if
invert_real
only returned sets that are strictly contained in the domain of a function
Since it has the domain
argument, I agree. I think I fixed a problem where the domain was integers but it wasn't return only integers. Those are troublesome bugs because you assume that the routine can be counted on to respect the domain and that you won't have worry about this in the the calling routine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree in general. The only other way I might think of is
g_ys = Intersection(g_ys, S.Reals)
which will also cover other cases (however, I believe that all the inverse functions return real-valued results for real-valued input, except for those that returns zoo, but I may be wrong). I'm a bit worried that this could explode in certain cases. (Intersection(ImageSet(..., Intersection(ImageSet(..., Intersection(...)), S.Reals), S.Reals)
) Also, I am not sure how computationally efficient this is, but can give it a try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will also be interesting see if that deals with: solveset(I*pi-log(x), x, S.Reals)
, which, if I guess correctly, will have an imaginary intermediate value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to fix this at the intersection-level in #22045.
87d63e5
to
c2be848
Compare
c2be848
to
83793ff
Compare
Co-authored-by: Christopher Smith <smichr@gmail.com>
new_res = Intersection(result, domain) | ||
# Check if the domain is really contributing | ||
if new_res.is_subset(result): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this always True? (Or rather is it not safe to assume that it is always True?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be that you are correct.
The thing was that just adding the domain sometimes led to some bad looking results. Typically, the domain was not really required in some cases and still remained. I do not remember an exact example, but, say, Intersection(ConditionSet(... S.Reals), S.Reals)
or something similar. This was one of many attempts to get rid of those that at least didn't add anything "stupid".
Maybe it would be better to just add the domain unless it is S.Complexes
and use that as input for improving Intersection
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, forgot what I had already written. I'll try to find a better way of doing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was the problem:
solveset(Abs(x) - n, x, S.Reals)
currently returns ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n})
, by Intersecting with the Reals domain we get ConditionSet(x, Contains(_n, Interval(0, oo)), Intersection({-_n, _n}, Reals))
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize that I was trying to solve issues that I didn't fully understood. So I'll just revert this part.
References to other Issues or PRs
Closes #10085 (added test, solved elsewhere)
Closes #10876 (added test, solved elsewhere)
Closes #12032 (added test, solved elsewhere)
Fixes #13396 (solved underlying problem)
Added test for #13961 (gives two identical solutions)
Closes #14541 (added test, solved elsewhere)
Closes #14642 (added test, solved elsewhere)
Added test for #16643 (original issue solved, but not follow-up equation)
Fixes #17580 (solved underlying problem)
Closes #17906 (added test, solved elsewhere(?))
Fixes #17940 (solved underlying problem)
Fixes #19506 (solved underlying problem)
Brief description of what is fixed or changed
Added tests and closed where appropriate.
Other comments
Release Notes
solveset
correctly solvesarg
when the argument is complex.