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