001/* 002 * $Id$ 003 */ 004 005package edu.jas.root; 006 007 008import java.util.ArrayList; 009import java.util.List; 010 011import org.apache.logging.log4j.LogManager; 012import org.apache.logging.log4j.Logger; 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 BigRational r = M.getRational(); 066 logger.info("rational root bound: " + r); 067 BigInteger i = new BigInteger(r.numerator().divide(r.denominator())); 068 i = i.sum(BigInteger.ONE); // ceiling 069 M = cfac.fromInteger(i.getVal()); 070 M = M.sum(f.ring.coFac.getONE()); 071 logger.info("integer root bound: " + M); 072 //System.out.println("M = " + M); 073 return M; 074 } 075 076 077 /** 078 * Magnitude bound. 079 * @param iv interval. 080 * @param f univariate polynomial. 081 * @return B such that |f(c)| < B for c in iv. 082 */ 083 @SuppressWarnings("unchecked") 084 public C magnitudeBound(Interval<C> iv, GenPolynomial<C> f) { 085 if (f == null) { 086 return null; 087 } 088 if (f.isZERO()) { 089 return f.ring.coFac.getONE(); 090 } 091 if (f.isConstant()) { 092 return f.leadingBaseCoefficient().abs(); 093 } 094 GenPolynomial<C> fa = f.map(new UnaryFunctor<C, C>() { 095 096 097 public C eval(C a) { 098 return a.abs(); 099 } 100 }); 101 //System.out.println("fa = " + fa); 102 C M = iv.left.abs(); 103 if (M.compareTo(iv.right.abs()) < 0) { 104 M = iv.right.abs(); 105 } 106 //System.out.println("M = " + M); 107 RingFactory<C> cfac = f.ring.coFac; 108 C B = PolyUtil.<C> evaluateMain(cfac, fa, M); 109 // works also without this case, only for optimization 110 // to use rational number interval end points 111 // can fail if real root is in interval [r,r+1] 112 // for too low precision or too big r, since r is approximation 113 //if ((Object) B instanceof RealAlgebraicNumber) { 114 // RealAlgebraicNumber Br = (RealAlgebraicNumber) B; 115 // BigRational r = Br.magnitude(); 116 // B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); 117 //} 118 BigRational r = B.getRational(); 119 B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); 120 //System.out.println("B = " + B); 121 return B; 122 } 123 124 125 /** 126 * Real minimal root bound. 127 * @param f univariate polynomial. 128 * @return M such that abs(xi) > M for f(xi) == 0. 129 */ 130 public C realMinimalRootBound(GenPolynomial<C> f) { 131 if (f == null) { 132 return null; 133 } 134 RingFactory<C> cfac = f.ring.coFac; 135 // maxNorm root bound 136 BigRational mr = f.maxNorm().getRational().sum(BigRational.ONE); 137 BigRational di = mr.sum(BigRational.ONE).inverse(); 138 C B = cfac.fromInteger(di.numerator()).divide(cfac.fromInteger(di.denominator())); 139 //System.out.println("B = " + B + ", sign(B) = " + B.signum()); 140 return B; 141 } 142 143 144 /** 145 * Real minimal root separation. 146 * @param f univariate polynomial. 147 * @return M such that abs(xi-xj) > M for roots xi, xj of f. 148 */ 149 public C realMinimalRootSeparation(GenPolynomial<C> f) { 150 if (f == null) { 151 return null; 152 } 153 RingFactory<C> cfac = f.ring.coFac; 154 // sumNorm root bound 155 BigRational pr = f.sumNorm().getRational(); 156 pr = pr.sum(BigRational.ONE); 157 BigRational sep = BigRational.ZERO; 158 long n = f.degree(); 159 if (n > 0) { 160 sep = pr.power(2 * n).multiply(pr.fromInteger(n).power(n + 1)).inverse(); 161 } 162 //System.out.println("sep = " + sep + ", sign(sep) = " + sep.signum()); 163 C M = cfac.fromInteger(sep.numerator()).divide(cfac.fromInteger(sep.denominator())); 164 return M; 165 } 166 167 168 /** 169 * Bi-section point. 170 * @param iv interval with f(left) * f(right) != 0. 171 * @param f univariate polynomial, non-zero. 172 * @return a point c in the interval iv such that f(c) != 0. 173 */ 174 public C bisectionPoint(Interval<C> iv, GenPolynomial<C> f) { 175 if (f == null) { 176 return null; 177 } 178 RingFactory<C> cfac = f.ring.coFac; 179 C two = cfac.fromInteger(2); 180 C c = iv.left.sum(iv.right); 181 c = c.divide(two); 182 if (f.isZERO() || f.isConstant()) { 183 return c; 184 } 185 C m = PolyUtil.<C> evaluateMain(cfac, f, c); 186 while (m.isZERO()) { 187 C d = iv.left.sum(c); 188 d = d.divide(two); 189 if (d.equals(c)) { 190 d = iv.right.sum(c); 191 d = d.divide(two); 192 if (d.equals(c)) { 193 throw new RuntimeException("should not happen " + iv); 194 } 195 } 196 c = d; 197 m = PolyUtil.<C> evaluateMain(cfac, f, c); 198 //System.out.println("c = " + c); 199 } 200 //System.out.println("c = " + c); 201 return c; 202 } 203 204 205 /** 206 * Isolating intervals for the real roots. 207 * @param f univariate polynomial. 208 * @return a list of isolating intervalls for the real roots of f. 209 */ 210 public abstract List<Interval<C>> realRoots(GenPolynomial<C> f); 211 212 213 /** 214 * Isolating intervals for the real roots. 215 * @param f univariate polynomial. 216 * @param eps requested intervals length. 217 * @return a list of isolating intervals v such that |v| < eps. 218 */ 219 public List<Interval<C>> realRoots(GenPolynomial<C> f, C eps) { 220 return realRoots(f, eps.getRational()); 221 } 222 223 224 /** 225 * Isolating intervals for the real roots. 226 * @param f univariate polynomial. 227 * @param eps requested intervals length. 228 * @return a list of isolating intervals v such that |v| < eps. 229 */ 230 public List<Interval<C>> realRoots(GenPolynomial<C> f, BigRational eps) { 231 List<Interval<C>> iv = realRoots(f); 232 return refineIntervals(iv, f, eps); 233 } 234 235 236 /** 237 * Sign changes on interval bounds. 238 * @param iv root isolating interval with f(left) * f(right) != 0. 239 * @param f univariate polynomial. 240 * @return true if f(left) * f(right) < 0, else false 241 */ 242 public boolean signChange(Interval<C> iv, GenPolynomial<C> f) { 243 if (f == null) { 244 return false; 245 } 246 RingFactory<C> cfac = f.ring.coFac; 247 C l = PolyUtil.<C> evaluateMain(cfac, f, iv.left); 248 C r = PolyUtil.<C> evaluateMain(cfac, f, iv.right); 249 return l.signum() * r.signum() < 0; 250 } 251 252 253 /** 254 * Number of real roots in interval. 255 * @param iv interval with f(left) * f(right) != 0. 256 * @param f univariate polynomial. 257 * @return number of real roots of f in I. 258 */ 259 public abstract long realRootCount(Interval<C> iv, GenPolynomial<C> f); 260 261 262 /** 263 * Half interval. 264 * @param iv root isolating interval with f(left) * f(right) < 0. 265 * @param f univariate polynomial, non-zero. 266 * @return a new interval v such that |v| < |iv|/2. 267 */ 268 public Interval<C> halfInterval(Interval<C> iv, GenPolynomial<C> f) { 269 if (f == null || f.isZERO()) { 270 return iv; 271 } 272 BigRational len = iv.rationalLength(); 273 BigRational two = len.factory().fromInteger(2); 274 BigRational eps = len.divide(two); 275 return refineInterval(iv, f, eps); 276 } 277 278 279 /** 280 * Refine interval. 281 * @param iv root isolating interval with f(left) * f(right) < 0. 282 * @param f univariate polynomial, non-zero. 283 * @param eps requested interval length. 284 * @return a new interval v such that |v| < eps. 285 */ 286 public Interval<C> refineInterval(Interval<C> iv, GenPolynomial<C> f, BigRational eps) { 287 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 288 return iv; 289 } 290 if (iv.rationalLength().compareTo(eps) < 0) { 291 return iv; 292 } 293 RingFactory<C> cfac = f.ring.coFac; 294 C two = cfac.fromInteger(2); 295 Interval<C> v = iv; 296 while (v.rationalLength().compareTo(eps) >= 0) { 297 C c = v.left.sum(v.right); 298 c = c.divide(two); 299 //System.out.println("c = " + c); 300 //c = RootUtil.<C>bisectionPoint(v,f); 301 if (PolyUtil.<C> evaluateMain(cfac, f, c).isZERO()) { 302 v = new Interval<C>(c, c); 303 break; 304 } 305 Interval<C> iv1 = new Interval<C>(v.left, c); 306 if (signChange(iv1, f)) { 307 v = iv1; 308 } else { 309 v = new Interval<C>(c, v.right); 310 } 311 } 312 return v; 313 } 314 315 316 /** 317 * Refine intervals. 318 * @param V list of isolating intervals with f(left) * f(right) < 0. 319 * @param f univariate polynomial, non-zero. 320 * @param eps requested intervals length. 321 * @return a list of new intervals v such that |v| < eps. 322 */ 323 public List<Interval<C>> refineIntervals(List<Interval<C>> V, GenPolynomial<C> f, BigRational eps) { 324 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 325 return V; 326 } 327 List<Interval<C>> IV = new ArrayList<Interval<C>>(); 328 for (Interval<C> v : V) { 329 Interval<C> iv = refineInterval(v, f, eps); 330 IV.add(iv); 331 } 332 return IV; 333 } 334 335 336 /** 337 * Invariant interval for algebraic number sign. 338 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 339 * @param f univariate polynomial, non-zero. 340 * @param g univariate polynomial, gcd(f,g) == 1. 341 * @return v with v a new interval contained in iv such that g(v) != 0. 342 */ 343 public abstract Interval<C> invariantSignInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g); 344 345 346 /** 347 * Real algebraic number sign. 348 * @param iv root isolating interval for f, with f(left) * f(right) < 0, 349 * with iv such that g(iv) != 0. 350 * @param f univariate polynomial, non-zero. 351 * @param g univariate polynomial, gcd(f,g) == 1. 352 * @return sign(g(iv)) . 353 */ 354 public int realIntervalSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) { 355 if (g == null || g.isZERO()) { 356 return 0; 357 } 358 if (f == null || f.isZERO() || f.isConstant()) { 359 return g.signum(); 360 } 361 if (g.isConstant()) { 362 return g.signum(); 363 } 364 RingFactory<C> cfac = f.ring.coFac; 365 C c = iv.left.sum(iv.right); 366 c = c.divide(cfac.fromInteger(2)); 367 C ev = PolyUtil.<C> evaluateMain(cfac, g, c); 368 //System.out.println("ev = " + ev); 369 return ev.signum(); 370 } 371 372 373 /** 374 * Real algebraic number sign. 375 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 376 * @param f univariate polynomial, non-zero. 377 * @param g univariate polynomial, gcd(f,g) == 1. 378 * @return sign(g(v)), with v a new interval contained in iv such that g(v) 379 * != 0. 380 */ 381 public int realSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) { 382 if (g == null || g.isZERO()) { 383 return 0; 384 } 385 if (f == null || f.isZERO() || f.isConstant()) { 386 return g.signum(); 387 } 388 if (g.isConstant()) { 389 return g.signum(); 390 } 391 Interval<C> v = invariantSignInterval(iv, f, g); 392 return realIntervalSign(v, f, g); 393 } 394 395 396 /** 397 * Invariant interval for algebraic number magnitude. 398 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 399 * @param f univariate polynomial, non-zero. 400 * @param g univariate polynomial, gcd(f,g) == 1. 401 * @param eps length limit for interval length. 402 * @return v with v a new interval contained in iv such that |g(a) - g(b)| 403 * < eps for a, b in v in iv. 404 */ 405 public Interval<C> invariantMagnitudeInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, 406 BigRational eps) { 407 Interval<C> v = iv; 408 if (g == null || g.isZERO()) { 409 return v; 410 } 411 if (g.isConstant()) { 412 return v; 413 } 414 if (f == null || f.isZERO() || f.isConstant()) { // ? 415 return v; 416 } 417 GenPolynomial<C> gp = PolyUtil.<C> baseDeriviative(g); 418 //System.out.println("g = " + g); 419 //System.out.println("gp = " + gp); 420 C B = magnitudeBound(iv, gp); 421 //System.out.println("B = " + B); 422 RingFactory<C> cfac = f.ring.coFac; 423 C two = cfac.fromInteger(2); 424 while (B.multiply(v.length()).getRational().compareTo(eps) >= 0) { 425 C c = v.left.sum(v.right); 426 c = c.divide(two); 427 Interval<C> im = new Interval<C>(c, v.right); 428 if (signChange(im, f)) { 429 v = im; 430 } else { 431 v = new Interval<C>(v.left, c); 432 } 433 //System.out.println("v = " + v.toDecimal()); 434 } 435 return v; 436 } 437 438 439 /** 440 * Real algebraic number magnitude. 441 * @param iv root isolating interval for f, with f(left) * f(right) < 0, 442 * with iv such that |g(a) - g(b)| < eps for a, b in iv. 443 * @param f univariate polynomial, non-zero. 444 * @param g univariate polynomial, gcd(f,g) == 1. 445 * @return g(iv) . 446 */ 447 public C realIntervalMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) { 448 if (g.isZERO() || g.isConstant()) { 449 return g.leadingBaseCoefficient(); 450 } 451 RingFactory<C> cfac = f.ring.coFac; 452 C evl = PolyUtil.<C> evaluateMain(cfac, g, iv.left); 453 C evr = PolyUtil.<C> evaluateMain(cfac, g, iv.right); 454 C ev = evl; 455 if (evl.compareTo(evr) <= 0) { 456 ev = evr; 457 } 458 //System.out.println("ev = " + ev + ", evl = " + evl + ", evr = " + evr + ", iv = " + iv); 459 return ev; 460 } 461 462 463 /** 464 * Real algebraic number magnitude. 465 * @param iv root isolating interval for f, with f(left) * f(right) < 0. 466 * @param f univariate polynomial, non-zero. 467 * @param g univariate polynomial, gcd(f,g) == 1. 468 * @param eps length limit for interval length. 469 * @return g(iv) . 470 */ 471 public C realMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, BigRational eps) { 472 if (g.isZERO() || g.isConstant()) { 473 return g.leadingBaseCoefficient(); 474 } 475 Interval<C> v = invariantMagnitudeInterval(iv, f, g, eps); 476 return realIntervalMagnitude(v, f, g); 477 } 478 479 480 /** 481 * Real algebraic number magnitude. 482 * @param iv root isolating interval for f, with f(left) * f(right) < 0, 483 * with iv such that |g(a) - g(b)| < eps for a, b in iv. 484 * @param f univariate polynomial, non-zero. 485 * @param g univariate polynomial, gcd(f,g) == 1. 486 * @return Interval( g(iv.left), g(iv.right) ) . 487 */ 488 public Interval<C> realIntervalMagnitudeInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) { 489 if (g.isZERO() || g.isConstant()) { 490 return iv; 491 } 492 RingFactory<C> cfac = f.ring.coFac; 493 C evl = PolyUtil.<C> evaluateMain(cfac, g, iv.left); 494 C evr = PolyUtil.<C> evaluateMain(cfac, g, iv.right); 495 Interval<C> ev = new Interval<C>(evr, evl); 496 if (evl.compareTo(evr) <= 0) { 497 ev = new Interval<C>(evl, evr); 498 } 499 System.out.println("ev = " + ev + ", iv = " + iv); 500 return ev; 501 } 502 503 504 /** 505 * Approximate real root. 506 * @param iv real root isolating interval with f(left) * f(right) < 0. 507 * @param f univariate polynomial, non-zero. 508 * @param eps requested interval length. 509 * @return a decimal approximation d such that |d-v| < eps, for f(v) = 0, 510 * v real. 511 */ 512 public BigDecimal approximateRoot(Interval<C> iv, GenPolynomial<C> f, BigRational eps) 513 throws NoConvergenceException { 514 if (iv == null) { 515 throw new IllegalArgumentException("null interval not allowed"); 516 } 517 BigDecimal d = iv.toDecimal(); 518 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 519 return d; 520 } 521 if (iv.rationalLength().compareTo(eps) < 0) { 522 return d; 523 } 524 BigDecimal left = new BigDecimal(iv.left.getRational()); 525 BigDecimal right = new BigDecimal(iv.right.getRational()); 526 BigRational reps = eps.getRational(); 527 BigDecimal e = new BigDecimal(reps); 528 BigDecimal q = new BigDecimal("0.25"); 529 //System.out.println("left = " + left); 530 //System.out.println("right = " + right); 531 e = e.multiply(d); // relative error 532 //System.out.println("e = " + e); 533 BigDecimal dc = BigDecimal.ONE; 534 // polynomials with decimal coefficients 535 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 536 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 537 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 538 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 539 // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n) 540 int i = 0; 541 final int MITER = 50; 542 int dir = 0; 543 while (i++ < MITER) { 544 BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, df, d); // f(d) 545 if (fx.isZERO()) { 546 return d; 547 } 548 BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, dfp, d); // f'(d) 549 if (fpx.isZERO()) { 550 throw new NoConvergenceException("zero deriviative should not happen"); 551 } 552 BigDecimal x = fx.divide(fpx); 553 BigDecimal dx = d.subtract(x); 554 //System.out.println("dx = " + dx + ", d = " + d); 555 if (d.subtract(dx).abs().compareTo(e) <= 0) { 556 return dx; 557 } 558 while (dx.compareTo(left) < 0 || dx.compareTo(right) > 0) { 559 // dx < left: dx - left < 0 560 // dx > right: dx - right > 0 561 //System.out.println("trying to leave interval"); 562 if (i++ > MITER) { // dx > right: dx - right > 0 563 throw new NoConvergenceException("no convergence after " + i + " steps"); 564 } 565 if (i > MITER / 2 && dir == 0) { 566 BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); 567 d = sd; 568 x = sd.getZERO(); 569 logger.info("trying new random starting point " + d); 570 i = 0; 571 dir = 1; 572 } 573 if (i > MITER / 2 && dir == 1) { 574 BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); 575 d = sd; 576 x = sd.getZERO(); 577 logger.info("trying new random starting point " + d); 578 //i = 0; 579 dir = 2; // end 580 } 581 x = x.multiply(q); // x * 1/4 582 dx = d.subtract(x); 583 //System.out.println(" x = " + x); 584 //System.out.println("dx = " + dx); 585 } 586 d = dx; 587 } 588 throw new NoConvergenceException("no convergence after " + i + " steps"); 589 } 590 591 592 /** 593 * Approximate real roots. 594 * @param f univariate polynomial, non-zero. 595 * @param eps requested interval length. 596 * @return a list of decimal approximations d such that |d-v| < eps for 597 * all real v with f(v) = 0. 598 */ 599 public List<BigDecimal> approximateRoots(GenPolynomial<C> f, BigRational eps) { 600 List<Interval<C>> iv = realRoots(f); 601 List<BigDecimal> roots = new ArrayList<BigDecimal>(iv.size()); 602 for (Interval<C> i : iv) { 603 BigDecimal r = null; //approximateRoot(i, f, eps); roots.add(r); 604 while (r == null) { 605 try { 606 r = approximateRoot(i, f, eps); 607 roots.add(r); 608 } catch (NoConvergenceException e) { 609 // fall back to exact algorithm 610 //System.out.println("" + e); 611 BigRational len = i.rationalLength(); 612 len = len.divide(len.factory().fromInteger(1000)); 613 i = refineInterval(i, f, len); 614 logger.info("fall back rootRefinement = " + i); 615 } 616 } 617 } 618 return roots; 619 } 620 621 622 /** 623 * Test if x is an approximate real root. 624 * @param x approximate real root. 625 * @param f univariate polynomial, non-zero. 626 * @param eps requested interval length. 627 * @return true if x is a decimal approximation of a real v with f(v) = 0 628 * with |d-v| < eps, else false. 629 */ 630 public boolean isApproximateRoot(BigDecimal x, GenPolynomial<C> f, C eps) { 631 if (x == null) { 632 throw new IllegalArgumentException("null root not allowed"); 633 } 634 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 635 return true; 636 } 637 BigDecimal e = new BigDecimal(eps.getRational()); 638 e = e.multiply(new BigDecimal("1000")); // relax 639 BigDecimal dc = BigDecimal.ONE; 640 // polynomials with decimal coefficients 641 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 642 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 643 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 644 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 645 // 646 return isApproximateRoot(x, df, dfp, e); 647 } 648 649 650 /** 651 * Test if x is an approximate real root. 652 * @param x approximate real root. 653 * @param f univariate polynomial, non-zero. 654 * @param fp univariate polynomial, non-zero, deriviative of f. 655 * @param eps requested interval length. 656 * @return true if x is a decimal approximation of a real v with f(v) = 0 657 * with |d-v| < eps, else false. 658 */ 659 public boolean isApproximateRoot(BigDecimal x, GenPolynomial<BigDecimal> f, GenPolynomial<BigDecimal> fp, 660 BigDecimal eps) { 661 if (x == 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 dc = BigDecimal.ONE; // only for clarity 668 // f(x) 669 BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, f, x); 670 //System.out.println("fx = " + fx); 671 if (fx.isZERO()) { 672 return true; 673 } 674 // f'(x) 675 BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, fp, x); // f'(d) 676 //System.out.println("fpx = " + fpx); 677 if (fpx.isZERO()) { 678 return false; 679 } 680 BigDecimal d = fx.divide(fpx); 681 if (d.isZERO()) { 682 return true; 683 } 684 if (d.abs().compareTo(eps) <= 0) { 685 return true; 686 } 687 System.out.println("x = " + x); 688 System.out.println("d = " + d); 689 return false; 690 } 691 692 693 /** 694 * Test if each x in R is an approximate real root. 695 * @param R ist of approximate real roots. 696 * @param f univariate polynomial, non-zero. 697 * @param eps requested interval length. 698 * @return true if each x in R is a decimal approximation of a real v with 699 * f(v) = 0 with |d-v| < eps, else false. 700 */ 701 public boolean isApproximateRoot(List<BigDecimal> R, GenPolynomial<C> f, BigRational eps) { 702 if (R == null) { 703 throw new IllegalArgumentException("null root not allowed"); 704 } 705 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 706 return true; 707 } 708 BigDecimal e = new BigDecimal(eps.getRational()); 709 e = e.multiply(new BigDecimal("1000")); // relax 710 BigDecimal dc = BigDecimal.ONE; 711 // polynomials with decimal coefficients 712 GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring); 713 GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f); 714 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 715 GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp); 716 for (BigDecimal x : R) { 717 if (!isApproximateRoot(x, df, dfp, e)) { 718 return false; 719 } 720 } 721 return true; 722 } 723 724 725 /** 726 * Fourier sequence. 727 * @param f univariate polynomial. 728 * @return (f, f', ..., f(n)) a Fourier sequence for f. 729 */ 730 public List<GenPolynomial<C>> fourierSequence(GenPolynomial<C> f) { 731 List<GenPolynomial<C>> S = new ArrayList<GenPolynomial<C>>(); 732 if (f == null || f.isZERO()) { 733 return S; 734 } 735 long d = f.degree(); 736 GenPolynomial<C> F = f; 737 S.add(F); 738 while (d-- > 0) { 739 GenPolynomial<C> G = PolyUtil.<C> baseDeriviative(F); 740 F = G; 741 S.add(F); 742 } 743 //System.out.println("F = " + F); 744 return S; 745 } 746 747 748 /** 749 * Thom sign sequence. 750 * @param f univariate polynomial. 751 * @param v interval for a real root, f(v.left) * f(v.right) < 0. 752 * @return (s1, s2, ..., sn) = (sign(f'(v)), .... sign(f(n)(v))) a Thom sign 753 * sequence for the real root in v of f. 754 */ 755 public List<Integer> signSequence(GenPolynomial<C> f, Interval<C> v) { 756 List<Integer> S = new ArrayList<Integer>(); 757 GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f); 758 List<GenPolynomial<C>> fs = fourierSequence(fp); 759 for (GenPolynomial<C> p : fs) { 760 int s = realSign(v, f, p); 761 S.add(s); 762 } 763 return S; 764 } 765 766 767 /** 768 * Root number. 769 * @param f univariate polynomial. 770 * @param v interval for a real root, f(v.left) * f(v.right) < 0. 771 * @return r the number of this root in the sequence a1 < a2 < ..., 772 * < am of all real roots of f 773 */ 774 public Long realRootNumber(GenPolynomial<C> f, Interval<C> v) { 775 C M = realRootBound(f); 776 Interval<C> iv = new Interval<C>(M.negate(), v.right); 777 long r = realRootCount(iv, f); 778 if (r <= 0) { 779 logger.warn("no real root in interval " + v); 780 } 781 return r; 782 } 783 784}