Skip to content
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

manualintegrate nested pow #23716

Merged
merged 4 commits into from Nov 17, 2022

Conversation

eagleoflqj
Copy link
Member

References to other Issues or PRs

Fixes #23712
Fixes #23505

Brief description of what is fixed or changed

This is an extension to power rule.
Nested pow like sqrt(x**(S(5)/3)) can be treated as x**(S(5)/6), but the structure should be kept in the end.

$$ \begin{align} &\int \sqrt{x^\frac{5}{3}}\mathrm{d}x\\ =&x\sqrt{x^\frac{5}{3}} - \int x\mathrm{d}\sqrt{x^\frac{5}{3}}\\ =&x\sqrt{x^\frac{5}{3}} - \int x\cdot\frac{1}{2}(x^\frac{5}{3})^{-\frac{1}{2}}\cdot\frac{5}{3}x^\frac{2}{3}\mathrm{d}x\\ =&x\sqrt{x^\frac{5}{3}} - \frac{5}{6}\int \sqrt{x^\frac{5}{3}}\mathrm{d}x\\ =&\frac{6}{11}x\sqrt{x^\frac{5}{3}} \end{align} $$

However, if the exponent is equivalent to -1, the integrand should be multiplied by x*log(x) instead of x/(exponent+1)

Other comments

Release Notes

  • integrals
    • Support integral steps for nested pow like (c*(a+b*x)**d)**e

@sympy-bot
Copy link

sympy-bot commented Jul 2, 2022

Hi, I am the SymPy bot (v167). 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:

  • integrals
    • Support integral steps for nested pow like (c*(a+b*x)**d)**e (#23716 by @eagleoflqj)

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.12.

Click here to see the pull request description that was parsed.
<!-- 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. -->

Fixes #23712
Fixes #23505
#### Brief description of what is fixed or changed

This is an extension to power rule.
Nested pow like `sqrt(x**(S(5)/3))` can be treated as `x**(S(5)/6)`, but the structure should be kept in the end.

$$
\begin{align}
&\int \sqrt{x^\frac{5}{3}}\mathrm{d}x\\
=&x\sqrt{x^\frac{5}{3}} - \int x\mathrm{d}\sqrt{x^\frac{5}{3}}\\
=&x\sqrt{x^\frac{5}{3}} - \int x\cdot\frac{1}{2}(x^\frac{5}{3})^{-\frac{1}{2}}\cdot\frac{5}{3}x^\frac{2}{3}\mathrm{d}x\\
=&x\sqrt{x^\frac{5}{3}} - \frac{5}{6}\int \sqrt{x^\frac{5}{3}}\mathrm{d}x\\
=&\frac{6}{11}x\sqrt{x^\frac{5}{3}}
\end{align}
$$

However, if the exponent is equivalent to -1, the integrand should be multiplied by `x*log(x)` instead of `x/(exponent+1)`
#### 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 -->
* integrals
  * Support integral steps for nested pow like (c*(a+b*x)**d)**e
<!-- END RELEASE NOTES -->

Update

The release notes on the wiki have been updated.

@github-actions
Copy link

github-actions bot commented Jul 2, 2022

Benchmark results from GitHub Actions

Lower numbers are good, higher numbers are bad. A ratio less than 1
means a speed up and greater than 1 means a slowdown. Green lines
beginning with + are slowdowns (the PR is slower then master or
master is slower than the previous release). Red lines beginning
with - are speedups.

Significantly changed benchmark results (PR vs master)

Significantly changed benchmark results (master vs previous release)

       before           after         ratio
     [41d90958]       [6afa478c]
     <sympy-1.11.1^0>                 
-         966±3μs          620±2μs     0.64  solve.TimeSparseSystem.time_linear_eq_to_matrix(10)
-     2.80±0.01ms         1.16±0ms     0.41  solve.TimeSparseSystem.time_linear_eq_to_matrix(20)
-     5.67±0.01ms         1.70±0ms     0.30  solve.TimeSparseSystem.time_linear_eq_to_matrix(30)

Full benchmark results can be found as artifacts in GitHub Actions
(click on checks at the top of the PR).

@eagleoflqj eagleoflqj requested a review from jksuom July 13, 2022 02:27
@eagleoflqj
Copy link
Member Author

@oscarbenjamin is this good to go?

if e.has_free(x):
raise ValueError()
base_, sub_exp = _get_base_exp(b)
return base_, sub_exp * e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this assume that (a**b**c) == a**(b*c)? If so then that identity does not always hold.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basic power rule: to calculate integral of x**n, n != -1, we multiply it by x and divide it by n+1, so we get x**(n+1)/(n+1).
Basic log rule: to calculate integral of x**-1, we multiply it by x*log(x), so we get log(x).

Now let's extend these basic rules to more complicated forms like (x**2)**(-1/2) and x*cbrt(1/x).

I know (x**2)**(-1/2) != x**-1, but to calculate the integral, we should decide whether to use power rule or log rule. The decision is made by treating (x**2)**(-1/2) as x**(2*(-1/2)), so the "nominal" exponent is -1, thus we apply log rule: multiply it by x*log(x) to get x*log(x)/sqrt(x**2). The correctness is easily verified: diff(x*log(x)/sqrt(x**2)) == 1/sqrt(x**2).

Similar thing happens to x*cbrt(1/x) as well. The "nominal" exponent is 1+(1/3)*(-1) == 2/3 which is not -1, so we apply power rule: multiply it by x and divide it by 5/3. The result is 3*x**2*cbrt(1/x)/5, and diff(3*x**2*cbrt(1/x)/5) == x*(1/x)**(1/3).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. So we just use sub_exp*e in the divisor.

try:
base, exp_ = _get_base_exp(integrand)
except ValueError:
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is generally better not to raise and catch ValueError as part of normal flow control because various bugs can result in raising ValueError and then this would obscure those bugs by silencing the exception. Here a special purpose exception should be used like class NoMatch(Exception).

@oscarbenjamin
Copy link
Contributor

I think this looks good.

@jksuom
Copy link
Member

jksuom commented Nov 16, 2022

I'm not sure that this would work if the base is not positive.

@eagleoflqj
Copy link
Member Author

I'm not sure that this would work if the base is not positive.

This aims to solve negative base issue. See #23712 (comment) which is wrong for negative base.
The result produced here is correct.

@eagleoflqj eagleoflqj merged commit e25e6ff into sympy:master Nov 17, 2022
@eagleoflqj eagleoflqj deleted the manualintegrate_nested_pow branch November 17, 2022 03:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

integrate 1/sqrt(x**2) is wrong integral_steps(sqrt(x**(S(5)/3)), x) returns DontKnowRule
4 participants