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