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