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
12 changes: 12 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,18 @@ of one argument in it reads a numeric slope and bounds the degree it writes. A s
| `"csc(a + b*x)^3*sin(2*a + 2*b*x)^7".ToEntity().Integrate("x")` | `integral(...)` | 127 characters |
| `"csc(a + b*x)*sin(2*a + 2*b*x)^8".ToEntity().Integrate("x")` | `integral(...)` | 134 characters |

### A cosecant of a double argument beside the argument is written as a product

**Answers where there were none.** `csc(2x) ln(tan(x))` was declined, Rubi's 4.7.7: the rule that writes
`sin(2A)` as `2 sin(A) cos(A)` beside functions of `A` declined any other function of `2A`. The cosecant is
`1/(2 sin(A) cos(A))`, one product as well, and is written so now, which leaves `ln(tan(x))` beside its derivative
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"csc(2*x)*ln(tan(x))".ToEntity().Integrate("x")` | `integral(...)` | `1/2 * ln(tan(x)) ^ 2 / 2` |
| `"csc(2*x)*ln(tan(x))^2".ToEntity().Integrate("x")` | `integral(...)` | `1/2 * ln(tan(x)) ^ 3 / 3` |

### A sine or a cosine of a shifted argument is written in the other

**Answers where there were none.** `sin(a + b x) sec(c + b x)^3` was declined, with the rest of Rubi's 4.7.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12968,9 +12968,11 @@ node is Powf(var @base, var power) && @base.ContainsNode(u)
}

/// <summary>
/// A sine of twice an argument beside functions of the argument, written as the product it is:
/// <c>sin(2A) = 2 sin(A) cos(A)</c>, so that every trigonometric function is of <c>A</c>.
/// <c>csc(a + b x)^3 sin(2a + 2b x)^7</c> is <c>2^7 sin(a + b x)^4 cos(a + b x)^7</c>.
/// A sine or a cosecant of twice an argument beside functions of the argument, written as the
/// product it is: <c>sin(2A) = 2 sin(A) cos(A)</c>, so that every trigonometric function is of
/// <c>A</c>. <c>csc(a + b x)^3 sin(2a + 2b x)^7</c> is <c>2^7 sin(a + b x)^4 cos(a + b x)^7</c>,
/// and <c>csc(2x) ln(tan(x))</c> is <c>ln(tan(x))/(2 sin(x) cos(x))</c>, which is
/// <c>ln(tan(x))</c> beside its derivative.
/// </summary>
/// <remarks>
/// The rule that writes multiples of one argument in it reads a numeric slope, and bounds the
Expand All @@ -12992,10 +12994,15 @@ node is Powf(var @base, var power) && @base.ContainsNode(u)
if (!TreeAnalyzer.TryGetPolyLinear(single, x, out var slope, out _) || slope.ContainsNode(x)
|| (twice - 2 * single).Expand().InnerSimplified.Evaled is not Number.Complex { IsZero: true })
continue;
// Only sines of the double, so that each is one product.
if (expr.Nodes.Any(node => node is Cosf or Tanf or Cotanf or Secantf or Cosecantf && node.DirectChildren.First() == twice))
// Only sines and cosecants of the double, so that each is one product.
if (expr.Nodes.Any(node => node is Cosf or Tanf or Cotanf or Secantf && node.DirectChildren.First() == twice))
return null;
var rewritten = expr.Replace(node => node is Sinf(var a) && a == twice ? 2 * MathS.Sin(single) * MathS.Cos(single) : node);
var rewritten = expr.Replace(node => node switch
{
Sinf(var a) when a == twice => 2 * MathS.Sin(single) * MathS.Cos(single),
Cosecantf(var a) when a == twice => 1 / (2 * MathS.Sin(single) * MathS.Cos(single)),
_ => node
});
return Integration.ComputeAsTheSameQuestion(rewritten, x, integrateByParts);
}
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// 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 cosecant of twice the argument beside functions of the argument, written as
/// <c>1/(2 sin cos)</c>: <c>csc(2x) ln(tan(x))</c> is <c>ln(tan(x))</c> beside its derivative.
/// Rubi's 4.7.7.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class ACosecantOfADoubleArgumentIntegralTest
{
[Theory]
[InlineData("csc(2*x)*ln(tan(x))", 200)]
[InlineData("csc(2*x)*ln(cot(x))", 200)]
[InlineData("csc(2*x)*ln(tan(x))^2", 200)]
[InlineData("csc(2*x)*ln(a*tan(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