001/* 002 * $Id: BigComplex.java 6014 2020-04-29 21:18:51Z kredel $ 003 */ 004 005package edu.jas.arith; 006 007 008import java.io.Reader; 009import java.math.BigInteger; 010import java.util.ArrayList; 011import java.util.List; 012import java.util.Random; 013 014import org.apache.logging.log4j.LogManager; 015import org.apache.logging.log4j.Logger; 016 017import edu.jas.kern.StringUtil; 018import edu.jas.structure.GcdRingElem; 019import edu.jas.structure.RingFactory; 020import edu.jas.structure.StarRingElem; 021 022 023/** 024 * BigComplex class based on BigRational implementing the RingElem respectively 025 * the StarRingElem interface. Objects of this class are immutable. The SAC2 026 * static methods are also provided. 027 * @author Heinz Kredel 028 */ 029public final class BigComplex 030 implements StarRingElem<BigComplex>, GcdRingElem<BigComplex>, RingFactory<BigComplex> { 031 032 033 /** 034 * Real part of the data structure. 035 */ 036 public final BigRational re; 037 038 039 /** 040 * Imaginary part of the data structure. 041 */ 042 public final BigRational im; 043 044 045 private final static Random random = new Random(); 046 047 048 private static final Logger logger = LogManager.getLogger(BigComplex.class); 049 050 051 /** 052 * The constructor creates a BigComplex object from two BigRational objects 053 * real and imaginary part. 054 * @param r real part. 055 * @param i imaginary part. 056 */ 057 public BigComplex(BigRational r, BigRational i) { 058 re = r; 059 im = i; 060 } 061 062 063 /** 064 * The constructor creates a BigComplex object from a BigRational object as 065 * real part, the imaginary part is set to 0. 066 * @param r real part. 067 */ 068 public BigComplex(BigRational r) { 069 this(r, BigRational.ZERO); 070 } 071 072 073 /** 074 * The constructor creates a BigComplex object from a long element as real 075 * part, the imaginary part is set to 0. 076 * @param r real part. 077 */ 078 public BigComplex(long r) { 079 this(new BigRational(r), BigRational.ZERO); 080 } 081 082 083 /** 084 * The constructor creates a BigComplex object with real part 0 and 085 * imaginary part 0. 086 */ 087 public BigComplex() { 088 this(BigRational.ZERO); 089 } 090 091 092 /** 093 * The constructor creates a BigComplex object from a String representation. 094 * @param s string of a BigComplex. 095 * @throws NumberFormatException 096 */ 097 public BigComplex(String s) throws NumberFormatException { 098 if (s == null || s.length() == 0) { 099 re = BigRational.ZERO; 100 im = BigRational.ZERO; 101 return; 102 } 103 s = s.trim(); 104 int i = s.indexOf("i"); 105 if (i < 0) { 106 re = new BigRational(s); 107 im = BigRational.ZERO; 108 return; 109 } 110 //logger.warn("String constructor not done"); 111 String sr = ""; 112 if (i > 0) { 113 sr = s.substring(0, i); 114 } 115 String si = ""; 116 if (i < s.length()) { 117 si = s.substring(i + 1, s.length()); 118 } 119 //int j = sr.indexOf("+"); 120 re = new BigRational(sr.trim()); 121 im = new BigRational(si.trim()); 122 } 123 124 125 /** 126 * Get the corresponding element factory. 127 * @return factory for this Element. 128 * @see edu.jas.structure.Element#factory() 129 */ 130 public BigComplex factory() { 131 return this; 132 } 133 134 135 /** 136 * Get a list of the generating elements. 137 * @return list of generators for the algebraic structure. 138 * @see edu.jas.structure.ElemFactory#generators() 139 */ 140 public List<BigComplex> generators() { 141 List<BigComplex> g = new ArrayList<BigComplex>(2); 142 g.add(getONE()); 143 g.add(getIMAG()); 144 return g; 145 } 146 147 148 /** 149 * Is this structure finite or infinite. 150 * @return true if this structure is finite, else false. 151 * @see edu.jas.structure.ElemFactory#isFinite() 152 */ 153 public boolean isFinite() { 154 return false; 155 } 156 157 158 /** 159 * Clone this. 160 * @see java.lang.Object#clone() 161 */ 162 @Override 163 public BigComplex copy() { 164 return new BigComplex(re, im); 165 } 166 167 168 /** 169 * Copy BigComplex element c. 170 * @param c BigComplex. 171 * @return a copy of c. 172 */ 173 public BigComplex copy(BigComplex c) { 174 return new BigComplex(c.re, c.im); 175 } 176 177 178 /** 179 * Get the zero element. 180 * @return 0 as BigComplex. 181 */ 182 public BigComplex getZERO() { 183 return ZERO; 184 } 185 186 187 /** 188 * Get the one element. 189 * @return 1 as BigComplex. 190 */ 191 public BigComplex getONE() { 192 return ONE; 193 } 194 195 196 /** 197 * Get the i element. 198 * @return i as BigComplex. 199 */ 200 public BigComplex getIMAG() { 201 return I; 202 } 203 204 205 /** 206 * Query if this ring is commutative. 207 * @return true. 208 */ 209 public boolean isCommutative() { 210 return true; 211 } 212 213 214 /** 215 * Query if this ring is associative. 216 * @return true. 217 */ 218 public boolean isAssociative() { 219 return true; 220 } 221 222 223 /** 224 * Query if this ring is a field. 225 * @return true. 226 */ 227 public boolean isField() { 228 return true; 229 } 230 231 232 /** 233 * Characteristic of this ring. 234 * @return characteristic of this ring. 235 */ 236 public java.math.BigInteger characteristic() { 237 return java.math.BigInteger.ZERO; 238 } 239 240 241 /** 242 * Get a BigComplex element from a BigInteger. 243 * @param a BigInteger. 244 * @return a BigComplex. 245 */ 246 public BigComplex fromInteger(BigInteger a) { 247 return new BigComplex(new BigRational(a)); 248 } 249 250 251 /** 252 * Get a BigComplex element from a long. 253 * @param a long. 254 * @return a BigComplex. 255 */ 256 public BigComplex fromInteger(long a) { 257 return new BigComplex(new BigRational(a)); 258 } 259 260 261 /** 262 * The constant 0. 263 */ 264 public static final BigComplex ZERO = new BigComplex(); 265 266 267 /** 268 * The constant 1. 269 */ 270 public static final BigComplex ONE = new BigComplex(BigRational.ONE); 271 272 273 /** 274 * The constant i. 275 */ 276 public static final BigComplex I = new BigComplex(BigRational.ZERO, BigRational.ONE); 277 278 279 /** 280 * Get the real part. 281 * @return re. 282 */ 283 public BigRational getRe() { 284 return re; 285 } 286 287 288 /** 289 * Get the imaginary part. 290 * @return im. 291 */ 292 public BigRational getIm() { 293 return im; 294 } 295 296 297 /** 298 * Get the String representation. 299 */ 300 @Override 301 public String toString() { 302 String s = "" + re; 303 int i = im.compareTo(BigRational.ZERO); 304 //logger.info("compareTo "+im+" ? 0 = "+i); 305 if (i == 0) 306 return s; 307 s += "i" + im; 308 return s; 309 } 310 311 312 /** 313 * Get a scripting compatible string representation. 314 * @return script compatible representation for this Element. 315 * @see edu.jas.structure.Element#toScript() 316 */ 317 @Override 318 public String toScript() { 319 // Python case: re or re+im*i 320 // was (re,im) or (re,) 321 StringBuffer s = new StringBuffer(); 322 boolean iz = im.isZERO(); 323 if (iz) { 324 s.append(re.toScript()); 325 return s.toString(); 326 } 327 boolean rz = re.isZERO(); 328 if (rz) { 329 if (!im.isONE()) { 330 if (im.signum() > 0) { 331 s.append(im.toScript() + "*"); 332 } else { 333 s.append("-"); 334 BigRational ii = im.negate(); 335 if (!ii.isONE()) { 336 s.append(ii.toScript() + "*"); 337 } 338 } 339 } 340 } else { 341 s.append(re.toScript()); 342 if (im.signum() > 0) { 343 s.append("+"); 344 if (!im.isONE()) { 345 s.append(im.toScript() + "*"); 346 } 347 } else { 348 s.append("-"); 349 BigRational ii = im.negate(); 350 if (!ii.isONE()) { 351 s.append(ii.toScript() + "*"); 352 } 353 } 354 } 355 s.append("I"); 356 return s.toString(); 357 } 358 359 360 /** 361 * Get a scripting compatible string representation of the factory. 362 * @return script compatible representation for this ElemFactory. 363 * @see edu.jas.structure.Element#toScriptFactory() 364 */ 365 @Override 366 public String toScriptFactory() { 367 // Python case 368 return "CC()"; 369 } 370 371 372 /** 373 * Complex number zero. 374 * @param A is a complex number. 375 * @return If A is 0 then true is returned, else false. 376 */ 377 public static boolean isCZERO(BigComplex A) { 378 if (A == null) 379 return false; 380 return A.isZERO(); 381 } 382 383 384 /** 385 * Is Complex number zero. 386 * @return If this is 0 then true is returned, else false. 387 * @see edu.jas.structure.RingElem#isZERO() 388 */ 389 public boolean isZERO() { 390 return re.isZERO() && im.isZERO(); 391 } 392 393 394 /** 395 * Complex number one. 396 * @param A is a complex number. 397 * @return If A is 1 then true is returned, else false. 398 */ 399 public static boolean isCONE(BigComplex A) { 400 if (A == null) 401 return false; 402 return A.isONE(); 403 } 404 405 406 /** 407 * Is Complex number one. 408 * @return If this is 1 then true is returned, else false. 409 * @see edu.jas.structure.RingElem#isONE() 410 */ 411 public boolean isONE() { 412 return re.isONE() && im.isZERO(); 413 } 414 415 416 /** 417 * Is Complex imaginary one. 418 * @return If this is i then true is returned, else false. 419 */ 420 public boolean isIMAG() { 421 return re.isZERO() && im.isONE(); 422 } 423 424 425 /** 426 * Is Complex unit element. 427 * @return If this is a unit then true is returned, else false. 428 * @see edu.jas.structure.RingElem#isUnit() 429 */ 430 public boolean isUnit() { 431 return (!isZERO()); 432 } 433 434 435 /** 436 * Comparison with any other object. 437 * @see java.lang.Object#equals(java.lang.Object) 438 */ 439 @Override 440 public boolean equals(Object b) { 441 if (!(b instanceof BigComplex)) { 442 return false; 443 } 444 BigComplex bc = (BigComplex) b; 445 return re.equals(bc.re) && im.equals(bc.im); 446 } 447 448 449 /** 450 * Hash code for this BigComplex. 451 * @see java.lang.Object#hashCode() 452 */ 453 @Override 454 public int hashCode() { 455 return 37 * re.hashCode() + im.hashCode(); 456 } 457 458 459 /** 460 * Since complex numbers are unordered, we use lexicographical order of re 461 * and im. 462 * @return 0 if this is equal to b; 1 if re > b.re, or re == b.re and im > 463 * b.im; -1 if re < b.re, or re == b.re and im < b.im 464 */ 465 @Override 466 public int compareTo(BigComplex b) { 467 int s = re.compareTo(b.re); 468 if (s != 0) { 469 return s; 470 } 471 return im.compareTo(b.im); 472 } 473 474 475 /** 476 * Since complex numbers are unordered, we use lexicographical order of re 477 * and im. 478 * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > 0; -1 479 * if re < 0, or re == 0 and im < 0 480 * @see edu.jas.structure.RingElem#signum() 481 */ 482 public int signum() { 483 int s = re.signum(); 484 if (s != 0) { 485 return s; 486 } 487 return im.signum(); 488 } 489 490 491 /* arithmetic operations: +, -, - 492 */ 493 494 /** 495 * Complex number summation. 496 * @param B a BigComplex number. 497 * @return this+B. 498 */ 499 public BigComplex sum(BigComplex B) { 500 return new BigComplex(re.sum(B.re), im.sum(B.im)); 501 } 502 503 504 /** 505 * Complex number sum. 506 * @param A and B are complex numbers. 507 * @return A+B. 508 */ 509 public static BigComplex CSUM(BigComplex A, BigComplex B) { 510 if (A == null) 511 return null; 512 return A.sum(B); 513 } 514 515 516 /** 517 * Complex number difference. 518 * @param A and B are complex numbers. 519 * @return A-B. 520 */ 521 public static BigComplex CDIF(BigComplex A, BigComplex B) { 522 if (A == null) 523 return null; 524 return A.subtract(B); 525 } 526 527 528 /** 529 * Complex number subtract. 530 * @param B a BigComplex number. 531 * @return this-B. 532 */ 533 public BigComplex subtract(BigComplex B) { 534 return new BigComplex(re.subtract(B.re), im.subtract(B.im)); 535 } 536 537 538 /** 539 * Complex number negative. 540 * @param A is a complex number. 541 * @return -A 542 */ 543 public static BigComplex CNEG(BigComplex A) { 544 if (A == null) 545 return null; 546 return A.negate(); 547 } 548 549 550 /** 551 * Complex number negative. 552 * @return -this. 553 * @see edu.jas.structure.RingElem#negate() 554 */ 555 public BigComplex negate() { 556 return new BigComplex(re.negate(), im.negate()); 557 } 558 559 560 /** 561 * Complex number conjugate. 562 * @param A is a complex number. 563 * @return the complex conjugate of A. 564 */ 565 public static BigComplex CCON(BigComplex A) { 566 if (A == null) 567 return null; 568 return A.conjugate(); 569 } 570 571 572 /* arithmetic operations: conjugate, absolut value 573 */ 574 575 /** 576 * Complex number conjugate. 577 * @return the complex conjugate of this. 578 */ 579 public BigComplex conjugate() { 580 return new BigComplex(re, im.negate()); 581 } 582 583 584 /** 585 * Complex number norm. 586 * @see edu.jas.structure.StarRingElem#norm() 587 * @return ||this||. 588 */ 589 public BigComplex norm() { 590 // this.multiply(this.conjugate()); 591 BigRational v = re.multiply(re); 592 v = v.sum(im.multiply(im)); 593 return new BigComplex(v); 594 } 595 596 597 /** 598 * Complex number absolute value. 599 * @see edu.jas.structure.RingElem#abs() 600 * @return |this|. 601 */ 602 public BigComplex abs() { 603 BigComplex n = norm(); 604 BigRational r = Roots.sqrt(n.re); 605 logger.debug("abs() square root approximaton {}", r); 606 return new BigComplex(r); 607 } 608 609 610 /** 611 * Complex number absolute value. 612 * @param A is a complex number. 613 * @return the absolute value of A, a rational number. Note: The square root 614 * is not jet implemented. 615 */ 616 public static BigRational CABS(BigComplex A) { 617 if (A == null) 618 return null; 619 return A.abs().re; 620 } 621 622 623 /** 624 * Complex number product. 625 * @param A and B are complex numbers. 626 * @return A*B. 627 */ 628 public static BigComplex CPROD(BigComplex A, BigComplex B) { 629 if (A == null) 630 return null; 631 return A.multiply(B); 632 } 633 634 635 /* arithmetic operations: *, inverse, / 636 */ 637 638 639 /** 640 * Complex number product. 641 * @param B is a complex number. 642 * @return this*B. 643 */ 644 public BigComplex multiply(BigComplex B) { 645 return new BigComplex(re.multiply(B.re).subtract(im.multiply(B.im)), 646 re.multiply(B.im).sum(im.multiply(B.re))); 647 } 648 649 650 /** 651 * Complex number inverse. 652 * @param A is a non-zero complex number. 653 * @return S with S*A = 1. 654 */ 655 public static BigComplex CINV(BigComplex A) { 656 if (A == null) 657 return null; 658 return A.inverse(); 659 } 660 661 662 /** 663 * Complex number inverse. 664 * @return S with S*this = 1. 665 * @see edu.jas.structure.RingElem#inverse() 666 */ 667 public BigComplex inverse() { 668 BigRational a = norm().re.inverse(); 669 return new BigComplex(re.multiply(a), im.multiply(a.negate())); 670 } 671 672 673 /** 674 * Complex number inverse. 675 * @param S is a complex number. 676 * @return 0. 677 */ 678 public BigComplex remainder(BigComplex S) { 679 if (S.isZERO()) { 680 throw new ArithmeticException("division by zero"); 681 } 682 return ZERO; 683 } 684 685 686 /** 687 * Complex number quotient. 688 * @param A and B are complex numbers, B non-zero. 689 * @return A/B. 690 */ 691 public static BigComplex CQ(BigComplex A, BigComplex B) { 692 if (A == null) 693 return null; 694 return A.divide(B); 695 } 696 697 698 /** 699 * Complex number divide. 700 * @param B is a complex number, non-zero. 701 * @return this/B. 702 */ 703 public BigComplex divide(BigComplex B) { 704 return this.multiply(B.inverse()); 705 } 706 707 708 /** 709 * Quotient and remainder by division of this by S. 710 * @param S a complex number 711 * @return [this/S, this - (this/S)*S]. 712 */ 713 public BigComplex[] quotientRemainder(BigComplex S) { 714 return new BigComplex[] { divide(S), ZERO }; 715 } 716 717 718 /** 719 * Complex number, random. Random rational numbers A and B are generated 720 * using random(n). Then R is the complex number with real part A and 721 * imaginary part B. 722 * @param n such that 0 ≤ A, B ≤ (2<sup>n</sup>-1). 723 * @return R. 724 */ 725 public BigComplex random(int n) { 726 return random(n, random); 727 } 728 729 730 /** 731 * Complex number, random. Random rational numbers A and B are generated 732 * using random(n). Then R is the complex number with real part A and 733 * imaginary part B. 734 * @param n such that 0 ≤ A, B ≤ (2<sup>n</sup>-1). 735 * @param rnd is a source for random bits. 736 * @return R. 737 */ 738 public BigComplex random(int n, Random rnd) { 739 BigRational r = BigRational.ONE.random(n, rnd); 740 BigRational i = BigRational.ONE.random(n, rnd); 741 return new BigComplex(r, i); 742 } 743 744 745 /** 746 * Complex number, random. Random rational numbers A and B are generated 747 * using random(n). Then R is the complex number with real part A and 748 * imaginary part B. 749 * @param n such that 0 ≤ A, B ≤ (2<sup>n</sup>-1). 750 * @return R. 751 */ 752 public static BigComplex CRAND(int n) { 753 return ONE.random(n, random); 754 } 755 756 757 /** 758 * Parse complex number from string. 759 * @param s String. 760 * @return BigComplex from s. 761 */ 762 public BigComplex parse(String s) { 763 return new BigComplex(s); 764 } 765 766 767 /** 768 * Parse complex number from Reader. 769 * @param r Reader. 770 * @return next BigComplex from r. 771 */ 772 public BigComplex parse(Reader r) { 773 return parse(StringUtil.nextString(r)); 774 } 775 776 777 /** 778 * Complex number greatest common divisor. 779 * @param S BigComplex. 780 * @return gcd(this,S). 781 */ 782 public BigComplex gcd(BigComplex S) { 783 if (S == null || S.isZERO()) { 784 return this; 785 } 786 if (this.isZERO()) { 787 return S; 788 } 789 return ONE; 790 } 791 792 793 /** 794 * BigComplex extended greatest common divisor. 795 * @param S BigComplex. 796 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 797 */ 798 public BigComplex[] egcd(BigComplex S) { 799 BigComplex[] ret = new BigComplex[3]; 800 ret[0] = null; 801 ret[1] = null; 802 ret[2] = null; 803 if (S == null || S.isZERO()) { 804 ret[0] = this; 805 return ret; 806 } 807 if (this.isZERO()) { 808 ret[0] = S; 809 return ret; 810 } 811 BigComplex half = new BigComplex(new BigRational(1, 2)); 812 ret[0] = ONE; 813 ret[1] = this.inverse().multiply(half); 814 ret[2] = S.inverse().multiply(half); 815 return ret; 816 } 817 818 819 /** 820 * Returns the number of bits in the representation of this BigComplex, 821 * including a sign bit. It is equivalent to 822 * {@code re.bitLength() + im.bitLength()}.) 823 * @return number of bits in the representation of this BigComplex, 824 * including a sign bit. 825 */ 826 public long bitLength() { 827 return re.bitLength() + im.bitLength(); 828 } 829 830}