PDL::Slices -- Stupid index tricks
use PDL; $a = ones(3,3); $b = $a->slice('-1:0,(1)'); $c = $a->dummy(2);
This package provides many of the powerful PerlDL core index manipulation routines. These routines are usually two-way so you can get a unit matrix by
$a = zeroes(1000,1000); $a->diagonal(0,1) ++;
which is usually fairly efficient. See the PDL::Indexing manpage and the PDL::Tips manpage for more examples.
These functions are usually two-way:
$b = $a->slice("1:3"); $b += 5; # $a is changed!
If you want to force a copy and no ``flow'' backwards, you need
$b = $a->slice("1:3")->copy; $b += 5; # $a is not changed.
alternatively, you can use
$b = $a->slice("1:3")->sever;
which does not copy the struct but beware that after
$b = $a->slice("1:3"); $c = $b->sever;
the variables $b
and $c
point to the same object but with
->copy
they do not.
The fact that there is this kind of flow makes PDL a very powerful language in many ways: since you can alter the original data by altering some easier-to-use representation of it, many things are much easier to accomplish, just like making the above unit matrix.
Slicing is so central to the PDL language that a special compile-time syntax has been introduced to handle it compactly; see the PDL::NiceSlice manpage for details.
For the moment, you can't slice the empty piddle. This should probably change: slices of the empty piddle should probably return the empty piddle.
Many types of index errors are reported far from the indexing
operation that caused them. This is caused by the underlying architecture:
slice()
sets up a mapping between variables, but that mapping isn't
tested for correctness until it is used (potentially much later).
Signature: (a(n); int ind(); [oca] c())
index
and index2d
provide rudimentary index indirection.
$c = index($source,$ind); $c = index2d($source2,$ind1,$ind2);
use the $ind
variables as indices to look up values in $source
.
index2d
uses separate piddles for X and Y coordinates. For more
general N-dimensional indexing, see the PDL::Slices manpage or the the PDL::NiceSlice manpage
syntax.
These functions are two-way, i.e. after
$c = $a->index(pdl[0,5,8]); $c .= pdl [0,2,4];
the changes in $c
will flow back to $a
.
Signature: (a(na,nb); int inda(); int indb(); [oca] c())
index
and index2d
provide rudimentary index indirection.
$c = index($source,$ind); $c = index2d($source2,$ind1,$ind2);
use the $ind
variables as indices to look up values in $source
.
index2d
uses separate piddles for X and Y coordinates. For more
general N-dimensional indexing, see the PDL::Slices manpage or the the PDL::NiceSlice manpage
syntax.
These functions are two-way, i.e. after
$c = $a->index(pdl[0,5,8]); $c .= pdl [0,2,4];
the changes in $c
will flow back to $a
.
Find selected elements in an N-D piddle
$source = 10*xvals(10,10) + yvals(10,10); $index = pdl([[2,3],[4,5]],[[6,7],[8,9]]); print $source->indexND( $index );
[ [23 45] [67 89] ]
IndexND collapses $index
by lookup into $source
. The
0th dimension of $index
is treated as coordinates in $source
, and
the return value has the same dimensions as the rest of $index
.
The returned elements are looked up from $source
. Dataflow
works -- propagated assignment flows back into $source
.
You can get out hyperplanes from $source, too, in the same way as with ordinary slicing: use a lower-order vector for the index, and the extra source dimensions are stuck on the end of the output dimension list. Here's an example, using the same index PDL as above but a higher-dimensional source:
$source = 100*xvals(10,10,2)+10*yvals(10,10,2)+zvals(10,10,2); $index = pdl([[2,3],[4,5]],[[6,7],[8,9]]); print $source->indexND( $index );
[ [ [230 450] [670 890] ] [ [231 451] [671 891] ] ]
WARNING: To save time, no boundary checking is done! Indices outside the boundaries of the original array are handled, er, poorly -- you can get anything from the wrong element (wrapped) to a slice-out-of-bounds error if you're out of bounds. indexBDb does boundary checking.
The natural counterpart to indexND is whichND, which generates appropriate lists of coordinates for indexND. See also indexNDb, which handles boundary conditions gracefully, and interpND, which handles floating-point index piddles.
$source = 10*xvals(10,10)+yvals(10,10); $index = pdl([[-1,3],[4,5]],[[6,7],[8,23]]); $out = indexNDb($source, $index);
$out = indexNDb($source, $index, $method, $missing);
indexNDb
collapses $index
by lookup into $source
, with boundary
condition handling using the given method (if present).
$method
can be one of:
indexNDb
is different than indexND
only because it includes
extra overhead for handling boundary values.
Signature: (int a(n); b(n); [o]c(m))
Run-length decode a vector
Given a vector $a
of the numbers of instances of values $b
, run-length
decode to $c
.
rld($a,$b,$c=null);
Signature: (c(n); int [o]a(n); [o]b(n))
Run-length encode a vector
Given vector $c
, generate a vector $a
with the number of each element,
and a vector $b
of the unique values. Only the elements up to the
first instance of `0' in $a
should be considered.
rle($c,$a=null,$b=null);
Signature: (P(); C(); int n1; int n2)
exchange two dimensions
Negative dimension indices count from the end.
The command
$b = $a->xchg(2,3);
creates $b
to be like $a
except that the dimensions 2 and 3
are exchanged with each other i.e.
$b->at(5,3,2,8) == $a->at(5,3,8,2)
Re-orders the dimensions of a PDL based on the supplied list.
Similar to the xchg method, this method re-orders the dimensions of a PDL. While the xchg method swaps the position of two dimensions, the reorder method can change the positions of many dimensions at once.
# Completely reverse the dimension order of a 6-Dim array. $reOrderedPDL = $pdl->reorder(5,4,3,2,1,0);
The argument to reorder is an array representing where the current dimensions
should go in the new array. In the above usage, the argument to reorder
(5,4,3,2,1,0)
indicates that the old dimensions ($pdl
's dims) should be re-arranged to make the
new pdl ($reOrderPDL
) according to the following:
Old Position New Position ------------ ------------ 5 0 4 1 3 2 2 3 1 4 0 5
Example:
perldl> $a = sequence(5,3,2); # Create a 3-d Array perldl> p $a [ [ [ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14] ] [ [15 16 17 18 19] [20 21 22 23 24] [25 26 27 28 29] ] ] perldl> p $a->reorder(2,1,0); # Reverse the order of the 3-D PDL [ [ [ 0 15] [ 5 20] [10 25] ] [ [ 1 16] [ 6 21] [11 26] ] [ [ 2 17] [ 7 22] [12 27] ] [ [ 3 18] [ 8 23] [13 28] ] [ [ 4 19] [ 9 24] [14 29] ] ]
The above is a simple example that could be duplicated by calling
$a->xchg(0,2)
, but it demonstrates the basic functionality of reorder.
As this is an index function, any modifications to the result PDL will change the parent.
Signature: (P(); C(); int n1; int n2)
move a dimension to another position
The command
$b = $a->mv(4,1);
creates $b
to be like $a
except that the dimension 4 is moved to the
place 1, so:
$b->at(1,2,3,4,5,6) == $a->at(1,5,2,3,4,6);
The other dimensions are moved accordingly. Negative dimension indices count from the end.
Signature: (P(); C(); int nth; int from; int step; int nsteps)
experimental function - not for public use
$a = oneslice();
This is not for public use currently. See the source if you have to. This function can be used to accomplish run-time changing of transformations i.e. changing the size of some piddle at run-time.
However, the mechanism is not yet finalized and this is just a demonstration.
Signature: (P(); C(); char* str)
Returns a rectangular slice of the original piddle
$a->slice('1:3'); # return the second to fourth elements of $a $a->slice('3:1'); # reverse the above $a->slice('-2:1'); # return last-but-one to second elements of $a
The argument string is a comma-separated list of what to do for each dimension. The current formats include the following, where a, b and c are integers and can take legal array index values (including -1 etc):
$a->slice(':,3')
is equal to $a->slice(',3')
).
$a
has dims (3,4,5)
then
$a->slice(':,(2),:')
has dimensions (3,5)
whereas
$a->slice(':,2,:')
has dimensions (3,1,5))
.
3:7:2
gives the indices
(3,5,7)
). This may be confusing to Matlab users but several other
packages already use this syntax.
An extension is planned for a later stage allowing
$a->slice('(=1),(=1|5:8),3:6(=1),4:6')
to express a multidimensional diagonal of $a
.
Trivial out-of-bounds slicing is allowed: if you slice a source dimension that doesn't exist, but only index the 0th element, then slice treats the source as if there were a dummy dimension there. The following are all equivalent:
xvals(5)->dummy(1,1)->slice('(2),0') # Add dummy dim, then slice xvals(5)->slice('(2),0') # Out-of-bounds slice adds dim. xvals(5)->slice((2),0) # NiceSlice syntax xvals(5)->((2))->dummy(0,1) # NiceSlice syntax
This is an error:
xvals(5)->slice('(2),1') # nontrivial out-of-bounds slice dies
Because slicing doesn't directly manipulate the source and destination pdl -- it just sets up a transformation between them -- indexing errors often aren't reported until later. This is either a bug or a feature, depending on whether you prefer error-reporting clarity or speed of execution.
Returns array of column numbers requested
line $pdl->using(1,2);
Plot, as a line, column 1 of $pdl
vs. column 2
perldl> $pdl = rcols("file"); perldl> line $pdl->using(1,2);
Signature: (P(); C(); SV *list)
Returns the multidimensional diagonal over the specified dimensions.
The diagonal is placed at the first (by number) dimension that is
diagonalized.
The other diagonalized dimensions are removed. So if $a
has dimensions
(5,3,5,4,6,5)
then after
$b = $a->diagonal(0,2,5);
the piddle $b
has dimensions (5,3,4,6)
and
$b->at(2,1,0,1)
refers
to $a->at(2,1,2,0,1,2)
.
NOTE: diagonal doesn't handle threadids correctly. XXX FIX
Signature: (P(); C(); int nthdim; int step; int n)
Returns a piddle of lags to parent.
Usage:
$lags = $a->lags($nthdim,$step,$nlags);
I.e. if $a
contains
[0,1,2,3,4,5,6,7]
then
$b = $a->lags(0,2,2);
is a (5,2) matrix
[2,3,4,5,6,7] [0,1,2,3,4,5]
This order of returned indices is kept because the function is called ``lags'' i.e. the nth lag is n steps behind the original.
$step
and $nlags
must be positive. $nthdim
can be
negative and will then be counted from the last dim backwards
in the usual way (-1 = last dim).
Signature: (P(); C(); int nthdim; int nsp)
Splits a dimension in the parent piddle (opposite of clump)
After
$b = $a->splitdim(2,3);
the expression
$b->at(6,4,x,y,3,6) == $a->at(6,4,x+3*y)
is always true (x
has to be less than 3).
Signature: (x(n); int shift(); [oca]y(n))
Shift vector elements along with wrap. Flows data back&forth.
Signature: (P(); C(); int id; SV *list)
internal
Put some dimensions to a threadid.
$b = $a->threadI(0,1,5); # thread over dims 1,5 in id 1
Signature: (P(); C())
A vaffine identity transformation (includes thread_id copying).
Mainly for internal use.
Signature: (P(); C(); int atind)
All threaded dimensions are made real again.
See [TBD Doc] for details and examples.
Dice rows/columns/planes out of a PDL using indexes for each dimension.
This function can be used to extract irregular subsets along many dimension of a PDL, e.g. only certain rows in an image, or planes in a cube. This can of course be done with the usual dimension tricks but this saves having to figure it out each time!
This method is similar in functionality to the slice
method, but slice requires that contiguous ranges or ranges
with constant offset be extracted. ( i.e. slice requires
ranges of the form 1,2,3,4,5
or 2,4,6,8,10
). Because of this
restriction, slice is more memory efficient and slightly faster
than dice
$slice = $data->dice([0,2,6],[2,1,6]); # Dicing a 2-D array
The arguments to dice are arrays (or 1D PDLs) for each dimension
in the PDL. These arrays are used as indexes to which rows/columns/cubes,etc
to dice-out (or extract) from the $data
PDL.
Use X
to select all indices along a given dimension (compare also
mslice). As usual (in slicing methods) trailing
dimensions can be omitted implying X
'es for those.
perldl> $a = sequence(10,4) perldl> p $a [ [ 0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19] [20 21 22 23 24 25 26 27 28 29] [30 31 32 33 34 35 36 37 38 39] ] perldl> p $a->dice([1,2],[0,3]) # Select columns 1,2 and rows 0,3 [ [ 1 2] [31 32] ] perldl> p $a->dice(X,[0,3]) [ [ 0 1 2 3 4 5 6 7 8 9] [30 31 32 33 34 35 36 37 38 39] ] perldl> p $a->dice([0,2,5]) [ [ 0 2 5] [10 12 15] [20 22 25] [30 32 35] ]
As this is an index function, any modifications to the
slice change the parent (use the .=
operator).
Dice rows/columns/planes from a single PDL axis (dimension) using index along a specified axis
This function can be used to extract irregular subsets along any dimension, e.g. only certain rows in an image, or planes in a cube. This can of course be done with the usual dimension tricks but this saves having to figure it out each time!
$slice = $data->dice_axis($axis,$index);
perldl> $a = sequence(10,4) perldl> $idx = pdl(1,2) perldl> p $a->dice_axis(0,$idx) # Select columns [ [ 1 2] [11 12] [21 22] [31 32] ] perldl> $t = $a->dice_axis(1,$idx) # Select rows perldl> $t.=0 perldl> p $a [ [ 0 1 2 3 4 5 6 7 8 9] [ 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0 0] [30 31 32 33 34 35 36 37 38 39] ]
The trick to using this is that the index selects
elements along the dimensions specified, so if you
have a 2D image axis=0
will select certain X
values
- i.e. extract columns
As this is an index function, any modifications to the slice change the parent.
Copyright (C) 1997 Tuomas J. Lukka. Contributions by Craig DeForest, deforest@boulder.swri.edu. All rights reserved. There is no warranty. You are allowed to redistribute this software / documentation under certain conditions. For details, see the file COPYING in the PDL distribution. If this file is separated from the PDL distribution, the copyright notice should be included in the file.