Repository: sympy/sympy

Issue:
Incorrect result from `manualintegrate` for definite integral
sympy vs sagecell error with triple integral?

I'm teaching a course in Multivariate Calculus and decided to convert my notes from Sage to Jupyter using SymPy. I have rewritten nearly all my notes as Jupyter Notebooks and am very impressed how I can use multiple cells like Mathematica and I can use MarkDown cells with LaTEX as well as all the great features of matplotlib, NumPy and SymPy.

I'm nearly done converting my segelets to python scripts on Colab and found a discrepency,

This Sage code:

`show(integral(integral(integral(1,z,x^2+y^2,2-x^2-y^2),y,-sqrt(1-x^2),sqrt(1-x^2)),x,-1,1))`

resolves as pi.

This SymPy code:

`display(Integral(1,(z,x**2+y**2,2-x**2-y**2),(y,-sqrt(1-x**2),sqrt(1-x**2)),(x,-1,1)).doit())`

resolves as -pi/2.

See #3 in this Jupyter Notebook:

[https://colab.research.google.com/drive/1OlT9nfPG8TzoR_WpDavx-SAa07HLg3hV?usp=sharing](https://colab.research.google.com/drive/1OlT9nfPG8TzoR_WpDavx-SAa07HLg3hV?usp=sharing)

Shouldn't these be equal? What am I missing? Any help would be greatly appreciated as I've done A LOT of work on this course using sympy and woud like to use it in class this summer session!

Please help,

A. Jorge Garcia

Applied Math & CS

Nassau Community College

http://shadowfaxrant.blogspot.com



PS: Here's the SAGECELL version,

[https://sagecell.sagemath.org/?z=eJzFk8FuwjAMhu9IvIMFB9qRTk1A07TrtE07cNuuSBkEGlGS4qRA-_RLQ1uQuDCGtlMsx_ns_5fTn-AbsJg-3scPoxg-J89sDB8os1TAu7JiiTw13U6fhvCy5WnOrQCu5v4OMxT2CWRdFpwHlJQkJiwkhTtGIdm7Yxx2OybRu6B3U2jPYbccg0FBykHT4seUdrYK52SzX0xIo-KArZvQo_DbYnsXyz1_e5A5unqe_ZQNiykjLHJR5KIKHJkN2oBWqZCcxFXviJ4a8deNL7XqOvrBzHEIr9JpsYmANTcG9MLHuZIWZvmXcNJ8YiHRWNAzy5WFXSIUYKJBGshQZxqt1IqnYLUvNpuco2hYc2ncq5ljoF77jEa5lKo19j-HaL_i6pKPuLoLareHZWWs39NmPf2yOmO_Adu6eJ4=&lang=sage](https://sagecell.sagemath.org/?z=eJzFk8FuwjAMhu9IvIMFB9qRTk1A07TrtE07cNuuSBkEGlGS4qRA-_RLQ1uQuDCGtlMsx_ns_5fTn-AbsJg-3scPoxg-J89sDB8os1TAu7JiiTw13U6fhvCy5WnOrQCu5v4OMxT2CWRdFpwHlJQkJiwkhTtGIdm7Yxx2OybRu6B3U2jPYbccg0FBykHT4seUdrYK52SzX0xIo-KArZvQo_DbYnsXyz1_e5A5unqe_ZQNiykjLHJR5KIKHJkN2oBWqZCcxFXviJ4a8deNL7XqOvrBzHEIr9JpsYmANTcG9MLHuZIWZvmXcNJ8YiHRWNAzy5WFXSIUYKJBGshQZxqt1IqnYLUvNpuco2hYc2ncq5ljoF77jEa5lKo19j-HaL_i6pKPuLoLareHZWWs39NmPf2yOmO_Adu6eJ4=&lang=sage)

Discussion:
sympy-bot: :white_check_mark:

Hi, I am the [SymPy bot](https://github.com/sympy/sympy-bot) (v161). I'm here to help you write a release notes entry. Please read the [guide on how to write release notes](https://github.com/sympy/sympy/wiki/Writing-Release-Notes).



* No release notes entry will be added for this pull request.

<details><summary>Click here to see the pull request description that was parsed.</summary>

    In a substitution like (1/x).subs(x**2, y) there need to be checks to
    see whether it is valid to replace x with e.g. sqrt(y). Previously those
    checks were heuristic and depended on the evaluation behaviour of
    _eval_power. This commit changes those to depend directly on the
    assumptions of the base and exponent in the base pow.

    <!-- 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
    <!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
    format, e.g. "Fixes #1234" (see
    https://tinyurl.com/auto-closing for more information). Also, please
    write a comment on that issue linking back to this pull request once it is
    open. -->


    #### Brief description of what is fixed or changed


    #### Other comments


    #### Release Notes

    <!-- Write the release notes for this release below between the BEGIN and END
    statements. The basic format is a bulleted list with the name of the subpackage
    and the release note for this PR. For example:

    * solvers
      * Added a new solver for logarithmic equations.

    * functions
      * Fixed a bug with log of integers.

    or if no release note(s) should be included use:

    NO ENTRY

    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 -->
    NO ENTRY
    <!-- END RELEASE NOTES -->


</details><p>

oscargus: Have you had the chance to try #18527 as well?
oscarbenjamin: > Have you had the chance to try #18527 as well?

Yes, I've added a test for that now.

Patch:
diff --git a/sympy/core/power.py b/sympy/core/power.py
index 6396cf1163..88c900ad77 100644
--- a/sympy/core/power.py
+++ b/sympy/core/power.py
@@ -861,9 +861,10 @@ def _check(ct1, ct2, old):
                         as_int(pow, strict=False)
                         combines = True
                     except ValueError:
-                        combines = isinstance(Pow._eval_power(
-                            Pow(*old.as_base_exp(), evaluate=False),
-                            pow), (Pow, exp, Symbol))
+                        b, e = old.as_base_exp()
+                        # These conditions ensure that (b**e)**f == b**(e*f) for any f
+                        combines = b.is_positive and e.is_real or b.is_nonnegative and e.is_nonnegative
+
                     return combines, pow, None
                 else:
                     # With noncommutative symbols, substitute only integer powers


Test patch:
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index 41783005de..f9c6215388 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -126,6 +126,7 @@ jobs:
   tensorflow:
     needs: code-quality
 
+
     runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@v2
diff --git a/sympy/core/tests/test_subs.py b/sympy/core/tests/test_subs.py
index e00b221d91..b816bec4ae 100644
--- a/sympy/core/tests/test_subs.py
+++ b/sympy/core/tests/test_subs.py
@@ -22,6 +22,7 @@
 from sympy.testing.pytest import XFAIL
 from sympy.abc import a, x, y, z, t
 
+
 def test_subs():
     n3 = Rational(3)
     e = x
@@ -48,6 +49,7 @@ def test_subs_Matrix():
     # Does not raise a TypeError, see comment on the MatAdd postprocessor
     assert Add(Matrix([[3]]), x).subs(x, 2.0) == Add(Matrix([[3]]), 2.0)
 
+
 def test_subs_AccumBounds():
     e = x
     e = e.subs(x, AccumBounds(1, 3))
@@ -481,6 +483,7 @@ def test_add():
     assert Add(*[AccumBounds(-1, 1), oo]) == oo
     assert Add(*[oo, AccumBounds(-1, 1)]) == oo
 
+
 def test_subs_issue_4009():
     assert (I*Symbol('a')).subs(1, 2) == I*Symbol('a')
 
@@ -879,9 +882,16 @@ def test_issue_19558():
     assert (sin(x) + cos(x)).subs(x, oo) == AccumBounds(-2, 2)
 
 
+
+def test_issue_22033():
+    xr = Symbol('xr', real=True)
+    e = (1/xr)
+    assert e.subs(xr**2, y) == e
+
+
 def test_guard_against_indeterminate_evaluation():
     eq = x**y
     assert eq.subs([(x, 1), (y, oo)]) == 1  # because 1**y == 1
     assert eq.subs([(y, oo), (x, 1)]) is S.NaN
     assert eq.subs({x: 1, y: oo}) is S.NaN
-    assert eq.subs([(x, 1), (y, oo)],simultaneous=True) is S.NaN
+    assert eq.subs([(x, 1), (y, oo)], simultaneous=True) is S.NaN
diff --git a/sympy/integrals/tests/test_integrals.py b/sympy/integrals/tests/test_integrals.py
index 5d0634245f..c643ed7604 100644
--- a/sympy/integrals/tests/test_integrals.py
+++ b/sympy/integrals/tests/test_integrals.py
@@ -1877,3 +1877,23 @@ def test_issue_21024():
 def test_issue_21831():
     theta = symbols('theta')
     assert integrate(cos(3*theta)/(5-4*cos(theta)), (theta, 0, 2*pi)) == pi/12
+
+
+@slow
+def test_issue_22033_integral():
+    assert integrate((x**2 - Rational(1, 4))**2 * sqrt(1 - x**2), (x, -1, 1)) == pi/32
+
+
+@slow
+def test_issue_21671():
+    assert integrate(1,(z,x**2+y**2,2-x**2-y**2),(y,-sqrt(1-x**2),sqrt(1-x**2)),(x,-1,1)) == pi
+    assert integrate(-4*(1 - x**2)**(S(3)/2)/3 + 2*sqrt(1 - x**2)*(2 - 2*x**2), (x, -1, 1)) == pi
+
+
+def test_issue_18527():
+    # The manual integrator can not currently solve this. Assert that it does
+    # not give an incorrect result involving Abs when x has real assumptions.
+    xr = symbols('xr', real=True)
+    expr = (cos(x)/(4+(sin(x))**2))
+    res_real = integrate(expr.subs(x, xr), xr, manual=True).subs(xr, x)
+    assert integrate(expr, x, manual=True) == res_real == Integral(expr, x)