Skip to content

Over the complex numbers, an equation in and out of a modulus is solved in the parts of x - #2309

Merged
Rafael-SOWNet merged 2 commits into
masterfrom
an-equation-in-and-out-of-a-modulus-is-solved-over-the-complex-numbers
Nov 1, 2026
Merged

Rafael-SOWNet merged 2 commits into
masterfrom
an-equation-in-and-out-of-a-modulus-is-solved-over-the-complex-numbers

Conversation

@Rafael-SOWNet

@Rafael-SOWNet Rafael-SOWNet commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

#2307 left these equations unsolved over the complex numbers, and as Happypig375 said there, that isn't solving them. This solves them exactly.

With x = a + b i and each |u| a real t ≥ 0 with t^2 = (Re u)^2 + (Im u)^2, the equation's real and imaginary parts and one equation per modulus make a polynomial system in as many unknowns. The Gröbner solver (#2127) answers it exactly and completely, or not at all. The roots are its solutions with a, b and every t real and no t negative.

  • conj, Re and Im split directly.
  • sgn(u) is u/|u| where u ≠ 0, and the case u = 0 is solved on its own.
Solve("x") 2.6.0 master (#2307) now
x^2/abs(1-x^2) = x { 0, 0.618…, 1.618…, 1.618… + 1.7E-9i, 1.618… + 9.9E-8i } unsolved { 0, (1 + sqrt(5)) / 2, (sqrt(5) - 1) / 2 }
abs(x^2 - 4) = 3x { 1, 4, 4.0000000000000062… + 1.6E-7i } unsolved { 1, 4 }
1/abs(x) = x^2 { -1, 1 } and six near-copies unsolved { 1, -1 }
x * abs(x) = 4 { 2 } unsolved { 2 }
x + sgn(x) = 3 { 2 } unsolved { 2 }
x^2 + 1 = abs(x) unsolved unsolved { ±i (sqrt(5) - 1) / 2 }
conj(x) = x^2 conj read as a variable unsolved { 0, 1, -1/2 ± i sqrt(3) / 2 }
  • Still left unsolved:
    • infinitely many solutions: |x| = Re x, a ray;
    • roots with no exact form: x^5 = |x| + 1, whose roots have modulus the real root of r^5 - r - 1;
    • anything with arg;
    • a system with more than 32 solutions by Bézout's bound.
  • The bound is a cost guard. x^7 = |x| + 1 ran past 20 s before declining, and every case solved here is at 24 or below. The slowest decline within the bound was 1.9 s (x^4 = |x| + 1).
  • It runs once per equation, on the equation as asked and before the spelling loop. Every spelling gives the same system, and run once per spelling, x^5 = |x^3 + 1| + 1 asked it dozens of times.
  • The test that picks these equations out costs nothing elsewhere. It runs on every equation, and enumerating Nodes for it added 4.5 MB (45%) to the kernel benchmark's SolveHard, which CI's Benchmark job caught. It now walks DirectChildren by hand, and SolveHard allocates 187,558,968 bytes per solve on master and on the branch.
  • Cross-checked against a 2-D Newton search (mpmath, 169 starting points each) on two batches of 300 random equations in abs, sgn, conj, Re and Im of polynomials. It solved 199 and 190, and every root it answered is a root. The search found no root missing from any answer. The one point it flagged in each batch is where the equation has no value: 0/0 at 0, approached along a line.
  • What it costs. On the second batch, run beside a chain, the median Solve is 35 ms, the 90th percentile 0.46 s and the slowest 3.1 s. The slow ones are mostly declines of a quotient by the modulus of a complex quadratic, where the roots can't be proved exactly. master (Over the complex numbers, an equation in and out of a modulus is left unsolved #2307) leaves all of these unsolved at once.
  • Twelve of the new cases fail on master. The suite, the trio, F#, AOT and the eight harnesses pass. The BREAKING-CHANGES.md entry from Over the complex numbers, an equation in and out of a modulus is left unsolved #2307 is rewritten as the change from 2.6.0.

Follows #2307, for #2139.

🤖 Generated with Claude Code

…ed in the parts of x

#2307 left an equation with x inside abs, sgn, conj, Re, Im or arg and outside it too
unsolved over the complex numbers, since Newton's method assumes a holomorphic function
and its near-copies of a root came back as roots. Leaving it unsolved is not solving it.

With x = a + b i and each |u| a real t >= 0 with t^2 = (Re u)^2 + (Im u)^2, the real and
imaginary parts of the equation and one equation per modulus are a polynomial system in
as many unknowns, which the Groebner solver answers exactly and completely or not at
all. The roots are its solutions with a, b and every t real and no t negative, each put
back into the equation as written, since clearing the denominators can add a pole.
conj, Re and Im split directly. sgn(u) is u/|u| where u is not zero, and the case where
it is zero is solved on its own.

x^2/|1 - x^2| = x is { 0, (1 + sqrt(5))/2, (sqrt(5) - 1)/2 }, x |x| = 4 is { 2 },
x + sgn(x) = 3 is { 2 } again, and x^2 + 1 = |x| is +-i (sqrt(5) - 1)/2, which neither
the search nor a split by the sign found. Left unsolved: infinitely many solutions
(|x| = Re x), roots with no exact form (x^5 = |x| + 1), arg, and a system above 32
solutions by Bezout's bound, past which x^7 = |x| + 1 spent over 20 s declining.

The route runs once, on the equation as asked and ahead of the spelling loop, whose
spellings would each be the same system: asked of every one, x^5 = |x^3 + 1| + 1 ran
it dozens of times.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.54762% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.75%. Comparing base (df991d3) to head (b192ae0).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...Continuous/Solvers/EquationSolver/ModulusSolver.cs 80.62% 11 Missing and 20 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2309      +/-   ##
==========================================
- Coverage   86.78%   86.75%   -0.03%     
==========================================
  Files         311      311              
  Lines       68032    68199     +167     
  Branches    19763    19821      +58     
==========================================
+ Hits        59039    59164     +125     
- Misses       4872     4893      +21     
- Partials     4121     4142      +21     
Flag Coverage Δ
cpp 37.77% <ø> (ø)
csharp 87.29% <81.54%> (-0.04%) ⬇️
fsharp 32.97% <ø> (ø)
interactive 40.72% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...ions/Algebra/Polynomials/MultivariatePolynomial.cs 91.30% <100.00%> (+0.11%) ⬆️
...Solvers/EquationSolver/AnalyticalEquationSolver.cs 96.40% <100.00%> (+0.10%) ⬆️
...Continuous/Solvers/EquationSolver/ModulusSolver.cs 78.57% <80.62%> (+3.88%) ⬆️

... and 6 files with indirect coverage changes

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

It is asked of every equation the solver is given, ahead of the spelling loop. Enumerating
Nodes allocates an iterator at each level, and that was 4.5 MB of the kernel benchmark's
SolveHard, 45% of it, which has no modulus in it. The walk allocates nothing: SolveHard
allocates 187,558,968 bytes per solve on master and on the branch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Rafael-SOWNet
Rafael-SOWNet merged commit a1fb7ae into master Nov 1, 2026
35 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in AngouriMath Nov 1, 2026
@Rafael-SOWNet
Rafael-SOWNet deleted the an-equation-in-and-out-of-a-modulus-is-solved-over-the-complex-numbers branch November 1, 2026 14:24
@Happypig375

Copy link
Copy Markdown
Member

Should simplification of a conditional set like this call solve?

@Rafael-SOWNet

Copy link
Copy Markdown
Member Author

Not as Solve stands, I think. Simplify has to keep the value, and some of Solve's answers are only what Newton's search found. On 400 random equations in logarithms, master's answers missed 25 roots across 22 of them (#2316 fixes that class). Simplifying { x : … } to such an answer would change the set. At the moment Simplify leaves every conditional set alone, even { x : x^2 = 4 }.

It would be sound for the routes that are complete by construction: polynomials, the Gröbner route here, and the exponentiated logarithms in #2316. That needs Solve to say which kind of answer it gave. Cost is the other half: Simplify runs everywhere, and a decline here can take a few seconds. Want me to open an issue for "Solve reports whether its answer is complete, and Simplify solves a conditional set where it is"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants