simon-git: spigot (main): Simon Tatham

Commits to Tartarus hosted VCS tartarus-commits at lists.tartarus.org
Tue Jan 13 18:57:48 GMT 2026


TL;DR:
  ddb1270 AlgebraicPrep: add a precautionary const in divide_poly.
  1eceb75 AlgebraicPrep: remove broken but redundant trimming loop.
  35d7383 AlgebraicPrep: comment the polynomial scalings better.
  ed81b83 algebraic(): use Sturm's theorem to validate input interval.

Repository:     https://git.tartarus.org/simon/spigot.git
On the web:     https://git.tartarus.org/?p=simon/spigot.git
Branch updated: main
Committer:      Simon Tatham <anakin at pobox.com>
Date:           2026-01-13 18:57:48

commit ddb1270a5d75ea0c59dbe759768aeb36baae047f
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=ddb1270a5d75ea0c59dbe759768aeb36baae047f;hp=f158e08520c061c01271fddcfa439d35b737d587
Author: Simon Tatham <anakin at pobox.com>
Date:   Tue Jan 13 18:48:12 2026 +0000

    AlgebraicPrep: add a precautionary const in divide_poly.
    
    One of the inputs is overwritten with the remainder of the division.
    To prevent an accident by getting them the wrong way round, mark the
    other input as const.

 algebraic.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

commit 1eceb75c67e21b0f43d68f0e08514ee37ca6cafc
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=1eceb75c67e21b0f43d68f0e08514ee37ca6cafc;hp=ddb1270a5d75ea0c59dbe759768aeb36baae047f
Author: Simon Tatham <anakin at pobox.com>
Date:   Tue Jan 13 18:48:28 2026 +0000

    AlgebraicPrep: remove broken but redundant trimming loop.
    
    The loop near the top of AlgebraicPrep::spigot() which trimmed leading
    0 coefficients from the polynomial was obviously broken, because its
    condition was based on the variable 'n', which wasn't modified inside
    the loop. If that loop had ever been entered in the first place, it
    would have trimmed away the _entire_ array of coefficients and also
    referenced off the end of it.
    
    Fortunately, it _wasn't_ ever entered, because the polynomial was
    already trimmed more competently by spigot_algebraic_wrapper() before
    calling that function. So rather than fix the broken code, we might as
    well remove it completely, leaving only an assertion that checks the
    caller did its job.

 algebraic.cpp | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

commit 35d7383c60952332d0e74165d038e525ff81cce0
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=35d7383c60952332d0e74165d038e525ff81cce0;hp=1eceb75c67e21b0f43d68f0e08514ee37ca6cafc
Author: Simon Tatham <anakin at pobox.com>
Date:   Tue Jan 13 18:48:50 2026 +0000

    AlgebraicPrep: comment the polynomial scalings better.
    
    During testing just now, I gave a non-monic polynomial to algebraic(),
    and was utterly confused by the 'scaled #2' line in the debug output,
    because I had mistaken the comment "scale P to be monic" to mean
    scaling the _coefficients_ (equivalently, the output), where in fact
    it means scaling the _input_.
    
    In fact, the code is correct as it is. So I've rewritten the comments,
    in the hope that they'll confuse me less the next time.

 algebraic.cpp | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

commit ed81b8390347037e502f5477a15bc08ff79cfe43
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=ed81b8390347037e502f5477a15bc08ff79cfe43;hp=35d7383c60952332d0e74165d038e525ff81cce0
Author: Simon Tatham <anakin at pobox.com>
Date:   Tue Jan 13 18:49:09 2026 +0000

    algebraic(): use Sturm's theorem to validate input interval.
    
    I learned about Sturm's theorem this week, which provides a simple way
    to accurately count the number of real roots of a square-free
    polynomial P within a specified interval (a,b), by making a sequence
    of smaller and smaller polynomials derived from P, evaluating them at
    each of a and b, and counting changes of sign within each sequence.
    
    This fills a gap in spigot's input validation for the algebraic()
    operation, which was previously not able to check whether you'd really
    given it an interval containing _exactly one_ root of P. It could
    check that P(a) and P(b) had opposite signs (guaranteeing _at least_
    one root), but if you provided an interval containing three roots, it
    would charge ahead anyway, and end up selecting a root arbitrarily by
    the luck of how the search algorithm happened to work.
    
    This isn't just useful for error checking. It also provides feedback
    allowing a human to interactively _find_ an appropriate bracketing
    interval, if they didn't already know one. For example, suppose I want
    real roots of x^5 - 4x + 2 for some purpose. I could start by guessing
    that there might be one within the interval [-2, +2] (as in fact all
    three of them are):
    
    $ spigot -d20 'algebraic(-2, +2, 2, -4, 0, 0, 0, 1)'
    interval for algebraic() contains 3 roots instead of 1
    
    Previously, that command would have output one of the roots (as it
    happens, the smallest of the three) and never told me that there were
    others to be found. But now I get a nice error telling me there's more
    than one, so I can respond by narrowing the interval further. Let's
    bisect it at 0:
    
    $ spigot -d20 'algebraic(-2, 0, 2, -4, 0, 0, 0, 1)'
    -1.51851215278491190384
    $ spigot -d20 'algebraic(0, +2, 2, -4, 0, 0, 0, 1)'
    interval for algebraic() contains 2 roots instead of 1
    
    In the negative half of the interval [-2,0], spigot stops giving an
    error and returns a root, because there's only one there. So by
    elimination the other two must be in the remaining interval [0,+2],
    and indeed we still get an error message saying there are two roots to
    look for. Bisecting again into [0,1] and [1,2] separates them:
    
    $ spigot -d20 'algebraic(0, 1, 2, -4, 0, 0, 0, 1)'
    0.50849948465733279699
    $ spigot -d20 'algebraic(1, 2, 2, -4, 0, 0, 0, 1)'
    1.24359639057354318715
    
    but if it hadn't, then we'd still have found out which half-interval
    contained no roots and which contained two, and could bisect that one
    further in turn.
    
    Of course, a natural next thought is to automate this manual process!
    But that's outside the remit of spigot's main evaluation engine. You
    could build a script on top of spigot, perhaps using the Python API,
    to automate this interval-narrowing process, so that you'd give it
    just a polynomial, and it would output a suitable spigot algebraic()
    call expression describing each of its real roots.
    
    (Further reading: https://en.wikipedia.org/wiki/Real-root_isolation .
    This is a well-studied problem, and bisecting the interval is not the
    most efficient way to go about it in general. I haven't thought
    seriously about which of the more advanced algorithms might fit well
    into spigot's way of looking at the world.)

 algebraic.cpp | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 137 insertions(+), 9 deletions(-)



More information about the tartarus-commits mailing list