perlpdl

Is there a map() equivalent for PDL without doing pdl( map {} unpdl)?


I would like to do something like this to call myfunc() on each element in-place on an existing PDL:

$pdl = pdl [1,2,3];
$pdl = pdl [ map { myfunc($_) } @{ unpdl($pdl) } ];

I've searched through the documentation, but nothing yet:

Is there a way to visit each element of a PDL and run something on the element?


Solution

  • You can use broadcast_define (thread_define in older versions) for this:

    use PDL;
    
    broadcast_define('square(a();[o]b())', over { $_[1] .= $_[0] ** 2 });
    
    my $pdl = pdl [[1,2,3], [4,5,6]];
    square($pdl, (my $out = null));
    print($out); # $out is pdl [[1,4,9], [16,25,36]]
    

    this is slower than using native ops ($pdl**2 gets the same result in this case, and many more complicated things are possible by composing native ops), or PDL::PP, in which you write your function in C, but it is faster than unpdl/map/pdl.

    You have to look at the PDL::PP docs for explanations of the signature like (a();[o]b()), but this is the simple case: the function has a scalar input and a scalar output, and can be broadcast to any number of dimensions.

    I can't seem to get broadcast_defined functions to return a value when the output argument is omitted (e.g. my $out = square($pdl)), but you can do in-place modification with square($pdl, $pdl).