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