Repository navigation
Expand file tree
/
Copy pathAFunctionOfTheReciprocalIntegralTest.cs
More file actions
79 lines (73 loc) · 3.29 KB
/
Copy pathAFunctionOfTheReciprocalIntegralTest.cs
File metadata and controls
79 lines (73 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//
// 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 trigonometric function of <c>a + b/x</c> beside a rational function, under <c>x = 1/u</c>:
/// <c>sin(c + d/x)/(e + f x)</c> is <c>-sin(c + d u)/(u (e u + f)) du</c>.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
/// <remarks>
/// Rubi's 4.1.12 <c>(a + b sin(c + d/x))^k/(e + f x)^m</c> were declined. Each answer is
/// differentiated back on both sides of 0.
/// </remarks>
[Trait("Area", "Calculus")]
public sealed class AFunctionOfTheReciprocalIntegralTest
{
private static void DifferentiatesBack(string integrand, double[] points, params (string, double)[] pins)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Assert.DoesNotContain("NaN", integral.Stringize());
var derivative = integral.Substitute("C", 0).Differentiate("x");
Entity original = integrand.ToEntity();
foreach (var (name, value) in pins)
{
derivative = derivative.Substitute(name, value);
original = original.Substitute(name, value);
}
var compared = 0;
foreach (var at in points)
{
var got = derivative.Substitute("x", at).EvalNumerical();
var want = original.Substitute("x", at).EvalNumerical();
if (got.IsNaN || want.IsNaN)
continue;
compared++;
var difference = Math.Abs((double)(got - want).RealPart)
+ Math.Abs((double)(got - want).ImaginaryPart);
var scale = Math.Max(1.0, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
Assert.True(difference / scale < 1e-8,
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, "
+ $"where the integrand is {want}");
}
Assert.True(compared >= 3,
$"only {compared} of {points.Length} points were comparable for {integrand}");
}
[Theory]
[InlineData("sin(c+d/x)/(e+f*x)")]
[InlineData("cos(c+d/x)/(e+f*x)^2")]
[InlineData("(a+b*sin(c+d/x))/(e+f*x)^3")]
[InlineData("(a+b*sin(c+d/x))^2/(e+f*x)")]
public void AFunctionOfAPlusBOverX(string integrand)
{
var points = new[] { -1.4, -0.3, 0.8, 2.25 };
DifferentiatesBack(integrand, points, ("a", 1.0 / 3), ("b", 2), ("c", 1.5), ("d", 1.25), ("e", 2), ("f", 3));
}
[Theory]
[InlineData("(c*e+d*e*x)^(1/3)*sin(a+b/(c+d*x)^(1/3))")]
[InlineData("sin(a+b/sqrt(c+d*x))/(e+f*x)")]
public void AFunctionOfAPlusBOverARootOfALinear(string integrand)
{
var points = new[] { -0.3, 0.8, 2.25 };
DifferentiatesBack(integrand, points, ("a", 1.0 / 3), ("b", 2), ("c", 1.5), ("d", 1.25), ("e", 2), ("f", 3));
}
}
}