Opened 9 years ago

# Solve does not give consistent results when a dummy variable is involved

Reported by: Owned by: afleckenstein burcin minor sage-6.4 symbolics solve kcrisman, mjo, eviatarbach N/A

### 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.

### comment:1 follow-up: ↓ 2 Changed 9 years ago by 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. 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 :-)

### comment:2 in reply to: ↑ 1 Changed 9 years ago by was

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 9 years ago by was

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 9 years ago by nbruin

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 9 years ago by afleckenstein

• Priority changed from major to minor

### comment:6 follow-up: ↓ 7 Changed 9 years ago by 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:

```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)
x=%pi*z36+%pi/4
sage: maxima_lib(soln).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 9 years ago by nbruin

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:9 Changed 7 years ago by jdemeyer

• Milestone changed from sage-5.11 to sage-5.12

### comment:10 Changed 7 years ago by vbraun_spam

• Milestone changed from sage-6.1 to sage-6.2

### comment:11 Changed 7 years ago by vbraun_spam

• Milestone changed from sage-6.2 to sage-6.3

### comment:12 Changed 6 years ago by vbraun_spam

• Milestone changed from sage-6.3 to sage-6.4

### comment:13 Changed 4 years ago by pelegm

Should we update the milestone?

Note: See TracTickets for help on using tickets.