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