############# Class : cmplx ##############
package Math::Cephes::Complex;
use strict;
use vars qw(%OWNER %ITERATORS @ISA 
	    @EXPORT_OK %EXPORT_TAGS $VERSION);
require Math::Cephes;

require Exporter;
*import = \&Exporter::import;
@ISA = qw( Math::Cephes );
#my @cmplx = qw(clog cexp csin ccos ctan ccot casin cmplx
#	       cacos catan cadd csub cmul cdiv cmov cneg cabs csqrt
#	       csinh ccosh ctanh cpow casinh cacosh catanh);
@EXPORT_OK = qw(cmplx);
#%EXPORT_TAGS = ('cmplx' => [qw(cmplx)]);

%OWNER = ();
%ITERATORS = ();
$VERSION = '0.47';

*swig_r_get = *Math::Cephesc::cmplx_r_get;
*swig_r_set = *Math::Cephesc::cmplx_r_set;
*swig_i_get = *Math::Cephesc::cmplx_i_get;
*swig_i_set = *Math::Cephesc::cmplx_i_set;

sub new {
    my $pkg = shift;
    my $self = Math::Cephesc::new_cmplx(@_);
    bless $self, $pkg if defined($self); 
}

sub DESTROY {
    return unless $_[0]->isa('HASH');
    my $self = tied(%{$_[0]});
    return unless defined $self;
    delete $ITERATORS{$self};
    if (exists $OWNER{$self}) {
        Math::Cephesc::delete_cmplx($self);
        delete $OWNER{$self};
    }
}

sub DISOWN {
    my $self = shift;
    my $ptr = tied(%$self);
    delete $OWNER{$ptr};
}

sub ACQUIRE {
    my $self = shift;
    my $ptr = tied(%$self);
    $OWNER{$ptr} = 1;
}


sub r {
    my ($self, $value) = @_;
    return $self->{r} unless (defined $value);
    $self->{r} = $value;
    return $value;
}

sub i {
    my ($self, $value) = @_;
    return $self->{i} unless (defined $value);
    $self->{i} = $value;
    return $value;
}

sub cmplx {
  return Math::Cephes::Complex->new(@_);
}

sub as_string {
  my $z = shift;
  my $string;
  my $re = $z->{r};
  my $im = $z->{i};
  if ($im == 0) {
    $string = "$re";
  }
  else {
    $string = sprintf "%f %s %f %s", $re, 
      (int( $im / abs($im) ) == -1) ? '-' : '+' , 
	($im < 0) ? abs($im) : $im, 'i';
  }
  return $string;
}


sub cadd {
  my ($z1, $z2) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cadd($z1, $z2, $z);
  return $z;
}

sub csub {
  my ($z1, $z2) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::csub($z2, $z1, $z);
  return $z;
}

sub cmul {
  my ($z1, $z2) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cmul($z1, $z2, $z);
  return $z;
}

sub cdiv {
  my ($z1, $z2) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cdiv($z2, $z1, $z);
  return $z;
}

sub cpow {
  my ($z1, $z2) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cpow($z1, $z2, $z);
  return $z;
}

sub clog {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::clog($z1, $z);
  return $z;
}
sub cexp {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cexp($z1, $z);
  return $z;
}
sub csin {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::csin($z1, $z);
  return $z;
}
sub ccos {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::ccos($z1, $z);
  return $z;
}
sub ctan {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::ctan($z1, $z);
  return $z;
}
sub ccot {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::ccot($z1, $z);
  return $z;
}
sub casin {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::casin($z1, $z);
  return $z;
}
sub cacos {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cacos($z1, $z);
  return $z;
}
sub catan {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::catan($z1, $z);
  return $z;
}
sub cmov {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cmov($z1, $z);
  return $z;
}
sub cneg {
  my ($z1) = @_;
  Math::Cephes::cneg($z1);
  return $z1;
}
sub csqrt {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::csqrt($z1, $z);
  return $z;
}
sub cabs {
  my ($z1) = @_;
  my $abs = Math::Cephes::cabs($z1);
  return $abs;
}

sub csinh {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::csinh($z1, $z);
  return $z;
}
sub ccosh {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::ccosh($z1, $z);
  return $z;
}
sub ctanh {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::ctanh($z1, $z);
  return $z;
}
sub casinh {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::casinh($z1, $z);
  return $z;
}
sub cacosh {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::cacosh($z1, $z);
  return $z;
}
sub catanh {
  my ($z1) = @_;
  my $z = Math::Cephes::Complex->new();
  Math::Cephes::catanh($z1, $z);
  return $z;
}

1;

__END__

=head1 NAME

  Math::Cephes::Complex - Perl interface to the cephes complex number routines

=head1 SYNOPSIS

  use Math::Cephes::Complex qw(cmplx);
  my $z1 = cmplx(2,3);          # $z1 = 2 + 3 i
  my $z2 = cmplx(3,4);          # $z2 = 3 + 4 i
  my $z3 = $z1->radd($z2);      # $z3 = $z1 + $z2

=head1 DESCRIPTION

This module is a layer on top of the basic routines in the
cephes math library to handle complex numbers. A complex 
number is created via any of the following syntaxes:

  my $f = Math::Cephes::Complex->new(3, 2);   # $f = 3 + 2 i
  my $g = new Math::Cephes::Complex(5, 3);    # $g = 5 + 3 i
  my $h = cmplx(7, 5);                        # $h = 7 + 5 i

the last one being available by importing I<cmplx>. If no arguments
are specified, as in

 my $h = cmplx();

then the defaults $z = 0 + 0 i are assumed. The real and imaginary 
part of a complex number are represented respectively by

   $f->{r}; $f->{i};

or, as methods,

   $f->r;  $f->i;

and can be set according to

  $f->{r} = 4; $f->{i} = 9;

or, again, as methods,

  $f->r(4);   $f->i(9);
 
The complex number can be printed out as

  print $f->as_string;

A summary of the usage is as follows.

=over 4

=item I<csin>: Complex circular sine

 SYNOPSIS:

 # void csin();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->csin;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 If
     z = x + iy,

 then

     w = sin x  cosh y  +  i cos x sinh y.

=item I<ccos>: Complex circular cosine

 SYNOPSIS:

 # void ccos();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->ccos;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 If
     z = x + iy,

 then

     w = cos x  cosh y  -  i sin x sinh y.

=item I<ctan>: Complex circular tangent

 SYNOPSIS:

 # void ctan();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->ctan;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 If
     z = x + iy,

 then

           sin 2x  +  i sinh 2y
     w  =  --------------------.
            cos 2x  +  cosh 2y

 On the real axis the denominator is zero at odd multiples
 of PI/2.  The denominator is evaluated by its Taylor
 series near these points.

=item I<ccot>: Complex circular cotangent

 SYNOPSIS:

 # void ccot();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->ccot;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 If
     z = x + iy,

 then

           sin 2x  -  i sinh 2y
     w  =  --------------------.
            cosh 2y  -  cos 2x

 On the real axis, the denominator has zeros at even
 multiples of PI/2.  Near these points it is evaluated
 by a Taylor series.

=item I<casin>: Complex circular arc sine

 SYNOPSIS:

 # void casin();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->casin;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 Inverse complex sine:

                               2
 w = -i clog( iz + csqrt( 1 - z ) ).

=item I<cacos>: Complex circular arc cosine

 SYNOPSIS:

 # void cacos();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->cacos;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 w = arccos z  =  PI/2 - arcsin z.

=item I<catan>: Complex circular arc tangent

 SYNOPSIS:

 # void catan();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->catan;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 If
     z = x + iy,

 then
          1       (    2x     )
 Re w  =  - arctan(-----------)  +  k PI
          2       (     2    2)
                  (1 - x  - y )

               ( 2         2)
          1    (x  +  (y+1) )
 Im w  =  - log(------------)
          4    ( 2         2)
               (x  +  (y-1) )

 Where k is an arbitrary integer.

=item I<csinh>: Complex hyperbolic sine

  SYNOPSIS:
 
  # void csinh();
  # cmplx z, w;
 
 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->csinh;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 
  DESCRIPTION:
 
  csinh z = (cexp(z) - cexp(-z))/2
          = sinh x * cos y  +  i cosh x * sin y .

=item I<casinh>: Complex inverse hyperbolic sine

  SYNOPSIS:
 
  # void casinh();
  # cmplx z, w;
 
 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->casinh;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)
 
  DESCRIPTION:
 
  casinh z = -i casin iz .

=item I<ccosh>: Complex hyperbolic cosine

  SYNOPSIS:
 
  # void ccosh();
  # cmplx z, w;
  
 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->ccosh;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)
 
  DESCRIPTION:
 
  ccosh(z) = cosh x  cos y + i sinh x sin y .

=item I<cacosh>: Complex inverse hyperbolic cosine

 
  SYNOPSIS:
 
  # void cacosh();
  # cmplx z, w;
 
 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->cacosh;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w 
 print $w->as_string;           # prints $w as Re($w) + i Im($w)
 
  DESCRIPTION:
 
  acosh z = i acos z .

=item I<ctanh>: Complex hyperbolic tangent

 SYNOPSIS:

 # void ctanh();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->ctanh;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w  
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 tanh z = (sinh 2x  +  i sin 2y) / (cosh 2x + cos 2y) .

=item I<catanh>: Complex inverse hyperbolic tangent

  SYNOPSIS:
 
  # void catanh();
  # cmplx z, w;
 
 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->catanh;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w  
 print $w->as_string;           # prints $w as Re($w) + i Im($w)
 
  DESCRIPTION:
 
  Inverse tanh, equal to  -i catan (iz);

=item I<cpow>: Complex power function 

  SYNOPSIS:
 
  # void cpow();
  # cmplx a, z, w;
 
 $a = cmplx(5, 6);    # $z = 5 + 6 i
 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $a->cpow($z);
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w  
 print $w->as_string;           # prints $w as Re($w) + i Im($w)
 
  DESCRIPTION:
 
  Raises complex A to the complex Zth power.
  Definition is per AMS55 # 4.2.8,
  analytically equivalent to cpow(a,z) = cexp(z clog(a)). 

=item I<cmplx>: Complex number arithmetic

 SYNOPSIS:

 # typedef struct {
 #     double r;     real part
 #     double i;     imaginary part
 #    }cmplx;

 # cmplx *a, *b, *c;

 $a = cmplx(3, 5);   # $a = 3 + 5 i
 $b = cmplx(2, 3);   # $b = 2 + 3 i

 $c = $a->cadd( $b );  #   c = a + b
 $c = $a->csub( $b );  #   c = a - b
 $c = $a->cmul( $b );  #   c = a * b
 $c = $a->cdiv( $b );  #   c = a / b
 $c = $a->cneg;        #   c = -a
 $c = $a->cmov;        #   c = a

 print $c->{r}, '  ', $c->{i};   # prints real and imaginary parts of $c
 print $c->as_string;           # prints $c as Re($c) + i Im($c)


 DESCRIPTION:

 Addition:
    c.r  =  b.r + a.r
    c.i  =  b.i + a.i

 Subtraction:
    c.r  =  b.r - a.r
    c.i  =  b.i - a.i

 Multiplication:
    c.r  =  b.r * a.r  -  b.i * a.i
    c.i  =  b.r * a.i  +  b.i * a.r

 Division:
    d    =  a.r * a.r  +  a.i * a.i
    c.r  = (b.r * a.r  + b.i * a.i)/d
    c.i  = (b.i * a.r  -  b.r * a.i)/d

=item I<cabs>: Complex absolute value

 SYNOPSIS:

 # double a, cabs();
 # cmplx z;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $a = cabs( $z );

 DESCRIPTION:

 If z = x + iy

 then

       a = sqrt( x**2 + y**2 ).
 
 Overflow and underflow are avoided by testing the magnitudes
 of x and y before squaring.  If either is outside half of
 the floating point full scale range, both are rescaled.

=item I<csqrt>: Complex square root

 SYNOPSIS:

 # void csqrt();
 # cmplx z, w;

 $z = cmplx(2, 3);    # $z = 2 + 3 i
 $w = $z->csqrt;
 print $w->{r}, '  ', $w->{i};  # prints real and imaginary parts of $w
 print $w->as_string;           # prints $w as Re($w) + i Im($w)

 DESCRIPTION:

 If z = x + iy,  r = |z|, then

                       1/2
 Im w  =  [ (r - x)/2 ]   ,

 Re w  =  y / 2 Im w.

 Note that -w is also a square root of z.  The root chosen
 is always in the upper half plane.

 Because of the potential for cancellation error in r - x,
 the result is sharpened by doing a Heron iteration
 (see sqrt.c) in complex arithmetic.

=back

=head1 BUGS

 Please report any to Randy Kobes <randy@theoryx5.uwinnipeg.ca>

=head1 SEE ALSO

For the basic interface to the cephes complex number routines, see
L<Math::Cephes>. See also L<Math::Complex> 
for a more extensive interface to complex number routines.

=head1 COPYRIGHT

The C code for the Cephes Math Library is
Copyright 1984, 1987, 1989, 2002 by Stephen L. Moshier, 
and is available at http://www.netlib.org/cephes/.
Direct inquiries to 30 Frost Street, Cambridge, MA 02140.

The perl interface is copyright 2000, 2002 by Randy Kobes.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

=cut