001/* 002 * $Id: RealRootsAbstract.java 5872 2018-07-20 16:01:46Z kredel $ 003 */ 004 005package edu.jas.root; 006 007 008import java.util.ArrayList; 009import java.util.List; 010 011import org.apache.logging.log4j.Logger; 012import org.apache.logging.log4j.LogManager; 013 014import edu.jas.arith.BigDecimal; 015import edu.jas.arith.BigInteger; 016import edu.jas.arith.BigRational; 017import edu.jas.arith.Rational; 018import edu.jas.poly.GenPolynomial; 019import edu.jas.poly.GenPolynomialRing; 020import edu.jas.poly.PolyUtil; 021import edu.jas.structure.RingElem; 022import edu.jas.structure.RingFactory; 023import edu.jas.structure.UnaryFunctor; 024 025 026/** 027 * Real roots abstract class. 028 * @param <C> coefficient type. 029 * @author Heinz Kredel 030 */ 031public abstract class RealRootsAbstract<C extends RingElem<C> & Rational> implements RealRoots<C> { 032 033 034 private static final Logger logger = LogManager.getLogger(RealRootsAbstract.class); 035 036 037 //private static final boolean debug = logger.isDebugEnabled(); 038 039 040 /** 041 * Real root bound. With f(M) * f(-M) != 0. 042 * @param f univariate polynomial. 043 * @return M such that -M < root(f) < M. 044 */ 045 public C realRootBound(GenPolynomial<C> f) { 046 if (f == null) { 047 return null; 048 } 049 RingFactory<C> cfac = f.ring.coFac; 050 C M = cfac.getONE(); 051 if (f.isZERO()) { 052 return M; 053 } 054 if (f.isConstant()) { 055 M = f.leadingBaseCoefficient().abs().sum(cfac.getONE()); 056 return M; 057 } 058 C a = f.leadingBaseCoefficient().abs(); 059 for (C c : f.getMap().values()) { 060 C d = c.abs().divide(a); 061 if (M.compareTo(d) < 0) { 062 M = d; 063 } 064 } 065 // works also without this case, only for optimization 066 // to use integral number interval end points 067 // could be obsolete: can fail if real root is in interval [r,r+1] 068 // for too low precision or too big r, since r is approximation 069 /* 070 if (false&&(Object) M instanceof RealAlgebraicNumber) { 071 RealAlgebraicNumber Mr = (RealAlgebraicNumber) M; 072 BigRational r = Mr.magnitude(); 073 //logger.info("rational root bound: " + r); 074 BigInteger i = new BigInteger(r.numerator().divide(r.denominator())); 075 i = i.sum(BigInteger.ONE); 076 //logger.info("integer root bound: " + i); 077 //M = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); 078 M = cfac.fromInteger(i.getVal()); 079 M = M.sum(f.ring.coFac.getONE()); 080 logger.info("root bound: " + M); 081 //System.out.println("M = " + M); 082 return M; 083 } 084 */ 085 BigRational r = M.getRational(); 086 logger.info("rational root bound: " + r); 087 BigInteger i = new BigInteger(r.numerator().divide(r.denominator())); 088 i = i.sum(BigInteger.ONE); // ceiling 089 M = cfac.fromInteger(i.getVal()); 090 M = M.sum(f.ring.coFac.getONE()); 091 logger.info("integer root bound: " + M); 092 //System.out.println("M = " + M); 093 return M; 094 } 095 096 097 /** 098 * Magnitude bound. 099 * @param iv interval. 100 * @param f univariate polynomial. 101 * @return B such that |f(c)| < B for c in iv. 102 */ 103 @SuppressWarnings("cast") 104 public C magnitudeBound(Interval<C> iv, GenPolynomial<C> f) { 105 if (f == null) { 106 return null; 107 } 108 if (f.isZERO()) { 109 return f.ring.coFac.getONE(); 110 } 111 if (f.isConstant()) { 112 return f.leadingBaseCoefficient().abs(); 113 } 114 GenPolynomial<C> fa = f.map(new UnaryFunctor<C, C>() { 115 116 117 public C eval(C a) { 118 return a.abs(); 119 } 120 }); 121 //System.out.println("fa = " + fa); 122 C M = iv.left.abs(); 123 if (M.compareTo(iv.right.abs()) < 0) { 124 M = iv.right.abs(); 125 } 126 //System.out.println("M = " + M); 127 RingFactory<C> cfac = f.ring.coFac; 128 C B = PolyUtil.<C> evaluateMain(cfac, fa, M); 129 // works also without this case, only for optimization 130 // to use rational number interval end points 131 // can fail if real root is in interval [r,r+1] 132 // for too low precision or too big r, since r is approximation 133 if ((Object) B instanceof RealAlgebraicNumber) { 134 RealAlgebraicNumber Br = (RealAlgebraicNumber) B; 135 BigRational r = Br.magnitude(); 136 B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); 137 } 138 //System.out.println("B = " + B); 139 return B; 140 } 141 142 143 /** 144 * Bi-section point. 145 * @param iv interval with f(left) * f(right) != 0. 146 * @param f univariate polynomial, non-zero. 147 * @return a point c in the interval iv such that f(c) != 0. 148 */ 149 public C bisectionPoint(Interval<C> iv, GenPolynomial<C> f) { 150 if (f == null) { 151 return null; 152 } 153 RingFactory<C> cfac = f.ring.coFac; 154 C two = cfac.fromInteger(2); 155 C c = iv.left.sum(iv.right); 156 c = c.divide(two); 157 if (f.isZERO() || f.isConstant()) { 158 return c; 159 } 160 C m = PolyUtil.<C> evaluateMain(cfac, f, c); 161 while (m.isZERO()) { 162 C d = iv.left.sum(c); 163 d = d.divide(two); 164 if (d.equals(c)) { 165 d = iv.right.sum(c); 166 d = d.divide(two); 167 if (d.equals(c)) { 168 throw new RuntimeException("should not happen " + iv); 169 } 170 } 171 c = d; 172 m = PolyUtil.<C> evaluateMain(cfac, f, c); 173 //System.out.println("c = " + c); 174 } 175 //System.out.println("c = " + c); 176 return c; 177 } 178 179 180 /** 181 * Isolating intervals for the real roots. 182 * @param f univariate polynomial. 183 * @return a list of isolating intervalls for the real roots of f. 184 */ 185 public abstract List<Interval<C>> realRoots(GenPolynomial<C> f); 186 187 188 /** 189 * Isolating intervals for the real roots. 190 * @param f univariate polynomial. 191 * @param eps requested intervals length. 192 * @return a list of isolating intervals v such that |v| < eps. 193 */ 194 public List<Interval<C>> realRoots(GenPolynomial<C> f, C eps) { 195 return realRoots(f, eps.getRational()); 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 List<Interval<C>> iv = realRoots(f); 207 return refineIntervals(iv, f, eps); 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 BigRational len = iv.rationalLength(); 248 BigRational two = len.factory().fromInteger(2); 249 BigRational 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, BigRational eps) { 262 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 263 return iv; 264 } 265 if (iv.rationalLength().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.rationalLength().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, BigRational 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 BigRational 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()).getRational().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, BigRational 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, BigRational 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.rationalLength().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) { 519 // dx < left: dx - left < 0 520 // dx > right: dx - right > 0 521 //System.out.println("trying to leave interval"); 522 if (i++ > MITER) { // dx > right: dx - right > 0 523 throw new NoConvergenceException("no convergence after " + i + " steps"); 524 } 525 if (i > MITER / 2 && dir == 0) { 526 BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); 527 d = sd; 528 x = sd.getZERO(); 529 logger.info("trying new random starting point " + d); 530 i = 0; 531 dir = 1; 532 } 533 if (i > MITER / 2 && dir == 1) { 534 BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); 535 d = sd; 536 x = sd.getZERO(); 537 logger.info("trying new random starting point " + d); 538 //i = 0; 539 dir = 2; // end 540 } 541 x = x.multiply(q); // x * 1/4 542 dx = d.subtract(x); 543 //System.out.println(" x = " + x); 544 //System.out.println("dx = " + dx); 545 } 546 d = dx; 547 } 548 throw new NoConvergenceException("no convergence after " + i + " steps"); 549 } 550 551 552 /** 553 * Approximate real roots. 554 * @param f univariate polynomial, non-zero. 555 * @param eps requested interval length. 556 * @return a list of decimal approximations d such that |d-v| < eps for 557 * all real v with f(v) = 0. 558 */ 559 public List<BigDecimal> approximateRoots(GenPolynomial<C> f, BigRational eps) { 560 List<Interval<C>> iv = realRoots(f); 561 List<BigDecimal> roots = new ArrayList<BigDecimal>(iv.size()); 562 for (Interval<C> i : iv) { 563 BigDecimal r = null; //approximateRoot(i, f, eps); roots.add(r); 564 while (r == null) { 565 try { 566 r = approximateRoot(i, f, eps); 567 roots.add(r); 568 } catch (NoConvergenceException e) { 569 // fall back to exact algorithm 570 //System.out.println("" + e); 571 BigRational len = i.rationalLength(); 572 len = len.divide(len.factory().fromInteger(1000)); 573 i = refineInterval(i, f, len); 574 logger.info("fall back rootRefinement = " + i); 575 } 576 } 577 } 578 return roots; 579 } 580 581 582 /** 583 * Test if x is an approximate real root. 584 * @param x approximate real root. 585 * @param f univariate polynomial, non-zero. 586 * @param eps requested interval length. 587 * @return true if x is a decimal approximation of a real v with f(v) = 0 588 * with |d-v| < eps, else false. 589 */ 590 public boolean isApproximateRoot(BigDecimal x, GenPolynomial<C> f, C eps) { 591 if (x == null) { 592 throw new IllegalArgumentException("null root not allowed"); 593 } 594 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 595 return true; 596 } 597 BigDecimal e = new BigDecimal(eps.getRational()); 598 e = e.multiply(new BigDecimal("1000")); // relax 599 BigDecimal dc = BigDecimal.ONE; 600 // polynomials with decimal coefficients 601 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 602 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 603 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 604 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 605 // 606 return isApproximateRoot(x, df, dfp, e); 607 } 608 609 610 /** 611 * Test if x is an approximate real root. 612 * @param x approximate real root. 613 * @param f univariate polynomial, non-zero. 614 * @param fp univariate polynomial, non-zero, deriviative of f. 615 * @param eps requested interval length. 616 * @return true if x is a decimal approximation of a real v with f(v) = 0 617 * with |d-v| < eps, else false. 618 */ 619 public boolean isApproximateRoot(BigDecimal x, GenPolynomial<BigDecimal> f, GenPolynomial<BigDecimal> fp, 620 BigDecimal eps) { 621 if (x == null) { 622 throw new IllegalArgumentException("null root not allowed"); 623 } 624 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 625 return true; 626 } 627 BigDecimal dc = BigDecimal.ONE; // only for clarity 628 // f(x) 629 BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, f, x); 630 //System.out.println("fx = " + fx); 631 if (fx.isZERO()) { 632 return true; 633 } 634 // f'(x) 635 BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, fp, x); // f'(d) 636 //System.out.println("fpx = " + fpx); 637 if (fpx.isZERO()) { 638 return false; 639 } 640 BigDecimal d = fx.divide(fpx); 641 if (d.isZERO()) { 642 return true; 643 } 644 if (d.abs().compareTo(eps) <= 0) { 645 return true; 646 } 647 System.out.println("x = " + x); 648 System.out.println("d = " + d); 649 return false; 650 } 651 652 653 /** 654 * Test if each x in R is an approximate real root. 655 * @param R ist of approximate real roots. 656 * @param f univariate polynomial, non-zero. 657 * @param eps requested interval length. 658 * @return true if each x in R is a decimal approximation of a real v with 659 * f(v) = 0 with |d-v| < eps, else false. 660 */ 661 public boolean isApproximateRoot(List<BigDecimal> R, GenPolynomial<C> f, BigRational eps) { 662 if (R == null) { 663 throw new IllegalArgumentException("null root not allowed"); 664 } 665 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 666 return true; 667 } 668 BigDecimal e = new BigDecimal(eps.getRational()); 669 e = e.multiply(new BigDecimal("1000")); // relax 670 BigDecimal dc = BigDecimal.ONE; 671 // polynomials with decimal coefficients 672 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 673 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 674 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 675 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 676 for (BigDecimal x : R) { 677 if (!isApproximateRoot(x, df, dfp, e)) { 678 return false; 679 } 680 } 681 return true; 682 } 683 684}