001/*
002 * $Id$
003 */
004
005package edu.jas.arith;
006
007
008import java.io.Reader;
009// import java.math.BigInteger;
010import java.util.ArrayList;
011import java.util.List;
012import java.util.Random;
013
014import org.apache.logging.log4j.Logger;
015import org.apache.logging.log4j.LogManager; 
016
017import edu.jas.kern.StringUtil;
018import edu.jas.kern.Scripting;
019import edu.jas.structure.RingFactory;
020
021
022/**
023 * BigQuaternion ring class based on BigRational implementing the RingElem
024 * interface.
025 * @author Heinz Kredel
026 */
027
028public final class BigQuaternionRing implements RingFactory<BigQuaternion> {
029
030
031    /**
032     * List of all 24 integral units.
033     */
034    static List<BigQuaternion> entierUnits = null; //later: unitsOfHurwitzian();
035
036
037    /**
038     * Flag to signal if this ring is integral.
039     */
040    protected boolean integral = false;
041
042
043    protected final static Random random = new Random();
044
045
046    private static final Logger logger = LogManager.getLogger(BigQuaternionRing.class);
047
048
049    //private static final boolean debug = logger.isDebugEnabled();
050
051
052    /**
053     * Constructor for a BigQuaternion ring.
054     */
055    public BigQuaternionRing() {
056        this(false);
057    }
058
059
060    /**
061     * Constructor for a BigQuaternion ring.
062     */
063    public BigQuaternionRing(boolean i) {
064        integral = i;
065        logger.info("integral = {}", integral);
066    }
067
068
069    /**
070     * Get a list of the generating elements.
071     * @return list of generators for the algebraic structure.
072     * @see edu.jas.structure.ElemFactory#generators()
073     */
074    public List<BigQuaternion> generators() {
075        List<BigQuaternion> g = new ArrayList<BigQuaternion>(4);
076        g.add(getONE());
077        g.add(I);
078        g.add(J);
079        g.add(K);
080        return g;
081    }
082
083
084    /**
085     * Is this structure finite or infinite.
086     * @return true if this structure is finite, else false.
087     * @see edu.jas.structure.ElemFactory#isFinite()
088     */
089    public boolean isFinite() {
090        return false;
091    }
092
093
094    /**
095     * Copy BigQuaternion element c.
096     * @param c BigQuaternion.
097     * @return a copy of c.
098     */
099    public BigQuaternion copy(BigQuaternion c) {
100        return new BigQuaternion(this, c.re, c.im, c.jm, c.km);
101    }
102
103
104    /**
105     * Get the zero element.
106     * @return 0 as BigQuaternion.
107     */
108    public BigQuaternion getZERO() {
109        return ZERO;
110    }
111
112
113    /**
114     * Get the one element.
115     * @return q as BigQuaternion.
116     */
117    public BigQuaternion getONE() {
118        return ONE;
119    }
120
121
122    /**
123     * Query if this ring is commutative.
124     * @return false.
125     */
126    public boolean isCommutative() {
127        return false;
128    }
129
130
131    /**
132     * Query if this ring is associative.
133     * @return true.
134     */
135    public boolean isAssociative() {
136        return true;
137    }
138
139
140    /**
141     * Query if this ring is a field.
142     * @return true.
143     */
144    public boolean isField() {
145        return !integral;
146    }
147
148
149    /**
150     * Characteristic of this ring.
151     * @return characteristic of this ring.
152     */
153    public java.math.BigInteger characteristic() {
154        return java.math.BigInteger.ZERO;
155    }
156
157
158    /**
159     * Get a BigQuaternion element from a BigInteger.
160     * @param a BigInteger.
161     * @return a BigQuaternion.
162     */
163    public BigQuaternion fromInteger(java.math.BigInteger a) {
164        return new BigQuaternion(this, new BigRational(a));
165    }
166
167
168    /**
169     * Get a BigQuaternion element from a long.
170     * @param a long.
171     * @return a BigQuaternion.
172     */
173    public BigQuaternion fromInteger(long a) {
174        return new BigQuaternion(this, new BigRational(a));
175    }
176
177
178    /**
179     * Get a BigQuaternion element from a long vector.
180     * @param a long vector.
181     * @return a BigQuaternion.
182     */
183    public BigQuaternion fromInteger(long[] a) {
184        return new BigQuaternion(this, new BigRational(a[0]), new BigRational(a[1]), new BigRational(a[2]),
185                        new BigRational(a[3]));
186    }
187
188
189    /**
190     * The constant 0.
191     */
192    public final BigQuaternion ZERO = new BigQuaternion(this);
193
194
195    /**
196     * The constant 1.
197     */
198    public final BigQuaternion ONE = new BigQuaternion(this, BigRational.ONE);
199
200
201    /**
202     * The constant i.
203     */
204    public final BigQuaternion I = new BigQuaternion(this, BigRational.ZERO, BigRational.ONE);
205
206
207    /**
208     * The constant j.
209     */
210    public final BigQuaternion J = new BigQuaternion(this, BigRational.ZERO, BigRational.ZERO,
211                    BigRational.ONE);
212
213
214    /**
215     * The constant k.
216     */
217    public final BigQuaternion K = new BigQuaternion(this, BigRational.ZERO, BigRational.ZERO,
218                    BigRational.ZERO, BigRational.ONE);
219
220
221    /**
222     * Get the string representation. Is compatible with the string constructor.
223     * @see java.lang.Object#toString()
224     */
225    @Override
226    public String toString() {
227        String s = "BigQuaternionRing(" + integral + ")";
228        return s;
229    }
230
231
232    /**
233     * Get a scripting compatible string representation.
234     * @return script compatible representation for this Element.
235     * @see edu.jas.structure.Element#toScript()
236     */
237    @Override
238    public String toScript() {
239        StringBuffer s = new StringBuffer("Quat(");
240        switch (Scripting.getLang()) {
241        case Ruby:
242            s.append((integral ? "true" : "" ));
243            break;
244        case Python:
245        default:
246            s.append((integral ? "True" : "" ));
247        }
248        s.append(")");
249        return s.toString();
250    }
251
252
253    /**
254     * Comparison with any other object.
255     * @see java.lang.Object#equals(java.lang.Object)
256     */
257    @Override
258    public boolean equals(Object b) {
259        if (!(b instanceof BigQuaternionRing)) {
260            return false;
261        }
262        BigQuaternionRing B = (BigQuaternionRing) b;
263        return this.integral == B.integral;
264    }
265
266
267    /**
268     * Hash code for this BigQuaternionRing.
269     * @see java.lang.Object#hashCode()
270     */
271    @Override
272    public int hashCode() {
273        int h = 4711;
274        return h;
275    }
276
277
278    /**
279     * BigQuaternion units of the Hurwitzian integers. BigQuaternion units with
280     * all integer or all 1/2 times integer components.
281     * @return list of all 24 units.
282     */
283    public List<BigQuaternion> unitsOfHurwitzian() {
284        if (entierUnits != null) {
285            return entierUnits;
286        }
287        BigRational half = BigRational.HALF;
288        // Lipschitz integer units
289        List<BigQuaternion> units = generators();
290        List<BigQuaternion> u = new ArrayList<BigQuaternion>(units);
291        for (BigQuaternion ue : u) {
292            units.add(ue.negate());
293        }
294        // Hurwitz integer units
295        long[][] comb = new long[][] { { 1, 1, 1, 1 }, { -1, 1, 1, 1 }, { 1, -1, 1, 1 }, { -1, -1, 1, 1 },
296                { 1, 1, -1, 1 }, { -1, 1, -1, 1 }, { 1, -1, -1, 1 }, { -1, -1, -1, 1 }, { 1, 1, 1, -1 },
297                { -1, 1, 1, -1 }, { 1, -1, 1, -1 }, { -1, -1, 1, -1 }, { 1, 1, -1, -1 }, { -1, 1, -1, -1 },
298                { 1, -1, -1, -1 }, { -1, -1, -1, -1 } };
299        for (long[] row : comb) {
300            BigQuaternion ue = fromInteger(row);
301            ue = ue.multiply(half);
302            units.add(ue);
303        }
304        //System.out.println("units = " + units);
305        //for (BigQuaternion ue : units) {
306        //System.out.println("unit = " + ue + ", norm = " + ue.norm());
307        //}
308        entierUnits = units;
309        return units;
310    }
311
312
313    /**
314     * BigQuaternion random. Random rational numbers A, B, C and D are generated
315     * using random(n). Then R is the quaternion number with real part A and
316     * imaginary parts B, C and D.
317     * @param n such that 0 &le; A, B, C, D &le; (2<sup>n</sup>-1).
318     * @return R, a random BigQuaternion.
319     */
320    public BigQuaternion random(int n) {
321        return random(n, random);
322    }
323
324
325    /**
326     * BigQuaternion random. Random rational numbers A, B, C and D are generated
327     * using RNRAND(n). Then R is the quaternion number with real part A and
328     * imaginary parts B, C and D.
329     * @param n such that 0 &le; A, B, C, D &le; (2<sup>n</sup>-1).
330     * @param rnd is a source for random bits.
331     * @return R, a random BigQuaternion.
332     */
333    public BigQuaternion random(int n, Random rnd) {
334        BigRational r = BigRational.ONE.random(n, rnd);
335        BigRational i = BigRational.ONE.random(n, rnd);
336        BigRational j = BigRational.ONE.random(n, rnd);
337        BigRational k = BigRational.ONE.random(n, rnd);
338        BigQuaternion q = new BigQuaternion(this, r, i, j, k);
339        if (integral) {
340            q = q.roundToHurwitzian();
341        }
342        return q;
343    }
344
345
346    /*
347     * Quaternion number, random. Random rational numbers A, B, C and D are
348     * generated using RNRAND(n). Then R is the quaternion number with real part
349     * A and imaginary parts B, C and D.
350     * @param n such that 0 &le; A, B, C, D &le; (2<sup>n</sup>-1).
351     * @return R, a random BigQuaternion.
352    public static BigQuaternion QRAND(int n) {
353        return ONE.random(n, random);
354    }
355     */
356
357
358    /**
359     * Parse quaternion number from String.
360     * @param s String.
361     * @return BigQuaternion from s.
362     */
363    public BigQuaternion parse(String s) {
364        return new BigQuaternion(this, s);
365    }
366
367
368    /**
369     * Parse quaternion number from Reader.
370     * @param r Reader.
371     * @return next BigQuaternion from r.
372     */
373    public BigQuaternion parse(Reader r) {
374        return parse(StringUtil.nextString(r));
375    }
376
377}