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