Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,21 @@ discriminant is zero is now one linear twice ([#233](https://github.com/asc-comm
| `"1/((a*g+b*g*x)^3*(A+B*ln(k*(a+b*x)/(c+d*x)))^2)".ToEntity().Integrate("x")` | no answer in twenty seconds | 644 characters, two powers of t |
| `"1/(x^2*(A+B*ln(k*x))^2)".ToEntity().Integrate("x")` | `integral(...)` | 133 characters, `Ei(-(A/B + ln(k x)))`, where before this change master gave an answer with no value at any point |

### A power of x beside a binomial in an odd negative power of x is integrated on both sides of 0

**Answers where there were none.** `sqrt(a + b/x^3)/x` and thirteen more of Rubi's 1.1.3.2,
`x^m (a + b/x^3)^(k/2)`, were declined. `a + b/x^3` is real on both sides of 0, and they are answered
there in the variable under the root, where taking `x^(-3/2)` out of it would leave an answer for a
positive x only ([#233](https://github.com/asc-community/AngouriMath/issues/233)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sqrt(a+b/x^3)/x".ToEntity().Integrate("x")` | `integral(...)` | 455 characters |
| `"sqrt(a+b/x^3)/x^7".ToEntity().Integrate("x")` | `integral(...)` | 101 characters |
| `"(a+b/x^3)^(3/2)*x^2".ToEntity().Integrate("x")` | `integral(...)` | 842 characters |
| `"x^5/sqrt(a+b/x^3)".ToEntity().Integrate("x")` | `integral(...)` | 831 characters |
| `"x^2/(a+b/x^3)^(3/2)".ToEntity().Integrate("x")` | `integral(...)` | 911 characters |

### The last digits of an evaluated sine, cosine, tangent, arcsine or arctangent

**Silent, and in the hundredth digit.** `EvalNumerical` at the default hundred digits gives the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31152,12 +31152,25 @@ bool MayBeARootOfASquare(Entity node, Entity.Variable x)
// minute of search to be declined, where as written it is five seconds. Past those
// nothing reads the sum as written, and the factor below answers both sides:
// `x/sqrt(a x + b x^4)`. An even power comes out as its sign, and a fractional one
// is real for a positive x only, as the sum already was.
// beside a power of x that is not whole is real for a positive x only, as the sum
// already was.
if (lowest is Number.Integer { EInteger.IsEven: false } odd && odd.EInteger.Abs().Equals(EInteger.One)
&& !sum.Nodes.Any(node => node is Powf(var @base, var r) && @base == x && r is not Number.Integer)
&& (Mulf.LinearChildren(rest).Where(part => part.ContainsNode(x)).ToList() is not [Sumf or Minusf]
|| Sumf.LinearChildren(rest).All(term => PowerOfX(term, x) is (_, Number.Integer { EInteger: var degree }) && degree.CompareTo(1) <= 0 && degree.Sign >= 0)))
continue;
// And x to any other odd power out of a sum of whole powers under a power p that
// leaves `x^(j p)` fractional: the sum is real on both sides of 0 and `x^(j p)` is
// not, and the answer came out for a positive x only. The substitution answers it
// on both: `sqrt(a + b/x^3)/x` is a function of `u = sqrt(a + b/x^3)`, where taking
// out `x^(-3/2)` left Rubi's 1.1.3.2 with no value at a negative x where the
// integrand is real. A whole `j p` is real on both sides, and the factor in front
// is constant on each: `(a x^3 + b x^6)^(5/3)` is `x^5` times a power of
// `a + b x^3`, Rubi's 1.2.3.2.
if (lowest is Number.Integer { EInteger.IsEven: false } oddPast && !oddPast.EInteger.Abs().Equals(EInteger.One)
&& (oddPast * power).Evaled is not Number.Integer
&& !sum.Nodes.Any(node => node is Powf(var @base, var r) && @base == x && r is not Number.Integer))
continue;
// The rest of the integrand a constant times the sum's derivative is the plain
// substitution's, u = the sum, which answers it as a power of u, where the sum
// with x taken out is a search: `(x - 3 sqrt(x))^(2/3) (2 sqrt(x) - 3)/sqrt(x)`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
// Website: https://am.angouri.org.
//

using System;
using AngouriMath.Extensions;
using Xunit;

namespace AngouriMath.Tests.Calculus
{
/// <summary>
/// <c>a + b/x^3</c> is real on both sides of 0, and taking <c>x^(-3/2)</c> out of its root, as
/// <c>sqrt(a + b/x^3) = K x^(-3/2) sqrt(a x^3 + b)</c>, left an answer with no value at a negative
/// x where the integrand is real: Rubi's 1.1.3.2 <c>x^m (a + b/x^3)^(k/2)</c>, fourteen of them. The
/// substitution under the root answers on both sides.
/// <a href="https://github.com/asc-community/AngouriMath/issues/233">#233</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class APowerOfXOutOfABinomialInAnOddNegativePowerIntegralTest
{
[Theory]
[InlineData("sqrt(a+b/x^3)/x")]
[InlineData("sqrt(a+b/x^3)/x^7")]
[InlineData("(a+b/x^3)^(3/2)*x^2")]
[InlineData("(a+b/x^3)^(3/2)/x^10")]
[InlineData("x^5/sqrt(a+b/x^3)")]
[InlineData("x^2/(a+b/x^3)^(3/2)")]
public void DifferentiatesBackOnBothSidesOfZero(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
// a + b/x^3 is positive below the root of -b/a, about -0.81, and above 0.
foreach (var at in new[] { -2.3, -1.7, -1.1, 0.4, 1.3, 2.2 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).EvalNumerical();
Assert.False(got.IsNaN, $"d/dx of the antiderivative of {integrand} has no value at x = {at}, where the integrand is {want}");
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}

/// <summary>
/// And an odd power taken out where <c>j p</c> is whole, which is real on both sides: Rubi's
/// 1.2.3.2 <c>(a x^3 + b x^6)^(5/3)</c> is <c>x^5</c> times a power of <c>a + b x^3</c>, and a
/// guard on the odd power alone declined it.
/// </summary>
[Fact]
public void TakesAnOddPowerOutWhereItsPowerIsWhole()
{
const string integrand = "(a*x^3+b*x^6)^(5/3)";
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
// a x^3 + b x^6 is positive below the root of -a/b, about -1.23, and above 0.
foreach (var at in new[] { -2.3, -1.7, -1.4, 0.4, 1.3, 2.2 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).EvalNumerical();
Assert.False(got.IsNaN, $"d/dx of the antiderivative of {integrand} has no value at x = {at}, where the integrand is {want}");
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}
}
}
Loading