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
16 changes: 16 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,22 @@ left ([#718](https://github.com/asc-community/AngouriMath/issues/718)).
| `"1/(a + b*cot(x) + c*csc(x))".ToEntity().Integrate("x")` | `integral(...)` | 2,738 characters |
| `"1/(a + c*sec(2*x + 1) + b*tan(2*x + 1))".ToEntity().Integrate("x")` | `integral(...)`; past 290 s on the unreleased master | 2,890 characters |

### A secant or a cosecant beside a power of a sum of them is read as a power of the cosine or the sine

**Answers where there were none.** `sec(x) sqrt(sec(x) + tan(x))` was declined, with the rest of Rubi's 4.7.7
that puts a secant beside a power of `sec + tan`: the rule that recognises a product of powers as a derivative
read `sec(x)` as a function of its own, not as `cos(x)^(-1)`, and the tangent substitution wrote an odd power of
the secant through the root of `1 + t^2` but not one of the cosecant. Both are read so now, and the integrand is
the derivative of a power of the sum
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sec(x)*sqrt(sec(x) + tan(x))".ToEntity().Integrate("x")` | `integral(...)` | `2 * sqrt(sec(x) + tan(x))` |
| `"csc(x)*sqrt(csc(x) + cot(x))".ToEntity().Integrate("x")` | `integral(...)` | `(-2) * sqrt(csc(x) + cotan(x))` |
| `"sec(a + b*x)*(sec(a + b*x) + tan(a + b*x))^c".ToEntity().Integrate("x")` | `integral(...)` | `1 / (b * c) * (sec(a + b * x) + tan(a + b * x)) ^ c` |
| `"sqrt(1 + tan(x))*csc(x)*sec(x)".ToEntity().Integrate("x")` | `integral(...)` | 94 characters |

### `a cos + i a sin` beside powers of the secant is written over the cosine

**Answers where there were none, and shorter ones.** `sec(c + d x)^5/(a cos(c + d x) + i a sin(c + d x))^2` was declined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11134,6 +11134,11 @@ static bool IsTwice(Entity argument, Entity.Variable x)
Secantf(var a) when a == x => sign * rootOfSecantSquared,
Powf(Secantf(var a), Number.Integer k) when a == x && k.EInteger.CanFitInInt32() && !k.EInteger.IsEven
=> MathS.Pow(sign * rootOfSecantSquared, k),
// And the cosecant the sine: `sqrt(1 + tan(x)) csc(x) sec(x)` is
// `sqrt(1 + u) (1 + u^2)/u`, the two signs one.
Cosecantf(var a) when a == x => sign * rootOfSecantSquared / tangent,
Powf(Cosecantf(var a), Number.Integer k) when a == x && k.EInteger.CanFitInInt32() && !k.EInteger.IsEven
=> MathS.Pow(sign * rootOfSecantSquared / tangent, k),
_ => node,
}).Substitute(tangent, uSub);
if (odd.ContainsNode(x) || !IsAlgebraicIn(odd, uSub))
Expand Down Expand Up @@ -14097,8 +14102,20 @@ static bool More(Entity difference)
var raisable = new List<(Entity Base, Entity Exponent)>();
var logarithmicDerivativesKept = new List<Entity>();
Entity kept = Number.Integer.One;
foreach (var (factor, underneath) in FactorsOfTheIntegrand(expr))
{
foreach (var (written, writtenUnderneath) in FactorsOfTheIntegrand(expr))
{
// A secant is a power of the cosine, and a cosecant of the sine, below the bar,
// where raising it by one takes it out of the candidate: `sec(x) sqrt(sec(x) + tan(x))`
// is `(2 sqrt(sec(x) + tan(x)))'`, and read as a power of the secant it could
// only be raised to a square.
var (factor, underneath) = written switch
{
Secantf(var a) => (MathS.Cos(a), !writtenUnderneath),
Cosecantf(var a) => (MathS.Sin(a), !writtenUnderneath),
Powf(Secantf(var a), var p) when !p.ContainsNode(x) => (MathS.Pow(MathS.Cos(a), p), !writtenUnderneath),
Powf(Cosecantf(var a), var p) when !p.ContainsNode(x) => (MathS.Pow(MathS.Sin(a), p), !writtenUnderneath),
_ => (written, writtenUnderneath)
};
if (!factor.ContainsNode(x))
{
constant = underneath ? constant / factor : constant * factor;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// 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 secant or a cosecant beside a root, read as the cosine or the sine the other way up:
/// <c>sec(x) sqrt(sec(x) + tan(x))</c> is <c>(2 sqrt(sec(x) + tan(x)))'</c>, and
/// <c>sqrt(1 + tan(x)) csc(x) sec(x)</c> is a function of the tangent. Rubi's 4.7.7.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class ASecantOrACosecantBesideARootIntegralTest
{
[Theory]
[InlineData("sec(x)*sqrt(sec(x) + tan(x))", 100)]
[InlineData("sec(x)*sqrt(sec(x) - tan(x))", 100)]
[InlineData("csc(x)*sqrt(csc(x) + cot(x))", 100)]
[InlineData("sec(a + b*x)*(sec(a + b*x) + tan(a + b*x))^c", 200)]
[InlineData("sqrt(1 + tan(x))*csc(x)*sec(x)", 400)]
public void DifferentiatesBack(string integrand, int atMost)
{
var integral = integrand.ToEntity().Integrate("x");
var text = integral.Stringize();
Assert.DoesNotContain("integral(", text);
Assert.True(text.Length < atMost, $"{text.Length} characters of answer for {integrand}");
Entity Pinned(Entity e) => e.Substitute("a", 2).Substitute("b", 3).Substitute("c", "5/4".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