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