Skip to content

Answer an identity equation with every value, not with none (#550) - #679

Merged
Happypig375 merged 1 commit into
ASC-Community:masterfrom
Rafael-SOWNet:fix/identity-equations
Aug 4, 2026
Merged

Happypig375 merged 1 commit into
ASC-Community:masterfrom
Rafael-SOWNet:fix/identity-equations

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Closes #550.

@Happypig375 — you said the null-returning line is the one to be fixed, so this is about that line and not about a 3x3 example. What follows is where the null comes from.

The line, and what reaches it

SolveSystem returns null when InSolveSystem hands back nothing. It gets nothing because an equation that has stopped constraining the variable is reported as having no solutions, when it has all of them.

"0 = 0".ToEntity().Solve("x")      // {  }    -- says no value satisfies it
"x - x = 0".ToEntity().Solve("x")  // { 0 }   -- says exactly one does

The second is a wrong answer rather than a missing one. GatherMonomialInformation collects x and -x into a single monomial of degree one whose coefficient is 1 + (-1), and nothing ever looks at that coefficient — so the equation is read as 1 * x and solved for the root 0.

That is what the report is about. Substituting one variable routinely leaves an equation that cancels away, and then:

MathS.Equations("x - y", "2 * x - 2 * y").Solve("x", "y")   // was [[0, 0]]

which is a solution but not the solution set — every x = y is one.

What this changes

Coefficients that evaluate to zero are dropped before the degree is read. When none is left the equation is an identity, and it is answered with C rather than the empty set. This also stops a cancelled leading term being counted towards the degree.

The branch that already knew about this now decides. It carried the comment in this case there is either 0 or +oo solutions and returned the empty set for both; it now looks at whether what is left is zero.

A free variable in a system gets a parameter instead of ending the search, the way sin(x) = 0 is already answered with n_1:

MathS.Equations("x - y", "2 * x - 2 * y").Solve("x", "y")           // [[t_1, t_1]]
MathS.Equations("x + y - 1", "2 * x + 2 * y - 2").Solve("x", "y")   // [[t_1, 1 - t_1]]

null now means what it says in the doc comment: there are no solutions. That is still the answer for a system that contradicts itself, e.g. { x + y - 1, x + y - 2 }.

What this does not change

A variable mentioned in no equation at all still ends in null, because dropping it leaves more equations than unknowns and the recursion is built on the two being equal. That belongs with #212 and I have not touched it here.

On the reported system

The 13-equation system in the report solves on master today — in both of the equation orders and both of the ways of writing the ninth equation that the reporter tried. TheReportedSystemSolvesWhicheverWayItIsWritten pins all four combinations, since a cosmetic rewrite deciding whether it solved is the complaint. It is a pin, not a demonstration of this fix; the nine tests that do fail without the change are marked below.

Verification

  • 25 new tests. 9 fail without this change (EveryValueSatisfiesAnIdentity x6, ARepeatedEquationLeavesAFreeParameter x3).
  • Parametric answers are verified by substituting the row back into the original equations and Simplifying the residual to exactly 0, so they hold for every value of the parameter rather than at a sample point.
  • 3905 unit tests, 0 failed. 127 F# tests, 0 failed. Both target frameworks build.
  • Solver corpus unchanged at 85/117, with 0 wrong answers, 0 errors and 0 timeouts — measured on master and on this branch with the same harness.
  • A property checker over 151 expressions (1320 checks) is clean.

An equation that puts no condition on the variable is satisfied by every value of
it. AngouriMath said the opposite in two different ways:

  (0 = 0).Solve(x)      gave {  }     -- no value satisfies it
  (x - x = 0).Solve(x)  gave { 0 }    -- exactly one does

The second is the more damaging of the two, because it is a wrong answer rather
than a missing one, and it is also where the reported symptom comes from. The
polynomial solver never checked whether a monomial's coefficient had cancelled,
so x - x was read as one times x, of degree one, with the root 0. A system that
happens to leave such an equation behind after substitution therefore came back
with a tuple that is a solution but not the solution set:

  { x - y = 0, 2x - 2y = 0 }.Solve(x, y)   gave  [[0, 0]]

Coefficients that evaluate to zero are now dropped before the degree is read.
When none is left the equation is an identity, and the solver says so with the
whole of C instead of the empty set. The same distinction is made where the
solver already knew it was there: the branch that gave up once the variable had
disappeared carried the comment "there is either 0 or +oo solutions" and returned
the empty set for both cases; it now decides which of the two it is.

A system whose equations no longer constrain a variable then has infinitely many
solutions, which is what the null return in SolveSystem was reporting as nothing
at all. It is now answered with a free parameter, the way the trigonometric
solvers already answer sin(x) = 0 with n_1:

  { x - y = 0, 2x - 2y = 0 }.Solve(x, y)      [[t_1, t_1]]
  { x + y - 1, 2x + 2y - 2 }.Solve(x, y)      [[t_1, 1 - t_1]]

null still means there are no solutions, which is the answer for a system that
contradicts itself.

The system in the report solves on master already, in all four combinations of
the two equation orders and the two ways of writing the ninth equation; a test
pins that, since a cosmetic rewrite deciding whether it solved is what was
reported. Nine of the twenty-five new tests fail without this change.

3905 unit tests and 127 F# tests pass, corpus unchanged at 85/117 with no wrong
answers, and the property checker's 1320 checks are clean.
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 85.71429% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.09%. Comparing base (90c00a8) to head (1985006).
⚠️ Report is 51 commits behind head on master.

Files with missing lines Patch % Lines
...ath/Functions/Continuous/Solvers/EquationSolver.cs 77.77% 1 Missing and 1 partial ⚠️
...Solvers/EquationSolver/AnalyticalEquationSolver.cs 75.00% 1 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #679      +/-   ##
==========================================
- Coverage   80.99%   80.09%   -0.90%     
==========================================
  Files         155      156       +1     
  Lines       13687    12652    -1035     
  Branches     1957     2069     +112     
==========================================
- Hits        11086    10134     -952     
+ Misses       1990     1921      -69     
+ Partials      611      597      -14     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Happypig375
Happypig375 merged commit 7cbdc3e into ASC-Community:master Aug 4, 2026
24 checks passed
@Rafael-SOWNet
Rafael-SOWNet deleted the fix/identity-equations branch August 4, 2026 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Equation system solver fails on simple case

3 participants