001/* 002 * $Id$ 003 */ 004 005package edu.jas.poly; 006 007 008import org.apache.logging.log4j.LogManager; 009import org.apache.logging.log4j.Logger; 010 011import edu.jas.arith.BigComplex; 012import edu.jas.arith.BigDecimal; 013import edu.jas.arith.BigInteger; 014import edu.jas.arith.BigRational; 015import edu.jas.structure.GcdRingElem; 016import edu.jas.structure.RingElem; 017import edu.jas.structure.StarRingElem; 018 019 020/** 021 * Generic Complex class implementing the RingElem interface. Objects of this 022 * class are immutable. 023 * @param <C> base type of RingElem (for complex polynomials). 024 * @author Heinz Kredel 025 */ 026public class Complex<C extends RingElem<C>> implements StarRingElem<Complex<C>>, GcdRingElem<Complex<C>> { 027 028 029 private static final Logger logger = LogManager.getLogger(Complex.class); 030 031 032 private static final boolean debug = logger.isDebugEnabled(); 033 034 035 /** 036 * Complex class factory data structure. 037 */ 038 public final ComplexRing<C> ring; 039 040 041 /** 042 * Real part of the data structure. 043 */ 044 protected final C re; 045 046 047 /** 048 * Imaginary part of the data structure. 049 */ 050 protected final C im; 051 052 053 /** 054 * The constructor creates a Complex object from two C objects as real and 055 * imaginary part. 056 * @param ring factory for Complex objects. 057 * @param r real part. 058 * @param i imaginary part. 059 */ 060 public Complex(ComplexRing<C> ring, C r, C i) { 061 this.ring = ring; 062 re = r; 063 im = i; 064 } 065 066 067 /** 068 * The constructor creates a Complex object from a C object as real part, 069 * the imaginary part is set to 0. 070 * @param r real part. 071 */ 072 public Complex(ComplexRing<C> ring, C r) { 073 this(ring, r, ring.ring.getZERO()); 074 } 075 076 077 /** 078 * The constructor creates a Complex object from a long element as real 079 * part, the imaginary part is set to 0. 080 * @param r real part. 081 */ 082 public Complex(ComplexRing<C> ring, long r) { 083 this(ring, ring.ring.fromInteger(r)); 084 } 085 086 087 /** 088 * The constructor creates a Complex object with real part 0 and imaginary 089 * part 0. 090 */ 091 public Complex(ComplexRing<C> ring) { 092 this(ring, ring.ring.getZERO()); 093 } 094 095 096 /** 097 * The constructor creates a Complex object from a String representation. 098 * @param s string of a Complex. 099 * @throws NumberFormatException 100 */ 101 public Complex(ComplexRing<C> ring, String s) throws NumberFormatException { 102 this.ring = ring; 103 if (s == null || s.length() == 0) { 104 re = ring.ring.getZERO(); 105 im = ring.ring.getZERO(); 106 return; 107 } 108 s = s.trim(); 109 int i = s.indexOf("i"); 110 if (i < 0) { 111 re = ring.ring.parse(s); 112 im = ring.ring.getZERO(); 113 return; 114 } 115 String sr = ""; 116 if (i > 0) { 117 sr = s.substring(0, i); 118 } 119 String si = ""; 120 if (i < s.length()) { 121 si = s.substring(i + 1, s.length()); 122 } 123 re = ring.ring.parse(sr.trim()); 124 im = ring.ring.parse(si.trim()); 125 } 126 127 128 /** 129 * Get the corresponding element factory. 130 * @return factory for this Element. 131 * @see edu.jas.structure.Element#factory() 132 */ 133 public ComplexRing<C> factory() { 134 return ring; 135 } 136 137 138 /** 139 * Get the real part. 140 * @return re. 141 */ 142 public C getRe() { 143 return re; 144 } 145 146 147 /** 148 * Get the imaginary part. 149 * @return im. 150 */ 151 public C getIm() { 152 return im; 153 } 154 155 156 /** 157 * Copy this. 158 * @see edu.jas.structure.Element#copy() 159 */ 160 @Override 161 public Complex<C> copy() { 162 return new Complex<C>(ring, re, im); 163 } 164 165 166 /** 167 * Get the String representation. 168 */ 169 @Override 170 public String toString() { 171 String s = re.toString(); 172 if (im.isZERO()) { 173 return s; 174 } 175 s += "i" + im; 176 return s; 177 } 178 179 180 /** 181 * Get a scripting compatible string representation. 182 * @return script compatible representation for this Element. 183 * @see edu.jas.structure.Element#toScript() 184 */ 185 @Override 186 public String toScript() { 187 // Python case 188 StringBuffer s = new StringBuffer(); 189 if (im.isZERO()) { 190 s.append(re.toScript()); 191 } else { 192 C mi = im; 193 //s.append(""); 194 if (!re.isZERO()) { 195 s.append(re.toScript()); 196 if (mi.signum() > 0) { 197 s.append(" + "); 198 } else { 199 s.append(" - "); 200 mi = mi.negate(); 201 } 202 } 203 if (mi.isONE()) { 204 s.append("I"); 205 } else { 206 s.append(mi.toScript()).append(" * I"); 207 } 208 s.append(""); 209 } 210 return s.toString(); 211 } 212 213 214 /** 215 * Get a scripting compatible string representation of the factory. 216 * @return script compatible representation for this ElemFactory. 217 * @see edu.jas.structure.Element#toScriptFactory() 218 */ 219 @Override 220 public String toScriptFactory() { 221 // Python case 222 return ring.toScript(); 223 } 224 225 226 /** 227 * Is Complex number zero. 228 * @return If this is 0 then true is returned, else false. 229 * @see edu.jas.structure.RingElem#isZERO() 230 */ 231 public boolean isZERO() { 232 return re.isZERO() && im.isZERO(); 233 } 234 235 236 /** 237 * Is Complex number one. 238 * @return If this is 1 then true is returned, else false. 239 * @see edu.jas.structure.RingElem#isONE() 240 */ 241 public boolean isONE() { 242 return re.isONE() && im.isZERO(); 243 } 244 245 246 /** 247 * Is Complex imaginary one. 248 * @return If this is i then true is returned, else false. 249 */ 250 public boolean isIMAG() { 251 return re.isZERO() && im.isONE(); 252 } 253 254 255 /** 256 * Is Complex unit element. 257 * @return If this is a unit then true is returned, else false. 258 * @see edu.jas.structure.RingElem#isUnit() 259 */ 260 public boolean isUnit() { 261 if (isZERO()) { 262 return false; 263 } 264 if (ring.isField()) { 265 return true; 266 } 267 return norm().re.isUnit(); 268 } 269 270 271 /** 272 * Comparison with any other object. 273 * @see java.lang.Object#equals(java.lang.Object) 274 */ 275 @Override 276 @SuppressWarnings("unchecked") 277 public boolean equals(Object b) { 278 if (b == null) { 279 return false; 280 } 281 if (!(b instanceof Complex)) { 282 return false; 283 } 284 Complex<C> bc = (Complex<C>) b; 285 if (!ring.equals(bc.ring)) { 286 return false; 287 } 288 return re.equals(bc.re) && im.equals(bc.im); 289 } 290 291 292 /** 293 * Hash code for this Complex. 294 * @see java.lang.Object#hashCode() 295 */ 296 @Override 297 public int hashCode() { 298 return 37 * re.hashCode() + im.hashCode(); 299 } 300 301 302 /** 303 * Since complex numbers are unordered, we use lexicographical order of re 304 * and im. 305 * @return 0 if this is equal to b; 1 if re > b.re, or re == b.re and im 306 * > b.im; -1 if re < b.re, or re == b.re and im < b.im 307 */ 308 @Override 309 public int compareTo(Complex<C> b) { 310 int s = re.compareTo(b.re); 311 if (s != 0) { 312 return s; 313 } 314 return im.compareTo(b.im); 315 } 316 317 318 /** 319 * Since complex numbers are unordered, we use lexicographical order of re 320 * and im. 321 * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > 322 * 0; -1 if re < 0, or re == 0 and im < 0 323 * @see edu.jas.structure.RingElem#signum() 324 */ 325 public int signum() { 326 int s = re.signum(); 327 if (s != 0) { 328 return s; 329 } 330 return im.signum(); 331 } 332 333 334 /* arithmetic operations: +, -, - 335 */ 336 337 /** 338 * Complex number summation. 339 * @param B a Complex<C> number. 340 * @return this+B. 341 */ 342 public Complex<C> sum(Complex<C> B) { 343 return new Complex<C>(ring, re.sum(B.re), im.sum(B.im)); 344 } 345 346 347 /** 348 * Complex number subtract. 349 * @param B a Complex<C> number. 350 * @return this-B. 351 */ 352 public Complex<C> subtract(Complex<C> B) { 353 return new Complex<C>(ring, re.subtract(B.re), im.subtract(B.im)); 354 } 355 356 357 /** 358 * Complex number negative. 359 * @return -this. 360 * @see edu.jas.structure.RingElem#negate() 361 */ 362 public Complex<C> negate() { 363 return new Complex<C>(ring, re.negate(), im.negate()); 364 } 365 366 367 /* arithmetic operations: conjugate, absolute value 368 */ 369 370 /** 371 * Complex number conjugate. 372 * @return the complex conjugate of this. 373 */ 374 public Complex<C> conjugate() { 375 return new Complex<C>(ring, re, im.negate()); 376 } 377 378 379 /** 380 * Complex number norm. 381 * @see edu.jas.structure.StarRingElem#norm() 382 * @return ||this||. 383 */ 384 public Complex<C> norm() { 385 // this.multiply(this.conjugate()); 386 C v = re.multiply(re); 387 v = v.sum(im.multiply(im)); 388 return new Complex<C>(ring, v); 389 } 390 391 392 /** 393 * Complex number absolute value. 394 * @see edu.jas.structure.RingElem#abs() 395 * @return |this|^2. <b>Note:</b> The square root is not jet implemented. 396 */ 397 public Complex<C> abs() { 398 Complex<C> n = norm(); 399 logger.error("abs() square root missing"); 400 // n = n.sqrt(); 401 return n; 402 } 403 404 405 /* arithmetic operations: *, inverse, / 406 */ 407 408 409 /** 410 * Complex number product. 411 * @param B is a complex number. 412 * @return this*B. 413 */ 414 public Complex<C> multiply(Complex<C> B) { 415 return new Complex<C>(ring, re.multiply(B.re).subtract(im.multiply(B.im)), 416 re.multiply(B.im).sum(im.multiply(B.re))); 417 } 418 419 420 /** 421 * Complex number inverse. 422 * @return S with S*this = 1, if it is defined. 423 * @see edu.jas.structure.RingElem#inverse() 424 */ 425 public Complex<C> inverse() { 426 C a = norm().re.inverse(); 427 return new Complex<C>(ring, re.multiply(a), im.multiply(a.negate())); 428 } 429 430 431 /** 432 * Complex number remainder. 433 * @param S is a complex number. 434 * @return 0. 435 */ 436 public Complex<C> remainder(Complex<C> S) { 437 if (ring.isField()) { 438 return ring.getZERO(); 439 } 440 return quotientRemainder(S)[1]; 441 } 442 443 444 /** 445 * Complex number divide. 446 * @param B is a complex number, non-zero. 447 * @return this/B. 448 */ 449 public Complex<C> divide(Complex<C> B) { 450 if (ring.isField()) { 451 return this.multiply(B.inverse()); 452 } 453 return quotientRemainder(B)[0]; 454 } 455 456 457 /** 458 * Complex number quotient and remainder. 459 * @param S Complex. 460 * @return Complex[] { q, r } with q = this/S and r = rem(this,S). 461 */ 462 @SuppressWarnings({ "unchecked", "cast" }) 463 public Complex<C>[] quotientRemainder(Complex<C> S) { 464 Complex<C>[] ret = new Complex[2]; 465 C n = S.norm().re; 466 Complex<C> Sp = this.multiply(S.conjugate()); // == this*inv(S)*n 467 C qr = Sp.re.divide(n); 468 C rr = Sp.re.remainder(n); 469 C qi = Sp.im.divide(n); 470 C ri = Sp.im.remainder(n); 471 C rr1 = rr; 472 C ri1 = ri; 473 if (rr.signum() < 0) { 474 rr = rr.negate(); 475 } 476 if (ri.signum() < 0) { 477 ri = ri.negate(); 478 } 479 C one = n.factory().fromInteger(1); 480 if (rr.sum(rr).compareTo(n) > 0) { // rr > n/2 481 if (rr1.signum() < 0) { 482 qr = qr.subtract(one); 483 } else { 484 qr = qr.sum(one); 485 } 486 } 487 if (ri.sum(ri).compareTo(n) > 0) { // ri > n/2 488 if (ri1.signum() < 0) { 489 qi = qi.subtract(one); 490 } else { 491 qi = qi.sum(one); 492 } 493 } 494 Sp = new Complex<C>(ring, qr, qi); 495 Complex<C> Rp = this.subtract(Sp.multiply(S)); 496 if (debug && n.compareTo(Rp.norm().re) < 0) { 497 System.out.println("n = " + n); 498 System.out.println("qr = " + qr); 499 System.out.println("qi = " + qi); 500 System.out.println("rr = " + rr); 501 System.out.println("ri = " + ri); 502 System.out.println("rr1 = " + rr1); 503 System.out.println("ri1 = " + ri1); 504 System.out.println("this = " + this); 505 System.out.println("S = " + S); 506 System.out.println("Sp = " + Sp); 507 BigInteger tr = (BigInteger) (Object) this.re; 508 BigInteger ti = (BigInteger) (Object) this.im; 509 BigInteger sr = (BigInteger) (Object) S.re; 510 BigInteger si = (BigInteger) (Object) S.im; 511 BigComplex tc = new BigComplex(new BigRational(tr), new BigRational(ti)); 512 BigComplex sc = new BigComplex(new BigRational(sr), new BigRational(si)); 513 BigComplex qc = tc.divide(sc); 514 System.out.println("qc = " + qc); 515 BigDecimal qrd = new BigDecimal(qc.getRe()); 516 BigDecimal qid = new BigDecimal(qc.getIm()); 517 System.out.println("qrd = " + qrd); 518 System.out.println("qid = " + qid); 519 throw new ArithmeticException("QR norm not decreasing " + Rp + ", " + Rp.norm()); 520 } 521 ret[0] = Sp; 522 ret[1] = Rp; 523 return ret; 524 } 525 526 527 /** 528 * Complex number greatest common divisor. 529 * @param S Complex<C>. 530 * @return gcd(this,S). 531 */ 532 public Complex<C> gcd(Complex<C> S) { 533 if (S == null || S.isZERO()) { 534 return this; 535 } 536 if (this.isZERO()) { 537 return S; 538 } 539 if (ring.isField()) { 540 return ring.getONE(); 541 } 542 Complex<C> a = this; 543 Complex<C> b = S; 544 if (a.re.signum() < 0) { 545 a = a.negate(); 546 } 547 if (b.re.signum() < 0) { 548 b = b.negate(); 549 } 550 while (!b.isZERO()) { 551 if (debug) { 552 logger.info("norm(b), a, b = {}, {}, {}", b.norm(), a, b); 553 } 554 Complex<C>[] qr = a.quotientRemainder(b); 555 if (qr[0].isZERO()) { 556 System.out.println("a = " + a); 557 } 558 a = b; 559 b = qr[1]; 560 } 561 if (a.re.signum() < 0) { 562 a = a.negate(); 563 } 564 return a; 565 } 566 567 568 /** 569 * Complex extended greatest common divisor. 570 * @param S Complex<C>. 571 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 572 */ 573 @SuppressWarnings("unchecked") 574 public Complex<C>[] egcd(Complex<C> S) { 575 Complex<C>[] ret = new Complex[3]; 576 ret[0] = null; 577 ret[1] = null; 578 ret[2] = null; 579 if (S == null || S.isZERO()) { 580 ret[0] = this; 581 return ret; 582 } 583 if (this.isZERO()) { 584 ret[0] = S; 585 return ret; 586 } 587 if (ring.isField()) { 588 Complex<C> half = new Complex<C>(ring, ring.ring.fromInteger(1).divide(ring.ring.fromInteger(2))); 589 ret[0] = ring.getONE(); 590 ret[1] = this.inverse().multiply(half); 591 ret[2] = S.inverse().multiply(half); 592 return ret; 593 } 594 Complex<C>[] qr; 595 Complex<C> q = this; 596 Complex<C> r = S; 597 Complex<C> c1 = ring.getONE(); 598 Complex<C> d1 = ring.getZERO(); 599 Complex<C> c2 = ring.getZERO(); 600 Complex<C> d2 = ring.getONE(); 601 Complex<C> x1; 602 Complex<C> x2; 603 while (!r.isZERO()) { 604 if (debug) { 605 logger.info("norm(r), q, r = {}, {}, {}", r.norm(), q, r); 606 } 607 qr = q.quotientRemainder(r); 608 q = qr[0]; 609 x1 = c1.subtract(q.multiply(d1)); 610 x2 = c2.subtract(q.multiply(d2)); 611 c1 = d1; 612 c2 = d2; 613 d1 = x1; 614 d2 = x2; 615 q = r; 616 r = qr[1]; 617 } 618 if (q.re.signum() < 0) { 619 q = q.negate(); 620 c1 = c1.negate(); 621 c2 = c2.negate(); 622 } 623 ret[0] = q; 624 ret[1] = c1; 625 ret[2] = c2; 626 return ret; 627 } 628 629}