001/*
002 * $Id: BigQuaternionInteger.java 5872 2018-07-20 16:01:46Z kredel $
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 inverse.
162     * @param A is a non-zero quaternion number.
163     * @return S with S * A = A * S = 1.
164     */
165    public static BigQuaternion QINV(BigQuaternion A) {
166        if (A == null)
167            return null;
168        return A.inverse();
169    }
170
171
172    /**
173     * BigQuaternion inverse.
174     * @return S with S * this = this * S = 1.
175     * @see edu.jas.structure.RingElem#inverse()
176     */
177    @Override
178    public BigQuaternion inverse() {
179        if (!isUnit()) {
180            logger.info("ring = " + ring);
181            throw new ArithmeticException("not invertible: " + this);
182        }
183        return super.inverse();
184    }
185
186
187    /**
188     * BigQuaternion remainder.
189     * @param S BigQuaternion.
190     * @return this - this * b**(-1).
191     */
192    @Override
193    public BigQuaternion remainder(BigQuaternion S) {
194        return rightRemainder(S);
195    }
196
197
198    /**
199     * Quaternion number quotient.
200     * @param A BigQuaternion.
201     * @param B BigQuaternion.
202     * @return R * B**(-1).
203     */
204    public static BigQuaternion QQ(BigQuaternion A, BigQuaternion B) {
205        if (A == null)
206            return null;
207        return A.divide(B);
208    }
209
210
211    /**
212     * BigQuaternion right divide.
213     * @param b BigQuaternion.
214     * @return this * b**(-1).
215     */
216    @Override
217    public BigQuaternion divide(BigQuaternion b) {
218        return rightDivide(b);
219    }
220
221
222    /**
223     * BigQuaternion right divide.
224     * @param b BigQuaternion.
225     * @return this * b**(-1).
226     */
227    @Override
228    public BigQuaternion rightDivide(BigQuaternion b) {
229        return rightQuotientAndRemainder(b)[0];
230    }
231
232
233    /**
234     * BigQuaternion left divide.
235     * @param b BigQuaternion.
236     * @return b**(-1) * this.
237     */
238    @Override
239    public BigQuaternion leftDivide(BigQuaternion b) {
240        return leftQuotientAndRemainder(b)[0];
241    }
242
243
244    /**
245     * BigQuaternion divide.
246     * @param b BigRational.
247     * @return this/b.
248     */
249    @Override
250    public BigQuaternion divide(BigRational b) {
251        BigQuaternion d = super.divide(b);
252        if (!d.isEntier()) {
253            throw new ArithmeticException("not divisible: " + this + " / " + b);
254        }
255        return d;
256    }
257
258
259    /**
260     * Quotient and remainder by division of this by S.
261     * @param S a quaternion number
262     * @return [this*S**(-1), this - (this*S**(-1))*S].
263     */
264    @Override
265    public BigQuaternion[] quotientRemainder(BigQuaternion S) {
266        return new BigQuaternion[] { divide(S), remainder(S) };
267    }
268
269
270    /**
271     * Quaternion number greatest common divisor.
272     * @param S BigQuaternion.
273     * @return gcd(this,S).
274     */
275    @Override
276    public BigQuaternion gcd(BigQuaternion S) {
277        return rightGcd(S);
278    }
279
280
281    /**
282     * BigQuaternion extended greatest common divisor.
283     * @param S BigQuaternion.
284     * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
285     */
286    @Override
287    public BigQuaternion[] egcd(BigQuaternion S) {
288        throw new UnsupportedOperationException("not implemented: egcd");
289        /*
290        BigQuaternion[] ret = new BigQuaternion[3];
291        ret[0] = null;
292        ret[1] = null;
293        ret[2] = null;
294        if (S == null || S.isZERO()) {
295           ret[0] = this;
296           return ret;
297        }
298        if (this.isZERO()) {
299           ret[0] = S;
300           return ret;
301        }
302        BigQuaternion half = new BigQuaternion(ring, new BigRational(1, 2));
303        ret[0] = ring.getONE();
304        ret[1] = this.inverse().multiply(half);
305        ret[2] = S.inverse().multiply(half);
306        return ret;
307        */
308    }
309
310
311    /**
312     * Integral quotient and remainder by left division of this by S. This must
313     * be also an integral (Hurwitz) quaternion number.
314     * @param b an integral (Hurwitz) quaternion number
315     * @return [round(b**(-1)) this, this - b * (round(b**(-1)) this)].
316     */
317    public BigQuaternion[] leftQuotientAndRemainder(BigQuaternion b) {
318        //System.out.println("left QR = " + this + ", " + b);
319        if (!this.isEntier() || !b.isEntier()) {
320            throw new IllegalArgumentException("entier elements required");
321        }
322        BigQuaternion bi = b.inverse();
323        BigQuaternion m = bi.multiply(this); // left divide
324        //System.out.println("m = " + m.toScript());
325        BigQuaternionInteger mh = m.roundToHurwitzian();
326        //System.out.println("mh = " + mh.toScript());
327        BigQuaternion n = this.subtract(b.multiply(mh));
328        BigQuaternion[] ret = new BigQuaternion[2];
329        ret[0] = mh;
330        ret[1] = n;
331        return ret;
332    }
333
334
335    /**
336     * Integral quotient and remainder by right division of this by S. This must
337     * be also an integral (Hurwitz) quaternion number.
338     * @param b an integral (Hurwitz) quaternion number
339     * @return [this round(b**(-1)), this - this (round(b**(-1)) b)].
340     */
341    public BigQuaternion[] rightQuotientAndRemainder(BigQuaternion b) {
342        //System.out.println("right QR = " + this + ", " + b);
343        if (!this.isEntier() || !b.isEntier()) {
344            throw new IllegalArgumentException("entier elements required");
345        }
346        BigQuaternion bi = b.inverse();
347        BigQuaternion m = this.multiply(bi); // right divide
348        //System.out.println("m = " + m.toScript());
349        BigQuaternionInteger mh = m.roundToHurwitzian();
350        //System.out.println("mh = " + mh.toScript());
351        BigQuaternion n = this.subtract(mh.multiply(b));
352        BigQuaternion[] ret = new BigQuaternion[2];
353        ret[0] = mh;
354        ret[1] = n;
355        return ret;
356    }
357
358
359    /**
360     * Left remainder.
361     * @param a element.
362     * @return r = this - (a/left) * a, where left * a = this.
363     */
364    @Override
365    public BigQuaternion leftRemainder(BigQuaternion a) {
366        return leftQuotientAndRemainder(a)[1];
367    }
368
369
370    /**
371     * Right remainder.
372     * @param a element.
373     * @return r = this - a * (a/right), where a * right = this.
374     */
375    @Override
376    public BigQuaternion rightRemainder(BigQuaternion a) {
377        return rightQuotientAndRemainder(a)[1];
378    }
379
380
381    /**
382     * Integer quaternion number left greatest common divisor.
383     * @param S integer BigQuaternion.
384     * @return leftGcd(this,S).
385     */
386    @Override
387    public BigQuaternion leftGcd(BigQuaternion S) {
388        if (S == null || S.isZERO()) {
389            return this;
390        }
391        if (this.isZERO()) {
392            return S;
393        }
394        BigQuaternionInteger q;
395        BigQuaternion r;
396        q = this;
397        r = S;
398        while (!r.isZERO()) {
399            BigQuaternion u = q.leftQuotientAndRemainder(r)[1];
400            //System.out.println("u = " + u.toScript());
401            q = new BigQuaternionInteger(ring, r);
402            r = u;
403        }
404        return q;
405    }
406
407
408    /**
409     * Integer quaternion number right greatest common divisor.
410     * @param S integer BigQuaternion.
411     * @return rightGcd(this,S).
412     */
413    @Override
414    public BigQuaternion rightGcd(BigQuaternion S) {
415        if (S == null || S.isZERO()) {
416            return this;
417        }
418        if (this.isZERO()) {
419            return S;
420        }
421        BigQuaternionInteger q;
422        BigQuaternion r;
423        q = this;
424        r = S;
425        while (!r.isZERO()) {
426            BigQuaternion u = q.rightQuotientAndRemainder(r)[1];
427            //System.out.println("u = " + u.toScript());
428            q = new BigQuaternionInteger(ring, r);
429            r = u;
430        }
431        return q;
432    }
433
434}