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 @@ -117,6 +117,21 @@ coefficients are the roots of that quadratic, and the polynomial over it is spli
| `"1/(4*a*c+4*c^2*x^2+4*c*d*x^3+d^2*x^4)".ToEntity().Integrate("x")` | `integral(...)` | 3,920 characters |
| `"x/(4*a*c+4*c^2*x^2+4*c*d*x^3+d^2*x^4)".ToEntity().Integrate("x")` | `integral(...)` | 2,315 characters |

### An even power of the sine beside the secant is written in the cosine

**Answers where there were none, shorter than master's.** Rubi's 4.5.1.3 `sin(c + d x)^2/(a + b sec(c + d x))` ran
past the corpus's budget. The half-angle substitution wrote it in 117,751 characters, and `sin(x)^4/(a + b sec(x))` in
160,657. A rational function of the secant was written in the cosine only beside the cosine itself. The sine beside it
stands to even powers only, and `sin(z)^(2k)` is `(1 - cos(z)^2)^k`, so the integrand is now written in the cosine, as a
polynomial over a linear in it. The cosine beside the cosecant is written in the sine the same way
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sin(c+d*x)^2/(a+b*sec(c+d*x))".ToEntity().Integrate("x")` | `integral(...)` | 1,187 characters, where before this change master gave 117,751 |
| `"sin(x)^4/(a+b*sec(x))".ToEntity().Integrate("x")` | `integral(...)` | 1,729 characters, where before this change master gave 160,657 |
| `"cos(x)^2/(a+b*csc(x))".ToEntity().Integrate("x")` | `integral(...)` | 994 characters, where before this change master gave 2,271 |

### An exponential of a quadratic over a power of the linear through its vertex is a moment about it

**Answers where there were none.** `f^(a + b x + c x^2)/(b + 2 c x)` was declined, and so were five more of Rubi's 2.3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46958,8 +46958,14 @@ bool IsAPolynomialInBoth(Entity polynomial)
var argument = reciprocal.DirectChildren.First();
var function = reciprocal is Secantf ? MathS.Cos(argument) : MathS.Sin(argument);
// The cosine of the same argument beside the secant, or the sine beside the cosecant, is
// what the rewritten integrand is in already; any other is a second function.
if (partners.Any(partner => partner != function))
// what the rewritten integrand is in already, and the other of the two is too where it
// stands only to even powers, `sin(z)^(2k)` being `(1 - cos(z)^2)^k`: the half-angle
// substitution wrote `sin(x)^2/(a + b sec(x))` in 117,517 characters, where
// `(1 - cos(x)^2) cos(x)/(a cos(x) + b)` is 969. Any other is a second function.
var complement = reciprocal is Secantf ? MathS.Sin(argument) : MathS.Cos(argument);
static bool AnEvenPower(Entity node, Entity of) => node is Powf(var @base, Number.Integer { EInteger: var power }) && @base == of && power.IsEven && power.Sign > 0;
var inEvenPowers = expr.Nodes.Count(node => node == complement) == expr.Nodes.Count(node => AnEvenPower(node, complement));
if (partners.Any(partner => partner != function && (partner != complement || !inEvenPowers)))
return null;
// Only two sums in the secant or more, all below the bar: one, or one above, the rules for
// the secant answer as written, and in the cosine `sec(x)^5/(a + b sec(x))^3` ran past five
Expand All @@ -46978,7 +46984,11 @@ bool IsAPolynomialInBoth(Entity polynomial)
if (partners.Count > 0
&& (!below.Nodes.Any(ASum) || Mulf.LinearChildren(below).Any(factor => factor is Powf(var @base, _) && ASum(@base))))
return null;
var rewritten = Functions.SingleQuotient.Combine(expr.Replace(node => node == reciprocal ? 1 / function : node));
var rewritten = Functions.SingleQuotient.Combine(expr.Replace(node =>
node == reciprocal ? 1 / function
: AnEvenPower(node, complement) && node is Powf(_, Number.Integer { EInteger: var power })
? MathS.Pow(1 - MathS.Pow(function, 2), Number.Integer.Create(power / 2))
: node));
return Integration.ComputeAsTheSameQuestion(rewritten, x, integrateByParts);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// 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>
/// An even power of the sine beside a rational function of the secant, written in the cosine,
/// <c>sin(z)^(2k)</c> as <c>(1 - cos(z)^2)^k</c>: the half-angle substitution wrote Rubi's 4.5.1.3
/// <c>sin(c + d x)^2/(a + b sec(c + d x))</c> in 117,751 characters and past the corpus's budget,
/// where in the cosine it is a polynomial over a linear. The cosine beside the cosecant the same way.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AnEvenPowerOfTheSineBesideASecantIntegralTest
{
[Theory]
// Rubi 4.5.1.3:238.
[InlineData("sin(c + d*x)^2/(a + b*sec(c + d*x))")]
[InlineData("sin(x)^4/(a + b*sec(x))")]
[InlineData("cos(x)^2/(a + b*csc(x))")]
public void IsAnsweredInTheCosine(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
var text = integral.Stringize();
Assert.DoesNotContain("integral(", text);
Assert.True(text.Length < 3000, $"{integrand} came back in {text.Length} characters");
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7).Substitute("c", 0.4).Substitute("d", 0.9);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in new[] { -2.2, -0.9, 0.3, 1.4, 2.1 })
{
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