Repository: sympy/sympy
Pull request: Fixed issue #16327 (atan2 rewrite atan ignores sign)
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
Fixes #16327 
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234". See
https://github.com/blog/1506-closing-issues-via-pull-requests . Please also
write a comment on that issue linking back to this pull request once it is
open. -->


#### Brief description of what is fixed or changed
Now If x is real then arg(x).rewrite(atan2).rewrite(atan)  returns the piecewise function
```
⎧0  for x > 0
⎨            
⎩π  otherwise
```
if the sign of the input (x) is not known.


#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
* functions
   * fixed a bug with eval_rewrite_as_atan
<!-- END RELEASE NOTES -->


Problem statement:
atan2 rewrite atan ignores sign
If `x` is real then `arg(x)` is either 0 or pi but this assumes 0:
```julia
In [14]: x = Symbol('x', real=True)                                                                                                            

In [15]: arg(x)                                                                                                                                
Out[15]: arg(x)

In [16]: arg(x).rewrite(atan2)                                                                                                                 
Out[16]: atan2(0, x)

In [17]: arg(x).rewrite(atan2).rewrite(atan)                                                                                                   
Out[17]: 0
```

If x is declared as negative then we get:
```
In [20]: x = Symbol('x', negative=True)                                                                                                        

In [21]: arg(x).rewrite(atan2).rewrite(atan)                                                                                                   
Out[21]: π
```

So when x is not declared positive or negative the solutions should be something like
```
In [27]: x = Symbol('x', real=True)                                                                                                            

In [28]: Piecewise((0, x>0), (pi, True))                                                                                                       
Out[28]: 
⎧0  for x > 0
⎨            
⎩π  otherwise
```

Hints from issue discussion:
I would like to work on this issue
Okay this code seems to do the trick:
```
            x = re(a)
            y = im(a)
            return Piecewise(
                (2*atan(y / (sqrt(x**2 + y**2) + x)), Or(x>0, Ne(y, 0))),
                (pi, And(x<0, Eq(y, 0))),
                (nan, True),
                    )
```
Probably needs to be added to arg._eval_rewrite or something...

Commit message: Simplified Piecewise

Patch to review:
diff --git a/sympy/functions/elementary/tests/test_trigonometric.py b/sympy/functions/elementary/tests/test_trigonometric.py
index e16f8f8b48cc..edb349d62106 100644
--- a/sympy/functions/elementary/tests/test_trigonometric.py
+++ b/sympy/functions/elementary/tests/test_trigonometric.py
@@ -903,8 +903,13 @@ def test_atan2():
     assert atan2(y, oo) ==  0
     assert atan2(y, -oo)==  2*pi*Heaviside(re(y)) - pi
 
+    w = Symbol('w')
+
     assert atan2(y, x).rewrite(log) == -I*log((x + I*y)/sqrt(x**2 + y**2))
-    assert atan2(y, x).rewrite(atan) == 2*atan(y/(x + sqrt(x**2 + y**2)))
+    from sympy.logic.boolalg import And
+    from sympy.core.relational import Ne, Lt, Eq, Gt
+    assert atan2(0, 0).rewrite(atan) == S.NaN
+    assert atan2(0, w).rewrite(atan) == Piecewise((pi, w < 0), (0, w > 0), (S.NaN, True))
 
     ex = atan2(y, x) - arg(x + I*y)
     assert ex.subs({x:2, y:3}).rewrite(arg) == 0
diff --git a/sympy/functions/elementary/trigonometric.py b/sympy/functions/elementary/trigonometric.py
index 77897e76762a..80d1b50608c2 100644
--- a/sympy/functions/elementary/trigonometric.py
+++ b/sympy/functions/elementary/trigonometric.py
@@ -2867,7 +2867,7 @@ class atan2(InverseTrigonometricFunction):
 
     >>> from sympy import atan
     >>> atan2(y, x).rewrite(atan)
-    2*atan(y/(x + sqrt(x**2 + y**2)))
+    Piecewise((2*atan(y/(x + sqrt(x**2 + y**2))), Ne(y, 0)), (pi, x < 0), (0, x > 0), (nan, True))
 
     but note that this form is undefined on the negative real axis.
 
@@ -2924,7 +2924,9 @@ def _eval_rewrite_as_log(self, y, x, **kwargs):
         return -S.ImaginaryUnit*log((x + S.ImaginaryUnit*y) / sqrt(x**2 + y**2))
 
     def _eval_rewrite_as_atan(self, y, x, **kwargs):
-        return 2*atan(y / (sqrt(x**2 + y**2) + x))
+        from sympy.logic.boolalg import And
+        from sympy.core.relational import Ne, Lt, Eq, Gt
+        return Piecewise((2*atan(y/(x + sqrt(x**2 + y**2))), Ne(y, 0)), (pi, x < 0), (0, x > 0), (S.NaN, True))
 
     def _eval_rewrite_as_arg(self, y, x, **kwargs):
         from sympy import arg


Code review comments:
diff_hunk: @@ -2924,7 +2924,9 @@ def _eval_rewrite_as_log(self, y, x, **kwargs):
         return -S.ImaginaryUnit*log((x + S.ImaginaryUnit*y) / sqrt(x**2 + y**2))
 
     def _eval_rewrite_as_atan(self, y, x, **kwargs):
-        return 2*atan(y / (sqrt(x**2 + y**2) + x))
+        from sympy.logic.boolalg import And
+        from sympy.core.relational import Ne, Lt, Eq, Gt
path: sympy/functions/elementary/trigonometric.py
text: @user1:
These imports are not all needed any more.

diff_hunk: @@ -903,8 +903,13 @@ def test_atan2():
     assert atan2(y, oo) ==  0
     assert atan2(y, -oo)==  2*pi*Heaviside(re(y)) - pi
 
+    w = Symbol('w')
+
     assert atan2(y, x).rewrite(log) == -I*log((x + I*y)/sqrt(x**2 + y**2))
-    assert atan2(y, x).rewrite(atan) == 2*atan(y/(x + sqrt(x**2 + y**2)))
+    from sympy.logic.boolalg import And
+    from sympy.core.relational import Ne, Lt, Eq, Gt
path: sympy/functions/elementary/tests/test_trigonometric.py
text: @user1:
These imports are no needed any more.