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
18 changes: 18 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,24 @@ roots, `1 - x^2`, is taken as its two ([#718](https://github.com/asc-community/A
| `"1/((1 - x^2)*(a + b*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,600 characters |
| `"1/(x*(1 - x^2)*(a + b*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,637 characters |

### A sine's binomial cube below the bar is split over the cube's two factors

**Answers where there were none.** `csc(c + d x)/(a + b sin(c + d x)^3)` was declined, and so were the second to fifth
powers of the cosecant and the second and fourth powers of the secant over the same block (Rubi's 4.1.7). With `a`
and `b` symbols the block has no rational factor, so the split over a symbolic quadratic in the sine had nothing to
split. It is written `b (s + r)(s^2 - r s + r^2)` now, with `r = (a/b)^(1/3)`, which that split answers
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"csc(c + d*x)/(a + b*sin(c + d*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 5,058 characters |
| `"csc(c + d*x)^2/(a + b*sin(c + d*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 4,866 characters |
| `"csc(c + d*x)^3/(a + b*sin(c + d*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 5,382 characters |
| `"csc(c + d*x)^4/(a + b*sin(c + d*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 5,426 characters |
| `"csc(c + d*x)^5/(a + b*sin(c + d*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 5,958 characters |
| `"sec(c + d*x)^2/(a + b*sin(c + d*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 7,010 characters |
| `"sec(c + d*x)^4/(a + b*sin(c + d*x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 11,646 characters |

### A symbol shared by a numerator sum's coefficients is taken out before the partial fractions

**Answers where there were none.** `(b d + 2c d x)^9/(a + b x + c x^2)^3` ran past a minute, where
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23744,10 +23744,59 @@ static bool IsASumOfPowersOfX(Entity sum, Entity.Variable x)
return null;
if (OverASymbolicQuadraticInTheFunction(inS, s, w, function == sine, argument, rate, x, integrateByParts) is { } answer)
return answer;
if (WithASymbolicBinomialCubeFactored(inS, s, w) is { } cube
&& OverASymbolicQuadraticInTheFunction(cube.Factored, s, w, function == sine, argument, rate, x, integrateByParts) is { } inR)
return inR.Substitute(cube.R, cube.Root);
}
return null;
}

/// <summary>
/// <paramref name="inS"/> with one factor <c>a + b s^3</c> below the bar, a symbol in it,
/// written <c>b (s + r)(s^2 - r s + r^2)</c> for a fresh <c>r</c> whose cube is <c>a/b</c>:
/// a linear and a quadratic with a symbol in it, which the rule above splits over. Null
/// where there is no such factor or more than one.
/// </summary>
/// <remarks>
/// Rubi's 4.1.7: <c>csc(x)/(a + b sin(x)^3)</c> and its even powers of the cosecant and
/// the secant were declined. Under the half-angle the cube is a sextic in <c>t</c> with
/// symbols in every coefficient. The identity holds for any cube root of <c>a/b</c>.
/// https://github.com/asc-community/AngouriMath/issues/718
/// </remarks>
private static (Entity Factored, Variable R, Entity Root)? WithASymbolicBinomialCubeFactored(Entity inS, Variable s, Variable w)
{
var combined = Functions.SingleQuotient.Combine(inS).InnerSimplified;
if (combined is Providedf(var bare, _))
combined = bare;
var (numerator, denominator) = Functions.SingleQuotient.Of(combined);
Entity? cube = null;
Entity rest = Number.Integer.One;
Entity free = Number.Integer.Zero, leading = Number.Integer.Zero;
foreach (var factor in Mulf.LinearChildren(denominator))
{
if (factor is not (Sumf or Minusf) || factor.ContainsNode(w)
|| !TreeAnalyzer.TryGetPolynomial(factor, s, out var read)
|| read.Count != 2 || !read.ContainsKey(EInteger.Zero) || !read.ContainsKey(EInteger.FromInt32(3))
|| read.Values.Any(coefficient => coefficient.ContainsNode(s))
|| !factor.Vars.Any(v => v != s))
{
rest = rest == Number.Integer.One ? factor : rest * factor;
continue;
}
if (cube is not null)
return null;
cube = factor;
free = read[EInteger.Zero];
leading = read[EInteger.FromInt32(3)];
}
if (cube is null || Functions.PartialFractions.IsZeroAsAValue(free) || Functions.PartialFractions.IsZeroAsAValue(leading))
return null;
var r = Variable.CreateUnique(inS, "r_cube");
var factored = leading * (s + r) * (MathS.Pow(s, 2) - r * s + MathS.Pow(r, 2));
var below = rest == Number.Integer.One ? factored : rest * factored;
return (numerator / below, r, MathS.Pow(free / leading, Number.Rational.Create(1, 3)));
}

/// <summary>
/// The rule above in <paramref name="s"/>, for the function that <paramref name="s"/>
/// stands for and <paramref name="w"/> its complement: null where the integrand is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// 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>
/// A rational function of the sine over <c>a + b sin^3</c>, the cube written
/// <c>b (s + r)(s^2 - r s + r^2)</c> with <c>r^3 = a/b</c> and split over its factors. Rubi's 4.1.7.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class ABinomialCubeInTheSineIntegralTest
{
[Theory]
[InlineData("csc(c + d*x)/(a + b*sin(c + d*x)^3)")]
[InlineData("csc(c + d*x)^2/(a + b*sin(c + d*x)^3)")]
[InlineData("csc(c + d*x)^3/(a + b*sin(c + d*x)^3)")]
[InlineData("sec(c + d*x)^2/(a + b*sin(c + d*x)^3)")]
public void DifferentiatesBack(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("a", 2).Substitute("b", 3).Substitute("c", "1/4".ToEntity()).Substitute("d", "3/2".ToEntity());
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in new[] { "0.35", "0.6", "1.1", "1.4" })
{
var want = original.Substitute("x", at.ToEntity()).EvalNumerical();
var got = derivative.Substitute("x", at.ToEntity()).EvalNumerical();
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}
}
}
Loading