// Complex.java
/*
 * Copyright (c) 2003 Jon S. Squire.  All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * -Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in
 *  the documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the author or the names of contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE AUTHOR AND CONTRIBUTORS
 * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE
 * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE
 * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL THE AUTHOR OR CONTRIBUTORS
 * OR SUCCEEDING LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF THE AUTHOR
 * OR CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or
 * intended for use in the design, construction, operation or
 * maintenance of any human use medical device.
 */

package myjava;

/** Immutable, complex numbers. A Complex consists of a real
 *  and imaginary part, called Cartesian coordinates.
 *
 *  The Complex class provides methods for arithmetic such as:
 *  add, subtract, multiply, divide, negate and invert.
 *  Also provided are complex functions sin, cos, tan, atan,
 *  sqrt, log, exp, pow, sinh, cosh, tanh, atanh.
 *
 *  Source code <a href="Complex.java">Complex.java</a>
 */

public strictfp class Complex extends Object
{
  double x, y; // Cartesian representation of complex

  /** cartesian coordinates real and imaginary are NaN */
  public Complex(){x=Double.NaN; y=Double.NaN;}

  /** construct a copy of a Complex object */
  public Complex(Complex z){x=z.real(); y=z.imaginary();}

  /** real value, imaginary=0.0 */
  public Complex(double x){this.x=x; y=0.0;}

  /** cartesian coordinates real and imaginary */
  public Complex(double x, double y){this.x=x; this.y=y;}

  /** convert cartesian to polar */
  public Complex polar(){double r = StrictMath.sqrt(
                                    this.x*this.x+this.y*this.y);
                         double a = StrictMath.atan2(this.y,this.x);
                         return new Complex(r,a);}

  /** convert polar to cartesian */
  public Complex cartesian(){return new Complex(this.x*StrictMath.cos(this.y),
                                               this.x*StrictMath.sin(this.y));}

  /** extract the real part of the complex number */ 
  public double real(){return this.x;}

  /** extract the imaginary part of the complex number */
  public double imaginary(){return this.y;}

  /** extract the magnitude of the complex number */ 
  public double magnitude(){return
                            StrictMath.sqrt(this.x*this.x+this.y*this.y);}

  /** extract the argument of the complex number */
  public double argument(){return StrictMath.atan2(this.y,this.x);}

  /** add complex numbers */ 
  public Complex add(Complex z){return new Complex
                                (this.x+z.x, this.y+z.y);}

  /** add a double to a complex number */
  public Complex add(double d){return new Complex
                                (this.x+d, this.y);}

  /** subtract z from the complex number */
  public Complex subtract(Complex z){return new Complex
                                     (this.x-z.x, this.y-z.y);}

  /** subtract the double d from the complex number */
  public Complex subtract(double d){return new Complex
                                     (this.x-d, this.y);}

  /** negate the complex number */
  public Complex negate(){return new Complex(-this.x, -this.y);}

  /** multiply complex numbers */ 
  public Complex multiply(Complex z){return new Complex
                          (this.x*z.x-this.y*z.y,
                           this.x*z.y+this.y*z.x);}

  /** multiply a complex number by a double */
  public Complex multiply(double d){return new Complex(this.x*d,this.y*d);}

  /** divide the complex number by z */
  public Complex divide(Complex z){double r=z.x*z.x+z.y*z.y;
                                   return new Complex
                                   ((this.x*z.x+this.y*z.y)/r,
                                    (this.y*z.x-this.x*z.y)/r);}

  /** divide the complex number by the double d */
  public Complex divide(double d){return new Complex(this.x/d,this.y/d);}

  /** invert the complex number */
  public Complex invert(){double r=this.x*this.x+this.y*this.y;
                          return new Complex(this.x/r, -this.y/r);}

  /** conjugate the complex number */
  public Complex conjugate(){return new Complex(this.x, -this.y);}

  /** compute the absolute value of a complex number */
  public double abs(){return  StrictMath.sqrt(this.x*this.x+this.y*this.y);}

  /** compare complex numbers for equality */
  public boolean equals(Complex z){return (z.x==this.x) &&
                                          (z.y==this.y);}

  /** convert a complex number to a String. 
   *  Complex z = new Complex(1.0,2.0);
   *  System.out.println("z="+z); */
  public String toString(){return new String("("+this.x+","+this.y+")");}

  /** convert text representation to a Complex.  
   *  input format  (real_double,imaginary_double) */
  public static Complex parseComplex(String s){
      int from = s.indexOf('(');
      if(from==-1) return null;
      int to = s.indexOf(',',from);
      double x = Double.parseDouble(s.substring(from+1,to));
      from = to;
      to = s.indexOf(')',from);
      double y = Double.parseDouble(s.substring(from+1,to));
      return new Complex(x,y); }

  /** compute e to the power of the complex number */
  public Complex exp(){double exp_x=StrictMath.exp(this.x);
                       return new Complex
                       (exp_x*StrictMath.cos(this.y),
                        exp_x*StrictMath.sin(this.y));}

  /** compute the natural logarithm of the complex number */
  public Complex log(){double rpart=StrictMath.sqrt(
                       this.x*this.x+this.y*this.y);
                       double ipart=StrictMath.atan2(this.y,this.x);
                       if(ipart>StrictMath.PI) ipart=ipart-2.0*StrictMath.PI;
                       return new Complex(StrictMath.log(rpart), ipart);}

  /** compute the square root of the complex number */
  public Complex sqrt(){double r=StrictMath.sqrt(this.x*this.x+this.y*this.y);
                        double rpart=StrictMath.sqrt(0.5*(r+this.x));
                        double ipart=StrictMath.sqrt(0.5*(r-this.x));
                        if(this.y<0.0) ipart=-ipart;
                        return new Complex(rpart,ipart);}
                       
  /** compute the complex number raised to the power z */
  public Complex pow(Complex z){Complex a=z.multiply(this.log());
                                return a.exp();}
                       
  /** compute the complex number raised to the power double d */
  public Complex pow(double d){Complex a=(this.log()).multiply(d);
                                return a.exp();}

  /** compute the sin of the complex number */
  public Complex sin(){return new Complex
                       (StrictMath.sin(this.x)*cosh(this.y),
                        StrictMath.cos(this.x)*sinh(this.y));}

  /** compute the cosine of the complex number */
  public Complex cos(){return new Complex
                       (StrictMath.cos(this.x)*cosh(this.y),
                        -StrictMath.sin(this.x)*sinh(this.y));}

  /** compute the tangent of the complex number */
  public Complex tan(){return (this.sin()).divide(this.cos());}

  /** compute the arctangent of a complex number */
  public Complex atan(){Complex IM = new Complex(0.0,-1.0);
                        Complex ZP = new Complex(1.0+this.y,this.x);
                        Complex ZM = new Complex(1.0-this.y,this.x);
                        return IM.multiply(((ZP.log()).subtract(
                               ZM.log())).divide(2.0));}

  /** compute the hyperbolic sin of the complex number */
  public Complex sinh(){return new Complex
                       (sinh(this.x)*StrictMath.cos(this.y),
                        cosh(this.x)*StrictMath.sin(this.y));}

  /** compute the hyperbolic cosine of the complex number */
  public Complex cosh(){return new Complex
                       (cosh(this.x)*StrictMath.cos(this.y),
                        sinh(this.x)*StrictMath.sin(this.y));}

  /** compute the hyperbolic tangent of the complex number */
  public Complex tanh(){return (this.sinh()).divide(this.cosh());}

  /** compute the inverse hyperbolic tangent of a complex number */
    public Complex atanh(){return (((this.add(1.0)).log()).subtract(
				   ((this.subtract(1.0)).negate()).log())
				   .divide(2.0));}

  
  // local - should be a good implementation in StrictMath
  private double sinh(double x){return(
                                StrictMath.exp(x)-StrictMath.exp(-x))/2.0;}
  private double cosh(double x){return(
                                StrictMath.exp(x)+StrictMath.exp(-x))/2.0;}
}
