/*

 File: cinterval.h, 2003/07/29

 CoStLy (COmplex interval STandard functions LibrarY), Version 2.0.4

 Copyright (C) Markus Neher, markus.neher@math.uni-karlsruhe.de
               Ingo Eble,    ingoeble@web.de

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 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.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef CINTERVAL_H_INCLUDED
#define CINTERVAL_H_INCLUDED

#include "adaptintval.h"

using Adapt::Interval;

#include <iostream>
#include <complex>

typedef std::complex<double> Complex;

class CInterval
{
private:

  Interval real_part,imag_part;

public:

  CInterval() {}
  CInterval(const Interval& x, const Interval& y) : real_part(x), imag_part(y) {}
  CInterval(const CInterval& z) : real_part(z.real_part), imag_part(z.imag_part) {}

  explicit CInterval(const double& d)   : real_part(d), imag_part(0.0) {}
  explicit CInterval(const Complex& c)  : real_part(c.real()), imag_part(c.imag()) {}
  explicit CInterval(const Interval& x) : real_part(x), imag_part(0.0) {}

  CInterval& operator = (const CInterval& z)
  {
    real_part = z.real_part;
    imag_part = z.imag_part;

    return *this;
  }

  Interval& re() { return real_part; }  
  Interval& im() { return imag_part; }
  const Interval& re() const { return real_part; }  
  const Interval& im() const { return imag_part; }

  Interval abs () const { return sqrt(sqr(real_part)+sqr(imag_part));           }
  Complex  mid () const { return Complex( real_part.mid() , imag_part.mid() );  }
  Complex  diam() const { return Complex( real_part.diam(), imag_part.diam() ); }

  /*
    set operations
  */

  CInterval& intersect(const CInterval& z)
    {
      real_part.intersect(z.real_part);
      imag_part.intersect(z.imag_part);

      return *this;
    }

  CInterval& operator &= (const CInterval& z)
    {
      real_part.intersect(z.real_part);
      imag_part.intersect(z.imag_part);

      return *this;
    }
  
  CInterval& hull(const CInterval& z)
    {
      real_part.hull(z.real_part);
      imag_part.hull(z.imag_part);

      return *this;
    }

  CInterval& operator |= (const CInterval& z)
    {
      real_part.hull(z.real_part);
      imag_part.hull(z.imag_part);

      return *this;
    }

  bool disjoint(const CInterval& z) const
    {
      return (real_part.disjoint(z.real_part) || imag_part.disjoint(z.imag_part));
    }

  bool contains(const Complex& z) const
    {
      return (real_part.contains(z.real()) && imag_part.contains(z.imag()));
    }

  bool subset(const CInterval& z) const
    {
      return (real_part.subset(z.real_part) && imag_part.subset(z.imag_part));
    }

  bool superset(const CInterval& z) const
    {
      return (real_part.superset(z.real_part) && imag_part.superset(z.imag_part));
    }

  /*
    arithmetic operations
  */

  CInterval operator - () const { return CInterval(-real_part,-imag_part); }
  CInterval& operator += (const CInterval& z)
  {
    real_part += z.real_part;
    imag_part += z.imag_part;

    return *this;
  }
  
  CInterval& operator -= (const CInterval& z)
  {
    real_part -= z.real_part;
    imag_part -= z.imag_part;

    return *this;
  }

  CInterval& operator *= (const CInterval& z)
  {
    Interval tmp( real_part );

    real_part = real_part*z.real_part - imag_part*z.imag_part;
    imag_part = tmp      *z.imag_part + imag_part*z.real_part;

    return *this;
  }

  CInterval& operator /= (const CInterval&);

  CInterval& operator += (const Interval& x)
  {
    real_part += x;

    return *this;
  }
  
  CInterval& operator -= (const Interval& x)
  {
    real_part -= x;

    return *this;
  }

  CInterval& operator *= (const Interval& x)
  {
    real_part *= x;
    imag_part *= x;

    return *this;
  }

  CInterval& operator /= (const Interval& x)
    {
      real_part /= x;
      imag_part /= x;

      return *this;
    }

  CInterval& operator += (const double& d)
  {
    real_part += d;

    return *this;
  }
  
  CInterval& operator -= (const double& d)
  {
    real_part -= d;

    return *this;
  }

  CInterval& operator *= (const double& d)
  {
    real_part *= d;
    imag_part *= d;

    return *this;
  }

  CInterval& operator /= (const double& d)
    {
      real_part /= d;
      imag_part /= d;

      return *this;
    }

  /*
    friend functions
  */
  
  friend bool operator == (const CInterval& w, const CInterval& z) 
    { 
      return (w.real_part == z.real_part && w.imag_part == z.imag_part); 
    }
  friend bool operator != (const CInterval& w, const CInterval& z) 
    { 
      return (w.real_part != z.real_part || w.imag_part != z.imag_part); 
    }
  
  friend std::ostream& operator << (std::ostream&, const CInterval&);
  friend std::istream& operator >> (std::istream&,       CInterval&);
  friend std::string&  operator << (std::string& s,const CInterval& z)
    { std::ostringstream out;    out << z; return (s = out.str()); }
  friend std::string&  operator >> (std::string& s,      CInterval& z)
    { std::istringstream in(s);  in  >> z; return (s = in .str()); }
};

inline Interval& Re(CInterval& z) { return z.re(); }
inline Interval& Im(CInterval& z) { return z.im(); }
inline const Interval& Re(const CInterval& z) { return z.re(); }
inline const Interval& Im(const CInterval& z) { return z.im(); }

inline Interval abs (const CInterval& z) { return z.abs();  }
inline Complex  mid (const CInterval& z) { return z.mid();  }
inline Complex  diam(const CInterval& z) { return z.diam(); }

//

inline CInterval intersect  (const CInterval& w, const CInterval& z) 
{ 
  CInterval result(w); 
  return result.intersect(z);
}
inline CInterval operator & (const CInterval& w, const CInterval& z) 
{ 
  CInterval result(w); 
  return result.intersect(z);
}

// CInterval o CInterval, o \in { +,-,* }.

inline CInterval operator + (const CInterval& w, const CInterval& z)
{ 
  CInterval result(w); 
  return result += z; 
}
inline CInterval operator - (const CInterval& w, const CInterval& z)
{ 
  CInterval result(w); 
  return result -= z; 
}
inline CInterval operator * (const CInterval& w, const CInterval& z)
{ 
  CInterval result(w); 
  return result *= z; 
}
inline CInterval operator / (const CInterval& w, const CInterval& z)
{ 
  CInterval result(w); 
  return result /= z; 
}

// Interval o CInterval, o \in { +,-,* }.

inline CInterval operator + (const Interval& x, const CInterval& z)
{ 
  CInterval result(z); 
  return result += x; 
}
inline CInterval operator - (const Interval& x, const CInterval& z)
{ 
  CInterval result(-z); 
  return result += x; 
}
inline CInterval operator * (const Interval& x, const CInterval& z)
{ 
  CInterval result(z); 
  return result *= x; 
}
inline CInterval operator / (const Interval& x, const CInterval& z)
{ 
  CInterval result(x); 
  return result /= z; 
}

// CInterval o Interval, o \in { +,-,* }.

inline CInterval operator + (const CInterval& z, const Interval& x) 
{ 
  CInterval result(z); 
  return result += x; 
}
inline CInterval operator - (const CInterval& z, const Interval& x) 
{ 
  CInterval result(z); 
  return result -= x; 
}
inline CInterval operator * (const CInterval& z, const Interval& x) 
{ 
  CInterval result(z); 
  return result *= x; 
}
inline CInterval operator / (const CInterval& z, const Interval& x) 
{ 
  CInterval result(z); 
  return result /= x; 
}

// double o CInterval, o \in { +,-,* }.

inline CInterval operator + (const double& d, const CInterval& z)
{ 
  CInterval result(z); 
  return result += d; 
}
inline CInterval operator - (const double& d, const CInterval& z)
{ 
  CInterval result(-z); 
  return result += d; 
}
inline CInterval operator * (const double& d, const CInterval& z)
{ 
  CInterval result(z); 
  return result *= d; 
}
inline CInterval operator / (const double& d, const CInterval& z)
{ 
  CInterval result(d); 
  return result /= z; 
}

// CInterval o double, o \in { +,-,* }.

inline CInterval operator + (const CInterval& z, const double& d) 
{ 
  CInterval result(z); 
  return result += d; 
}
inline CInterval operator - (const CInterval& z, const double& d) 
{ 
  CInterval result(z); 
  return result -= d; 
}
inline CInterval operator * (const CInterval& z, const double& d) 
{ 
  CInterval result(z); 
  return result *= d; 
}
inline CInterval operator / (const CInterval& z, const double& d) 
{ 
  CInterval result(z); 
  return result /= d; 
}

//

inline bool operator <= (const double& d, const CInterval& z) { return z.contains(Complex(d,0.0)); }

#endif

/*

  End of File: cinterval.h

*/
