From 6477079499e859fbfe7eef02f5fd4b9c5cff7f30 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sun, 1 Nov 2026 16:38:08 +0000 Subject: [PATCH] A polynomial is not answered with no roots Every root a solver finds is put back into the equation as written, and the ones that fail are dropped. Where all of them failed, the empty set was left, and the empty set claims there is no root. For a polynomial of degree one or more, read over the complex numbers, that is never true, so what failed was the solver: (x + 1)^3 = 2 came back { } while Cardano's C was 0 for a shifted cube (#2315), and 31x^4 - 62x^3 + 33x^2 - 2x - 1 = 0 while a biquadratic quartic was shifted by -b a / 4 (#2314). Such a polynomial is now left as the set of the x that satisfy it, which claims only that its roots were not found. Only a polynomial with numbers for coefficients and over the complex numbers: an equation that is not a polynomial can have no root, as sqrt(x) = -1 has none, and so can a polynomial over the reals. With those two fixed, no equation known reaches this, so nothing answered changes. Co-Authored-By: Claude Opus 5.5 (1M context) --- Sources/.editorconfig | 3 ++ .../Solvers/EquationSolver/SolveStatement.cs | 29 ++++++++-- .../SolveTest/APolynomialHasARootTest.cs | 53 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 Sources/Tests/UnitTests/Algebra/SolveTest/APolynomialHasARootTest.cs 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")); + } + } +}