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
Original file line number Diff line number Diff line change
Expand Up @@ -2821,7 +2821,10 @@ private static bool TryReadAHomogeneousTrigonometricPolynomial(

var found = (Entity?)null;
var theDegree = (int?)null;
foreach (var term in Entity.Sumf.LinearChildren(expr.Expand()))
// The terms with their degrees, for the parity case below.
var terms = new List<(Entity Term, int Degree)>();
var expanded = expr.Expand();
foreach (var term in Entity.Sumf.LinearChildren(expanded))
{
var thisDegree = 0;
foreach (var factor in Entity.Mulf.LinearChildren(term))
Expand All @@ -2848,10 +2851,11 @@ private static bool TryReadAHomogeneousTrigonometricPolynomial(
break;
}
}
terms.Add((term, thisDegree));
if (theDegree is null)
theDegree = thisDegree;
else if (theDegree != thisDegree)
return false;
theDegree = -1; // not homogeneous as written; the parity case below
}
if (theDegree is null)
return false;
Expand All @@ -2863,9 +2867,31 @@ private static bool TryReadAHomogeneousTrigonometricPolynomial(
return !expr.ContainsNode(x);
}

degree = theDegree.Value;
// **Homogeneous up to parity is homogeneous**: a term two degrees short of the
// highest is the same term times `sin^2 + cos^2`, which is one. `sin + sin^2 cos`
// has degrees one and three and is `sin (sin^2 + cos^2) + sin^2 cos`, of degree
// three throughout; it is what `cos(x)/(sin(x)(2 + sin(2x)))` has below the bar once
// its arguments are unified, and it was declined here for the spelling. A term an
// odd number short is a genuine boundary -- no power of one bridges it.
var highest = terms.Max(pair => pair.Degree);
if (theDegree == -1)
{
if (terms.Any(pair => (highest - pair.Degree) % 2 != 0))
return false;
var pythagorean = MathS.Sqr(MathS.Sin(found)) + MathS.Sqr(MathS.Cos(found));
Entity raised = Number.Integer.Zero;
foreach (var (term, thisDegree) in terms)
{
var levels = (highest - thisDegree) / 2;
var lifted = levels == 0 ? term : term * MathS.Pow(pythagorean, levels);
raised = raised == Number.Integer.Zero ? lifted : raised + lifted;
}
expanded = raised.Expand();
}

degree = highest;
argument = found;
rewritten = expr.Expand().Replace(node => node switch
rewritten = expanded.Replace(node => node switch
{
Sinf(var a) when a == found => HomogeneousTangent * HomogeneousCosine,
Cosf(var a) when a == found => HomogeneousCosine,
Expand Down
23 changes: 20 additions & 3 deletions Sources/Tests/UnitTests/Calculus/HomogeneousTrigonometricTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,26 @@ public void ALinearArgument(string integrand, double[] points)
=> DifferentiatesBack(integrand, points);

/// <summary>
/// What the read must refuse: a polynomial that is not homogeneous, and a degree
/// difference that is odd — there the substitution leaves a square root of <c>1 + t^2</c>
/// behind, which is a different problem.
/// Homogeneous up to parity is homogeneous: a term two degrees short of the highest is
/// the same term times <c>sin^2 + cos^2</c>, which is one. <c>sin + sin^2 cos</c> has
/// degrees one and three and is <c>sin (sin^2 + cos^2) + sin^2 cos</c>, of degree three
/// throughout; it is what Timofeev's <c>cos(x)/(sin(x)(2 + sin(2x)))</c> has below the
/// bar once its arguments are unified, and it was declined for the spelling.
/// </summary>
[Theory]
[InlineData("cos(x)/(sin(x) + sin(x)^2*cos(x))", new[] { 0.3, 0.8, 1.2, 2.0 })]
[InlineData("cos(x)/(sin(x)*(2 + sin(2*x)))", new[] { 0.3, 0.8, 1.2, 2.0 })]
[InlineData("1/(1 + sin(x)^2)", new[] { 0.3, 0.8, 1.2, -0.5 })]
[InlineData("(1 + sin(x)^2)/(1 + cos(x)^2)", new[] { 0.3, 0.8, 1.2, -0.5 })]
[InlineData("1/(sin(x)^2 + 2*sin(x)*cos(x))", new[] { 0.3, 0.8, 1.2, 2.0 })]
public void HomogeneousUpToParity(string integrand, double[] points)
=> DifferentiatesBack(integrand, points);

/// <summary>
/// What the read must refuse: a polynomial whose degrees differ by an odd number, which
/// no power of <c>sin^2 + cos^2</c> bridges, and a degree difference that is odd — there
/// the substitution leaves a square root of <c>1 + t^2</c> behind, which is a different
/// problem.
/// </summary>
[Theory]
[InlineData("1/(1 + cos(x))", new[] { 0.3, 0.8, 1.2, -0.5 })]
Expand Down
Loading