001/* 002 * $Id$ 003 */ 004 005package edu.jas.root; 006 007 008import java.util.ArrayList; 009import java.util.Collections; 010import java.util.List; 011 012import junit.framework.Test; 013import junit.framework.TestCase; 014import junit.framework.TestSuite; 015 016import edu.jas.arith.BigDecimal; 017import edu.jas.arith.BigRational; 018import edu.jas.arith.Roots; 019import edu.jas.poly.GenPolynomial; 020import edu.jas.poly.GenPolynomialRing; 021import edu.jas.poly.TermOrder; 022import edu.jas.structure.Power; 023import edu.jas.structure.RingFactory; 024 025 026/** 027 * RealRoot tests with JUnit. 028 * @author Heinz Kredel 029 */ 030 031public class RealRootTest extends TestCase { 032 033 034 /** 035 * main. 036 */ 037 public static void main(String[] args) { 038 junit.textui.TestRunner.run(suite()); 039 } 040 041 042 /** 043 * Constructs a <CODE>RealRootTest</CODE> object. 044 * @param name String. 045 */ 046 public RealRootTest(String name) { 047 super(name); 048 } 049 050 051 /** 052 */ 053 public static Test suite() { 054 TestSuite suite = new TestSuite(RealRootTest.class); 055 return suite; 056 } 057 058 059 TermOrder to = new TermOrder(TermOrder.INVLEX); 060 061 062 GenPolynomialRing<BigRational> dfac; 063 064 065 BigRational ai, bi, ci, di, ei, eps; 066 067 068 GenPolynomial<BigRational> a, b, c, d, e; 069 070 071 int rl = 1; 072 073 074 int kl = 5; 075 076 077 int ll = 7; 078 079 080 int el = 7; 081 082 083 float q = 0.7f; 084 085 086 @Override 087 protected void setUp() { 088 a = b = c = d = e = null; 089 ai = bi = ci = di = ei = null; 090 String[] vars = new String[] { "x" }; 091 dfac = new GenPolynomialRing<BigRational>(new BigRational(1), rl, to, vars); 092 // eps = new BigRational(1L,1000000L*1000000L*1000000L); 093 eps = Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION); 094 } 095 096 097 @Override 098 protected void tearDown() { 099 a = b = c = d = e = null; 100 ai = bi = ci = di = ei = null; 101 dfac = null; 102 eps = null; 103 } 104 105 106 /** 107 * Test Sturm sequence. 108 */ 109 public void testSturmSequence() { 110 a = dfac.random(kl, ll, el, q); 111 //System.out.println("a = " + a); 112 113 RealRootsSturm<BigRational> rrs = new RealRootsSturm<BigRational>(); 114 115 List<GenPolynomial<BigRational>> S = rrs.sturmSequence(a); 116 //System.out.println("S = " + S); 117 118 try { 119 b = a.remainder(S.get(0)); 120 } catch (Exception e) { 121 fail("not S(0)|f " + e); 122 } 123 assertTrue("a mod S(0) == 0 ", b.isZERO()); 124 125 assertTrue("S(-1) == 1 ", S.get(S.size() - 1).isConstant()); 126 } 127 128 129 /** 130 * Test root bound. 131 */ 132 public void testRootBound() { 133 a = dfac.random(kl, ll, el, q); 134 //System.out.println("a = " + a); 135 136 RealRootsAbstract<BigRational> rr = new RealRootsSturm<BigRational>(); 137 138 // used root bound 139 BigRational M = rr.realRootBound(a); 140 //System.out.println("M = " + M); 141 assertTrue("M >= 1 ", M.compareTo(BigRational.ONE) >= 0); 142 Interval<BigRational> v1 = new Interval<BigRational>(M.negate(), M); 143 long r1 = rr.realRootCount(v1, a); 144 //System.out.println("v1 = " + v1 + ", r1 = " + r1); 145 146 a = a.monic(); 147 //System.out.println("a = " + a); 148 BigDecimal ar = M.getDecimal(); 149 //System.out.println("ar = " + ar); 150 assertTrue("ar >= 1 ", ar.compareTo(BigDecimal.ONE) >= 0); 151 152 // maxNorm root bound 153 BigRational mr = a.maxNorm().getRational().sum(BigRational.ONE); 154 BigDecimal dr = mr.getDecimal(); 155 //System.out.println("dr = " + dr); 156 //assertTrue("ar >= maxNorm(a): " + (ar.subtract(dr)), ar.compareTo(dr) >= 0); 157 Interval<BigRational> v2 = new Interval<BigRational>(mr.negate(), mr); 158 long r2 = rr.realRootCount(v2,a); 159 //System.out.println("v2 = " + v2 + ", r2 = " + r2); 160 assertTrue("r1 == r2: " + (r2-r1), r1 == r2); 161 162 // squareNorm root bound 163 BigRational qr = a.squareNorm().getRational(); 164 BigDecimal ir = Roots.sqrt(qr.getDecimal()); 165 //qr = Roots.sqrt(qr); 166 //System.out.println("ir = " + ir); 167 //assertTrue("ar >= squareNorm(a): " + (ar.subtract(ir)), ar.compareTo(ir) >= 0); 168 Interval<BigRational> v3 = new Interval<BigRational>(qr.negate(), qr); 169 long r3 = rr.realRootCount(v3,a); 170 //System.out.println("v3 = " + v3 + ", r3 = " + r3); 171 assertTrue("r1 == r3: " + (r3-r1), r1 == r3); 172 173 // sumNorm root bound 174 BigRational pr = a.sumNorm().getRational(); 175 BigDecimal sr = pr.getDecimal(); 176 //System.out.println("sr = " + sr); 177 //assertTrue("ar >= squareNorm(a): " + (ar.subtract(sr)), ar.compareTo(sr) >= 0); 178 Interval<BigRational> v4 = new Interval<BigRational>(pr.negate(), pr); 179 long r4 = rr.realRootCount(v4,a); 180 //System.out.println("v4 = " + v4 + ", r4 = " + r4); 181 assertTrue("r1 == r4: " + (r4-r1), r1 == r4); 182 183 // minimal root bound 184 BigDecimal dri = dr.sum(BigDecimal.ONE).inverse(); 185 //System.out.println("dri = " + dri + ", sign(dri) = " + dri.signum()); 186 assertTrue("minimal root > 0: " + dri, dri.signum() > 0); 187 BigDecimal mri = rr.realMinimalRootBound(a).getDecimal(); 188 //System.out.println("mri = " + mri + ", sign(mri) = " + mri.signum()); 189 BigDecimal s = dri.subtract(mri).abs(); 190 eps = eps.multiply(BigRational.ONE.fromInteger(10)); 191 //System.out.println("s = " + s + ", eps = " + eps.getDecimal()); 192 assertTrue("minimal root: " + dri, s.compareTo(eps.getDecimal()) < 0); 193 194 // minimal root separation 195 long n = a.degree(); 196 if (n > 0) { 197 BigDecimal sep = sr.sum(BigDecimal.ONE).power(2*n).multiply(sr.fromInteger(n).power(n+1)).inverse(); 198 //System.out.println("sep = " + sep + ", sign(sep) = " + sep.signum()); 199 assertTrue("separation(a) > 0: " + sep, sep.signum() > 0); 200 BigDecimal sri = rr.realMinimalRootSeparation(a).getDecimal(); 201 BigDecimal ss = sep.subtract(sri).abs(); 202 assertTrue("minimal separation: " + sep, ss.compareTo(eps.getDecimal()) < 0); 203 } 204 } 205 206 207 /** 208 * Test real root isolation. 209 */ 210 public void testRealRootIsolation() { 211 a = dfac.random(kl, ll * 2, el * 2, q); 212 //a = a.multiply( dfac.univariate(0) ); 213 //System.out.println("a = " + a); 214 215 RealRoots<BigRational> rr = new RealRootsSturm<BigRational>(); 216 217 List<Interval<BigRational>> R = rr.realRoots(a); 218 //System.out.println("R = " + R); 219 //assertTrue("#roots >= 0 ", R.size() >= 0); 220 assertTrue("#roots >= 0 ", R != null); 221 } 222 223 224 /** 225 * Test Thom lemma real root sign sequence. 226 */ 227 public void testRealRootSignSequence() { 228 a = dfac.random(kl, ll * 2, el * 2, q); 229 if (a.degree() % 2 == 0) { 230 a = a.multiply( dfac.univariate(0).subtract(dfac.getONE()) ); 231 } 232 //System.out.println("a = " + a); 233 RealRootsAbstract<BigRational> rr = new RealRootsSturm<BigRational>(); 234 235 List<Interval<BigRational>> R = rr.realRoots(a); 236 //System.out.println("R = " + R); 237 //assertTrue("#roots >= 0 ", R.size() >= 0); 238 assertTrue("#roots >= 0 ", R != null); 239 240 int l = R.size(); 241 Interval<BigRational> v = R.get(l-1); 242 Interval<BigRational> u = R.get(0); 243 if (u.left.isZERO() && u.right.isZERO()) { 244 Interval<BigRational> w = v; 245 v = u; 246 u = w; 247 } 248 Interval<BigRational> vm = new Interval<BigRational>(u.left,v.right); 249 //System.out.println("v = " + v); 250 //System.out.println("u = " + u); 251 //System.out.println("vm = " + vm); 252 long rc = rr.realRootCount(vm,a); 253 //System.out.println("rc = " + rc); 254 assertTrue("root number: R = " + R + ", rc = " + rc, rc == l); 255 long rn = rr.realRootNumber(a,vm); 256 assertTrue("root number == " + rn, rn == l); 257 258 long d = a.degree(); 259 List<GenPolynomial<BigRational>> fs = rr.fourierSequence(a); 260 //System.out.println("fs = " + fs); 261 assertTrue("len(fs) == " + (d+1-fs.size()), fs.size() == (d+1)); 262 263 //List<Integer> ss = rr.signSequence(a, v); 264 //System.out.println("ss = " + ss); 265 //assertTrue("len(ss) == " + (d-ss.size()), ss.size() == d); 266 for (Interval<BigRational> t : R) { 267 List<Integer> ss = rr.signSequence(a, t); 268 //System.out.println("ss = " + ss); 269 assertTrue("len(ss) == " + (d-ss.size()), ss.size() == d); 270 } 271 } 272 273 274 /** 275 * Test real root isolation Wilkinson polynomials. 276 * p = (x-0)*(x-1)*(x-2)*(x-3)*...*(x-n) 277 */ 278 public void testRealRootIsolationWilkinson() { 279 final int N = 10; 280 d = dfac.getONE(); 281 e = dfac.univariate(0); 282 283 List<Interval<BigRational>> Rn = new ArrayList<Interval<BigRational>>(N); 284 a = d; 285 for (int i = 0; i < N; i++) { 286 c = dfac.fromInteger(i); 287 Rn.add(new Interval<BigRational>(c.leadingBaseCoefficient())); 288 b = e.subtract(c); 289 a = a.multiply(b); 290 } 291 //System.out.println("a = " + a); 292 293 RealRoots<BigRational> rr = new RealRootsSturm<BigRational>(); 294 295 List<Interval<BigRational>> R = rr.realRoots(a); 296 //System.out.println("R = " + R); 297 298 assertTrue("#roots = " + N + " ", R.size() == N); 299 300 eps = eps.multiply(new BigRational("1/10")); 301 //System.out.println("eps = " + eps); 302 303 R = rr.refineIntervals(R, a, eps); 304 //System.out.println("R = " + R); 305 int i = 0; 306 for (Interval<BigRational> v : R) { 307 BigDecimal dd = v.toDecimal(); 308 BigDecimal di = Rn.get(i++).toDecimal(); 309 //System.out.println("v = " + dd); 310 //System.out.println("vi = " + di); 311 //System.out.println("|dd - di| < eps: " + dd.compareTo(di)); 312 assertTrue("|dd - di| < eps ", dd.compareTo(di) == 0); 313 } 314 } 315 316 317 /** 318 * Test real root isolation Wilkinson polynomials inverse. 319 * p = (x-1)*(x-1/2)*(x-1/3)*...*(x-1/n) 320 */ 321 public void testRealRootIsolationWilkinsonInverse() { 322 final int N = 9; 323 d = dfac.getONE(); 324 e = dfac.univariate(0); 325 326 List<Interval<BigRational>> Rn = new ArrayList<Interval<BigRational>>(N); 327 a = d; 328 for (int i = 1; i < N; i++) { // use only for i > 0, since reverse 329 c = dfac.fromInteger(i); 330 if (i != 0) { 331 c = d.divide(c); 332 } 333 Rn.add(new Interval<BigRational>(c.leadingBaseCoefficient())); 334 b = e.subtract(c); 335 a = a.multiply(b); 336 } 337 //System.out.println("a = " + a); 338 //System.out.println("Rn = " + Rn); 339 Collections.reverse(Rn); 340 //System.out.println("Rn = " + Rn); 341 342 RealRoots<BigRational> rr = new RealRootsSturm<BigRational>(); 343 344 List<Interval<BigRational>> R = rr.realRoots(a); 345 //System.out.println("R = " + R); 346 347 assertTrue("#roots = " + (N - 1) + " ", R.size() == (N - 1)); 348 349 eps = eps.multiply(new BigRational("1/100")); 350 //System.out.println("eps = " + eps); 351 352 R = rr.refineIntervals(R, a, eps); 353 //System.out.println("R = " + R); 354 int i = 0; 355 for (Interval<BigRational> v : R) { 356 BigDecimal dd = v.toDecimal(); //.sum(eps1); 357 BigDecimal di = Rn.get(i++).toDecimal(); 358 //System.out.println("v = " + dd); 359 //System.out.println("vi = " + di); 360 //System.out.println("|dd - di| < eps: " + dd.compareTo(di)); 361 assertTrue("|dd - di| < eps ", dd.compareTo(di) == 0); 362 } 363 } 364 365 366 /** 367 * Test real algebraic number sign. 368 */ 369 public void testRealAlgebraicNumberSign() { 370 d = dfac.fromInteger(2); 371 e = dfac.univariate(0); 372 373 a = e.multiply(e); 374 // a = a.multiply(e).multiply(e).multiply(e); 375 a = a.subtract(d); // x^2 -2 376 //System.out.println("a = " + a); 377 378 RealRoots<BigRational> rr = new RealRootsSturm<BigRational>(); 379 380 ai = new BigRational(1); 381 bi = new BigRational(2); 382 Interval<BigRational> iv = new Interval<BigRational>(ai, bi); 383 //System.out.println("iv = " + iv); 384 assertTrue("sign change", rr.signChange(iv, a)); 385 386 b = dfac.random(kl, (int) a.degree() + 1, (int) a.degree(), 1.0f); 387 //b = dfac.getZERO(); 388 //b = dfac.random(kl,ll,el,q); 389 //b = b.multiply(b); 390 //b = b.abs().negate(); 391 //System.out.println("b = " + b); 392 if (b.isZERO()) { 393 int s = rr.realSign(iv, a, b); 394 assertTrue("algebraic sign", s == 0); 395 return; 396 } 397 398 int as = rr.realSign(iv, a, b); 399 //System.out.println("as = " + as); 400 // how to test? 401 int asn = rr.realSign(iv, a, b.negate()); 402 //System.out.println("asn = " + asn); 403 assertTrue("algebraic sign", as != asn); 404 405 iv = new Interval<BigRational>(bi.negate(), ai.negate()); 406 //System.out.println("iv = " + iv); 407 assertTrue("sign change", rr.signChange(iv, a)); 408 409 int as1 = rr.realSign(iv, a, b); 410 //System.out.println("as1 = " + as1); 411 // how to test? 412 int asn1 = rr.realSign(iv, a, b.negate()); 413 //System.out.println("asn1 = " + asn1); 414 assertTrue("algebraic sign", as1 != asn1); 415 416 assertTrue("algebraic sign", as * as1 == asn * asn1); 417 } 418 419 420 /** 421 * Test real root isolation and decimal refinement of Wilkinson polynomials. 422 * p = (x-0)*(x-1)*(x-2)*(x-3)*...*(x-n) 423 */ 424 public void testRealRootIsolationDecimalWilkinson() { 425 final int N = 10; 426 d = dfac.getONE(); 427 e = dfac.univariate(0); 428 429 List<Interval<BigRational>> Rn = new ArrayList<Interval<BigRational>>(N); 430 a = d; 431 for (int i = 0; i < N; i++) { 432 c = dfac.fromInteger(i); 433 Rn.add(new Interval<BigRational>(c.leadingBaseCoefficient())); 434 b = e.subtract(c); 435 a = a.multiply(b); 436 } 437 //System.out.println("a = " + a); 438 439 RealRootsAbstract<BigRational> rr = new RealRootsSturm<BigRational>(); 440 441 List<Interval<BigRational>> R = rr.realRoots(a); 442 //System.out.println("R = " + R); 443 444 assertTrue("#roots = " + N + " ", R.size() == N); 445 446 eps = eps.multiply(new BigRational(100000)); 447 //System.out.println("eps = " + eps); 448 BigDecimal eps1 = new BigDecimal(eps); 449 BigDecimal eps2 = eps1.multiply(new BigDecimal("100")); 450 //System.out.println("eps1 = " + eps1); 451 //System.out.println("eps2 = " + eps2); 452 453 try { 454 int i = 0; 455 for (Interval<BigRational> v : R) { 456 //System.out.println("v = " + v); 457 BigDecimal dd = rr.approximateRoot(v,a,eps); 458 BigDecimal di = Rn.get(i++).toDecimal(); 459 //System.out.println("di = " + di); 460 //System.out.println("dd = " + dd); 461 assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); 462 } 463 } catch (NoConvergenceException e) { 464 fail(e.toString()); 465 } 466 } 467 468 469 /** 470 * Test real root isolation and decimal refinement of Wilkinson polynomials, inverse roots. 471 * p = (x-1)*(x-1/2)*(x-1/3)*...*(x-1/n) 472 */ 473 public void testRealRootIsolationDecimalWilkinsonInverse() { 474 final int N = 10; 475 d = dfac.getONE(); 476 e = dfac.univariate(0); 477 478 List<Interval<BigRational>> Rn = new ArrayList<Interval<BigRational>>(N); 479 a = d; 480 for (int i = 1; i < N; i++) { // use only for i > 0, since reverse 481 c = dfac.fromInteger(i); 482 if (i != 0) { 483 c = d.divide(c); 484 } 485 Rn.add(new Interval<BigRational>(c.leadingBaseCoefficient())); 486 b = e.subtract(c); 487 a = a.multiply(b); 488 } 489 //System.out.println("a = " + a); 490 //System.out.println("Rn = " + Rn); 491 Collections.reverse(Rn); 492 //System.out.println("Rn = " + Rn); 493 494 RealRootsAbstract<BigRational> rr = new RealRootsSturm<BigRational>(); 495 496 List<Interval<BigRational>> R = rr.realRoots(a); 497 //System.out.println("R = " + R); 498 499 assertTrue("#roots = " + (N - 1) + " ", R.size() == (N - 1)); 500 501 eps = eps.multiply(new BigRational(1000000)); 502 //System.out.println("eps = " + eps); 503 BigDecimal eps1 = new BigDecimal(eps); 504 BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); 505 //System.out.println("eps1 = " + eps1); 506 //System.out.println("eps2 = " + eps2); 507 508 try { 509 int i = 0; 510 for (Interval<BigRational> v : R) { 511 //System.out.println("v = " + v); 512 BigDecimal dd = rr.approximateRoot(v,a,eps); 513 BigDecimal di = Rn.get(i++).toDecimal(); 514 //System.out.println("di = " + di); 515 //System.out.println("dd = " + dd); 516 assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); 517 } 518 } catch (NoConvergenceException e) { 519 fail(e.toString()); 520 } 521 } 522 523 524 /** 525 * Test real root isolation and decimal refinement of Wilkinson polynomials, all roots. 526 * p = (x-0)*(x-1)*(x-2)*(x-3)*...*(x-n) 527 */ 528 public void testRealRootIsolationDecimalWilkinsonAll() { 529 final int N = 10; 530 d = dfac.getONE(); 531 e = dfac.univariate(0); 532 533 List<Interval<BigRational>> Rn = new ArrayList<Interval<BigRational>>(N); 534 a = d; 535 for (int i = 0; i < N; i++) { 536 c = dfac.fromInteger(i); 537 Rn.add(new Interval<BigRational>(c.leadingBaseCoefficient())); 538 b = e.subtract(c); 539 a = a.multiply(b); 540 } 541 //System.out.println("a = " + a); 542 543 RealRootsAbstract<BigRational> rr = new RealRootsSturm<BigRational>(); 544 545 eps = eps.multiply(new BigRational(10000)); 546 //System.out.println("eps = " + eps); 547 BigDecimal eps1 = new BigDecimal(eps); 548 BigDecimal eps2 = eps1.multiply(new BigDecimal("100")); 549 //System.out.println("eps1 = " + eps1); 550 //System.out.println("eps2 = " + eps2); 551 552 List<BigDecimal> R = null; 553 R = rr.approximateRoots(a,eps); 554 //System.out.println("R = " + R); 555 assertTrue("#roots = " + N + " ", R.size() == N); 556 557 int i = 0; 558 for (BigDecimal dd : R) { 559 //System.out.println("dd = " + dd); 560 BigDecimal di = Rn.get(i++).toDecimal(); 561 //System.out.println("di = " + di); 562 assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); 563 } 564 boolean t = rr.isApproximateRoot(R,a,eps); 565 assertTrue("some |a(dd)| < eps ", t); 566 } 567 568 569 /** 570 * Test real root isolation and decimal refinement of Wilkinson polynomials, inverse roots, all roots. 571 * p = (x-1)*(x-1/2)*(x-1/3)*...*(x-1/n) 572 */ 573 public void testRealRootIsolationDecimalWilkinsonInverseAll() { 574 final int N = 10; 575 d = dfac.getONE(); 576 e = dfac.univariate(0); 577 578 List<Interval<BigRational>> Rn = new ArrayList<Interval<BigRational>>(N); 579 a = d; 580 for (int i = 1; i < N; i++) { // use only for i > 0, since reverse 581 c = dfac.fromInteger(i); 582 if (i != 0) { 583 c = d.divide(c); 584 } 585 Rn.add(new Interval<BigRational>(c.leadingBaseCoefficient())); 586 b = e.subtract(c); 587 a = a.multiply(b); 588 } 589 //System.out.println("a = " + a); 590 //System.out.println("Rn = " + Rn); 591 Collections.reverse(Rn); 592 //System.out.println("Rn = " + Rn); 593 594 RealRootsAbstract<BigRational> rr = new RealRootsSturm<BigRational>(); 595 596 eps = eps.multiply(new BigRational(1000000)); 597 //System.out.println("eps = " + eps); 598 BigDecimal eps1 = new BigDecimal(eps); 599 BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); 600 //System.out.println("eps1 = " + eps1); 601 //System.out.println("eps2 = " + eps2); 602 603 List<BigDecimal> R = null; 604 R = rr.approximateRoots(a,eps); 605 //System.out.println("R = " + R); 606 assertTrue("#roots = " + (N - 1) + " ", R.size() == (N - 1)); 607 608 int i = 0; 609 for (BigDecimal dd : R) { 610 //System.out.println("dd = " + dd); 611 BigDecimal di = Rn.get(i++).toDecimal(); 612 //System.out.println("di = " + di); 613 assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); 614 } 615 boolean t = rr.isApproximateRoot(R,a,eps); 616 assertTrue("some |a(dd)| < eps ", t); 617 } 618 619}