diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index e11efd135..5fe39349e 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -72,6 +72,18 @@ one inside another was answered with the empty set, a claim that it has no solut | `"1/(2 + p^(-3)) = 1/3".Solve("p")` | `{ }` | `{ 1, -1/2 + i * 1/2 * sqrt(3), -1/2 + i * -1/2 * sqrt(3) }` | | `"1/(1 + x^(-2)) = y".Solve("x")` | `{ }` | `{ ((-1) / (-y) - 1) ^ (-1/2), -((-1) / (-y) - 1) ^ (-1/2) }` | +### A quartic that is biquadratic once depressed is solved + +**Silent: a quartic whose depressed form `y^4 + alpha y^2 + gamma`, for `y = x + b/(4a)`, has no cubic term is solved, +where it was answered `{ }`.** Its roots were shifted back by `-b a / 4` where the shift is `-b/(4a)`, so with a leading +coefficient other than `1` or `-1` every candidate was off and failed its check, and the empty set claimed there was no +root. An equation in a square root whose squared form is such a quartic was answered `{ }` with it. + +| Input | Was (2.6.0) | Now | +|---|---|---| +| `"31x^4 - 62x^3 + 33x^2 - 2x - 1 = 0".ToEntity().Solve("x")` | `{ }` | `{ 1/2 + -sqrt((27/62 + -8/31 * sqrt(2)) / 2), … }`, four real roots | +| `"x^2 - x - 1 = 4x*sqrt(2x^2 - 4x + 2)".ToEntity().Solve("x")` | `{ }` | `{ 1/2 + -sqrt((27/62 + 8/31 * sqrt(2)) / 2) }` | + ### A quotient of logarithms is differentiated only where both diverge **Silent: a limit of a quotient of logarithms whose divisor tends to 0 is no longer answered by l'Hopital's rule, which diff --git a/Sources/.editorconfig b/Sources/.editorconfig index 8edc021c0..ece1ed53a 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -102,6 +102,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Algebra/ExponentialTwoBasesTest.cs] file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n +[Tests/UnitTests/Algebra/SolveTest/ADepressedBiquadraticQuarticTest.cs] +file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n + [Tests/UnitTests/Algebra/OneByOneMatrixTest.cs] file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n diff --git a/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/PolynomialSolver.cs b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/PolynomialSolver.cs index 9f273c0d6..6e0a235f4 100644 --- a/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/PolynomialSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/PolynomialSolver.cs @@ -268,9 +268,14 @@ internal static IEnumerable SolveQuartic(Entity a, Entity b, Entity c, E var gamma = (-3 * MathS.Pow(b, 4) / (256 * MathS.Pow(a, 4)) + MathS.Sqr(b) * c / (16 * MathS.Pow(a, 3)) - (b * d) / (4 * MathS.Sqr(a)) + e / a) .InnerSimplified; + // Biquadratic once depressed: y^4 + alpha y^2 + gamma = 0 for y = x + b/(4a), so x is + // the root of the quadratic in y^2 shifted back by b/(4a). The shift was written + // -b / 4 * a, which is -b a / 4, and for a leading coefficient other than 1 or -1 every + // candidate was off and failed its check: 31x^4 - 62x^3 + 33x^2 - 2x - 1 = 0, with four + // real roots, was answered { }. if (beta.Evaled == 0) return sqrtsOf1.SelectMany(_ => sqrtsOf1, - (s, t) => -b / 4 * a + s * MathS.Sqrt((-alpha + t * MathS.Sqrt(MathS.Sqr(alpha) - 4 * gamma)) / 2)); + (s, t) => -b / (4 * a) + s * MathS.Sqrt((-alpha + t * MathS.Sqrt(MathS.Sqr(alpha) - 4 * gamma)) / 2)); var oneThird = Rational.Create(1, 3); var P = (-MathS.Sqr(alpha) / 12 - gamma) diff --git a/Sources/Tests/UnitTests/Algebra/SolveTest/ADepressedBiquadraticQuarticTest.cs b/Sources/Tests/UnitTests/Algebra/SolveTest/ADepressedBiquadraticQuarticTest.cs new file mode 100644 index 000000000..08705303d --- /dev/null +++ b/Sources/Tests/UnitTests/Algebra/SolveTest/ADepressedBiquadraticQuarticTest.cs @@ -0,0 +1,63 @@ +// +// 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.Linq; +using AngouriMath.Extensions; +using Xunit; +using static AngouriMath.Entity; +using static AngouriMath.Entity.Set; + +namespace AngouriMath.Tests.Algebra +{ + /// + /// A quartic whose depressed form y^4 + alpha y^2 + gamma, for y = x + b/(4a), has + /// no cubic term is solved as a quadratic in y^2 and shifted back by b/(4a). The + /// shift was written -b / 4 * a, which is -a b / 4, so with a leading coefficient + /// other than 1 or -1 every candidate was off and failed its check, and the quartic was + /// answered { }. Found by a cross-check of equations in square roots, whose squared + /// forms are such quartics; no issue was filed. + /// + [Trait("Area", "Algebra")] + public sealed class ADepressedBiquadraticQuarticTest + { + private static void AssertRoots(string equation, params string[] roots) + { + var answer = Assert.IsType(equation.ToEntity().Solve("x")); + Assert.Equal(roots.Length, answer.Count); + foreach (var root in roots) + Assert.Contains(answer, found => Number.IsZero((found - root.ToEntity()).EvalNumerical())); + } + + /// Irreducible over the rationals, so that no factoring answers it first. + [Fact] + public void FourRealRoots() + => AssertRoots("31x^4 - 62x^3 + 33x^2 - 2x - 1 = 0", + "1/2 + sqrt((27/62 + 8/31 * sqrt(2)) / 2)", "1/2 - sqrt((27/62 + 8/31 * sqrt(2)) / 2)", + "1/2 + sqrt((27/62 - 8/31 * sqrt(2)) / 2)", "1/2 - sqrt((27/62 - 8/31 * sqrt(2)) / 2)"); + + /// 2(x - 1)^4 - 2(x - 1)^2 - 1: two real roots and two that are not. + [Fact] + public void TwoRealRootsAndTwoComplex() + => AssertRoots("2x^4 - 8x^3 + 10x^2 - 4x - 1 = 0", + "1 + sqrt((1 + sqrt(3)) / 2)", "1 - sqrt((1 + sqrt(3)) / 2)", + "1 + sqrt((1 - sqrt(3)) / 2)", "1 - sqrt((1 - sqrt(3)) / 2)"); + + /// + /// Equations in a square root whose squared form is such a quartic, each answered + /// { }. The first has the one real root its squaring keeps; the second, four + /// complex ones. + /// + [Fact] + public void TheEquationsInARootWhoseSquareIsOne() + { + AssertRoots("x^2 - x - 1 = 4x * sqrt(2x^2 - 4x + 2)", "(1 - sqrt(1 + 4 / (1 + 4 * sqrt(2)))) / 2"); + AssertRoots("(2x^2 + 4x - 2) / sqrt(-2x - x^2) = -2", + "-1 + sqrt((3 + sqrt(-3)) / 2)", "-1 - sqrt((3 + sqrt(-3)) / 2)", + "-1 + sqrt((3 - sqrt(-3)) / 2)", "-1 - sqrt((3 - sqrt(-3)) / 2)"); + } + } +}