001/* 002 * $Id$ 003 */ 004 005package edu.jas.root; 006 007 008import java.util.ArrayList; 009import java.util.List; 010import java.util.Map; 011import java.util.TreeMap; 012import java.util.SortedMap; 013 014import org.apache.logging.log4j.Logger; 015import org.apache.logging.log4j.LogManager; 016 017import edu.jas.arith.BigDecimal; 018import edu.jas.arith.BigRational; 019import edu.jas.arith.Rational; 020import edu.jas.poly.Complex; 021import edu.jas.poly.ComplexRing; 022import edu.jas.poly.GenPolynomial; 023import edu.jas.poly.GenPolynomialRing; 024import edu.jas.poly.PolyUtil; 025import edu.jas.structure.RingElem; 026import edu.jas.structure.RingFactory; 027import edu.jas.structure.UnaryFunctor; 028import edu.jas.ufd.Squarefree; 029import edu.jas.ufd.SquarefreeFactory; 030 031 032/** 033 * Complex roots abstract class. 034 * @param <C> coefficient type. 035 * @author Heinz Kredel 036 */ 037public abstract class ComplexRootsAbstract<C extends RingElem<C> & Rational> implements ComplexRoots<C> { 038 039 040 private static final Logger logger = LogManager.getLogger(ComplexRootsAbstract.class); 041 042 043 private static final boolean debug = logger.isDebugEnabled(); 044 045 046 /** 047 * Engine for square free decomposition. 048 */ 049 public final Squarefree<Complex<C>> engine; 050 051 052 /** 053 * Constructor. 054 * @param cf coefficient factory. 055 */ 056 public ComplexRootsAbstract(RingFactory<Complex<C>> cf) { 057 if (!(cf instanceof ComplexRing)) { 058 throw new IllegalArgumentException("cf not supported coefficients " + cf); 059 } 060 engine = SquarefreeFactory.<Complex<C>> getImplementation(cf); 061 } 062 063 064 /** 065 * Root bound. With f(-M + i M) * f(-M - i M) * f(M - i M) * f(M + i M) != 066 * 0. 067 * @param f univariate polynomial. 068 * @return M such that root(f) is contained in the rectangle spanned by M. 069 */ 070 public Complex<C> rootBound(GenPolynomial<Complex<C>> f) { 071 if (f == null) { 072 return null; 073 } 074 RingFactory<Complex<C>> cfac = f.ring.coFac; 075 Complex<C> M = cfac.getONE(); 076 if (f.isZERO() || f.isConstant()) { 077 return M; 078 } 079 Complex<C> a = f.leadingBaseCoefficient().norm(); 080 for (Complex<C> c : f.getMap().values()) { 081 Complex<C> d = c.norm().divide(a); 082 if (M.compareTo(d) < 0) { 083 M = d; 084 } 085 } 086 M = M.sum(cfac.getONE()); 087 //System.out.println("M = " + M); 088 return M; 089 } 090 091 092 /** 093 * Magnitude bound. 094 * @param rect rectangle. 095 * @param f univariate polynomial. 096 * @return B such that |f(c)| < B for c in rect. 097 */ 098 public C magnitudeBound(Rectangle<C> rect, GenPolynomial<Complex<C>> f) { 099 if (f == null) { 100 return null; 101 } 102 if (f.isZERO()) { 103 return f.ring.coFac.getONE().getRe(); 104 } 105 //System.out.println("f = " + f); 106 if (f.isConstant()) { 107 Complex<C> c = f.leadingBaseCoefficient(); 108 return c.norm().getRe(); 109 } 110 GenPolynomial<Complex<C>> fa = f.map(new UnaryFunctor<Complex<C>, Complex<C>>() { 111 112 113 public Complex<C> eval(Complex<C> a) { 114 return a.norm(); 115 } 116 }); 117 //System.out.println("fa = " + fa); 118 Complex<C> Mc = rect.getNW().norm(); 119 C M = Mc.getRe(); 120 //System.out.println("M = " + M); 121 Complex<C> M1c = rect.getSW().norm(); 122 C M1 = M1c.getRe(); 123 if (M.compareTo(M1) < 0) { 124 M = M1; 125 Mc = M1c; 126 } 127 M1c = rect.getSE().norm(); 128 M1 = M1c.getRe(); 129 if (M.compareTo(M1) < 0) { 130 M = M1; 131 Mc = M1c; 132 } 133 M1c = rect.getNE().norm(); 134 M1 = M1c.getRe(); 135 if (M.compareTo(M1) < 0) { 136 //M = M1; 137 Mc = M1c; 138 } 139 //System.out.println("M = " + M); 140 Complex<C> B = PolyUtil.<Complex<C>> evaluateMain(f.ring.coFac, fa, Mc); 141 //System.out.println("B = " + B); 142 return B.getRe(); 143 } 144 145 146 /** 147 * Complex root count of complex polynomial on rectangle. 148 * @param rect rectangle. 149 * @param a univariate complex polynomial. 150 * @return root count of a in rectangle. 151 */ 152 public abstract long complexRootCount(Rectangle<C> rect, GenPolynomial<Complex<C>> a) 153 throws InvalidBoundaryException; 154 155 156 /** 157 * List of complex roots of complex polynomial a on rectangle. 158 * @param rect rectangle. 159 * @param a univariate squarefree complex polynomial. 160 * @return list of complex roots. 161 */ 162 public abstract List<Rectangle<C>> complexRoots(Rectangle<C> rect, GenPolynomial<Complex<C>> a) 163 throws InvalidBoundaryException; 164 165 166 /** 167 * List of complex roots of complex polynomial. 168 * @param a univariate complex polynomial. 169 * @return list of complex roots. 170 */ 171 @SuppressWarnings({"cast","unchecked"}) 172 public List<Rectangle<C>> complexRoots(GenPolynomial<Complex<C>> a) { 173 List<Rectangle<C>> roots = new ArrayList<Rectangle<C>>(); 174 if (a.isConstant() || a.isZERO()) { 175 return roots; 176 } 177 ComplexRing<C> cr = (ComplexRing<C>) a.ring.coFac; 178 GenPolynomial<Complex<C>> sp = engine.squarefreePart(a); 179 SortedMap<GenPolynomial<Complex<C>>, Long> sa = new TreeMap<GenPolynomial<Complex<C>>, Long>(); 180 sa.put(sp, 1L); 181 //SortedMap<GenPolynomial<Complex<C>>, Long> sa = engine.squarefreeFactors(a); // BUG to addAll 182 //System.out.println("squarefree factors = " + sa); 183 for (Map.Entry<GenPolynomial<Complex<C>>, Long> me : sa.entrySet()) { // todo fix addAll 184 GenPolynomial<Complex<C>> p = me.getKey(); 185 Complex<C> Mb = rootBound(p); 186 C M = Mb.getRe(); 187 C M1 = M.sum(M.factory().fromInteger(1)); // asymmetric to origin 188 //System.out.println("M = " + M); 189 if (debug) { 190 logger.info("rootBound = " + M); 191 } 192 Complex<C>[] corner = (Complex<C>[]) new Complex[4]; 193 corner[0] = new Complex<C>(cr, M1.negate(), M); // nw 194 corner[1] = new Complex<C>(cr, M1.negate(), M1.negate()); // sw 195 corner[2] = new Complex<C>(cr, M, M1.negate()); // se 196 corner[3] = new Complex<C>(cr, M, M); // ne 197 Rectangle<C> rect = new Rectangle<C>(corner); 198 try { 199 List<Rectangle<C>> rs = complexRoots(rect, p); 200 long e = me.getValue(); // sa.get(p); 201 for (int i = 0; i < e; i++) { // add with multiplicity 202 roots.addAll(rs); 203 } 204 } catch (InvalidBoundaryException e) { 205 //logger.error("invalid boundary for p = " + p); 206 throw new RuntimeException("this should never happen " + e); 207 } 208 } 209 return roots; 210 } 211 212 213 /** 214 * Complex root refinement of complex polynomial a on rectangle. 215 * @param rect rectangle containing exactly one complex root. 216 * @param a univariate squarefree complex polynomial. 217 * @param len rational length for refinement. 218 * @return refined complex root. 219 */ 220 @SuppressWarnings({"cast","unchecked"}) 221 public Rectangle<C> complexRootRefinement(Rectangle<C> rect, GenPolynomial<Complex<C>> a, BigRational len) 222 throws InvalidBoundaryException { 223 ComplexRing<C> cr = (ComplexRing<C>) a.ring.coFac; 224 Rectangle<C> root = rect; 225 long w; 226 if (debug) { 227 w = complexRootCount(root, a); 228 if (w != 1) { 229 System.out.println("#root = " + w); 230 System.out.println("root = " + root); 231 throw new ArithmeticException("no initial isolating rectangle " + rect); 232 } 233 } 234 Complex<C> eps = cr.fromInteger(1); 235 eps = eps.divide(cr.fromInteger(1000)); // 1/1000 236 BigRational length = len.multiply(len); 237 Complex<C> delta = null; 238 boolean work = true; 239 while (work) { 240 try { 241 while (root.rationalLength().compareTo(length) > 0) { 242 //System.out.println("root = " + root + ", len = " + new BigDecimal(root.rationalLength())); 243 if (delta == null) { 244 delta = root.corners[3].subtract(root.corners[1]); 245 delta = delta.divide(cr.fromInteger(2)); 246 //System.out.println("delta = " + toDecimal(delta)); 247 } 248 Complex<C> center = root.corners[1].sum(delta); 249 //System.out.println("refine center = " + toDecimal(center)); 250 if (debug) { 251 logger.info("new center = " + center); 252 } 253 254 Complex<C>[] cp = (Complex<C>[]) copyOfComplex(root.corners, 4); 255 // cp[0] fix 256 cp[1] = new Complex<C>(cr, cp[1].getRe(), center.getIm()); 257 cp[2] = center; 258 cp[3] = new Complex<C>(cr, center.getRe(), cp[3].getIm()); 259 Rectangle<C> nw = new Rectangle<C>(cp); 260 w = complexRootCount(nw, a); 261 if (w == 1) { 262 root = nw; 263 delta = null; 264 continue; 265 } 266 267 cp = (Complex<C>[]) copyOfComplex(root.corners, 4); 268 cp[0] = new Complex<C>(cr, cp[0].getRe(), center.getIm()); 269 // cp[1] fix 270 cp[2] = new Complex<C>(cr, center.getRe(), cp[2].getIm()); 271 cp[3] = center; 272 Rectangle<C> sw = new Rectangle<C>(cp); 273 w = complexRootCount(sw, a); 274 //System.out.println("#swr = " + w); 275 if (w == 1) { 276 root = sw; 277 delta = null; 278 continue; 279 } 280 281 cp = (Complex<C>[]) copyOfComplex(root.corners, 4); 282 cp[0] = center; 283 cp[1] = new Complex<C>(cr, center.getRe(), cp[1].getIm()); 284 // cp[2] fix 285 cp[3] = new Complex<C>(cr, cp[3].getRe(), center.getIm()); 286 Rectangle<C> se = new Rectangle<C>(cp); 287 w = complexRootCount(se, a); 288 //System.out.println("#ser = " + w); 289 if (w == 1) { 290 root = se; 291 delta = null; 292 continue; 293 } 294 295 cp = (Complex<C>[]) copyOfComplex(root.corners, 4); 296 cp[0] = new Complex<C>(cr, center.getRe(), cp[0].getIm()); 297 cp[1] = center; 298 cp[2] = new Complex<C>(cr, cp[2].getRe(), center.getIm()); 299 // cp[3] fix 300 Rectangle<C> ne = new Rectangle<C>(cp); 301 w = complexRootCount(ne, a); 302 //System.out.println("#ner = " + w); 303 if (w == 1) { 304 root = ne; 305 delta = null; 306 continue; 307 } 308 if (true) { 309 w = complexRootCount(root, a); 310 System.out.println("#root = " + w); 311 System.out.println("root = " + root); 312 } 313 throw new ArithmeticException("no isolating rectangle " + rect); 314 } 315 work = false; 316 } catch (InvalidBoundaryException e) { 317 // repeat with new center 318 delta = delta.sum(delta.multiply(eps)); // distort 319 //System.out.println("new refine delta = " + toDecimal(delta)); 320 eps = eps.sum(eps.multiply(cr.getIMAG())); 321 } 322 } 323 return root; 324 } 325 326 327 /** 328 * List of complex roots of complex polynomial. 329 * @param a univariate complex polynomial. 330 * @param len rational length for refinement. 331 * @return list of complex roots to desired precision. 332 */ 333 @SuppressWarnings({"cast","unchecked"}) 334 public List<Rectangle<C>> complexRoots(GenPolynomial<Complex<C>> a, BigRational len) { 335 ComplexRing<C> cr = (ComplexRing<C>) a.ring.coFac; 336 SortedMap<GenPolynomial<Complex<C>>, Long> sa = engine.squarefreeFactors(a); 337 List<Rectangle<C>> roots = new ArrayList<Rectangle<C>>(); 338 for (Map.Entry<GenPolynomial<Complex<C>>, Long> me : sa.entrySet()) { 339 GenPolynomial<Complex<C>> p = me.getKey(); 340 Complex<C> Mb = rootBound(p); 341 C M = Mb.getRe(); 342 C M1 = M.sum(M.factory().fromInteger(1)); // asymmetric to origin 343 if (debug) { 344 logger.info("rootBound = " + M); 345 } 346 Complex<C>[] corner = (Complex<C>[]) new Complex[4]; 347 corner[0] = new Complex<C>(cr, M1.negate(), M); // nw 348 corner[1] = new Complex<C>(cr, M1.negate(), M1.negate()); // sw 349 corner[2] = new Complex<C>(cr, M, M1.negate()); // se 350 corner[3] = new Complex<C>(cr, M, M); // ne 351 Rectangle<C> rect = new Rectangle<C>(corner); 352 try { 353 List<Rectangle<C>> rs = complexRoots(rect, p); 354 List<Rectangle<C>> rf = new ArrayList<Rectangle<C>>(rs.size()); 355 for (Rectangle<C> r : rs) { 356 Rectangle<C> rr = complexRootRefinement(r, p, len); 357 rf.add(rr); 358 } 359 long e = me.getValue(); // sa.get(p); 360 for (int i = 0; i < e; i++) { // add with multiplicity 361 roots.addAll(rf); 362 } 363 } catch (InvalidBoundaryException e) { 364 throw new RuntimeException("this should never happen " + e); 365 } 366 } 367 return roots; 368 } 369 370 371 /** 372 * Invariant rectangle for algebraic number. 373 * @param rect root isolating rectangle for f which contains exactly one 374 * root. 375 * @param f univariate polynomial, non-zero. 376 * @param g univariate polynomial, gcd(f,g) == 1. 377 * @return v with v a new rectangle contained in iv such that g(w) != 0 for 378 * w in v. 379 */ 380 public abstract Rectangle<C> invariantRectangle(Rectangle<C> rect, GenPolynomial<Complex<C>> f, 381 GenPolynomial<Complex<C>> g) throws InvalidBoundaryException; 382 383 384 /** 385 * Get decimal approximation. 386 * @param a complex number. 387 * @return decimal(a). 388 */ 389 public String toDecimal(Complex<C> a) { 390 C r = a.getRe(); 391 String s = r.toString(); 392 BigRational rs = new BigRational(s); 393 BigDecimal rd = new BigDecimal(rs); 394 C i = a.getIm(); 395 s = i.toString(); 396 BigRational is = new BigRational(s); 397 BigDecimal id = new BigDecimal(is); 398 //System.out.println("rd = " + rd); 399 //System.out.println("id = " + id); 400 return rd.toString() + " i " + id.toString(); 401 } 402 403 404 /** 405 * Approximate complex root. 406 * @param rt root isolating rectangle. 407 * @param f univariate polynomial, non-zero. 408 * @param eps requested interval length. 409 * @return a decimal approximation d such that |d-v| < eps, for f(v) = 0, 410 * v in rt. 411 */ 412 public Complex<BigDecimal> approximateRoot(Rectangle<C> rt, GenPolynomial<Complex<C>> f, BigRational eps) 413 throws NoConvergenceException { 414 if (rt == null) { 415 throw new IllegalArgumentException("null interval not allowed"); 416 } 417 Complex<BigDecimal> d = rt.getDecimalCenter(); 418 //System.out.println("d = " + d); 419 if (f == null || f.isZERO() || f.isConstant() || eps == null) { 420 return d; 421 } 422 if (rt.rationalLength().compareTo(eps) < 0) { 423 return d; 424 } 425 ComplexRing<BigDecimal> cr = d.ring; 426 Complex<C> sw = rt.getSW(); 427 BigDecimal swr = new BigDecimal(sw.getRe().getRational()); 428 BigDecimal swi = new BigDecimal(sw.getIm().getRational()); 429 Complex<BigDecimal> ll = new Complex<BigDecimal>(cr, swr, swi); 430 Complex<C> ne = rt.getNE(); 431 BigDecimal ner = new BigDecimal(ne.getRe().getRational()); 432 BigDecimal nei = new BigDecimal(ne.getIm().getRational()); 433 Complex<BigDecimal> ur = new Complex<BigDecimal>(cr, ner, nei); 434 435 BigDecimal e = new BigDecimal(eps.getRational()); 436 Complex<BigDecimal> q = new Complex<BigDecimal>(cr, new BigDecimal("0.25")); 437 e = e.multiply(d.norm().getRe()); // relative error 438 //System.out.println("e = " + e); 439 440 // polynomials with decimal coefficients 441 GenPolynomialRing<Complex<BigDecimal>> dfac = new GenPolynomialRing<Complex<BigDecimal>>(cr, f.ring); 442 GenPolynomial<Complex<BigDecimal>> df = PolyUtil.<C> complexDecimalFromRational(dfac, f); 443 GenPolynomial<Complex<C>> fp = PolyUtil.<Complex<C>> baseDeriviative(f); 444 GenPolynomial<Complex<BigDecimal>> dfp = PolyUtil.<C> complexDecimalFromRational(dfac, fp); 445 446 // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n) 447 int i = 0; 448 final int MITER = 50; 449 int dir = -1; 450 while (i++ < MITER) { 451 Complex<BigDecimal> fx = PolyUtil.<Complex<BigDecimal>> evaluateMain(cr, df, d); // f(d) 452 //BigDecimal fs = fx.norm().getRe(); 453 //System.out.println("fs = " + fs); 454 if (fx.isZERO()) { 455 return d; 456 } 457 Complex<BigDecimal> fpx = PolyUtil.<Complex<BigDecimal>> evaluateMain(cr, dfp, d); // f'(d) 458 if (fpx.isZERO()) { 459 throw new NoConvergenceException("zero deriviative should not happen"); 460 } 461 Complex<BigDecimal> x = fx.divide(fpx); 462 Complex<BigDecimal> dx = d.subtract(x); 463 //System.out.println("dx = " + dx); 464 if (d.subtract(dx).norm().getRe().compareTo(e) <= 0) { 465 return dx; 466 } 467 // if ( false ) { // not useful: 468 // Complex<BigDecimal> fxx = PolyUtil.<Complex<BigDecimal>> evaluateMain(cr, df, dx); // f(dx) 469 // //System.out.println("fxx = " + fxx); 470 // BigDecimal fsx = fxx.norm().getRe(); 471 // System.out.println("fsx = " + fsx); 472 // while ( fsx.compareTo( fs ) >= 0 ) { 473 // System.out.println("trying to increase f(d) "); 474 // if ( i++ > MITER ) { // dx > right: dx - right > 0 475 // throw new NoConvergenceException("no convergence after " + i + " steps"); 476 // } 477 // x = x.multiply(q); // x * 1/4 478 // dx = d.subtract(x); 479 // //System.out.println(" x = " + x); 480 // System.out.println("dx = " + dx); 481 // fxx = PolyUtil.<Complex<BigDecimal>> evaluateMain(cr, df, dx); // f(dx) 482 // //System.out.println("fxx = " + fxx); 483 // fsx = fxx.norm().getRe(); 484 // System.out.println("fsx = " + fsx); 485 // } 486 // } 487 // check interval bounds 488 while (dx.getRe().compareTo(ll.getRe()) < 0 || dx.getIm().compareTo(ll.getIm()) < 0 489 || dx.getRe().compareTo(ur.getRe()) > 0 || dx.getIm().compareTo(ur.getIm()) > 0) { 490 // dx < ll: dx - ll < 0 491 // dx > ur: dx - ur > 0 492 if (i++ > MITER) { // dx > right: dx - right > 0 493 throw new NoConvergenceException("no convergence after " + i + " steps"); 494 } 495 if (i > MITER / 2 && dir == 0) { 496 Complex<C> cc = rt.getCenter(); 497 Rectangle<C> nrt = rt.exchangeSE(cc); 498 Complex<BigDecimal> sd = nrt.getDecimalCenter(); 499 d = sd; 500 x = cr.getZERO(); 501 logger.info("trying new SE starting point " + d); 502 i = 0; 503 dir = 1; 504 } 505 if (i > MITER / 2 && dir == 1) { 506 Complex<C> cc = rt.getCenter(); 507 Rectangle<C> nrt = rt.exchangeNW(cc); 508 Complex<BigDecimal> sd = nrt.getDecimalCenter(); 509 d = sd; 510 x = cr.getZERO(); 511 logger.info("trying new NW starting point " + d); 512 i = 0; 513 dir = 2; 514 } 515 if (i > MITER / 2 && dir == 2) { 516 Complex<C> cc = rt.getCenter(); 517 Rectangle<C> nrt = rt.exchangeSW(cc); 518 Complex<BigDecimal> sd = nrt.getDecimalCenter(); 519 d = sd; 520 x = cr.getZERO(); 521 logger.info("trying new SW starting point " + d); 522 i = 0; 523 dir = 3; 524 } 525 if (i > MITER / 2 && dir == 3) { 526 Complex<C> cc = rt.getCenter(); 527 Rectangle<C> nrt = rt.exchangeNE(cc); 528 Complex<BigDecimal> sd = nrt.getDecimalCenter(); 529 d = sd; 530 x = cr.getZERO(); 531 logger.info("trying new NE starting point " + d); 532 i = 0; 533 dir = 4; 534 } 535 if (i > MITER / 2 && (dir == -1 || dir == 4 || dir == 5)) { 536 Complex<C> sr = rt.randomPoint(); 537 BigDecimal srr = new BigDecimal(sr.getRe().getRational()); 538 BigDecimal sri = new BigDecimal(sr.getIm().getRational()); 539 Complex<BigDecimal> sd = new Complex<BigDecimal>(cr, srr, sri); 540 d = sd; 541 x = cr.getZERO(); 542 logger.info("trying new random starting point " + d); 543 if (dir == -1) { 544 i = 0; 545 dir = 0; 546 } else if (dir == 4) { 547 i = 0; 548 dir = 5; 549 } else { 550 //i = 0; 551 dir = 6; // end 552 } 553 } 554 x = x.multiply(q); // x * 1/4 555 dx = d.subtract(x); 556 //System.out.println(" x = " + x); 557 //System.out.println("dx = " + dx); 558 } 559 d = dx; 560 } 561 throw new NoConvergenceException("no convergence after " + i + " steps"); 562 } 563 564 565 /** 566 * List of decimal approximations of complex roots of complex polynomial. 567 * @param a univariate complex polynomial. 568 * @param eps length for refinement. 569 * @return list of complex decimal root approximations to desired precision. 570 */ 571 @SuppressWarnings({"cast","unchecked"}) 572 public List<Complex<BigDecimal>> approximateRoots(GenPolynomial<Complex<C>> a, BigRational eps) { 573 ComplexRing<C> cr = (ComplexRing<C>) a.ring.coFac; 574 SortedMap<GenPolynomial<Complex<C>>, Long> sa = engine.squarefreeFactors(a); 575 List<Complex<BigDecimal>> roots = new ArrayList<Complex<BigDecimal>>(); 576 for (Map.Entry<GenPolynomial<Complex<C>>, Long> me : sa.entrySet()) { 577 GenPolynomial<Complex<C>> p = me.getKey(); 578 List<Complex<BigDecimal>> rf = null; 579 if (p.degree(0) <= 1) { 580 Complex<C> tc = p.trailingBaseCoefficient(); 581 tc = tc.negate(); 582 BigDecimal rr = new BigDecimal(tc.getRe().getRational()); 583 BigDecimal ri = new BigDecimal(tc.getIm().getRational()); 584 ComplexRing<BigDecimal> crf = new ComplexRing<BigDecimal>(rr); 585 Complex<BigDecimal> r = new Complex<BigDecimal>(crf, rr, ri); 586 rf = new ArrayList<Complex<BigDecimal>>(1); 587 rf.add(r); 588 } else { 589 Complex<C> Mb = rootBound(p); 590 C M = Mb.getRe(); 591 C M1 = M.sum(M.factory().fromInteger(1)); // asymmetric to origin 592 if (debug) { 593 logger.info("rootBound = " + M); 594 } 595 Complex<C>[] corner = (Complex<C>[]) new Complex[4]; 596 corner[0] = new Complex<C>(cr, M1.negate(), M); // nw 597 corner[1] = new Complex<C>(cr, M1.negate(), M1.negate()); // sw 598 corner[2] = new Complex<C>(cr, M, M1.negate()); // se 599 corner[3] = new Complex<C>(cr, M, M); // ne 600 Rectangle<C> rect = new Rectangle<C>(corner); 601 List<Rectangle<C>> rs = null; 602 try { 603 rs = complexRoots(rect, p); 604 } catch (InvalidBoundaryException e) { 605 throw new RuntimeException("this should never happen " + e); 606 } 607 rf = new ArrayList<Complex<BigDecimal>>(rs.size()); 608 for (Rectangle<C> r : rs) { 609 Complex<BigDecimal> rr = null; 610 while (rr == null) { 611 try { 612 rr = approximateRoot(r, p, eps); 613 rf.add(rr); 614 } catch (NoConvergenceException e) { 615 // fall back to exact algorithm 616 BigRational len = r.rationalLength(); 617 len = len.multiply(new BigRational(1, 1000)); 618 try { 619 r = complexRootRefinement(r, p, len); 620 logger.info("fall back rootRefinement = " + r); 621 //System.out.println("len = " + len); 622 } catch (InvalidBoundaryException ee) { 623 throw new RuntimeException("this should never happen " + ee); 624 } 625 } 626 } 627 } 628 } 629 long e = me.getValue(); // sa.get(p); 630 for (int i = 0; i < e; i++) { // add with multiplicity 631 roots.addAll(rf); 632 } 633 } 634 return roots; 635 } 636 637 638 /** 639 * Copy the specified array. 640 * @param original array. 641 * @param newLength new array length. 642 * @return copy of this. 643 */ 644 public Complex[] copyOfComplex(Complex[] original, int newLength) { 645 Complex[] copy = new Complex[newLength]; 646 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); 647 return copy; 648 } 649 650 651 /** 652 * Invariant rectangle for algebraic number magnitude. 653 * @param rect root isolating rectangle for f which contains exactly one 654 * root. 655 * @param f univariate polynomial, non-zero. 656 * @param g univariate polynomial, gcd(f,g) == 1. 657 * @param eps length limit for rectangle length. 658 * @return v with v a new rectangle contained in rect such that |g(a) - 659 * g(b)| < eps for a, b in v in rect. 660 */ 661 public Rectangle<C> invariantMagnitudeRectangle(Rectangle<C> rect, GenPolynomial<Complex<C>> f, 662 GenPolynomial<Complex<C>> g, BigRational eps) throws InvalidBoundaryException { 663 Rectangle<C> v = rect; 664 if (g == null || g.isZERO()) { 665 return v; 666 } 667 if (g.isConstant()) { 668 return v; 669 } 670 if (f == null || f.isZERO() || f.isConstant()) { // ? 671 return v; 672 } 673 GenPolynomial<Complex<C>> gp = PolyUtil.<Complex<C>> baseDeriviative(g); 674 //System.out.println("g = " + g); 675 //System.out.println("gp = " + gp); 676 BigRational B = magnitudeBound(rect, gp).getRational(); 677 //System.out.println("B = " + B + " : " + B.getClass()); 678 679 BigRational len = v.rationalLength(); 680 BigRational half = new BigRational(1, 2); 681 682 BigRational vlen = v.rationalLength(); 683 vlen = vlen.multiply(vlen); 684 //eps = eps.multiply(eps); 685 //System.out.println("v = " + v); 686 //System.out.println("vlen = " + vlen); 687 while (B.multiply(vlen).compareTo(eps) >= 0) { // TODO: test squared 688 len = len.multiply(half); 689 v = complexRootRefinement(v, f, len); 690 //System.out.println("v = " + v); 691 vlen = v.rationalLength(); 692 vlen = vlen.multiply(vlen); 693 //System.out.println("vlen = " + vlen); 694 } 695 //System.out.println("vlen = " + vlen); 696 return v; 697 } 698 699 700 /** 701 * Complex algebraic number magnitude. 702 * @param rect root isolating rectangle for f which contains exactly one 703 * root, with rect such that |g(a) - g(b)| < eps for a, b in 704 * rect. 705 * @param f univariate polynomial, non-zero. 706 * @param g univariate polynomial, gcd(f,g) == 1. 707 * @return g(rect) . 708 */ 709 public Complex<C> complexRectangleMagnitude(Rectangle<C> rect, GenPolynomial<Complex<C>> f, 710 GenPolynomial<Complex<C>> g) { 711 if (g.isZERO() || g.isConstant()) { 712 return g.leadingBaseCoefficient(); 713 } 714 RingFactory<Complex<C>> cfac = f.ring.coFac; 715 //System.out.println("cfac = " + cfac + " : " + cfac.getClass()); 716 Complex<C> c = rect.getCenter(); 717 Complex<C> ev = PolyUtil.<Complex<C>> evaluateMain(cfac, g, c); 718 return ev; 719 } 720 721 722 /** 723 * Complex algebraic number magnitude. 724 * @param rect root isolating rectangle for f which contains exactly one 725 * root, with rect such that |g(a) - g(b)| < eps for a, b in 726 * rect. 727 * @param f univariate polynomial, non-zero. 728 * @param g univariate polynomial, gcd(f,g) == 1. 729 * @param eps length limit for rectangle length. 730 * @return g(rect) . 731 */ 732 public Complex<C> complexMagnitude(Rectangle<C> rect, GenPolynomial<Complex<C>> f, 733 GenPolynomial<Complex<C>> g, BigRational eps) throws InvalidBoundaryException { 734 if (g.isZERO() || g.isConstant()) { 735 return g.leadingBaseCoefficient(); 736 } 737 Rectangle<C> v = invariantMagnitudeRectangle(rect, f, g, eps); 738 //System.out.println("ref = " + ref); 739 return complexRectangleMagnitude(v, f, g); 740 } 741 742}