From 8b5e96e21a316e0036eaaf33326466b2b5d293b8 Mon Sep 17 00:00:00 2001 From: tylerjarvis Date: Tue, 22 Sep 2026 11:54:13 -0600 Subject: [PATCH 1/3] Update landing page: software citation, repo links, solver references - Cite section now leads with a @software BibTeX entry for yroots (and instructions for citing yroots-serial/jroots), demoting the algorithm paper to a secondary "Algorithm" reference. - Repoint all GitHub/Colab links from wlgns0330 to tylerjarvis. - Add functioning links for Bertini, MTV, and Chebfun2 in the method table and benchmark solver chips. Co-Authored-By: Claude Sonnet 5 --- docs/landing/index.html | 91 +++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/docs/landing/index.html b/docs/landing/index.html index ad76b382..235d4941 100644 --- a/docs/landing/index.html +++ b/docs/landing/index.html @@ -258,6 +258,10 @@ font-family:var(--mono); font-size:11.5px; color:var(--muted); border:1px solid var(--hair); border-radius:99px; padding:5px 12px; } + a.chip{text-decoration:none; transition:color .2s, border-color .2s;} + a.chip:hover{color:var(--accent-y); border-color:var(--accent-y);} + .solver-link{color:inherit; text-decoration:underline; text-decoration-color:var(--hair); text-underline-offset:3px; transition:color .2s, text-decoration-color .2s;} + .solver-link:hover{color:var(--accent-y); text-decoration-color:var(--accent-y);} /* ---------- about / thanks ---------- */ .thanks{ @@ -308,9 +312,9 @@ @@ -321,11 +325,11 @@
-
Numerical rootfinding suite · Rn → {0}
-

Find every root in the box.
Prove there's nothing left out.

-

Yroots locates all real roots of smooth multivariate systems inside a compact search interval — no initial guess, no missed solutions, just the box and the functions. The same algorithm ships three ways: two Python editions and jroots, the Julia port.

+
Numerical rootfinding suite · Rn → R
+

Find every real root of a system of equations.

+

Yroots locates all real roots inside a compact search interval of a multivariate system of smooth equations. No need for initial guesses, no missed solutions. It only requires the interval and the functions. The same algorithm is implemented three ways: two Python editions (parallel and serial) and a Julia port jroots.

- Try yroots in your browser ↗ + Try yroots in your browser ↗ Opens the tutorial notebook on Google Colab. Single-threaded edition, nothing to install.
@@ -345,15 +349,15 @@

Find every root in the box.
Prove there's nothing left out.

Algorithm
-

Chebyshev subdivision, not homotopy or elimination.

-

Rootfinders for this problem tend to fall into one of three families: homotopy continuation methods that track paths from a related system with known solutions, eigenvalue methods built on Möller–Stetter matrices, and resultant-based methods that eliminate variables one pair at a time. Yroots takes a fourth route — it builds a Chebyshev interpolant of each function, then repeatedly subdivides and shrinks the search box using properties specific to the Chebyshev basis. Near a simple zero, the interval is proven to shrink quadratically.

+

Chebyshev subdivision.

+

Rootfinders for this problem commonly fall into several broad families, including homotopy continuation methods that track paths from a related system with known solutions, eigenvalue methods based on Möller–Stetter multiplication matrices, and methods that eliminate variables to reduce the system to lower-dimensional problems. Yroots uses a branch-and-bound approach: it builds a Chebyshev interpolant of each function, then repeatedly subdivides and shrinks the search interval using properties specific to the Chebyshev basis. Near a simple zero, the interval is proven to shrink quadratically.

- - - - + + + +
Method classRepresentative solverApproach
Homotopy continuationBertiniTrack paths from a related system with known roots
Eigenvalue-basedMöller–StetterRecast rootfinding as an eigenvalue problem
Resultant-basedChebfun2Eliminate variables one pair at a time
Chebyshev subdivisionyroots / jrootsSubdivide and shrink the box using Chebyshev basis properties
Homotopy continuationBertini, PHCpackTrack paths from a related system with known roots
Eigenvalue-basedMourrain-Telen-vanBarel (MTV)Recast rootfinding as an eigenvalue problem
Dimension ReductionChebfun2, ReduceEliminate variables to reduce dimension
Chebyshev subdivisionyroots / jrootsSubdivide and shrink an interval using Chebyshev basis properties
@@ -367,7 +371,10 @@

Chebyshev subdivision, not homotopy or elimination.

Benchmark.

-

Every solver runs on the same three families of systems. Dense systems are randomly generated with every coefficient populated up to a given degree, across dimensions 2–5. Sparse systems keep only a small, fixed number of nonzero terms per polynomial — that sparsity is what makes dimensions up to 8 tractable at all. Chebfun isn't randomly generated — it's a fixed set of hand-picked, harder bivariate systems (curves with cusps, near-tangencies, clustered roots), run specifically to compare against Chebfun2, which only handles two dimensions. Data pulled live from tylerjarvis/rootfinding_testing.

+

+ We benchmarked our solvers (YRoots and JRoots) against the Mourrain–Telen–vanBarel truncated normal form solver (MTV); Bertini; Mathematica's NSolveValues (a hybrid solver, which uses a combination of different methods; Mathematica's Reduce, which uses cylindrical algebraic decomposition to reduce the dimension of the problem; and ChebFun2, which uses a combination of Chebyshev approximation, interval subdivision, and resultants. Of these, MTV and Bertini work only with polynomial systems, and ChebFun2 only works in two dimensions.

+ +

Each solver is benchmarked on the same three families of systems. Dense systems are randomly generated systems of polynomials with every coefficient populated up to a given degree, across dimensions 2 through 5. Sparse systems are also polynomial and keep only a small, fixed number of nonzero terms per polynomial. That sparsity makes higher dimensions tractable. Our tests go up to dimension 8. Chebfun test suite is a fixed set of harder bivariate systems (curves with cusps, near-tangencies, clustered roots), hand picked by the ChebFun2 development team. The results here are pulled live from tylerjarvis/rootfinding_testing.

@@ -391,11 +398,11 @@

Benchmark.

yroots jroots - MTV - Bertini + MTV + Bertini NSolveValues Reduce - Chebfun + Chebfun Croots Lambda variants
@@ -407,7 +414,7 @@

Benchmark.

Three implementations, one algorithm

Pick the engine that fits your system.

-

All three solve the same problem — zeros of n smooth functions in n variables over a compact box. The two Python editions differ only in whether the subdivision runs across threads; jroots is the Julia port. The benchmark above is where yroots and jroots are run side by side against solvers like Bertini, Chebfun and NSolve.

+

All three implementations use the same basic algorithm to solve the same problem (zeros of n smooth functions in n variables over a compact interval. The two Python editions differ only in whether the subdivision runs in parallel across threads; and jroots is the Julia port.

@@ -415,20 +422,21 @@

Pick the engine that fits your system.

Python · parallel

yroots

-

Uses Chebyshev polynomial approximation to subdivide the search box and isolate roots to machine precision. Guaranteed to find every root as long as the system is smooth, continuous, and has finitely many simple zeros in the interval. Subdivided regions are handed to a worker pool, which is why it wants the free-threaded build.

+

Uses Chebyshev polynomial approximation to subdivide the search interval and isolate roots to machine precision. Finds every root as long as the system is smooth, continuous, has finitely many roots in the interval, and each root is simple. If the roots are not simple (the Jacobian is singular) then the rootfinding problem is ill-conditioned and no algorithm can be expected to accurately find the root nor distinguish it from a cluster of several closely spaced simple roots.

+ +

Subdivided regions are handed to a worker pool, which is why it wants the free-threaded build.

  • Requires Python 3.14t (free-threaded build), NumPy ≥2.4.4, Numba ≥0.65.1, SciPy ≥1.17.1, SymPy ≥1.12
  • Returns a NumPy array of root coordinates, one row per root
  • Parallelism max_cpu and parallel_depth on solve()
  • -
  • Funding NSF grant DMS-1564502
  • -
+
-
# install (with uv, recommended)
uv python install 3.14t
uv pip install git+https://github.com/wlgns0330/RootFinding.git

# usage
import yroots as yr
f = lambda x, y: np.sin(x*y) + x*np.log(y + 3) - x**2
g = lambda x, y: np.cos(3*x*y) + np.exp(3*y/(x - 2)) - x
a, b = [-1, -2], [0, 1]
roots = yr.solve([f, g], a, b)
+
# install (with uv, recommended)
uv python install 3.14t
uv pip install git+https://github.com/tylerjarvis/RootFinding.git

# usage
import yroots as yr
f = lambda x, y: np.sin(x*y) + x*np.log(y + 3) - x**2
g = lambda x, y: np.cos(3*x*y) + np.exp(3*y/(x - 2)) - x
a, b = [-1, -2], [0, 1]
roots = yr.solve([f, g], a, b)
@@ -437,7 +445,7 @@

yroots

Python · serial

yroots-serial

-

The same subdivision solver with the parallel driver taken out: one thread, stock CPython. It is the reference the parallel fork is checked against, and the edition to reach for where a free-threaded interpreter isn't available. Same import, same call — without the two parallel arguments.

+

The same subdivision solver with the parallel driver taken out: one thread, stock CPython. It is the reference the parallel fork is checked against, and the edition to reach for where a free-threaded interpreter isn't available. Same import, same call, but without the two parallel arguments.

  • Requires Python ≥3.9, NumPy ≥1.21, Numba ≥0.57, SciPy ≥1.10, Matplotlib ≥3.7
  • Returns a NumPy array of root coordinates, one row per root
  • @@ -445,11 +453,11 @@

    yroots-serial

-
# install (stock CPython, 3.9 or newer)
pip install git+https://github.com/wlgns0330/Rootfinding-serial.git

# usage -- same f, g and box as above
import yroots as yr
roots = yr.solve([f, g], a, b)

# the parallel edition adds, on top of this:
# roots = yr.solve([f, g], a, b, max_cpu=8)
+
# install (stock CPython, 3.9 or newer)
pip install git+https://github.com/tylerjarvis/Rootfinding-serial.git

# usage -- same f, g and interval as above
import yroots as yr
roots = yr.solve([f, g], a, b)

# the parallel edition adds, on top of this:
# roots = yr.solve([f, g], a, b, max_cpu=8)
@@ -466,11 +474,11 @@

jroots

-
# install (not yet registered — clone and include directly)
git clone https://github.com/wlgns0330/Julia-Rootfinding.git
cd Julia-Rootfinding # then ] activate . && ] instantiate in Julia

# usage
include("src/CombinedSolver.jl")
f = (x,y) -> sin(30*x - y/30) + y
g = (x,y) -> cos(x/30 - 30*y) - x
a, b = [-1,-1], [1,1]
roots = solve([f, g], a, b; verbose=true)
+
# install (not yet registered — clone and include directly)
git clone https://github.com/tylerjarvis/Julia-Rootfinding.git
cd Julia-Rootfinding # then ] activate . && ] instantiate in Julia

# usage
include("src/CombinedSolver.jl")
f = (x,y) -> sin(30*x - y/30) + y
g = (x,y) -> cos(x/30 - 30*y) - x
a, b = [-1,-1], [1,1]
roots = solve([f, g], a, b; verbose=true)
@@ -497,7 +505,12 @@

jroots

Reference

Cite this work.

-

The algorithm behind yroots is described and proven in Parkinson, Wall, Slagle, Treuhaft, de la Bruere, Goldrup, Keith, Call & Jarvis, Chebyshev Subdivision and Reduction Methods for Solving Multivariable Systems of Equations, Journal of Symbolic Computation (2024).

+

If yroots, yroots-serial, or jroots contributed to your research, cite the software you used directly:

+
@software{yroots2025,
  title = {yroots: Numerical rootfinding for multivariate
    systems of equations},
  author = {Jarvis, Tyler J. and Call, Peter and de la Bruere, Xander
    and Erekson, Lukas and Goldrup, Samuel and Hermosilla, Alex
    and Kartchner, David and Keith, Timothy and Kellar, Catherine
    and Larsen, Natalie and Lee, Hyun and Longhurst, Nathan
    and Magland, Jeremy and Miller, Derek and Moncur, Tyler
    and Parkinson, Erik and Ringer, Hayden and Slagle, Jane
    and Stephenson, Suzanna and Taylor, Zachary and Treuhaft, Daniel
    and Wall, Kate and Williams, Rowan},
  year = {2025},
  url = {https://github.com/tylerjarvis/RootFinding},
  version = {0.1.0}
}
+

yroots-serial and jroots share the same author list — cite them the same way, with url set to tylerjarvis/Rootfinding-serial or tylerjarvis/Julia-Rootfinding respectively.

+ +
Algorithm
+

The Chebyshev subdivision algorithm all three implementations are built on is described and proven in Parkinson, Wall, Slagle, Treuhaft, de la Bruere, Goldrup, Keith, Call & Jarvis, Chebyshev Subdivision and Reduction Methods for Solving Multivariable Systems of Equations, Journal of Symbolic Computation (2024).

@article{parkinson2024chebyshev,
  title = {Chebyshev Subdivision and Reduction Methods for
    Solving Multivariable Systems of Equations},
  author = {Parkinson, Erik and Wall, Kate and Slagle, Jane
    and Treuhaft, Daniel and de la Bruere, Xander
    and Goldrup, Samuel and Keith, Timothy and Call, Peter
    and Jarvis, Tyler J.},
  journal = {Journal of Symbolic Computation},
  year = {2024},
  eprint = {2401.02114},
  archivePrefix = {arXiv}
}
-

Yroots content follows wlgns0330/RootFinding, with the single-threaded edition at wlgns0330/Rootfinding-serial; jroots follows wlgns0330/Julia-Rootfinding. Benchmark graphs are pulled live from tylerjarvis/rootfinding_testing.

+

Yroots content follows tylerjarvis/RootFinding, with the single-threaded edition at tylerjarvis/Rootfinding-serial; jroots follows tylerjarvis/Julia-Rootfinding. Benchmark graphs are pulled live from tylerjarvis/rootfinding_testing.

From 807f43684bb3b57cc07319e233ce9d640503e7a2 Mon Sep 17 00:00:00 2001 From: tylerjarvis Date: Tue, 22 Sep 2026 12:11:34 -0600 Subject: [PATCH 2/3] Scope fork-owner substitution in docs deploy to the three repo names Previously the deployed landing page's owner substitution matched the literal "wlgns0330", a contributor's username who is leaving the project. Source now says "tylerjarvis" directly; the CI step matches only the three implementation-repo paths (RootFinding, Rootfinding- serial, Julia-Rootfinding) so a fork's build points at its own repos without touching the tylerjarvis/rootfinding_testing benchmark-data links, which stay fixed regardless of who hosts the page. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/docs.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 70a3c2ef..3ce1201d 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -44,13 +44,16 @@ jobs: - name: Add landing page at the site root run: | cp -R docs/landing/. docs/_build/html/ - # The page links this project's three repositories, their clone URLs - # and the siblings' documentation sites, all under one owner. Point - # them at whoever is publishing this build, so the same page serves - # a fork and its upstream without being edited. The repository names - # are the same in both places; only the owner differs. + # The page links this project's three implementation repos (RootFinding, + # Rootfinding-serial, Julia-Rootfinding), their clone URLs, and the + # siblings' documentation sites, all under one owner in the source. + # Point them at whoever is publishing this build instead, so the same + # page serves a fork and its upstream without being edited. Scoped to + # just those repo names (not a blanket "tylerjarvis" replace) so the + # benchmark-data links to tylerjarvis/rootfinding_testing -- which + # stays tylerjarvis's regardless of who forks this page -- are untouched. owner='${{ github.repository_owner }}' - sed -i "s|wlgns0330|${owner}|g" docs/_build/html/index.html + sed -i -E "s#tylerjarvis/(RootFinding|Rootfinding-serial|Julia-Rootfinding)#${owner}/\1#g; s#tylerjarvis\.github\.io#${owner}.github.io#g" docs/_build/html/index.html echo "landing page owner set to ${owner}" - name: Upload Pages artifact From cd94fb81fc55ff46075eb2b86c57adc4603acd21 Mon Sep 17 00:00:00 2001 From: tylerjarvis Date: Tue, 22 Sep 2026 12:13:27 -0600 Subject: [PATCH 3/3] Exempt the citation section from fork-owner substitution Forks of this project are expected to mostly come from people working under Tyler Jarvis, and citations should point at one canonical repo regardless of who built and deployed the docs page. Switch the deploy step from sed to a small awk script that skips the
block, so the @software BibTeX and its yroots-serial/jroots citation note always resolve to tylerjarvis/... even on a fork's build. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/docs.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3ce1201d..69b778bd 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -51,10 +51,23 @@ jobs: # page serves a fork and its upstream without being edited. Scoped to # just those repo names (not a blanket "tylerjarvis" replace) so the # benchmark-data links to tylerjarvis/rootfinding_testing -- which - # stays tylerjarvis's regardless of who forks this page -- are untouched. + # stays tylerjarvis's regardless of who forks this page -- are + # untouched, and so is the "Cite this work" section: citations should + # always point at the upstream repo, even from a fork's build. owner='${{ github.repository_owner }}' - sed -i -E "s#tylerjarvis/(RootFinding|Rootfinding-serial|Julia-Rootfinding)#${owner}/\1#g; s#tylerjarvis\.github\.io#${owner}.github.io#g" docs/_build/html/index.html - echo "landing page owner set to ${owner}" + awk -v owner="${owner}" ' + /
/ { in_cite = 0 } + { print } + ' docs/_build/html/index.html > docs/_build/html/index.html.tmp + mv docs/_build/html/index.html.tmp docs/_build/html/index.html + echo "landing page owner set to ${owner} (cite section left pointing at tylerjarvis)" - name: Upload Pages artifact uses: actions/upload-pages-artifact@v4