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 }