001/*
002 * $Id: BigQuaternionInteger.java 5731 2017-02-11 11:38:15Z kredel $
003 */
004
005package edu.jas.arith;
006
007
008import org.apache.log4j.Logger;
009
010
011/**
012 * Integer BigQuaternion class based on BigRational implementing the RingElem
013 * interface and with the familiar MAS static method names. Objects of this
014 * class are immutable. The integer quaternion methods are implemented after
015 * https://de.wikipedia.org/wiki/Hurwitzquaternion see also
016 * https://en.wikipedia.org/wiki/Hurwitz_quaternion
017 * @author Heinz Kredel
018 */
019
020public final class BigQuaternionInteger extends BigQuaternion
021// implements StarRingElem<BigQuaternion>, GcdRingElem<BigQuaternion> 
022{
023
024
025    private static final Logger logger = Logger.getLogger(BigQuaternionInteger.class);
026
027
028    //private static final boolean debug = logger.isDebugEnabled();
029
030
031    /**
032     * Constructor for a BigQuaternion from BigRationals.
033     * @param fac BigQuaternionRing.
034     * @param r BigRational.
035     * @param i BigRational.
036     * @param j BigRational.
037     * @param k BigRational.
038     */
039    public BigQuaternionInteger(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j,
040                    BigRational k) {
041        super(fac, r, i, j, k);
042    }
043
044
045    /**
046     * Constructor for a BigQuaternion from BigRationals.
047     * @param fac BigQuaternionRing.
048     * @param r BigRational.
049     * @param i BigRational.
050     * @param j BigRational.
051     */
052    public BigQuaternionInteger(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j) {
053        this(fac, r, i, j, BigRational.ZERO);
054    }
055
056
057    /**
058     * Constructor for a BigQuaternion from BigRationals.
059     * @param fac BigQuaternionRing.
060     * @param r BigRational.
061     * @param i BigRational.
062     */
063    public BigQuaternionInteger(BigQuaternionRing fac, BigRational r, BigRational i) {
064        this(fac, r, i, BigRational.ZERO);
065    }
066
067
068    /**
069     * Constructor for a BigQuaternion from BigRationals.
070     * @param fac BigQuaternionRing.
071     * @param r BigRational.
072     */
073    public BigQuaternionInteger(BigQuaternionRing fac, BigRational r) {
074        this(fac, r, BigRational.ZERO);
075    }
076
077
078    /**
079     * Constructor for a BigQuaternion from BigComplex.
080     * @param fac BigQuaternionRing.
081     * @param r BigComplex.
082     */
083    public BigQuaternionInteger(BigQuaternionRing fac, BigComplex r) {
084        this(fac, r.re, r.im);
085    }
086
087
088    /**
089     * Constructor for a BigQuaternionInteger from BigQuaternion.
090     * @param fac BigQuaternionRing.
091     * @param q BigQuaternion.
092     */
093    public BigQuaternionInteger(BigQuaternionRing fac, BigQuaternion q) {
094        this(fac, q.re, q.im, q.jm, q.km);
095    }
096
097
098    /**
099     * Constructor for a BigQuaternion from long.
100     * @param fac BigQuaternionRing.
101     * @param r long.
102     */
103    public BigQuaternionInteger(BigQuaternionRing fac, long r) {
104        this(fac, new BigRational(r), BigRational.ZERO);
105    }
106
107
108    /**
109     * Constructor for a BigQuaternion with no arguments.
110     * @param fac BigQuaternionRing.
111     */
112    public BigQuaternionInteger(BigQuaternionRing fac) {
113        this(fac, BigRational.ZERO);
114    }
115
116
117    /**
118     * The BigQuaternion string constructor accepts the following formats: empty
119     * string, "rational", or "rat i rat j rat k rat" with no blanks around i, j
120     * or k if used as polynoial coefficient.
121     * @param fac BigQuaternionRing.
122     * @param s String.
123     * @throws NumberFormatException
124     */
125    public BigQuaternionInteger(BigQuaternionRing fac, String s) throws NumberFormatException {
126        super(fac, s);
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    @Override
136    public BigQuaternionRing factory() {
137        return ring;
138    }
139
140
141    /**
142     * Clone this.
143     * @see java.lang.Object#clone()
144     */
145    @Override
146    public BigQuaternionInteger copy() {
147        return new BigQuaternionInteger(ring, re, im, jm, km);
148    }
149
150
151    /* arithmetic operations: +, -, -
152     */
153
154
155    /* arithmetic operations: *, inverse, / 
156     */
157
158
159    /**
160     * Quaternion number inverse.
161     * @param A is a non-zero quaternion number.
162     * @return S with S * A = A * S = 1.
163     */
164    public static BigQuaternion QINV(BigQuaternion A) {
165        if (A == null)
166            return null;
167        return A.inverse();
168    }
169
170
171    /**
172     * BigQuaternion inverse.
173     * @return S with S * this = this * S = 1.
174     * @see edu.jas.structure.RingElem#inverse()
175     */
176    @Override
177    public BigQuaternion inverse() {
178        if (!isUnit()) {
179            logger.info("ring = " + ring);
180            throw new ArithmeticException("not invertible: " + this);
181        }
182        return super.inverse();
183    }
184
185
186    /**
187     * BigQuaternion remainder.
188     * @param S BigQuaternion.
189     * @return this - this * b**(-1).
190     */
191    @Override
192    public BigQuaternion remainder(BigQuaternion S) {
193        return rightRemainder(S);
194    }
195
196
197    /**
198     * Quaternion number quotient.
199     * @param A BigQuaternion.
200     * @param B BigQuaternion.
201     * @return R * B**(-1).
202     */
203    public static BigQuaternion QQ(BigQuaternion A, BigQuaternion B) {
204        if (A == null)
205            return null;
206        return A.divide(B);
207    }
208
209
210    /**
211     * BigQuaternion right divide.
212     * @param b BigQuaternion.
213     * @return this * b**(-1).
214     */
215    @Override
216    public BigQuaternion divide(BigQuaternion b) {
217        return rightDivide(b);
218    }
219
220
221    /**
222     * BigQuaternion right divide.
223     * @param b BigQuaternion.
224     * @return this * b**(-1).
225     */
226    @Override
227    public BigQuaternion rightDivide(BigQuaternion b) {
228        return rightQuotientAndRemainder(b)[0];
229    }
230
231
232    /**
233     * BigQuaternion left divide.
234     * @param b BigQuaternion.
235     * @return b**(-1) * this.
236     */
237    @Override
238    public BigQuaternion leftDivide(BigQuaternion b) {
239        return leftQuotientAndRemainder(b)[0];
240    }
241
242
243    /**
244     * BigQuaternion divide.
245     * @param b BigRational.
246     * @return this/b.
247     */
248    @Override
249    public BigQuaternion divide(BigRational b) {
250        BigQuaternion d = super.divide(b);
251        if (!d.isEntier()) {
252            throw new ArithmeticException("not divisible: " + this + " / " + b);
253        }
254        return d;
255    }
256
257
258    /**
259     * Quotient and remainder by division of this by S.
260     * @param S a quaternion number
261     * @return [this*S**(-1), this - (this*S**(-1))*S].
262     */
263    @Override
264    public BigQuaternion[] quotientRemainder(BigQuaternion S) {
265        return new BigQuaternion[] { divide(S), remainder(S) };
266    }
267
268
269    /**
270     * Quaternion number greatest common divisor.
271     * @param S BigQuaternion.
272     * @return gcd(this,S).
273     */
274    @Override
275    public BigQuaternion gcd(BigQuaternion S) {
276        return rightGcd(S);
277    }
278
279
280    /**
281     * BigQuaternion extended greatest common divisor.
282     * @param S BigQuaternion.
283     * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
284     */
285    @Override
286    public BigQuaternion[] egcd(BigQuaternion S) {
287        throw new UnsupportedOperationException("not implemented: egcd");
288        /*
289        BigQuaternion[] ret = new BigQuaternion[3];
290        ret[0] = null;
291        ret[1] = null;
292        ret[2] = null;
293        if (S == null || S.isZERO()) {
294           ret[0] = this;
295           return ret;
296        }
297        if (this.isZERO()) {
298           ret[0] = S;
299           return ret;
300        }
301        BigQuaternion half = new BigQuaternion(ring, new BigRational(1, 2));
302        ret[0] = ring.getONE();
303        ret[1] = this.inverse().multiply(half);
304        ret[2] = S.inverse().multiply(half);
305        return ret;
306        */
307    }
308
309
310    /**
311     * Integral quotient and remainder by left division of this by S. This must
312     * be also an integral (Hurwitz) quaternion number.
313     * @param b an integral (Hurwitz) quaternion number
314     * @return [round(b**(-1)) this, this - b * (round(b**(-1)) this)].
315     */
316    public BigQuaternion[] leftQuotientAndRemainder(BigQuaternion b) {
317        //System.out.println("left QR = " + this + ", " + b);
318        if (!this.isEntier() || !b.isEntier()) {
319            throw new IllegalArgumentException("entier elements required");
320        }
321        BigQuaternion bi = b.inverse();
322        BigQuaternion m = bi.multiply(this); // left divide
323        //System.out.println("m = " + m.toScript());
324        BigQuaternionInteger mh = m.roundToHurwitzian();
325        //System.out.println("mh = " + mh.toScript());
326        BigQuaternion n = this.subtract(b.multiply(mh));
327        BigQuaternion[] ret = new BigQuaternion[2];
328        ret[0] = mh;
329        ret[1] = n;
330        return ret;
331    }
332
333
334    /**
335     * Integral quotient and remainder by right division of this by S. This must
336     * be also an integral (Hurwitz) quaternion number.
337     * @param b an integral (Hurwitz) quaternion number
338     * @return [this round(b**(-1)), this - this (round(b**(-1)) b)].
339     */
340    public BigQuaternion[] rightQuotientAndRemainder(BigQuaternion b) {
341        //System.out.println("right QR = " + this + ", " + b);
342        if (!this.isEntier() || !b.isEntier()) {
343            throw new IllegalArgumentException("entier elements required");
344        }
345        BigQuaternion bi = b.inverse();
346        BigQuaternion m = this.multiply(bi); // right divide
347        //System.out.println("m = " + m.toScript());
348        BigQuaternionInteger mh = m.roundToHurwitzian();
349        //System.out.println("mh = " + mh.toScript());
350        BigQuaternion n = this.subtract(mh.multiply(b));
351        BigQuaternion[] ret = new BigQuaternion[2];
352        ret[0] = mh;
353        ret[1] = n;
354        return ret;
355    }
356
357
358    /**
359     * Left remainder.
360     * @param a element.
361     * @return r = this - (a/left) * a, where left * a = this.
362     */
363    @Override
364    public BigQuaternion leftRemainder(BigQuaternion a) {
365        return leftQuotientAndRemainder(a)[1];
366    }
367
368
369    /**
370     * Right remainder.
371     * @param a element.
372     * @return r = this - a * (a/right), where a * right = this.
373     */
374    @Override
375    public BigQuaternion rightRemainder(BigQuaternion a) {
376        return rightQuotientAndRemainder(a)[1];
377    }
378
379
380    /**
381     * Integer quaternion number left greatest common divisor.
382     * @param S integer BigQuaternion.
383     * @return leftGcd(this,S).
384     */
385    @Override
386    public BigQuaternion leftGcd(BigQuaternion S) {
387        if (S == null || S.isZERO()) {
388            return this;
389        }
390        if (this.isZERO()) {
391            return S;
392        }
393        BigQuaternionInteger q;
394        BigQuaternion r;
395        q = this;
396        r = S;
397        while (!r.isZERO()) {
398            BigQuaternion u = q.leftQuotientAndRemainder(r)[1];
399            //System.out.println("u = " + u.toScript());
400            q = new BigQuaternionInteger(ring, r);
401            r = u;
402        }
403        return q;
404    }
405
406
407    /**
408     * Integer quaternion number right greatest common divisor.
409     * @param S integer BigQuaternion.
410     * @return rightGcd(this,S).
411     */
412    @Override
413    public BigQuaternion rightGcd(BigQuaternion S) {
414        if (S == null || S.isZERO()) {
415            return this;
416        }
417        if (this.isZERO()) {
418            return S;
419        }
420        BigQuaternionInteger q;
421        BigQuaternion r;
422        q = this;
423        r = S;
424        while (!r.isZERO()) {
425            BigQuaternion u = q.rightQuotientAndRemainder(r)[1];
426            //System.out.println("u = " + u.toScript());
427            q = new BigQuaternionInteger(ring, r);
428            r = u;
429        }
430        return q;
431    }
432
433}