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