If you would like to interface your PDL code with routines written in C then you will need to begin working with PDL::PP. PDL::PP allows you to use a syntax very similar to C in which you specify - with the verbosity and precision of C - exactly what you want PDL to do with your data.
The PP stands for 'pre-processor' because PDL::PP will take your specifications and generate XS code from it. What is XS? XS is basically the way you interface C-code with Perl. So cutting out the middle part, since it doesn't really enter into our workflow much, PDL::PP is a way to interface PDL with C-code.
For more on XS, see <http://perldoc.perl.org/perlxs.html>. For more about the guts of PDL::PP, read on, or check out the docs page here: http://pdl.sourceforge.net/PDLdocs/PP.html....
While PDL::PP is great, this cookbook shows that it's not trivial to get plain ol' PDL::PP code set up. This sort of arrangement makes sense if you want to package an interface to a C or FORTRAN library, but if you simply want to write some customized code in C, it seems like quite a barrier.
Enter Inline, and Inline::Pdlpp. You can read more about both of those on the web, but I will get down to some code to illustrate how it works. (Note: you'll need to get Inline from the CPAN for these scripts to run, but I will assure you it is definitely worth it.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/usr/bin/perl use PDL; use Inline qw( Pdlpp ); # Most first programs in a language say 'Hello world!' # For numerical programming, we show you how to write an incrementer. :) my $seq = sequence(5,2); print "Original sequence: ", $seq, "\n"; print "Incremented: ", $seq->increment, "\n"; __DATA__ __Pdlpp__ pp_def('increment', Pars => 'in(); [o] out();', Code => ' $out() = $in() + 1; ', ); |
An almost useless example, yes, but it demonstrates many things for us.
To declare a Pdlpp function, you have to call
pp_def(<func-name>, <options>)
The first argument is the name of the function and the remaining arguments are key/value pairs of a hash, the most important of which are Pars and Code.
2. The function parameters, i.e. the variables that would normally go into the function declaration, are designated in the Pars hash entry, whose corresponding value is a string. The string contains semicolon-separated variable specifications as
(<dimension>); <var-name>(<dimension>); ...
I've not used the dimension spec here; we'll get to that shortly. Output variables are preceded by [o], as in <pre>[o] <output-var-name>(<dimension>); ... and do not necessarily have to come at the end of the parameter specification.
3. In order to access function parameters in the code itself, we use the syntax <pre>$<var>() The parentheses at this point may seem unnecessary, but they clarify the code under certain circumstances (se PDL::PP for details).
4. We only told PDL::PP what to do with a single input, but we were able to call the function on an array and it Does What I Mean. This is threading in action and helps to vastly simplify our code.
Now we'll look at something almost as trivial: an accumulator that operates on two piddles and returns two results:
<pre>
use PDL; use Inline qw( Pdlpp );
my $seq1 = sequence(4) + 1; my $seq2 = 2 + 3 * sequence(4); print "Original sequences: ", $seq1, $seq2, "\n"; my ($sum, $mult) = accum($seq1, $seq2); print "Sum: $sum; Multiplicative accumulation: $mult\n";
sub accum {
my $piddle = shift; $piddle->accum(@_);
}
DATA
Pdlpp
pp_def('accum',
Pars => 'a(n); b(n); [o] sum(); [o] mult();', Code => ' $sum() = 0; $mult() = 1; loop(n) %{ $sum() += $a() + $b(); $mult() *= $a() * $b(); %} ',
);
What's changed between this code and the last? Note the following:
Both Inline::Pdlpp and PDL::PP have many more capabilities that I have not touched upon here. Hopefully now you have enough of a foot-hold to read through the PDL::PP documentation, and enough of a working template to experiment as you go along. Good luck and have fun!