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 &le; A, B, C, D &le; (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 &le; A, B, C, D &le; (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 &le; A, B, C, D &le; (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    }