001/*
002 * $Id: BigComplex.java 4640 2013-09-14 11:32:01Z 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 * BigComplex class based on BigRational implementing the RingElem respectively
024 * the StarRingElem interface. Objects of this class are immutable. The SAC2
025 * static methods are also provided.
026 * @author Heinz Kredel
027 */
028public final class BigComplex implements StarRingElem<BigComplex>, GcdRingElem<BigComplex>,
029                RingFactory<BigComplex> {
030
031
032    /**
033     * Real part of the data structure.
034     */
035    public final BigRational re;
036
037
038    /**
039     * Imaginary part of the data structure.
040     */
041    public final BigRational im;
042
043
044    private final static Random random = new Random();
045
046
047    private static final Logger logger = Logger.getLogger(BigComplex.class);
048
049
050    /**
051     * The constructor creates a BigComplex object from two BigRational objects
052     * real and imaginary part.
053     * @param r real part.
054     * @param i imaginary part.
055     */
056    public BigComplex(BigRational r, BigRational i) {
057        re = r;
058        im = i;
059    }
060
061
062    /**
063     * The constructor creates a BigComplex object from a BigRational object as
064     * real part, the imaginary part is set to 0.
065     * @param r real part.
066     */
067    public BigComplex(BigRational r) {
068        this(r, BigRational.ZERO);
069    }
070
071
072    /**
073     * The constructor creates a BigComplex object from a long element as real
074     * part, the imaginary part is set to 0.
075     * @param r real part.
076     */
077    public BigComplex(long r) {
078        this(new BigRational(r), BigRational.ZERO);
079    }
080
081
082    /**
083     * The constructor creates a BigComplex object with real part 0 and
084     * imaginary part 0.
085     */
086    public BigComplex() {
087        this(BigRational.ZERO);
088    }
089
090
091    /**
092     * The constructor creates a BigComplex object from a String representation.
093     * @param s string of a BigComplex.
094     * @throws NumberFormatException
095     */
096    public BigComplex(String s) throws NumberFormatException {
097        if (s == null || s.length() == 0) {
098            re = BigRational.ZERO;
099            im = BigRational.ZERO;
100            return;
101        }
102        s = s.trim();
103        int i = s.indexOf("i");
104        if (i < 0) {
105            re = new BigRational(s);
106            im = BigRational.ZERO;
107            return;
108        }
109        //logger.warn("String constructor not done");
110        String sr = "";
111        if (i > 0) {
112            sr = s.substring(0, i);
113        }
114        String si = "";
115        if (i < s.length()) {
116            si = s.substring(i + 1, s.length());
117        }
118        //int j = sr.indexOf("+");
119        re = new BigRational(sr.trim());
120        im = new BigRational(si.trim());
121    }
122
123
124    /**
125     * Get the corresponding element factory.
126     * @return factory for this Element.
127     * @see edu.jas.structure.Element#factory()
128     */
129    public BigComplex factory() {
130        return this;
131    }
132
133
134    /**
135     * Get a list of the generating elements.
136     * @return list of generators for the algebraic structure.
137     * @see edu.jas.structure.ElemFactory#generators()
138     */
139    public List<BigComplex> generators() {
140        List<BigComplex> g = new ArrayList<BigComplex>(2);
141        g.add(getONE());
142        g.add(getIMAG());
143        return g;
144    }
145
146
147    /**
148     * Is this structure finite or infinite.
149     * @return true if this structure is finite, else false.
150     * @see edu.jas.structure.ElemFactory#isFinite()
151     */
152    public boolean isFinite() {
153        return false;
154    }
155
156
157    /**
158     * Clone this.
159     * @see java.lang.Object#clone()
160     */
161    @Override
162    public BigComplex copy() {
163        return new BigComplex(re, im);
164    }
165
166
167    /**
168     * Copy BigComplex element c.
169     * @param c BigComplex.
170     * @return a copy of c.
171     */
172    public BigComplex copy(BigComplex c) {
173        return new BigComplex(c.re, c.im);
174    }
175
176
177    /**
178     * Get the zero element.
179     * @return 0 as BigComplex.
180     */
181    public BigComplex getZERO() {
182        return ZERO;
183    }
184
185
186    /**
187     * Get the one element.
188     * @return 1 as BigComplex.
189     */
190    public BigComplex getONE() {
191        return ONE;
192    }
193
194
195    /**
196     * Get the i element.
197     * @return i as BigComplex.
198     */
199    public BigComplex getIMAG() {
200        return I;
201    }
202
203
204    /**
205     * Query if this ring is commutative.
206     * @return true.
207     */
208    public boolean isCommutative() {
209        return true;
210    }
211
212
213    /**
214     * Query if this ring is associative.
215     * @return true.
216     */
217    public boolean isAssociative() {
218        return true;
219    }
220
221
222    /**
223     * Query if this ring is a field.
224     * @return true.
225     */
226    public boolean isField() {
227        return true;
228    }
229
230
231    /**
232     * Characteristic of this ring.
233     * @return characteristic of this ring.
234     */
235    public java.math.BigInteger characteristic() {
236        return java.math.BigInteger.ZERO;
237    }
238
239
240    /**
241     * Get a BigComplex element from a BigInteger.
242     * @param a BigInteger.
243     * @return a BigComplex.
244     */
245    public BigComplex fromInteger(BigInteger a) {
246        return new BigComplex(new BigRational(a));
247    }
248
249
250    /**
251     * Get a BigComplex element from a long.
252     * @param a long.
253     * @return a BigComplex.
254     */
255    public BigComplex fromInteger(long a) {
256        return new BigComplex(new BigRational(a));
257    }
258
259
260    /**
261     * The constant 0.
262     */
263    public static final BigComplex ZERO = new BigComplex();
264
265
266    /**
267     * The constant 1.
268     */
269    public static final BigComplex ONE = new BigComplex(BigRational.ONE);
270
271
272    /**
273     * The constant i.
274     */
275    public static final BigComplex I = new BigComplex(BigRational.ZERO, BigRational.ONE);
276
277
278    /**
279     * Get the real part.
280     * @return re.
281     */
282    public BigRational getRe() {
283        return re;
284    }
285
286
287    /**
288     * Get the imaginary part.
289     * @return im.
290     */
291    public BigRational getIm() {
292        return im;
293    }
294
295
296    /**
297     * Get the String representation.
298     */
299    @Override
300    public String toString() {
301        String s = "" + re;
302        int i = im.compareTo(BigRational.ZERO);
303        //logger.info("compareTo "+im+" ? 0 = "+i);
304        if (i == 0)
305            return s;
306        s += "i" + im;
307        return s;
308    }
309
310
311    /**
312     * Get a scripting compatible string representation.
313     * @return script compatible representation for this Element.
314     * @see edu.jas.structure.Element#toScript()
315     */
316    @Override
317    public String toScript() {
318        // Python case: re or re+im*i 
319        // was (re,im) or (re,) 
320        StringBuffer s = new StringBuffer();
321        boolean iz = im.isZERO();
322        if (iz) {
323            s.append(re.toScript());
324            return s.toString();
325        }
326        boolean rz = re.isZERO();
327        if (rz) {
328            if (!im.isONE()) {
329                if (im.signum() > 0) {
330                    s.append(im.toScript() + "*");
331                } else {
332                    s.append("-");
333                    BigRational ii = im.negate();
334                    if (!ii.isONE()) {
335                        s.append(ii.toScript() + "*");
336                    }
337                }
338            }
339        } else {
340            s.append(re.toScript());
341            if (im.signum() > 0) {
342                s.append("+");
343                if (!im.isONE()) {
344                    s.append(im.toScript() + "*");
345                }
346            } else {
347                s.append("-");
348                BigRational ii = im.negate();
349                if (!ii.isONE()) {
350                    s.append(ii.toScript() + "*");
351                }
352            }
353        }
354        s.append("I");
355        return s.toString();
356    }
357
358
359    /**
360     * Get a scripting compatible string representation of the factory.
361     * @return script compatible representation for this ElemFactory.
362     * @see edu.jas.structure.Element#toScriptFactory()
363     */
364    @Override
365    public String toScriptFactory() {
366        // Python case
367        return "CC()";
368    }
369
370
371    /**
372     * Complex number zero.
373     * @param A is a complex number.
374     * @return If A is 0 then true is returned, else false.
375     */
376    public static boolean isCZERO(BigComplex A) {
377        if (A == null)
378            return false;
379        return A.isZERO();
380    }
381
382
383    /**
384     * Is Complex number zero.
385     * @return If this is 0 then true is returned, else false.
386     * @see edu.jas.structure.RingElem#isZERO()
387     */
388    public boolean isZERO() {
389        return re.equals(BigRational.ZERO) && im.equals(BigRational.ZERO);
390    }
391
392
393    /**
394     * Complex number one.
395     * @param A is a complex number.
396     * @return If A is 1 then true is returned, else false.
397     */
398    public static boolean isCONE(BigComplex A) {
399        if (A == null)
400            return false;
401        return A.isONE();
402    }
403
404
405    /**
406     * Is Complex number one.
407     * @return If this is 1 then true is returned, else false.
408     * @see edu.jas.structure.RingElem#isONE()
409     */
410    public boolean isONE() {
411        return re.equals(BigRational.ONE) && im.equals(BigRational.ZERO);
412    }
413
414
415    /**
416     * Is Complex imaginary one.
417     * @return If this is i then true is returned, else false.
418     */
419    public boolean isIMAG() {
420        return re.equals(BigRational.ZERO) && im.equals(BigRational.ONE);
421    }
422
423
424    /**
425     * Is Complex unit element.
426     * @return If this is a unit then true is returned, else false.
427     * @see edu.jas.structure.RingElem#isUnit()
428     */
429    public boolean isUnit() {
430        return (!isZERO());
431    }
432
433
434    /**
435     * Comparison with any other object.
436     * @see java.lang.Object#equals(java.lang.Object)
437     */
438    @Override
439    public boolean equals(Object b) {
440        if (!(b instanceof BigComplex)) {
441            return false;
442        }
443        BigComplex bc = (BigComplex) b;
444        return re.equals(bc.re) && im.equals(bc.im);
445    }
446
447
448    /**
449     * Hash code for this BigComplex.
450     * @see java.lang.Object#hashCode()
451     */
452    @Override
453    public int hashCode() {
454        return 37 * re.hashCode() + im.hashCode();
455    }
456
457
458    /**
459     * Since complex numbers are unordered, we use lexicographical order of re
460     * and im.
461     * @return 0 if this is equal to b; 1 if re > b.re, or re == b.re and im >
462     *         b.im; -1 if re < b.re, or re == b.re and im < b.im
463     */
464    @Override
465    public int compareTo(BigComplex b) {
466        int s = re.compareTo(b.re);
467        if (s != 0) {
468            return s;
469        }
470        return im.compareTo(b.im);
471    }
472
473
474    /**
475     * Since complex numbers are unordered, we use lexicographical order of re
476     * and im.
477     * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > 0; -1
478     *         if re < 0, or re == 0 and im < 0
479     * @see edu.jas.structure.RingElem#signum()
480     */
481    public int signum() {
482        int s = re.signum();
483        if (s != 0) {
484            return s;
485        }
486        return im.signum();
487    }
488
489
490    /* arithmetic operations: +, -, -
491     */
492
493    /**
494     * Complex number summation.
495     * @param B a BigComplex number.
496     * @return this+B.
497     */
498    public BigComplex sum(BigComplex B) {
499        return new BigComplex(re.sum(B.re), im.sum(B.im));
500    }
501
502
503    /**
504     * Complex number sum.
505     * @param A and B are complex numbers.
506     * @return A+B.
507     */
508    public static BigComplex CSUM(BigComplex A, BigComplex B) {
509        if (A == null)
510            return null;
511        return A.sum(B);
512    }
513
514
515    /**
516     * Complex number difference.
517     * @param A and B are complex numbers.
518     * @return A-B.
519     */
520    public static BigComplex CDIF(BigComplex A, BigComplex B) {
521        if (A == null)
522            return null;
523        return A.subtract(B);
524    }
525
526
527    /**
528     * Complex number subtract.
529     * @param B a BigComplex number.
530     * @return this-B.
531     */
532    public BigComplex subtract(BigComplex B) {
533        return new BigComplex(re.subtract(B.re), im.subtract(B.im));
534    }
535
536
537    /**
538     * Complex number negative.
539     * @param A is a complex number.
540     * @return -A
541     */
542    public static BigComplex CNEG(BigComplex A) {
543        if (A == null)
544            return null;
545        return A.negate();
546    }
547
548
549    /**
550     * Complex number negative.
551     * @return -this.
552     * @see edu.jas.structure.RingElem#negate()
553     */
554    public BigComplex negate() {
555        return new BigComplex(re.negate(), im.negate());
556    }
557
558
559    /**
560     * Complex number conjugate.
561     * @param A is a complex number.
562     * @return the complex conjugate of A.
563     */
564    public static BigComplex CCON(BigComplex A) {
565        if (A == null)
566            return null;
567        return A.conjugate();
568    }
569
570
571    /* arithmetic operations: conjugate, absolut value 
572     */
573
574    /**
575     * Complex number conjugate.
576     * @return the complex conjugate of this.
577     */
578    public BigComplex conjugate() {
579        return new BigComplex(re, im.negate());
580    }
581
582
583    /**
584     * Complex number norm.
585     * @see edu.jas.structure.StarRingElem#norm()
586     * @return ||this||.
587     */
588    public BigComplex norm() {
589        // this.conjugate().multiply(this);
590        BigRational v = re.multiply(re);
591        v = v.sum(im.multiply(im));
592        return new BigComplex(v);
593    }
594
595
596    /**
597     * Complex number absolute value.
598     * @see edu.jas.structure.RingElem#abs()
599     * @return |this|^2. Note: The square root is not jet implemented.
600     */
601    public BigComplex abs() {
602        BigComplex n = norm();
603        logger.error("abs() square root missing");
604        // n = n.sqrt();
605        return n;
606    }
607
608
609    /**
610     * Complex number absolute value.
611     * @param A is a complex number.
612     * @return the absolute value of A, a rational number. Note: The square root
613     *         is not jet implemented.
614     */
615    public static BigRational CABS(BigComplex A) {
616        if (A == null)
617            return null;
618        return A.abs().re;
619    }
620
621
622    /**
623     * Complex number product.
624     * @param A and B are complex numbers.
625     * @return A*B.
626     */
627    public static BigComplex CPROD(BigComplex A, BigComplex B) {
628        if (A == null)
629            return null;
630        return A.multiply(B);
631    }
632
633
634    /* arithmetic operations: *, inverse, / 
635     */
636
637
638    /**
639     * Complex number product.
640     * @param B is a complex number.
641     * @return this*B.
642     */
643    public BigComplex multiply(BigComplex B) {
644        return new BigComplex(re.multiply(B.re).subtract(im.multiply(B.im)), re.multiply(B.im).sum(
645                        im.multiply(B.re)));
646    }
647
648
649    /**
650     * Complex number inverse.
651     * @param A is a non-zero complex number.
652     * @return S with S*A = 1.
653     */
654    public static BigComplex CINV(BigComplex A) {
655        if (A == null)
656            return null;
657        return A.inverse();
658    }
659
660
661    /**
662     * Complex number inverse.
663     * @return S with S*this = 1.
664     * @see edu.jas.structure.RingElem#inverse()
665     */
666    public BigComplex inverse() {
667        BigRational a = norm().re.inverse();
668        return new BigComplex(re.multiply(a), im.multiply(a.negate()));
669    }
670
671
672    /**
673     * Complex number inverse.
674     * @param S is a complex number.
675     * @return 0.
676     */
677    public BigComplex remainder(BigComplex S) {
678        if (S.isZERO()) {
679            throw new ArithmeticException("division by zero");
680        }
681        return ZERO;
682    }
683
684
685    /**
686     * Complex number quotient.
687     * @param A and B are complex numbers, B non-zero.
688     * @return A/B.
689     */
690    public static BigComplex CQ(BigComplex A, BigComplex B) {
691        if (A == null)
692            return null;
693        return A.divide(B);
694    }
695
696
697    /**
698     * Complex number divide.
699     * @param B is a complex number, non-zero.
700     * @return this/B.
701     */
702    public BigComplex divide(BigComplex B) {
703        return this.multiply(B.inverse());
704    }
705
706
707    /**
708     * Quotient and remainder by division of this by S.
709     * @param S a complex number
710     * @return [this/S, this - (this/S)*S].
711     */
712    public BigComplex[] quotientRemainder(BigComplex S) {
713        return new BigComplex[] { divide(S), ZERO };
714    }
715
716
717    /**
718     * Complex number, random. Random rational numbers A and B are generated
719     * using random(n). Then R is the complex number with real part A and
720     * imaginary part B.
721     * @param n such that 0 &le; A, B &le; (2<sup>n</sup>-1).
722     * @return R.
723     */
724    public BigComplex random(int n) {
725        return random(n, random);
726    }
727
728
729    /**
730     * Complex number, random. Random rational numbers A and B are generated
731     * using random(n). Then R is the complex number with real part A and
732     * imaginary part B.
733     * @param n such that 0 &le; A, B &le; (2<sup>n</sup>-1).
734     * @param rnd is a source for random bits.
735     * @return R.
736     */
737    public BigComplex random(int n, Random rnd) {
738        BigRational r = BigRational.ONE.random(n, rnd);
739        BigRational i = BigRational.ONE.random(n, rnd);
740        return new BigComplex(r, i);
741    }
742
743
744    /**
745     * Complex number, random. Random rational numbers A and B are generated
746     * using random(n). Then R is the complex number with real part A and
747     * imaginary part B.
748     * @param n such that 0 &le; A, B &le; (2<sup>n</sup>-1).
749     * @return R.
750     */
751    public static BigComplex CRAND(int n) {
752        return ONE.random(n, random);
753    }
754
755
756    /**
757     * Parse complex number from string.
758     * @param s String.
759     * @return BigComplex from s.
760     */
761    public BigComplex parse(String s) {
762        return new BigComplex(s);
763    }
764
765
766    /**
767     * Parse complex number from Reader.
768     * @param r Reader.
769     * @return next BigComplex from r.
770     */
771    public BigComplex parse(Reader r) {
772        return parse(StringUtil.nextString(r));
773    }
774
775
776    /**
777     * Complex number greatest common divisor.
778     * @param S BigComplex.
779     * @return gcd(this,S).
780     */
781    public BigComplex gcd(BigComplex S) {
782        if (S == null || S.isZERO()) {
783            return this;
784        }
785        if (this.isZERO()) {
786            return S;
787        }
788        return ONE;
789    }
790
791
792    /**
793     * BigComplex extended greatest common divisor.
794     * @param S BigComplex.
795     * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
796     */
797    public BigComplex[] egcd(BigComplex S) {
798        BigComplex[] ret = new BigComplex[3];
799        ret[0] = null;
800        ret[1] = null;
801        ret[2] = null;
802        if (S == null || S.isZERO()) {
803            ret[0] = this;
804            return ret;
805        }
806        if (this.isZERO()) {
807            ret[0] = S;
808            return ret;
809        }
810        BigComplex half = new BigComplex(new BigRational(1, 2));
811        ret[0] = ONE;
812        ret[1] = this.inverse().multiply(half);
813        ret[2] = S.inverse().multiply(half);
814        return ret;
815    }
816
817}