| 1 | """ |
|---|
| 2 | Isolate Real Roots of Real Polynomials |
|---|
| 3 | |
|---|
| 4 | AUTHOR: |
|---|
| 5 | -- Carl Witty (2007-09-19): initial version |
|---|
| 6 | |
|---|
| 7 | This is an implementation of real root isolation. That is, given a |
|---|
| 8 | polynomial with exact real coefficients, we compute isolating intervals |
|---|
| 9 | for the real roots of the polynomial. (Polynomials with |
|---|
| 10 | integer, rational, or algebraic real coefficients are supported.) |
|---|
| 11 | |
|---|
| 12 | We convert the polynomials into the Bernstein basis, and then use |
|---|
| 13 | de Casteljau's algorithm and Descartes' rule of signs on the Bernstein |
|---|
| 14 | basis polynomial (using interval arithmetic) to locate the roots. The |
|---|
| 15 | algorithm is similar to that in "A Descartes Algorithm for Polynomials |
|---|
| 16 | with Bit-Stream Coefficients", by Eigenwillig, Kettner, Krandick, Mehlhorn, |
|---|
| 17 | Schmitt, and Wolpert, but has three crucial optimizations over the |
|---|
| 18 | algorithm in that paper: |
|---|
| 19 | |
|---|
| 20 | * Precision reduction: at certain points in the computation, we discard |
|---|
| 21 | the low-order bits of the coefficients, widening the intervals. |
|---|
| 22 | |
|---|
| 23 | * Degree reduction: at certain points in the computation, we find |
|---|
| 24 | lower-degree polynomials that are approximately equal to our |
|---|
| 25 | high-degree polynomial over the region of interest. |
|---|
| 26 | |
|---|
| 27 | * When the intervals are too wide to continue (either because of a |
|---|
| 28 | too-low initial precision, or because of precision or degree |
|---|
| 29 | reduction), and we need to restart with higher precision, we recall |
|---|
| 30 | which regions have already been proven not to have any roots and do |
|---|
| 31 | not examine them again. |
|---|
| 32 | |
|---|
| 33 | The best description of the algorithms used (other than this source |
|---|
| 34 | code itself) is in the slides for my SAGE Days 4 talk, currently available |
|---|
| 35 | from http://www.sagemath.org:9001/days4schedule . |
|---|
| 36 | """ |
|---|
| 37 | |
|---|
| 38 | ################################################################################ |
|---|
| 39 | # Copyright (C) 2007 Carl Witty <cwitty@newtonlabs.com> |
|---|
| 40 | # |
|---|
| 41 | # Distributed under the terms of the GNU General Public License (GPL) |
|---|
| 42 | # |
|---|
| 43 | # http://www.gnu.org/licenses/ |
|---|
| 44 | ################################################################################ |
|---|
| 45 | |
|---|
| 46 | # TODO: |
|---|
| 47 | # These things would almost certainly improve the speed: |
|---|
| 48 | # * Use Anatole Ruslanov's register tiling versions of de Casteljau's |
|---|
| 49 | # algorithms when doing de Casteljau splitting at 1/2 in the integer case. |
|---|
| 50 | # * Use a register tiling version of de Casteljau's algorithm for the |
|---|
| 51 | # floating-point case...if you have n free FP registers (after allocating |
|---|
| 52 | # registers to hold r and 1-r) you should be able to do about n rows at |
|---|
| 53 | # once. |
|---|
| 54 | # * Use vectorized FP instructions for de Casteljau's algorithm. |
|---|
| 55 | # Using SSE2 to do 2 FP operations at once should be twice as fast. |
|---|
| 56 | # * Faster degree elevation |
|---|
| 57 | # Currently, when bernstein_expand expands from a degree-d1 to a |
|---|
| 58 | # degree-d2 polynomial, it does O(d2^2 - d1^2) operations. I |
|---|
| 59 | # have thought of (but not implemented) an approach that takes |
|---|
| 60 | # O(d1*d2) operations, which should be much faster when d1 is 30 |
|---|
| 61 | # and d2 is 1000. |
|---|
| 62 | # Basically, the idea is to compute the d1 derivatives of the polynomial |
|---|
| 63 | # at x=0. This can be done exactly, in O(d1^2) operations. Then |
|---|
| 64 | # lift the d1'th derivative (a constant polynomial) to a polynomial of |
|---|
| 65 | # formal degree d2-d1 (trivial; the coefficients are just d2-d1+1 copies |
|---|
| 66 | # of the derivative). Then, compute the integral of that polynomial |
|---|
| 67 | # d1 times, using the computed derivatives to give the constant offset. |
|---|
| 68 | # (Computing the integral in Bernstein form involves divisions; these can |
|---|
| 69 | # be done ahead of time, to the derivatives at x=0.) |
|---|
| 70 | # The only tricky bit is tracking the error bounds and making sure you |
|---|
| 71 | # use appropriate precisions at various parts of the computation. |
|---|
| 72 | |
|---|
| 73 | # These things are interesting ideas that may or may not help: |
|---|
| 74 | # * Partial degree reduction |
|---|
| 75 | # Build a new subclass of interval_bernstein_polynomial, which |
|---|
| 76 | # represents a polynomial as the sum of several |
|---|
| 77 | # interval_bernstein_polynomial_integer (of different degrees). |
|---|
| 78 | # Suppose you have a degree-1000 polynomial with 2000-bit coefficients. |
|---|
| 79 | # When you try degree reduction, you get a degree-30 polynomial with |
|---|
| 80 | # 2000-bit coefficients; but you get 300 bits of error. |
|---|
| 81 | # Instead of just using the degree-30 polynomial and accepting the |
|---|
| 82 | # loss of 300 bits of precision, you could represent the reduced polynomial |
|---|
| 83 | # as the sum of a degree-30 polynomial with 2000-bit coefficients and |
|---|
| 84 | # a degree-1000 polynomial with 300-bit coefficients. The combined |
|---|
| 85 | # polynomial should still be much cheaper to work with than the original. |
|---|
| 86 | # * Faster degree reduction |
|---|
| 87 | # Perhaps somebody clever can figure out a way to do degree reduction |
|---|
| 88 | # that doesn't involve matrix inversion, so that degree reduction can |
|---|
| 89 | # target degrees larger than 30. |
|---|
| 90 | # * Better heuristics |
|---|
| 91 | # ** Better degree reduction heuristics |
|---|
| 92 | # When should we degree reduce? What degrees should be targeted? |
|---|
| 93 | # ** Better precision reduction heuristics |
|---|
| 94 | # ** Better split point selection |
|---|
| 95 | # Currently we attempt to split at 1/2, and then at a random offset. |
|---|
| 96 | # We do not look at the current coefficients at all to try to select |
|---|
| 97 | # a good split point. Would it be worthwhile to do so? (For instance, |
|---|
| 98 | # it's a standard result that the polynomial in the region is bounded |
|---|
| 99 | # by the convex hull of the coefficients.) |
|---|
| 100 | # * Better initial transformation into Bernstein form |
|---|
| 101 | # If a polynomial has roots which are very close to 0, or very large, |
|---|
| 102 | # it may be better to rescale the roots (using a transformation like |
|---|
| 103 | # p -> p(1000*x)). This can be done as part of the initial transformation |
|---|
| 104 | # into Bernstein form. |
|---|
| 105 | # If a polynomial has some roots which are very close to 0, and also |
|---|
| 106 | # some roots which are very large, it might be better to isolate the roots |
|---|
| 107 | # in two groups. |
|---|
| 108 | # * More kinds of interval_bernstein_polynomial |
|---|
| 109 | # Currently we have arbitrary-precision GMP coefficients or double-precision |
|---|
| 110 | # floats. Would choices between these extremes help? (double-double? |
|---|
| 111 | # quad-double? fixed-precision multi-word integer arithmetic?) |
|---|
| 112 | # * Currently, some of our competitors are faster than this algorithm |
|---|
| 113 | # for polynomials that are "easy" in some way. (This algorithm |
|---|
| 114 | # seems to be vastly faster than everything else for "hard" polynomials.) |
|---|
| 115 | # Maybe there is a way to start out using another algorithm |
|---|
| 116 | # and then switch over to this algorithm once the polynomial |
|---|
| 117 | # is determined to be hard. |
|---|
| 118 | # * standard optimization |
|---|
| 119 | # There's probably some more to be gained by just running the profiler |
|---|
| 120 | # and optimizing individual functions. (To use more Cython featuers, for |
|---|
| 121 | # instance.) |
|---|
| 122 | |
|---|
| 123 | # Extra features: |
|---|
| 124 | # * Specify a minimal island width: once islands are this narrow, |
|---|
| 125 | # stop even if roots are not isolated. |
|---|
| 126 | # * Do some sort of inexact version, for inexact input polynomials. |
|---|
| 127 | # (For example, given a polynomial with (non-point) interval coefficients, |
|---|
| 128 | # give a set of roots such that each root is guaranteed to be a root |
|---|
| 129 | # of some polynomial in the set represented by the interval polynomial. |
|---|
| 130 | # This may be vastly faster than the exact calculations carried out |
|---|
| 131 | # by this algorithm! Is it enough faster to be faster than, say, |
|---|
| 132 | # Pari's floating-point algorithms?) |
|---|
| 133 | |
|---|
| 134 | from copy import copy |
|---|
| 135 | from random import Random |
|---|
| 136 | import time |
|---|
| 137 | |
|---|
| 138 | from sage.rings.all import ZZ, QQ, RR, AA, RealField, RealIntervalField, RIF, RDF, infinity |
|---|
| 139 | from sage.rings.arith import binomial, factorial |
|---|
| 140 | from sage.modules.all import vector, FreeModule |
|---|
| 141 | from sage.matrix.all import MatrixSpace |
|---|
| 142 | from sage.rings.polynomial.polynomial_ring import PolynomialRing, polygen |
|---|
| 143 | from sage.misc.all import numerator, denominator, prod |
|---|
| 144 | |
|---|
| 145 | from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense |
|---|
| 146 | from sage.modules.vector_integer_dense cimport Vector_integer_dense |
|---|
| 147 | from sage.modules.real_double_vector cimport RealDoubleVectorSpaceElement |
|---|
| 148 | from sage.rings.integer cimport Integer |
|---|
| 149 | from sage.rings.real_mpfr cimport RealNumber |
|---|
| 150 | |
|---|
| 151 | # We need to put x86-family CPUs in round-to-double mode. |
|---|
| 152 | # To do this, we call fpu_fix_start/fpu_fix_end from the quad-double package. |
|---|
| 153 | # We could use them like this: |
|---|
| 154 | # from sage.rings.real_rqdf cimport fpu_fix_start, fpu_fix_end |
|---|
| 155 | # but that requires compiling this file into C++. Instead, we copy the |
|---|
| 156 | # following declarations from real_rqdf.pxd: |
|---|
| 157 | |
|---|
| 158 | # For controlling the round-to-double bit on x86 machines |
|---|
| 159 | # These functions have no effects on other platforms |
|---|
| 160 | cdef extern from "qd/fpu.h": |
|---|
| 161 | void fpu_fix_start(unsigned int *old_cw) |
|---|
| 162 | void fpu_fix_end(unsigned int *old_cw) |
|---|
| 163 | |
|---|
| 164 | include "../../ext/cdefs.pxi" |
|---|
| 165 | include "../../ext/gmp.pxi" |
|---|
| 166 | include "../../gsl/gsl.pxi" |
|---|
| 167 | include "../mpfr.pxi" |
|---|
| 168 | |
|---|
| 169 | cdef class interval_bernstein_polynomial: |
|---|
| 170 | """ |
|---|
| 171 | An interval_bernstein_polynomial is an approximation to an exact |
|---|
| 172 | polynomial. This approximation is in the form of a Bernstein |
|---|
| 173 | polynomial (a polynomial given as coefficients over a Bernstein |
|---|
| 174 | basis) with interval coefficients. |
|---|
| 175 | |
|---|
| 176 | The Bernstein basis of degree n over the region [a .. b] is the |
|---|
| 177 | set of polynomials |
|---|
| 178 | binomial(n, k) * (x-a)^k * (b-x)^{n-k} / (b-a)^n |
|---|
| 179 | for 0 <= k <= n. |
|---|
| 180 | |
|---|
| 181 | A degree-n interval Bernstein polynomial P with its region [a .. b] can |
|---|
| 182 | represent an exact polynomial p in two different ways: it can |
|---|
| 183 | "contain" the polynomial or it can "bound" the polynomial. |
|---|
| 184 | |
|---|
| 185 | We say that P contains p if, when p is represented as a degree-n |
|---|
| 186 | Bernstein polynomial over [a .. b], its coefficients are contained |
|---|
| 187 | in the corresponding interval coefficients of P. For instance, |
|---|
| 188 | [0.9 .. 1.1]*x^2 (which is a degree-2 interval Bernstein polynomial |
|---|
| 189 | over [0 .. 1]) contains x^2. |
|---|
| 190 | |
|---|
| 191 | We say that P bounds p if, for all a <= x <= b, there exists a |
|---|
| 192 | polynomial p' contained in P such that p(x) == p'(x). For instance, |
|---|
| 193 | [0 .. 1]*x is a degree-1 interval Bernstein polynomial which bounds |
|---|
| 194 | x^2 over [0 .. 1]. |
|---|
| 195 | |
|---|
| 196 | If P contains p, then P bounds p; but the converse is not necessarily |
|---|
| 197 | true. In particular, if n < m, it is possible for a degree-n interval |
|---|
| 198 | Bernstein polynomial to bound a degree-m polynomial; but it cannot |
|---|
| 199 | contain the polynomial. |
|---|
| 200 | |
|---|
| 201 | In the case where P bounds p, we maintain extra information, the |
|---|
| 202 | "slope error". We say that P (over [a .. b]) bounds p with a |
|---|
| 203 | slope error of E (where E is an interval) if there is a polynomial |
|---|
| 204 | p' contained in P such that the derivative of (p - p') is bounded |
|---|
| 205 | by E in the range [a .. b]. If P bounds p with a slope error of 0 |
|---|
| 206 | then P contains p. |
|---|
| 207 | |
|---|
| 208 | (Note that "contains" and "bounds" are not standard terminology; |
|---|
| 209 | I just made them up.) |
|---|
| 210 | |
|---|
| 211 | Interval Bernstein polynomials are useful in finding real roots |
|---|
| 212 | because of the following properties: |
|---|
| 213 | |
|---|
| 214 | * Given an exact real polynomial p, we can compute an interval |
|---|
| 215 | Bernstein polynomial over an arbitrary region containing p. |
|---|
| 216 | |
|---|
| 217 | * Given an interval Bernstein polynomial P over [a .. c], where |
|---|
| 218 | a < b < c, we can compute interval Bernstein polynomials P1 over |
|---|
| 219 | [a .. b] and P2 over [b .. c], where P1 and P2 contain (or bound) |
|---|
| 220 | all polynomials that P contains (or bounds). |
|---|
| 221 | |
|---|
| 222 | * Given a degree-n interval Bernstein polynomial P over [a .. b], |
|---|
| 223 | and m < n, we can compute a degree-m interval Bernstein polynomial |
|---|
| 224 | P' over [a .. b] that bounds all polynomials that P bounds. |
|---|
| 225 | |
|---|
| 226 | * It is sometimes possible to prove that no polynomial bounded by |
|---|
| 227 | P over [a .. b] has any roots in [a .. b]. (Roughly, this |
|---|
| 228 | is possible when no polynomial contained by P has any complex roots |
|---|
| 229 | near the line segment [a .. b], where "near" is defined relative |
|---|
| 230 | to the length b-a.) |
|---|
| 231 | |
|---|
| 232 | * It is sometimes possible to prove that every polynomial bounded |
|---|
| 233 | by P over [a .. b] with slope error E has exactly one root in |
|---|
| 234 | [a .. b]. (Roughly, this is possible when every polynomial contained |
|---|
| 235 | by P over [a .. b] has exactly one root in [a .. b], there are |
|---|
| 236 | no other complex roots near the line segment [a .. b], and every |
|---|
| 237 | polynomial contained in P has a derivative which is bounded |
|---|
| 238 | away from zero over [a .. b] by an amount which is large relative |
|---|
| 239 | to E.) |
|---|
| 240 | |
|---|
| 241 | * Starting from a sufficiently precise interval Bernstein polynomial, |
|---|
| 242 | it is always possible to split it into polynomials which provably |
|---|
| 243 | have 0 or 1 roots (as long as your original polynomial has no |
|---|
| 244 | multiple real roots). |
|---|
| 245 | |
|---|
| 246 | So a rough outline of a family of algorithms would be: |
|---|
| 247 | * Given a polynomial p, compute a region [a .. b] in which any |
|---|
| 248 | real roots must lie. |
|---|
| 249 | * Compute an interval Bernstein polynomial P containing p over [a .. b]. |
|---|
| 250 | * Keep splitting P until you have isolated all the roots. |
|---|
| 251 | Optionally, reduce the degree or the precision of the interval |
|---|
| 252 | Bernstein polynomials at intermediate stages (to reduce computation time). |
|---|
| 253 | If this seems not to be working, go back and try again with |
|---|
| 254 | higher precision. |
|---|
| 255 | |
|---|
| 256 | Obviously, there are many details to be worked out to turn this |
|---|
| 257 | into a full algorithm, like: |
|---|
| 258 | * What initial precision is selected for computing P? |
|---|
| 259 | * How do you decide when to reduce the degree of intermediate polynomials? |
|---|
| 260 | * How do you decide when to reduce the precision of intermediate |
|---|
| 261 | polynomials? |
|---|
| 262 | * How do you decide where to split the interval Bernstein polynomial |
|---|
| 263 | regions? |
|---|
| 264 | * How do you decide when to give up and start over with higher |
|---|
| 265 | precision? |
|---|
| 266 | |
|---|
| 267 | Each set of answers to these questions gives a different algorithm |
|---|
| 268 | (potentially with very different performance characteristics), |
|---|
| 269 | but all of them can use this interval_bernstein_polynomial class |
|---|
| 270 | as their basic building block. |
|---|
| 271 | |
|---|
| 272 | To save computation time, all coefficients in an |
|---|
| 273 | interval_bernstein_polynomial share the same interval width. |
|---|
| 274 | (There is one exception: when creating an interval_bernstein_polynomial, |
|---|
| 275 | the first and last coefficients can be marked as "known positive" |
|---|
| 276 | or "known negative". This has some of the same effect as having |
|---|
| 277 | a (potentially) smaller interval width for these two coefficients, |
|---|
| 278 | although it does not affect de Casteljau splitting.) |
|---|
| 279 | To allow for widely varying coefficient magnitudes, all |
|---|
| 280 | coefficients in an interval_bernstein_polynomial are scaled |
|---|
| 281 | by 2^n (where n may be positive, negative, or zero). |
|---|
| 282 | |
|---|
| 283 | There are two representations for interval_bernstein_polynomials, |
|---|
| 284 | integer and floating-point. These are the two subclasses of |
|---|
| 285 | this class; interval_bernstein_polynomial itself is an abstract |
|---|
| 286 | class. |
|---|
| 287 | |
|---|
| 288 | interval_bernstein_polynomial and its subclasses are not expected |
|---|
| 289 | to be used outside this file. |
|---|
| 290 | """ |
|---|
| 291 | |
|---|
| 292 | def variations(self): |
|---|
| 293 | """ |
|---|
| 294 | Consider a polynomial (written in either the normal power basis |
|---|
| 295 | or the Bernstein basis). Take its list of coefficients, omitting |
|---|
| 296 | zeroes. Count the number of positions in the list where the |
|---|
| 297 | sign of one coefficient is opposite the sign of the next coefficient. |
|---|
| 298 | |
|---|
| 299 | This count is the number of sign variations of the polynomial. |
|---|
| 300 | According to Descartes' rule of signs, the number of real |
|---|
| 301 | roots of the polynomial (counted with multiplicity) in a |
|---|
| 302 | certain interval is always less than or equal to the number of |
|---|
| 303 | sign variations, and the difference is always even. (If the |
|---|
| 304 | polynomial is written in the power basis, the region is the |
|---|
| 305 | positive reals; if the polynomial is written in the Bernstein |
|---|
| 306 | basis over a particular region, then we count roots in that region.) |
|---|
| 307 | |
|---|
| 308 | In particular, a polynomial with no sign variations has no real |
|---|
| 309 | roots in the region, and a polynomial with one sign variation |
|---|
| 310 | has one real root in the region. |
|---|
| 311 | |
|---|
| 312 | In an interval Bernstein polynomial, we do not necessarily |
|---|
| 313 | know the signs of the coefficients (if some of the coefficient |
|---|
| 314 | intervals contain zero), so the polynomials contained by |
|---|
| 315 | this interval polynomial may not all have the same number |
|---|
| 316 | of sign variations. However, we can compute a range of |
|---|
| 317 | possible numbers of sign variations. |
|---|
| 318 | |
|---|
| 319 | This function returns the range, as a 2-tuple of integers. |
|---|
| 320 | """ |
|---|
| 321 | return (self.min_variations, self.max_variations) |
|---|
| 322 | |
|---|
| 323 | cdef void update_variations(self, interval_bernstein_polynomial bp1, interval_bernstein_polynomial bp2): |
|---|
| 324 | """ |
|---|
| 325 | Update the max_variations of bp1 and bp2 (which are assumed to be |
|---|
| 326 | the result of splitting this polynomial). |
|---|
| 327 | |
|---|
| 328 | If we knew the number of variations of self, bp1, and bp2 exactly, |
|---|
| 329 | we would have |
|---|
| 330 | self.variations == bp1.variations + bp2.variations + 2*n |
|---|
| 331 | for some nonnegative integer n. Thus, we can use our information |
|---|
| 332 | on min and max variations on self and bp1 (or bp2) to refine the range |
|---|
| 333 | on bp2 (or bp1). |
|---|
| 334 | """ |
|---|
| 335 | if self.max_variations - bp1.min_variations < bp2.max_variations: |
|---|
| 336 | bp2.max_variations = self.max_variations - bp1.min_variations |
|---|
| 337 | if self.max_variations - bp2.min_variations < bp1.max_variations: |
|---|
| 338 | bp1.max_variations = self.max_variations - bp2.min_variations |
|---|
| 339 | |
|---|
| 340 | def try_split(self, context ctx, logging_note): |
|---|
| 341 | """ |
|---|
| 342 | Try doing a de Casteljau split of this polynomial at 1/2, resulting |
|---|
| 343 | in polynomials p1 and p2. If we see that the sign of this polynomial |
|---|
| 344 | is determined at 1/2, then return (p1, p2, 1/2); otherwise, |
|---|
| 345 | return None. |
|---|
| 346 | |
|---|
| 347 | EXAMPLES: |
|---|
| 348 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 349 | sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5) |
|---|
| 350 | sage: bp1, bp2, _ = bp.try_split(mk_context(), None) |
|---|
| 351 | sage: str(bp1) |
|---|
| 352 | '<IBP: (50, 35, 0, -29, -31) + [0 .. 6) over [0 .. 1/2]>' |
|---|
| 353 | sage: str(bp2) |
|---|
| 354 | '<IBP: (-31, -33, -8, 65, 200) + [0 .. 6) over [1/2 .. 1]>' |
|---|
| 355 | sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01) |
|---|
| 356 | sage: bp1, bp2, _ = bp.try_split(mk_context(), None) |
|---|
| 357 | sage: str(bp1) |
|---|
| 358 | '<IBP: (0.5, 0.35, 0.0, -0.2875, -0.369375) + [-0.1 .. 0.01] over [0 .. 1/2]>' |
|---|
| 359 | sage: str(bp2) |
|---|
| 360 | '<IBP: (-0.369375, -0.45125, -0.3275, 0.145, 0.99) + [-0.1 .. 0.01] over [1/2 .. 1]>' |
|---|
| 361 | """ |
|---|
| 362 | (p1, p2, ok) = self.de_casteljau(ctx, QQ_1_2) |
|---|
| 363 | ctx.dc_log_append(("half" + self._type_code(), self.scale_log2, self.bitsize, ok, logging_note)) |
|---|
| 364 | if ok: |
|---|
| 365 | return (p1, p2, QQ_1_2) |
|---|
| 366 | return None |
|---|
| 367 | |
|---|
| 368 | def try_rand_split(self, context ctx, logging_note): |
|---|
| 369 | """ |
|---|
| 370 | Compute a random split point r (using the random number generator |
|---|
| 371 | embedded in ctx). We require 1/4 <= r < 3/4 (to ensure that |
|---|
| 372 | recursive algorithms make progress). |
|---|
| 373 | |
|---|
| 374 | Then, try doing a de Casteljau split of this polynomial at r, resulting |
|---|
| 375 | in polynomials p1 and p2. If we see that the sign of this polynomial |
|---|
| 376 | is determined at r, then return (p1, p2, r); otherwise, |
|---|
| 377 | return None. |
|---|
| 378 | |
|---|
| 379 | EXAMPLES: |
|---|
| 380 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 381 | sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5) |
|---|
| 382 | sage: bp1, bp2, _ = bp.try_rand_split(mk_context(), None) |
|---|
| 383 | sage: str(bp1) |
|---|
| 384 | '<IBP: (50, 29, -27, -56, -11) + [0 .. 6) over [0 .. 43/64]>' |
|---|
| 385 | sage: str(bp2) |
|---|
| 386 | '<IBP: (-11, 10, 49, 111, 200) + [0 .. 6) over [43/64 .. 1]>' |
|---|
| 387 | sage: bp1, bp2, _ = bp.try_rand_split(mk_context(seed=42), None) |
|---|
| 388 | sage: str(bp1) |
|---|
| 389 | '<IBP: (50, 32, -11, -41, -29) + [0 .. 6) over [0 .. 583/1024]>' |
|---|
| 390 | sage: str(bp2) |
|---|
| 391 | '<IBP: (-29, -20, 13, 83, 200) + [0 .. 6) over [583/1024 .. 1]>' |
|---|
| 392 | sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01) |
|---|
| 393 | sage: bp1, bp2, _ = bp.try_rand_split(mk_context(), None) |
|---|
| 394 | sage: str(bp1) |
|---|
| 395 | '<IBP: (0.5, 0.2984375, -0.2642578125, -0.551166152954, -0.314580697417) + [-0.1 .. 0.01] over [0 .. 43/64]>' |
|---|
| 396 | sage: str(bp2) |
|---|
| 397 | '<IBP: (-0.314580697417, -0.199038963318, 0.0413598632813, 0.43546875, 0.99) + [-0.1 .. 0.01] over [43/64 .. 1]>' |
|---|
| 398 | """ |
|---|
| 399 | |
|---|
| 400 | # We want a split point which is a dyadic rational (denominator |
|---|
| 401 | # is a power of 2), because that speeds up de_casteljau. We want |
|---|
| 402 | # a small denominator, because that helps us find simpler isolating |
|---|
| 403 | # intervals. However, if we require that our denominator be too |
|---|
| 404 | # small, then that might keep the algorithm from terminating; |
|---|
| 405 | # if the current polynomial has roots at (4/16, 5/16, ..., 12/16), |
|---|
| 406 | # and we pick our split points from that same set, then we will |
|---|
| 407 | # never find a split point with a determined sign. We avoid this |
|---|
| 408 | # problem by making sure we have more possible split points |
|---|
| 409 | # to choose from than our polynomial has roots. |
|---|
| 410 | |
|---|
| 411 | # A different algorithm here might be more efficient. |
|---|
| 412 | |
|---|
| 413 | div = 1024 |
|---|
| 414 | while self.degree() >= div//4: |
|---|
| 415 | div = div * 2 |
|---|
| 416 | qdiv = div/4 |
|---|
| 417 | rand = Integer(ctx.random.randrange(qdiv, 3*qdiv)) / div |
|---|
| 418 | (p1, p2, ok) = self.de_casteljau(ctx, rand) |
|---|
| 419 | ctx.dc_log_append(("div" + self._type_code(), self.scale_log2, self.bitsize, rand, ok, logging_note)) |
|---|
| 420 | if ok: |
|---|
| 421 | return (p1, p2, rand) |
|---|
| 422 | return None |
|---|
| 423 | |
|---|
| 424 | cdef int degree(self): |
|---|
| 425 | raise NotImplementedError() |
|---|
| 426 | |
|---|
| 427 | def region(self): |
|---|
| 428 | return (self.lower, self.upper) |
|---|
| 429 | |
|---|
| 430 | def region_width(self): |
|---|
| 431 | return (self.upper - self.lower) |
|---|
| 432 | |
|---|
| 433 | dr_cache = {} |
|---|
| 434 | |
|---|
| 435 | cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): |
|---|
| 436 | """ |
|---|
| 437 | This is the subclass of interval_bernstein_polynomial where |
|---|
| 438 | polynomial coefficients are represented using integers. |
|---|
| 439 | |
|---|
| 440 | In this integer representation, each coefficient is represented by |
|---|
| 441 | a GMP arbitrary-precision integer A, and a (shared) interval width |
|---|
| 442 | E (which is a machine integer). These represent the coefficients |
|---|
| 443 | A*2^n <= c < (A+E)*2^n. |
|---|
| 444 | |
|---|
| 445 | (Note that mk_ibpi is a simple helper function for creating |
|---|
| 446 | elements of interval_bernstein_polynomial_integer in doctests.) |
|---|
| 447 | |
|---|
| 448 | EXAMPLES: |
|---|
| 449 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 450 | sage: bp = mk_ibpi([1, 2, 3], error=5); bp |
|---|
| 451 | degree 2 IBP with 2-bit coefficients |
|---|
| 452 | sage: str(bp) |
|---|
| 453 | '<IBP: (1, 2, 3) + [0 .. 5)>' |
|---|
| 454 | sage: bp.variations() |
|---|
| 455 | (0, 0) |
|---|
| 456 | sage: bp = mk_ibpi([-3, -1, 1, -1, -3, -1], lower=1, upper=5/4, usign=1, error=2, scale_log2=-3, level=2, slope_err=RIF(pi)); bp |
|---|
| 457 | degree 5 IBP with 2-bit coefficients |
|---|
| 458 | sage: str(bp) |
|---|
| 459 | '<IBP: ((-3, -1, 1, -1, -3, -1) + [0 .. 2)) * 2^-3 over [1 .. 5/4]; usign 1; level 2; slope_err [3.1415926535897931 .. 3.1415926535897936]>' |
|---|
| 460 | sage: bp.variations() |
|---|
| 461 | (3, 3) |
|---|
| 462 | """ |
|---|
| 463 | |
|---|
| 464 | def __init__(self, Vector_integer_dense coeffs, Rational lower, Rational upper, int lsign, int usign, int error, int scale_log2, int level, RealIntervalFieldElement slope_err): |
|---|
| 465 | """ |
|---|
| 466 | Initialize an interval_bernstein_polynomial_integer. |
|---|
| 467 | |
|---|
| 468 | INPUT: |
|---|
| 469 | coeffs -- a coefficient vector for a polynomial in Bernstein form |
|---|
| 470 | lower -- the lower bound of the region over which the Bernstein basis is defined |
|---|
| 471 | upper -- the upper bound of the region over which the Bernstein basis is defined |
|---|
| 472 | lsign -- the sign of the polynomial at lower, if known |
|---|
| 473 | usign -- the sign of the polynomial at upper, if known |
|---|
| 474 | error -- the maximum error in the Bernstein coefficients |
|---|
| 475 | scale_log2 -- the log2 of the scaling factor for the Bernstein coefficients |
|---|
| 476 | level -- the number of times we have performed degree reduction to get this polynomial |
|---|
| 477 | slope_err -- the maximum extra error in the derivative of this polynomial from degree reduction |
|---|
| 478 | |
|---|
| 479 | EXAMPLES: |
|---|
| 480 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 481 | sage: bp = interval_bernstein_polynomial_integer(vector(ZZ, [50, -30, -10]), -3/7, 4/7, 0, -1, 17, 3, 2, RIF(10^-30)) |
|---|
| 482 | sage: bp |
|---|
| 483 | degree 2 IBP with 6-bit coefficients |
|---|
| 484 | sage: str(bp) |
|---|
| 485 | '<IBP: ((50, -30, -10) + [0 .. 17)) * 2^3 over [-3/7 .. 4/7]; usign -1; level 2; slope_err [9.9999999999999990e-31 .. 1.0000000000000001e-30]>' |
|---|
| 486 | """ |
|---|
| 487 | assert(len(coeffs) > 0) |
|---|
| 488 | self.coeffs = coeffs |
|---|
| 489 | self.lower = lower |
|---|
| 490 | self.upper = upper |
|---|
| 491 | self.lsign = lsign |
|---|
| 492 | if self.lsign == 0: |
|---|
| 493 | if mpz_sgn(coeffs._entries[0]) > 0: |
|---|
| 494 | self.lsign = 1 |
|---|
| 495 | if mpz_cmp_si(coeffs._entries[0], -error) <= 0: |
|---|
| 496 | self.lsign = -1 |
|---|
| 497 | self.usign = usign |
|---|
| 498 | cdef int n = len(coeffs) |
|---|
| 499 | if self.usign == 0: |
|---|
| 500 | if mpz_sgn(coeffs._entries[n-1]) > 0: |
|---|
| 501 | self.usign = 1 |
|---|
| 502 | if mpz_cmp_si(coeffs._entries[n-1], -error) <= 0: |
|---|
| 503 | self.usign = -1 |
|---|
| 504 | self.error = error |
|---|
| 505 | self.scale_log2 = scale_log2 |
|---|
| 506 | self.level = level |
|---|
| 507 | self.slope_err = slope_err |
|---|
| 508 | self._set_bitsize() |
|---|
| 509 | self._count_variations() |
|---|
| 510 | self.lft = None |
|---|
| 511 | |
|---|
| 512 | def __str__(self): |
|---|
| 513 | """ |
|---|
| 514 | Reveal all the internals of this interval bernstein polynomial. |
|---|
| 515 | |
|---|
| 516 | EXAMPLES: |
|---|
| 517 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 518 | sage: bp = mk_ibpi([-11, 22, -33], upper=1/9, error=20, lsign=1) |
|---|
| 519 | sage: str(bp) |
|---|
| 520 | '<IBP: (-11, 22, -33) + [0 .. 20) over [0 .. 1/9]; lsign 1>' |
|---|
| 521 | """ |
|---|
| 522 | base = "%s + [0 .. %s)" % (self.coeffs, self.error) |
|---|
| 523 | if self.scale_log2 != 0: |
|---|
| 524 | base = "(%s) * 2^%d" % (base, self.scale_log2) |
|---|
| 525 | s = "<IBP: %s" % base |
|---|
| 526 | if self.lower != 0 or self.upper != 1: |
|---|
| 527 | s += " over [%s .. %s]" % (self.lower, self.upper) |
|---|
| 528 | if (mpz_sgn(self.coeffs._entries[0]) <= 0 and mpz_cmp_si(self.coeffs._entries[0], -self.error) > 0) and self.lsign != 0: |
|---|
| 529 | s += "; lsign %d" % self.lsign |
|---|
| 530 | cdef int n = len(self.coeffs) |
|---|
| 531 | if (mpz_sgn(self.coeffs._entries[n-1]) <= 0 and mpz_cmp_si(self.coeffs._entries[n-1], -self.error) > 0) and self.usign != 0: |
|---|
| 532 | s += "; usign %d" % self.usign |
|---|
| 533 | if self.level != 0: |
|---|
| 534 | s += "; level %d" % self.level |
|---|
| 535 | if not (self.slope_err == 0): |
|---|
| 536 | s += "; slope_err %s" % self.slope_err |
|---|
| 537 | return s + ">" |
|---|
| 538 | |
|---|
| 539 | def __repr__(self): |
|---|
| 540 | """ |
|---|
| 541 | Return a short summary of this interval bernstein polynomial. |
|---|
| 542 | |
|---|
| 543 | EXAMPLES: |
|---|
| 544 | EXAMPLES: |
|---|
| 545 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 546 | sage: bp = mk_ibpi([-11, 22, -33], upper=1/9, error=20, lsign=1) |
|---|
| 547 | sage: bp |
|---|
| 548 | degree 2 IBP with 6-bit coefficients |
|---|
| 549 | sage: repr(bp) |
|---|
| 550 | 'degree 2 IBP with 6-bit coefficients' |
|---|
| 551 | """ |
|---|
| 552 | return "degree %d IBP with %d-bit coefficients" % (len(self.coeffs) - 1, self.bitsize) |
|---|
| 553 | |
|---|
| 554 | def _type_code(self): |
|---|
| 555 | """ |
|---|
| 556 | Classifies this as either an integer representation ('i') or a |
|---|
| 557 | floating-point representation ('f'). |
|---|
| 558 | """ |
|---|
| 559 | return 'i' |
|---|
| 560 | |
|---|
| 561 | cdef void _set_bitsize(self): |
|---|
| 562 | """ |
|---|
| 563 | A private function that computes the maximum coefficient size |
|---|
| 564 | of this Bernstein polynomial (in bits). |
|---|
| 565 | |
|---|
| 566 | EXAMPLES: |
|---|
| 567 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 568 | sage: mk_ibpi([2^12345]) |
|---|
| 569 | degree 0 IBP with 12346-bit coefficients |
|---|
| 570 | sage: mk_ibpi([2^12345 - 1]) |
|---|
| 571 | degree 0 IBP with 12345-bit coefficients |
|---|
| 572 | """ |
|---|
| 573 | self.bitsize = max_bitsize_intvec(self.coeffs) |
|---|
| 574 | |
|---|
| 575 | cdef void _count_variations(self): |
|---|
| 576 | """ |
|---|
| 577 | A private function that counts the number of sign variations in |
|---|
| 578 | this Bernstein polynomial. Since the coefficients are represented |
|---|
| 579 | with intervals, not exactly, we cannot necessarily compute the exact |
|---|
| 580 | number of sign variations; instead, we compute lower and upper |
|---|
| 581 | bounds on this number. |
|---|
| 582 | |
|---|
| 583 | TESTS: |
|---|
| 584 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 585 | sage: mk_ibpi([-1, -2, -3], error=1).variations() |
|---|
| 586 | (0, 0) |
|---|
| 587 | sage: mk_ibpi([-1, -2, -3], error=2).variations() |
|---|
| 588 | (0, 2) |
|---|
| 589 | sage: mk_ibpi([-1, -2, -3], error=2, lsign=-1).variations() |
|---|
| 590 | (0, 2) |
|---|
| 591 | sage: mk_ibpi([-1, -2, -3], error=2, lsign=0).variations() |
|---|
| 592 | (0, 2) |
|---|
| 593 | sage: mk_ibpi([-1, -2, -3], error=2, lsign=1).variations() |
|---|
| 594 | (1, 1) |
|---|
| 595 | sage: mk_ibpi([-1, -2, -3], error=3).variations() |
|---|
| 596 | (0, 2) |
|---|
| 597 | sage: mk_ibpi([-1, -2, -3], error=3, lsign=-1).variations() |
|---|
| 598 | (0, 2) |
|---|
| 599 | sage: mk_ibpi([-1, -2, -3], error=3, lsign=1).variations() |
|---|
| 600 | (1, 1) |
|---|
| 601 | sage: mk_ibpi([-1, -2, -3], error=4).variations() |
|---|
| 602 | (0, 2) |
|---|
| 603 | sage: mk_ibpi([-1, -2, -3], error=4, lsign=-1, usign=1).variations() |
|---|
| 604 | (1, 1) |
|---|
| 605 | sage: mk_ibpi([-1, -2, -3], error=4, lsign=1, usign=-1).variations() |
|---|
| 606 | (1, 1) |
|---|
| 607 | """ |
|---|
| 608 | cdef Vector_integer_dense c = self.coeffs |
|---|
| 609 | |
|---|
| 610 | cdef int count_maybe_pos, count_maybe_neg |
|---|
| 611 | cdef int sign |
|---|
| 612 | cdef int count_definite = 0 |
|---|
| 613 | |
|---|
| 614 | cdef int n = len(c) |
|---|
| 615 | |
|---|
| 616 | cdef int new_count_maybe_pos, new_count_maybe_neg |
|---|
| 617 | |
|---|
| 618 | cdef int lower_sgn, upper_sgn |
|---|
| 619 | |
|---|
| 620 | cdef int i |
|---|
| 621 | |
|---|
| 622 | if self.lsign > 0: |
|---|
| 623 | count_maybe_pos = 0 |
|---|
| 624 | count_maybe_neg = -1 |
|---|
| 625 | sign = 1 |
|---|
| 626 | elif self.lsign < 0: |
|---|
| 627 | count_maybe_pos = -1 |
|---|
| 628 | count_maybe_neg = 0 |
|---|
| 629 | sign = -1 |
|---|
| 630 | else: |
|---|
| 631 | count_maybe_pos = 0 |
|---|
| 632 | count_maybe_neg = 0 |
|---|
| 633 | sign = 0 |
|---|
| 634 | |
|---|
| 635 | for i from 1 <= i < n: |
|---|
| 636 | lower_sgn = mpz_sgn(c._entries[i]) |
|---|
| 637 | upper_sgn = mpz_cmp_si(c._entries[i], -self.error) |
|---|
| 638 | new_count_maybe_pos = count_maybe_pos |
|---|
| 639 | new_count_maybe_neg = count_maybe_neg |
|---|
| 640 | if lower_sgn > 0: |
|---|
| 641 | if sign < 0: |
|---|
| 642 | count_definite = count_definite + 1 |
|---|
| 643 | sign = 1 |
|---|
| 644 | new_count_maybe_neg = -1 |
|---|
| 645 | if upper_sgn <= 0: |
|---|
| 646 | if sign > 0: |
|---|
| 647 | count_definite = count_definite + 1 |
|---|
| 648 | sign = -1 |
|---|
| 649 | new_count_maybe_pos = -1 |
|---|
| 650 | if upper_sgn >= 0 and count_maybe_neg + 1 > new_count_maybe_pos: |
|---|
| 651 | new_count_maybe_pos = count_maybe_neg + 1 |
|---|
| 652 | if lower_sgn < 0 and count_maybe_pos + 1 > new_count_maybe_neg: |
|---|
| 653 | new_count_maybe_neg = count_maybe_pos + 1 |
|---|
| 654 | |
|---|
| 655 | count_maybe_pos = new_count_maybe_pos |
|---|
| 656 | count_maybe_neg = new_count_maybe_neg |
|---|
| 657 | |
|---|
| 658 | if self.usign > 0 and sign < 0: |
|---|
| 659 | count_definite = count_definite + 1 |
|---|
| 660 | if self.usign < 0 and sign > 0: |
|---|
| 661 | count_definite = count_definite + 1 |
|---|
| 662 | self.min_variations = count_definite |
|---|
| 663 | |
|---|
| 664 | if self.usign > 0: |
|---|
| 665 | self.max_variations = count_maybe_pos |
|---|
| 666 | elif self.usign < 0: |
|---|
| 667 | self.max_variations = count_maybe_neg |
|---|
| 668 | else: |
|---|
| 669 | self.max_variations = max(count_maybe_pos, count_maybe_neg) |
|---|
| 670 | |
|---|
| 671 | cdef int degree(self): |
|---|
| 672 | """ |
|---|
| 673 | Returns the (formal) degree of this polynomial. |
|---|
| 674 | """ |
|---|
| 675 | return len(self.coeffs) - 1 |
|---|
| 676 | |
|---|
| 677 | def de_casteljau(self, context ctx, mid, msign=0): |
|---|
| 678 | """ |
|---|
| 679 | Uses de Casteljau's algorithm to compute the representation |
|---|
| 680 | of this polynomial in a Bernstein basis over new regions. |
|---|
| 681 | |
|---|
| 682 | INPUT: |
|---|
| 683 | mid -- where to split the Bernstein basis region; 0 < mid < 1 |
|---|
| 684 | msign -- default 0 (unknown); the sign of this polynomial at mid |
|---|
| 685 | OUTPUT: |
|---|
| 686 | bp1, bp2 -- the new interval Bernstein polynomials |
|---|
| 687 | ok -- a boolean; True if the sign of the original polynomial at mid is known |
|---|
| 688 | |
|---|
| 689 | EXAMPLES: |
|---|
| 690 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 691 | sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5) |
|---|
| 692 | sage: ctx = mk_context() |
|---|
| 693 | sage: bp1, bp2, ok = bp.de_casteljau(ctx, 1/2) |
|---|
| 694 | sage: str(bp1) |
|---|
| 695 | '<IBP: (50, 35, 0, -29, -31) + [0 .. 6) over [0 .. 1/2]>' |
|---|
| 696 | sage: str(bp2) |
|---|
| 697 | '<IBP: (-31, -33, -8, 65, 200) + [0 .. 6) over [1/2 .. 1]>' |
|---|
| 698 | sage: bp1, bp2, ok = bp.de_casteljau(ctx, 2/3) |
|---|
| 699 | sage: str(bp1) |
|---|
| 700 | '<IBP: (50, 30, -26, -55, -13) + [0 .. 6) over [0 .. 2/3]>' |
|---|
| 701 | sage: str(bp2) |
|---|
| 702 | '<IBP: (-13, 8, 47, 110, 200) + [0 .. 6) over [2/3 .. 1]>' |
|---|
| 703 | sage: bp1, bp2, ok = bp.de_casteljau(ctx, 7/39) |
|---|
| 704 | sage: str(bp1) |
|---|
| 705 | '<IBP: (50, 44, 36, 27, 17) + [0 .. 6) over [0 .. 7/39]>' |
|---|
| 706 | sage: str(bp2) |
|---|
| 707 | '<IBP: (17, -26, -75, -22, 200) + [0 .. 6) over [7/39 .. 1]>' |
|---|
| 708 | """ |
|---|
| 709 | (c1_, c2_, err_inc) = de_casteljau_intvec(self.coeffs, self.bitsize, mid, ctx.wordsize == 32) |
|---|
| 710 | cdef Vector_integer_dense c1 = c1_ |
|---|
| 711 | cdef Vector_integer_dense c2 = c2_ |
|---|
| 712 | |
|---|
| 713 | cdef int new_err = self.error + err_inc |
|---|
| 714 | |
|---|
| 715 | cdef int sign = 0 |
|---|
| 716 | |
|---|
| 717 | if mpz_sgn(c2._entries[0]) > 0: |
|---|
| 718 | sign = 1 |
|---|
| 719 | if mpz_cmp_si(c2._entries[0], -new_err) <= 0: |
|---|
| 720 | sign = -1 |
|---|
| 721 | |
|---|
| 722 | if msign == 0: |
|---|
| 723 | msign = sign |
|---|
| 724 | elif sign != 0: |
|---|
| 725 | assert(msign == sign) |
|---|
| 726 | |
|---|
| 727 | cdef Rational absolute_mid = self.lower + mid * (self.upper - self.lower) |
|---|
| 728 | |
|---|
| 729 | cdef interval_bernstein_polynomial_integer bp1, bp2 |
|---|
| 730 | bp1 = interval_bernstein_polynomial_integer(c1, self.lower, absolute_mid, self.lsign, msign, new_err, self.scale_log2, self.level, self.slope_err) |
|---|
| 731 | bp2 = interval_bernstein_polynomial_integer(c2, absolute_mid, self.upper, msign, self.usign, new_err, self.scale_log2, self.level, self.slope_err) |
|---|
| 732 | |
|---|
| 733 | if self.lft is not None: |
|---|
| 734 | (a, b, c, d) = self.lft |
|---|
| 735 | bp1.lft = (a * mid, b, c * mid, d) |
|---|
| 736 | bp2.lft = (a * (1-mid), b + a*mid, c * (1-mid), d + c*mid) |
|---|
| 737 | |
|---|
| 738 | if msign != 0: |
|---|
| 739 | self.update_variations(bp1, bp2) |
|---|
| 740 | |
|---|
| 741 | return (bp1, bp2, msign != 0) |
|---|
| 742 | |
|---|
| 743 | def as_float(self): |
|---|
| 744 | """ |
|---|
| 745 | Compute an interval_bernstein_polynomial_float which contains |
|---|
| 746 | (or bounds) all the polynomials this interval polynomial |
|---|
| 747 | contains (or bounds). |
|---|
| 748 | |
|---|
| 749 | EXAMPLES: |
|---|
| 750 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 751 | sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5) |
|---|
| 752 | sage: bp.as_float() |
|---|
| 753 | degree 4 IBP with floating-point coefficients |
|---|
| 754 | sage: str(bp.as_float()) |
|---|
| 755 | '<IBP: ((0.1953125, 0.078125, -0.3515625, -0.2734375, 0.78125) + [-1.11022302463e-16 .. 0.01953125]) * 2^8>' |
|---|
| 756 | """ |
|---|
| 757 | (fcoeffs, neg_err, pos_err, scale_log2_delta) = intvec_to_doublevec(self.coeffs, self.error) |
|---|
| 758 | cdef interval_bernstein_polynomial_float fbp = interval_bernstein_polynomial_float(fcoeffs, self.lower, self.upper, self.lsign, self.usign, neg_err, pos_err, self.scale_log2 + scale_log2_delta, self.level, self.slope_err) |
|---|
| 759 | fbp.min_variations = self.min_variations |
|---|
| 760 | fbp.max_variations = self.max_variations |
|---|
| 761 | return fbp |
|---|
| 762 | |
|---|
| 763 | def get_msb_bit(self): |
|---|
| 764 | """ |
|---|
| 765 | Returns an approximation of the log2 of the maximum of the |
|---|
| 766 | absolute values of the coefficients, as an integer. |
|---|
| 767 | """ |
|---|
| 768 | return self.scale_log2 + self.bitsize |
|---|
| 769 | |
|---|
| 770 | def down_degree(self, context ctx, max_err, exp_err_shift): |
|---|
| 771 | """ |
|---|
| 772 | Compute an interval_bernstein_polynomial_integer which bounds |
|---|
| 773 | all the polynomials this interval polynomial bounds, but is |
|---|
| 774 | of lesser degree. |
|---|
| 775 | |
|---|
| 776 | During the computation, we find an "expected error" |
|---|
| 777 | expected_err, which is the error inherent in our approach |
|---|
| 778 | (this depends on the degrees involved, and is proportional |
|---|
| 779 | to the error of the current polynomial). |
|---|
| 780 | |
|---|
| 781 | We require that the error of the new interval polynomial |
|---|
| 782 | be bounded both by max_err, and by expected_err << exp_err_shift. |
|---|
| 783 | If we find such a polynomial p, then we return a pair of p and some |
|---|
| 784 | debugging/logging information. Otherwise, we return the pair |
|---|
| 785 | (None, None). |
|---|
| 786 | |
|---|
| 787 | If the resulting polynomial would have error more than 2^17, |
|---|
| 788 | then it is downscaled before returning. |
|---|
| 789 | |
|---|
| 790 | EXAMPLES: |
|---|
| 791 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 792 | sage: bp = mk_ibpi([0, 100, 400, 903], error=2) |
|---|
| 793 | sage: ctx = mk_context() |
|---|
| 794 | sage: str(bp) |
|---|
| 795 | '<IBP: (0, 100, 400, 903) + [0 .. 2)>' |
|---|
| 796 | sage: dbp, _ = bp.down_degree(ctx, 10, 32) |
|---|
| 797 | sage: str(dbp) |
|---|
| 798 | '<IBP: (-1, 148, 901) + [0 .. 4); level 1; slope_err [-24.000000000000000 .. 24.000000000000000]>' |
|---|
| 799 | """ |
|---|
| 800 | |
|---|
| 801 | # return (None, None) |
|---|
| 802 | |
|---|
| 803 | degree = self.degree() |
|---|
| 804 | |
|---|
| 805 | try: |
|---|
| 806 | (next, downmat, expected_err, (bdi, den)) = dr_cache[degree] |
|---|
| 807 | except KeyError: |
|---|
| 808 | precompute_degree_reduction_cache(degree) |
|---|
| 809 | (next, downmat, expected_err, (bdi, den)) = dr_cache[degree] |
|---|
| 810 | |
|---|
| 811 | expected_err = expected_err * self.error |
|---|
| 812 | if expected_err > max_err: |
|---|
| 813 | return (None, ('$', self.scale_log2 + bitsize(expected_err))) |
|---|
| 814 | |
|---|
| 815 | if (expected_err << exp_err_shift) < max_err: |
|---|
| 816 | max_err = (expected_err << exp_err_shift) |
|---|
| 817 | |
|---|
| 818 | v0 = dprod_imatrow_vec(bdi, self.coeffs, 0) // den |
|---|
| 819 | # v0 = dprod_matrow_vec(downmat, self.coeffs, 0) |
|---|
| 820 | v0_err = abs(v0 - self.coeffs[0]) |
|---|
| 821 | if v0_err > max_err: |
|---|
| 822 | return (None, ('>', self.scale_log2 + bitsize(v0_err))) |
|---|
| 823 | vn = dprod_imatrow_vec(bdi, self.coeffs, next) // den |
|---|
| 824 | # vn = dprod_matrow_vec(downmat, self.coeffs, next) |
|---|
| 825 | vn_err = abs(vn - self.coeffs[degree]) |
|---|
| 826 | if vn_err > max_err: |
|---|
| 827 | return (None, ('>', self.scale_log2 + bitsize(vn_err))) |
|---|
| 828 | ribp = (ZZ**(next+1))(0) |
|---|
| 829 | ribp[0] = v0 |
|---|
| 830 | ribp[next] = vn |
|---|
| 831 | for i in range(1, next): |
|---|
| 832 | ribp[i] = dprod_imatrow_vec(bdi, self.coeffs, i) // den |
|---|
| 833 | |
|---|
| 834 | before = time.time() |
|---|
| 835 | (eribp, err_inc) = bernstein_expand(ribp, self.degree()) |
|---|
| 836 | after = time.time() |
|---|
| 837 | (base_max, base_min) = min_max_delta_intvec(self.coeffs, eribp) |
|---|
| 838 | err_max = base_max + self.error |
|---|
| 839 | err_min = base_min - err_inc |
|---|
| 840 | for i in range(len(ribp)): |
|---|
| 841 | ribp[i] = ribp[i] + err_min |
|---|
| 842 | err = err_max - err_min |
|---|
| 843 | |
|---|
| 844 | ctx.be_log_append((after - before, self.scale_log2, max_bitsize_intvec(ribp), err < max_err, err_max, err_min, err_inc, self.degree(), next, self.variations())) |
|---|
| 845 | if err < max_err: |
|---|
| 846 | rng = RIF(-2*err, 2*err) |
|---|
| 847 | rng = rng * self.degree() |
|---|
| 848 | width = self.region_width() |
|---|
| 849 | rng = rng / width |
|---|
| 850 | if self.scale_log2 >= 0: |
|---|
| 851 | rng = rng << self.scale_log2 |
|---|
| 852 | else: |
|---|
| 853 | rng = rng >> (-self.scale_log2) |
|---|
| 854 | # slope_err could be smaller by actually computing |
|---|
| 855 | # the derivative of the error polynomial |
|---|
| 856 | slope_err = rng |
|---|
| 857 | lsb = self.scale_log2 |
|---|
| 858 | if err <= expected_err: |
|---|
| 859 | indicator = '<' |
|---|
| 860 | else: |
|---|
| 861 | indicator = '=' |
|---|
| 862 | if bitsize(err) > 17: |
|---|
| 863 | shift = bitsize(err) - 15 |
|---|
| 864 | for i in xrange(len(ribp)): |
|---|
| 865 | ribp[i] = ribp[i] >> shift |
|---|
| 866 | max_err = max_err >> shift |
|---|
| 867 | err = -((-err) >> shift) |
|---|
| 868 | lsb = lsb + shift |
|---|
| 869 | ibp = interval_bernstein_polynomial_integer(ribp, self.lower, self.upper, self.lsign, self.usign, err, lsb, self.level+1, self.slope_err + slope_err) |
|---|
| 870 | |
|---|
| 871 | return (ibp, (indicator, lsb + bitsize(err))) |
|---|
| 872 | else: |
|---|
| 873 | return (None, ('=', self.scale_log2 + bitsize(err))) |
|---|
| 874 | |
|---|
| 875 | def down_degree_iter(self, context ctx, max_scale): |
|---|
| 876 | """ |
|---|
| 877 | Compute a degree-reduced version of this interval polynomial, by |
|---|
| 878 | iterating down_degree. |
|---|
| 879 | |
|---|
| 880 | We stop when degree reduction would give a polynomial which is |
|---|
| 881 | too inaccurate, meaning that either we think the current polynomial |
|---|
| 882 | may have more roots in its region than the degree of the |
|---|
| 883 | reduced polynomial, or that the least significant accurate bit |
|---|
| 884 | in the result (on the absolute scale) would be larger than |
|---|
| 885 | 1 << max_scale. |
|---|
| 886 | |
|---|
| 887 | EXAMPLES: |
|---|
| 888 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 889 | sage: bp = mk_ibpi([0, 100, 400, 903, 1600, 2500], error=2) |
|---|
| 890 | sage: ctx = mk_context() |
|---|
| 891 | sage: str(bp) |
|---|
| 892 | '<IBP: (0, 100, 400, 903, 1600, 2500) + [0 .. 2)>' |
|---|
| 893 | sage: rbp = bp.down_degree_iter(ctx, 6) |
|---|
| 894 | sage: str(rbp) |
|---|
| 895 | '<IBP: (-4, 249, 2497) + [0 .. 9); level 2; slope_err [-114.00000000000000 .. 114.00000000000000]>' |
|---|
| 896 | """ |
|---|
| 897 | |
|---|
| 898 | cdef interval_bernstein_polynomial bp = self |
|---|
| 899 | |
|---|
| 900 | while True: |
|---|
| 901 | next = degree_reduction_next_size(bp.degree()) |
|---|
| 902 | if next is None: return bp |
|---|
| 903 | if bp.variations()[0] > next: |
|---|
| 904 | return bp |
|---|
| 905 | (rbp, err_info) = bp.down_degree(ctx, Integer(1) << (max_scale - bp.scale_log2), 32) |
|---|
| 906 | ctx.dc_log_append(('down_degree', rbp is not None, err_info)) |
|---|
| 907 | if rbp is None: |
|---|
| 908 | # global dd_count_no |
|---|
| 909 | # dd_count_no += 1 |
|---|
| 910 | return bp |
|---|
| 911 | else: |
|---|
| 912 | # global dd_count_yes |
|---|
| 913 | # dd_count_yes += 1 |
|---|
| 914 | bp = rbp |
|---|
| 915 | |
|---|
| 916 | def downscale(self, bits): |
|---|
| 917 | """ |
|---|
| 918 | Compute an interval_bernstein_polynomial_integer which |
|---|
| 919 | contains (or bounds) all the polynomials this interval |
|---|
| 920 | polynomial contains (or bounds), but uses |
|---|
| 921 | "bits" fewer bits. |
|---|
| 922 | |
|---|
| 923 | EXAMPLES: |
|---|
| 924 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 925 | sage: bp = mk_ibpi([0, 100, 400, 903], error=2) |
|---|
| 926 | sage: str(bp.downscale(5)) |
|---|
| 927 | '<IBP: ((0, 3, 12, 28) + [0 .. 1)) * 2^5>' |
|---|
| 928 | """ |
|---|
| 929 | p = self.coeffs.__copy__() |
|---|
| 930 | for i in xrange(len(p)): |
|---|
| 931 | p[i] = p[i] >> bits |
|---|
| 932 | return interval_bernstein_polynomial_integer(p, self.lower, self.upper, self.lsign, self.usign, -((-self.error) >> bits), self.scale_log2 + bits, self.level, self.slope_err) |
|---|
| 933 | |
|---|
| 934 | def slope_range(self): |
|---|
| 935 | """ |
|---|
| 936 | Compute a bound on the derivative of this polynomial, over its region. |
|---|
| 937 | |
|---|
| 938 | EXAMPLES: |
|---|
| 939 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 940 | sage: bp = mk_ibpi([0, 100, 400, 903], error=2) |
|---|
| 941 | sage: bp.slope_range() |
|---|
| 942 | [294.00000000000000 .. 1515.0000000000000] |
|---|
| 943 | """ |
|---|
| 944 | width = self.region_width() |
|---|
| 945 | (min_diff, max_diff) = min_max_diff_intvec(self.coeffs) |
|---|
| 946 | rng = RIF(min_diff - self.error, max_diff + self.error) |
|---|
| 947 | rng = rng * (len(self.coeffs) - 1) |
|---|
| 948 | rng = rng / width |
|---|
| 949 | if self.scale_log2 >= 0: |
|---|
| 950 | rng = rng << self.scale_log2 |
|---|
| 951 | else: |
|---|
| 952 | rng = rng >> (-self.scale_log2) |
|---|
| 953 | return rng |
|---|
| 954 | |
|---|
| 955 | def mk_ibpi(coeffs, lower=0, upper=1, lsign=0, usign=0, error=1, scale_log2=0, |
|---|
| 956 | level=0, slope_err=RIF(0)): |
|---|
| 957 | """ |
|---|
| 958 | A simple wrapper for creating interval_bernstein_polynomial_integer |
|---|
| 959 | objects with coercions, defaults, etc. |
|---|
| 960 | |
|---|
| 961 | For use in doctests. |
|---|
| 962 | |
|---|
| 963 | EXAMPLES: |
|---|
| 964 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 965 | sage: mk_ibpi([50, 20, -90, -70, 200], error=5) |
|---|
| 966 | degree 4 IBP with 8-bit coefficients |
|---|
| 967 | """ |
|---|
| 968 | return interval_bernstein_polynomial_integer(vector(ZZ, coeffs), QQ(lower), QQ(upper), lsign, usign, error, scale_log2, level, slope_err) |
|---|
| 969 | |
|---|
| 970 | def de_casteljau_intvec(Vector_integer_dense c, int c_bitsize, Rational x, int use_ints): |
|---|
| 971 | """ |
|---|
| 972 | Given a polynomial in Bernstein form with integer coefficients |
|---|
| 973 | over the region [0 .. 1], and a split point x, use de Casteljau's |
|---|
| 974 | algorithm to give polynomials in Bernstein form over [0 .. x] and |
|---|
| 975 | [x .. 1]. |
|---|
| 976 | |
|---|
| 977 | This function will work for an arbitrary rational split point x, as |
|---|
| 978 | long as 0 < x < 1; but it has specialized code paths that make |
|---|
| 979 | some values of x faster than others. If x == a/(a + b), |
|---|
| 980 | there are special efficient cases for a==1, b==1, a+b fits in a machine |
|---|
| 981 | word, a+b is a power of 2, a fits in a machine word, b fits in |
|---|
| 982 | a machine word. The most efficient case is x==1/2. |
|---|
| 983 | |
|---|
| 984 | Given split points x == a/(a + b) and y == c/(c + d), where |
|---|
| 985 | min(a, b) and min(c, d) fit in the same number of machine words |
|---|
| 986 | and a+b and c+d are both powers of two, then x and y should be |
|---|
| 987 | equally fast split points. |
|---|
| 988 | |
|---|
| 989 | If use_ints is nonzero, then instead of checking whether numerators |
|---|
| 990 | and denominators fit in machine words, we check whether they fit in |
|---|
| 991 | ints (32 bits, even on 64-bit machines). This slows things down, but |
|---|
| 992 | allows for identical results across machines. |
|---|
| 993 | |
|---|
| 994 | INPUT: |
|---|
| 995 | c -- vector of coefficients of polynomial in Bernstein form |
|---|
| 996 | c_bitsize -- approximate size of coefficients in c (in bits) |
|---|
| 997 | x -- rational splitting point; 0 < x < 1 |
|---|
| 998 | |
|---|
| 999 | OUTPUT: |
|---|
| 1000 | c1 -- coefficients of polynomial over range [0 .. x] |
|---|
| 1001 | c2 -- coefficients of polynomial over range [x .. 1] |
|---|
| 1002 | err_inc -- amount by which error intervals widened |
|---|
| 1003 | |
|---|
| 1004 | EXAMPLES: |
|---|
| 1005 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1006 | sage: c = vector(ZZ, [1048576, 0, 0, 0, 0, 0]) |
|---|
| 1007 | sage: de_casteljau_intvec(c, 20, 1/2, 1) |
|---|
| 1008 | ((1048576, 524288, 262144, 131072, 65536, 32768), (32768, 0, 0, 0, 0, 0), 1) |
|---|
| 1009 | sage: de_casteljau_intvec(c, 20, 1/3, 1) |
|---|
| 1010 | ((1048576, 699050, 466033, 310689, 207126, 138084), (138084, 0, 0, 0, 0, 0), 1) |
|---|
| 1011 | sage: de_casteljau_intvec(c, 20, 7/22, 1) |
|---|
| 1012 | ((1048576, 714938, 487457, 332357, 226607, 154505), (154505, 0, 0, 0, 0, 0), 1) |
|---|
| 1013 | """ |
|---|
| 1014 | vs = c.parent() |
|---|
| 1015 | |
|---|
| 1016 | cdef Vector_integer_dense c1, c2, den_powers |
|---|
| 1017 | |
|---|
| 1018 | c1 = Vector_integer_dense(vs, 0) |
|---|
| 1019 | c2 = c.__copy__() |
|---|
| 1020 | |
|---|
| 1021 | cdef int n = len(c) |
|---|
| 1022 | |
|---|
| 1023 | cdef int i, j |
|---|
| 1024 | |
|---|
| 1025 | cdef mpz_t num, den, diff, tmp, tmp2 |
|---|
| 1026 | |
|---|
| 1027 | cdef unsigned long num_ui, den_ui, diff_ui |
|---|
| 1028 | cdef int num_fits_ui, den_fits_ui, diff_fits_ui |
|---|
| 1029 | cdef int den_is_pow2, den_log2 |
|---|
| 1030 | cdef int num_less_diff |
|---|
| 1031 | |
|---|
| 1032 | cdef int max_den_power |
|---|
| 1033 | |
|---|
| 1034 | # We want to compute (diff*a + num*b)/den. This costs |
|---|
| 1035 | # 2*mul, 1*div, 1*add/sub. |
|---|
| 1036 | # We see below a way to trade a multiplication for a subtraction, |
|---|
| 1037 | # for a cost of 1*mul, 1*div, 2*add/sub. |
|---|
| 1038 | # Another possibility is to postpone divisions, for a cost of |
|---|
| 1039 | # 2*mul, 1/6*div, 1*add/sub. Clearly, this is worthwhile if |
|---|
| 1040 | # 5/6*div + 1*add/sub > 1*mul. This is very likely true whenever |
|---|
| 1041 | # the denominator is not a power of 2 (so that you have to do |
|---|
| 1042 | # real divisions, instead of shifts), and might be true in other cases. |
|---|
| 1043 | |
|---|
| 1044 | # If one of the multiplications is by 1, then the costs become: |
|---|
| 1045 | # straightforward: 1*mul, 1*div, 1*add/sub |
|---|
| 1046 | # trade mul->sub: 1*div, 2*add/sub |
|---|
| 1047 | # postpone division: 1*mul, 1/6*div, 1*add/sub |
|---|
| 1048 | # for the same result. |
|---|
| 1049 | |
|---|
| 1050 | # If both multiplications are by 1, then the costs are: |
|---|
| 1051 | # straightforward: 1*div, 1*add/sub |
|---|
| 1052 | # trade mul->sub: 1*div, 2*add/sub |
|---|
| 1053 | # postpone division: 1/6*div, 1*add/sub |
|---|
| 1054 | # with postpone division being the obvious winner. |
|---|
| 1055 | |
|---|
| 1056 | # For now, we use "postpone division" whenever the denominator fits |
|---|
| 1057 | # in an unsigned long. This is not going to be drastically bad, |
|---|
| 1058 | # even when dividing by a power of two. For full generality, |
|---|
| 1059 | # it would also be important to use "postpone division" for |
|---|
| 1060 | # non-power-of-two denominators that do not fit in an unsigned long; |
|---|
| 1061 | # however, the current calling code essentially never does that, |
|---|
| 1062 | # so we'll stick with simpler code here. |
|---|
| 1063 | |
|---|
| 1064 | mpz_init(num) |
|---|
| 1065 | mpz_init(den) |
|---|
| 1066 | mpz_init(diff) |
|---|
| 1067 | mpz_init(tmp) |
|---|
| 1068 | mpz_init(tmp2) |
|---|
| 1069 | |
|---|
| 1070 | mpq_get_num(num, x.value) |
|---|
| 1071 | mpq_get_den(den, x.value) |
|---|
| 1072 | mpz_sub(diff, den, num) |
|---|
| 1073 | |
|---|
| 1074 | if use_ints: |
|---|
| 1075 | den_fits_ui = mpz_fits_uint_p(den) |
|---|
| 1076 | num_fits_ui = mpz_fits_uint_p(num) |
|---|
| 1077 | diff_fits_ui = mpz_fits_uint_p(diff) |
|---|
| 1078 | else: |
|---|
| 1079 | den_fits_ui = mpz_fits_ulong_p(den) |
|---|
| 1080 | num_fits_ui = mpz_fits_ulong_p(num) |
|---|
| 1081 | diff_fits_ui = mpz_fits_ulong_p(diff) |
|---|
| 1082 | |
|---|
| 1083 | if den_fits_ui: |
|---|
| 1084 | den_ui = mpz_get_ui(den) |
|---|
| 1085 | if num_fits_ui: |
|---|
| 1086 | num_ui = mpz_get_ui(num) |
|---|
| 1087 | if diff_fits_ui: |
|---|
| 1088 | diff_ui = mpz_get_ui(diff) |
|---|
| 1089 | |
|---|
| 1090 | mpz_sub_ui(tmp, den, 1) |
|---|
| 1091 | mpz_and(tmp, tmp, den) |
|---|
| 1092 | den_is_pow2 = (mpz_sgn(tmp) == 0) |
|---|
| 1093 | if den_is_pow2: |
|---|
| 1094 | den_log2 = mpz_sizeinbase(den, 2) - 1 |
|---|
| 1095 | |
|---|
| 1096 | cdef int max_den_bits = c_bitsize / 2 |
|---|
| 1097 | if max_den_bits < 100: max_den_bits = 100 |
|---|
| 1098 | # These settings are slower than the above on laguerre(1000), but that's |
|---|
| 1099 | # the only experiment I've done so far... more testing is needed. |
|---|
| 1100 | # cdef int max_den_bits = 3 * c_bitsize / 2 |
|---|
| 1101 | # if max_den_bits < 100: max_den_bits = 300 |
|---|
| 1102 | |
|---|
| 1103 | cdef int cur_den_steps = 0 |
|---|
| 1104 | |
|---|
| 1105 | cdef int ndivs = 0 |
|---|
| 1106 | |
|---|
| 1107 | if den_fits_ui: |
|---|
| 1108 | den_powers = FreeModule(ZZ, len(c)+1)(0) |
|---|
| 1109 | mpz_set_ui(den_powers._entries[0], 1) |
|---|
| 1110 | max_den_power = 1 |
|---|
| 1111 | for i from 1 <= i <= n: |
|---|
| 1112 | mpz_mul_ui(den_powers._entries[i], den_powers._entries[i-1], den_ui) |
|---|
| 1113 | if mpz_sizeinbase(den_powers._entries[i], 2) < max_den_bits: |
|---|
| 1114 | max_den_power = i |
|---|
| 1115 | else: |
|---|
| 1116 | break |
|---|
| 1117 | |
|---|
| 1118 | for i from 0 <= i < n: |
|---|
| 1119 | mpz_set(c1._entries[i], c2._entries[0]) |
|---|
| 1120 | if den_ui == 2: |
|---|
| 1121 | # x == 1/2 |
|---|
| 1122 | for j from 0 <= j < n-i-1: |
|---|
| 1123 | mpz_add(c2._entries[j], c2._entries[j], c2._entries[j+1]) |
|---|
| 1124 | else: |
|---|
| 1125 | for j from 0 <= j < n-i-1: |
|---|
| 1126 | if diff_ui != 1: |
|---|
| 1127 | mpz_mul_ui(c2._entries[j], c2._entries[j], diff_ui) |
|---|
| 1128 | if num_ui == 1: |
|---|
| 1129 | mpz_add(c2._entries[j], c2._entries[j], c2._entries[j+1]) |
|---|
| 1130 | else: |
|---|
| 1131 | mpz_addmul_ui(c2._entries[j], c2._entries[j+1], num_ui) |
|---|
| 1132 | cur_den_steps = cur_den_steps + 1 |
|---|
| 1133 | if cur_den_steps == max_den_power or i == n-1: |
|---|
| 1134 | if den_is_pow2: |
|---|
| 1135 | for j from 1 <= j < cur_den_steps: |
|---|
| 1136 | mpz_fdiv_q_2exp(c1._entries[i-cur_den_steps+j+1], |
|---|
| 1137 | c1._entries[i-cur_den_steps+j+1], |
|---|
| 1138 | j*den_log2) |
|---|
| 1139 | mpz_fdiv_q_2exp(c2._entries[n-i+cur_den_steps-j-2], |
|---|
| 1140 | c2._entries[n-i+cur_den_steps-j-2], |
|---|
| 1141 | j*den_log2) |
|---|
| 1142 | for j from 0 <= j < n-i-1: |
|---|
| 1143 | mpz_fdiv_q_2exp(c2._entries[j], c2._entries[j], |
|---|
| 1144 | cur_den_steps*den_log2) |
|---|
| 1145 | else: |
|---|
| 1146 | for j from 1 <= j < cur_den_steps: |
|---|
| 1147 | mpz_fdiv_q(c1._entries[i-cur_den_steps+j+1], |
|---|
| 1148 | c1._entries[i-cur_den_steps+j+1], |
|---|
| 1149 | den_powers._entries[j]) |
|---|
| 1150 | mpz_fdiv_q(c2._entries[n-i+cur_den_steps-j-2], |
|---|
| 1151 | c2._entries[n-i+cur_den_steps-j-2], |
|---|
| 1152 | den_powers._entries[j]) |
|---|
| 1153 | for j from 0 <= j < n-i-1: |
|---|
| 1154 | mpz_fdiv_q(c2._entries[j], c2._entries[j], |
|---|
| 1155 | den_powers._entries[cur_den_steps]) |
|---|
| 1156 | cur_den_steps = 0 |
|---|
| 1157 | ndivs = ndivs+1 |
|---|
| 1158 | else: |
|---|
| 1159 | # We want to compute (diff*a + num*b)/den, where |
|---|
| 1160 | # a == c2._entries[j] and b == c2._entries[j+1]. |
|---|
| 1161 | # The result goes in c2._entries[j]. Since den == diff + num, |
|---|
| 1162 | # this is equal to a + num*(b-a)/den or diff*(a-b)/den + b. |
|---|
| 1163 | # If num<diff, we compute the former, otherwise the latter. |
|---|
| 1164 | |
|---|
| 1165 | |
|---|
| 1166 | num_less_diff = (mpz_cmp(num, diff) < 0) |
|---|
| 1167 | |
|---|
| 1168 | ndivs = n-1 |
|---|
| 1169 | |
|---|
| 1170 | for i from 0 <= i < n: |
|---|
| 1171 | mpz_set(c1._entries[i], c2._entries[0]) |
|---|
| 1172 | for j from 0 <= j < n-i-1: |
|---|
| 1173 | if num_less_diff: |
|---|
| 1174 | mpz_sub(tmp, c2._entries[j+1], c2._entries[j]) |
|---|
| 1175 | if num_fits_ui and num_ui == 1: |
|---|
| 1176 | if den_is_pow2: |
|---|
| 1177 | mpz_fdiv_q_2exp(tmp2, tmp, den_log2) |
|---|
| 1178 | elif den_fits_ui: |
|---|
| 1179 | mpz_fdiv_q_ui(tmp2, tmp, den_ui) |
|---|
| 1180 | else: |
|---|
| 1181 | mpz_fdiv_q(tmp2, tmp, den) |
|---|
| 1182 | mpz_add(c2._entries[j], c2._entries[j], tmp2) |
|---|
| 1183 | else: |
|---|
| 1184 | if num_fits_ui: |
|---|
| 1185 | mpz_mul_ui(tmp2, tmp, num_ui) |
|---|
| 1186 | else: |
|---|
| 1187 | mpz_mul(tmp2, tmp, num) |
|---|
| 1188 | if den_is_pow2: |
|---|
| 1189 | mpz_fdiv_q_2exp(tmp, tmp2, den_log2) |
|---|
| 1190 | elif den_fits_ui: |
|---|
| 1191 | mpz_fdiv_q_ui(tmp, tmp2, den_ui) |
|---|
| 1192 | else: |
|---|
| 1193 | mpz_fdiv_q(tmp, tmp2, den) |
|---|
| 1194 | mpz_add(c2._entries[j], c2._entries[j], tmp) |
|---|
| 1195 | else: |
|---|
| 1196 | mpz_sub(c2._entries[j], c2._entries[j], c2._entries[j+1]) |
|---|
| 1197 | if diff_fits_ui: |
|---|
| 1198 | if diff_ui == 1: |
|---|
| 1199 | mpz_set(tmp, c2._entries[j]) |
|---|
| 1200 | else: |
|---|
| 1201 | mpz_mul_ui(tmp, c2._entries[j], diff_ui) |
|---|
| 1202 | else: |
|---|
| 1203 | mpz_mul(tmp, c2._entries[j], diff) |
|---|
| 1204 | if den_is_pow2: |
|---|
| 1205 | mpz_fdiv_q_2exp(c2._entries[j], tmp, den_log2) |
|---|
| 1206 | elif den_fits_ui: |
|---|
| 1207 | mpz_fdiv_q_ui(c2._entries[j], tmp, den_ui) |
|---|
| 1208 | else: |
|---|
| 1209 | mpz_fdiv_q(c2._entries[j], tmp, den) |
|---|
| 1210 | mpz_add(c2._entries[j], c2._entries[j], c2._entries[j+1]) |
|---|
| 1211 | |
|---|
| 1212 | mpz_clear(num) |
|---|
| 1213 | mpz_clear(den) |
|---|
| 1214 | mpz_clear(diff) |
|---|
| 1215 | mpz_clear(tmp) |
|---|
| 1216 | mpz_clear(tmp2) |
|---|
| 1217 | |
|---|
| 1218 | return (c1, c2, ndivs) |
|---|
| 1219 | |
|---|
| 1220 | # An ULP is a "unit in the last place"; it is the (varying) unit for |
|---|
| 1221 | # how much adjacent floating-point numbers differ from each other. |
|---|
| 1222 | # A half-ULP is half this amount; it is the maximum rounding error |
|---|
| 1223 | # in the basic operations (+,-,*,/) in a correctly-operating IEEE |
|---|
| 1224 | # floating-point unit. |
|---|
| 1225 | # (Note that by default, the x86 does not use IEEE double precision; |
|---|
| 1226 | # instead, it uses extra precision, which can (counterintuitively) |
|---|
| 1227 | # actually give worse double-precision results in some rare cases. |
|---|
| 1228 | # To avoid this, we change the x86 floating-point unit into true |
|---|
| 1229 | # double-precision mode in places where it matters; that is, in |
|---|
| 1230 | # functions that add, subtract, multiply, or divide floating-point numbers. |
|---|
| 1231 | # Functions whose floating-point operations are limited to negation |
|---|
| 1232 | # and comparison do not require special treatment, since those operations |
|---|
| 1233 | # give the same results in double-precision or extended precision.) |
|---|
| 1234 | |
|---|
| 1235 | # This is the value of a half-ULP for numbers in the range 0.5 <= x < 1. |
|---|
| 1236 | cdef double half_ulp = ldexp(1.0, -54) |
|---|
| 1237 | |
|---|
| 1238 | def intvec_to_doublevec(Vector_integer_dense b, long err): |
|---|
| 1239 | """ |
|---|
| 1240 | Given a vector of integers A = [a1, ..., an], and an integer |
|---|
| 1241 | error bound E, returns a vector of floating-point numbers |
|---|
| 1242 | B = [b1, ..., bn], lower and upper error bounds F1 and F2, and |
|---|
| 1243 | a scaling factor d, such that |
|---|
| 1244 | (bk + F1) * 2^d <= ak |
|---|
| 1245 | and |
|---|
| 1246 | ak + E <= (bk + F2) * 2^d |
|---|
| 1247 | |
|---|
| 1248 | If bj is the element of B with largest absolute value, then |
|---|
| 1249 | 0.5 <= abs(bj) < 1.0 . |
|---|
| 1250 | |
|---|
| 1251 | EXAMPLES: |
|---|
| 1252 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1253 | sage: intvec_to_doublevec(vector(ZZ, [1, 2, 3, 4, 5]), 3) |
|---|
| 1254 | ((0.125, 0.25, 0.375, 0.5, 0.625), -1.1102230246251565e-16, 0.37500000000000017, 3) |
|---|
| 1255 | """ |
|---|
| 1256 | cdef unsigned int cwf |
|---|
| 1257 | fpu_fix_start(&cwf) |
|---|
| 1258 | |
|---|
| 1259 | vs = FreeModule(RDF, len(b)) |
|---|
| 1260 | |
|---|
| 1261 | cdef RealDoubleVectorSpaceElement db = vs(0) |
|---|
| 1262 | |
|---|
| 1263 | cdef long max_exp = -10000 |
|---|
| 1264 | cdef long cur_exp |
|---|
| 1265 | |
|---|
| 1266 | cdef int i |
|---|
| 1267 | |
|---|
| 1268 | for i from 0 <= i < len(b): |
|---|
| 1269 | mpz_get_d_2exp(&cur_exp, b._entries[i]) |
|---|
| 1270 | if cur_exp > max_exp: |
|---|
| 1271 | max_exp = cur_exp |
|---|
| 1272 | |
|---|
| 1273 | cdef int delta = -max_exp |
|---|
| 1274 | cdef double d |
|---|
| 1275 | cdef int new_exp |
|---|
| 1276 | cdef double half = 0.5 |
|---|
| 1277 | |
|---|
| 1278 | for i from 0 <= i < len(b): |
|---|
| 1279 | d = mpz_get_d_2exp(&cur_exp, b._entries[i]) |
|---|
| 1280 | # 0.5 <= d < 1; b._entries[i] ~= d*2^cur_exp |
|---|
| 1281 | new_exp = cur_exp + delta |
|---|
| 1282 | if new_exp >= -100: |
|---|
| 1283 | db.v.data[i] = ldexp(d, new_exp) |
|---|
| 1284 | # db[i] = ldexp(d, new_exp) |
|---|
| 1285 | |
|---|
| 1286 | # The true value can be off by an ulp because mpz_get_d_2exp truncates. |
|---|
| 1287 | # (If we created a version of mpz_get_d_2exp that rounded instead, |
|---|
| 1288 | # we could do a little better.) |
|---|
| 1289 | # The third half_ulp in the positive direction is to compensate for |
|---|
| 1290 | # possible bad rounding when adding ldexp(err, delta). |
|---|
| 1291 | |
|---|
| 1292 | cdef double low_err = -2*half_ulp |
|---|
| 1293 | cdef double high_err = 3*half_ulp + ldexp(err, delta) |
|---|
| 1294 | fpu_fix_end(&cwf) |
|---|
| 1295 | return (db, low_err, high_err, -delta) |
|---|
| 1296 | |
|---|
| 1297 | |
|---|
| 1298 | cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): |
|---|
| 1299 | """ |
|---|
| 1300 | This is the subclass of interval_bernstein_polynomial where |
|---|
| 1301 | polynomial coefficients are represented using floating-point numbers. |
|---|
| 1302 | |
|---|
| 1303 | In the floating-point representation, each coefficient is represented |
|---|
| 1304 | as an IEEE double-precision float A, and the (shared) lower and |
|---|
| 1305 | upper interval widths E1 and E2. These represent the coefficents |
|---|
| 1306 | (A+E1)*2^n <= c <= (A+E2)*2^n. |
|---|
| 1307 | |
|---|
| 1308 | Note that we always have E1 <= 0 <= E2. Also, each floating-point |
|---|
| 1309 | coefficient has absolute value less than one. |
|---|
| 1310 | |
|---|
| 1311 | (Note that mk_ibpf is a simple helper function for creating |
|---|
| 1312 | elements of interval_bernstein_polynomial_float in doctests.) |
|---|
| 1313 | |
|---|
| 1314 | EXAMPLES: |
|---|
| 1315 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1316 | sage: bp = mk_ibpf([0.1, 0.2, 0.3], pos_err=0.5); bp |
|---|
| 1317 | degree 2 IBP with floating-point coefficients |
|---|
| 1318 | sage: str(bp) |
|---|
| 1319 | '<IBP: (0.1, 0.2, 0.3) + [0.0 .. 0.5]>' |
|---|
| 1320 | sage: bp.variations() |
|---|
| 1321 | (0, 0) |
|---|
| 1322 | sage: bp = mk_ibpf([-0.3, -0.1, 0.1, -0.1, -0.3, -0.1], lower=1, upper=5/4, usign=1, pos_err=0.2, scale_log2=-3, level=2, slope_err=RIF(pi)); bp |
|---|
| 1323 | degree 5 IBP with floating-point coefficients |
|---|
| 1324 | sage: str(bp) |
|---|
| 1325 | '<IBP: ((-0.3, -0.1, 0.1, -0.1, -0.3, -0.1) + [0.0 .. 0.2]) * 2^-3 over [1 .. 5/4]; usign 1; level 2; slope_err [3.1415926535897931 .. 3.1415926535897936]>' |
|---|
| 1326 | sage: bp.variations() |
|---|
| 1327 | (3, 3) |
|---|
| 1328 | """ |
|---|
| 1329 | |
|---|
| 1330 | def __init__(self, RealDoubleVectorSpaceElement coeffs, Rational lower, Rational upper, int lsign, int usign, double neg_err, double pos_err, int scale_log2, int level, RealIntervalFieldElement slope_err): |
|---|
| 1331 | """ |
|---|
| 1332 | Initialize an interval_bernstein_polynomial_integer. |
|---|
| 1333 | |
|---|
| 1334 | INPUT: |
|---|
| 1335 | coeffs -- a coefficient vector for a polynomial in Bernstein form |
|---|
| 1336 | (all coefficients must have absolute value less than one) |
|---|
| 1337 | lower -- the lower bound of the region over which the Bernstein basis is defined |
|---|
| 1338 | upper -- the upper bound of the region over which the Bernstein basis is defined |
|---|
| 1339 | lsign -- the sign of the polynomial at lower, if known |
|---|
| 1340 | usign -- the sign of the polynomial at upper, if known |
|---|
| 1341 | neg_err -- the minimum error in the Bernstein coefficients |
|---|
| 1342 | pos_err -- the maximum error in the Bernstein coefficients |
|---|
| 1343 | (so a Bernstein coefficient x really represents the range |
|---|
| 1344 | [neg_err+x .. pos_err+x] |
|---|
| 1345 | scale_log2 -- the log2 of the scaling factor for the Bernstein coefficients |
|---|
| 1346 | level -- the number of times we have performed degree reduction to get this polynomial |
|---|
| 1347 | slope_err -- the maximum extra error in the derivative of this polynomial from degree reduction |
|---|
| 1348 | |
|---|
| 1349 | EXAMPLES: |
|---|
| 1350 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1351 | sage: bp = interval_bernstein_polynomial_float(vector(RDF, [0.50, -0.30, -0.10]), -3/7, 4/7, 0, -1, -0.02, 0.17, 3, 2, RIF(10^-30)) |
|---|
| 1352 | sage: bp |
|---|
| 1353 | degree 2 IBP with floating-point coefficients |
|---|
| 1354 | sage: str(bp) |
|---|
| 1355 | '<IBP: ((0.5, -0.3, -0.1) + [-0.02 .. 0.17]) * 2^3 over [-3/7 .. 4/7]; usign -1; level 2; slope_err [9.9999999999999990e-31 .. 1.0000000000000001e-30]>' |
|---|
| 1356 | """ |
|---|
| 1357 | assert(len(coeffs) > 0) |
|---|
| 1358 | self.coeffs = coeffs |
|---|
| 1359 | self.lower = lower |
|---|
| 1360 | self.upper = upper |
|---|
| 1361 | self.lsign = lsign |
|---|
| 1362 | if self.lsign == 0: |
|---|
| 1363 | if coeffs.v.data[0] > -neg_err: |
|---|
| 1364 | self.lsign = 1 |
|---|
| 1365 | if coeffs.v.data[0] < -pos_err: |
|---|
| 1366 | self.lsign = -1 |
|---|
| 1367 | self.usign = usign |
|---|
| 1368 | cdef int n = len(coeffs) |
|---|
| 1369 | if self.usign == 0: |
|---|
| 1370 | if coeffs.v.data[n-1] > -neg_err: |
|---|
| 1371 | self.usign = 1 |
|---|
| 1372 | if coeffs.v.data[n-1] < -pos_err: |
|---|
| 1373 | self.usign = -1 |
|---|
| 1374 | self.neg_err = neg_err |
|---|
| 1375 | self.pos_err = pos_err |
|---|
| 1376 | self.scale_log2 = scale_log2 |
|---|
| 1377 | self.level = level |
|---|
| 1378 | self.slope_err = slope_err |
|---|
| 1379 | self._count_variations() |
|---|
| 1380 | max_abs = max_abs_doublevec(coeffs) |
|---|
| 1381 | cdef int exp |
|---|
| 1382 | frexp(max_abs, &exp) |
|---|
| 1383 | self.bitsize = exp + 53 |
|---|
| 1384 | self.lft = None |
|---|
| 1385 | |
|---|
| 1386 | def __str__(self): |
|---|
| 1387 | """ |
|---|
| 1388 | Reveal all the internals of this interval bernstein polynomial. |
|---|
| 1389 | |
|---|
| 1390 | EXAMPLES: |
|---|
| 1391 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1392 | sage: bp = mk_ibpf([-0.11, 0.22, -0.33], upper=1/9, neg_err=-0.3, pos_err=0.1, lsign=1) |
|---|
| 1393 | sage: str(bp) |
|---|
| 1394 | '<IBP: (-0.11, 0.22, -0.33) + [-0.3 .. 0.1] over [0 .. 1/9]>' |
|---|
| 1395 | """ |
|---|
| 1396 | base = "%s + [%s .. %s]" % (self.coeffs, self.neg_err, self.pos_err) |
|---|
| 1397 | if self.scale_log2 != 0: |
|---|
| 1398 | base = "(%s) * 2^%d" % (base, self.scale_log2) |
|---|
| 1399 | s = "<IBP: %s" % base |
|---|
| 1400 | if self.lower != 0 or self.upper != 1: |
|---|
| 1401 | s += " over [%s .. %s]" % (self.lower, self.upper) |
|---|
| 1402 | if self.coeffs.v.data[0] <= -self.neg_err and self.coeffs.v.data[0] >= -self.pos_err and self.lsign != 0: |
|---|
| 1403 | s += "; lsign %d" % self.lsign |
|---|
| 1404 | cdef int n = len(self.coeffs) |
|---|
| 1405 | if self.coeffs.v.data[n-1] <= -self.neg_err and self.coeffs.v.data[n-1] >= -self.pos_err and self.usign != 0: |
|---|
| 1406 | s += "; usign %d" % self.usign |
|---|
| 1407 | if self.level != 0: |
|---|
| 1408 | s += "; level %d" % self.level |
|---|
| 1409 | if self.slope_err != 0: |
|---|
| 1410 | s += "; slope_err %s" % self.slope_err |
|---|
| 1411 | return s + ">" |
|---|
| 1412 | |
|---|
| 1413 | def __repr__(self): |
|---|
| 1414 | """ |
|---|
| 1415 | Return a short summary of this interval bernstein polynomial. |
|---|
| 1416 | |
|---|
| 1417 | EXAMPLES: |
|---|
| 1418 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1419 | sage: bp = mk_ibpf([-0.11, 0.22, -0.33], upper=1/9, neg_err=-0.1, pos_err=0.2, lsign=1) |
|---|
| 1420 | sage: bp |
|---|
| 1421 | degree 2 IBP with floating-point coefficients |
|---|
| 1422 | sage: repr(bp) |
|---|
| 1423 | 'degree 2 IBP with floating-point coefficients' |
|---|
| 1424 | """ |
|---|
| 1425 | return "degree %d IBP with floating-point coefficients" % (len(self.coeffs) - 1) |
|---|
| 1426 | |
|---|
| 1427 | def _type_code(self): |
|---|
| 1428 | """ |
|---|
| 1429 | Classifies this as either an integer representation ('i') or a |
|---|
| 1430 | floating-point representation ('f'). |
|---|
| 1431 | """ |
|---|
| 1432 | return 'f' |
|---|
| 1433 | |
|---|
| 1434 | cdef void _count_variations(self): |
|---|
| 1435 | """ |
|---|
| 1436 | A private function that counts the number of sign variations in |
|---|
| 1437 | this Bernstein polynomial. Since the coefficients are represented |
|---|
| 1438 | with intervals, not exactly, we cannot necessarily compute the exact |
|---|
| 1439 | number of sign variations; instead, we compute lower and upper |
|---|
| 1440 | bounds on this number. |
|---|
| 1441 | |
|---|
| 1442 | """ |
|---|
| 1443 | |
|---|
| 1444 | cdef double* cd = self.coeffs.v.data |
|---|
| 1445 | |
|---|
| 1446 | cdef int count_maybe_pos |
|---|
| 1447 | cdef int count_maybe_neg |
|---|
| 1448 | cdef int sign |
|---|
| 1449 | cdef int count_definite = 0 |
|---|
| 1450 | |
|---|
| 1451 | cdef int n = len(self.coeffs) |
|---|
| 1452 | |
|---|
| 1453 | cdef int new_count_maybe_pos, new_count_maybe_neg |
|---|
| 1454 | |
|---|
| 1455 | cdef int i |
|---|
| 1456 | |
|---|
| 1457 | cdef double val |
|---|
| 1458 | |
|---|
| 1459 | if self.lsign > 0: |
|---|
| 1460 | count_maybe_pos = 0 |
|---|
| 1461 | count_maybe_neg = -1 |
|---|
| 1462 | sign = 1 |
|---|
| 1463 | elif self.lsign < 0: |
|---|
| 1464 | count_maybe_pos = -1 |
|---|
| 1465 | count_maybe_neg = 0 |
|---|
| 1466 | sign = -1 |
|---|
| 1467 | else: |
|---|
| 1468 | count_maybe_pos = 0 |
|---|
| 1469 | count_maybe_neg = 0 |
|---|
| 1470 | sign = 0 |
|---|
| 1471 | |
|---|
| 1472 | for i from 1 <= i < n: |
|---|
| 1473 | new_count_maybe_pos = count_maybe_pos |
|---|
| 1474 | new_count_maybe_neg = count_maybe_neg |
|---|
| 1475 | val = cd[i] |
|---|
| 1476 | if val > -self.neg_err: |
|---|
| 1477 | if sign < 0: |
|---|
| 1478 | count_definite = count_definite + 1 |
|---|
| 1479 | sign = 1 |
|---|
| 1480 | new_count_maybe_neg = -1 |
|---|
| 1481 | if val < -self.pos_err: |
|---|
| 1482 | if sign > 0: |
|---|
| 1483 | count_definite = count_definite + 1 |
|---|
| 1484 | sign = -1 |
|---|
| 1485 | new_count_maybe_pos = -1 |
|---|
| 1486 | if val > -self.pos_err and count_maybe_neg + 1 > new_count_maybe_pos: |
|---|
| 1487 | new_count_maybe_pos = count_maybe_neg + 1 |
|---|
| 1488 | if val < -self.neg_err and count_maybe_pos + 1 > new_count_maybe_neg: |
|---|
| 1489 | new_count_maybe_neg = count_maybe_pos + 1 |
|---|
| 1490 | |
|---|
| 1491 | count_maybe_pos = new_count_maybe_pos |
|---|
| 1492 | count_maybe_neg = new_count_maybe_neg |
|---|
| 1493 | |
|---|
| 1494 | if self.usign > 0 and sign < 0: |
|---|
| 1495 | count_definite = count_definite + 1 |
|---|
| 1496 | if self.usign < 0 and sign > 0: |
|---|
| 1497 | count_definite = count_definite + 1 |
|---|
| 1498 | self.min_variations = count_definite |
|---|
| 1499 | |
|---|
| 1500 | if self.usign > 0: |
|---|
| 1501 | self.max_variations = count_maybe_pos |
|---|
| 1502 | elif self.usign < 0: |
|---|
| 1503 | self.max_variations = count_maybe_neg |
|---|
| 1504 | else: |
|---|
| 1505 | self.max_variations = max(count_maybe_pos, count_maybe_neg) |
|---|
| 1506 | |
|---|
| 1507 | cdef int degree(self): |
|---|
| 1508 | """ |
|---|
| 1509 | Returns the (formal) degree of this polynomial. |
|---|
| 1510 | """ |
|---|
| 1511 | return len(self.coeffs) - 1 |
|---|
| 1512 | |
|---|
| 1513 | def de_casteljau(self, context ctx, mid, msign=0): |
|---|
| 1514 | """ |
|---|
| 1515 | Uses de Casteljau's algorithm to compute the representation |
|---|
| 1516 | of this polynomial in a Bernstein basis over new regions. |
|---|
| 1517 | |
|---|
| 1518 | INPUT: |
|---|
| 1519 | mid -- where to split the Bernstein basis region; 0 < mid < 1 |
|---|
| 1520 | msign -- default 0 (unknown); the sign of this polynomial at mid |
|---|
| 1521 | OUTPUT: |
|---|
| 1522 | bp1, bp2 -- the new interval Bernstein polynomials |
|---|
| 1523 | ok -- a boolean; True if the sign of the original polynomial at mid is known |
|---|
| 1524 | |
|---|
| 1525 | EXAMPLES: |
|---|
| 1526 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1527 | sage: ctx = mk_context() |
|---|
| 1528 | sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01) |
|---|
| 1529 | sage: bp1, bp2, ok = bp.de_casteljau(ctx, 1/2) |
|---|
| 1530 | sage: str(bp1) |
|---|
| 1531 | '<IBP: (0.5, 0.35, 0.0, -0.2875, -0.369375) + [-0.1 .. 0.01] over [0 .. 1/2]>' |
|---|
| 1532 | sage: str(bp2) |
|---|
| 1533 | '<IBP: (-0.369375, -0.45125, -0.3275, 0.145, 0.99) + [-0.1 .. 0.01] over [1/2 .. 1]>' |
|---|
| 1534 | sage: bp1, bp2, ok = bp.de_casteljau(ctx, 2/3) |
|---|
| 1535 | sage: str(bp1) |
|---|
| 1536 | '<IBP: (0.5, 0.3, -0.255555555556, -0.544444444444, -0.321728395062) + [-0.1 .. 0.01] over [0 .. 2/3]>' |
|---|
| 1537 | sage: str(bp2) |
|---|
| 1538 | '<IBP: (-0.321728395062, -0.21037037037, 0.0288888888889, 0.426666666667, 0.99) + [-0.1 .. 0.01] over [2/3 .. 1]>' |
|---|
| 1539 | sage: bp1, bp2, ok = bp.de_casteljau(ctx, 7/39) |
|---|
| 1540 | sage: str(bp1) |
|---|
| 1541 | '<IBP: (0.5, 0.446153846154, 0.366535174227, 0.273286805239, 0.176569270623) + [-0.1 .. 0.01] over [0 .. 7/39]>' |
|---|
| 1542 | sage: str(bp2) |
|---|
| 1543 | '<IBP: (0.176569270623, -0.265568030479, -0.780203813281, -0.396666666667, 0.99) + [-0.1 .. 0.01] over [7/39 .. 1]>' |
|---|
| 1544 | """ |
|---|
| 1545 | (c1_, c2_, err_inc) = de_casteljau_doublevec(self.coeffs, mid) |
|---|
| 1546 | cdef RealDoubleVectorSpaceElement c1 = c1_ |
|---|
| 1547 | cdef RealDoubleVectorSpaceElement c2 = c2_ |
|---|
| 1548 | |
|---|
| 1549 | cdef int sign = 0 |
|---|
| 1550 | |
|---|
| 1551 | if c2.v.data[0] > -self.neg_err: |
|---|
| 1552 | sign = 1 |
|---|
| 1553 | if c2.v.data[0] < -self.pos_err: |
|---|
| 1554 | sign = -1 |
|---|
| 1555 | |
|---|
| 1556 | if msign == 0: |
|---|
| 1557 | msign = sign |
|---|
| 1558 | elif sign != 0: |
|---|
| 1559 | assert(msign == sign) |
|---|
| 1560 | |
|---|
| 1561 | # As long as new_neg and new_pos have |
|---|
| 1562 | # magnitudes less than 0.5, these computations |
|---|
| 1563 | # are exact. This will be the case for any sensible |
|---|
| 1564 | # usage of this class. |
|---|
| 1565 | cdef double new_neg = self.neg_err - half_ulp * err_inc |
|---|
| 1566 | cdef double new_pos = self.pos_err + half_ulp * err_inc |
|---|
| 1567 | |
|---|
| 1568 | if not (-0.5 <= new_neg <= 0 <= new_pos <= 0.5): |
|---|
| 1569 | # Give up on this computation...it's horribly inaccurate anyway. |
|---|
| 1570 | msign = 0 |
|---|
| 1571 | |
|---|
| 1572 | cdef Rational absolute_mid = self.lower + mid * (self.upper - self.lower) |
|---|
| 1573 | |
|---|
| 1574 | cdef interval_bernstein_polynomial_float bp1, bp2 |
|---|
| 1575 | bp1 = interval_bernstein_polynomial_float(c1, self.lower, absolute_mid, self.lsign, msign, new_neg, new_pos, self.scale_log2, self.level, self.slope_err) |
|---|
| 1576 | bp2 = interval_bernstein_polynomial_float(c2, absolute_mid, self.upper, msign, self.usign, new_neg, new_pos, self.scale_log2, self.level, self.slope_err) |
|---|
| 1577 | |
|---|
| 1578 | if self.lft is not None: |
|---|
| 1579 | (a, b, c, d) = self.lft |
|---|
| 1580 | bp1.lft = (a * mid, b, c * mid, d) |
|---|
| 1581 | bp2.lft = (a * (1-mid), b + a*mid, c * (1-mid), d + c*mid) |
|---|
| 1582 | |
|---|
| 1583 | if msign != 0: |
|---|
| 1584 | self.update_variations(bp1, bp2) |
|---|
| 1585 | |
|---|
| 1586 | return (bp1, bp2, msign != 0) |
|---|
| 1587 | |
|---|
| 1588 | def as_float(self): |
|---|
| 1589 | return self |
|---|
| 1590 | |
|---|
| 1591 | def get_msb_bit(self): |
|---|
| 1592 | """ |
|---|
| 1593 | Returns an approximation of the log2 of the maximum of the |
|---|
| 1594 | absolute values of the coefficients, as an integer. |
|---|
| 1595 | """ |
|---|
| 1596 | return self.scale_log2 - 53 + self.bitsize |
|---|
| 1597 | |
|---|
| 1598 | def slope_range(self): |
|---|
| 1599 | """ |
|---|
| 1600 | Compute a bound on the derivative of this polynomial, over its region. |
|---|
| 1601 | |
|---|
| 1602 | EXAMPLES: |
|---|
| 1603 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1604 | sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01) |
|---|
| 1605 | sage: bp.slope_range() |
|---|
| 1606 | [-4.8400000000000017 .. 7.2000000000000011] |
|---|
| 1607 | """ |
|---|
| 1608 | cdef unsigned int cwf |
|---|
| 1609 | fpu_fix_start(&cwf) |
|---|
| 1610 | |
|---|
| 1611 | width = self.region_width() |
|---|
| 1612 | (min_diff, max_diff) = min_max_diff_doublevec(self.coeffs) |
|---|
| 1613 | err = self.pos_err - self.neg_err |
|---|
| 1614 | # 2 half_ulp's because subtracting two numbers with aboslute values |
|---|
| 1615 | # in (-1 .. 1) can give a number in (-2 .. 2), and the subtraction |
|---|
| 1616 | # can have an error of up to half an ulp in that range, which |
|---|
| 1617 | # is 2 half ulps for (-1 .. 1). |
|---|
| 1618 | rng = RIF(min_diff - err - 2*half_ulp, max_diff + err + 2*half_ulp) |
|---|
| 1619 | rng = rng * (len(self.coeffs) - 1) |
|---|
| 1620 | rng = rng / width |
|---|
| 1621 | if self.scale_log2 >= 0: |
|---|
| 1622 | rng = rng << self.scale_log2 |
|---|
| 1623 | else: |
|---|
| 1624 | rng = rng >> (-self.scale_log2) |
|---|
| 1625 | |
|---|
| 1626 | fpu_fix_end(&cwf) |
|---|
| 1627 | |
|---|
| 1628 | return rng |
|---|
| 1629 | |
|---|
| 1630 | |
|---|
| 1631 | def mk_ibpf(coeffs, lower=0, upper=1, lsign=0, usign=0, neg_err=0, pos_err=0, |
|---|
| 1632 | scale_log2=0, level=0, slope_err=RIF(0)): |
|---|
| 1633 | """ |
|---|
| 1634 | A simple wrapper for creating interval_bernstein_polynomial_float |
|---|
| 1635 | objects with coercions, defaults, etc. |
|---|
| 1636 | |
|---|
| 1637 | For use in doctests. |
|---|
| 1638 | |
|---|
| 1639 | EXAMPLES: |
|---|
| 1640 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1641 | sage: mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], pos_err=0.1, neg_err=-0.01) |
|---|
| 1642 | degree 4 IBP with floating-point coefficients |
|---|
| 1643 | """ |
|---|
| 1644 | return interval_bernstein_polynomial_float(vector(RDF, coeffs), QQ(lower), QQ(upper), lsign, usign, neg_err, pos_err, scale_log2, level, slope_err) |
|---|
| 1645 | |
|---|
| 1646 | cdef Rational QQ_1_2 = ZZ(1)/2 |
|---|
| 1647 | cdef Rational QQ_1_32 = QQ(1)/32 |
|---|
| 1648 | cdef Rational QQ_31_32 = QQ(31)/32 |
|---|
| 1649 | cdef Rational zero_QQ = QQ(0) |
|---|
| 1650 | cdef Rational one_QQ = QQ(1) |
|---|
| 1651 | cdef Integer zero_ZZ = ZZ(0) |
|---|
| 1652 | cdef Integer one_ZZ = ZZ(1) |
|---|
| 1653 | cdef Integer ZZ_2_31 = ZZ(2) ** 31 |
|---|
| 1654 | cdef Integer ZZ_2_32 = ZZ(2) ** 32 |
|---|
| 1655 | cdef RealIntervalFieldElement zero_RIF = RIF(0) |
|---|
| 1656 | |
|---|
| 1657 | def de_casteljau_doublevec(RealDoubleVectorSpaceElement c, Rational x): |
|---|
| 1658 | """ |
|---|
| 1659 | Given a polynomial in Bernstein form with floating-point coefficients |
|---|
| 1660 | over the region [0 .. 1], and a split point x, use de Casteljau's |
|---|
| 1661 | algorithm to give polynomials in Bernstein form over [0 .. x] and |
|---|
| 1662 | [x .. 1]. |
|---|
| 1663 | |
|---|
| 1664 | This function will work for an arbitrary rational split point x, as |
|---|
| 1665 | long as 0 < x < 1; but it has a specialized code path for x==1/2. |
|---|
| 1666 | |
|---|
| 1667 | INPUT: |
|---|
| 1668 | c -- vector of coefficients of polynomial in Bernstein form |
|---|
| 1669 | x -- rational splitting point; 0 < x < 1 |
|---|
| 1670 | |
|---|
| 1671 | OUTPUT: |
|---|
| 1672 | c1 -- coefficients of polynomial over range [0 .. x] |
|---|
| 1673 | c2 -- coefficients of polynomial over range [x .. 1] |
|---|
| 1674 | err_inc -- number of half-ulps by which error intervals widened |
|---|
| 1675 | |
|---|
| 1676 | EXAMPLES: |
|---|
| 1677 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1678 | sage: c = vector(RDF, [0.7, 0, 0, 0, 0, 0]) |
|---|
| 1679 | sage: de_casteljau_doublevec(c, 1/2) |
|---|
| 1680 | ((0.7, 0.35, 0.175, 0.0875, 0.04375, 0.021875), (0.021875, 0.0, 0.0, 0.0, 0.0, 0.0), 5) |
|---|
| 1681 | sage: de_casteljau_doublevec(c, 1/3) |
|---|
| 1682 | ((0.7, 0.466666666667, 0.311111111111, 0.207407407407, 0.138271604938, 0.0921810699588), (0.0921810699588, 0.0, 0.0, 0.0, 0.0, 0.0), 15) |
|---|
| 1683 | sage: de_casteljau_doublevec(c, 7/22) |
|---|
| 1684 | ((0.7, 0.477272727273, 0.32541322314, 0.221872652141, 0.151276808278, 0.103143278371), (0.103143278371, 0.0, 0.0, 0.0, 0.0, 0.0), 15) |
|---|
| 1685 | """ |
|---|
| 1686 | vs = c.parent() |
|---|
| 1687 | |
|---|
| 1688 | cdef RealDoubleVectorSpaceElement c1, c2 |
|---|
| 1689 | |
|---|
| 1690 | c1 = RealDoubleVectorSpaceElement(vs, 0) |
|---|
| 1691 | c2 = c.__copy__() |
|---|
| 1692 | |
|---|
| 1693 | assert(c1.v.stride == 1 and c2.v.stride == 1) |
|---|
| 1694 | |
|---|
| 1695 | cdef unsigned int cwf |
|---|
| 1696 | fpu_fix_start(&cwf) |
|---|
| 1697 | |
|---|
| 1698 | cdef double* c1d = c1.v.data |
|---|
| 1699 | cdef double* c2d = c2.v.data |
|---|
| 1700 | |
|---|
| 1701 | cdef double half = 0.5 |
|---|
| 1702 | |
|---|
| 1703 | cdef int n = len(c) |
|---|
| 1704 | cdef int i, j |
|---|
| 1705 | |
|---|
| 1706 | cdef int cur_den_steps = 0 |
|---|
| 1707 | |
|---|
| 1708 | cdef double rx, rnx |
|---|
| 1709 | |
|---|
| 1710 | cdef int extra_err |
|---|
| 1711 | |
|---|
| 1712 | if x == QQ_1_2: |
|---|
| 1713 | for i from 0 <= i < n: |
|---|
| 1714 | c1d[i] = c2d[0] |
|---|
| 1715 | for j from 0 <= j < n-i-1: |
|---|
| 1716 | c2d[j] = (c2d[j] + c2d[j+1]) * half |
|---|
| 1717 | |
|---|
| 1718 | # The following code lets us avoid O(n^2) floating-point multiplications |
|---|
| 1719 | # in favor of O(n) calls to ldexp(). In one experiment, though, it seems |
|---|
| 1720 | # to actually slow down the code by about 10%. (On an Intel Core 2 Duo |
|---|
| 1721 | # in 32-bit mode, on the test chebyt2(200).) |
|---|
| 1722 | # cur_den_steps = cur_den_steps + 1 |
|---|
| 1723 | # if cur_den_steps == 1020 or i == n-1: |
|---|
| 1724 | # for j from 1 <= j < cur_den_steps: |
|---|
| 1725 | # c1d[i-cur_den_steps+j+1] = ldexp(c1d[i-cur_den_steps+j+1], -j) |
|---|
| 1726 | # c2d[n-i+cur_den_steps-j-2] = ldexp(c2d[n-i+cur_den_steps-j-2], -j) |
|---|
| 1727 | # for j from 0 <= j < n-i-1: |
|---|
| 1728 | # c2d[j] = ldexp(c2d[j], -cur_den_steps) |
|---|
| 1729 | |
|---|
| 1730 | extra_err = n-1 |
|---|
| 1731 | else: |
|---|
| 1732 | rx = x |
|---|
| 1733 | rnx = 1-rx |
|---|
| 1734 | for i from 0 <= i < n: |
|---|
| 1735 | c1d[i] = c2d[0] |
|---|
| 1736 | for j from 0 <= j < n-i-1: |
|---|
| 1737 | c2d[j] = (c2d[j]*rnx + c2d[j+1]*rx) |
|---|
| 1738 | |
|---|
| 1739 | extra_err = 3*(n-1) |
|---|
| 1740 | |
|---|
| 1741 | fpu_fix_end(&cwf) |
|---|
| 1742 | |
|---|
| 1743 | return (c1, c2, extra_err) |
|---|
| 1744 | |
|---|
| 1745 | def max_abs_doublevec(RealDoubleVectorSpaceElement c): |
|---|
| 1746 | """ |
|---|
| 1747 | Given a floating-point vector, return the maximum of the |
|---|
| 1748 | absolute values of its elements. |
|---|
| 1749 | |
|---|
| 1750 | EXAMPLES: |
|---|
| 1751 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1752 | sage: max_abs_doublevec(vector(RDF, [0.1, -0.767, 0.3, 0.693])) |
|---|
| 1753 | 0.76700000000000002 |
|---|
| 1754 | """ |
|---|
| 1755 | assert(c.v.stride == 1) |
|---|
| 1756 | |
|---|
| 1757 | cdef double* cd = c.v.data |
|---|
| 1758 | |
|---|
| 1759 | cdef double m = 0 |
|---|
| 1760 | cdef double a |
|---|
| 1761 | |
|---|
| 1762 | for i from 0 <= i < len(c): |
|---|
| 1763 | a = fabs(cd[i]) |
|---|
| 1764 | if a > m: m = a |
|---|
| 1765 | |
|---|
| 1766 | return m |
|---|
| 1767 | |
|---|
| 1768 | def wordsize_rational(a, b, wordsize): |
|---|
| 1769 | """ |
|---|
| 1770 | Given rationals a and b, selects a de Casteljau split point r between |
|---|
| 1771 | a and b. An attempt is made to select an efficient split point |
|---|
| 1772 | (according to the criteria mentioned in the documentation |
|---|
| 1773 | for de_casteljau_intvec), with a bias towards split points near a. |
|---|
| 1774 | |
|---|
| 1775 | In full detail: |
|---|
| 1776 | |
|---|
| 1777 | Takes as input two rationals, a and b, such that 0<=a<=1, 0<=b<=1, |
|---|
| 1778 | and a!=b. Returns rational r, such that a<=r<=b or b<=r<=a. |
|---|
| 1779 | The denominator of r is a power of 2. Let m be min(r, 1-r), |
|---|
| 1780 | nm be numerator(m), and dml be log2(denominator(m)). The return value |
|---|
| 1781 | r is taken from the first of the following classes to have any |
|---|
| 1782 | members between a and b (except that if a <= 1/8, or 7/8 <= a, then |
|---|
| 1783 | class 2 is preferred to class 1). |
|---|
| 1784 | 1) dml < wordsize |
|---|
| 1785 | 2) bitsize(nm) <= wordsize |
|---|
| 1786 | 3) bitsize(nm) <= 2*wordsize |
|---|
| 1787 | 4) bitsize(nm) <= 3*wordsize |
|---|
| 1788 | ... |
|---|
| 1789 | k) bitsize(nm) <= (k-1)*wordsize |
|---|
| 1790 | From the first class to have members between a and b, r is chosen |
|---|
| 1791 | as the element of the class which is closest to a. |
|---|
| 1792 | |
|---|
| 1793 | EXAMPLES: |
|---|
| 1794 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1795 | sage: wordsize_rational(1/5, 1/7, 32) |
|---|
| 1796 | 429496729/2147483648 |
|---|
| 1797 | sage: wordsize_rational(1/7, 1/5, 32) |
|---|
| 1798 | 306783379/2147483648 |
|---|
| 1799 | sage: wordsize_rational(1/5, 1/7, 64) |
|---|
| 1800 | 1844674407370955161/9223372036854775808 |
|---|
| 1801 | sage: wordsize_rational(1/7, 1/5, 64) |
|---|
| 1802 | 658812288346769701/4611686018427387904 |
|---|
| 1803 | sage: wordsize_rational(1/17, 1/19, 32) |
|---|
| 1804 | 252645135/4294967296 |
|---|
| 1805 | sage: wordsize_rational(1/17, 1/19, 64) |
|---|
| 1806 | 1085102592571150095/18446744073709551616 |
|---|
| 1807 | sage: wordsize_rational(1/1234567890, 1/1234567891, 32) |
|---|
| 1808 | 933866427/1152921504606846976 |
|---|
| 1809 | sage: wordsize_rational(1/1234567890, 1/1234567891, 64) |
|---|
| 1810 | 4010925763784056541/4951760157141521099596496896 |
|---|
| 1811 | """ |
|---|
| 1812 | |
|---|
| 1813 | # assert 0 <= a <= 1 |
|---|
| 1814 | |
|---|
| 1815 | swap_01 = False |
|---|
| 1816 | if b <= a: |
|---|
| 1817 | a = one_QQ-a |
|---|
| 1818 | b = one_QQ-b |
|---|
| 1819 | swap_01 = True |
|---|
| 1820 | sub_1 = False |
|---|
| 1821 | if a > QQ_1_2: |
|---|
| 1822 | a = a-one_QQ |
|---|
| 1823 | b = b-one_QQ |
|---|
| 1824 | sub_1 = True |
|---|
| 1825 | |
|---|
| 1826 | cur_size = wordsize |
|---|
| 1827 | # fld = RealField(cur_size, rnd='RNDU') |
|---|
| 1828 | fld = get_realfield_rndu(cur_size) |
|---|
| 1829 | cdef RealNumber rf |
|---|
| 1830 | while True: |
|---|
| 1831 | rf = fld(a) |
|---|
| 1832 | if cur_size == wordsize: |
|---|
| 1833 | assert(mpfr_number_p(rf.value)) |
|---|
| 1834 | exp = mpfr_get_exp(rf.value) |
|---|
| 1835 | if rf <= -(fld(-b)): |
|---|
| 1836 | if exp <= -3: |
|---|
| 1837 | break |
|---|
| 1838 | # rf2 = RealField(cur_size + exp - 1, rnd='RNDU')(a) |
|---|
| 1839 | fld2 = get_realfield_rndu(cur_size + exp - 1) |
|---|
| 1840 | rf2 = fld2(a) |
|---|
| 1841 | if rf2 <= -(fld2(-b)): |
|---|
| 1842 | rf = rf2 |
|---|
| 1843 | break |
|---|
| 1844 | if rf <= -(fld(-b)): |
|---|
| 1845 | break |
|---|
| 1846 | cur_size = cur_size + wordsize |
|---|
| 1847 | fld = RealField(cur_size, rnd='RNDU') |
|---|
| 1848 | |
|---|
| 1849 | r = rf.exact_rational() |
|---|
| 1850 | if sub_1: r = r + one_QQ |
|---|
| 1851 | if swap_01: r = one_QQ - r |
|---|
| 1852 | # assert 0 <= r <= 1 |
|---|
| 1853 | return r |
|---|
| 1854 | |
|---|
| 1855 | def relative_bounds(a, b): |
|---|
| 1856 | """ |
|---|
| 1857 | INPUT: |
|---|
| 1858 | (al, ah) -- pair of rationals |
|---|
| 1859 | (bl, bh) -- pair of rationals |
|---|
| 1860 | |
|---|
| 1861 | OUTPUT: |
|---|
| 1862 | (cl, ch) -- pair of rationals |
|---|
| 1863 | |
|---|
| 1864 | Computes the linear transformation that maps (al, ah) to (0, 1); |
|---|
| 1865 | then applies this transformation to (bl, bh) and returns the result. |
|---|
| 1866 | |
|---|
| 1867 | EXAMPLES: |
|---|
| 1868 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1869 | sage: relative_bounds((1/7, 1/4), (1/6, 1/5)) |
|---|
| 1870 | (2/9, 8/15) |
|---|
| 1871 | """ |
|---|
| 1872 | (al, ah) = a |
|---|
| 1873 | (bl, bh) = b |
|---|
| 1874 | width = ah - al |
|---|
| 1875 | return ((bl - al) / width, (bh - al) / width) |
|---|
| 1876 | |
|---|
| 1877 | cdef int bitsize(Integer a): |
|---|
| 1878 | """ |
|---|
| 1879 | Compute the number of bits required to write a given integer |
|---|
| 1880 | (the sign is ignored). |
|---|
| 1881 | |
|---|
| 1882 | EXAMPLES: |
|---|
| 1883 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1884 | sage: bitsize_doctest(0) |
|---|
| 1885 | 1 |
|---|
| 1886 | sage: bitsize_doctest(1) |
|---|
| 1887 | 1 |
|---|
| 1888 | sage: bitsize_doctest(2) |
|---|
| 1889 | 2 |
|---|
| 1890 | sage: bitsize_doctest(-2) |
|---|
| 1891 | 2 |
|---|
| 1892 | sage: bitsize_doctest(65535) |
|---|
| 1893 | 16 |
|---|
| 1894 | sage: bitsize_doctest(65536) |
|---|
| 1895 | 17 |
|---|
| 1896 | """ |
|---|
| 1897 | return int(mpz_sizeinbase(a.value, 2)) |
|---|
| 1898 | |
|---|
| 1899 | def bitsize_doctest(n): |
|---|
| 1900 | return bitsize(n) |
|---|
| 1901 | |
|---|
| 1902 | def degree_reduction_next_size(n): |
|---|
| 1903 | """ |
|---|
| 1904 | Given n (a polynomial degree), returns either a smaller integer or None. |
|---|
| 1905 | This defines the sequence of degrees followed by our degree reduction |
|---|
| 1906 | implementation. |
|---|
| 1907 | |
|---|
| 1908 | EXAMPLES: |
|---|
| 1909 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1910 | sage: degree_reduction_next_size(1000) |
|---|
| 1911 | 30 |
|---|
| 1912 | sage: degree_reduction_next_size(20) |
|---|
| 1913 | 15 |
|---|
| 1914 | sage: degree_reduction_next_size(3) |
|---|
| 1915 | 2 |
|---|
| 1916 | sage: degree_reduction_next_size(2) is None |
|---|
| 1917 | True |
|---|
| 1918 | """ |
|---|
| 1919 | |
|---|
| 1920 | # Virtually any descending sequence would be "correct" here; no |
|---|
| 1921 | # testing has been done to see if another sequence would be better. |
|---|
| 1922 | |
|---|
| 1923 | # Constraints: must return None for n <= 2; degree reduction to |
|---|
| 1924 | # degrees > 30 may be very, very slow. (Part of reducing from |
|---|
| 1925 | # degree n to degree k is computing the exact inverse of a k by k |
|---|
| 1926 | # rational matrix. Fortunately, this matrix depends only on |
|---|
| 1927 | # n and k, so the inverted matrix can be cached; but still, |
|---|
| 1928 | # computing the exact inverse of a k by k matrix seems infeasible |
|---|
| 1929 | # for k much larger than 30.) |
|---|
| 1930 | |
|---|
| 1931 | if n <= 2: return None |
|---|
| 1932 | next = n * 3 // 4 |
|---|
| 1933 | if next > 30: next = 30 |
|---|
| 1934 | return next |
|---|
| 1935 | |
|---|
| 1936 | def precompute_degree_reduction_cache(n): |
|---|
| 1937 | """ |
|---|
| 1938 | Compute and cache the matrices used for degree reduction, starting |
|---|
| 1939 | from degree n. |
|---|
| 1940 | |
|---|
| 1941 | EXAMPLES: |
|---|
| 1942 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 1943 | sage: precompute_degree_reduction_cache(5) |
|---|
| 1944 | sage: dr_cache[5] |
|---|
| 1945 | (3, [121/126 8/63 -1/9 -2/63 11/126 -2/63] |
|---|
| 1946 | [ -3/7 37/42 16/21 1/21 -3/7 1/6] |
|---|
| 1947 | [ 1/6 -3/7 1/21 16/21 37/42 -3/7] |
|---|
| 1948 | [ -2/63 11/126 -2/63 -1/9 8/63 121/126], 2, ([121 16 -14 -4 11 -4] |
|---|
| 1949 | [-54 111 96 6 -54 21] |
|---|
| 1950 | [ 21 -54 6 96 111 -54] |
|---|
| 1951 | [ -4 11 -4 -14 16 121], 126)) |
|---|
| 1952 | """ |
|---|
| 1953 | while True: |
|---|
| 1954 | if dr_cache.has_key(n): return |
|---|
| 1955 | next = degree_reduction_next_size(n) |
|---|
| 1956 | if next is None: |
|---|
| 1957 | dr_cache[n] = (None, None, 0) |
|---|
| 1958 | return |
|---|
| 1959 | |
|---|
| 1960 | # We can compute a degree n -> degree k reduction by looking at |
|---|
| 1961 | # as few as k+1 of the coefficients of the degree n polynomial. |
|---|
| 1962 | # Using more samples reduces the error involved in degree |
|---|
| 1963 | # reduction, but is slower. More testing might reveal a better |
|---|
| 1964 | # way to select the number of samples here. |
|---|
| 1965 | |
|---|
| 1966 | samps = min(n+1, next+5) |
|---|
| 1967 | bd = bernstein_down(next, n, samps) |
|---|
| 1968 | |
|---|
| 1969 | # For each coefficient in the reduced polynomial, we see how |
|---|
| 1970 | # it varies as the (sampled) coefficients in the original |
|---|
| 1971 | # polynomial change by +/- 1. Then we take the reduced |
|---|
| 1972 | # coefficient which changes the most, and call that the expected |
|---|
| 1973 | # error. We can multiply this by the error in the original |
|---|
| 1974 | # polynomial, and be fairly certain (absolutely certain?) that |
|---|
| 1975 | # the error in the reduced polynomial will be no better |
|---|
| 1976 | # than this product. |
|---|
| 1977 | expected_err = max([sum([abs(x) for x in bd[k]]) for k in xrange(next+1)]) |
|---|
| 1978 | |
|---|
| 1979 | # bdd = bd.denominator() |
|---|
| 1980 | # bdi = MatrixSpace(ZZ, next+1, samps, sparse=False)(bd * bdd) |
|---|
| 1981 | (bdi, bdd) = bd._clear_denom() |
|---|
| 1982 | |
|---|
| 1983 | dr_cache[n] = (next, bd, expected_err.floor(), (bdi, bdd)) |
|---|
| 1984 | n = next |
|---|
| 1985 | |
|---|
| 1986 | def bernstein_down(d1, d2, s): |
|---|
| 1987 | """ |
|---|
| 1988 | Given polynomial degrees d1 and d2 (where d1 < d2), and a number |
|---|
| 1989 | of samples s, computes a matrix bd. |
|---|
| 1990 | |
|---|
| 1991 | If you have a Bernstein polynomial of formal degree d2, and select |
|---|
| 1992 | s of its coefficients (according to subsample_vec), and multiply |
|---|
| 1993 | the resulting vector by bd, then you get the coefficients |
|---|
| 1994 | of a Bernstein polynomial of formal degree d1, where this second |
|---|
| 1995 | polynomial is a good approximation to the first polynomial over the |
|---|
| 1996 | region of the Bernstein basis. |
|---|
| 1997 | |
|---|
| 1998 | EXAMPLES: |
|---|
| 1999 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2000 | sage: bernstein_down(3, 8, 5) |
|---|
| 2001 | [ 612/245 -348/245 -37/49 338/245 -172/245] |
|---|
| 2002 | [-724/441 132/49 395/441 -290/147 452/441] |
|---|
| 2003 | [ 452/441 -290/147 395/441 132/49 -724/441] |
|---|
| 2004 | [-172/245 338/245 -37/49 -348/245 612/245] |
|---|
| 2005 | """ |
|---|
| 2006 | |
|---|
| 2007 | # The use of the pseudoinverse means that the coefficients of the |
|---|
| 2008 | # reduced polynomial are selected according to a least-squares fit. |
|---|
| 2009 | # We would prefer to minimize the maximum error, rather than the |
|---|
| 2010 | # sum of the squares of the errors; but I don't know how to do that. |
|---|
| 2011 | |
|---|
| 2012 | # Also, this pseudoinverse is very slow to compute if d1 is large. |
|---|
| 2013 | # Since the coefficients of bernstein_up(...) can be represented |
|---|
| 2014 | # with a fairly simple formula (see the implementation of |
|---|
| 2015 | # bernstein_up()), it seems possible that there is some sort of |
|---|
| 2016 | # formula for the coefficients of the pseudoinverse that would be |
|---|
| 2017 | # faster than the computation here. |
|---|
| 2018 | |
|---|
| 2019 | return pseudoinverse(bernstein_up(d1, d2, s)) |
|---|
| 2020 | |
|---|
| 2021 | def pseudoinverse(m): |
|---|
| 2022 | mt = m.transpose() |
|---|
| 2023 | return ~(mt * m) * mt |
|---|
| 2024 | |
|---|
| 2025 | def bernstein_up(d1, d2, s=None): |
|---|
| 2026 | """ |
|---|
| 2027 | Given polynomial degrees d1 and d2, where d1 < d2, compute a matrix bu. |
|---|
| 2028 | |
|---|
| 2029 | If you have a Bernstein polynomial of formal degree d1, and |
|---|
| 2030 | multiply its coefficient vector by bu, then the result is the |
|---|
| 2031 | coefficient vector of the same polynomial represented as a |
|---|
| 2032 | Bernstein polynomial of formal degree d2. |
|---|
| 2033 | |
|---|
| 2034 | If s is not None, then it represents a number of samples; then the |
|---|
| 2035 | product only gives s of the coefficients of the new Bernstein polynomial, |
|---|
| 2036 | selected according to subsample_vec. |
|---|
| 2037 | |
|---|
| 2038 | EXAMPLES: |
|---|
| 2039 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2040 | sage: bernstein_down(3, 7, 4) |
|---|
| 2041 | [ 12/5 -4 3 -2/5] |
|---|
| 2042 | [-13/15 16/3 -4 8/15] |
|---|
| 2043 | [ 8/15 -4 16/3 -13/15] |
|---|
| 2044 | [ -2/5 3 -4 12/5] |
|---|
| 2045 | """ |
|---|
| 2046 | if s is None: s = d1 + 1 |
|---|
| 2047 | MS = MatrixSpace(QQ, s, d1+1, sparse=False) |
|---|
| 2048 | m = MS() |
|---|
| 2049 | scale = factorial(d2)/factorial(d2-d1) |
|---|
| 2050 | for b in range(0, d1+1): |
|---|
| 2051 | scale2 = scale / binomial(d1, b) |
|---|
| 2052 | if (d1 - b) & 1 == 1: |
|---|
| 2053 | scale2 = -scale2 |
|---|
| 2054 | scale2 = ~scale2 |
|---|
| 2055 | for a in range(0, s): |
|---|
| 2056 | ra = ZZ(subsample_vec(a, s, d2 + 1)) |
|---|
| 2057 | m[a, b] = prod([ra-i for i in range(0, b)]) * prod([ra-i for i in range(d2-d1+b+1, d2+1)]) * scale2 |
|---|
| 2058 | |
|---|
| 2059 | return m |
|---|
| 2060 | |
|---|
| 2061 | cdef int subsample_vec(int a, int slen, int llen): |
|---|
| 2062 | """ |
|---|
| 2063 | Given a vector of length llen, and slen < llen, we want to |
|---|
| 2064 | select slen of the elements of the vector, evenly spaced. |
|---|
| 2065 | |
|---|
| 2066 | Given an index 0 <= a < slen, this function computes the index |
|---|
| 2067 | in the original vector of length llen corresponding to a. |
|---|
| 2068 | |
|---|
| 2069 | EXAMPLES: |
|---|
| 2070 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2071 | sage: [subsample_vec_doctest(a, 10, 100) for a in range(10)] |
|---|
| 2072 | [5, 15, 25, 35, 45, 54, 64, 74, 84, 94] |
|---|
| 2073 | sage: [subsample_vec_doctest(a, 3, 4) for a in range(3)] |
|---|
| 2074 | [1, 2, 3] |
|---|
| 2075 | """ |
|---|
| 2076 | |
|---|
| 2077 | # round((a + 0.5) * (llen - 1) / slen) |
|---|
| 2078 | # round((2*a + 1) * (llen - 1) / (2 * slen) |
|---|
| 2079 | # floor(((2*a + 1) * (llen - 1) + slen) / (2 * slen)) |
|---|
| 2080 | return ((2*a + 1) * (llen - 1) + slen) // (2 * slen) |
|---|
| 2081 | |
|---|
| 2082 | def subsample_vec_doctest(a, slen, llen): |
|---|
| 2083 | return subsample_vec(a, slen, llen) |
|---|
| 2084 | |
|---|
| 2085 | def maximum_root_first_lambda(p): |
|---|
| 2086 | """ |
|---|
| 2087 | Given a polynomial with real coefficients, computes an upper bound |
|---|
| 2088 | on its largest real root, using the first-\lambda algorithm from |
|---|
| 2089 | "Implementations of a New Theorem for Computing Bounds for Positive |
|---|
| 2090 | Roots of Polynomials", by Akritas, Strzebo\'nski, and Vigklas. |
|---|
| 2091 | |
|---|
| 2092 | EXAMPLES: |
|---|
| 2093 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2094 | sage: x = polygen(ZZ) |
|---|
| 2095 | sage: maximum_root_first_lambda((x-1)*(x-2)*(x-3)) |
|---|
| 2096 | 6.00000000000001 |
|---|
| 2097 | sage: maximum_root_first_lambda((x+1)*(x+2)*(x+3)) |
|---|
| 2098 | 0 |
|---|
| 2099 | sage: maximum_root_first_lambda(x^2 - 1) |
|---|
| 2100 | 1.00000000000000 |
|---|
| 2101 | """ |
|---|
| 2102 | n = p.degree() |
|---|
| 2103 | if p[n] < 0: p = -p |
|---|
| 2104 | cl = [RIF(x) for x in p.list()] |
|---|
| 2105 | return cl_maximum_root_first_lambda(cl) |
|---|
| 2106 | |
|---|
| 2107 | def cl_maximum_root_first_lambda(cl): |
|---|
| 2108 | """ |
|---|
| 2109 | Given a polynomial represented by a list of its coefficients |
|---|
| 2110 | (as RealIntervalFieldElements), compute an upper bound on its |
|---|
| 2111 | largest real root. |
|---|
| 2112 | |
|---|
| 2113 | Uses the first-\lambda algorithm from "Implementations of a New Theorem |
|---|
| 2114 | for Computing Bounds for Positive Roots of Polynomials", |
|---|
| 2115 | by Akritas, Strzebo\'nski, and Vigklas. |
|---|
| 2116 | |
|---|
| 2117 | EXAMPLES: |
|---|
| 2118 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2119 | sage: cl_maximum_root_first_lambda([RIF(-1), RIF(0), RIF(1)]) |
|---|
| 2120 | 1.00000000000000 |
|---|
| 2121 | """ |
|---|
| 2122 | n = len(cl) - 1 |
|---|
| 2123 | assert(cl[n] > 0) |
|---|
| 2124 | pending_pos_coeff = cl[n] |
|---|
| 2125 | pending_pos_exp = n |
|---|
| 2126 | lastPos = True |
|---|
| 2127 | posCounter = 1 |
|---|
| 2128 | negCounter = 0 |
|---|
| 2129 | pos = [] |
|---|
| 2130 | neg = [] |
|---|
| 2131 | for j in xrange(n-1, -2, -1): |
|---|
| 2132 | if j < 0: |
|---|
| 2133 | coeff = 1 |
|---|
| 2134 | else: |
|---|
| 2135 | coeff = cl[j] |
|---|
| 2136 | if coeff < 0: |
|---|
| 2137 | neg += [(coeff, j)] |
|---|
| 2138 | lastPos = False |
|---|
| 2139 | negCounter = negCounter+1 |
|---|
| 2140 | if coeff > 0: |
|---|
| 2141 | if negCounter > posCounter: |
|---|
| 2142 | chunks = negCounter - posCounter + 1 |
|---|
| 2143 | pos += [(pending_pos_coeff / chunks, pending_pos_exp)] * chunks |
|---|
| 2144 | posCounter = negCounter |
|---|
| 2145 | else: |
|---|
| 2146 | pos += [(pending_pos_coeff, pending_pos_exp)] |
|---|
| 2147 | pending_pos_coeff = coeff |
|---|
| 2148 | pending_pos_exp = j |
|---|
| 2149 | posCounter = posCounter+1 |
|---|
| 2150 | |
|---|
| 2151 | if len(neg) == 0: return 0 |
|---|
| 2152 | |
|---|
| 2153 | max_ub_log = RIF('-infinity') |
|---|
| 2154 | for j in xrange(len(neg)): |
|---|
| 2155 | cur_ub_log = (-neg[j][0] / pos[j][0]).log() / (pos[j][1] - neg[j][1]) |
|---|
| 2156 | max_ub_log = max_ub_log.union(cur_ub_log) |
|---|
| 2157 | |
|---|
| 2158 | return max_ub_log.upper().exp() |
|---|
| 2159 | |
|---|
| 2160 | def maximum_root_local_max(p): |
|---|
| 2161 | """ |
|---|
| 2162 | Given a polynomial with real coefficients, computes an upper bound |
|---|
| 2163 | on its largest real root, using the local-max algorithm from |
|---|
| 2164 | "Implementations of a New Theorem for Computing Bounds for Positive |
|---|
| 2165 | Roots of Polynomials", by Akritas, Strzebo\'nski, and Vigklas. |
|---|
| 2166 | |
|---|
| 2167 | EXAMPLES: |
|---|
| 2168 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2169 | sage: x = polygen(ZZ) |
|---|
| 2170 | sage: maximum_root_local_max((x-1)*(x-2)*(x-3)) |
|---|
| 2171 | 12.0000000000001 |
|---|
| 2172 | sage: maximum_root_local_max((x+1)*(x+2)*(x+3)) |
|---|
| 2173 | 0.000000000000000 |
|---|
| 2174 | sage: maximum_root_local_max(x^2 - 1) |
|---|
| 2175 | 1.41421356237310 |
|---|
| 2176 | """ |
|---|
| 2177 | n = p.degree() |
|---|
| 2178 | if p[n] < 0: p = -p |
|---|
| 2179 | cl = [RIF(x) for x in p.list()] |
|---|
| 2180 | return cl_maximum_root_local_max(cl) |
|---|
| 2181 | |
|---|
| 2182 | def cl_maximum_root_local_max(cl): |
|---|
| 2183 | """ |
|---|
| 2184 | Given a polynomial represented by a list of its coefficients |
|---|
| 2185 | (as RealIntervalFieldElements), compute an upper bound on its |
|---|
| 2186 | largest real root. |
|---|
| 2187 | |
|---|
| 2188 | Uses the local-max algorithm from "Implementations of a New Theorem |
|---|
| 2189 | for Computing Bounds for Positive Roots of Polynomials", |
|---|
| 2190 | by Akritas, Strzebo\'nski, and Vigklas. |
|---|
| 2191 | |
|---|
| 2192 | EXAMPLES: |
|---|
| 2193 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2194 | sage: cl_maximum_root_local_max([RIF(-1), RIF(0), RIF(1)]) |
|---|
| 2195 | 1.41421356237310 |
|---|
| 2196 | """ |
|---|
| 2197 | n = len(cl) - 1 |
|---|
| 2198 | assert(cl[n] > 0) |
|---|
| 2199 | max_pos_coeff = cl[n] |
|---|
| 2200 | max_pos_exp = n |
|---|
| 2201 | max_pos_uses = 0 |
|---|
| 2202 | max_ub_log = RIF('-infinity') |
|---|
| 2203 | |
|---|
| 2204 | for j in xrange(n-1, -1, -1): |
|---|
| 2205 | if cl[j] < 0: |
|---|
| 2206 | max_pos_uses = max_pos_uses+1 |
|---|
| 2207 | cur_ub_log = (-cl[j] / (max_pos_coeff >> max_pos_uses)).log() / (max_pos_exp - j) |
|---|
| 2208 | max_ub_log = max_ub_log.union(cur_ub_log) |
|---|
| 2209 | elif cl[j] > max_pos_coeff: |
|---|
| 2210 | max_pos_coeff = cl[j] |
|---|
| 2211 | max_pos_exp = j |
|---|
| 2212 | max_pos_uses = 0 |
|---|
| 2213 | |
|---|
| 2214 | return max_ub_log.upper().exp() |
|---|
| 2215 | |
|---|
| 2216 | def cl_maximum_root(cl): |
|---|
| 2217 | """ |
|---|
| 2218 | Given a polynomial represented by a list of its coefficients |
|---|
| 2219 | (as RealIntervalFieldElements), compute an upper bound on its |
|---|
| 2220 | largest real root. |
|---|
| 2221 | |
|---|
| 2222 | Uses two algorithms of Akritas, Strzebo\'nski, and Vigklas, and |
|---|
| 2223 | picks the better result. |
|---|
| 2224 | |
|---|
| 2225 | EXAMPLES: |
|---|
| 2226 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2227 | sage: cl_maximum_root([RIF(-1), RIF(0), RIF(1)]) |
|---|
| 2228 | 1.00000000000000 |
|---|
| 2229 | """ |
|---|
| 2230 | n = len(cl) - 1 |
|---|
| 2231 | if cl[n] < 0: |
|---|
| 2232 | cl = [-x for x in cl] |
|---|
| 2233 | return min(cl_maximum_root_first_lambda(cl), |
|---|
| 2234 | cl_maximum_root_local_max(cl)) |
|---|
| 2235 | |
|---|
| 2236 | def root_bounds(p): |
|---|
| 2237 | """ |
|---|
| 2238 | Given a polynomial with real coefficients, computes a lower and |
|---|
| 2239 | upper bound on its real roots. Uses algorithms of |
|---|
| 2240 | Akritas, Strzebo\'nski, and Vigklas. |
|---|
| 2241 | |
|---|
| 2242 | EXAMPLES: |
|---|
| 2243 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2244 | sage: x = polygen(ZZ) |
|---|
| 2245 | sage: root_bounds((x-1)*(x-2)*(x-3)) |
|---|
| 2246 | (0.545454545454545, 6.00000000000001) |
|---|
| 2247 | sage: root_bounds(x^2) |
|---|
| 2248 | (0, 0) |
|---|
| 2249 | sage: root_bounds(x*(x+1)) |
|---|
| 2250 | (-1.00000000000000, 0) |
|---|
| 2251 | sage: root_bounds((x+2)*(x-3)) |
|---|
| 2252 | (-2.44948974278317, 3.46410161513776) |
|---|
| 2253 | sage: root_bounds(x^995 * (x^2 - 9999) - 1) |
|---|
| 2254 | (-99.9949998749937, 141.414284992713) |
|---|
| 2255 | sage: root_bounds(x^995 * (x^2 - 9999) + 1) |
|---|
| 2256 | (-141.414284992712, 99.9949998749938) |
|---|
| 2257 | |
|---|
| 2258 | If we can see that the polynomial has no real roots, return None. |
|---|
| 2259 | sage: root_bounds(x^2 + 1) is None |
|---|
| 2260 | True |
|---|
| 2261 | """ |
|---|
| 2262 | n = p.degree() |
|---|
| 2263 | if p[n] < 0: p = -p |
|---|
| 2264 | cl = [RIF(x) for x in p.list()] |
|---|
| 2265 | |
|---|
| 2266 | cdef int zero_roots = 0 |
|---|
| 2267 | while cl[0] == 0: |
|---|
| 2268 | cl.pop(0) |
|---|
| 2269 | zero_roots = zero_roots + 1 |
|---|
| 2270 | n = n-1 |
|---|
| 2271 | |
|---|
| 2272 | if n == 0: return (0, 0) |
|---|
| 2273 | |
|---|
| 2274 | ub = cl_maximum_root(cl) |
|---|
| 2275 | |
|---|
| 2276 | neg_cl = copy(cl) |
|---|
| 2277 | for j in xrange(n-1, -1, -2): |
|---|
| 2278 | neg_cl[j] = -neg_cl[j] |
|---|
| 2279 | |
|---|
| 2280 | lb = -cl_maximum_root(neg_cl) |
|---|
| 2281 | |
|---|
| 2282 | if ub == 0 and lb == 0: |
|---|
| 2283 | if zero_roots == 0: |
|---|
| 2284 | return None |
|---|
| 2285 | else: |
|---|
| 2286 | return (lb, ub) |
|---|
| 2287 | |
|---|
| 2288 | if ub == 0 and zero_roots == 0: |
|---|
| 2289 | swap_neg_cl = copy(neg_cl) |
|---|
| 2290 | swap_neg_cl.reverse() |
|---|
| 2291 | ub = (-(~RIF(cl_maximum_root(swap_neg_cl)))).upper() |
|---|
| 2292 | |
|---|
| 2293 | if lb == 0 and zero_roots == 0: |
|---|
| 2294 | swap_cl = copy(cl) |
|---|
| 2295 | swap_cl.reverse() |
|---|
| 2296 | lb = (~RIF(cl_maximum_root(swap_cl))).lower() |
|---|
| 2297 | |
|---|
| 2298 | return (lb, ub) |
|---|
| 2299 | |
|---|
| 2300 | def rational_root_bounds(p): |
|---|
| 2301 | """ |
|---|
| 2302 | Given a polynomial p with real coefficients, computes rationals |
|---|
| 2303 | a and b, such that for every real root r of p, a < r < b. |
|---|
| 2304 | We try to find rationals which bound the roots somewhat tightly, |
|---|
| 2305 | yet are simple (have small numerators and denominators). |
|---|
| 2306 | |
|---|
| 2307 | EXAMPLES: |
|---|
| 2308 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2309 | sage: x = polygen(ZZ) |
|---|
| 2310 | sage: rational_root_bounds((x-1)*(x-2)*(x-3)) |
|---|
| 2311 | (0, 7) |
|---|
| 2312 | sage: rational_root_bounds(x^2) |
|---|
| 2313 | (-1/2, 1/2) |
|---|
| 2314 | sage: rational_root_bounds(x*(x+1)) |
|---|
| 2315 | (-3/2, 1/2) |
|---|
| 2316 | sage: rational_root_bounds((x+2)*(x-3)) |
|---|
| 2317 | (-3, 6) |
|---|
| 2318 | sage: rational_root_bounds(x^995 * (x^2 - 9999) - 1) |
|---|
| 2319 | (-100, 1000/7) |
|---|
| 2320 | sage: rational_root_bounds(x^995 * (x^2 - 9999) + 1) |
|---|
| 2321 | (-142, 213/2) |
|---|
| 2322 | |
|---|
| 2323 | If we can see that the polynomial has no real roots, return None. |
|---|
| 2324 | sage: rational_root_bounds(x^2 + 7) is None |
|---|
| 2325 | True |
|---|
| 2326 | """ |
|---|
| 2327 | |
|---|
| 2328 | # There are two stages to the root isolation process. First, |
|---|
| 2329 | # we convert the polynomial to the Bernstein basis given by |
|---|
| 2330 | # the root bounds, exactly; then we isolate the roots from |
|---|
| 2331 | # that Bernstein basis, using interval arithmetic. |
|---|
| 2332 | |
|---|
| 2333 | # We want the root bounds to be as small as possible, because that |
|---|
| 2334 | # speeds up the second phase; but we also want them to be as |
|---|
| 2335 | # simple as possible, because that speeds up the first phase. |
|---|
| 2336 | |
|---|
| 2337 | # As a heuristic, given a polynomial of degree d with floating-point |
|---|
| 2338 | # root bounds lb and ub, we compute simple rational root bounds |
|---|
| 2339 | # rlb and rub such that lb - (ub - lb)/sqrt(d) <= rlb <= lb, |
|---|
| 2340 | # and ub <= rub <= ub + (ub - lb)/sqrt(d). Very little testing |
|---|
| 2341 | # was done to come up with this heuristic, and it can probably |
|---|
| 2342 | # be improved. |
|---|
| 2343 | |
|---|
| 2344 | if p.degree() == 0: |
|---|
| 2345 | return (QQ(-1), QQ(1)) |
|---|
| 2346 | |
|---|
| 2347 | sqrtd = sqrt(RR(p.degree())) |
|---|
| 2348 | bounds = root_bounds(p) |
|---|
| 2349 | if bounds is None: |
|---|
| 2350 | return None |
|---|
| 2351 | (lb, ub) = bounds |
|---|
| 2352 | |
|---|
| 2353 | if lb == ub: |
|---|
| 2354 | # The code below would give overly precise bounds in this case, |
|---|
| 2355 | # giving very non-simple isolating intervals in the result. |
|---|
| 2356 | # We don't need tight root bounds to quickly find the roots |
|---|
| 2357 | # of a linear polynomial, so go for simple root bounds. |
|---|
| 2358 | |
|---|
| 2359 | b = QQ(lb) |
|---|
| 2360 | |
|---|
| 2361 | return (b - QQ_1_2, b + QQ_1_2) |
|---|
| 2362 | |
|---|
| 2363 | # XXX A gross hack. Sometimes, root_bounds() gives a lower or |
|---|
| 2364 | # upper bound which is a root. We want bounds which are |
|---|
| 2365 | # not roots, so we just spread out the bounds a tiny bit. |
|---|
| 2366 | # (It might be more efficient to check the bounds from root_bounds() |
|---|
| 2367 | # and, if they are roots, use that information to factor out a linear |
|---|
| 2368 | # polynomial. However, as far as I can tell, root_bounds() only |
|---|
| 2369 | # gives roots as bounds on toy examples; so this is not too inefficient.) |
|---|
| 2370 | lb = RR(lb).nextbelow() |
|---|
| 2371 | ub = RR(ub).nextabove() |
|---|
| 2372 | |
|---|
| 2373 | # Given the current implementation of to_bernstein, we want rlb |
|---|
| 2374 | # and (rub/rlb - 1) to be simple rationals -- we don't really care |
|---|
| 2375 | # about the simplicity of rub by itself. (Or else we want rlb to |
|---|
| 2376 | # be zero, and rub to be a simple rational.) |
|---|
| 2377 | |
|---|
| 2378 | ilb = RIF(lb - (ub - lb)/sqrtd, lb) |
|---|
| 2379 | rlb = ilb.simplest_rational() |
|---|
| 2380 | |
|---|
| 2381 | if rlb == 0: |
|---|
| 2382 | iub = RIF(ub, ub + (ub - lb)/sqrtd) |
|---|
| 2383 | rub = iub.simplest_rational() |
|---|
| 2384 | return (rlb, rub) |
|---|
| 2385 | |
|---|
| 2386 | # We want to compute an interval for the upper bound, |
|---|
| 2387 | # iub = [ub .. ub + (ub - lb)/sqrtd], |
|---|
| 2388 | # and then compute (iub/ilb - 1).simplest_rational(). |
|---|
| 2389 | # However, we want to compute this |
|---|
| 2390 | # interval with inward instead of outward rounding. Instead, |
|---|
| 2391 | # we compute the lower and upper bounds of the interval separately. |
|---|
| 2392 | |
|---|
| 2393 | iub_l = RIF(ub) |
|---|
| 2394 | iub_h = RIF(ub + (ub - lb)/sqrtd) |
|---|
| 2395 | |
|---|
| 2396 | iub_l2 = iub_l/rlb - 1 |
|---|
| 2397 | iub_h2 = iub_h/rlb - 1 |
|---|
| 2398 | |
|---|
| 2399 | if iub_l2 < iub_h2: |
|---|
| 2400 | rub = (RIF(iub_l2.upper(), iub_h2.lower()).simplest_rational() + 1)*rlb |
|---|
| 2401 | else: |
|---|
| 2402 | rub = (RIF(iub_h2.upper(), iub_l2.lower()).simplest_rational() + 1)*rlb |
|---|
| 2403 | |
|---|
| 2404 | return (rlb, rub) |
|---|
| 2405 | |
|---|
| 2406 | class PrecisionError(ValueError): |
|---|
| 2407 | pass |
|---|
| 2408 | |
|---|
| 2409 | class bernstein_polynomial_factory: |
|---|
| 2410 | """ |
|---|
| 2411 | An abstract base class for bernstein_polynomial factories. That |
|---|
| 2412 | is, elements of subclasses represent Bernstein polynomials |
|---|
| 2413 | (exactly), and are responsible for creating |
|---|
| 2414 | interval_bernstein_polynomial_integer approximations at arbitrary |
|---|
| 2415 | precision. |
|---|
| 2416 | |
|---|
| 2417 | Supports four methods, coeffs_bitsize(), bernstein_polynomial(), |
|---|
| 2418 | lsign(), and usign(). The coeffs_bitsize() method gives an |
|---|
| 2419 | integer approximation to the log2 of the max of the absolute |
|---|
| 2420 | values of the Bernstein coefficients. The |
|---|
| 2421 | bernstein_polynomial(scale_log2) method gives an approximation |
|---|
| 2422 | where the maximum coefficient has approximately coeffs_bitsize() - |
|---|
| 2423 | scale_log2 bits. The lsign() and usign() methods give the (exact) |
|---|
| 2424 | sign of the first and last coefficient, respectively. |
|---|
| 2425 | """ |
|---|
| 2426 | |
|---|
| 2427 | def _sign(self, v): |
|---|
| 2428 | if v > 0: return 1 |
|---|
| 2429 | if v < 0: return -1 |
|---|
| 2430 | return 0 |
|---|
| 2431 | |
|---|
| 2432 | def lsign(self): |
|---|
| 2433 | """ |
|---|
| 2434 | Returns the sign of the first coefficient of this |
|---|
| 2435 | Bernstein polynomial. |
|---|
| 2436 | """ |
|---|
| 2437 | return self._sign(self.coeffs[0]) |
|---|
| 2438 | |
|---|
| 2439 | def usign(self): |
|---|
| 2440 | """ |
|---|
| 2441 | Returns the sign of the last coefficient of this |
|---|
| 2442 | Bernstein polynomial. |
|---|
| 2443 | """ |
|---|
| 2444 | return self._sign(self.coeffs[-1]) |
|---|
| 2445 | |
|---|
| 2446 | class bernstein_polynomial_factory_intlist(bernstein_polynomial_factory): |
|---|
| 2447 | """ |
|---|
| 2448 | This class holds an exact Bernstein polynomial (represented |
|---|
| 2449 | as a list of integer coefficients), and returns arbitrarily-precise |
|---|
| 2450 | interval approximations of this polynomial on demand. |
|---|
| 2451 | """ |
|---|
| 2452 | |
|---|
| 2453 | def __init__(self, coeffs): |
|---|
| 2454 | """ |
|---|
| 2455 | Initializes a bernstein_polynomial_factory_intlist, |
|---|
| 2456 | given a list of integer coefficients. |
|---|
| 2457 | |
|---|
| 2458 | EXAMPLES: |
|---|
| 2459 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2460 | sage: bernstein_polynomial_factory_intlist([1, 2, 3]) |
|---|
| 2461 | degree 2 Bernstein factory with 2-bit integer coefficients |
|---|
| 2462 | """ |
|---|
| 2463 | self.coeffs = coeffs |
|---|
| 2464 | |
|---|
| 2465 | def __repr__(self): |
|---|
| 2466 | """ |
|---|
| 2467 | Return a short summary of this bernstein polynomial factory. |
|---|
| 2468 | |
|---|
| 2469 | EXAMPLES: |
|---|
| 2470 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2471 | sage: bernstein_polynomial_factory_intlist([1, 2, 3, 4000]) |
|---|
| 2472 | degree 3 Bernstein factory with 12-bit integer coefficients |
|---|
| 2473 | """ |
|---|
| 2474 | |
|---|
| 2475 | return "degree %d Bernstein factory with %d-bit integer coefficients" % (len(self.coeffs) - 1, self.coeffs_bitsize()) |
|---|
| 2476 | |
|---|
| 2477 | def coeffs_bitsize(self): |
|---|
| 2478 | """ |
|---|
| 2479 | Computes the approximate log2 of the maximum of the absolute |
|---|
| 2480 | values of the coefficients. |
|---|
| 2481 | |
|---|
| 2482 | EXAMPLES: |
|---|
| 2483 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2484 | sage: bernstein_polynomial_factory_intlist([1, 2, 3, -60000]).coeffs_bitsize() |
|---|
| 2485 | 16 |
|---|
| 2486 | """ |
|---|
| 2487 | b = self.coeffs |
|---|
| 2488 | return max([bitsize(c) for c in b]) |
|---|
| 2489 | # return intlist_size(self.coeffs) |
|---|
| 2490 | |
|---|
| 2491 | def bernstein_polynomial(self, scale_log2): |
|---|
| 2492 | """ |
|---|
| 2493 | Compute an interval_bernstein_polynomial_integer that approximates |
|---|
| 2494 | this polynomial, using the given scale_log2. (Smaller scale_log2 |
|---|
| 2495 | values give more accurate approximations.) |
|---|
| 2496 | |
|---|
| 2497 | EXAMPLES: |
|---|
| 2498 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2499 | sage: bpf = bernstein_polynomial_factory_intlist([10, -20, 30, -40]) |
|---|
| 2500 | sage: bpf.bernstein_polynomial(0) |
|---|
| 2501 | degree 3 IBP with 6-bit coefficients |
|---|
| 2502 | sage: str(bpf.bernstein_polynomial(20)) |
|---|
| 2503 | '<IBP: ((0, -1, 0, -1) + [0 .. 1)) * 2^20; lsign 1>' |
|---|
| 2504 | sage: str(bpf.bernstein_polynomial(0)) |
|---|
| 2505 | '<IBP: (10, -20, 30, -40) + [0 .. 1)>' |
|---|
| 2506 | sage: str(bpf.bernstein_polynomial(-20)) |
|---|
| 2507 | '<IBP: ((10485760, -20971520, 31457280, -41943040) + [0 .. 1)) * 2^-20>' |
|---|
| 2508 | """ |
|---|
| 2509 | b = self.coeffs |
|---|
| 2510 | if scale_log2 < 0: |
|---|
| 2511 | shift = ZZ(-scale_log2) |
|---|
| 2512 | intv_b = [c << shift for c in b] |
|---|
| 2513 | else: |
|---|
| 2514 | shift = ZZ(scale_log2) |
|---|
| 2515 | intv_b = [c >> shift for c in b] |
|---|
| 2516 | |
|---|
| 2517 | return interval_bernstein_polynomial_integer((ZZ ** len(b))(intv_b), zero_QQ, one_QQ, self.lsign(), self.usign(), 1, scale_log2, 0, zero_RIF) |
|---|
| 2518 | # return bp_of_intlist(self.coeffs, scale_log2) |
|---|
| 2519 | |
|---|
| 2520 | class bernstein_polynomial_factory_ratlist(bernstein_polynomial_factory): |
|---|
| 2521 | """ |
|---|
| 2522 | This class holds an exact Bernstein polynomial (represented |
|---|
| 2523 | as a list of rational coefficients), and returns arbitrarily-precise |
|---|
| 2524 | interval approximations of this polynomial on demand. |
|---|
| 2525 | """ |
|---|
| 2526 | |
|---|
| 2527 | def __init__(self, coeffs): |
|---|
| 2528 | """ |
|---|
| 2529 | Initializes a bernstein_polynomial_factory_intlist, |
|---|
| 2530 | given a list of rational coefficients. |
|---|
| 2531 | |
|---|
| 2532 | EXAMPLES: |
|---|
| 2533 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2534 | sage: bernstein_polynomial_factory_ratlist([1, 1/2, 1/3]) |
|---|
| 2535 | degree 2 Bernstein factory with 0-bit rational coefficients |
|---|
| 2536 | """ |
|---|
| 2537 | self.coeffs = coeffs |
|---|
| 2538 | |
|---|
| 2539 | def __repr__(self): |
|---|
| 2540 | """ |
|---|
| 2541 | Return a short summary of this bernstein polynomial factory. |
|---|
| 2542 | |
|---|
| 2543 | EXAMPLES: |
|---|
| 2544 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2545 | sage: bernstein_polynomial_factory_ratlist([1, 2, 3, 4000/17]) |
|---|
| 2546 | degree 3 Bernstein factory with 7-bit rational coefficients |
|---|
| 2547 | """ |
|---|
| 2548 | |
|---|
| 2549 | return "degree %d Bernstein factory with %d-bit rational coefficients" % (len(self.coeffs) - 1, self.coeffs_bitsize()) |
|---|
| 2550 | |
|---|
| 2551 | def coeffs_bitsize(self): |
|---|
| 2552 | """ |
|---|
| 2553 | Computes the approximate log2 of the maximum of the absolute |
|---|
| 2554 | values of the coefficients. |
|---|
| 2555 | |
|---|
| 2556 | EXAMPLES: |
|---|
| 2557 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2558 | sage: bernstein_polynomial_factory_ratlist([1, 2, 3, -60000]).coeffs_bitsize() |
|---|
| 2559 | 15 |
|---|
| 2560 | sage: bernstein_polynomial_factory_ratlist([65535/65536]).coeffs_bitsize() |
|---|
| 2561 | -1 |
|---|
| 2562 | sage: bernstein_polynomial_factory_ratlist([65536/65535]).coeffs_bitsize() |
|---|
| 2563 | 1 |
|---|
| 2564 | """ |
|---|
| 2565 | |
|---|
| 2566 | # This returns an estimate of the log base 2 of the rational in the |
|---|
| 2567 | # list with largest absolute value. The estimate is an integer, |
|---|
| 2568 | # and within +/- 1 of the correct answer. |
|---|
| 2569 | r = max([bitsize(c.numerator()) - bitsize(c.denominator()) for c in self.coeffs]) |
|---|
| 2570 | return r |
|---|
| 2571 | |
|---|
| 2572 | def bernstein_polynomial(self, scale_log2): |
|---|
| 2573 | """ |
|---|
| 2574 | Compute an interval_bernstein_polynomial_integer that approximates |
|---|
| 2575 | this polynomial, using the given scale_log2. (Smaller scale_log2 |
|---|
| 2576 | values give more accurate approximations.) |
|---|
| 2577 | |
|---|
| 2578 | EXAMPLES: |
|---|
| 2579 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2580 | sage: bpf = bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]) |
|---|
| 2581 | sage: bpf.bernstein_polynomial(0) |
|---|
| 2582 | degree 3 IBP with 3-bit coefficients |
|---|
| 2583 | sage: str(bpf.bernstein_polynomial(20)) |
|---|
| 2584 | '<IBP: ((0, -1, 0, -1) + [0 .. 1)) * 2^20; lsign 1>' |
|---|
| 2585 | sage: str(bpf.bernstein_polynomial(0)) |
|---|
| 2586 | '<IBP: (0, -4, 2, -2) + [0 .. 1); lsign 1>' |
|---|
| 2587 | sage: str(bpf.bernstein_polynomial(-20)) |
|---|
| 2588 | '<IBP: ((349525, -3295525, 2850354, -1482835) + [0 .. 1)) * 2^-20>' |
|---|
| 2589 | """ |
|---|
| 2590 | b = self.coeffs |
|---|
| 2591 | |
|---|
| 2592 | if scale_log2 < 0: |
|---|
| 2593 | intv_b = [(numerator(c) << (-scale_log2)) // denominator(c) for c in b] |
|---|
| 2594 | else: |
|---|
| 2595 | intv_b = [(numerator(c) >> scale_log2) // denominator(c) for c in b] |
|---|
| 2596 | |
|---|
| 2597 | return interval_bernstein_polynomial_integer((ZZ ** len(b))(intv_b), zero_QQ, one_QQ, self.lsign(), self.usign(), 1, scale_log2, 0, zero_RIF) |
|---|
| 2598 | # return bp_of_ratlist(self.coeffs, scale_log2) |
|---|
| 2599 | |
|---|
| 2600 | class bernstein_polynomial_factory_ar(bernstein_polynomial_factory): |
|---|
| 2601 | """ |
|---|
| 2602 | This class holds an exact Bernstein polynomial (represented as a |
|---|
| 2603 | list of algebraic real coefficients), and returns |
|---|
| 2604 | arbitrarily-precise interval approximations of this polynomial on |
|---|
| 2605 | demand. |
|---|
| 2606 | """ |
|---|
| 2607 | |
|---|
| 2608 | def __init__(self, poly, neg): |
|---|
| 2609 | """ |
|---|
| 2610 | Initializes a bernstein_polynomial_factory_ar, |
|---|
| 2611 | given a polynomial with algebraic real coefficients. |
|---|
| 2612 | If neg is True, then gives the Bernstein polynomial for |
|---|
| 2613 | the negative half-line; if neg is False, the positive. |
|---|
| 2614 | |
|---|
| 2615 | EXAMPLES: |
|---|
| 2616 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2617 | sage: x = polygen(AA) |
|---|
| 2618 | sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2) |
|---|
| 2619 | sage: bernstein_polynomial_factory_ar(p, False) |
|---|
| 2620 | degree 3 Bernstein factory with algebraic real coefficients |
|---|
| 2621 | """ |
|---|
| 2622 | coeffs = to_bernstein_warp(poly) |
|---|
| 2623 | if neg: |
|---|
| 2624 | for i in range(1, len(coeffs), 2): |
|---|
| 2625 | coeffs[i] = -coeffs[i] |
|---|
| 2626 | sizes = [] |
|---|
| 2627 | for c in coeffs: |
|---|
| 2628 | size = RIF(c).magnitude() |
|---|
| 2629 | if size > 0: |
|---|
| 2630 | sizes.append(size.log2().floor()) |
|---|
| 2631 | else: |
|---|
| 2632 | sizes.append(-1000000) |
|---|
| 2633 | |
|---|
| 2634 | self.coeffs = coeffs |
|---|
| 2635 | self.sizes = sizes |
|---|
| 2636 | |
|---|
| 2637 | def __repr__(self): |
|---|
| 2638 | """ |
|---|
| 2639 | Return a short summary of this Bernstein polynomial factory. |
|---|
| 2640 | |
|---|
| 2641 | EXAMPLES: |
|---|
| 2642 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2643 | sage: x = polygen(AA) |
|---|
| 2644 | sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2) |
|---|
| 2645 | sage: bernstein_polynomial_factory_ar(p, False) |
|---|
| 2646 | degree 3 Bernstein factory with algebraic real coefficients |
|---|
| 2647 | """ |
|---|
| 2648 | |
|---|
| 2649 | return "degree %d Bernstein factory with algebraic real coefficients" % (len(self.coeffs) - 1) |
|---|
| 2650 | |
|---|
| 2651 | def coeffs_bitsize(self): |
|---|
| 2652 | """ |
|---|
| 2653 | Computes the approximate log2 of the maximum of the absolute |
|---|
| 2654 | values of the coefficients. |
|---|
| 2655 | |
|---|
| 2656 | EXAMPLES: |
|---|
| 2657 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2658 | sage: x = polygen(AA) |
|---|
| 2659 | sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2) |
|---|
| 2660 | sage: bernstein_polynomial_factory_ar(p, False).coeffs_bitsize() |
|---|
| 2661 | 1 |
|---|
| 2662 | """ |
|---|
| 2663 | return max(self.sizes) |
|---|
| 2664 | |
|---|
| 2665 | def bernstein_polynomial(self, scale_log2): |
|---|
| 2666 | """ |
|---|
| 2667 | Compute an interval_bernstein_polynomial_integer that approximates |
|---|
| 2668 | this polynomial, using the given scale_log2. (Smaller scale_log2 |
|---|
| 2669 | values give more accurate approximations.) |
|---|
| 2670 | |
|---|
| 2671 | EXAMPLES: |
|---|
| 2672 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2673 | sage: x = polygen(AA) |
|---|
| 2674 | sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2) |
|---|
| 2675 | sage: bpf = bernstein_polynomial_factory_ar(p, False) |
|---|
| 2676 | sage: bpf.bernstein_polynomial(0) |
|---|
| 2677 | degree 3 IBP with 2-bit coefficients |
|---|
| 2678 | sage: str(bpf.bernstein_polynomial(-20)) |
|---|
| 2679 | '<IBP: ((-2965821, 2181961, -1542880, 1048576) + [0 .. 1)) * 2^-20>' |
|---|
| 2680 | sage: bpf = bernstein_polynomial_factory_ar(p, True) |
|---|
| 2681 | sage: str(bpf.bernstein_polynomial(-20)) |
|---|
| 2682 | '<IBP: ((-2965821, -2181962, -1542880, -1048576) + [0 .. 1)) * 2^-20>' |
|---|
| 2683 | """ |
|---|
| 2684 | res = (ZZ ** len(self.coeffs))(0) |
|---|
| 2685 | max_err = 0 |
|---|
| 2686 | |
|---|
| 2687 | for i in range(len(self.coeffs)): |
|---|
| 2688 | intv_c = RealIntervalField(max(self.sizes[i] - scale_log2 + 4, 4))(self.coeffs[i]) |
|---|
| 2689 | if scale_log2 < 0: |
|---|
| 2690 | intv_c = intv_c << (-scale_log2) |
|---|
| 2691 | else: |
|---|
| 2692 | intv_c = intv_c >> scale_log2 |
|---|
| 2693 | |
|---|
| 2694 | lower = intv_c.lower().floor() |
|---|
| 2695 | upper = intv_c.upper().ceil() |
|---|
| 2696 | |
|---|
| 2697 | res[i] = lower |
|---|
| 2698 | max_err = max(max_err, upper - lower) |
|---|
| 2699 | |
|---|
| 2700 | return interval_bernstein_polynomial_integer(res, zero_QQ, one_QQ, self.lsign(), self.usign(), max_err, scale_log2, 0, zero_RIF) |
|---|
| 2701 | |
|---|
| 2702 | |
|---|
| 2703 | def split_for_targets(context ctx, interval_bernstein_polynomial bp, target_list, precise=False): |
|---|
| 2704 | """ |
|---|
| 2705 | Given an interval Bernstein polynomial over a particular region |
|---|
| 2706 | (assumed to be a (not necessarily proper) subregion of [0 .. 1]), |
|---|
| 2707 | and a list of targets, uses de Casteljau's method to compute |
|---|
| 2708 | representations of the Bernstein polynomial over each target. |
|---|
| 2709 | Uses degree reduction as often as possible while maintaining the |
|---|
| 2710 | requested precision. |
|---|
| 2711 | |
|---|
| 2712 | Each target is of the form (lgap, ugap, b). Suppose lgap.region() |
|---|
| 2713 | is (l1, l2), and ugap.region() is (u1, u2). Then we will compute |
|---|
| 2714 | an interval Bernstein polynomial over a region [l .. u], where |
|---|
| 2715 | l1 <= l <= l2 and u1 <= u <= u2. (split_for_targets() is free to |
|---|
| 2716 | select arbitrary region endpoints within these bounds; it picks |
|---|
| 2717 | endpoints which make the computation easier.) The third component |
|---|
| 2718 | of the target, b, is the maximum allowed scale_log2 of the result; |
|---|
| 2719 | this is used to decide when degree reduction is allowed. |
|---|
| 2720 | |
|---|
| 2721 | The pair (l1, l2) can be replaced by None, meaning [-infinity .. 0]; |
|---|
| 2722 | or, (u1, u2) can be replaced by None, meaning [1 .. infinity]. |
|---|
| 2723 | |
|---|
| 2724 | There is another constraint on the region endpoints selected by |
|---|
| 2725 | split_for_targets() for a target ((l1, l2), (u1, u2), b). |
|---|
| 2726 | We set a size goal g, such that (u - l) <= g * (u1 - l2). |
|---|
| 2727 | Normally g is 256/255, but if precise is True, then g is 65536/65535. |
|---|
| 2728 | |
|---|
| 2729 | EXAMPLES: |
|---|
| 2730 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2731 | sage: bp = mk_ibpi([1000000, -2000000, 3000000, -4000000, -5000000, -6000000]) |
|---|
| 2732 | sage: ctx = mk_context() |
|---|
| 2733 | sage: bps = split_for_targets(ctx, bp, [(rr_gap(1/1234567893, 1/1234567892, 1), rr_gap(1/1234567891, 1/1234567890, 1), 12), (rr_gap(1/3, 1/2, -1), rr_gap(2/3, 3/4, -1), 6)]) |
|---|
| 2734 | sage: str(bps[0]) |
|---|
| 2735 | '<IBP: (999992, 999992, 999992) + [0 .. 15) over [8613397477114467984778830327/10633823966279326983230456482242756608 .. 591908168025934394813836527495938294787/730750818665451459101842416358141509827966271488]; level 2; slope_err [-192592590990.49338 .. 192592590990.49338]>' |
|---|
| 2736 | sage: str(bps[1]) |
|---|
| 2737 | '<IBP: (-1562500, -1875001, -2222223, -2592593, -2969137, -3337450) + [0 .. 4) over [1/2 .. 2863311531/4294967296]>' |
|---|
| 2738 | """ |
|---|
| 2739 | ntargs = len(target_list) |
|---|
| 2740 | if ntargs == 0: |
|---|
| 2741 | return [] |
|---|
| 2742 | |
|---|
| 2743 | bounds = bp.region() |
|---|
| 2744 | |
|---|
| 2745 | out_of_bounds = False |
|---|
| 2746 | |
|---|
| 2747 | cdef rr_gap l |
|---|
| 2748 | cdef rr_gap r |
|---|
| 2749 | |
|---|
| 2750 | split_targets = [] |
|---|
| 2751 | for (l,r,_) in target_list: |
|---|
| 2752 | if l is None: |
|---|
| 2753 | split_targets += [(QQ(0), None, 0)] |
|---|
| 2754 | else: |
|---|
| 2755 | lbounds = relative_bounds(bounds, l.region()) |
|---|
| 2756 | split_targets += [(lbounds[1], lbounds[0], l.sign)] |
|---|
| 2757 | if lbounds[0] > 0: |
|---|
| 2758 | out_of_bounds = True |
|---|
| 2759 | if r is None: |
|---|
| 2760 | split_targets += [(QQ(1), None, 0)] |
|---|
| 2761 | else: |
|---|
| 2762 | rbounds = relative_bounds(bounds, r.region()) |
|---|
| 2763 | split_targets += [(rbounds[0], rbounds[1], r.sign)] |
|---|
| 2764 | if rbounds[1] < 1: |
|---|
| 2765 | out_of_bounds = True |
|---|
| 2766 | |
|---|
| 2767 | if precise: |
|---|
| 2768 | goal = Integer(65535)/65536 |
|---|
| 2769 | else: |
|---|
| 2770 | goal = Integer(255)/256 |
|---|
| 2771 | |
|---|
| 2772 | if ntargs == 1 and not(out_of_bounds) and split_targets[1][0] - split_targets[0][0] >= goal: |
|---|
| 2773 | return [bp] |
|---|
| 2774 | |
|---|
| 2775 | half = Integer(1)/2 |
|---|
| 2776 | best_target = split_targets[0][0] |
|---|
| 2777 | best_index = 0 |
|---|
| 2778 | for i in range(1, len(split_targets)): |
|---|
| 2779 | if abs(split_targets[i][0] - half) < abs(best_target - half): |
|---|
| 2780 | best_target = split_targets[i][0] |
|---|
| 2781 | best_index = i |
|---|
| 2782 | |
|---|
| 2783 | split = wordsize_rational(split_targets[best_index][0], split_targets[best_index][1], ctx.wordsize) |
|---|
| 2784 | |
|---|
| 2785 | (p1_, p2_, ok) = bp.de_casteljau(ctx, split, msign=split_targets[best_index][2]) |
|---|
| 2786 | assert(ok) |
|---|
| 2787 | |
|---|
| 2788 | cdef interval_bernstein_polynomial p1 = p1_ |
|---|
| 2789 | cdef interval_bernstein_polynomial p2 = p2_ |
|---|
| 2790 | |
|---|
| 2791 | if bp.lft is not None: |
|---|
| 2792 | (a, b, c, d) = bp.lft |
|---|
| 2793 | left = b/d |
|---|
| 2794 | if c+d != 0: |
|---|
| 2795 | right = (a+b)/(c+d) |
|---|
| 2796 | width = right-left |
|---|
| 2797 | err = (a/2 + b)/(c/2 + d) - (left+right)/2 |
|---|
| 2798 | else: |
|---|
| 2799 | width = RR(infinity) |
|---|
| 2800 | err = RR(infinity) |
|---|
| 2801 | slope = (a*d - b*c)/(d*d) |
|---|
| 2802 | ctx.dc_log_append(('lft', a, b, c, d, RR(left), RR(width), RR(slope/width), RR(err/width/width))) |
|---|
| 2803 | ctx.dc_log_append(('split_for_targets', best_index, split, bp.scale_log2, bp.bitsize, p1.bitsize, p2.bitsize)) |
|---|
| 2804 | |
|---|
| 2805 | target_list_splitpoint = (best_index + 1) // 2 |
|---|
| 2806 | tl1 = target_list[:target_list_splitpoint] |
|---|
| 2807 | tl2 = target_list[target_list_splitpoint:] |
|---|
| 2808 | |
|---|
| 2809 | tiny = ~Integer(32) |
|---|
| 2810 | |
|---|
| 2811 | if len(tl1) > 0: |
|---|
| 2812 | if True: # p1.region_width() / bp.region_width() < tiny: |
|---|
| 2813 | max_lsb = max([t[2] for t in tl1]) |
|---|
| 2814 | p1 = p1.down_degree_iter(ctx, max_lsb) |
|---|
| 2815 | r1 = split_for_targets(ctx, p1, tl1) |
|---|
| 2816 | else: |
|---|
| 2817 | r1 = [] |
|---|
| 2818 | if len(tl2) > 0: |
|---|
| 2819 | if True: # p2.region_width() / bp.region_width() < tiny: |
|---|
| 2820 | max_lsb = max([t[2] for t in tl2]) |
|---|
| 2821 | p2 = p2.down_degree_iter(ctx, max_lsb) |
|---|
| 2822 | r2 = split_for_targets(ctx, p2, tl2) |
|---|
| 2823 | else: |
|---|
| 2824 | r2 = [] |
|---|
| 2825 | |
|---|
| 2826 | return r1 + r2 |
|---|
| 2827 | |
|---|
| 2828 | cdef class ocean: |
|---|
| 2829 | """ |
|---|
| 2830 | Given the tools we've defined so far, there are many possible root |
|---|
| 2831 | isolation algorithms that differ on where to select split points, |
|---|
| 2832 | what precision to work at when, and when to attempt degree |
|---|
| 2833 | reduction. |
|---|
| 2834 | |
|---|
| 2835 | Here we implement one particular algorithm, which I call the |
|---|
| 2836 | ocean-island algorithm. We start with an interval Bernstein |
|---|
| 2837 | polynomial defined over the region [0 .. 1]. This region is |
|---|
| 2838 | the "ocean". Using de Casteljau's algorithm and Descartes' |
|---|
| 2839 | rule of signs, we divide this region into subregions which may |
|---|
| 2840 | contain roots, and subregions which are guaranteed not to contain |
|---|
| 2841 | roots. Subregions which may contain roots are "islands"; subregions |
|---|
| 2842 | known not to contain roots are "gaps". |
|---|
| 2843 | |
|---|
| 2844 | All the real root isolation work happens in class island. See the |
|---|
| 2845 | documentation of that class for more information. |
|---|
| 2846 | |
|---|
| 2847 | An island can be told to refine itself until it contains only a |
|---|
| 2848 | single root. This may not succeed, if the island's interval |
|---|
| 2849 | Bernstein polynomial does not have enough precision. The ocean |
|---|
| 2850 | basically loops, refining each of its islands, then increasing the |
|---|
| 2851 | precision of islands which did not succeed in isolating a single |
|---|
| 2852 | root; until all islands are done. |
|---|
| 2853 | |
|---|
| 2854 | Increasing the precision of unsuccessful islands is done in a |
|---|
| 2855 | single pass using split_for_target(); this means it is possible |
|---|
| 2856 | to share work among multiple islands. |
|---|
| 2857 | """ |
|---|
| 2858 | |
|---|
| 2859 | def __init__(self, ctx, bpf, mapping): |
|---|
| 2860 | """ |
|---|
| 2861 | Initialize an ocean from a context and a Bernstein polynomial |
|---|
| 2862 | factory. |
|---|
| 2863 | |
|---|
| 2864 | EXAMPLES: |
|---|
| 2865 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2866 | sage: ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 2867 | ocean with precision 120 and 1 island(s) |
|---|
| 2868 | """ |
|---|
| 2869 | |
|---|
| 2870 | # Islands and gaps are maintained in a doubly-linked (circular) |
|---|
| 2871 | # list. Islands point to the gaps on either side, and gaps |
|---|
| 2872 | # point to the islands on either side. |
|---|
| 2873 | |
|---|
| 2874 | # The list starts with self.lgap, which is the gap that starts |
|---|
| 2875 | # at 0; it ends at self.endpoint, which is a fictional island |
|---|
| 2876 | # after the gap that ends at 1. |
|---|
| 2877 | |
|---|
| 2878 | # The initial gaps are unique in being 0-width; all gaps that |
|---|
| 2879 | # are created during execution of the algorithm have positive |
|---|
| 2880 | # width. |
|---|
| 2881 | |
|---|
| 2882 | # Note that the constructor for islands side-effects its argument |
|---|
| 2883 | # gaps, so that they point to the island as their neighbor. |
|---|
| 2884 | |
|---|
| 2885 | self.ctx = ctx |
|---|
| 2886 | self.bpf = bpf |
|---|
| 2887 | self.mapping = mapping |
|---|
| 2888 | self.lgap = rr_gap(zero_QQ, zero_QQ, bpf.lsign()) |
|---|
| 2889 | rgap = rr_gap(one_QQ, one_QQ, bpf.usign()) |
|---|
| 2890 | self.endpoint = island(None, rgap, self.lgap) |
|---|
| 2891 | self.msb = bpf.coeffs_bitsize() |
|---|
| 2892 | self.prec = 120 |
|---|
| 2893 | |
|---|
| 2894 | cdef island isle = island(self.approx_bp(self.msb - self.prec), self.lgap, rgap) |
|---|
| 2895 | if isle.bp.max_variations == 0: |
|---|
| 2896 | self.lgap.risland = self.endpoint |
|---|
| 2897 | self.endpoint.lgap = self.lgap |
|---|
| 2898 | |
|---|
| 2899 | def __repr__(self): |
|---|
| 2900 | """ |
|---|
| 2901 | Return a short summary of this root isolator. |
|---|
| 2902 | |
|---|
| 2903 | EXAMPLES: |
|---|
| 2904 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2905 | sage: ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 2906 | ocean with precision 120 and 1 island(s) |
|---|
| 2907 | """ |
|---|
| 2908 | |
|---|
| 2909 | cdef int isle_count = 0 |
|---|
| 2910 | cdef island isle = self.lgap.risland |
|---|
| 2911 | while isle is not self.endpoint: |
|---|
| 2912 | isle_count = isle_count + 1 |
|---|
| 2913 | isle = isle.rgap.risland |
|---|
| 2914 | |
|---|
| 2915 | return "ocean with precision %d and %d island(s)" % (self.prec, isle_count) |
|---|
| 2916 | |
|---|
| 2917 | def _islands(self): |
|---|
| 2918 | """ |
|---|
| 2919 | Return a list of the islands in this ocean (for debugging purposes). |
|---|
| 2920 | |
|---|
| 2921 | EXAMPLES: |
|---|
| 2922 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2923 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 2924 | sage: oc._islands() |
|---|
| 2925 | [island of width 1.00000000000000] |
|---|
| 2926 | """ |
|---|
| 2927 | |
|---|
| 2928 | islands = [] |
|---|
| 2929 | cdef island isle = self.lgap.risland |
|---|
| 2930 | while isle is not self.endpoint: |
|---|
| 2931 | islands.append(isle) |
|---|
| 2932 | isle = isle.rgap.risland |
|---|
| 2933 | |
|---|
| 2934 | return islands |
|---|
| 2935 | |
|---|
| 2936 | def approx_bp(self, scale_log2): |
|---|
| 2937 | """ |
|---|
| 2938 | Returns an approximation to our Bernstein polynomial with the |
|---|
| 2939 | given scale_log2. |
|---|
| 2940 | |
|---|
| 2941 | EXAMPLES: |
|---|
| 2942 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2943 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 2944 | sage: str(oc.approx_bp(0)) |
|---|
| 2945 | '<IBP: (0, -4, 2, -2) + [0 .. 1); lsign 1>' |
|---|
| 2946 | sage: str(oc.approx_bp(-20)) |
|---|
| 2947 | '<IBP: ((349525, -3295525, 2850354, -1482835) + [0 .. 1)) * 2^-20>' |
|---|
| 2948 | """ |
|---|
| 2949 | return self.bpf.bernstein_polynomial(scale_log2) |
|---|
| 2950 | |
|---|
| 2951 | def find_roots(self): |
|---|
| 2952 | """ |
|---|
| 2953 | Isolate all roots in this ocean. |
|---|
| 2954 | |
|---|
| 2955 | EXAMPLES: |
|---|
| 2956 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2957 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 2958 | sage: oc |
|---|
| 2959 | ocean with precision 120 and 1 island(s) |
|---|
| 2960 | sage: oc.find_roots() |
|---|
| 2961 | sage: oc |
|---|
| 2962 | ocean with precision 120 and 3 island(s) |
|---|
| 2963 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1, 0, -1111/2, 0, 11108889/14, 0, 0, 0, 0, -1]), lmap) |
|---|
| 2964 | sage: oc.find_roots() |
|---|
| 2965 | sage: oc |
|---|
| 2966 | ocean with precision 240 and 3 island(s) |
|---|
| 2967 | """ |
|---|
| 2968 | while not self.all_done(): |
|---|
| 2969 | self.refine_all() |
|---|
| 2970 | self.increase_precision() |
|---|
| 2971 | |
|---|
| 2972 | def roots(self): |
|---|
| 2973 | """ |
|---|
| 2974 | Return the locations of all islands in this ocean. (If run |
|---|
| 2975 | after find_roots(), this is the location of all roots in the ocean.) |
|---|
| 2976 | |
|---|
| 2977 | EXAMPLES: |
|---|
| 2978 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 2979 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 2980 | sage: oc.find_roots() |
|---|
| 2981 | sage: oc.roots() |
|---|
| 2982 | [(1/32, 1/16), (1/2, 5/8), (3/4, 7/8)] |
|---|
| 2983 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1, 0, -1111/2, 0, 11108889/14, 0, 0, 0, 0, -1]), lmap) |
|---|
| 2984 | sage: oc.find_roots() |
|---|
| 2985 | sage: oc.roots() |
|---|
| 2986 | [(95761241267509487747625/9671406556917033397649408, 191522482605387719863145/19342813113834066795298816), (1496269395904347376805/151115727451828646838272, 374067366568272936175/37778931862957161709568), (31/32, 63/64)] |
|---|
| 2987 | """ |
|---|
| 2988 | rts = [] |
|---|
| 2989 | cdef island isle = self.lgap.risland |
|---|
| 2990 | while isle is not self.endpoint: |
|---|
| 2991 | rts.append((isle.lgap.upper, isle.rgap.lower)) |
|---|
| 2992 | isle = isle.rgap.risland |
|---|
| 2993 | return rts |
|---|
| 2994 | |
|---|
| 2995 | def refine_all(self): |
|---|
| 2996 | """ |
|---|
| 2997 | Refine all islands which are not done (which are not known to |
|---|
| 2998 | contain exactly one root). |
|---|
| 2999 | |
|---|
| 3000 | EXAMPLES: |
|---|
| 3001 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 3002 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 3003 | sage: oc |
|---|
| 3004 | ocean with precision 120 and 1 island(s) |
|---|
| 3005 | sage: oc.refine_all() |
|---|
| 3006 | sage: oc |
|---|
| 3007 | ocean with precision 120 and 3 island(s) |
|---|
| 3008 | """ |
|---|
| 3009 | cdef island isle = self.lgap.risland |
|---|
| 3010 | while isle is not self.endpoint: |
|---|
| 3011 | if not isle.done(self.ctx): |
|---|
| 3012 | isle.refine(self.ctx) |
|---|
| 3013 | isle = isle.rgap.risland |
|---|
| 3014 | |
|---|
| 3015 | def all_done(self): |
|---|
| 3016 | """ |
|---|
| 3017 | Returns true iff all islands are known to contain exactly one root. |
|---|
| 3018 | |
|---|
| 3019 | EXAMPLES: |
|---|
| 3020 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 3021 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 3022 | sage: oc.all_done() |
|---|
| 3023 | False |
|---|
| 3024 | sage: oc.find_roots() |
|---|
| 3025 | sage: oc.all_done() |
|---|
| 3026 | True |
|---|
| 3027 | """ |
|---|
| 3028 | cdef island isle = self.lgap.risland |
|---|
| 3029 | while isle is not self.endpoint: |
|---|
| 3030 | if not isle.done(self.ctx): |
|---|
| 3031 | return False |
|---|
| 3032 | if not isle.has_root(): |
|---|
| 3033 | isle.lgap.risland = isle.rgap.risland |
|---|
| 3034 | isle.rgap.risland.lgap = isle.lgap |
|---|
| 3035 | isle.lgap.upper = isle.rgap.upper |
|---|
| 3036 | isle = isle.rgap.risland |
|---|
| 3037 | return True |
|---|
| 3038 | |
|---|
| 3039 | def reset_root_width(self, int isle_num, target_width): |
|---|
| 3040 | """ |
|---|
| 3041 | Require that the isle_num island have a width at most target_width. |
|---|
| 3042 | |
|---|
| 3043 | If this is followed by a call to find_roots(), then the |
|---|
| 3044 | corresponding root will be refined to the specified width. |
|---|
| 3045 | |
|---|
| 3046 | EXAMPLES: |
|---|
| 3047 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 3048 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([-1, -1, 1]), lmap) |
|---|
| 3049 | sage: oc.find_roots() |
|---|
| 3050 | sage: oc.roots() |
|---|
| 3051 | [(1/2, 3/4)] |
|---|
| 3052 | sage: oc.reset_root_width(0, 1/2^200) |
|---|
| 3053 | sage: oc.find_roots() |
|---|
| 3054 | sage: oc |
|---|
| 3055 | ocean with precision 240 and 1 island(s) |
|---|
| 3056 | sage: RR(RealIntervalField(300)(oc.roots()[0]).absolute_diameter()).log2() |
|---|
| 3057 | -232.668979560890 |
|---|
| 3058 | """ |
|---|
| 3059 | cdef island isle = self.lgap.risland |
|---|
| 3060 | cdef int n = 0 |
|---|
| 3061 | while isle is not self.endpoint: |
|---|
| 3062 | if n == isle_num: |
|---|
| 3063 | isle.reset_root_width(target_width) |
|---|
| 3064 | |
|---|
| 3065 | isle = isle.rgap.risland |
|---|
| 3066 | n = n+1 |
|---|
| 3067 | |
|---|
| 3068 | def increase_precision(self): |
|---|
| 3069 | """ |
|---|
| 3070 | Increase the precision of the interval Bernstein polynomial held |
|---|
| 3071 | by any islands which are not done. (In normal use, calls to this |
|---|
| 3072 | function are separated by calls to self.refine_all().) |
|---|
| 3073 | |
|---|
| 3074 | EXAMPLES: |
|---|
| 3075 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 3076 | sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap) |
|---|
| 3077 | sage: oc |
|---|
| 3078 | ocean with precision 120 and 1 island(s) |
|---|
| 3079 | sage: oc.increase_precision() |
|---|
| 3080 | sage: oc.increase_precision() |
|---|
| 3081 | sage: oc.increase_precision() |
|---|
| 3082 | sage: oc |
|---|
| 3083 | ocean with precision 960 and 1 island(s) |
|---|
| 3084 | """ |
|---|
| 3085 | active_islands = [] |
|---|
| 3086 | cdef int total_islands = 0 |
|---|
| 3087 | cdef island isle = self.lgap.risland |
|---|
| 3088 | while isle is not self.endpoint: |
|---|
| 3089 | total_islands = total_islands + 1 |
|---|
| 3090 | if not isle.done(self.ctx) and len(isle.ancestors) == 0: |
|---|
| 3091 | active_islands += [isle] |
|---|
| 3092 | isle = isle.rgap.risland |
|---|
| 3093 | if len(active_islands) > 0: |
|---|
| 3094 | self.prec = self.prec * 2 |
|---|
| 3095 | p = self.approx_bp(self.msb - self.prec) |
|---|
| 3096 | targets = [] |
|---|
| 3097 | for isle in active_islands: |
|---|
| 3098 | targets += [(isle.lgap, isle.rgap, isle.bp.scale_log2)] |
|---|
| 3099 | self.ctx.dc_log_append(('splitting', (isle.lgap.lower, isle.lgap.upper), (isle.rgap.lower, isle.rgap.upper), isle.bp.scale_log2)) |
|---|
| 3100 | bps = split_for_targets(self.ctx, p, targets) |
|---|
| 3101 | for i in range(len(active_islands)): |
|---|
| 3102 | bp = bps[i] |
|---|
| 3103 | isle = active_islands[i] |
|---|
| 3104 | isle.bp = bp |
|---|
| 3105 | |
|---|
| 3106 | cdef class island: |
|---|
| 3107 | """ |
|---|
| 3108 | This implements the island portion of my ocean-island root isolation |
|---|
| 3109 | algorithm. See the documentation for class ocean, for more |
|---|
| 3110 | information on the overall algorithm. |
|---|
| 3111 | |
|---|
| 3112 | Island root refinement starts with a Bernstein polynomial whose |
|---|
| 3113 | region is the whole island (or perhaps slightly more than the |
|---|
| 3114 | island in certain cases). There are two subalgorithms; one when |
|---|
| 3115 | looking at a Bernstein polynomial covering a whole island (so we |
|---|
| 3116 | know that there are gaps on the left and right), and one when |
|---|
| 3117 | looking at a Bernstein polynomial covering the left segment of an |
|---|
| 3118 | island (so we know that there is a gap on the left, but the right |
|---|
| 3119 | is in the middle of an island). An important invariant of the |
|---|
| 3120 | left-segment subalgorithm over the region [l .. r] is that it |
|---|
| 3121 | always finds a gap [r0 .. r] ending at its right endpoint. |
|---|
| 3122 | |
|---|
| 3123 | Ignoring degree reduction, downscaling (precision reduction), and |
|---|
| 3124 | failures to split, the algorithm is roughly: |
|---|
| 3125 | |
|---|
| 3126 | Whole island: |
|---|
| 3127 | 1. If the island definitely has exactly one root, then return. |
|---|
| 3128 | 2. Split the island in (approximately) half. |
|---|
| 3129 | 3. If both halves definitely have no roots, then remove this island |
|---|
| 3130 | from its doubly-linked list (merging its left and right gaps) |
|---|
| 3131 | and return. |
|---|
| 3132 | 4. If either half definitely has no roots, then discard that half |
|---|
| 3133 | and call the whole-island algorithm with the other half, then return. |
|---|
| 3134 | 5. If both halves may have roots, then call the left-segment algorithm |
|---|
| 3135 | on the left half. |
|---|
| 3136 | 6. We now know that there is a gap immediately to the left of the |
|---|
| 3137 | right half, so call the whole-island algorithm on the right half, |
|---|
| 3138 | then return. |
|---|
| 3139 | |
|---|
| 3140 | Left segment: |
|---|
| 3141 | 1. Split the left segment in (approximately) half. |
|---|
| 3142 | 2. If both halves definitely have no roots, then extend the left gap |
|---|
| 3143 | over the segment and return. |
|---|
| 3144 | 3. If the left half definitely has no roots, then extend the left gap |
|---|
| 3145 | over this half and call the left-segment algorithm on the right half, |
|---|
| 3146 | then return. |
|---|
| 3147 | 4. If the right half definitely has no roots, then split the island |
|---|
| 3148 | in two, creating a new gap. Call the whole-island algorithm on the |
|---|
| 3149 | left half, then return. |
|---|
| 3150 | 5. Both halves may have roots. Call the left-segment algorithm on |
|---|
| 3151 | the left half. |
|---|
| 3152 | 6. We now know that there is a gap immediately to the left of the |
|---|
| 3153 | right half, so call the left-segment algorithm on the right half, |
|---|
| 3154 | then return. |
|---|
| 3155 | |
|---|
| 3156 | Degree reduction complicates this picture only slightly. Basically, |
|---|
| 3157 | we use heuristics to decide when degree reduction might be likely |
|---|
| 3158 | to succeed and be helpful; whenever this is the case, we attempt |
|---|
| 3159 | degree reduction. |
|---|
| 3160 | |
|---|
| 3161 | Precision reduction and split failure add more complications. |
|---|
| 3162 | The algorithm maintains a stack of different-precision representations |
|---|
| 3163 | of the interval Bernstein polynomial. The base of the stack |
|---|
| 3164 | is at the highest (currently known) precision; each stack entry has |
|---|
| 3165 | approximately half the precision of the entry below it. When we |
|---|
| 3166 | do a split, we pop off the top of the stack, split it, then push |
|---|
| 3167 | whichever half we're interested in back on the stack (so the |
|---|
| 3168 | different Bernstein polynomials may be over different regions). |
|---|
| 3169 | When we push a polynomial onto the stack, we may heuristically decide to |
|---|
| 3170 | push further lower-precision versions of the same polynomial onto the |
|---|
| 3171 | stack. |
|---|
| 3172 | |
|---|
| 3173 | In the algorithm above, whenever we say "split in (approximately) half", |
|---|
| 3174 | we attempt to split the top-of-stack polynomial using try_split() |
|---|
| 3175 | and try_rand_split(). However, these will fail if the sign of the |
|---|
| 3176 | polynomial at the chosen split point is unknown (if the polynomial is |
|---|
| 3177 | not known to high enough precision, or if the chosen split point |
|---|
| 3178 | actually happens to be a root of the polynomial). If this fails, then |
|---|
| 3179 | we discard the top-of-stack polynomial, and try again with the |
|---|
| 3180 | next polynomial down (which has approximately twice the precision). |
|---|
| 3181 | This next polynomial may not be over the same region; if not, we |
|---|
| 3182 | split it using de Casteljau's algorithm to get a polynomial over |
|---|
| 3183 | (approximately) the same region first. |
|---|
| 3184 | |
|---|
| 3185 | If we run out of higher-precision polynomials (if we empty out the |
|---|
| 3186 | entire stack), then we give up on root refinement for this island. |
|---|
| 3187 | The ocean class will notice this, provide the island with a |
|---|
| 3188 | higher-precision polynomial, and restart root refinement. Basically |
|---|
| 3189 | the only information kept in that case is the lower and upper bounds |
|---|
| 3190 | on the island. Since these are updated whenever we discover a "half" |
|---|
| 3191 | (of an island or a segment) that definitely contains no roots, we |
|---|
| 3192 | never need to re-examine these gaps. (We could keep more information. |
|---|
| 3193 | For example, we could keep a record of split points that succeeded |
|---|
| 3194 | and failed. However, a split point that failed at lower precision |
|---|
| 3195 | is likely to succeed at higher precision, so it's not worth avoiding. |
|---|
| 3196 | It could be useful to select split points that are known to succeed, |
|---|
| 3197 | but starting from a new Bernstein polynomial over a slightly different |
|---|
| 3198 | region, hitting such split points would require de Casteljau splits |
|---|
| 3199 | with non-power-of-two denominators, which are much much slower.) |
|---|
| 3200 | """ |
|---|
| 3201 | |
|---|
| 3202 | def __init__(self, interval_bernstein_polynomial bp, rr_gap lgap, rr_gap rgap): |
|---|
| 3203 | """ |
|---|
| 3204 | Initialize an island from a Bernstein polynomial, and the gaps to |
|---|
| 3205 | the left and right of the island. |
|---|
| 3206 | """ |
|---|
| 3207 | self.bp = bp |
|---|
| 3208 | self.ancestors = [] |
|---|
| 3209 | self.target_width = None |
|---|
| 3210 | self.lgap = lgap |
|---|
| 3211 | self.rgap = rgap |
|---|
| 3212 | self.known_done = False |
|---|
| 3213 | |
|---|
| 3214 | lgap.risland = self |
|---|
| 3215 | rgap.lisland = self |
|---|
| 3216 | |
|---|
| 3217 | def __repr__(self): |
|---|
| 3218 | """ |
|---|
| 3219 | Return a short summary of this island. |
|---|
| 3220 | """ |
|---|
| 3221 | |
|---|
| 3222 | return "island of width %s" % RR(self.bp.region_width()) |
|---|
| 3223 | |
|---|
| 3224 | def _info(self): |
|---|
| 3225 | # A python accessor for the information in this island. |
|---|
| 3226 | # For debugging purposes. |
|---|
| 3227 | return (self.bp, self.ancestors, self.target_width, self.lgap, self.rgap, self.known_done) |
|---|
| 3228 | |
|---|
| 3229 | def shrink_bp(self, context ctx): |
|---|
| 3230 | """ |
|---|
| 3231 | If the island's Bernstein polynomial covers a region much larger |
|---|
| 3232 | than the island itself (in particular, if either the island's |
|---|
| 3233 | left gap or right gap are totally contained in the polynomial's |
|---|
| 3234 | region) then shrink the polynomial down to cover the island more |
|---|
| 3235 | tightly. |
|---|
| 3236 | """ |
|---|
| 3237 | while True: |
|---|
| 3238 | bounds = self.bp.region() |
|---|
| 3239 | lbounds = relative_bounds(bounds, self.lgap.region()) |
|---|
| 3240 | rbounds = relative_bounds(bounds, self.rgap.region()) |
|---|
| 3241 | |
|---|
| 3242 | rtarget = wordsize_rational(rbounds[0], rbounds[1], ctx.wordsize) |
|---|
| 3243 | ltarget = wordsize_rational(lbounds[1], lbounds[0], ctx.wordsize) |
|---|
| 3244 | |
|---|
| 3245 | if lbounds[0] > zero_QQ or (ltarget >= QQ_1_32 and ltarget >= one_QQ-rtarget): |
|---|
| 3246 | (_, self.bp, _) = self.bp.de_casteljau(ctx, ltarget) |
|---|
| 3247 | elif rbounds[1] < one_QQ or rtarget <= QQ_31_32: |
|---|
| 3248 | (self.bp, _, _) = self.bp.de_casteljau(ctx, rtarget) |
|---|
| 3249 | else: |
|---|
| 3250 | break |
|---|
| 3251 | |
|---|
| 3252 | self.bp.lsign = self.lgap.sign |
|---|
| 3253 | self.bp.usign = self.rgap.sign |
|---|
| 3254 | |
|---|
| 3255 | def refine(self, context ctx): |
|---|
| 3256 | """ |
|---|
| 3257 | Attempts to shrink and/or split this island into sub-island |
|---|
| 3258 | that each definitely contain exactly one root. |
|---|
| 3259 | """ |
|---|
| 3260 | self.shrink_bp(ctx) |
|---|
| 3261 | try: |
|---|
| 3262 | self.refine_recurse(ctx, self.bp, self.ancestors, [], True) |
|---|
| 3263 | except PrecisionError: |
|---|
| 3264 | pass |
|---|
| 3265 | |
|---|
| 3266 | def refine_recurse(self, context ctx, interval_bernstein_polynomial bp, ancestors, history, rightmost): |
|---|
| 3267 | """ |
|---|
| 3268 | This implements the root isolation algorithm described in the |
|---|
| 3269 | class documentation for class island. This is the implementation |
|---|
| 3270 | of both the whole-island and the left-segment algorithms; |
|---|
| 3271 | if the flag rightmost is True, then it is the whole-island algorithm, |
|---|
| 3272 | otherwise the left-segment algorithm. |
|---|
| 3273 | |
|---|
| 3274 | The precision-reduction stack is (ancestors + [bp]); that is, the |
|---|
| 3275 | top-of-stack is maintained separately. |
|---|
| 3276 | """ |
|---|
| 3277 | cdef interval_bernstein_polynomial p1, p2 |
|---|
| 3278 | cdef rr_gap mgap |
|---|
| 3279 | cdef island lisland |
|---|
| 3280 | |
|---|
| 3281 | # If you examine the description of this algorithm in the |
|---|
| 3282 | # class island class documentation, you see that several of |
|---|
| 3283 | # the calls involved are tail recursions (that is, they are |
|---|
| 3284 | # of the form "call (this algorithm) recursively, then return"). |
|---|
| 3285 | # We perform tail-recursion optimization by hand: such calls |
|---|
| 3286 | # assign new values to the method parameters, and then fall off |
|---|
| 3287 | # the end of the following "while True" loop, and return to |
|---|
| 3288 | # the top of the method here. |
|---|
| 3289 | |
|---|
| 3290 | # This optimization is VITAL; without it, several test polynomials |
|---|
| 3291 | # (in particular, polynomials with roots that are very, very |
|---|
| 3292 | # close together) give stack overflow errors. |
|---|
| 3293 | |
|---|
| 3294 | while True: |
|---|
| 3295 | if rightmost and self.bp_done(bp): |
|---|
| 3296 | if bp.max_variations == 0: |
|---|
| 3297 | # No roots! Make the island disappear. |
|---|
| 3298 | self.lgap.risland = self.rgap.risland |
|---|
| 3299 | self.rgap.risland.lgap = self.lgap |
|---|
| 3300 | self.lgap.upper = self.rgap.upper |
|---|
| 3301 | else: |
|---|
| 3302 | self.bp = bp |
|---|
| 3303 | self.ancestors = ancestors |
|---|
| 3304 | return |
|---|
| 3305 | |
|---|
| 3306 | # This is our heuristic for deciding when to do degree |
|---|
| 3307 | # reduction. |
|---|
| 3308 | |
|---|
| 3309 | # In general, given a degree-d Bernstein polynomial, |
|---|
| 3310 | # if you perform a de Casteljau split at 1/2, the |
|---|
| 3311 | # coefficients of the resulting polynomials are about d bits |
|---|
| 3312 | # smaller than the coefficients of the original polynomial. |
|---|
| 3313 | |
|---|
| 3314 | # Conversely, if you do a split and the coefficients are |
|---|
| 3315 | # k bits smaller than the coefficients of the original |
|---|
| 3316 | # polynomial, this indicates that the original polynomial |
|---|
| 3317 | # may be very close to some degree-k polynomial. |
|---|
| 3318 | |
|---|
| 3319 | # Here, we look at the amount that the coefficients got smaller |
|---|
| 3320 | # over the last 3 splits. If they got more than 100 bits |
|---|
| 3321 | # smaller (that is, an average of more than 33 bits per split), |
|---|
| 3322 | # then we expect that the original polynomial is not |
|---|
| 3323 | # close to any polynomial of degree 30 or less. Since degree |
|---|
| 3324 | # reduction works by finding a polynomial of (currently) |
|---|
| 3325 | # degree 30 that is close to the original polynomial, |
|---|
| 3326 | # then this drastic reduction in coefficient size means that |
|---|
| 3327 | # degree reduction is likely to fail, so we don't bother |
|---|
| 3328 | # attempting it. |
|---|
| 3329 | |
|---|
| 3330 | # Note that this does not take into account the effects of |
|---|
| 3331 | # random splitting; maybe it should? For example, if the |
|---|
| 3332 | # last three splits were random splits with split points near |
|---|
| 3333 | # 1/4, and we're in the left-hand branch of all these splits, |
|---|
| 3334 | # then we would expect twice as much coefficient reduction; |
|---|
| 3335 | # so a coefficient size drop of 100 bits would actually |
|---|
| 3336 | # mean that we are near a degree-17 polynomial. |
|---|
| 3337 | |
|---|
| 3338 | # Also, we are willing to throw away up to 70 + msb_delta |
|---|
| 3339 | # bits of precision during degree reduction. I don't remember |
|---|
| 3340 | # how I selected this heuristic... |
|---|
| 3341 | |
|---|
| 3342 | if len(history) >= 3: |
|---|
| 3343 | old = history[-3] |
|---|
| 3344 | old_msb = old.get_msb_bit() |
|---|
| 3345 | cur_msb = bp.get_msb_bit() |
|---|
| 3346 | msb_delta = old_msb - cur_msb |
|---|
| 3347 | if msb_delta <= 100 and bp.bitsize - msb_delta >= 70: |
|---|
| 3348 | bp = bp.down_degree_iter(ctx, bp.scale_log2 + 70 + msb_delta) |
|---|
| 3349 | |
|---|
| 3350 | history = history[-3:] + [bp] |
|---|
| 3351 | |
|---|
| 3352 | # Heuristically push more lower-precision polynomials |
|---|
| 3353 | # on the "ancestors" stack |
|---|
| 3354 | (ancestors, bp) = self.less_bits(ancestors, bp) |
|---|
| 3355 | |
|---|
| 3356 | # Currently, we try a random split only once before giving up |
|---|
| 3357 | # and trying for higher precision; and then we try a 1/2 split |
|---|
| 3358 | # at the higher precision. Maybe we should try more random |
|---|
| 3359 | # splits before going to higher precision? Maybe we should |
|---|
| 3360 | # try less 1/2 splits? |
|---|
| 3361 | rv = bp.try_split(ctx, []) |
|---|
| 3362 | while rv is None: |
|---|
| 3363 | if bp.bitsize > 30: |
|---|
| 3364 | rv = bp.try_rand_split(ctx, []) |
|---|
| 3365 | if rv is None: |
|---|
| 3366 | (ancestors, bp) = self.more_bits(ctx, ancestors, bp, rightmost) |
|---|
| 3367 | if rv is None: |
|---|
| 3368 | rv = bp.try_split(ctx, []) |
|---|
| 3369 | |
|---|
| 3370 | (p1_, p2_, _) = rv |
|---|
| 3371 | p1 = p1_ |
|---|
| 3372 | p2 = p2_ |
|---|
| 3373 | |
|---|
| 3374 | # ctx.dc_log_append(('split_results', p1.variations(), p2.variations())) |
|---|
| 3375 | |
|---|
| 3376 | if p1.variations()[1] == 0: |
|---|
| 3377 | self.lgap.upper = p2.lower |
|---|
| 3378 | if p2.variations()[1] == 0: |
|---|
| 3379 | if rightmost: |
|---|
| 3380 | # No roots! Make the island disappear. |
|---|
| 3381 | self.lgap.risland = self.rgap.risland |
|---|
| 3382 | self.rgap.risland.lgap = self.lgap |
|---|
| 3383 | self.lgap.upper = self.rgap.upper |
|---|
| 3384 | return |
|---|
| 3385 | self.lgap.upper = p2.upper |
|---|
| 3386 | return |
|---|
| 3387 | else: |
|---|
| 3388 | bp = p2 |
|---|
| 3389 | # return to top of function (tail recursion optimization) |
|---|
| 3390 | else: |
|---|
| 3391 | if p2.variations()[1] == 0: |
|---|
| 3392 | if rightmost: |
|---|
| 3393 | self.rgap.lower = p2.lower |
|---|
| 3394 | bp = p1 |
|---|
| 3395 | # return to top of function |
|---|
| 3396 | else: |
|---|
| 3397 | # Split the island! |
|---|
| 3398 | mgap = rr_gap(p2.lower, p2.upper, p2.lsign) |
|---|
| 3399 | lisland = island(p1, self.lgap, mgap) |
|---|
| 3400 | lisland.target_width = self.target_width |
|---|
| 3401 | self.lgap = mgap |
|---|
| 3402 | mgap.risland = self |
|---|
| 3403 | if not lisland.done(ctx): |
|---|
| 3404 | try: |
|---|
| 3405 | lisland.refine_recurse(ctx, p1, ancestors, history, True) |
|---|
| 3406 | except PrecisionError: |
|---|
| 3407 | pass |
|---|
| 3408 | return |
|---|
| 3409 | else: |
|---|
| 3410 | self.refine_recurse(ctx, p1, ancestors, history, False) |
|---|
| 3411 | assert(self.lgap.upper == p2.lower) |
|---|
| 3412 | bp = p2 |
|---|
| 3413 | # return to top of function (tail recursion optimization) |
|---|
| 3414 | |
|---|
| 3415 | def less_bits(self, ancestors, interval_bernstein_polynomial bp): |
|---|
| 3416 | """ |
|---|
| 3417 | Heuristically pushes lower-precision polynomials on |
|---|
| 3418 | the polynomial stack. See the class documentation for class |
|---|
| 3419 | island for more information. |
|---|
| 3420 | """ |
|---|
| 3421 | # The current heuristic is to always push one lower-precision |
|---|
| 3422 | # polynomial, unless the current polynomial is floating-point. |
|---|
| 3423 | # If the current polynomial has bitsize < 130, then the new |
|---|
| 3424 | # polynomial is floating-point, otherwise it is integer, |
|---|
| 3425 | # with half the precision of the original. |
|---|
| 3426 | |
|---|
| 3427 | if bp.bitsize < 130: |
|---|
| 3428 | if isinstance(bp, interval_bernstein_polynomial_float): |
|---|
| 3429 | return (ancestors, bp) |
|---|
| 3430 | else: |
|---|
| 3431 | return (ancestors + [bp], bp.as_float()) |
|---|
| 3432 | else: |
|---|
| 3433 | return (ancestors + [bp], bp.downscale(bp.bitsize // 2)) |
|---|
| 3434 | |
|---|
| 3435 | def more_bits(self, context ctx, ancestors, interval_bernstein_polynomial bp, rightmost): |
|---|
| 3436 | """ |
|---|
| 3437 | Find a Bernstein polynomial on the "ancestors" stack with |
|---|
| 3438 | more precision than bp; if it is over a different region, |
|---|
| 3439 | then shrink its region to (approximately) match that of bp. |
|---|
| 3440 | (If this is rightmost -- if bp covers the whole island -- then |
|---|
| 3441 | we only require that the new region cover the whole island |
|---|
| 3442 | fairly tightly; if this is not rightmost, then the new region |
|---|
| 3443 | will have exactly the same right boundary as bp, although the |
|---|
| 3444 | left boundary may vary slightly.) |
|---|
| 3445 | """ |
|---|
| 3446 | cur_msb = bp.scale_log2 + bp.bitsize |
|---|
| 3447 | extra_bits = bp.bitsize // 2 |
|---|
| 3448 | if extra_bits < 30: extra_bits = 30 |
|---|
| 3449 | |
|---|
| 3450 | target_lsb_h = cur_msb - 3*extra_bits |
|---|
| 3451 | target_lsb = cur_msb - 4*extra_bits |
|---|
| 3452 | target_lsb_l = cur_msb - 6*extra_bits |
|---|
| 3453 | |
|---|
| 3454 | if bp.bitsize < 32: |
|---|
| 3455 | target_lsb_h = cur_msb - 48 |
|---|
| 3456 | target_lsb = target_lsb_h - 16 |
|---|
| 3457 | target_lsb_l = target_lsb - 32 |
|---|
| 3458 | |
|---|
| 3459 | cdef interval_bernstein_polynomial anc |
|---|
| 3460 | cdef interval_bernstein_polynomial ancestor_val |
|---|
| 3461 | |
|---|
| 3462 | for i in range(len(ancestors)-1, -1, -1): |
|---|
| 3463 | anc = ancestors[i] |
|---|
| 3464 | if target_lsb_h >= anc.scale_log2: |
|---|
| 3465 | ancestor_bitsize = anc.bitsize |
|---|
| 3466 | ancestor_msb = anc.scale_log2 + ancestor_bitsize |
|---|
| 3467 | ancestor_val = anc |
|---|
| 3468 | first_lsb = ancestor_val.scale_log2 |
|---|
| 3469 | first_msb = first_lsb + ancestor_val.bitsize |
|---|
| 3470 | |
|---|
| 3471 | ancestors = ancestors[:i] |
|---|
| 3472 | |
|---|
| 3473 | if bp.region() == ancestor_val.region(): |
|---|
| 3474 | if bp.bitsize < 32: |
|---|
| 3475 | return (ancestors + [ancestor_val], ancestor_val.as_float()) |
|---|
| 3476 | else: |
|---|
| 3477 | return (ancestors, ancestor_val) |
|---|
| 3478 | |
|---|
| 3479 | new_lsb = ancestor_val.scale_log2 |
|---|
| 3480 | if new_lsb < target_lsb_l: |
|---|
| 3481 | new_lsb = target_lsb |
|---|
| 3482 | |
|---|
| 3483 | hv_width = ancestor_val.region_width() |
|---|
| 3484 | rel_bounds = relative_bounds(ancestor_val.region(), bp.region()) |
|---|
| 3485 | rel_width = rel_bounds[1] - rel_bounds[0] |
|---|
| 3486 | |
|---|
| 3487 | rel_width_rr = RR(rel_width) |
|---|
| 3488 | |
|---|
| 3489 | ctx.dc_log_append(('pulling', |
|---|
| 3490 | first_msb, |
|---|
| 3491 | ancestor_val.level, |
|---|
| 3492 | first_lsb, |
|---|
| 3493 | ancestor_val.scale_log2, |
|---|
| 3494 | rel_width_rr, |
|---|
| 3495 | new_lsb, |
|---|
| 3496 | cur_msb, bp.scale_log2, |
|---|
| 3497 | target_lsb_h, target_lsb, target_lsb_l)) |
|---|
| 3498 | |
|---|
| 3499 | if rightmost: |
|---|
| 3500 | maybe_rgap = self.rgap |
|---|
| 3501 | else: |
|---|
| 3502 | maybe_rgap = None |
|---|
| 3503 | if rel_bounds[1] < 1: |
|---|
| 3504 | (ancestor_val, _, _) = ancestor_val.de_casteljau(ctx, rel_bounds[1]) |
|---|
| 3505 | ctx.dc_log_append(('pull_right', rel_bounds[1])) |
|---|
| 3506 | if ancestor_val.region_width() / hv_width < ~Integer(32): |
|---|
| 3507 | ancestor_val = ancestor_val.down_degree_iter(ctx, target_lsb_h) |
|---|
| 3508 | |
|---|
| 3509 | rel_bounds = relative_bounds(ancestor_val.region(), bp.region()) |
|---|
| 3510 | assert(rel_bounds[1] == 1) |
|---|
| 3511 | |
|---|
| 3512 | ancestor_val = split_for_targets(ctx, ancestor_val, [(self.lgap, maybe_rgap, target_lsb_h)])[0] |
|---|
| 3513 | # if rel_lbounds[1] > 0: |
|---|
| 3514 | # left_split = -exact_rational(simple_wordsize_float(-rel_lbounds[1], -rel_lbounds[0])) |
|---|
| 3515 | # (_, ancestor_val, _) = ancestor_val.de_casteljau(ctx, left_split) |
|---|
| 3516 | # ctx.dc_log_append(('pull_left', left_split)) |
|---|
| 3517 | |
|---|
| 3518 | ancestor_val.lsign = bp.lsign |
|---|
| 3519 | ancestor_val.usign = bp.usign |
|---|
| 3520 | |
|---|
| 3521 | new_rel_bounds = relative_bounds(ancestor_val.region(), bp.region()) |
|---|
| 3522 | assert(new_rel_bounds[1] - new_rel_bounds[0] >= Integer(255)/256) |
|---|
| 3523 | |
|---|
| 3524 | while ancestor_val.scale_log2 < target_lsb_l: |
|---|
| 3525 | ancestors = ancestors + [ancestor_val] |
|---|
| 3526 | ancestor_val = ancestor_val.downscale(ancestor_val.bitsize // 2) |
|---|
| 3527 | |
|---|
| 3528 | if bp.bitsize < 32: |
|---|
| 3529 | return (ancestors + [ancestor_val], ancestor_val.as_float()) |
|---|
| 3530 | |
|---|
| 3531 | return (ancestors, ancestor_val) |
|---|
| 3532 | |
|---|
| 3533 | self.ancestors = [] |
|---|
| 3534 | raise PrecisionError() |
|---|
| 3535 | |
|---|
| 3536 | def reset_root_width(self, target_width): |
|---|
| 3537 | """ |
|---|
| 3538 | Modify the criteria for this island to require that it is not "done" |
|---|
| 3539 | until its width is less than or equal to target_width. |
|---|
| 3540 | """ |
|---|
| 3541 | |
|---|
| 3542 | width = self.bp.upper - self.bp.lower |
|---|
| 3543 | |
|---|
| 3544 | if target_width < width: |
|---|
| 3545 | self.known_done = False |
|---|
| 3546 | |
|---|
| 3547 | if self.target_width is None or target_width < self.target_width: |
|---|
| 3548 | self.target_width = target_width |
|---|
| 3549 | |
|---|
| 3550 | def bp_done(self, interval_bernstein_polynomial bp): |
|---|
| 3551 | """ |
|---|
| 3552 | Examine the given Bernstein polynomial to see if it is known |
|---|
| 3553 | to have exactly one root in its region. (In addition, we require |
|---|
| 3554 | that the polynomial region not include 0 or 1. This makes things |
|---|
| 3555 | work if the user gives explicit bounds to real_roots(), |
|---|
| 3556 | where the lower or upper bound is a root of the polynomial. |
|---|
| 3557 | real_roots() deals with this by explicitly detecting it, |
|---|
| 3558 | dividing out the appropriate linear polynomial, and adding the |
|---|
| 3559 | root to the returned list of roots; but then if the island |
|---|
| 3560 | considers itself "done" with a region including 0 or 1, the returned |
|---|
| 3561 | root regions can overlap with each other.) |
|---|
| 3562 | """ |
|---|
| 3563 | |
|---|
| 3564 | variations = bp.variations()[1] |
|---|
| 3565 | |
|---|
| 3566 | if variations > 1: |
|---|
| 3567 | return False |
|---|
| 3568 | if bp.lower == 0: |
|---|
| 3569 | return False |
|---|
| 3570 | if bp.upper == 1: |
|---|
| 3571 | return False |
|---|
| 3572 | if variations == 0: |
|---|
| 3573 | return True |
|---|
| 3574 | if self.target_width is not None and self.bp.upper - self.bp.lower > self.target_width: |
|---|
| 3575 | return False |
|---|
| 3576 | if bp.level == 0: |
|---|
| 3577 | return True |
|---|
| 3578 | if not (0 in bp.slope_err + bp.slope_range()): |
|---|
| 3579 | return True |
|---|
| 3580 | return False |
|---|
| 3581 | |
|---|
| 3582 | |
|---|
| 3583 | def done(self, context ctx): |
|---|
| 3584 | """ |
|---|
| 3585 | Check to see if the island is known to contain zero roots or |
|---|
| 3586 | is known to contain one root. |
|---|
| 3587 | """ |
|---|
| 3588 | |
|---|
| 3589 | if self.known_done: |
|---|
| 3590 | return True |
|---|
| 3591 | |
|---|
| 3592 | if self.bp_done(self.bp): |
|---|
| 3593 | self.known_done = True |
|---|
| 3594 | else: |
|---|
| 3595 | self.shrink_bp(ctx) |
|---|
| 3596 | if self.bp_done(self.bp): |
|---|
| 3597 | self.known_done = True |
|---|
| 3598 | |
|---|
| 3599 | return self.known_done |
|---|
| 3600 | |
|---|
| 3601 | def has_root(self): |
|---|
| 3602 | """ |
|---|
| 3603 | Assuming that the island is done (has either 0 or 1 roots), |
|---|
| 3604 | reports whether the island has a root. |
|---|
| 3605 | """ |
|---|
| 3606 | |
|---|
| 3607 | assert(self.known_done) |
|---|
| 3608 | |
|---|
| 3609 | return bool(self.bp.max_variations) |
|---|
| 3610 | |
|---|
| 3611 | cdef class rr_gap: |
|---|
| 3612 | """ |
|---|
| 3613 | A simple class representing the gaps between islands, in my |
|---|
| 3614 | ocean-island root isolation algorithm. Named "rr_gap" for |
|---|
| 3615 | "real roots gap", because "gap" seemed too short and generic. |
|---|
| 3616 | """ |
|---|
| 3617 | |
|---|
| 3618 | def __init__(self, lower, upper, sign): |
|---|
| 3619 | """ |
|---|
| 3620 | Initialize an rr_gap element. |
|---|
| 3621 | """ |
|---|
| 3622 | self.lower = lower |
|---|
| 3623 | self.upper = upper |
|---|
| 3624 | self.sign = sign |
|---|
| 3625 | |
|---|
| 3626 | def region(self): |
|---|
| 3627 | return (self.lower, self.upper) |
|---|
| 3628 | |
|---|
| 3629 | class linear_map: |
|---|
| 3630 | """ |
|---|
| 3631 | A simple class to map linearly between original coordinates |
|---|
| 3632 | (ranging from [lower .. upper]) and ocean coordinates (ranging |
|---|
| 3633 | from [0 .. 1]). |
|---|
| 3634 | """ |
|---|
| 3635 | |
|---|
| 3636 | def __init__(self, lower, upper): |
|---|
| 3637 | self.lower = lower |
|---|
| 3638 | self.upper = upper |
|---|
| 3639 | self.width = upper - lower |
|---|
| 3640 | |
|---|
| 3641 | def from_ocean(self, region): |
|---|
| 3642 | (l, u) = region |
|---|
| 3643 | return (self.lower + l*self.width, self.lower + u*self.width) |
|---|
| 3644 | |
|---|
| 3645 | def to_ocean(self, region): |
|---|
| 3646 | (l, u) = region |
|---|
| 3647 | return ((l - self.lower) / self.width, (u - self.lower) / self.width) |
|---|
| 3648 | |
|---|
| 3649 | lmap = linear_map(0, 1) |
|---|
| 3650 | |
|---|
| 3651 | class warp_map: |
|---|
| 3652 | """ |
|---|
| 3653 | A class to map between original coordinates and ocean coordinates. |
|---|
| 3654 | If neg is False, then the original->ocean transform is |
|---|
| 3655 | x -> x/(x+1), and the ocean->original transform is x/(1-x); |
|---|
| 3656 | this maps between [0 .. infinity] and [0 .. 1]. |
|---|
| 3657 | If neg is True, then the original->ocean transform is |
|---|
| 3658 | x -> -x/(1-x), and the ocean->original transform is the same thing: |
|---|
| 3659 | -x/(1-x). This maps between [0 .. -infinity] and [0 .. 1]. |
|---|
| 3660 | """ |
|---|
| 3661 | |
|---|
| 3662 | def __init__(self, neg): |
|---|
| 3663 | self.neg = neg |
|---|
| 3664 | |
|---|
| 3665 | def from_ocean(self, region): |
|---|
| 3666 | (l, u) = region |
|---|
| 3667 | if self.neg: |
|---|
| 3668 | return (-u/(1-u), -l/(1-l)) |
|---|
| 3669 | else: |
|---|
| 3670 | return (l/(1-l), u/(1-u)) |
|---|
| 3671 | |
|---|
| 3672 | def to_ocean(self, region): |
|---|
| 3673 | (l, u) = region |
|---|
| 3674 | if self.neg: |
|---|
| 3675 | return (-u/(1-u), -l/(1-l)) |
|---|
| 3676 | else: |
|---|
| 3677 | return (l/(l+1), u/(u+1)) |
|---|
| 3678 | |
|---|
| 3679 | def real_roots(p, bounds=None, seed=None, skip_squarefree=False, do_logging=False, wordsize=32, retval='rational', strategy=None, max_diameter=None): |
|---|
| 3680 | """ |
|---|
| 3681 | Compute the real roots of a given polynomial with exact |
|---|
| 3682 | coefficients (integer, rational, and algebraic real coefficients |
|---|
| 3683 | are supported). Returns a list of pairs of a root and its |
|---|
| 3684 | multiplicity. |
|---|
| 3685 | |
|---|
| 3686 | The root itself can be returned in one of three different ways. |
|---|
| 3687 | If retval=='rational', then it is returned as a pair of rationals |
|---|
| 3688 | that define a region that includes exactly one root. If |
|---|
| 3689 | retval=='interval', then it is returned as a RealIntervalFieldElement |
|---|
| 3690 | that includes exactly one root. If retval=='algebraic_real', then |
|---|
| 3691 | it is returned as an algebraic_real. In the former two cases, all |
|---|
| 3692 | the intervals are disjoint. |
|---|
| 3693 | |
|---|
| 3694 | An alternate high-level algorithm can be used by selecting |
|---|
| 3695 | strategy='warp'. This affects the conversion into Bernstein |
|---|
| 3696 | polynomial form, but still uses the same ocean-island algorithm |
|---|
| 3697 | as the default algorithm. The 'warp' algorithm performs the conversion |
|---|
| 3698 | into Bernstein polynomial form much more quickly, but performs |
|---|
| 3699 | the rest of the computation slightly slower in some benchmarks. |
|---|
| 3700 | The 'warp' algorithm is particularly likely to be helpful for |
|---|
| 3701 | low-degree polynomials. |
|---|
| 3702 | |
|---|
| 3703 | Part of the algorithm is randomized; the seed parameter gives a seed |
|---|
| 3704 | for the random number generator. (By default, the same |
|---|
| 3705 | seed is used for every call, so that results are repeatable.) The |
|---|
| 3706 | random seed may affect the running time, or the exact intervals returned, |
|---|
| 3707 | but the results are correct regardless of the seed used. |
|---|
| 3708 | |
|---|
| 3709 | The bounds parameter lets you find roots in some proper subinterval of |
|---|
| 3710 | the reals; it takes a pair of a rational lower and upper bound |
|---|
| 3711 | and only roots within this bound will be found. Currently, specifying |
|---|
| 3712 | bounds does not work if you select strategy='warp', or if you |
|---|
| 3713 | use a polynomial with algebraic real coefficients. |
|---|
| 3714 | |
|---|
| 3715 | By default, the algorithm will do a squarefree decomposition |
|---|
| 3716 | to get squarefree polynomials. The skip_squarefree parameter |
|---|
| 3717 | lets you skip this step. (If this step is skipped, and the polynomial |
|---|
| 3718 | has a repeated real root, then the algorithm will loop forever! |
|---|
| 3719 | However, repeated non-real roots are not a problem.) |
|---|
| 3720 | |
|---|
| 3721 | For integer and rational coefficients, the squarefree |
|---|
| 3722 | decomposition is very fast, but it may be slow for algebraic |
|---|
| 3723 | reals. (It may trigger exact computation, so it might be |
|---|
| 3724 | arbitrarily slow. The only other way that this algorithm might |
|---|
| 3725 | trigger exact computation on algebraic real coefficients is that |
|---|
| 3726 | it checks the constant term of the input polynomial for equality with |
|---|
| 3727 | zero.) |
|---|
| 3728 | |
|---|
| 3729 | Part of the algorithm works (approximately) by splitting numbers into |
|---|
| 3730 | word-size pieces (that is, pieces that fit into a machine word). |
|---|
| 3731 | For portability, this defaults to always selecting pieces suitable |
|---|
| 3732 | for a 32-bit machine; the wordsize parameter lets you make choices |
|---|
| 3733 | suitable for a 64-bit machine instead. (This affects the running |
|---|
| 3734 | time, and the exact intervals returned, but the results are correct |
|---|
| 3735 | on both 32- and 64-bit machines even if the wordsize is chosen "wrong".) |
|---|
| 3736 | |
|---|
| 3737 | The precision of the results can be improved (at the expense of time, |
|---|
| 3738 | of course) by specifying the max_diameter parameter. If specified, |
|---|
| 3739 | this sets the maximum diameter() of the intervals returned. |
|---|
| 3740 | (SAGE defines diameter() to be the relative diameter for intervals |
|---|
| 3741 | that do not contain 0, and the absolute diameter for intervals |
|---|
| 3742 | containing 0.) This directly affects the results in rational or |
|---|
| 3743 | interval return mode; in algebraic_real mode, it increases the |
|---|
| 3744 | precision of the intervals passed to the algebraic_real package, |
|---|
| 3745 | which may speed up some operations on that algebraic_real. |
|---|
| 3746 | |
|---|
| 3747 | Some logging can be enabled with do_logging=True. If logging is enabled, |
|---|
| 3748 | then the normal values are not returned; instead, a pair of |
|---|
| 3749 | the internal context object and a list of all the roots in their |
|---|
| 3750 | internal form is returned. |
|---|
| 3751 | |
|---|
| 3752 | ALGORITHM: We convert the polynomial into the Bernstein basis, and |
|---|
| 3753 | then use de Casteljau's algorithm and Descartes' rule of signs |
|---|
| 3754 | (using interval arithmetic) to locate the roots. |
|---|
| 3755 | |
|---|
| 3756 | EXAMPLES: |
|---|
| 3757 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 3758 | sage: x = polygen(ZZ) |
|---|
| 3759 | sage: real_roots(x^3 - x^2 - x - 1) |
|---|
| 3760 | [((7/4, 19/8), 1)] |
|---|
| 3761 | sage: real_roots((x-1)*(x-2)*(x-3)*(x-5)*(x-8)*(x-13)*(x-21)*(x-34)) |
|---|
| 3762 | [((11/16, 33/32), 1), ((11/8, 33/16), 1), ((11/4, 55/16), 1), ((77/16, 165/32), 1), ((11/2, 33/4), 1), ((11, 55/4), 1), ((165/8, 341/16), 1), ((22, 44), 1)] |
|---|
| 3763 | sage: real_roots(x^5 * (x^2 - 9999)^2 - 1) |
|---|
| 3764 | [((-29274496381311/9007199254740992, 419601125186091/2251799813685248), 1), ((2126658450145849453951061654415153249597/21267647932558653966460912964485513216, 4253316902721330018853696359533061621799/42535295865117307932921825928971026432), 1), ((1063329226287740282451317352558954186101/10633823966279326983230456482242756608, 531664614358685696701445201630854654353/5316911983139663491615228241121378304), 1)] |
|---|
| 3765 | sage: real_roots(x^5 * (x^2 - 9999)^2 - 1, seed=42) |
|---|
| 3766 | [((-123196838480289/18014398509481984, 293964743458749/9007199254740992), 1), ((8307259573979551907841696381986376143/83076749736557242056487941267521536, 16614519150981033789137940378745325503/166153499473114484112975882535043072), 1), ((519203723562592617581015249797434335/5192296858534827628530496329220096, 60443268924081068060312183/604462909807314587353088), 1)] |
|---|
| 3767 | sage: real_roots(x^5 * (x^2 - 9999)^2 - 1, wordsize=64) |
|---|
| 3768 | [((-62866503803202151050003/19342813113834066795298816, 901086554512564177624143/4835703278458516698824704), 1), ((544424563237337315214990987922809050101157/5444517870735015415413993718908291383296, 1088849127096660194637118845654929064385439/10889035741470030830827987437816582766592), 1), ((272212281929661439711063928866060007142141/2722258935367507707706996859454145691648, 136106141275823501959100399337685485662633/1361129467683753853853498429727072845824), 1)] |
|---|
| 3769 | sage: real_roots(x) |
|---|
| 3770 | [((-47/256, 81/512), 1)] |
|---|
| 3771 | sage: real_roots(x * (x-1)) |
|---|
| 3772 | [((-47/256, 81/512), 1), ((1/2, 1201/1024), 1)] |
|---|
| 3773 | sage: real_roots(x-1) |
|---|
| 3774 | [((209/256, 593/512), 1)] |
|---|
| 3775 | sage: real_roots(x*(x-1)*(x-2), bounds=(0, 2)) |
|---|
| 3776 | [((0, 0), 1), ((81/128, 337/256), 1), ((2, 2), 1)] |
|---|
| 3777 | sage: real_roots(x*(x-1)*(x-2), bounds=(0, 2), retval='algebraic_real') |
|---|
| 3778 | [([0.00000000000000000 .. 0.00000000000000000], 1), ([1.0000000000000000 .. 1.0000000000000000], 1), ([2.0000000000000000 .. 2.0000000000000000], 1)] |
|---|
| 3779 | sage: v = 2^40 |
|---|
| 3780 | sage: real_roots((x^2-1)^2 * (x^2 - (v+1)/v)) |
|---|
| 3781 | [((-12855504354077768210885019021174120740504020581912910106032833/12855504354071922204335696738729300820177623950262342682411008, -6427752177038884105442509510587059395588605840418680645585479/6427752177035961102167848369364650410088811975131171341205504), 1), ((-1125899906842725/1125899906842624, -562949953421275/562949953421312), 2), ((62165404551223330269422781018352603934643403586760330761772204409982940218804935733653/62165404551223330269422781018352605012557018849668464680057997111644937126566671941632, 3885337784451458141838923813647037871787041539340705594199885610069035709862106085785/3885337784451458141838923813647037813284813678104279042503624819477808570410416996352), 2), ((509258994083853105745586001837045839749063767798922046787130823804169826426726965449697819/509258994083621521567111422102344540262867098416484062659035112338595324940834176545849344, 25711008708155536421770038042348240136257704305733983563630791/25711008708143844408671393477458601640355247900524685364822016), 1)] |
|---|
| 3782 | sage: real_roots(x^2 - 2) |
|---|
| 3783 | [((-3/2, -1), 1), ((1, 3/2), 1)] |
|---|
| 3784 | sage: real_roots(x^2 - 2, retval='interval') |
|---|
| 3785 | [([-1.5000000000000000 .. -1.0000000000000000], 1), ([1.0000000000000000 .. 1.5000000000000000], 1)] |
|---|
| 3786 | sage: real_roots(x^2 - 2, max_diameter=1/2^30) |
|---|
| 3787 | [((-22506280506048041472675379598886543645348790970912519198456805737131269246430553365310109/15914343565113172548972231940698266883214596825515126958094847260581103904401068017057792, -45012561012096082945350759197773086524448972309421182031053065599548946985601579935498343/31828687130226345097944463881396533766429193651030253916189694521162207808802136034115584), 1), ((45012561012096082945350759197773086524448972309421182031053065599548946985601579935498343/31828687130226345097944463881396533766429193651030253916189694521162207808802136034115584, 22506280506048041472675379598886543645348790970912519198456805737131269246430553365310109/15914343565113172548972231940698266883214596825515126958094847260581103904401068017057792), 1)] |
|---|
| 3788 | sage: real_roots(x^2 - 2, retval='interval', max_diameter=1/2^500) |
|---|
| 3789 | [([-1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095530 .. -1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095519], 1), ([1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095519 .. 1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095530], 1)] |
|---|
| 3790 | sage: ar_rts = real_roots(x^2 - 2, retval='algebraic_real'); ar_rts |
|---|
| 3791 | [([-1.4142135623730952 .. -1.4142135623730949], 1), ([1.4142135623730949 .. 1.4142135623730952], 1)] |
|---|
| 3792 | sage: ar_rts[0][0]^2 - 2 == 0 |
|---|
| 3793 | True |
|---|
| 3794 | sage: v = 2^40 |
|---|
| 3795 | sage: real_roots((x-1) * (x-(v+1)/v), retval='interval') |
|---|
| 3796 | [([0.99999999999977251 .. 1.0000000000001137], 1), ([1.0000000000004545 .. 1.0000000000018190], 1)] |
|---|
| 3797 | sage: v = 2^60 |
|---|
| 3798 | sage: real_roots((x-1) * (x-(v+1)/v), retval='interval') |
|---|
| 3799 | [([0.999999999999999999941850329426260 .. 1.00000000000000000016070246737549], 1), ([1.00000000000000000037955460532465 .. 1.00000000000000000125496315712147], 1)] |
|---|
| 3800 | sage: real_roots((x-1) * (x-2), strategy='warp') |
|---|
| 3801 | [((499/525, 1173/875), 1), ((337/175, 849/175), 1)] |
|---|
| 3802 | sage: real_roots((x+3)*(x+1)*x*(x-1)*(x-2), strategy='warp') |
|---|
| 3803 | [((-1713/335, -689/335), 1), ((-2067/2029, -689/1359), 1), ((0, 0), 1), ((499/525, 1173/875), 1), ((337/175, 849/175), 1)] |
|---|
| 3804 | sage: real_roots((x+3)*(x+1)*x*(x-1)*(x-2), strategy='warp', retval='algebraic_real') |
|---|
| 3805 | [([-3.0000000000000005 .. -2.9999999999999995], 1), ([-1.0000000000000003 .. -0.99999999999999988], 1), ([0.00000000000000000 .. 0.00000000000000000], 1), ([0.99999999999999988 .. 1.0000000000000003], 1), ([1.9999999999999997 .. 2.0000000000000005], 1)] |
|---|
| 3806 | sage: ar_rts = real_roots(x-1, retval='algebraic_real') |
|---|
| 3807 | sage: ar_rts[0][0] == 1 |
|---|
| 3808 | True |
|---|
| 3809 | |
|---|
| 3810 | If the polynomial has no real roots, we get an empty list. |
|---|
| 3811 | sage: (x^2 + 1).real_root_intervals() |
|---|
| 3812 | [] |
|---|
| 3813 | |
|---|
| 3814 | We can compute Conway's constant |
|---|
| 3815 | (see http://mathworld.wolfram.com/ConwaysConstant.html) to arbitrary |
|---|
| 3816 | precision. |
|---|
| 3817 | sage: p = x^71 - x^69 - 2*x^68 - x^67 + 2*x^66 + 2*x^65 + x^64 - x^63 - x^62 - x^61 - x^60 - x^59 + 2*x^58 + 5*x^57 + 3*x^56 - 2*x^55 - 10*x^54 - 3*x^53 - 2*x^52 + 6*x^51 + 6*x^50 + x^49 + 9*x^48 - 3*x^47 - 7*x^46 - 8*x^45 - 8*x^44 + 10*x^43 + 6*x^42 + 8*x^41 - 5*x^40 - 12*x^39 + 7*x^38 - 7*x^37 + 7*x^36 + x^35 - 3*x^34 + 10*x^33 + x^32 - 6*x^31 - 2*x^30 - 10*x^29 - 3*x^28 + 2*x^27 + 9*x^26 - 3*x^25 + 14*x^24 - 8*x^23 - 7*x^21 + 9*x^20 + 3*x^19 - 4*x^18 - 10*x^17 - 7*x^16 + 12*x^15 + 7*x^14 + 2*x^13 - 12*x^12 - 4*x^11 - 2*x^10 + 5*x^9 + x^7 - 7*x^6 + 7*x^5 - 4*x^4 + 12*x^3 - 6*x^2 + 3*x - 6 |
|---|
| 3818 | sage: cc = real_roots(p, retval='algebraic_real')[2][0] # long time |
|---|
| 3819 | sage: RealField(180)(cc) # long time |
|---|
| 3820 | 1.3035772690342963912570991121525518907307025046594049 |
|---|
| 3821 | |
|---|
| 3822 | Now we play with algebraic real coefficients. |
|---|
| 3823 | sage: x = polygen(AA) |
|---|
| 3824 | sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2) |
|---|
| 3825 | sage: real_roots(p) |
|---|
| 3826 | [((499/525, 2171/1925), 1), ((1173/875, 2521/1575), 1), ((337/175, 849/175), 1)] |
|---|
| 3827 | sage: ar_rts = real_roots(p, retval='algebraic_real'); ar_rts |
|---|
| 3828 | [([0.99999999999999988 .. 1.0000000000000003], 1), ([1.4142135623730949 .. 1.4142135623730952], 1), ([1.9999999999999997 .. 2.0000000000000005], 1)] |
|---|
| 3829 | sage: ar_rts[1][0]^2 == 2 |
|---|
| 3830 | True |
|---|
| 3831 | sage: ar_rts = real_roots(x*(x-1), retval='algebraic_real') |
|---|
| 3832 | sage: ar_rts[0][0] == 0 |
|---|
| 3833 | True |
|---|
| 3834 | sage: p2 = p * (p - 1/100); p2 |
|---|
| 3835 | x^6 + [-8.8284271247461917 .. -8.8284271247461898]*x^5 + [31.970562748477139 .. 31.970562748477143]*x^4 + [-60.779552621700475 .. -60.779552621700467]*x^3 + [63.985267632578008 .. 63.985267632578016]*x^2 + [-35.376134905855956 .. -35.376134905855948]*x + [8.0282842712474611 .. 8.0282842712474630] |
|---|
| 3836 | sage: real_roots(p2, retval='interval') |
|---|
| 3837 | [([0.99197568389057744 .. 1.0026279602750193], 1), ([1.0133947772657450 .. 1.0352795031055902], 1), ([1.3701989150090414 .. 1.3852957233848955], 1), ([1.4005860805860805 .. 1.4637593984962408], 1), ([1.9959314285714284 .. 2.0019352991697686], 1), ([2.0079632816982213 .. 2.0200921658986180], 1)] |
|---|
| 3838 | sage: p = (x - 1) * (x - sqrt(AA(2)))^2 * (x - 2)^3 * sqrt(AA(3)) |
|---|
| 3839 | sage: real_roots(p, retval='interval') |
|---|
| 3840 | [([0.99999999999999988 .. 1.0000000000000003], 1), ([1.4142135623730949 .. 1.4142135623730952], 2), ([1.9999999999999997 .. 2.0000000000000005], 3)] |
|---|
| 3841 | """ |
|---|
| 3842 | base = p.base_ring() |
|---|
| 3843 | |
|---|
| 3844 | ar_input = False |
|---|
| 3845 | |
|---|
| 3846 | if base is not ZZ: |
|---|
| 3847 | ZZx = PolynomialRing(ZZ, 'x') |
|---|
| 3848 | if base is QQ: |
|---|
| 3849 | p = ZZx(p * p.denominator()) |
|---|
| 3850 | elif base is AA: |
|---|
| 3851 | ar_input = True |
|---|
| 3852 | else: |
|---|
| 3853 | raise ValueError, "Don't know how to isolate roots for " + str(p.parent()) |
|---|
| 3854 | |
|---|
| 3855 | if ar_input and bounds is not None: |
|---|
| 3856 | raise NotImplementedError, "Cannot set your own bounds with algebraic real input" |
|---|
| 3857 | |
|---|
| 3858 | if ar_input: strategy = 'warp' |
|---|
| 3859 | |
|---|
| 3860 | if bounds is not None and strategy=='warp': |
|---|
| 3861 | raise NotImplementedError, "Cannot set your own bounds with strategy=warp" |
|---|
| 3862 | |
|---|
| 3863 | if seed is None: seed = 1 |
|---|
| 3864 | |
|---|
| 3865 | if skip_squarefree: |
|---|
| 3866 | factors = [(p, 1)] |
|---|
| 3867 | else: |
|---|
| 3868 | factors = p.squarefree_decomposition() |
|---|
| 3869 | |
|---|
| 3870 | ctx = context(do_logging, seed, wordsize) |
|---|
| 3871 | |
|---|
| 3872 | extra_roots = [] |
|---|
| 3873 | oceans = [] |
|---|
| 3874 | |
|---|
| 3875 | cdef ocean oc |
|---|
| 3876 | |
|---|
| 3877 | for (factor, exp) in factors: |
|---|
| 3878 | if strategy=='warp': |
|---|
| 3879 | if factor.constant_coefficient() == 0: |
|---|
| 3880 | x = factor.parent().gen() |
|---|
| 3881 | extra_roots.append(((0, 0), x, exp, None, None)) |
|---|
| 3882 | factor = factor // x |
|---|
| 3883 | if ar_input: |
|---|
| 3884 | oc = ocean(ctx, bernstein_polynomial_factory_ar(factor, False), warp_map(False)) |
|---|
| 3885 | else: |
|---|
| 3886 | b = to_bernstein_warp(factor) |
|---|
| 3887 | oc = ocean(ctx, bernstein_polynomial_factory_ratlist(b), warp_map(False)) |
|---|
| 3888 | oc.find_roots() |
|---|
| 3889 | oceans.append((oc, factor, exp)) |
|---|
| 3890 | |
|---|
| 3891 | if ar_input: |
|---|
| 3892 | oc = ocean(ctx, bernstein_polynomial_factory_ar(factor, True), warp_map(True)) |
|---|
| 3893 | else: |
|---|
| 3894 | b = copy(b) |
|---|
| 3895 | for i in range(1, len(b), 2): |
|---|
| 3896 | b[i] = -b[i] |
|---|
| 3897 | oc = ocean(ctx, bernstein_polynomial_factory_ratlist(b), warp_map(True)) |
|---|
| 3898 | oc.find_roots() |
|---|
| 3899 | oceans.append((oc, factor, exp)) |
|---|
| 3900 | else: |
|---|
| 3901 | if bounds is None: |
|---|
| 3902 | bounds = rational_root_bounds(factor) |
|---|
| 3903 | if bounds is None: |
|---|
| 3904 | continue |
|---|
| 3905 | else: |
|---|
| 3906 | (left, right) = bounds |
|---|
| 3907 | else: |
|---|
| 3908 | (left, right) = bounds |
|---|
| 3909 | # Bad things happen if the bounds are roots themselves. |
|---|
| 3910 | # Avoid this by dividing out linear polynomials if |
|---|
| 3911 | # the bounds are roots. |
|---|
| 3912 | if factor(left) == 0: |
|---|
| 3913 | x = factor.parent().gen() |
|---|
| 3914 | linfac = (x * left.denominator() - left.numerator()) |
|---|
| 3915 | extra_roots.append(((left, left), linfac, exp, None, None)) |
|---|
| 3916 | factor = factor // linfac |
|---|
| 3917 | if factor(right) == 0: |
|---|
| 3918 | x = factor.parent().gen() |
|---|
| 3919 | linfac = (x * right.denominator() - right.numerator()) |
|---|
| 3920 | extra_roots.append(((right, right), linfac, exp, None, None)) |
|---|
| 3921 | factor = factor // linfac |
|---|
| 3922 | |
|---|
| 3923 | b, _ = to_bernstein(factor, left, right) |
|---|
| 3924 | |
|---|
| 3925 | oc = ocean(ctx, bernstein_polynomial_factory_ratlist(b), linear_map(left, right)) |
|---|
| 3926 | oc.find_roots() |
|---|
| 3927 | oceans.append((oc, factor, exp)) |
|---|
| 3928 | |
|---|
| 3929 | while True: |
|---|
| 3930 | all_roots = copy(extra_roots) |
|---|
| 3931 | |
|---|
| 3932 | for (oc, factor, exp) in oceans: |
|---|
| 3933 | rel_roots = oc.roots() |
|---|
| 3934 | |
|---|
| 3935 | cur_roots = [oc.mapping.from_ocean(r) for r in rel_roots] |
|---|
| 3936 | |
|---|
| 3937 | all_roots.extend([(cur_roots[j], factor, exp, oc, j) for j in range(len(cur_roots))]) |
|---|
| 3938 | |
|---|
| 3939 | all_roots.sort() |
|---|
| 3940 | |
|---|
| 3941 | ok = True |
|---|
| 3942 | |
|---|
| 3943 | target_widths = [None] * len(all_roots) |
|---|
| 3944 | |
|---|
| 3945 | |
|---|
| 3946 | if max_diameter is not None: |
|---|
| 3947 | # Check to make sure that no intervals are too wide. |
|---|
| 3948 | |
|---|
| 3949 | # We use half_diameter, because if we ended up with a rational |
|---|
| 3950 | # interval that was exactly max_diameter, we might not |
|---|
| 3951 | # be able to coerce it into an interval small enough. |
|---|
| 3952 | half_diameter = max_diameter/2 |
|---|
| 3953 | |
|---|
| 3954 | for i in range(len(all_roots)): |
|---|
| 3955 | root = all_roots[i][0] |
|---|
| 3956 | if (root[0] <= 0) and (root[1] >= 0): |
|---|
| 3957 | cur_diam = root[1] - root[0] |
|---|
| 3958 | if cur_diam > half_diameter: |
|---|
| 3959 | target_widths[i] = half_diameter |
|---|
| 3960 | ok = False |
|---|
| 3961 | else: |
|---|
| 3962 | cur_diam = (root[1] - root[0]) / abs((root[0] + root[1]) / 2) |
|---|
| 3963 | if cur_diam > half_diameter: |
|---|
| 3964 | target_widths[i] = (root[1] - root[0]) / cur_diam * half_diameter |
|---|
| 3965 | ok = False |
|---|
| 3966 | |
|---|
| 3967 | |
|---|
| 3968 | for i in range(len(all_roots) - 1): |
|---|
| 3969 | # Check to be sure that all intervals are disjoint. |
|---|
| 3970 | if all_roots[i][0][1] >= all_roots[i+1][0][0]: |
|---|
| 3971 | ok = False |
|---|
| 3972 | cur_width = max(all_roots[i+1][0][1] - all_roots[i+1][0][0], all_roots[i][0][1] - all_roots[i][0][0]) |
|---|
| 3973 | target_width = cur_width/16 |
|---|
| 3974 | target_widths[i] = target_width |
|---|
| 3975 | target_widths[i+1] = target_width |
|---|
| 3976 | |
|---|
| 3977 | for i in range(len(all_roots)): |
|---|
| 3978 | if target_widths[i] is not None: |
|---|
| 3979 | root = all_roots[i][0] |
|---|
| 3980 | oc = all_roots[i][3] |
|---|
| 3981 | target_region = (root[0], root[0] + target_widths[i]) |
|---|
| 3982 | if target_region[0] <= 0 and target_region[1] >= 0: |
|---|
| 3983 | target_region = (root[1] - target_widths[i], root[1]) |
|---|
| 3984 | |
|---|
| 3985 | ocean_target = oc.mapping.to_ocean(target_region) |
|---|
| 3986 | oc.reset_root_width(all_roots[i][4], ocean_target[1] - ocean_target[0]) |
|---|
| 3987 | |
|---|
| 3988 | if ok: break |
|---|
| 3989 | |
|---|
| 3990 | for (oc, factor, exp) in oceans: oc.find_roots() |
|---|
| 3991 | |
|---|
| 3992 | if do_logging: |
|---|
| 3993 | return ctx, all_roots |
|---|
| 3994 | |
|---|
| 3995 | if retval=='rational': |
|---|
| 3996 | return [(r[0], r[2]) for r in all_roots] |
|---|
| 3997 | |
|---|
| 3998 | for i in range(1000): |
|---|
| 3999 | intv_bits = 53 << i |
|---|
| 4000 | intv_fld = RealIntervalField(intv_bits) |
|---|
| 4001 | intv_roots = [(intv_fld(r[0]), r[1], r[2], r[3], r[4]) for r in all_roots] |
|---|
| 4002 | ok = True |
|---|
| 4003 | |
|---|
| 4004 | if max_diameter is not None: |
|---|
| 4005 | for rt in intv_roots: |
|---|
| 4006 | if rt[0].diameter() > max_diameter: |
|---|
| 4007 | ok = False |
|---|
| 4008 | |
|---|
| 4009 | for j in range(len(intv_roots) - 1): |
|---|
| 4010 | # The following line should work, but does not due to a Cython |
|---|
| 4011 | # bug (it calls PyObject_Cmp() for comparison operators, |
|---|
| 4012 | # instead of PyObject_RichCompare()). |
|---|
| 4013 | |
|---|
| 4014 | # if not (intv_roots[j][0] < intv_roots[j+1][0]): |
|---|
| 4015 | |
|---|
| 4016 | if not (intv_roots[j][0].upper() < intv_roots[j+1][0].lower()): |
|---|
| 4017 | ok = False |
|---|
| 4018 | |
|---|
| 4019 | if ok: |
|---|
| 4020 | break |
|---|
| 4021 | |
|---|
| 4022 | if retval=='interval': |
|---|
| 4023 | return [(r[0], r[2]) for r in intv_roots] |
|---|
| 4024 | |
|---|
| 4025 | if retval=='algebraic_real': |
|---|
| 4026 | return [(AA.polynomial_root(r[1], r[0]), r[2]) for r in intv_roots] |
|---|
| 4027 | |
|---|
| 4028 | raise ValueError, "Illegal retval parameter " + retval |
|---|
| 4029 | |
|---|
| 4030 | |
|---|
| 4031 | def scale_intvec_var(Vector_integer_dense c, k): |
|---|
| 4032 | """ |
|---|
| 4033 | Given a vector of integers c of length n+1, and a rational |
|---|
| 4034 | k == kn / kd, multiplies each element c[i] by (kd^i)*(kn^(n-i)). |
|---|
| 4035 | |
|---|
| 4036 | Modifies the input vector; has no return value. |
|---|
| 4037 | |
|---|
| 4038 | EXAMPLES: |
|---|
| 4039 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4040 | sage: v = vector(ZZ, [1, 1, 1, 1]) |
|---|
| 4041 | sage: scale_intvec_var(v, 3/4) |
|---|
| 4042 | sage: v |
|---|
| 4043 | (64, 48, 36, 27) |
|---|
| 4044 | """ |
|---|
| 4045 | |
|---|
| 4046 | kn = numerator(k) |
|---|
| 4047 | kd = denominator(k) |
|---|
| 4048 | |
|---|
| 4049 | # XXX could use direct mpz calls for more speed |
|---|
| 4050 | cdef Integer factor = Integer(kd) ** (len(c) - 1) |
|---|
| 4051 | |
|---|
| 4052 | cdef int i |
|---|
| 4053 | for i from 0 <= i < len(c): |
|---|
| 4054 | c[i] = c[i] * factor |
|---|
| 4055 | factor = (factor * kn) // kd |
|---|
| 4056 | |
|---|
| 4057 | def taylor_shift1_intvec(Vector_integer_dense c): |
|---|
| 4058 | """ |
|---|
| 4059 | Given a vector of integers c of length d+1, representing the |
|---|
| 4060 | coefficients of a degree-d polynomial p, modify the vector |
|---|
| 4061 | to perform a Taylor shift by 1 (that is, p becomes p(x+1)). |
|---|
| 4062 | |
|---|
| 4063 | This is the straightforward algorithm, which is not asymptotically |
|---|
| 4064 | optimal. |
|---|
| 4065 | |
|---|
| 4066 | Modifies the input vector; has no return value. |
|---|
| 4067 | |
|---|
| 4068 | EXAMPLES: |
|---|
| 4069 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4070 | sage: x = polygen(ZZ) |
|---|
| 4071 | sage: p = (x-1)*(x-2)*(x-3) |
|---|
| 4072 | sage: v = vector(ZZ, p.list()) |
|---|
| 4073 | sage: p, v |
|---|
| 4074 | (x^3 - 6*x^2 + 11*x - 6, (-6, 11, -6, 1)) |
|---|
| 4075 | sage: taylor_shift1_intvec(v) |
|---|
| 4076 | sage: p(x+1), v |
|---|
| 4077 | (x^3 - 3*x^2 + 2*x, (0, 2, -3, 1)) |
|---|
| 4078 | """ |
|---|
| 4079 | cdef int degree = len(c) - 1 |
|---|
| 4080 | |
|---|
| 4081 | cdef int i, k |
|---|
| 4082 | for i from 1 <= i <= degree: |
|---|
| 4083 | for k from degree-i <= k < degree: |
|---|
| 4084 | mpz_add(c._entries[k], c._entries[k], c._entries[k+1]) |
|---|
| 4085 | |
|---|
| 4086 | def reverse_intvec(Vector_integer_dense c): |
|---|
| 4087 | """ |
|---|
| 4088 | Given a vector of integers, reverse the vector (like the reverse() |
|---|
| 4089 | method on lists). |
|---|
| 4090 | |
|---|
| 4091 | Modifies the input vector; has no return value. |
|---|
| 4092 | |
|---|
| 4093 | EXAMPLES: |
|---|
| 4094 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4095 | sage: v = vector(ZZ, [1, 2, 3, 4]); v |
|---|
| 4096 | (1, 2, 3, 4) |
|---|
| 4097 | sage: reverse_intvec(v) |
|---|
| 4098 | sage: v |
|---|
| 4099 | (4, 3, 2, 1) |
|---|
| 4100 | """ |
|---|
| 4101 | cdef int i |
|---|
| 4102 | cdef int c_len = len(c) |
|---|
| 4103 | for i from 0 <= i < c_len // 2: |
|---|
| 4104 | mpz_swap(c._entries[i], c._entries[c_len - 1 - i]) |
|---|
| 4105 | |
|---|
| 4106 | realfield_rndu_cache = {} |
|---|
| 4107 | |
|---|
| 4108 | def get_realfield_rndu(n): |
|---|
| 4109 | """ |
|---|
| 4110 | A simple cache for RealField fields (with rounding set to |
|---|
| 4111 | round-to-positive-infinity). |
|---|
| 4112 | |
|---|
| 4113 | EXAMPLES: |
|---|
| 4114 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4115 | sage: get_realfield_rndu(20) |
|---|
| 4116 | Real Field with 20 bits of precision and rounding RNDU |
|---|
| 4117 | sage: get_realfield_rndu(53) |
|---|
| 4118 | Real Field with 53 bits of precision and rounding RNDU |
|---|
| 4119 | sage: get_realfield_rndu(20) |
|---|
| 4120 | Real Field with 20 bits of precision and rounding RNDU |
|---|
| 4121 | """ |
|---|
| 4122 | try: |
|---|
| 4123 | return realfield_rndu_cache[n] |
|---|
| 4124 | except KeyError: |
|---|
| 4125 | fld = RealField(n, rnd='RNDU') |
|---|
| 4126 | realfield_rndu_cache[n] = fld |
|---|
| 4127 | return fld |
|---|
| 4128 | |
|---|
| 4129 | cdef class context: |
|---|
| 4130 | """ |
|---|
| 4131 | A simple context class, which is passed through parts of the |
|---|
| 4132 | real root isolation algorithm to avoid global variables. |
|---|
| 4133 | |
|---|
| 4134 | Holds logging information, a random number generator, and |
|---|
| 4135 | the target machine wordsize. |
|---|
| 4136 | """ |
|---|
| 4137 | |
|---|
| 4138 | def __init__(self, do_logging, seed, wordsize): |
|---|
| 4139 | """ |
|---|
| 4140 | Initialize a context class. |
|---|
| 4141 | """ |
|---|
| 4142 | self.seed = seed # saved to make context printable |
|---|
| 4143 | self.random = Random() |
|---|
| 4144 | self.random.seed(seed) |
|---|
| 4145 | self.do_logging = do_logging |
|---|
| 4146 | self.wordsize = wordsize |
|---|
| 4147 | self.dc_log = [] |
|---|
| 4148 | self.be_log = [] |
|---|
| 4149 | |
|---|
| 4150 | def __repr__(self): |
|---|
| 4151 | """ |
|---|
| 4152 | Return a short summary of this context. |
|---|
| 4153 | |
|---|
| 4154 | EXAMPLES: |
|---|
| 4155 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4156 | sage: mk_context() |
|---|
| 4157 | root isolation context: seed=0 |
|---|
| 4158 | sage: mk_context(do_logging=True, seed=37, wordsize=64) |
|---|
| 4159 | root isolation context: seed=37; do_logging=True; wordsize=64 |
|---|
| 4160 | """ |
|---|
| 4161 | |
|---|
| 4162 | s = "root isolation context: seed=%d" % self.seed |
|---|
| 4163 | if self.do_logging: |
|---|
| 4164 | s = s + "; do_logging=True" |
|---|
| 4165 | if self.wordsize != 32: |
|---|
| 4166 | s = s + "; wordsize=%d" % self.wordsize |
|---|
| 4167 | return s |
|---|
| 4168 | |
|---|
| 4169 | cdef void dc_log_append(self, x): |
|---|
| 4170 | """ |
|---|
| 4171 | Optional logging for the root isolation algorithm. |
|---|
| 4172 | """ |
|---|
| 4173 | if self.do_logging: |
|---|
| 4174 | self.dc_log.append(x) |
|---|
| 4175 | |
|---|
| 4176 | cdef void be_log_append(self, x): |
|---|
| 4177 | """ |
|---|
| 4178 | Optional logging for degree reduction in the root isolation algorithm. |
|---|
| 4179 | """ |
|---|
| 4180 | if self.do_logging: |
|---|
| 4181 | self.be_log.append(x) |
|---|
| 4182 | |
|---|
| 4183 | def get_dc_log(self): |
|---|
| 4184 | return self.dc_log |
|---|
| 4185 | |
|---|
| 4186 | def get_be_log(self): |
|---|
| 4187 | return self.be_log |
|---|
| 4188 | |
|---|
| 4189 | def mk_context(do_logging=False, seed=0, wordsize=32): |
|---|
| 4190 | """ |
|---|
| 4191 | A simple wrapper for creating context objects with coercions, |
|---|
| 4192 | defaults, etc. |
|---|
| 4193 | |
|---|
| 4194 | For use in doctests. |
|---|
| 4195 | |
|---|
| 4196 | EXAMPLES: |
|---|
| 4197 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4198 | sage: mk_context(do_logging=True, seed=3, wordsize=64) |
|---|
| 4199 | root isolation context: seed=3; do_logging=True; wordsize=64 |
|---|
| 4200 | """ |
|---|
| 4201 | return context(do_logging, seed, wordsize) |
|---|
| 4202 | |
|---|
| 4203 | def to_bernstein(p, low=0, high=1, degree=None): |
|---|
| 4204 | """ |
|---|
| 4205 | Given a polynomial p with integer coefficients, and rational |
|---|
| 4206 | bounds low and high, compute the exact rational Bernstein |
|---|
| 4207 | coefficients of p over the region [low .. high]. The optional |
|---|
| 4208 | parameter degree can be used to give a formal degree higher than |
|---|
| 4209 | the actual degree. |
|---|
| 4210 | |
|---|
| 4211 | The return value is a pair (c, scale); c represents the same |
|---|
| 4212 | polynomial as p*scale. (If you only care about the roots of |
|---|
| 4213 | the polynomial, then of course scale can be ignored.) |
|---|
| 4214 | |
|---|
| 4215 | EXAMPLES: |
|---|
| 4216 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4217 | sage: x = polygen(ZZ) |
|---|
| 4218 | sage: to_bernstein(x) |
|---|
| 4219 | ([0, 1], 1) |
|---|
| 4220 | sage: to_bernstein(x, degree=5) |
|---|
| 4221 | ([0, 1/5, 2/5, 3/5, 4/5, 1], 1) |
|---|
| 4222 | sage: to_bernstein(x^3 + x^2 - x - 1, low=-3, high=3) |
|---|
| 4223 | ([-16, 24, -32, 32], 1) |
|---|
| 4224 | sage: to_bernstein(x^3 + x^2 - x - 1, low=3, high=22/7) |
|---|
| 4225 | ([296352, 310464, 325206, 340605], 9261) |
|---|
| 4226 | """ |
|---|
| 4227 | |
|---|
| 4228 | if degree is None: |
|---|
| 4229 | degree = p.degree() |
|---|
| 4230 | elif degree < p.degree(): |
|---|
| 4231 | raise ValueError, 'Bernstein degree must be at least polynomial degree' |
|---|
| 4232 | vs = ZZ ** (degree + 1) |
|---|
| 4233 | c = vs(0) |
|---|
| 4234 | for i in range(0, p.degree() + 1): |
|---|
| 4235 | c[i] = p[i] |
|---|
| 4236 | scale = ZZ(1) |
|---|
| 4237 | if low == 0: |
|---|
| 4238 | scale_intvec_var(c, high) |
|---|
| 4239 | scale = denominator(high) ** degree |
|---|
| 4240 | else: |
|---|
| 4241 | scale_intvec_var(c, low) |
|---|
| 4242 | scale = denominator(low) ** degree |
|---|
| 4243 | taylor_shift1_intvec(c) |
|---|
| 4244 | scv = QQ(high - low) / low |
|---|
| 4245 | scale_intvec_var(c, scv) |
|---|
| 4246 | scale = scale * denominator(scv) ** degree |
|---|
| 4247 | reverse_intvec(c) |
|---|
| 4248 | taylor_shift1_intvec(c) |
|---|
| 4249 | reverse_intvec(c) |
|---|
| 4250 | return ([c[k] / binomial(degree, k) for k in range(0, degree+1)], scale) |
|---|
| 4251 | |
|---|
| 4252 | def to_bernstein_warp(p): |
|---|
| 4253 | """ |
|---|
| 4254 | Given a polynomial p with rational coefficients, compute the |
|---|
| 4255 | exact rational Bernstein coefficients of p(x/(x+1)). |
|---|
| 4256 | |
|---|
| 4257 | EXAMPLES: |
|---|
| 4258 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4259 | sage: x = polygen(ZZ) |
|---|
| 4260 | sage: to_bernstein_warp(1 + x + x^2 + x^3 + x^4 + x^5) |
|---|
| 4261 | [1, 1/5, 1/10, 1/10, 1/5, 1] |
|---|
| 4262 | """ |
|---|
| 4263 | |
|---|
| 4264 | c = p.list() |
|---|
| 4265 | |
|---|
| 4266 | for i in range(len(c)): |
|---|
| 4267 | c[i] = c[i] / binomial(len(c) - 1, i) |
|---|
| 4268 | |
|---|
| 4269 | return c |
|---|
| 4270 | |
|---|
| 4271 | def bernstein_expand(Vector_integer_dense c, int d2): |
|---|
| 4272 | """ |
|---|
| 4273 | Given an integer vector representing a Bernstein polynomial p, and |
|---|
| 4274 | a degree d2, compute the representation of p as a Bernstein |
|---|
| 4275 | polynomial of formal degree d2. |
|---|
| 4276 | |
|---|
| 4277 | This is similar to multiplying by the result of bernstein_up, but |
|---|
| 4278 | should be faster for large d2 (this has about the same number of |
|---|
| 4279 | multiplies, but in this version all the multiplies are by single |
|---|
| 4280 | machine words). |
|---|
| 4281 | |
|---|
| 4282 | Returns a pair consisting of the expanded polynomial, and the maximum |
|---|
| 4283 | error E. (So if an element of the returned polynomial is a, and the |
|---|
| 4284 | true value of that coefficient is b, then a <= b < a + E.) |
|---|
| 4285 | |
|---|
| 4286 | EXAMPLES: |
|---|
| 4287 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4288 | sage: c = vector(ZZ, [1000, 2000, -3000]) |
|---|
| 4289 | sage: bernstein_expand(c, 3) |
|---|
| 4290 | ((1000, 1666, 333, -3000), 1) |
|---|
| 4291 | sage: bernstein_expand(c, 4) |
|---|
| 4292 | ((1000, 1500, 1000, -500, -3000), 1) |
|---|
| 4293 | sage: bernstein_expand(c, 20) |
|---|
| 4294 | ((1000, 1100, 1168, 1205, 1210, 1184, 1126, 1036, 915, 763, 578, 363, 115, -164, -474, -816, -1190, -1595, -2032, -2500, -3000), 1) |
|---|
| 4295 | """ |
|---|
| 4296 | cdef int d1 = len(c)-1 |
|---|
| 4297 | |
|---|
| 4298 | vs = FreeModule(ZZ, d2+1) |
|---|
| 4299 | |
|---|
| 4300 | cdef Vector_integer_dense c2 = vs(0) |
|---|
| 4301 | |
|---|
| 4302 | cdef int i, j |
|---|
| 4303 | |
|---|
| 4304 | cdef int ndivides = 0 |
|---|
| 4305 | |
|---|
| 4306 | cdef mpz_t tmp |
|---|
| 4307 | cdef mpz_t divisor |
|---|
| 4308 | |
|---|
| 4309 | mpz_init(tmp) |
|---|
| 4310 | mpz_init_set_ui(divisor, 1) |
|---|
| 4311 | |
|---|
| 4312 | # XXX do experimentation here on how to decide when to divide |
|---|
| 4313 | cdef int max_bits = max_bitsize_intvec(c) / 2 |
|---|
| 4314 | if max_bits < 64: max_bits = 64 |
|---|
| 4315 | |
|---|
| 4316 | for i from 0 <= i <= d1: |
|---|
| 4317 | mpz_set(c2._entries[i], c._entries[i]) |
|---|
| 4318 | |
|---|
| 4319 | for i from d1 <= i < d2: |
|---|
| 4320 | for j from i >= j >= 0: |
|---|
| 4321 | mpz_addmul_ui(c2._entries[j+1], c2._entries[j], j+1) |
|---|
| 4322 | |
|---|
| 4323 | mpz_mul_ui(c2._entries[j], c2._entries[j], i+1-j) |
|---|
| 4324 | |
|---|
| 4325 | mpz_mul_ui(divisor, divisor, i+1) |
|---|
| 4326 | |
|---|
| 4327 | if i == d2-1 or mpz_sizeinbase(divisor, 2) > max_bits: |
|---|
| 4328 | for j from 0 <= j <= i+1: |
|---|
| 4329 | mpz_fdiv_q(c2._entries[j], c2._entries[j], divisor) |
|---|
| 4330 | mpz_set_ui(divisor, 1) |
|---|
| 4331 | ndivides = ndivides + 1 |
|---|
| 4332 | |
|---|
| 4333 | mpz_clear(tmp) |
|---|
| 4334 | mpz_clear(divisor) |
|---|
| 4335 | |
|---|
| 4336 | return (c2, ndivides) |
|---|
| 4337 | |
|---|
| 4338 | cdef int max_bitsize_intvec(Vector_integer_dense b): |
|---|
| 4339 | """ |
|---|
| 4340 | Given an integer vector, find the approximate log2 of the maximum |
|---|
| 4341 | of the absolute values of the elements. |
|---|
| 4342 | |
|---|
| 4343 | EXAMPLES: |
|---|
| 4344 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4345 | sage: max_bitsize_intvec_doctest(vector(ZZ, [1, 2, 3, 1024])) |
|---|
| 4346 | 11 |
|---|
| 4347 | """ |
|---|
| 4348 | cdef int max_bits = 0 |
|---|
| 4349 | cdef int i |
|---|
| 4350 | cdef int size |
|---|
| 4351 | |
|---|
| 4352 | for i from 0 <= i < len(b): |
|---|
| 4353 | size = mpz_sizeinbase(b._entries[i], 2) |
|---|
| 4354 | if size > max_bits: max_bits = size |
|---|
| 4355 | |
|---|
| 4356 | return max_bits |
|---|
| 4357 | |
|---|
| 4358 | def max_bitsize_intvec_doctest(b): |
|---|
| 4359 | return max_bitsize_intvec(b) |
|---|
| 4360 | |
|---|
| 4361 | def dprod_imatrow_vec(Matrix_integer_dense m, Vector_integer_dense v, int k): |
|---|
| 4362 | """ |
|---|
| 4363 | Computes the dot product of row k of the matrix m with the vector v |
|---|
| 4364 | (that is, compute one element of the product m*v). |
|---|
| 4365 | |
|---|
| 4366 | If v has more elements than m has columns, then elements of v are |
|---|
| 4367 | selected using subsample_vec. |
|---|
| 4368 | |
|---|
| 4369 | EXAMPLES: |
|---|
| 4370 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4371 | sage: m = matrix(3, range(9)) |
|---|
| 4372 | sage: dprod_imatrow_vec(m, vector(ZZ, [1, 0, 0, 0]), 1) |
|---|
| 4373 | 0 |
|---|
| 4374 | sage: dprod_imatrow_vec(m, vector(ZZ, [0, 1, 0, 0]), 1) |
|---|
| 4375 | 3 |
|---|
| 4376 | sage: dprod_imatrow_vec(m, vector(ZZ, [0, 0, 1, 0]), 1) |
|---|
| 4377 | 4 |
|---|
| 4378 | sage: dprod_imatrow_vec(m, vector(ZZ, [0, 0, 0, 1]), 1) |
|---|
| 4379 | 5 |
|---|
| 4380 | sage: dprod_imatrow_vec(m, vector(ZZ, [1, 0, 0]), 1) |
|---|
| 4381 | 3 |
|---|
| 4382 | sage: dprod_imatrow_vec(m, vector(ZZ, [0, 1, 0]), 1) |
|---|
| 4383 | 4 |
|---|
| 4384 | sage: dprod_imatrow_vec(m, vector(ZZ, [0, 0, 1]), 1) |
|---|
| 4385 | 5 |
|---|
| 4386 | sage: dprod_imatrow_vec(m, vector(ZZ, [1, 2, 3]), 1) |
|---|
| 4387 | 26 |
|---|
| 4388 | """ |
|---|
| 4389 | |
|---|
| 4390 | assert(0 <= k < m.nrows()) |
|---|
| 4391 | assert(m.ncols() <= len(v)) |
|---|
| 4392 | |
|---|
| 4393 | cdef Integer sum = Integer(0) |
|---|
| 4394 | |
|---|
| 4395 | cdef mpz_t tmp |
|---|
| 4396 | |
|---|
| 4397 | cdef int msize = m.ncols() |
|---|
| 4398 | cdef int vsize = len(v) |
|---|
| 4399 | cdef int ra |
|---|
| 4400 | cdef int a |
|---|
| 4401 | |
|---|
| 4402 | for a from 0 <= a < msize: |
|---|
| 4403 | ra = subsample_vec(a, msize, vsize) |
|---|
| 4404 | mpz_addmul(sum.value, m._matrix[k][a], v._entries[ra]) |
|---|
| 4405 | |
|---|
| 4406 | return sum |
|---|
| 4407 | |
|---|
| 4408 | def min_max_delta_intvec(Vector_integer_dense a, Vector_integer_dense b): |
|---|
| 4409 | """ |
|---|
| 4410 | Given two integer vectors a and b (of equal, nonzero length), return |
|---|
| 4411 | a pair of the minimum and maximum values taken on by a[i] - b[i]. |
|---|
| 4412 | |
|---|
| 4413 | EXAMPLES: |
|---|
| 4414 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4415 | sage: a = vector(ZZ, [10, -30]) |
|---|
| 4416 | sage: b = vector(ZZ, [15, -60]) |
|---|
| 4417 | sage: min_max_delta_intvec(a, b) |
|---|
| 4418 | (30, -5) |
|---|
| 4419 | """ |
|---|
| 4420 | |
|---|
| 4421 | assert(len(a) == len(b)) |
|---|
| 4422 | assert(len(a) > 0) |
|---|
| 4423 | |
|---|
| 4424 | cdef Integer max = Integer() |
|---|
| 4425 | cdef Integer min = Integer() |
|---|
| 4426 | |
|---|
| 4427 | cdef mpz_t tmp |
|---|
| 4428 | mpz_init(tmp) |
|---|
| 4429 | |
|---|
| 4430 | cdef int i |
|---|
| 4431 | for i from 0 <= i < len(a): |
|---|
| 4432 | mpz_sub(tmp, a._entries[i], b._entries[i]) |
|---|
| 4433 | if i == 0 or mpz_cmp(tmp, max.value) > 0: |
|---|
| 4434 | mpz_set(max.value, tmp) |
|---|
| 4435 | if i == 0 or mpz_cmp(tmp, min.value) < 0: |
|---|
| 4436 | mpz_set(min.value, tmp) |
|---|
| 4437 | |
|---|
| 4438 | mpz_clear(tmp) |
|---|
| 4439 | |
|---|
| 4440 | return (max, min) |
|---|
| 4441 | |
|---|
| 4442 | def min_max_diff_intvec(Vector_integer_dense b): |
|---|
| 4443 | """ |
|---|
| 4444 | Given an integer vector b = (b0, ..., bn), compute the |
|---|
| 4445 | minimum and maximum values of b_{j+1} - b_j. |
|---|
| 4446 | |
|---|
| 4447 | EXAMPLES: |
|---|
| 4448 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4449 | sage: min_max_diff_intvec(vector(ZZ, [1, 7, -2])) |
|---|
| 4450 | (-9, 6) |
|---|
| 4451 | """ |
|---|
| 4452 | l = len(b) |
|---|
| 4453 | assert(l > 1) |
|---|
| 4454 | |
|---|
| 4455 | cdef Integer min_diff = b[1] - b[0] |
|---|
| 4456 | cdef Integer max_diff = Integer() |
|---|
| 4457 | |
|---|
| 4458 | cdef Integer diff = Integer() |
|---|
| 4459 | |
|---|
| 4460 | mpz_set(max_diff.value, min_diff.value) |
|---|
| 4461 | |
|---|
| 4462 | for i from 1 <= i < l-1: |
|---|
| 4463 | mpz_sub(diff.value, b._entries[i+1], b._entries[i]) |
|---|
| 4464 | if mpz_cmp(diff.value, max_diff.value) > 0: |
|---|
| 4465 | mpz_set(max_diff.value, diff.value) |
|---|
| 4466 | if mpz_cmp(diff.value, min_diff.value) < 0: |
|---|
| 4467 | mpz_set(min_diff.value, diff.value) |
|---|
| 4468 | |
|---|
| 4469 | return (min_diff, max_diff) |
|---|
| 4470 | |
|---|
| 4471 | def min_max_diff_doublevec(RealDoubleVectorSpaceElement c): |
|---|
| 4472 | """ |
|---|
| 4473 | Given a floating-point vector b = (b0, ..., bn), compute the |
|---|
| 4474 | minimum and maximum values of b_{j+1} - b_j. |
|---|
| 4475 | |
|---|
| 4476 | EXAMPLES: |
|---|
| 4477 | sage: from sage.rings.polynomial.real_roots import * |
|---|
| 4478 | sage: min_max_diff_doublevec(vector(RDF, [1, 7, -2])) |
|---|
| 4479 | (-9.0, 6.0) |
|---|
| 4480 | """ |
|---|
| 4481 | assert(c.v.stride == 1) |
|---|
| 4482 | |
|---|
| 4483 | cdef double* cd = c.v.data |
|---|
| 4484 | |
|---|
| 4485 | l = len(c) |
|---|
| 4486 | assert(l > 1) |
|---|
| 4487 | |
|---|
| 4488 | cdef double min_diff = cd[1] - cd[0] |
|---|
| 4489 | cdef double max_diff = min_diff |
|---|
| 4490 | |
|---|
| 4491 | cdef double diff |
|---|
| 4492 | |
|---|
| 4493 | for i from 1 <= i < l-1: |
|---|
| 4494 | diff = cd[i+1] - cd[i] |
|---|
| 4495 | if diff < min_diff: |
|---|
| 4496 | min_diff = diff |
|---|
| 4497 | if diff > max_diff: |
|---|
| 4498 | max_diff = diff |
|---|
| 4499 | |
|---|
| 4500 | return (min_diff, max_diff) |
|---|
| 4501 | |
|---|