PDLA-Core

 view release on metacpan or  search on metacpan

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

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


=head1 OPERATORS

The following operators are overloaded:

=over 4

=item +, += (addition)

=item -, -= (subtraction)

=item *, *= (multiplication; L<Cmul|/Cmul>)

=item /, /= (division; L<Cdiv|/Cdiv>)

=item **, **= (exponentiation; L<Cpow|/Cpow>)

=item atan2 (4-quadrant arc tangent)

=item <=> (nonsensical comparison operator; L<Ccmp|/Ccmp>)

=item sin (L<Csin|/Csin>)

=item cos (L<Ccos|/Ccos>)

=item exp (L<Cexp|/Cexp>)

=item abs (L<Cabs|/Cabs>)

=item log (L<Clog|/Clog>)

=item sqrt (L<Csqrt|/Csqrt>)

=item <, <=, ==, !=, >=, > (just as nonsensical as L<Ccmp|/Ccmp>)

=item ++, -- (increment, decrement; they affect the real part of the complex number only)

=item "" (stringification)

=back

=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=>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, im

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],
       PMCode=> q!
sub rCpolynomial {
    my $coeffs = shift;
    my $x = shift;
    my $out = $x->copy;
    _rCpolynomial_int($coeffs,$x,$out);
    return PDLA::complex($out);
    }
!,
       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 (thanks to Luis Mochan!)
sub Catan2($$) { Clog( $_[1] + i*$_[0])/i }
sub atan2($$) { Clog( $_[1] + i*$_[0])/i }


=begin comment

In _gen_biop, the '+' or '-' between the operator (e.g., '*') and the
function that it overloads (e.g., 'Cmul') flags whether the operation
is ('+') or is not ('-') commutative. See the discussion of argument
swapping in the section "Calling Conventions and Magic Autogeneration"
in "perldoc overload".

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

      $sub = eval 'sub { my $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                       $_[2] ? '.$2.' $y, $_[0] : '.$2.' $_[0], $y }'; #need to swap?
   } 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 $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
#                 ($_[2] ? $y <=> $_[0] : $_[0] <=> $y) '.$_[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)),
#   (map _gen_cpop($_), qw(< <= == != >= >)), #segfaults with infinite recursion of the operator.
#final ternary used to make result a scalar, not a PDLA:::Complex (thx CED!)
    "<" => sub { my $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
		 PDLA::lt( ($_[2] ? $y <=> $_[0] : $_[0] <=> $y), 0, 0) ? 1 : 0;},
    "<=" => sub { my $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                 PDLA::le( ($_[2] ? $y <=> $_[0] : $_[0] <=> $y), 0, 0) ? 1 : 0;},
    "==" => sub { my $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                 PDLA::eq( ($_[2] ? $y <=> $_[0] : $_[0] <=> $y), 0, 0) ? 1 : 0;},
    "!=" => sub { my $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                 PDLA::ne( ($_[2] ? $y <=> $_[0] : $_[0] <=> $y), 0, 0) ? 1 : 0;},
    ">=" => sub { my $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                 PDLA::ge( ($_[2] ? $y <=> $_[0] : $_[0] <=> $y), 0, 0) ? 1 : 0;},
    ">" => sub { my $y = ref $_[1] eq __PACKAGE__ ? $_[1] : r2C $_[1];
                 PDLA::gt( ($_[2] ? $y <=> $_[0] : $_[0] <=> $y), 0, 0) ? 1 : 0;},
   '++' => 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.510 second using v1.01-cache-2.11-cpan-524268b4103 )