Opened 7 years ago
Last modified 2 years ago
#12809 new defect
Solve does not give consistent results when a dummy variable is involved
Reported by: | afleckenstein | Owned by: | burcin |
---|---|---|---|
Priority: | minor | Milestone: | sage-6.4 |
Component: | symbolics | Keywords: | solve |
Cc: | kcrisman, mjo, eviatarbach | Merged in: | |
Authors: | Reviewers: | ||
Report Upstream: | N/A | Work issues: | |
Branch: | Commit: | ||
Dependencies: | Stopgaps: |
Description
When working on another ticket (#11201) that involves documentation for the solve function, doing doctests proved to be frustrating. I added to the examples section of the docstring, and then multiple tests failed. I did some manual testing in sage and noticed a problem:
sage: var('x y') (x, y) sage: solve(cos(x)*sin(y)==1/2, x+y==0,x,y) [[x == 1/4*pi + pi*z6, y == -1/4*pi - pi*z6]]
This is a perfectly valid answer, except that when I tried to solve the same equations again, the answer is different:
sage: solve(cos(x)*sin(y)==1/2, x+y==0,x,y) [[x == 1/4*pi + pi*z14, y == -1/4*pi - pi*z14]]
This is still mathematically correct. If I solve them many more times, z's coefficient keeps going up by 8:
sage: solve(cos(x)*sin(y)==1/2, x+y==0,x,y) [[x == 1/4*pi + pi*z22, y == -1/4*pi - pi*z22]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z30, y == -1/4*pi - pi*z30]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z38, y == -1/4*pi - pi*z38]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z46, y == -1/4*pi - pi*z46]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z54, y == -1/4*pi - pi*z54]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z62, y == -1/4*pi - pi*z62]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z70, y == -1/4*pi - pi*z70]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z78, y == -1/4*pi - pi*z78]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z86, y == -1/4*pi - pi*z86]] sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z94, y == -1/4*pi - pi*z94]]
All still mathematically correct.
This is a problem when you are trying to add examples to the documentation for solve and many doctests fail because the coefficients for the dummy variable are shifted up by some integer amount. I have included the file expressions_pyx_doctests.txt to show more of what I am talking about. To cause this, I added two examples, and the examples that I added were not complained about in the doctest. Also, z's coefficient went up by 6 this time, different than 8 in the first example.
Attachments (1)
Change History (14)
Changed 7 years ago by
comment:1 follow-up: ↓ 2 Changed 7 years ago by
comment:2 in reply to: ↑ 1 Changed 7 years ago by
Replying to kcrisman:
This is a known issue - I won't call it a problem, though some people (like the reporter) certainly have strong feelings on this. People have tried to weasel out of it in changing doctests by putting ellipses in for the variable names, but in the end it's better to show the end user reading the documentation what a likely output actually looks like.
I completely disagree with you. I think it is perfectly reasonable to replace an example like
sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z94, y == -1/4*pi - pi*z94]]
with
sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) [[x == 1/4*pi + pi*z..., y == -1/4*pi - pi*z...]]
Alternatively, if this is NOT intended for somebody to actually read, then simply make it a "unit test", e.g., put all the tests into a function (e.g., "test_solve"), then do whatever you want to verify correctness of output using asserts, and finally put one single doctest in test_solve, which is:
sage: test_solve()
comment:3 follow-up: ↓ 4 Changed 7 years ago by
This does suggest we may want to consider reseting Maxima's counter for dummy variables before calling solve.
comment:4 in reply to: ↑ 3 Changed 7 years ago by
Replying to was:
This does suggest we may want to consider reseting Maxima's counter for dummy variables before calling solve.
It would require care of the user to remember whether different occurrences of the same variable name refer to independent parameters or not, but to_poly has a convenience function to relabel the temporaries:
(%i1) load(to_poly_solver); (%o1) ... (%i2) display2d: false; (%o2) false (%i3) nicedummies(to_poly_solve([sin(x)=cos(x)],[x])); (%o3) %union([x = (4*%pi*%z0+%pi)/4]) (%i4) nicedummies(to_poly_solve([sin(x)=cos(x)],[x])); (%o4) %union([x = (4*%pi*%z0+%pi)/4])
I think the slight inconvenience of getting new names every time is preferable to the ambiguity that is caused by reusing names among several equation solves. Another issue is that the maxima-to-sage conversion maps %z1 to z1 without checking. This can lead to further unintended name collisions.
(but then again, if someone is willing to use the results returned by a CAS solve routine without checking, they're asking for trouble anyway)
comment:5 Changed 7 years ago by
- Priority changed from major to minor
comment:6 follow-up: ↓ 7 Changed 7 years ago by
- Cc mjo added
I implemented MaximaLibElement.nicedummies()
, but it seems that once you make the round-trip through sage, the information that zXX is a dummy is lost:
from sage.interfaces.maxima_lib import maxima_lib sage: y = var('y') sage: soln = solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y) sage: maxima_lib(soln[0][0]) x=%pi*z36+%pi/4 sage: maxima_lib(soln[0][0]).nicedummies() x=%pi*z36+%pi/4
(The function does actually work before you leave Maxima.)
So, we'd either have to add a nicedummies
parameter to each of the routines that return them, or write our own implementation that works entirely within sage.
comment:7 in reply to: ↑ 6 Changed 7 years ago by
Replying to mjo:
I implemented
MaximaLibElement.nicedummies()
, but it seems that once you make the round-trip through sage, the information that zXX is a dummy is lost
This is mainly for documentation and sufficient cross linking. In this sage-devel thread the cause is described: maxima's %z2
gets translated to z2
in sage and then to z2
in maxima, so the variables get renamed.
See nicedummies
in maxima's share/contrib/topoly.lisp
to see how "dummies" get recognized (it's a property hanging off the symbol, not the name of the symbol)
comment:8 Changed 6 years ago by
- Cc eviatarbach added
comment:9 Changed 6 years ago by
- Milestone changed from sage-5.11 to sage-5.12
comment:10 Changed 5 years ago by
- Milestone changed from sage-6.1 to sage-6.2
comment:11 Changed 5 years ago by
- Milestone changed from sage-6.2 to sage-6.3
comment:12 Changed 5 years ago by
- Milestone changed from sage-6.3 to sage-6.4
comment:13 Changed 2 years ago by
Should we update the milestone?
This is a known issue - I won't call it a problem, though some people (like the reporter) certainly have strong feelings on this. People have tried to weasel out of it in changing doctests by putting ellipses in for the variable names, but in the end it's better to show the end user reading the documentation what a likely output actually looks like. Concur that it's annoying for those writing doctests, but at least in one opinion this is not really a bug.
That said, if we can be smart enough with Maxima and how it's naming these dummy variables for this not to happen, or to return something different, that would be great. But it's probably not worth the effort, given how many actual enhancements or bugs we can fix instead :-)