=head1 NAME

PDL::PP - Generate PDL routines from concise descriptions

=head1 SYNOPSIS

e.g.

	pp_def(
		'sumover',
		Pars => 'a(n); [o]b();',
		Code => 'double tmp=0;
			loop(n) %{ tmp += $a(); %}
			$b() = tmp;
			'
	);

	pp_done();

(remember to include '-MPDL::PP Module...' in Makefile.PL)

=head1 DESCRIPTION

The PDL::PP module provides a way of concisely describing an operation
on some data, so that this description may then be compiled into C
and object code.

PDL::PP is only of interest if you want to 

=over 4

=item

Interface PDL to some external library

=item

Write some algorithm that would be slow on the perl side 
in C (this is not as often as you think; take a look at threading
and dataflow first).

=item

Be a PDL developer (and even then it's not obligatory)

=back

In order to understand all this, you should be familiar with
the other features of PDL, like threading and dataflow.

What happens when you run the code in the SYNOPSIS? 
The function C<pp_def> takes as arguments first the name of the function
you are defining and then a hash list that can contain various keys.

Based on the keys, transformations are applied to a hash, resulting
in the end in XS code and a .pm file.  The function C<pp_done> takes
these (they were stored in a global variable) and writes the actual
files (the file names were given when the module was imported).

There may be several pp_def() calls inside a file but generally
only one pp_done().

=head1 WARNING

Because of its architecture, PDL::PP can be both flexible and
easy to use (yet exuberantly complicated) at the same time. The problem
is that if something goes wrong, you'd better know what you are
doing and be able to hack your way through the internals.

An alternative of course is to ask someone about it.

=head1 ABANDON ALL HOPE, YE WHO ENTER HERE (DESCRIPTION)

There are two main syntaxes for the parameters of pp_def():
the 'data operation' and 'slice operation' prototypes.

The 'data operation' is used to take some data, mangle it and
give out some other data; examples include the '+' operation, 
matrix inverse, sumover etc.

The 'slice operation' is a different kind of operation: in a slice
operation, you are not changing any data, you are defining 
correspondences between different elements of two piddles.

If you are just interested in communicating with some external
library, you'll usually want the 'data operation' so we are
going to discuss that first.

=head2 Data operation

In the data operation, you must know what dimensions of data
you need. First, an example with scalars:

	pp_def('add',
		Pars => 'a(); b(); [o]c();',
		Code => '$c() = $a() + $b();'
	);

That looks a little strange but let's dissect it. The first
line is self-evident: we're defining a routine with the name 'add'.
The second line simply declares our parameters and the parentheses
mean that they are scalars. 

The third line is the actual operation. You need to use the
dollar signs and parentheses to refer to your parameters
(this will probably change at some point in the future, once
a good syntax is found).

These lines are all that is necessary to actually define the function
for PDL so now you can do

	use MyModule;
	$a = pdl 2,3,4;
	$b = pdl 5;
	add($a,$b,($c=null));

and have threading work correctly (the result is $c == [7 8 9]).

Implicit and explicit threading and the creation of the result
are taken care of automatically. You can even do dataflow with P<add>.

What about dimensions? Let's say that we want to add
a scalar + the index number to a vector:

	pp_def('add2',
		Pars => 'a(n); b(); [o]c(n);',
		Code => 'loop(n) %{
				$c() = $a() + $b() + n;
			 %}'
	);

There are several points to notice here: first, the C<Pars>
argument now contains the I<n> arguments to show that we have a single
dimensions in I<a> and I<c>. It is important to note that dimensions
are actual entities that are accessed by name so this declares
I<a> and I<c> to have the B<same> first dimensions.

The C<loop> construct also refers to the dimension name so you don't
need to specify any limits: the loop correctly sized and everything
is done for you, again. 

Next, there is the surprising fact that C<$a()> and C<$c()> do B<not>
contain the index. This is not necessary because we're looping over
I<n> and both variables know that they have a dimensions 'n' so
they automatically know they're being looped over.

This feature comes in very handy in many places and makes for
much shorter code. Of course, there are times when you want to
circumvent this; here is a function which symmetrizes a matrix:

	pp_def('symm',
		Pars => 'a(n,n); [o]c(n,n);',
		Code => 'loop(n) %{
				int n2;
				for(n2=n; n2<n_size; n2++) {
					$c(n0 => n, n1 => n2) =
					$c(n0 => n2, n1 => n) =
					 $a(n0 => n, n1 => n2);
				}
			%}
		'
	);

What happens here is probably self-evident.

Now, consider the following: you have your own C function
which takes as arguments two pointers to vectors of double:
	
	void myfunc(int n,double *v1,double *v2);

The correct way of defining the PDL function is

	pp_def('myfunc',
		Pars => 'a(n); [o]b(n);',
		GenericTypes => [D],
		Code => 'myfunc(n_size,$P(a),$P(b));'
	);

The C<$P(>I<par>C<)> syntax returns a pointer to the first
element and the other elements are guaranteed to lie after that.

Notice that here it is possible to make many mistakes. First,
C<n_size> must be used instead of C<n>. Second, you shouldn't
put any loops in this code. Third, the C<GenericTypes> declaration 
is especially important since otherwise the function might get 
called with pointers to char, for instance (a bad bad thing).

The more complicated examples will be here later on; contact
Tjl if you need them now.

=head2 Slice operation

The slice operation section of this manual is provided using
dataflow and lazy evaluation: when you need it, ask Tjl to write it.
24h delivery from when I receive the email is 95% probable and
48h delivery is 99% probable.

=head2 INTERNALS

The internals of the current version consist of a large
table which gives the rules according to which things are translated
and the subs which implement these rules.

Later on, it would be good to make the table modifiable by the user
so that different things may be tried.

=head1 BUGS

PDL::PP is still, even in its rewritten form, too complicated. 
It needs to be rethought a little as well as deconvoluted and
modularized some more (e.g. all the NS things).

After the rewrite, this can happen a little by little, though.

=head1 AUTHOR

Copyright(C) 1997 Tuomas J. Lukka (lukka@fas.harvard.edu).
Redistribution in the same form is allowed provided that the copyright
notice stays intact but reprinting requires
a permission from the author.


