"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "Basic/Core/Core.pm" between
PDL-2.074.tar.gz and PDL-2.075.tar.gz

About: PDL (Perl Data Language) aims to turn perl into an efficient numerical language for scientific computing (similar to IDL and MatLab).

Core.pm  (PDL-2.074):Core.pm  (PDL-2.075)
skipping to change at line 27 skipping to change at line 27
use Scalar::Util 'blessed'; use Scalar::Util 'blessed';
# If quad (q/Q) is available for pack(). # If quad (q/Q) is available for pack().
our $CAN_PACK_QUAD = !! eval { my $packed = pack "Q", 0; 1 }; our $CAN_PACK_QUAD = !! eval { my $packed = pack "Q", 0; 1 };
# If "D" is available for pack(). # If "D" is available for pack().
our $CAN_PACK_D = !! eval { my $packed = pack "D", 0; 1 }; our $CAN_PACK_D = !! eval { my $packed = pack "D", 0; 1 };
our @EXPORT = qw( piddle pdl null barf ); # Only stuff always exported! our @EXPORT = qw( piddle pdl null barf ); # Only stuff always exported!
my @convertfuncs = map $_->convertfunc, PDL::Types::types(); my @convertfuncs = map $_->convertfunc, PDL::Types::types();
my @exports_internal = qw(howbig threadids topdl); my @exports_internal = qw(howbig broadcastids topdl);
my @exports_normal = (@EXPORT, my @exports_normal = (@EXPORT,
@convertfuncs, @convertfuncs,
qw(nelem dims shape null qw(nelem dims shape null
empty
convert inplace zeroes zeros ones nan inf i list listindices unpdl convert inplace zeroes zeros ones nan inf i list listindices unpdl
set at flows thread_define over reshape dog cat barf type set at flows broadcast_define over reshape dog cat barf type
dummy mslice approx flat sclr squeeze thread_define dummy mslice approx flat sclr squeeze
get_autopthread_targ set_autopthread_targ get_autopthread_actual get_autopthread_targ set_autopthread_targ get_autopthread_actual
get_autopthread_dim get_autopthread_size set_autopthread_size) ); get_autopthread_dim get_autopthread_size set_autopthread_size) );
our @EXPORT_OK = (@exports_internal, @exports_normal); our @EXPORT_OK = (@exports_internal, @exports_normal);
our %EXPORT_TAGS = ( our %EXPORT_TAGS = (
Func => [@exports_normal], Func => [@exports_normal],
Internal => [@exports_internal] ); Internal => [@exports_internal] );
our ($level, @dims, $sep, $sep2, $match); our ($level, @dims, $sep, $sep2, $match);
# Important variables (place in PDL namespace) # Important variables (place in PDL namespace)
skipping to change at line 60 skipping to change at line 61
$PDL::use_commas = 0; # Whether to insert commas when printing arrays $PDL::use_commas = 0; # Whether to insert commas when printing arrays
$PDL::floatformat = "%7g"; # Default print format for long numbers $PDL::floatformat = "%7g"; # Default print format for long numbers
$PDL::doubleformat = "%10.8g"; $PDL::doubleformat = "%10.8g";
$PDL::indxformat = "%12d"; # Default print format for PDL_Indx values $PDL::indxformat = "%12d"; # Default print format for PDL_Indx values
$PDL::undefval = 0; # Value to use instead of undef when creating PDL s $PDL::undefval = 0; # Value to use instead of undef when creating PDL s
$PDL::toolongtoprint = 10000; # maximum pdl size to stringify for printing $PDL::toolongtoprint = 10000; # maximum pdl size to stringify for printing
################ Exportable functions of the Core ###################### ################ Exportable functions of the Core ######################
*at_c = *at_bad_c; # back-compat alias *at_c = *at_bad_c; # back-compat alias
*thread_define = *broadcast_define;
*PDL::threadover_n = *PDL::broadcastover_n;
*howbig = \&PDL::howbig; *unpdl = \&PDL::unpdl; *howbig = \&PDL::howbig; *unpdl = \&PDL::unpdl;
*nelem = \&PDL::nelem; *inplace = \&PDL::inplace; *nelem = \&PDL::nelem; *inplace = \&PDL::inplace;
*dims = \&PDL::dims; *list = \&PDL::list; *dims = \&PDL::dims; *list = \&PDL::list;
*threadids = \&PDL::threadids; *listindices = \&PDL::listindices; *broadcastids = \&PDL::broadcastids; *listindices = \&PDL::listindices;
*null = \&PDL::null; *set = \&PDL::set; *null = \&PDL::null; *set = \&PDL::set;
*at = \&PDL::at; *flows = \&PDL::flows; *at = \&PDL::at; *flows = \&PDL::flows;
*sclr = \&PDL::sclr; *shape = \&PDL::shape; *sclr = \&PDL::sclr; *shape = \&PDL::shape;
for my $t (PDL::Types::types()) { for my $t (PDL::Types::types()) {
my $conv = $t->convertfunc; my $conv = $t->convertfunc;
no strict 'refs'; no strict 'refs';
*$conv = *{"PDL::$conv"} = sub { *$conv = *{"PDL::$conv"} = sub {
return $t unless @_; return $t unless @_;
alltopdl('PDL', (@_>1 ? [@_] : shift), $t); alltopdl('PDL', (@_>1 ? [@_] : shift), $t);
}; };
} }
BEGIN { BEGIN {
*thread_define = \&PDL::thread_define; *broadcast_define = \&PDL::broadcast_define;
*convert = \&PDL::convert; *over = \&PDL::over; *convert = \&PDL::convert; *over = \&PDL::over;
*dog = \&PDL::dog; *cat = \&PDL::cat; *dog = \&PDL::dog; *cat = \&PDL::cat;
*type = \&PDL::type; *approx = \&PDL::approx; *type = \&PDL::type; *approx = \&PDL::approx;
*dummy = \&PDL::dummy; *dummy = \&PDL::dummy;
*mslice = \&PDL::mslice; *mslice = \&PDL::mslice;
*isempty = \&PDL::isempty; *isempty = \&PDL::isempty;
*string = \&PDL::string; *string = \&PDL::string;
} }
=head1 NAME =head1 NAME
PDL::Core - fundamental PDL functionality and vectorization/threading PDL::Core - fundamental PDL functionality and vectorization/broadcasting
=head1 DESCRIPTION =head1 DESCRIPTION
Methods and functions for type conversions, PDL creation, Methods and functions for type conversions, PDL creation,
type conversion, threading etc. type conversion, broadcasting etc.
=head1 SYNOPSIS =head1 SYNOPSIS
use PDL::Core; # Normal routines use PDL::Core; # Normal routines
use PDL::Core ':Internal'; # Hairy routines use PDL::Core ':Internal'; # Hairy routines
=head1 VECTORIZATION/THREADING: METHOD AND NOMENCLATURE =head1 VECTORIZATION/BROADCASTING: METHOD AND NOMENCLATURE
PDL provides vectorized operations via a built-in engine. PDL provides vectorized operations via a built-in engine.
Vectorization is called "threading" for historical reasons. Vectorization in PDL is called "broadcasting" (formerly, up to 2.075, "threading
The threading engine implements simple rules for each operation. ").
The broadcasting engine implements simple rules for each operation.
Each PDL object has a "shape" that is a generalized N-dimensional Each PDL object has a "shape" that is a generalized N-dimensional
rectangle defined by a "dim list" of sizes in an arbitrary rectangle defined by a "dim list" of sizes in an arbitrary
set of dimensions. A PDL with shape 2x3 has 6 elements and is set of dimensions. A PDL with shape 2x3 has 6 elements and is
said to be two-dimensional, or may be referred to as a 2x3-PDL. said to be two-dimensional, or may be referred to as a 2x3-PDL.
The dimensions are indexed numerically starting at 0, so a The dimensions are indexed numerically starting at 0, so a
2x3-PDL has a dimension 0 (or "dim 0") with size 2 and a 1 dimension 2x3-PDL has a dimension 0 (or "dim 0") with size 2 and a 1 dimension
(or "dim 1") with size 3. (or "dim 1") with size 3.
PDL generalizes *all* mathematical operations with the notion of PDL generalizes *all* mathematical operations with the notion of
"active dims": each operator has zero or more active dims that are "active dims": each operator has zero or more active dims that are
used in carrying out the operation. Simple scalar operations like used in carrying out the operation. Simple scalar operations like
scalar multiplication ('*') have 0 active dims. More complicated scalar multiplication ('*') have 0 active dims. More complicated
operators can have more active dims. For example, matrix operators can have more active dims. For example, matrix
multiplication ('x') has 2 active dims. Additional dims are multiplication ('x') has 2 active dims. Additional dims are
automatically vectorized across -- e.g. multiplying a 2x5-PDL with a automatically vectorized across -- e.g. multiplying a 2x5-PDL with a
2x5-PDL requires 10 simple multiplication operations, and yields a 2x5-PDL requires 10 simple multiplication operations, and yields a
2x5-PDL result. 2x5-PDL result.
=head2 Threading rules =head2 Broadcasting rules
In any PDL expression, the active dims appropriate for each operator In any PDL expression, the active dims appropriate for each operator
are used starting at the 0 dim and working forward through the dim are used starting at the 0 dim and working forward through the dim
list of each object. All additional dims after the active dims are list of each object. All additional dims after the active dims are
"thread dims". The thread dims do not have to agree exactly: they are "broadcast dims". The broadcast dims do not have to agree exactly: they are
coerced to agree according to simple rules: coerced to agree according to simple rules:
=over 3 =over 3
=item * Null PDLs match any dim list (see below). =item * Null PDLs match any dim list (see below).
=item * Dims with sizes other than 1 must all agree in size. =item * Dims with sizes other than 1 must all agree in size.
=item * Dims of size 1 are silently repeated as necessary except for C<[phys]> P DLs. =item * Dims of size 1 are silently repeated as necessary except for C<[phys]> P DLs.
skipping to change at line 178 skipping to change at line 181
Any dim of a PDL can be set explicitly to size 0. If so, the PDL Any dim of a PDL can be set explicitly to size 0. If so, the PDL
contains zero values (because the total number of values is the contains zero values (because the total number of values is the
product of all the sizes in the PDL's shape or dimlist). product of all the sizes in the PDL's shape or dimlist).
Scalar PDLs are zero-dimensional and have no entries in the dim list, Scalar PDLs are zero-dimensional and have no entries in the dim list,
so they cannot be empty. 1-D and higher PDLs can be empty. Empty so they cannot be empty. 1-D and higher PDLs can be empty. Empty
PDLs are useful for set operations, and are most commonly encountered PDLs are useful for set operations, and are most commonly encountered
in the output from selection operators such as L<which|PDL::Primitive> in the output from selection operators such as L<which|PDL::Primitive>
and L<whichND|PDL::Primitive>. Not all empty PDLs have the same and L<whichND|PDL::Primitive>. Not all empty PDLs have the same
threading properties -- e.g. a 2x0-PDL represents a collection of broadcasting properties -- e.g. a 2x0-PDL represents a collection of
2-vectors that happens to contain no elements, while a simple 0-PDL 2-vectors that happens to contain no elements, while a simple 0-PDL
represents a collection of scalar values (that also happens to contain represents a collection of scalar values (that also happens to contain
no elements). no elements).
Note that 0 dims are not adjustable via the threading rules -- a dim Note that 0 dims are not adjustable via the broadcasting rules -- a dim
with size 0 can only match a corresponding dim of size 0 or 1. with size 0 can only match a corresponding dim of size 0 or 1.
=head2 Thread rules and assignments =head2 Broadcast rules and assignments
Versions of PDL through 2.4.10 have some irregularity with threading and Versions of PDL through 2.4.10 have some irregularity with broadcasting and
assignments. Currently the threading engine performs a full expansion of assignments. Currently the broadcasting engine performs a full expansion of
both sides of the computed assignment operator C<.=> (which assigns values both sides of the computed assignment operator C<.=> (which assigns values
to a pre-existing PDL). This leads to counter-intuitive behavior in to a pre-existing PDL). This leads to counter-intuitive behavior in
some cases: some cases:
=over 3 =over 3
=item * Generalized scalars and computed assignment =item * Generalized scalars and computed assignment
If the PDL on the left-hand side of C<.=> has a dim of size 1, it can be If the PDL on the left-hand side of C<.=> has a dim of size 1, it can be
treated as a generalized scalar, as in: treated as a generalized scalar, as in:
$x = sequence(2,3); $x = sequence(2,3);
$y = zeroes(1,3); $y = zeroes(1,3);
$y .= $x; $y .= $x;
In this case, C<$y> is automatically treated as a 2x3-PDL during the In this case, C<$y> is automatically treated as a 2x3-PDL during the
threading operation, but half of the values from C<$x> silently disappear. broadcasting operation, but half of the values from C<$x> silently disappear.
The output is, as Kernighan and Ritchie would say, "undefined". The output is, as Kernighan and Ritchie would say, "undefined".
Further, if the value on the right of C<.=> is empty, then C<.=> becomes Further, if the value on the right of C<.=> is empty, then C<.=> becomes
a silent no-op: a silent no-op:
$x = zeroes(0); $x = zeroes(0);
$y = zeroes(1); $y = zeroes(1);
$y .= $x+1; $y .= $x+1;
print $y; print $y;
skipping to change at line 460 skipping to change at line 463
C<$PDL::undefval> defaults to zero. C<$PDL::undefval> defaults to zero.
As a final note, if you include an Empty PDL in the list of objects to As a final note, if you include an Empty PDL in the list of objects to
construct into a PDL, it is kept as a placeholder pane -- so if you feed construct into a PDL, it is kept as a placeholder pane -- so if you feed
in (say) 7 objects, you get a size of 7 in the 0th dim of the output PDL. in (say) 7 objects, you get a size of 7 in the 0th dim of the output PDL.
The placeholder panes are completely padded out. But if you feed in only The placeholder panes are completely padded out. But if you feed in only
a single Empty PDL, you get back the Empty PDL (no padding). a single Empty PDL, you get back the Empty PDL (no padding).
=cut =cut
=head2 empty
=for ref
Returns an empty ndarray, with a single zero-length dimension.
Only available as a function, not a method.
=for usage
$x = empty; # defaults to lowest type so it can always be promoted up
$x = empty(float);
=cut
sub empty {
my ($type) = @_;
$type //= 0;
PDL->new_from_specification(PDL::Type->new($type), 0);
}
=head2 null =head2 null
=for ref =for ref
Returns a 'null' ndarray. Returns a 'null' ndarray.
It is an error to pass one of these as an input to a function. It is an error to pass one of these as an input to a function.
=for usage =for usage
$x = null; $x = null;
skipping to change at line 509 skipping to change at line 532
=head2 nullcreate =head2 nullcreate
=for ref =for ref
Returns a 'null' ndarray. Returns a 'null' ndarray.
=for usage =for usage
$x = PDL->nullcreate($arg) $x = PDL->nullcreate($arg)
This is an routine used by many of the threading primitives This is an routine used by many of the broadcasting primitives
(i.e. L<sumover|PDL::Ufunc/sumover>, (i.e. L<sumover|PDL::Ufunc/sumover>,
L<minimum|PDL::Ufunc/minimum>, etc.) to generate a null ndarray for the L<minimum|PDL::Ufunc/minimum>, etc.) to generate a null ndarray for the
function's output that will behave properly for derived (or function's output that will behave properly for derived (or
subclassed) PDL objects. subclassed) PDL objects.
For the above usage: For the above usage:
If C<$arg> is a PDL, or a derived PDL, then C<$arg-E<gt>null> is returned. If C<$arg> is a PDL, or a derived PDL, then C<$arg-E<gt>null> is returned.
If C<$arg> is a scalar (i.e. a zero-dimensional PDL) then C<PDL-E<gt>null> If C<$arg> is a scalar (i.e. a zero-dimensional PDL) then C<PDL-E<gt>null>
is returned. is returned.
skipping to change at line 771 skipping to change at line 794
sub PDL::shape { # Return dimensions as a pdl sub PDL::shape { # Return dimensions as a pdl
indx([PDL->topdl(shift)->dims]); indx([PDL->topdl(shift)->dims]);
} }
sub PDL::howbig { sub PDL::howbig {
my $t = shift; my $t = shift;
if("PDL::Type" eq ref $t) {$t = $t->[0]} if("PDL::Type" eq ref $t) {$t = $t->[0]}
PDL::howbig_c($t); PDL::howbig_c($t);
} }
=head2 threadids =head2 broadcastids
=for ref =for ref
Returns the ndarray thread IDs as a perl list Returns the ndarray broadcast IDs as a perl list
Note that C<threadids()> is not exported by default (see example Note that C<broadcastids()> is not exported by default (see example
below for usage). below for usage).
=for usage =for usage
use PDL::Core ':Internal'; # use the internal routines of use PDL::Core ':Internal'; # use the internal routines of
# the Core module # the Core module
@ids = threadids $ndarray; @ids = broadcastids $ndarray;
=cut =cut
sub PDL::threadids { # Return dimensions as @list sub PDL::broadcastids {
PDL->topdl(shift)->threadids_c; PDL->topdl(shift)->broadcastids_c;
} }
################# Creation/copying functions ####################### ################# Creation/copying functions #######################
sub piddle {PDL->pdl(@_)} sub piddle {PDL->pdl(@_)}
sub pdl {PDL->pdl(@_)} sub pdl {PDL->pdl(@_)}
sub PDL::pdl { my $x = shift; return $x->new(@_) } sub PDL::pdl { shift->new(@_) }
=head2 doflow =head2 doflow
=for ref =for ref
Turn on dataflow, forward only. This means any transformations (a.k.a. PDL Turn on dataflow, forward only. This means any transformations (a.k.a. PDL
operations) applied to this ndarray afterwards will have forward dataflow: operations) applied to this ndarray afterwards will have forward dataflow:
$x = sequence 3; $x = sequence 3;
$x->doflow; $x->doflow;
skipping to change at line 1172 skipping to change at line 1195
return max($item->type->enum, $sofar) if UNIVERSAL::isa($item, 'PDL'); return max($item->type->enum, $sofar) if UNIVERSAL::isa($item, 'PDL');
return $PDL_D if ref($item) ne 'ARRAY'; return $PDL_D if ref($item) ne 'ARRAY';
# only need to check first item for an array of complex vals # only need to check first item for an array of complex vals
return $MAX_TYPE if _establish_type($item->[0], $sofar) == $MAX_TYPE; return $MAX_TYPE if _establish_type($item->[0], $sofar) == $MAX_TYPE;
# only need to recurse for items that are refs # only need to recurse for items that are refs
# as $sofar will be $PDL_D at a minimum # as $sofar will be $PDL_D at a minimum
max ($sofar, map _establish_type($_, $sofar), grep ref, @$item); max ($sofar, map _establish_type($_, $sofar), grep ref, @$item);
} }
sub PDL::new { sub PDL::new {
# print "in PDL::new\n"; return $_[0]->copy if ref($_[0]);
my $this = shift; my $this = shift;
return $this->copy if ref($this);
my $type = ref($_[0]) eq 'PDL::Type' ? shift->enum : undef; my $type = ref($_[0]) eq 'PDL::Type' ? shift->enum : undef;
my $value = (@_ >1 ? [@_] : shift); # ref thyself my $value = (@_ > 1 ? [@_] : shift);
unless(defined $value) { unless(defined $value) {
if($PDL::debug) { if($PDL::debug) {
print STDERR "Warning: PDL::new converted undef to \$PDL::undefval ($P DL::undefval)\n"; print STDERR "Warning: PDL::new converted undef to \$PDL::undefval ($P DL::undefval)\n";
} }
$value = ($PDL::undefval//0)+0 $value = ($PDL::undefval//0)+0
} }
$type //= ref($value) ? _establish_type($value, $PDL_D) : $PDL_D; $type //= ref($value) ? _establish_type($value, $PDL_D) : $PDL_D;
return pdl_avref($value,$this,$type) if ref($value) eq "ARRAY"; return pdl_avref($value,$this,$type) if ref($value) eq "ARRAY";
my $new = $this->initialize(); my $new = $this->initialize;
$new->set_datatype($type); $new->set_datatype($type);
if (ref(\$value) eq "SCALAR") { if (ref(\$value) eq "SCALAR") {
# The string processing is extremely slow. Benchmarks indicated that it # The string processing is extremely slow. Benchmarks indicated that it
# takes 10x longer to process a scalar number compared with normal Perl # takes 10x longer to process a scalar number compared with normal Perl
# conversion of a string to a number. So, only use the string processing # conversion of a string to a number. So, only use the string processing
# if the input looks like a real string, i.e. it doesn't look like a plain # if the input looks like a real string, i.e. it doesn't look like a plain
# number. Note that for our purposes, looks_like_number incorrectly # number. Note that for our purposes, looks_like_number incorrectly
# handles the strings 'inf' and 'nan' on Windows machines. We want to send # handles the strings 'inf' and 'nan' on Windows machines. We want to send
# those to the string processing, so this checks for them in a way that # those to the string processing, so this checks for them in a way that
skipping to change at line 1249 skipping to change at line 1271
Since C<$new = $old> just makes a new reference, the Since C<$new = $old> just makes a new reference, the
C<copy> method is provided to allow real independent C<copy> method is provided to allow real independent
copies to be made. copies to be made.
=cut =cut
sub PDL::copy { sub PDL::copy {
my $value = shift; my $value = shift;
barf("Argument is an ".ref($value)." not an object") unless blessed($value); barf("Argument is an ".ref($value)." not an object") unless blessed($value);
# threadI(-1,[]) is just an identity vafftrans with threadId copying ;) return $value->nullcreate if $value->isnull;
$value->threadI(-1,[])->sever; # broadcastI(-1,[]) is just an identity vafftrans with broadcastid copying ;
)
$value->broadcastI(-1,[])->sever;
} }
=head2 hdr_copy =head2 hdr_copy
=for ref =for ref
Return an explicit copy of the header of a PDL. Return an explicit copy of the header of a PDL.
hdr_copy is just a wrapper for the internal routine _hdr_copy, which hdr_copy is just a wrapper for the internal routine _hdr_copy, which
takes the hash ref itself. That is the routine which is used to make takes the hash ref itself. That is the routine which is used to make
skipping to change at line 1375 skipping to change at line 1398
} }
$val; $val;
} }
=head2 unwind =head2 unwind
=for ref =for ref
Return an ndarray which is the same as the argument except Return an ndarray which is the same as the argument except
that all threadids have been removed. that all broadcastids have been removed.
=for usage =for usage
$y = $x->unwind; $y = $x->unwind;
=head2 make_physical =head2 make_physical
=for ref =for ref
Make sure the data portion of an ndarray can be accessed from XS code. Make sure the data portion of an ndarray can be accessed from XS code.
skipping to change at line 1413 skipping to change at line 1436
might want to consider using the PDL preprocessor might want to consider using the PDL preprocessor
(see L<PDL::PP>) (see L<PDL::PP>)
which can be used to transparently access virtual ndarrays without the which can be used to transparently access virtual ndarrays without the
need to physicalise them (though there are exceptions). need to physicalise them (though there are exceptions).
=cut =cut
sub PDL::unwind { sub PDL::unwind {
my $value = shift; my $value = shift;
my $foo = $value->null(); my $foo = $value->null();
$foo .= $value->unthread(); $foo .= $value->unbroadcast();
return $foo; return $foo;
} }
=head2 dummy =head2 dummy
=for ref =for ref
Insert a 'dummy dimension' of given length (defaults to 1) Insert a 'dummy dimension' of given length (defaults to 1)
No relation to the 'Dungeon Dimensions' in Discworld! No relation to the 'Dungeon Dimensions' in Discworld!
skipping to change at line 1537 skipping to change at line 1560
my $ndims = $this->getndims; my $ndims = $this->getndims;
my $targd = $ndims-1; my $targd = $ndims-1;
my @dimmark = (0..$ndims-1); my @dimmark = (0..$ndims-1);
barf "too many dimensions" if @dims > $ndims; barf "too many dimensions" if @dims > $ndims;
for my $dim (@dims) { for my $dim (@dims) {
barf "dimension index $dim larger than greatest dimension" barf "dimension index $dim larger than greatest dimension"
if $dim > $ndims-1 ; if $dim > $ndims-1 ;
$targd = $dim if $targd > $dim; $targd = $dim if $targd > $dim;
barf "duplicate dimension $dim" if $dimmark[$dim]++ > $dim; barf "duplicate dimension $dim" if $dimmark[$dim]++ > $dim;
} }
my $clumped = $this->thread(@dims)->unthread(0)->clump(scalar @dims); my $clumped = $this->broadcast(@dims)->unbroadcast(0)->clump(scalar @dims);
$clumped = $clumped->mv(0,$targd) if $targd > 0; $clumped = $clumped->mv(0,$targd) if $targd > 0;
return $clumped; return $clumped;
} }
=head2 thread_define =head2 broadcast_define
=for ref =for ref
define functions that support threading at the perl level define functions that support broadcasting at the perl level
=for example =for example
thread_define 'tline(a(n);b(n))', over { broadcast_define 'tline(a(n);b(n))', over {
line $_[0], $_[1]; # make line compliant with threading line $_[0], $_[1]; # make line compliant with broadcasting
}; };
C<thread_define> provides some support for threading (see C<broadcast_define> provides some support for broadcasting (see
L<PDL::Indexing>) at the perl level. It allows you to do things for L<PDL::Indexing>) at the perl level. It allows you to do things for
which you normally would have resorted to PDL::PP (see L<PDL::PP>); which you normally would have resorted to PDL::PP (see L<PDL::PP>);
however, it is most useful to wrap existing perl functions so that the however, it is most useful to wrap existing perl functions so that the
new routine supports PDL threading. new routine supports PDL broadcasting.
C<thread_define> is used to define new I<threading aware> C<broadcast_define> is used to define new I<broadcasting aware>
functions. Its first argument is a symbolic repesentation of the new functions. Its first argument is a symbolic repesentation of the new
function to be defined. The string is composed of the name of the new function to be defined. The string is composed of the name of the new
function followed by its signature (see L<PDL::Indexing> and L<PDL::PP>) function followed by its signature (see L<PDL::Indexing> and L<PDL::PP>)
in parentheses. The second argument is a subroutine that will be in parentheses. The second argument is a subroutine that will be
called with the slices of the actual runtime arguments as specified by called with the slices of the actual runtime arguments as specified by
its signature. Correct dimension sizes and minimal number of its signature. Correct dimension sizes and minimal number of
dimensions for all arguments will be checked (assuming the rules of dimensions for all arguments will be checked (assuming the rules of
PDL threading, see L<PDL::Indexing>). PDL broadcasting, see L<PDL::Indexing>).
The actual work is done by the C<signature> class which parses the signature The actual work is done by the C<signature> class which parses the signature
string, does runtime dimension checks and the routine C<threadover> that string, does runtime dimension checks and the routine C<broadcastover> that
generates the loop over all appropriate slices of pdl arguments and creates generates the loop over all appropriate slices of pdl arguments and creates
pdls as needed. pdls as needed.
Similar to C<pp_def> and its C<OtherPars> option it is possible to Similar to C<pp_def> and its C<OtherPars> option it is possible to
define the new function so that it accepts normal perl args as well as define the new function so that it accepts normal perl args as well as
ndarrays. You do this by using the C<NOtherPars> parameter in the ndarrays. You do this by using the C<NOtherPars> parameter in the
signature. The number of C<NOtherPars> specified will be passed signature. The number of C<NOtherPars> specified will be passed
unaltered into the subroutine given as the second argument of unaltered into the subroutine given as the second argument of
C<thread_define>. Let's illustrate this with an example: C<broadcast_define>. Let's illustrate this with an example:
PDL::thread_define 'triangles(inda();indb();indc()), NOtherPars => 2', PDL::broadcast_define 'triangles(inda();indb();indc()), NOtherPars => 2',
PDL::over { PDL::over {
${$_[3]} .= $_[4].join(',',map {$_->at} @_[0..2]).",-1,\n"; ${$_[3]} .= $_[4].join(',',map {$_->at} @_[0..2]).",-1,\n";
}; };
This defines a function C<triangles> that takes 3 ndarrays as input This defines a function C<triangles> that takes 3 ndarrays as input
plus 2 arguments which are passed into the routine unaltered. This routine plus 2 arguments which are passed into the routine unaltered. This routine
is used to collect lists of indices into a perl scalar that is passed by is used to collect lists of indices into a perl scalar that is passed by
reference. Each line is preceded by a prefix passed as C<$_[4]>. Here is reference. Each line is preceded by a prefix passed as C<$_[4]>. Here is
typical usage: typical usage:
skipping to change at line 1616 skipping to change at line 1639
Currently, this is probably not much more than a POP (proof of principle) Currently, this is probably not much more than a POP (proof of principle)
but is hoped to be useful enough for some real life work. but is hoped to be useful enough for some real life work.
Check L<PDL::PP> for the format of the signature. Currently, the Check L<PDL::PP> for the format of the signature. Currently, the
C<[t]> qualifier and all type qualifiers are ignored. C<[t]> qualifier and all type qualifiers are ignored.
=cut =cut
sub PDL::over (&) { $_[0] } sub PDL::over (&) { $_[0] }
sub PDL::thread_define ($$) { sub PDL::broadcast_define ($$) {
require PDL::PP::Signature; require PDL::PP::Signature;
my ($str,$sub) = @_; my ($str,$sub) = @_;
my $others = 0; my $others = 0;
if ($str =~ s/[,]*\s*NOtherPars\s*=>\s*([0-9]+)\s*[,]*//) {$others = $1} if ($str =~ s/[,]*\s*NOtherPars\s*=>\s*([0-9]+)\s*[,]*//) {$others = $1}
barf "invalid string $str" unless $str =~ /\s*([^(]+)\((.+)\)\s*$/x; barf "invalid string $str" unless $str =~ /\s*([^(]+)\((.+)\)\s*$/x;
my ($name,$sigstr) = ($1,$2); my ($name,$sigstr) = ($1,$2);
print "defining '$name' with signature '$sigstr' and $others extra args\n" print "defining '$name' with signature '$sigstr' and $others extra args\n"
if $PDL::debug; if $PDL::debug;
my $sig = PDL::PP::Signature->new($sigstr); my $sig = PDL::PP::Signature->new($sigstr);
my $args = @{$sig->names}; # number of ndarray arguments my $args = @{$sig->names}; # number of ndarray arguments
barf "no ndarray args" if $args == 0; barf "no ndarray args" if $args == 0;
$args--; $args--;
# TODO: $sig->dimcheck(@_) + proper creating generation # TODO: $sig->dimcheck(@_) + proper creating generation
my $package = caller; my $package = caller;
print "defining... $name\n" if $PDL::debug; print "defining... $name\n" if $PDL::debug;
no strict 'refs'; no strict 'refs';
*{"$package\::$name"} = sub { *{"$package\::$name"} = sub {
@_[0..$args] = map PDL::Core::topdl($_), @_[0..$args]; @_[0..$args] = map PDL::Core::topdl($_), @_[0..$args];
$sig->checkdims(@_); $sig->checkdims(@_);
PDL::threadover($others,@_,$sig->realdims,$sig->creating,$sub); PDL::broadcastover($others,@_,$sig->realdims,$sig->creating,$sub);
}; };
} }
=head2 thread =head2 broadcast
=for ref =for ref
Use explicit threading over specified dimensions (see also L<PDL::Indexing>) Use explicit broadcasting over specified dimensions (see also L<PDL::Indexing>)
=for usage =for usage
$y = $x->thread($dim,[$dim1,...]) $y = $x->broadcast($dim,[$dim1,...])
=for example =for example
$x = zeroes 3,4,5; $x = zeroes 3,4,5;
$y = $x->thread(2,0); $y = $x->broadcast(2,0);
Same as L</thread1>, i.e. uses thread id 1. Same as L</broadcast1>, i.e. uses broadcast id 1.
=cut =cut
sub PDL::thread { sub PDL::broadcast {
my $var = shift; my $var = shift;
$var->threadI(1,\@_); $var->broadcastI(1,\@_);
} }
=head2 thread1 =head2 broadcast1
=for ref =for ref
Explicit threading over specified dims using thread id 1. Explicit broadcasting over specified dims using broadcast id 1.
=for usage =for usage
$xx = $x->thread1(3,1) $xx = $x->broadcast1(3,1)
=for example =for example
Wibble Wibble
Convenience function interfacing to Convenience function interfacing to
L<PDL::Slices::threadI|PDL::Slices/threadI>. L<PDL::Slices::broadcastI|PDL::Slices/broadcastI>.
=cut =cut
sub PDL::thread1 { sub PDL::broadcast1 {
my $var = shift; my $var = shift;
$var->threadI(1,\@_); $var->broadcastI(1,\@_);
} }
=head2 thread2 =head2 broadcast2
=for ref =for ref
Explicit threading over specified dims using thread id 2. Explicit broadcasting over specified dims using broadcast id 2.
=for usage =for usage
$xx = $x->thread2(3,1) $xx = $x->broadcast2(3,1)
=for example =for example
Wibble Wibble
Convenience function interfacing to Convenience function interfacing to
L<PDL::Slices::threadI|PDL::Slices/threadI>. L<PDL::Slices::broadcastI|PDL::Slices/broadcastI>.
=cut =cut
sub PDL::thread2 { sub PDL::broadcast2 {
my $var = shift; my $var = shift;
$var->threadI(2,\@_); $var->broadcastI(2,\@_);
} }
=head2 thread3 =head2 broadcast3
=for ref =for ref
Explicit threading over specified dims using thread id 3. Explicit broadcasting over specified dims using broadcast id 3.
=for usage =for usage
$xx = $x->thread3(3,1) $xx = $x->broadcast3(3,1)
=for example =for example
Wibble Wibble
Convenience function interfacing to Convenience function interfacing to
L<PDL::Slices::threadI|PDL::Slices/threadI>. L<PDL::Slices::broadcastI|PDL::Slices/broadcastI>.
=cut =cut
sub PDL::thread3 { sub PDL::broadcast3 {
my $var = shift; my $var = shift;
$var->threadI(3,\@_); $var->broadcastI(3,\@_);
} }
my %info = ( my %info = (
D => { D => {
Name => 'Dimension', Name => 'Dimension',
Sub => \&PDL::Core::dimstr, Sub => \&PDL::Core::dimstr,
}, },
T => { T => {
Name => 'Type', Name => 'Type',
Sub => sub { return $_[0]->type->shortctype; }, Sub => sub { return $_[0]->type->shortctype; },
skipping to change at line 1794 skipping to change at line 1817
$ivdformat =~ s/"//g; $ivdformat =~ s/"//g;
sprintf "%$ivdformat", $_[0]->address } sprintf "%$ivdformat", $_[0]->address }
}, },
); );
# print the dimension information about a pdl in some appropriate form # print the dimension information about a pdl in some appropriate form
sub dimstr { sub dimstr {
my $this = shift; my $this = shift;
my @dims = $this->dims; my @dims = $this->dims;
my @ids = $this->threadids; my @ids = $this->broadcastids;
my ($nids,$i) = ($#ids - 1,0); my ($nids,$i) = ($#ids - 1,0);
my $dstr = 'D ['. join(',',@dims[0..($ids[0]-1)]) .']'; my $dstr = 'D ['. join(',',@dims[0..($ids[0]-1)]) .']';
if ($nids > 0) { if ($nids > 0) {
for $i (1..$nids) { for $i (1..$nids) {
$dstr .= " T$i [". join(',',@dims[$ids[$i]..$ids[$i+1]-1]) .']'; $dstr .= " T$i [". join(',',@dims[$ids[$i]..$ids[$i+1]-1]) .']';
} }
} }
return $dstr; return $dstr;
} }
skipping to change at line 2803 skipping to change at line 2826
=for ref =for ref
Convert ndarray to perl list Convert ndarray to perl list
=for usage =for usage
@tmp = list $x; @tmp = list $x;
Obviously this is grossly inefficient for the large datasets PDL is designed to Obviously this is grossly inefficient for the large datasets PDL is designed to
handle. This was provided as a get out while PDL matured. It should now be mostl y handle. This was provided as a get out while PDL matured. It should now be mostl y
superseded by superior constructs, such as PP/threading. However it is still superseded by superior constructs, such as PP/broadcasting. However it is still
occasionally useful and is provided for backwards compatibility. occasionally useful and is provided for backwards compatibility.
=for example =for example
for (list $x) { for (list $x) {
# Do something on each value... # Do something on each value...
} }
=for bad =for bad
list converts any bad values into the string 'BAD'. list converts any bad values into the string 'BAD'.
=cut =cut
# No threading, just the ordinary dims. # No broadcasting, just the ordinary dims.
sub PDL::list{ # pdl -> @list sub PDL::list{ # pdl -> @list
barf 'Usage: list($pdl)' if $#_!=0; barf 'Usage: list($pdl)' if $#_!=0;
my $pdl = PDL->topdl(shift); my $pdl = PDL->topdl(shift);
return () if nelem($pdl)==0; return () if nelem($pdl)==0;
@{listref_c($pdl)}; @{listref_c($pdl)};
} }
=head2 unpdl =head2 unpdl
=for ref =for ref
skipping to change at line 2893 skipping to change at line 2916
Convert ndarray indices to perl list Convert ndarray indices to perl list
=for usage =for usage
@tmp = listindices $x; @tmp = listindices $x;
C<@tmp> now contains the values C<0..nelem($x)>. C<@tmp> now contains the values C<0..nelem($x)>.
Obviously this is grossly inefficient for the large datasets PDL is designed to Obviously this is grossly inefficient for the large datasets PDL is designed to
handle. This was provided as a get out while PDL matured. It should now be most ly handle. This was provided as a get out while PDL matured. It should now be most ly
superseded by superior constructs, such as PP/threading. However it is still superseded by superior constructs, such as PP/broadcasting. However it is still
occasionally useful and is provied for backwards compatibility. occasionally useful and is provied for backwards compatibility.
=for example =for example
for $i (listindices $x) { for $i (listindices $x) {
# Do something on each value... # Do something on each value...
} }
=cut =cut
skipping to change at line 3702 skipping to change at line 3725
See L<PDL::ParallelCPU> for an overview of the auto-pthread process. See L<PDL::ParallelCPU> for an overview of the auto-pthread process.
=for example =for example
# Example turning on auto-pthreading for a target of 2 pthreads and for functi ons involving # Example turning on auto-pthreading for a target of 2 pthreads and for functi ons involving
# PDLs with greater than 1M elements # PDLs with greater than 1M elements
set_autopthread_targ(2); set_autopthread_targ(2);
set_autopthread_size(1); set_autopthread_size(1);
# Execute a pdl function, processing will split into two pthreads as long as # Execute a pdl function, processing will split into two pthreads
# one of the pdl-threaded dimensions is divisible by 2.
$x = minimum($y); $x = minimum($y);
# Get the actual number of pthreads that were run. # Get the actual number of pthreads that were run.
$actual_pthread = get_autopthread_actual(); $actual_pthread = get_autopthread_actual();
=cut =cut
*set_autopthread_targ = \&PDL::set_autopthread_targ; *set_autopthread_targ = \&PDL::set_autopthread_targ;
=head2 get_autopthread_targ =head2 get_autopthread_targ
 End of changes. 75 change blocks. 
79 lines changed or deleted 103 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)