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