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 ≤ A, B ≤ (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 ≤ A, B ≤ (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 ≤ A, B ≤ (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 }