001/* 002 * $Id: RealRootsAbstract.java 4961 2014-10-17 18:59:39Z kredel $ 003 */ 004 005package edu.jas.root; 006 007 008import java.util.ArrayList; 009import java.util.List; 010 011import org.apache.log4j.Logger; 012 013import edu.jas.arith.BigDecimal; 014import edu.jas.arith.BigInteger; 015import edu.jas.arith.BigRational; 016import edu.jas.arith.Rational; 017import edu.jas.poly.GenPolynomial; 018import edu.jas.poly.GenPolynomialRing; 019import edu.jas.poly.PolyUtil; 020import edu.jas.structure.RingElem; 021import edu.jas.structure.RingFactory; 022import edu.jas.structure.UnaryFunctor; 023 024 025/** 026 * Real roots abstract class. 027 * @param <C> coefficient type. 028 * @author Heinz Kredel 029 */ 030public abstract class RealRootsAbstract<C extends RingElem<C> & Rational> implements RealRoots<C> { 031 032 033 private static final Logger logger = Logger.getLogger(RealRootsAbstract.class); 034 035 036 //private static boolean debug = logger.isDebugEnabled(); 037 038 039 /** 040 * Real root bound. With f(M) * f(-M) != 0. 041 * @param f univariate polynomial. 042 * @return M such that -M < root(f) < M. 043 */ 044 public C realRootBound(GenPolynomial<C> f) { 045 if (f == null) { 046 return null; 047 } 048 RingFactory<C> cfac = f.ring.coFac; 049 C M = cfac.getONE(); 050 if (f.isZERO()) { 051 return M; 052 } 053 if (f.isConstant()) { 054 M = f.leadingBaseCoefficient().abs().sum(cfac.getONE()); 055 return M; 056 } 057 C a = f.leadingBaseCoefficient().abs(); 058 for (C c : f.getMap().values()) { 059 C d = c.abs().divide(a); 060 if (M.compareTo(d) < 0) { 061 M = d; 062 } 063 } 064 // works also without this case, only for optimization 065 // to use integral number interval end points 066 // could be obsolete: can fail if real root is in interval [r,r+1] 067 // for too low precision or too big r, since r is approximation 068 /* 069 if (false&&(Object) M instanceof RealAlgebraicNumber) { 070 RealAlgebraicNumber Mr = (RealAlgebraicNumber) M; 071 BigRational r = Mr.magnitude(); 072 //logger.info("rational root bound: " + r); 073 BigInteger i = new BigInteger(r.numerator().divide(r.denominator())); 074 i = i.sum(BigInteger.ONE); 075 //logger.info("integer root bound: " + i); 076 //M = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); 077 M = cfac.fromInteger(i.getVal()); 078 M = M.sum(f.ring.coFac.getONE()); 079 logger.info("root bound: " + M); 080 //System.out.println("M = " + M); 081 return M; 082 } 083 */ 084 BigRational r = M.getRational(); 085 logger.info("rational root bound: " + r); 086 BigInteger i = new BigInteger(r.numerator().divide(r.denominator())); 087 i = i.sum(BigInteger.ONE); // ceiling 088 M = cfac.fromInteger(i.getVal()); 089 M = M.sum(f.ring.coFac.getONE()); 090 logger.info("integer root bound: " + M); 091 //System.out.println("M = " + M); 092 return M; 093 } 094 095 096 /** 097 * Magnitude bound. 098 * @param iv interval. 099 * @param f univariate polynomial. 100 * @return B such that |f(c)| < B for c in iv. 101 */ 102 @SuppressWarnings("cast") 103 public C magnitudeBound(Interval<C> iv, GenPolynomial<C> f) { 104 if (f == null) { 105 return null; 106 } 107 if (f.isZERO()) { 108 return f.ring.coFac.getONE(); 109 } 110 if (f.isConstant()) { 111 return f.leadingBaseCoefficient().abs(); 112 } 113 GenPolynomial<C> fa = f.map(new UnaryFunctor<C, C>() { 114 115 116 public C eval(C a) { 117 return a.abs(); 118 } 119 }); 120 //System.out.println("fa = " + fa); 121 C M = iv.left.abs(); 122 if (M.compareTo(iv.right.abs()) < 0) { 123 M = iv.right.abs(); 124 } 125 //System.out.println("M = " + M); 126 RingFactory<C> cfac = f.ring.coFac; 127 C B = PolyUtil.<C> evaluateMain(cfac, fa, M); 128 // works also without this case, only for optimization 129 // to use rational number interval end points 130 // can fail if real root is in interval [r,r+1] 131 // for too low precision or too big r, since r is approximation 132 if ((Object) B instanceof RealAlgebraicNumber) { 133 RealAlgebraicNumber Br = (RealAlgebraicNumber) B; 134 BigRational r = Br.magnitude(); 135 B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); 136 } 137 //System.out.println("B = " + B); 138 return B; 139 } 140 141 142 /** 143 * Bi-section point. 144 * @param iv interval with f(left) * f(right) != 0. 145 * @param f univariate polynomial, non-zero. 146 * @return a point c in the interval iv such that f(c) != 0. 147 */ 148 public C bisectionPoint(Interval<C> iv, GenPolynomial<C> f) { 149 if (f == null) { 150 return null; 151 } 152 RingFactory<C> cfac = f.ring.coFac; 153 C two = cfac.fromInteger(2); 154 C c = iv.left.sum(iv.right); 155 c = c.divide(two); 156 if (f.isZERO() || f.isConstant()) { 157 return c; 158 } 159 C m = PolyUtil.<C> evaluateMain(cfac, f, c); 160 while (m.isZERO()) { 161 C d = iv.left.sum(c); 162 d = d.divide(two); 163 if (d.equals(c)) { 164 d = iv.right.sum(c); 165 d = d.divide(two); 166 if (d.equals(c)) { 167 throw new RuntimeException("should not happen " + iv); 168 } 169 } 170 c = d; 171 m = PolyUtil.<C> evaluateMain(cfac, f, c); 172 //System.out.println("c = " + c); 173 } 174 //System.out.println("c = " + c); 175 return c; 176 } 177 178 179 /** 180 * Isolating intervals for the real roots. 181 * @param f univariate polynomial. 182 * @return a list of isolating intervalls for the real roots of f. 183 */ 184 public abstract List<Interval<C>> realRoots(GenPolynomial<C> f); 185 186 187 /** 188 * Isolating intervals for the real roots. 189 * @param f univariate polynomial. 190 * @param eps requested intervals length. 191 * @return a list of isolating intervals v such that |v| < eps. 192 */ 193 public List<Interval<C>> realRoots(GenPolynomial<C> f, C eps) { 194 List<Interval<C>> iv = realRoots(f); 195 return refineIntervals(iv, f, eps); 196 } 197 198 199 /** 200 * Isolating intervals for the real roots. 201 * @param f univariate polynomial. 202 * @param eps requested intervals length. 203 * @return a list of isolating intervals v such that |v| < eps. 204 */ 205 public List<Interval<C>> realRoots(GenPolynomial<C> f, BigRational eps) { 206 C e = f.ring.coFac.parse(eps.toString()); 207 return realRoots(f, e); 208 } 209 210 211 /** 212 * Sign changes on interval bounds. 213 * @param iv root isolating interval with f(left) * f(right) != 0. 214 * @param f univariate polynomial. 215 * @return true if f(left) * f(right) < 0, else false 216 */ 217 public boolean signChange(Interval<C> iv, GenPolynomial<C> f) { 218 if (f == null) { 219 return false; 220 } 221 RingFactory<C> cfac = f.ring.coFac; 222 C l = PolyUtil.<C> evaluateMain(cfac, f, iv.left); 223 C r = PolyUtil.<C> evaluateMain(cfac, f, iv.right); 224 return l.signum() * r.signum() < 0; 225 } 226 227 228 /** 229 * Number of real roots in interval. 230 * @param iv interval with f(left) * f(right) != 0. 231 * @param f univariate polynomial. 232 * @return number of real roots of f in I. 233 */ 234 public abstract long realRootCount(Interval<C> iv, GenPolynomial<C> f); 235 236 237 /** 238 * Half interval. 239 * @param iv root isolating interval with f(left) * f(right) < 0. 240 * @param f univariate polynomial, non-zero. 241 * @return a new interval v such that |v| < |iv|/2. 242 */ 243 public Interval<C> halfInterval(Interval<C> iv, GenPolynomial<C> f) { 244 if (f == null || f.isZERO()) { 245 return iv; 246 } 247 C len = iv.length(); 248 C two = len.factory().fromInteger(2); 249 C eps = len.divide(two); 250 return refineInterval(iv, f, eps); 251 } 252 253 254 /** 255 * Refine interval. 256 * @param iv root isolating interval with f(left) * f(right) < 0. 257 * @param f univariate polynomial, non-zero. 258 * @param eps requested interval length. 259 * @return a new interval v such that |v| < eps. 260 */ 261 public Interval<C> refineInterval(Interval<C> iv, GenPolynomial<C> f, C eps) { 262 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 263 return iv; 264 } 265 if (iv.length().compareTo(eps) < 0) { 266 return iv; 267 } 268 RingFactory<C> cfac = f.ring.coFac; 269 C two = cfac.fromInteger(2); 270 Interval<C> v = iv; 271 while (v.length().compareTo(eps) >= 0) { 272 C c = v.left.sum(v.right); 273 c = c.divide(two); 274 //System.out.println("c = " + c); 275 //c = RootUtil.<C>bisectionPoint(v,f); 276 if (PolyUtil.<C> evaluateMain(cfac, f, c).isZERO()) { 277 v = new Interval<C>(c, c); 278 break; 279 } 280 Interval<C> iv1 = new Interval<C>(v.left, c); 281 if (signChange(iv1, f)) { 282 v = iv1; 283 } else { 284 v = new Interval<C>(c, v.right); 285 } 286 } 287 return v; 288 } 289 290 291 /** 292 * Refine intervals. 293 * @param V list of isolating intervals with f(left) * f(right) < 0. 294 * @param f univariate polynomial, non-zero. 295 * @param eps requested intervals length. 296 * @return a list of new intervals v such that |v| < eps. 297 */ 298 public List<Interval<C>> refineIntervals(List<Interval<C>> V, GenPolynomial<C> f, C eps) { 299 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 300 return V; 301 } 302 List<Interval<C>> IV = new ArrayList<Interval<C>>(); 303 for (Interval<C> v : V) { 304 Interval<C> iv = refineInterval(v, f, eps); 305 IV.add(iv); 306 } 307 return IV; 308 } 309 310 311 /** 312 * Invariant interval for algebraic number sign. 313 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 314 * @param f univariate polynomial, non-zero. 315 * @param g univariate polynomial, gcd(f,g) == 1. 316 * @return v with v a new interval contained in iv such that g(v) != 0. 317 */ 318 public abstract Interval<C> invariantSignInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g); 319 320 321 /** 322 * Real algebraic number sign. 323 * @param iv root isolating interval for f, with f(left) * f(right) < 0, 324 * with iv such that g(iv) != 0. 325 * @param f univariate polynomial, non-zero. 326 * @param g univariate polynomial, gcd(f,g) == 1. 327 * @return sign(g(iv)) . 328 */ 329 public int realIntervalSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) { 330 if (g == null || g.isZERO()) { 331 return 0; 332 } 333 if (f == null || f.isZERO() || f.isConstant()) { 334 return g.signum(); 335 } 336 if (g.isConstant()) { 337 return g.signum(); 338 } 339 RingFactory<C> cfac = f.ring.coFac; 340 C c = iv.left.sum(iv.right); 341 c = c.divide(cfac.fromInteger(2)); 342 C ev = PolyUtil.<C> evaluateMain(cfac, g, c); 343 //System.out.println("ev = " + ev); 344 return ev.signum(); 345 } 346 347 348 /** 349 * Real algebraic number sign. 350 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 351 * @param f univariate polynomial, non-zero. 352 * @param g univariate polynomial, gcd(f,g) == 1. 353 * @return sign(g(v)), with v a new interval contained in iv such that g(v) 354 * != 0. 355 */ 356 public int realSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) { 357 if (g == null || g.isZERO()) { 358 return 0; 359 } 360 if (f == null || f.isZERO() || f.isConstant()) { 361 return g.signum(); 362 } 363 if (g.isConstant()) { 364 return g.signum(); 365 } 366 Interval<C> v = invariantSignInterval(iv, f, g); 367 return realIntervalSign(v, f, g); 368 } 369 370 371 /** 372 * Invariant interval for algebraic number magnitude. 373 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 374 * @param f univariate polynomial, non-zero. 375 * @param g univariate polynomial, gcd(f,g) == 1. 376 * @param eps length limit for interval length. 377 * @return v with v a new interval contained in iv such that |g(a) - g(b)| 378 * < eps for a, b in v in iv. 379 */ 380 public Interval<C> invariantMagnitudeInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, 381 C eps) { 382 Interval<C> v = iv; 383 if (g == null || g.isZERO()) { 384 return v; 385 } 386 if (g.isConstant()) { 387 return v; 388 } 389 if (f == null || f.isZERO() || f.isConstant()) { // ? 390 return v; 391 } 392 GenPolynomial<C> gp = PolyUtil.<C> baseDeriviative(g); 393 //System.out.println("g = " + g); 394 //System.out.println("gp = " + gp); 395 C B = magnitudeBound(iv, gp); 396 //System.out.println("B = " + B); 397 398 RingFactory<C> cfac = f.ring.coFac; 399 C two = cfac.fromInteger(2); 400 401 while (B.multiply(v.length()).compareTo(eps) >= 0) { 402 C c = v.left.sum(v.right); 403 c = c.divide(two); 404 Interval<C> im = new Interval<C>(c, v.right); 405 if (signChange(im, f)) { 406 v = im; 407 } else { 408 v = new Interval<C>(v.left, c); 409 } 410 //System.out.println("v = " + v.toDecimal()); 411 } 412 return v; 413 } 414 415 416 /** 417 * Real algebraic number magnitude. 418 * @param iv root isolating interval for f, with f(left) * f(right) < 0, 419 * with iv such that |g(a) - g(b)| < eps for a, b in iv. 420 * @param f univariate polynomial, non-zero. 421 * @param g univariate polynomial, gcd(f,g) == 1. 422 * @return g(iv) . 423 */ 424 public C realIntervalMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) { 425 if (g.isZERO() || g.isConstant()) { 426 return g.leadingBaseCoefficient(); 427 } 428 RingFactory<C> cfac = f.ring.coFac; 429 //if (false) { 430 // C c = iv.left.sum(iv.right); 431 // c = c.divide(cfac.fromInteger(2)); 432 // C ev = PolyUtil.<C> evaluateMain(cfac, g, c); 433 // return ev; 434 //} 435 C evl = PolyUtil.<C> evaluateMain(cfac, g, iv.left); 436 C evr = PolyUtil.<C> evaluateMain(cfac, g, iv.right); 437 C ev = evl; 438 if (evl.compareTo(evr) <= 0) { 439 ev = evr; 440 } 441 //System.out.println("ev = " + ev + ", evl = " + evl + ", evr = " + evr + ", iv = " + iv); 442 return ev; 443 } 444 445 446 /** 447 * Real algebraic number magnitude. 448 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 449 * @param f univariate polynomial, non-zero. 450 * @param g univariate polynomial, gcd(f,g) == 1. 451 * @param eps length limit for interval length. 452 * @return g(iv) . 453 */ 454 public C realMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, C eps) { 455 if (g.isZERO() || g.isConstant()) { 456 return g.leadingBaseCoefficient(); 457 } 458 Interval<C> v = invariantMagnitudeInterval(iv, f, g, eps); 459 return realIntervalMagnitude(v, f, g); 460 } 461 462 463 /** 464 * Approximate real root. 465 * @param iv real root isolating interval with f(left) * f(right) < 0. 466 * @param f univariate polynomial, non-zero. 467 * @param eps requested interval length. 468 * @return a decimal approximation d such that |d-v| < eps, for f(v) = 0, 469 * v real. 470 */ 471 public BigDecimal approximateRoot(Interval<C> iv, GenPolynomial<C> f, C eps) 472 throws NoConvergenceException { 473 if (iv == null) { 474 throw new IllegalArgumentException("null interval not allowed"); 475 } 476 BigDecimal d = iv.toDecimal(); 477 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 478 return d; 479 } 480 if (iv.length().compareTo(eps) < 0) { 481 return d; 482 } 483 BigDecimal left = new BigDecimal(iv.left.getRational()); 484 BigDecimal right = new BigDecimal(iv.right.getRational()); 485 BigRational reps = eps.getRational(); 486 BigDecimal e = new BigDecimal(reps); 487 BigDecimal q = new BigDecimal("0.25"); 488 //System.out.println("left = " + left); 489 //System.out.println("right = " + right); 490 e = e.multiply(d); // relative error 491 //System.out.println("e = " + e); 492 BigDecimal dc = BigDecimal.ONE; 493 // polynomials with decimal coefficients 494 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 495 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 496 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 497 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 498 499 // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n) 500 int i = 0; 501 final int MITER = 50; 502 int dir = 0; 503 while (i++ < MITER) { 504 BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, df, d); // f(d) 505 if (fx.isZERO()) { 506 return d; 507 } 508 BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, dfp, d); // f'(d) 509 if (fpx.isZERO()) { 510 throw new NoConvergenceException("zero deriviative should not happen"); 511 } 512 BigDecimal x = fx.divide(fpx); 513 BigDecimal dx = d.subtract(x); 514 //System.out.println("dx = " + dx + ", d = " + d); 515 if (d.subtract(dx).abs().compareTo(e) <= 0) { 516 return dx; 517 } 518 while (dx.compareTo(left) < 0 || dx.compareTo(right) > 0) { // dx < left: dx - left < 0 519 // dx > right: dx - right > 0 520 //System.out.println("trying to leave interval"); 521 if (i++ > MITER) { // dx > right: dx - right > 0 522 throw new NoConvergenceException("no convergence after " + i + " steps"); 523 } 524 if (i > MITER / 2 && dir == 0) { 525 BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); 526 d = sd; 527 x = sd.getZERO(); 528 logger.info("trying new random starting point " + d); 529 i = 0; 530 dir = 1; 531 } 532 if (i > MITER / 2 && dir == 1) { 533 BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); 534 d = sd; 535 x = sd.getZERO(); 536 logger.info("trying new random starting point " + d); 537 //i = 0; 538 dir = 2; // end 539 } 540 x = x.multiply(q); // x * 1/4 541 dx = d.subtract(x); 542 //System.out.println(" x = " + x); 543 //System.out.println("dx = " + dx); 544 } 545 d = dx; 546 } 547 throw new NoConvergenceException("no convergence after " + i + " steps"); 548 } 549 550 551 /** 552 * Approximate real roots. 553 * @param f univariate polynomial, non-zero. 554 * @param eps requested interval length. 555 * @return a list of decimal approximations d such that |d-v| < eps for 556 * all real v with f(v) = 0. 557 */ 558 public List<BigDecimal> approximateRoots(GenPolynomial<C> f, C eps) { 559 List<Interval<C>> iv = realRoots(f); 560 List<BigDecimal> roots = new ArrayList<BigDecimal>(iv.size()); 561 for (Interval<C> i : iv) { 562 BigDecimal r = null; //approximateRoot(i, f, eps); roots.add(r); 563 while (r == null) { 564 try { 565 r = approximateRoot(i, f, eps); 566 roots.add(r); 567 } catch (NoConvergenceException e) { 568 // fall back to exact algorithm 569 //System.out.println("" + e); 570 C len = i.length(); 571 len = len.divide(f.ring.coFac.fromInteger(1000)); 572 i = refineInterval(i, f, len); 573 logger.info("fall back rootRefinement = " + i); 574 } 575 } 576 } 577 return roots; 578 } 579 580 581 /** 582 * Test if x is an approximate real root. 583 * @param x approximate real root. 584 * @param f univariate polynomial, non-zero. 585 * @param eps requested interval length. 586 * @return true if x is a decimal approximation of a real v with f(v) = 0 587 * with |d-v| < eps, else false. 588 */ 589 public boolean isApproximateRoot(BigDecimal x, GenPolynomial<C> f, C eps) { 590 if (x == null) { 591 throw new IllegalArgumentException("null root not allowed"); 592 } 593 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 594 return true; 595 } 596 BigDecimal e = new BigDecimal(eps.getRational()); 597 e = e.multiply(new BigDecimal("1000")); // relax 598 BigDecimal dc = BigDecimal.ONE; 599 // polynomials with decimal coefficients 600 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 601 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 602 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 603 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 604 // 605 return isApproximateRoot(x, df, dfp, e); 606 } 607 608 609 /** 610 * Test if x is an approximate real root. 611 * @param x approximate real root. 612 * @param f univariate polynomial, non-zero. 613 * @param fp univariate polynomial, non-zero, deriviative of f. 614 * @param eps requested interval length. 615 * @return true if x is a decimal approximation of a real v with f(v) = 0 616 * with |d-v| < eps, else false. 617 */ 618 public boolean isApproximateRoot(BigDecimal x, GenPolynomial<BigDecimal> f, GenPolynomial<BigDecimal> fp, 619 BigDecimal eps) { 620 if (x == null) { 621 throw new IllegalArgumentException("null root not allowed"); 622 } 623 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 624 return true; 625 } 626 BigDecimal dc = BigDecimal.ONE; // only for clarity 627 // f(x) 628 BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, f, x); 629 //System.out.println("fx = " + fx); 630 if (fx.isZERO()) { 631 return true; 632 } 633 // f'(x) 634 BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, fp, x); // f'(d) 635 //System.out.println("fpx = " + fpx); 636 if (fpx.isZERO()) { 637 return false; 638 } 639 BigDecimal d = fx.divide(fpx); 640 if (d.isZERO()) { 641 return true; 642 } 643 if (d.abs().compareTo(eps) <= 0) { 644 return true; 645 } 646 System.out.println("x = " + x); 647 System.out.println("d = " + d); 648 return false; 649 } 650 651 652 /** 653 * Test if each x in R is an approximate real root. 654 * @param R ist of approximate real roots. 655 * @param f univariate polynomial, non-zero. 656 * @param eps requested interval length. 657 * @return true if each x in R is a decimal approximation of a real v with 658 * f(v) = 0 with |d-v| < eps, else false. 659 */ 660 public boolean isApproximateRoot(List<BigDecimal> R, GenPolynomial<C> f, C eps) { 661 if (R == null) { 662 throw new IllegalArgumentException("null root not allowed"); 663 } 664 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 665 return true; 666 } 667 BigDecimal e = new BigDecimal(eps.getRational()); 668 e = e.multiply(new BigDecimal("1000")); // relax 669 BigDecimal dc = BigDecimal.ONE; 670 // polynomials with decimal coefficients 671 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 672 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 673 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 674 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 675 for (BigDecimal x : R) { 676 if (!isApproximateRoot(x, df, dfp, e)) { 677 return false; 678 } 679 } 680 return true; 681 } 682 683}