PDLA

 view release on metacpan or  search on metacpan

Basic/Complex/complex.pd  view on Meta::CPAN

   [0 -1.70998i  1.48088 +0.854988i  -1.48088 +0.854988i]

Now plot the magnitude of (part of) the complex sine. First generate the
coefficients:

   pdl> $sin = i * zeroes(50)->xlinvals(2,4) + zeroes(50)->xlinvals(0,7)

Now plot the imaginary part, the real part and the magnitude of the sine
into the same diagram:

   pdl> use PDLA::Graphics::Gnuplot
   pdl> gplot( with => 'lines',
              PDLA::cat(im ( sin $sin ),
                       re ( sin $sin ),
                       abs( sin $sin ) ))

An ASCII version of this plot looks like this:

  30 ++-----+------+------+------+------+------+------+------+------+-----++
     +      +      +      +      +      +      +      +      +      +      +
     |                                                                   $$|
     |                                                                  $  |
  25 ++                                                               $$  ++
     |                                                              ***    |
     |                                                            **   *** |
     |                                                         $$*        *|
  20 ++                                                       $**         ++
     |                                                     $$$*           #|
     |                                                  $$$   *          # |
     |                                                $$     *           # |
  15 ++                                            $$$       *          # ++
     |                                          $$$        **           #  |
     |                                      $$$$          *            #   |
     |                                  $$$$              *            #   |
  10 ++                            $$$$$                 *            #   ++
     |                        $$$$$                     *             #    |
     |                 $$$$$$$                         *             #     |
   5 ++       $$$############                          *             #    ++
     |*****$$$###            ###                      *             #      |
     *    #*****                #                     *             #      |
     | ###      ***              ###                **              #      |
   0 ##            ***              #              *               #      ++
     |                *              #             *              #        |
     |                 ***            #          **               #        |
     |                    *            #        *                #         |
  -5 ++                    **           #      *                 #        ++
     |                       ***         ##  **                 #          |
     |                          *          #*                  #           |
     |                           ****    ***##                #            |
 -10 ++                              ****     #              #            ++
     |                                         #             #             |
     |                                          ##         ##              |
     +      +      +      +      +      +      +  ### + ###  +      +      +
 -15 ++-----+------+------+------+------+------+-----###-----+------+-----++
     0      5      10     15     20     25     30     35     40     45     50

=cut

my $i;
BEGIN { $i = bless pdl 0,1 }
sub i () { $i->copy };
EOD

for (qw(Ctan Catan re im i cplx real)) {
   pp_add_exported '', $_;
}

pp_addhdr <<'EOH';

#include <math.h>

#ifndef M_PI
# define M_PI   3.1415926535897932384626433832795029
#endif
#ifndef M_2PI
# define M_2PI  (2. * M_PI)
#endif

#if __GLIBC__ > 1 && (defined __USE_MISC || defined __USE_XOPEN || defined __USE_ISOC9X)
# define CABS(r,i) hypot (r, i)
#else
  static double
  CABS (double r, double i)
  {
    double t;

    if (r < 0) r = - r;
    if (i < 0) i = - i;

    if (i > r)
      {
        t = r; r = i; i = t;
      }

    if (r + i == r)
      return r;

    t = i / r;
    return r * sqrt (1 + t*t);
  }
#endif

#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 && defined __USE_GNU
# define SINCOS(x,s,c) sincos ((x), &(s), &(c))
#else
# define SINCOS(x,s,c)                  \
        (s) = sin (x);                  \
        (c) = cos (x);
#endif


#define CSQRT(type,ar,ai,cr,ci) 		\
        type mag = CABS ((ar), (ai));		\
        type t;					\
                                                \
        if (mag == 0)				\
          (cr) = (ci) = 0;			\
        else if ((ar) > 0)			\
          {					\
            t = sqrt (0.5 * (mag + (ar)));	\
            (cr) = t;				\

Basic/Complex/complex.pd  view on Meta::CPAN

           $c(m=>0) = 0.25 * (log(num) - log(den));
           $c(m=>1) = 0.5 * atan2 (2*ai, 1 - ar*ar - i2);
        ^
;

pp_def 'Cproj',
	Pars => 'a(m=2); [o]c(m=2)',
	Inplace => 1,
        GenericTypes => [F,D],
        Doc => 'compute the projection of a complex number to the riemann sphere. Works inplace',
        Code => q^
           $GENERIC() ar = $a(m=>0), ai = $a(m=>1);

           double den = ar*ar + ai*ai + 1;

           $c(m=>0) = 2*ar / den;
           $c(m=>1) = 2*ai / den;
        ^
;

pp_def 'Croots',
	Pars => 'a(m=2); [o]c(m=2,n)',
        OtherPars => 'int n => n',
        GenericTypes => [F,D],
        Doc => 'Compute the C<n> roots of C<a>. C<n> must be a positive integer. The result will always be a complex type!',
        PMCode => q^sub PDLA::Complex::Croots($$) {
           my ($pdl, $n) = @_;
           my $r = PDLA->null;
           &PDLA::Complex::_Croots_int($pdl, $r, $n);
           bless $r;
        }^,
        Code => q^
           double s, c;
           double ar = $a(m=>0), ai = $a(m=>1),
                  n1 = 1 / (double)$COMP(n),
                  rr = pow (CABS (ar, ai), n1), /* do not optimize the sqrt out of this expr! */
                  at = atan2 (ai, ar) * n1,
                  ti = M_2PI * n1;

           loop(n) %{
               SINCOS (at, s, c);

               $c(m=>0) = rr * c;
               $c(m=>1) = rr * s;

               at += ti;
            %}
        ^
;

pp_addpm <<'EOD';

=head2 re cplx, im cplx

Return the real or imaginary part of the complex number(s) given. These
are slicing operators, so data flow works. The real and imaginary parts
are returned as piddles (ref eq PDLA).

=cut

sub re($) { bless $_[0]->slice("(0)"), 'PDLA'; }
sub im($) { bless $_[0]->slice("(1)"), 'PDLA'; }

*PDLA::Complex::re = \&re;
*PDLA::Complex::im = \&im;

EOD

pp_def 'rCpolynomial',
       Pars => 'coeffs(n); x(c=2,m); [o]out(c=2,m)',
       Doc => 'evaluate the polynomial with (real) coefficients C<coeffs> at the (complex) position(s) C<x>. C<coeffs[0]> is the constant term.',
       GenericTypes => [F,D],
       Code => q!
          loop(m) %{
             double xr = 1;
             double xi = 0;
             double or = 0;
             double oi = 0;
             double Xr;

             loop(n) %{
                or += $coeffs() * xr;
                oi += $coeffs() * xi;

                Xr = xr;
                xr = Xr * $x(c=>0) - xi * $x(c=>1);
                xi = xi * $x(c=>0) + Xr * $x(c=>1);
             %}

             $out(c=>0) = or;
             $out(c=>1) = oi;
          %}
       !
;

pp_add_isa 'PDLA';

pp_addpm {At => Bot}, <<'EOD';

# overload must be here, so that all the functions can be seen

# undocumented compatibility functions
sub Catan2($$) { Catan Cdiv $_[1], $_[0] }
sub atan2($$)  { Catan Cdiv $_[1], $_[0] }

sub _gen_biop {
   local $_ = shift;
   my $sub;
   if (/(\S+)\+(\w+)/) {
      $sub = eval 'sub { '.$2.' $_[0], ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1] }';
   } elsif (/(\S+)\-(\w+)/) {
      $sub = eval 'sub { my $b = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                       $_[2] ? '.$2.' $b, $_[0] : '.$2.' $_[0], $b }';
   } else {
      die;
   }
   if($1 eq "atan2" || $1 eq "<=>") { return ($1, $sub) }
   ($1, $sub, "$1=", $sub);
}

sub _gen_unop {
   my ($op, $func) = ($_[0] =~ /(.+)@(\w+)/);
   *$op = \&$func if $op =~ /\w+/; # create an alias
   ($op, eval 'sub { '.$func.' $_[0] }');
}

sub _gen_cpop {
   ($_[0], eval 'sub { my $b = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                 ($_[2] ? $b <=> $_[0] : $_[0] <=> $b) '.$_[0].' 0 }');
}

sub initialize {
   # Bless a null PDLA into the supplied 1st arg package
   #   If 1st arg is a ref, get the package from it
   bless PDLA->null, ref($_[0]) ? ref($_[0]) : $_[0];
}

use overload
   (map _gen_biop($_), qw(++Cadd --Csub *+Cmul /-Cdiv **-Cpow atan2-Catan2 <=>-Ccmp)),
   (map _gen_unop($_), qw(sin@Csin cos@Ccos exp@Cexp abs@Cabs log@Clog sqrt@Csqrt abs@Cabs)),
   (map _gen_cpop($_), qw(< <= == != >= >)),
   '++' => sub { $_[0] += 1 },
   '--' => sub { $_[0] -= 1 },
   '""' => \&PDLA::Complex::string
;

# overwrite PDLA's overloading to honour subclass methods in + - * /
{ package PDLA;
        my $warningFlag;
        # This strange usage of BEGINs is to ensure the
        # warning messages get disabled and enabled in the
        # proper order. Without the BEGIN's the 'use overload'
        #  would be called first.
        BEGIN {$warningFlag = $^W; # Temporarily disable warnings caused by
               $^W = 0;            # redefining PDLA's subs
              }


sub cp(;@) {
	my $foo;
	if (ref $_[1]
		&& (ref $_[1] ne 'PDLA')
		&& defined ($foo = overload::Method($_[1],'+')))
		{ &$foo($_[1], $_[0], !$_[2])}
	else { PDLA::plus (@_)}
}

sub cm(;@) {
	my $foo;
	if (ref $_[1]
		&& (ref $_[1] ne 'PDLA')
		&& defined ($foo = overload::Method($_[1],'*')))
		{ &$foo($_[1], $_[0], !$_[2])}
	else { PDLA::mult (@_)}
}

sub cmi(;@) {
	my $foo;
	if (ref $_[1]
		&& (ref $_[1] ne 'PDLA')
		&& defined ($foo = overload::Method($_[1],'-')))
		{ &$foo($_[1], $_[0], !$_[2])}
	else { PDLA::minus (@_)}
}

sub cd(;@) {
	my $foo;
	if (ref $_[1]
		&& (ref $_[1] ne 'PDLA')
		&& defined ($foo = overload::Method($_[1],'/')))
		{ &$foo($_[1], $_[0], !$_[2])}
	else { PDLA::divide (@_)}
}


  # Used in overriding standard PDLA +, -, *, / ops in the complex subclass.
  use overload (
		 '+' => \&cp,
		 '*' => \&cm,
	         '-' => \&cmi,
		 '/' => \&cd,
		);



        BEGIN{ $^W = $warningFlag;} # Put Back Warnings
};


{

   our $floatformat  = "%4.4g";    # Default print format for long numbers
   our $doubleformat = "%6.6g";

   $PDLA::Complex::_STRINGIZING = 0;

   sub PDLA::Complex::string {
      my($self,$format1,$format2)=@_;
      my @dims = $self->dims;
      return PDLA::string($self) if ($dims[0] != 2);

      if($PDLA::Complex::_STRINGIZING) {
         return "ALREADY_STRINGIZING_NO_LOOPS";
      }
      local $PDLA::Complex::_STRINGIZING = 1;
      my $ndims = $self->getndims;
      if($self->nelem > $PDLA::toolongtoprint) {
         return "TOO LONG TO PRINT";
      }
      if ($ndims==0){
         PDLA::Core::string($self,$format1);
      }
      return "Null" if $self->isnull;
      return "Empty" if $self->isempty; # Empty piddle
      local $sep  = $PDLA::use_commas ? ", " : "  ";
      local $sep2 = $PDLA::use_commas ? ", " : "";
      if ($ndims < 3) {
         return str1D($self,$format1,$format2);
      }
      else{
         return strND($self,$format1,$format2,0);
      }
   }


    sub sum {



( run in 0.782 second using v1.01-cache-2.11-cpan-524268b4103 )