/**@file templates for Complex classes
unlike the built-in complex<> templates, these inline most operations for speed
*/

/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

*/




#ifndef COMPLEXCPP_H
#define COMPLEXCPP_H

#include <math.h>
#include <ostream>


template<class Real> class Complex {

public:

  Real r, i;

  /**@name constructors */
  //@{
  /**@name from real */
  //@{
  Complex(Real real, Real imag) {r=real; i=imag;}	// x=complex(a,b)
  Complex(Real real) {r=real; i=0;}			// x=complex(a)
  //@}
  /**@name from nothing */
  //@{
  Complex() {r=(Real)0; i=(Real)0;}			// x=complex()
  //@}
  /**@name from other complex */
  //@{
  Complex(const Complex<float>& z) {r=z.r; i=z.i;}	// x=complex(z)
  Complex(const Complex<double>& z) {r=z.r; i=z.i;}	// x=complex(z)
  Complex(const Complex<long double>& z) {r=z.r; i=z.i;}	// x=complex(z)
  //@}
  //@}

  /**@name casting up from basic numeric types */
  //@{
  Complex& operator=(char a) { r=(Real)a; i=(Real)0; return *this; }
  Complex& operator=(int a) { r=(Real)a; i=(Real)0; return *this; }
  Complex& operator=(long int a) { r=(Real)a; i=(Real)0; return *this; }
  Complex& operator=(short a) { r=(Real)a; i=(Real)0; return *this; }
  Complex& operator=(float a) { r=(Real)a; i=(Real)0; return *this; }
  Complex& operator=(double a) { r=(Real)a; i=(Real)0; return *this; }
  Complex& operator=(long double a) { r=(Real)a; i=(Real)0; return *this; }
  //@}

  /**@name arithmetic */
  //@{
  /**@ binary operators */
  //@{
  Complex operator+(const Complex<Real>& a) const { return Complex<Real>(r+a.r, i+a.i); }
  Complex operator+(Real a) const { return Complex<Real>(r+a,i); }
  Complex operator-(const Complex<Real>& a) const { return Complex<Real>(r-a.r, i-a.i); }
  Complex operator-(Real a) const { return Complex<Real>(r-a,i); }
  Complex operator*(const Complex<Real>& a) const { return Complex<Real>(r*a.r-i*a.i, r*a.i+i*a.r); }
  Complex operator*(Real a) const { return Complex<Real>(r*a, i*a); }
  Complex operator/(const Complex<Real>& a) const { return operator*(a.inv()); }
  Complex operator/(Real a) const { return Complex<Real>(r/a, i/a); }
  //@}
  /*@name component-wise product */
  //@{
  Complex operator&(const Complex<Real>& a) const { return Complex<Real>(r*a.r, i*a.i); }
  //@}
  /*@name inplace operations */
  //@{
  Complex& operator+=(const Complex<Real>&);
  Complex& operator-=(const Complex<Real>&);
  Complex& operator*=(const Complex<Real>&);
  Complex& operator/=(const Complex<Real>&);
  Complex& operator+=(Real);
  Complex& operator-=(Real);
  Complex& operator*=(Real);
  Complex& operator/=(Real);
  //@}
  //@}

  /**@name comparisons */
  //@{
  bool operator==(const Complex<Real>& a) const { return ((i==a.i)&&(r==a.r)); }
  bool operator!=(const Complex<Real>& a) const { return ((i!=a.i)||(r!=a.r)); }
  bool operator<(const Complex<Real>& a) const { return norm2()<a.norm2(); }
  bool operator>(const Complex<Real>& a) const { return norm2()>a.norm2(); }
  //@}

  /// reciprocation
  Complex inv() const;	

  // unary functions -- inlined
  /**@name unary functions */
  //@{
  /**@name inlined */
  //@{
  Complex conj() const { return Complex<Real>(r,-i); }
  Real norm2() const { return i*i+r*r; }
  Complex flip() const { return Complex<Real>(i,r); }
  Real real() const { return r;}
  Real imag() const { return i;}
  Complex neg() const { return Complex<Real>(-r, -i); }
  bool isZero() const { return ((r==(Real)0) && (i==(Real)0)); }
  //@}
  /**@name not inlined due to outside calls */
  //@{
  Real abs() const { return ::sqrt(norm2()); }
  Real arg() const { return ::atan2(i,r); }
  float dB() const { return 10.0*log10(norm2()); }
  Complex exp() const { return expj(i)*(::exp(r)); }
  Complex unit() const; 			///< unit phasor with same angle
  Complex log() const { return Complex(::log(abs()),arg()); }
  Complex pow(double n) const { return expj(arg()*n)*(::pow(abs(),n)); }
  Complex sqrt() const { return pow(0.5); }
  //@}
  //@}

};


/**@name standard Complex manifestations */
//@{
typedef Complex<float> complex;
typedef Complex<double> dcomplex;
typedef Complex<short> complex16;
typedef Complex<long> complex32;
//@}


template<class Real> inline Complex<Real> Complex<Real>::inv() const
{
  Real nVal;

  nVal = norm2();
  return Complex<Real>(r/nVal, -i/nVal);
}

template<class Real> Complex<Real>& Complex<Real>::operator+=(const Complex<Real>& a)
{
  r += a.r;
  i += a.i;
  return *this;
}

template<class Real> Complex<Real>& Complex<Real>::operator*=(const Complex<Real>& a)
{
  operator*(a);
  return *this;
}

template<class Real> Complex<Real>& Complex<Real>::operator-=(const Complex<Real>& a)
{
  r -= a.r;
  i -= a.i;
  return *this;
}

template<class Real> Complex<Real>& Complex<Real>::operator/=(const Complex<Real>& a)
{
  operator/(a);
  return *this;
}


/* op= style operations with reals */

template<class Real> Complex<Real>& Complex<Real>::operator+=(Real a)
{
  r += a;
  return *this;
}

template<class Real> Complex<Real>& Complex<Real>::operator*=(Real a)
{
  r *=a;
  i *=a;
  return *this;
}

template<class Real> Complex<Real>& Complex<Real>::operator-=(Real a)
{
  r -= a;
  return *this;
}

template<class Real> Complex<Real>& Complex<Real>::operator/=(Real a)
{
  r /= a;
  i /= a;
  return *this;
}


template<class Real> Complex<Real> Complex<Real>::unit() const
{
  Real absVal = abs();
  return (Complex<Real>(r/absVal, i/absVal));
}



/**@name complex functions outside of the Complex<> class. */
//@{

/** this allows type-commutative multiplication */
template<class Real> Complex<Real> operator*(Real a, const Complex<Real>& z)
{
  return Complex<Real>(z.r*a, z.i*a);
}


/** this allows type-commutative addition */
template<class Real> Complex<Real> operator+(Real a, const Complex<Real>& z)
{
  return Complex<Real>(z.r+a, z.i);
}


/** this allows type-commutative subtraction */
template<class Real> Complex<Real> operator-(Real a, const Complex<Real>& z)
{
  return Complex<Real>(z.r-a, z.i);
}



/// e^jphi
template<class Real> Complex<Real> expj(Real phi)
{
  return Complex<Real>(cos(phi),sin(phi));
}

/// phasor expression of a complex number
template<class Real> Complex<Real> phasor(Real C, Real phi)
{
  return (expj(phi)*C);
}

/// formatted stream output
template<class Real> std::ostream& operator<<(std::ostream& os, const Complex<Real>& z)
{
  os << z.r << ' ';
  //os << z.r << ", ";
  //if (z.i>=0) { os << "+"; }
  os << z.i << "j";
  return os;
}

//@}


#endif
