diff --git a/Sources/.editorconfig b/Sources/.editorconfig index 8edc021c0..33d0fddf9 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -57,6 +57,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Convenience/SpellingsAtRiskTest.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/APolynomialHasARootTest.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/Convenience/RoundIsExactTest.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/SolveStatement.cs b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/SolveStatement.cs index f743c0caa..a1fc46f63 100644 --- a/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/SolveStatement.cs +++ b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/SolveStatement.cs @@ -42,9 +42,32 @@ private static Entity Minus(Entity left, Entity right) /// equation as the caller wrote it. /// internal static Set WithoutSpuriousRoots(Set roots, Entity equation, Variable x) - => roots is FiniteSet finite && finite.Any(root => IsSpurious(equation, x, root)) - ? finite.Where(root => !IsSpurious(equation, x, root)).ToSet() - : roots; + { + if (roots is not FiniteSet finite || !finite.Any(root => IsSpurious(equation, x, root))) + return roots; + var kept = finite.Where(root => !IsSpurious(equation, x, root)).ToSet(); + // A polynomial of degree one or more has a root over the complex numbers, so where every + // candidate for one fails, what failed is the solver, and the empty set left would claim + // there is no root: (x + 1)^3 = 2 was { } while Cardano's C was 0 for a shifted cube, and + // 31x^4 - 62x^3 + 33x^2 - 2x - 1 = 0 while a biquadratic quartic was shifted by -b a / 4. + // Left unsolved instead, which says only that the roots were not found. + if (kept.Count == 0 && IsAPolynomialWithARoot(equation, x)) + return new ConditionalSet(x, equation is Minusf(var left, var right) ? left.Equalizes(right) : equation.Equalizes(0)); + return kept; + } + + /// + /// Whether is a polynomial in with numbers + /// for coefficients and a degree of one or more, read over the complex numbers, where such a + /// polynomial has a root. + /// + private static bool IsAPolynomialWithARoot(Entity equation, Variable x) + => MathS.Settings.Codomain.Value != Core.Domain.Real + && TreeAnalyzer.TryGetPolynomial(equation, x, out var monomials) + && monomials.Keys.All(power => power.Sign >= 0) + && monomials.Where(monomial => monomial.Key.Sign > 0) + .Any(monomial => monomial.Value.Evaled is Number.Complex { IsZero: false }) + && monomials.Values.All(coefficient => coefficient.Evaled is Number.Complex { IsFinite: true }); /// /// Answers the condition itself where a root denies the independence the calculus diff --git a/Sources/Tests/UnitTests/Algebra/SolveTest/APolynomialHasARootTest.cs b/Sources/Tests/UnitTests/Algebra/SolveTest/APolynomialHasARootTest.cs new file mode 100644 index 000000000..9b7179ba5 --- /dev/null +++ b/Sources/Tests/UnitTests/Algebra/SolveTest/APolynomialHasARootTest.cs @@ -0,0 +1,53 @@ +// +// 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 AngouriMath.Core; +using AngouriMath.Extensions; +using AngouriMath.Functions.Algebra.AnalyticalSolving; +using Xunit; +using static AngouriMath.Entity; +using static AngouriMath.Entity.Set; + +namespace AngouriMath.Tests.Algebra +{ + /// + /// A polynomial of degree one or more has a root over the complex numbers, so where every + /// candidate a solver found for one fails its check, the solver failed, and the empty set + /// would claim there is no root. (x + 1)^3 = 2 and + /// 31x^4 - 62x^3 + 33x^2 - 2x - 1 = 0 were answered { } that way. Asked here of + /// the check itself, with candidates that fail, since no polynomial reaches it so any more. + /// + [Trait("Area", "Algebra")] + public sealed class APolynomialHasARootTest + { + [Theory] + [InlineData("x^2 - 2")] + [InlineData("(x + 1)^3 - 2")] + [InlineData("31x^4 - 62x^3 + 33x^2 - 2x - 1")] + public void APolynomialWhoseCandidatesAllFailIsLeftUnsolved(string polynomial) + => Assert.IsType( + StatementSolver.WithoutSpuriousRoots(new FiniteSet((Entity)5, (Entity)7), polynomial.ToEntity(), "x")); + + /// The roots that hold are kept, as before. + [Fact] + public void TheRootsThatHoldAreKept() + => Assert.Equal("{ 2 }".ToEntity(), + StatementSolver.WithoutSpuriousRoots(new FiniteSet((Entity)2, (Entity)5), "x^2 - 4".ToEntity(), "x").InnerSimplified); + + /// + /// An equation that is not a polynomial can have no root, and its empty set is an answer: + /// sqrt(x) = -1. So can a polynomial over the reals: x^2 + 1 = 0. + /// + [Fact] + public void TheOthersCanHaveNoRoot() + { + Assert.Equal(Empty, StatementSolver.WithoutSpuriousRoots(new FiniteSet((Entity)1), "sqrt(x) + 1".ToEntity(), "x")); + using var _ = MathS.Settings.Codomain.Set(Domain.Real); + Assert.Equal(Empty, StatementSolver.WithoutSpuriousRoots(new FiniteSet((Entity)5), "x^2 + 1".ToEntity(), "x")); + } + } +}