diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 7a602ae02..eef54d33e 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -911,6 +911,20 @@ no value at `i`, where it is 1 ([#2256](https://github.com/asc-community/Angouri | `"x! = 0".ToEntity().Simplify()` | `False provided x in RR and (x >= 0 or not x in ZZ)` | `False provided x in ZZ implies x >= 0` | | `"x!".ToEntity().DomainCondition` | `x in RR and (x >= 0 or not x in ZZ)` | `x in ZZ implies x >= 0` | +### `am_series` keeps the power it is asked for + +**Silent: `am_series` and `Catalogue.Series` keep the powers up to the degree given, where they kept one fewer.** +The degree, documented as the highest power kept, was passed to `MathS.Series.Maclaurin` and `Taylor` as their +number of terms. So degree 1 gave the constant term alone, and linearising a model gave its value at the point. +`MathS.Series` is unchanged, and its documentation now says that its argument counts terms +([#2299](https://github.com/asc-community/AngouriMath/issues/2299)). + +| Input | Was (2.6.0) | Now | +|---|---|---| +| `am_series`, `sin(x)`, degree 7 | `x ^ 5 / 120 - x ^ 3 / 6 + x` | `x ^ 5 / 120 - x ^ 7 / 5040 - x ^ 3 / 6 + x` | +| `am_series`, `sin(x)`, degree 1 | `0` | `x` | +| `am_series`, `e^x`, degree 1 | `1` | `1 + x` | + ### A number's conjugate is made under the setting in force **Silent: `Complex.Conjugate` is made under the downcasting setting of the caller, where the first caller's setting was diff --git a/Sources/AngouriMath/Convenience/MathS.cs b/Sources/AngouriMath/Convenience/MathS.cs index 2cfee6d72..72a9eb5a8 100644 --- a/Sources/AngouriMath/Convenience/MathS.cs +++ b/Sources/AngouriMath/Convenience/MathS.cs @@ -2624,7 +2624,8 @@ public static class Series /// The function to find the Maclaurin expansion of /// /// - /// The degree of the resulting Maclaurin polynomial (and the variable in the resulting series) + /// The number of terms, one more than the highest power kept: 4 keeps the powers up to the + /// cube, as the example shows. https://github.com/asc-community/AngouriMath/issues/2299 /// /// /// The variable/s to take the series over (and the variable the series will be over) @@ -2711,7 +2712,8 @@ public static Entity Maclaurin(Entity expr, int degree, params Variable[] exprVa /// The function to find the Taylor expansion of /// /// - /// The degree of the resulting taylor polynomial + /// The number of terms, one more than the highest power kept: 4 keeps the powers up to the + /// cube, as the example shows. https://github.com/asc-community/AngouriMath/issues/2299 /// /// /// The variable/s to take the series over (and the variable in the resulting series), @@ -2799,7 +2801,8 @@ public static Entity Taylor(Entity expr, int degree, params (Variable exprVariab /// The function to find the Taylor expansion of /// /// - /// The degree of the resulting taylor polynomial + /// The number of terms, one more than the highest power kept: 4 keeps the powers up to the + /// cube, as the example shows. https://github.com/asc-community/AngouriMath/issues/2299 /// /// /// The variable/s to take the series over, the variable the series will be over, diff --git a/Sources/AngouriMath/Core/Operations/Catalogue.cs b/Sources/AngouriMath/Core/Operations/Catalogue.cs index 6dfb2e3a3..4390c8465 100644 --- a/Sources/AngouriMath/Core/Operations/Catalogue.cs +++ b/Sources/AngouriMath/Core/Operations/Catalogue.cs @@ -146,13 +146,15 @@ internal static class Catalogue /// /// , or - /// where there is no point. + /// where there is no point, + /// with one term more than the degree, since those count terms: sin(x) to degree 1 is + /// x, and was 0. https://github.com/asc-community/AngouriMath/issues/2299 /// public static Query> Series { get; } = new( "series", "Expands as a Taylor series in a variable, up to a degree, around a point or around zero.", static (e, variable, degree, around) => around is null - ? MathS.Series.Maclaurin(e, degree, variable) - : MathS.Series.Taylor(e, degree, (variable, around)), + ? MathS.Series.Maclaurin(e, degree + 1, variable) + : MathS.Series.Taylor(e, degree + 1, (variable, around)), TheVariable, new Parameter("degree", "The highest power kept."), new Parameter("around", "The point, or none for zero.")); // ---------------------------------------------------------------- queries on a number diff --git a/Sources/Tests/McpUnitTests/ToolsTest.cs b/Sources/Tests/McpUnitTests/ToolsTest.cs index c8fb608a5..7c57762ee 100644 --- a/Sources/Tests/McpUnitTests/ToolsTest.cs +++ b/Sources/Tests/McpUnitTests/ToolsTest.cs @@ -175,9 +175,14 @@ public void EigenvaluesHoldAtZeroToo() Assert.DoesNotContain("provided", answer.Field("eigenvalues")); } - [Fact] - public void Series() => - Assert.Equal("x ^ 5 / 120 - x ^ 3 / 6 + x", Mcp.Call("am_series", """{"expression":"sin(x)","variable":"x","degree":7}""").Field("result")); + // The degree is the highest power kept, x ^ 7 at 7. It was passed on as the number of terms, so + // degree 7 stopped at x ^ 5 and degree 1 was the constant. https://github.com/asc-community/AngouriMath/issues/2299 + [Theory] + [InlineData("sin(x)", 7, "x ^ 5 / 120 - x ^ 7 / 5040 - x ^ 3 / 6 + x")] + [InlineData("sin(x)", 1, "x")] + [InlineData("e^x", 1, "1 + x")] + public void Series(string expression, int degree, string expected) => + Assert.Equal(expected, Mcp.Call("am_series", $$"""{"expression":"{{expression}}","variable":"x","degree":{{degree}}}""").Field("result")); [Fact] public void Factorize() => diff --git a/Sources/Tests/UnitTests/Core/Operations/CatalogueTest.cs b/Sources/Tests/UnitTests/Core/Operations/CatalogueTest.cs index 288aa6743..996d6094f 100644 --- a/Sources/Tests/UnitTests/Core/Operations/CatalogueTest.cs +++ b/Sources/Tests/UnitTests/Core/Operations/CatalogueTest.cs @@ -171,6 +171,23 @@ public void AnEntryClaimsWhatItsTransformationClaims(Transformation transformati Assert.Equal(transformation.Relation, relation); } + /// + /// The series is taken to the degree asked for, which is the highest power it keeps. It + /// was passed on as the number of terms, one fewer: sin(x) to degree 1 was 0. + /// https://github.com/asc-community/AngouriMath/issues/2299 + /// + [Theory] + [InlineData("sin(x)", 1, null, "x")] + [InlineData("e^x", 1, null, "1 + x")] + [InlineData("sin(x)", 7, null, "x - x^3/6 + x^5/120 - x^7/5040")] + [InlineData("e^x", 2, "1", "e + e (x - 1) + e (x - 1)^2 / 2")] + [InlineData("cos(x)", 0, null, "1")] + public void ASeriesKeepsTheHighestPowerItIsAskedFor(string expression, int degree, string? around, string expected) + { + var series = Catalogue.Series.Ask(expression, MathS.Var("x"), degree, around is null ? null : MathS.FromString(around)); + Assert.Equal(Entity.Number.Integer.Zero, (series - MathS.FromString(expected)).Simplify()); + } + /// /// One answer from each entry, against the method the entry names, on an input where /// that method and its neighbours answer differently -- so that an entry holding the @@ -203,8 +220,8 @@ public void EachEntryAnswersAsTheMethodItNames() Assert.Equal(MathS.Boolean.BuildTruthTable("a and not b", "a", "b"), Catalogue.TruthTable.Ask("a and not b", [MathS.Var("a"), MathS.Var("b")])); Assert.Equal(MathS.SolveBooleanTable("a and not b", "a", "b"), Catalogue.SatisfyingAssignments.Ask("a and not b", [MathS.Var("a"), MathS.Var("b")])); Assert.NotEqual(Catalogue.TruthTable.Ask("a and not b", [MathS.Var("a"), MathS.Var("b")]), Catalogue.SatisfyingAssignments.Ask("a and not b", [MathS.Var("a"), MathS.Var("b")])); - Assert.Equal(MathS.Series.Maclaurin("e^x", 3, x), Catalogue.Series.Ask("e^x", x, 3, null)); - Assert.Equal(MathS.Series.Taylor("e^x", 3, (x, 1)), Catalogue.Series.Ask("e^x", x, 3, 1)); + Assert.Equal(MathS.Series.Maclaurin("e^x", 4, x), Catalogue.Series.Ask("e^x", x, 3, null)); + Assert.Equal(MathS.Series.Taylor("e^x", 4, (x, 1)), Catalogue.Series.Ask("e^x", x, 3, 1)); Assert.NotEqual(Catalogue.Series.Ask("e^x", x, 3, null), Catalogue.Series.Ask("e^x", x, 3, 1)); Assert.Equal(MathS.ToBaseN(10.5m, 2), Catalogue.ToBase.Ask(10.5m, 2));