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