NAME¶
PDL::Slices -- Indexing, slicing, and dicing
SYNOPSIS¶
use PDL;
$a = ones(3,3);
$b = $a->slice('-1:0,(1)');
$c = $a->dummy(2);
DESCRIPTION¶
This package provides many of the powerful PerlDL core index manipulation
routines. These routines mostly allow two-way data flow, so you can modify
your data in the most convenient representation. For example, you can make a
1000x1000 unit matrix with
$a = zeroes(1000,1000);
$a->diagonal(0,1) ++;
which is quite efficient. See PDL::Indexing and PDL::Tips for more examples.
Slicing is so central to the PDL language that a special compile-time syntax has
been introduced to handle it compactly; see PDL::NiceSlice for details.
PDL indexing and slicing functions usually include two-way data flow, so that
you can separate the actions of reshaping your data structures and modifying
the data themselves. Two special methods, copy and sever, help you control the
data flow connection between related variables.
$b = $a->slice("1:3"); # Slice maintains a link between $a and $b.
$b += 5; # $a is changed!
If you want to force a physical copy and no data flow, you can copy or sever the
slice expression:
$b = $a->slice("1:3")->copy;
$b += 5; # $a is not changed.
$b = $a->slice("1:3")->sever;
$b += 5; # $a is not changed.
The difference between "sever" and "copy" is that sever acts
on (and returns) its argument, while copy produces a disconnected copy. If you
say
$b = $a->slice("1:3");
$c = $b->sever;
then the variables $b and $c point to the same object but with
"->copy" they would not.
FUNCTIONS¶
s_identity¶
Signature: (P(); C())
Internal vaffine identity function.
s_identity processes bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
index¶
Signature: (a(n); indx ind(); [oca] c())
"index", "index1d", and "index2d" provide
rudimentary index indirection.
$c = index($source,$ind);
$c = index($source,$ind);
$c = index2d($source2,$ind1,$ind2);
use the $ind variables as indices to look up values in $source. The three
routines thread slightly differently.
- "index" uses direct threading for 1-D indexing across the 0 dim
of $source. It can thread over source thread dims or index thread dims dims
not not (easily) both: If <$source> has more than 1 dimension and $ind
has more than 0 dimensions, they must agree in a threading sense.
- "index1d" uses a single active dim in $ind to produce a list of
indexed values in the 0 dim of the output - it is useful for collapsing
$source by indexing with a single row of values long $source's 0 dimension.
The output has the same number of dims as $source. The 0 dim of the output
has size 1 if $ind is a scalar, and the same size as the 0 dim of $ind if it
is not. If $ind and $<source> both have more than 1 dim, then all dims
higher than 0 must agree in a threading sense.
- "index2d" works like "index" but uses separate piddles
for X and Y coordinates. For more general N-dimensional indexing, see the
PDL::NiceSlice syntax or PDL::Slices (in particular "slice",
"indexND", and "range").
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.
"index" provids simple threading: multiple-dimensioned arrays are
treated as collections of 1-D arrays, so that
$a = xvals(10,10)+10*yvals(10,10);
$b = $a->index(3);
$c = $a->index(9-xvals(10));
puts a single column from $a into $b, and puts a single element from each column
of $a into $c. If you want to extract multiple columns from an array in one
operation, see dice or indexND.
index barfs if any of the index values are bad.
index1d¶
Signature: (a(n); indx ind(m); [oca] c(m))
"index", "index1d", and "index2d" provide
rudimentary index indirection.
$c = index($source,$ind);
$c = index($source,$ind);
$c = index2d($source2,$ind1,$ind2);
use the $ind variables as indices to look up values in $source. The three
routines thread slightly differently.
- "index" uses direct threading for 1-D indexing across the 0 dim
of $source. It can thread over source thread dims or index thread dims dims
not not (easily) both: If <$source> has more than 1 dimension and $ind
has more than 0 dimensions, they must agree in a threading sense.
- "index1d" uses a single active dim in $ind to produce a list of
indexed values in the 0 dim of the output - it is useful for collapsing
$source by indexing with a single row of values long $source's 0 dimension.
The output has the same number of dims as $source. The 0 dim of the output
has size 1 if $ind is a scalar, and the same size as the 0 dim of $ind if it
is not. If $ind and $<source> both have more than 1 dim, then all dims
higher than 0 must agree in a threading sense.
- "index2d" works like "index" but uses separate piddles
for X and Y coordinates. For more general N-dimensional indexing, see the
PDL::NiceSlice syntax or PDL::Slices (in particular "slice",
"indexND", and "range").
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.
"index" provids simple threading: multiple-dimensioned arrays are
treated as collections of 1-D arrays, so that
$a = xvals(10,10)+10*yvals(10,10);
$b = $a->index(3);
$c = $a->index(9-xvals(10));
puts a single column from $a into $b, and puts a single element from each column
of $a into $c. If you want to extract multiple columns from an array in one
operation, see dice or indexND.
index1d propagates BAD index elements to the output variable.
index2d¶
Signature: (a(na,nb); indx inda(); indx indb(); [oca] c())
"index", "index1d", and "index2d" provide
rudimentary index indirection.
$c = index($source,$ind);
$c = index($source,$ind);
$c = index2d($source2,$ind1,$ind2);
use the $ind variables as indices to look up values in $source. The three
routines thread slightly differently.
- "index" uses direct threading for 1-D indexing across the 0 dim
of $source. It can thread over source thread dims or index thread dims dims
not not (easily) both: If <$source> has more than 1 dimension and $ind
has more than 0 dimensions, they must agree in a threading sense.
- "index1d" uses a single active dim in $ind to produce a list of
indexed values in the 0 dim of the output - it is useful for collapsing
$source by indexing with a single row of values long $source's 0 dimension.
The output has the same number of dims as $source. The 0 dim of the output
has size 1 if $ind is a scalar, and the same size as the 0 dim of $ind if it
is not. If $ind and $<source> both have more than 1 dim, then all dims
higher than 0 must agree in a threading sense.
- "index2d" works like "index" but uses separate piddles
for X and Y coordinates. For more general N-dimensional indexing, see the
PDL::NiceSlice syntax or PDL::Slices (in particular "slice",
"indexND", and "range").
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.
"index" provids simple threading: multiple-dimensioned arrays are
treated as collections of 1-D arrays, so that
$a = xvals(10,10)+10*yvals(10,10);
$b = $a->index(3);
$c = $a->index(9-xvals(10));
puts a single column from $a into $b, and puts a single element from each column
of $a into $c. If you want to extract multiple columns from an array in one
operation, see dice or indexND.
index2d barfs if either of the index values are bad.
indexNDb¶
Backwards-compatibility alias for indexND
indexND¶
Find selected elements in an N-D piddle, with optional boundary handling
$out = $source->indexND( $index, [$method] )
$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.
IndexND and IndexNDb were originally separate routines but they are both now
implemented as a call to range, and have identical syntax to one another.
rangeb¶
Signature: (P(); C(); SV *index; SV *size; SV *boundary)
Engine for range
Same calling convention as range, but you must supply all parameters.
"rangeb" is marginally faster as it makes a direct PP call, avoiding
the perl argument-parsing step.
range¶
Extract selected chunks from a source piddle, with boundary conditions
$out = $source->range($index,[$size,[$boundary]])
Returns elements or rectangular slices of the original piddle, indexed by the
$index piddle. $source is an N-dimensional piddle, and $index is a piddle
whose first dimension has size up to N. Each row of $index is treated as
coordinates of a single value or chunk from $source, specifying the
location(s) to extract.
If you specify a single index location, then range is essentially an expensive
slice, with controllable boundary conditions.
INPUTS
$index and $size can be piddles or array refs such as you would feed to zeroes
and its ilk. If $index's 0th dimension has size higher than the number of
dimensions in $source, then $source is treated as though it had trivial dummy
dimensions of size 1, up to the required size to be indexed by $index -- so if
your source array is 1-D and your index array is a list of 3-vectors, you get
two dummy dimensions of size 1 on the end of your source array.
You can extract single elements or N-D rectangular ranges from $source, by
setting $size. If $size is undef or zero, then you get a single sample for
each row of $index. This behavior is similar to indexNDb, which is in fact
implemented as a call to range.
If $size is positive then you get a range of values from $source at each
location, and the output has extra dimensions allocated for them. $size can be
a scalar, in which case it applies to all dimensions, or an N-vector, in which
case each element is applied independently to the corresponding dimension in
$source. See below for details.
$boundary is a number, string, or list ref indicating the type of boundary
conditions to use when ranges reach the edge of $source. If you specify no
boundary conditions the default is to forbid boundary violations on all axes.
If you specify exactly one boundary condition, it applies to all axes. If you
specify more (as elements of a list ref, or as a packed string, see below),
then they apply to dimensions in the order in which they appear, and the last
one applies to all subsequent dimensions. (This is less difficult than it
sounds; see the examples below).
- 0 (synonyms: 'f','forbid') (default)
- Ranges are not allowed to cross the boundary of the original PDL.
Disallowed ranges throw an error. The errors are thrown at evaluation
time, not at the time of the range call (this is the same behavior as
slice).
- 1 (synonyms: 't','truncate')
- Values outside the original piddle get BAD if you've got bad value support
compiled into your PDL and set the badflag for the source PDL; or 0 if you
haven't (you must set the badflag if you want BADs for out of bound
values, otherwise you get 0). Reverse dataflow works OK for the portion of
the child that is in-bounds. The out-of-bounds part of the child is reset
to (BAD|0) during each dataflow operation, but execution continues.
- 2 (synonyms: 'e','x','extend')
- Values that would be outside the original piddle point instead to the
nearest allowed value within the piddle. See the CAVEAT below on mappings
that are not single valued.
- 3 (synonyms: 'p','periodic')
- Periodic boundary conditions apply: the numbers in $index are applied,
strict-modulo the corresponding dimensions of $source. This is equivalent
to duplicating the $source piddle throughout N-D space. See the CAVEAT
below about mappings that are not single valued.
- 4 (synonyms: 'm','mirror')
- Mirror-reflection periodic boundary conditions apply. See the CAVEAT below
about mappings that are not single valued.
The boundary condition identifiers all begin with unique characters, so you can
feed in multiple boundary conditions as either a list ref or a packed string.
(The packed string is marginally faster to run). For example, the four
expressions [0,1], ['forbid','truncate'], ['f','t'], and 'ft' all specify that
violating the boundary in the 0th dimension throws an error, and all other
dimensions get truncated.
If you feed in a single string, it is interpreted as a packed boundary array if
all of its characters are valid boundary specifiers (e.g. 'pet'), but as a
single word-style specifier if they are not (e.g. 'forbid').
OUTPUT
The output threads over both $index and $source. Because implicit threading can
happen in a couple of ways, a little thought is needed. The returned dimension
list is stacked up like this:
(index thread dims), (index dims (size)), (source thread dims)
The first few dims of the output correspond to the extra dims of $index (beyond
the 0 dim). They allow you to pick out individual ranges from a large,
threaded collection.
The middle few dims of the output correspond to the size dims specified in
$size, and contain the range of values that is extracted at each location in
$source. Every nonzero element of $size is copied to the dimension list here,
so that if you feed in (for example) "$size = [2,0,1]" you get an
index dim list of "(2,1)".
The last few dims of the output correspond to extra dims of $source beyond the
number of dims indexed by $index. These dims act like ordinary thread dims,
because adding more dims to $source just tacks extra dims on the end of the
output. Each source thread dim ranges over the entire corresponding dim of
$source.
Dataflow: Dataflow is bidirectional.
Examples: Here are basic examples of "range" operation, showing
how to get ranges out of a small matrix. The first few examples show
extraction and selection of individual chunks. The last example shows how to
mark loci in the original matrix (using dataflow).
pdl> $src = 10*xvals(10,5)+yvals(10,5)
pdl> print $src->range([2,3]) # Cut out a single element
23
pdl> print $src->range([2,3],1) # Cut out a single 1x1 block
[
[23]
]
pdl> print $src->range([2,3], [2,1]) # Cut a 2x1 chunk
[
[23 33]
]
pdl> print $src->range([[2,3]],[2,1]) # Trivial list of 1 chunk
[
[
[23]
[33]
]
]
pdl> print $src->range([[2,3],[0,1]], [2,1]) # two 2x1 chunks
[
[
[23 1]
[33 11]
]
]
pdl> # A 2x2 collection of 2x1 chunks
pdl> print $src->range([[[1,1],[2,2]],[[2,3],[0,1]]],[2,1])
[
[
[
[11 22]
[23 1]
]
[
[21 32]
[33 11]
]
]
]
pdl> $src = xvals(5,3)*10+yvals(5,3)
pdl> print $src->range(3,1) # Thread over y dimension in $src
[
[30]
[31]
[32]
]
pdl> $src = zeroes(5,4);
pdl> $src->range(pdl([2,3],[0,1]),pdl(2,1)) .= xvals(2,2,1) + 1
pdl> print $src
[
[0 0 0 0 0]
[2 2 0 0 0]
[0 0 0 0 0]
[0 0 1 1 0]
]
CAVEAT: It's quite possible to select multiple ranges that intersect. In
that case, modifying the ranges doesn't have a guaranteed result in the
original PDL -- the result is an arbitrary choice among the valid values. For
some things that's OK; but for others it's not. In particular, this doesn't
work:
pdl> $photon_list = new PDL::RandVar->sample(500)->reshape(2,250)*10
pdl> histogram = zeroes(10,10)
pdl> histogram->range($photon_list,1)++; #not what you wanted
The reason is that if two photons land in the same bin, then that bin doesn't
get incremented twice. (That may get fixed in a later version...)
PERMISSIVE RANGING: If $index has too many dimensions compared to
$source, then $source is treated as though it had dummy dimensions of size 1,
up to the required number of dimensions. These virtual dummy dimensions have
the usual boundary conditions applied to them.
If the 0 dimension of $index is ludicrously large (if its size is more than 5
greater than the number of dims in the source PDL) then range will insist that
you specify a size in every dimension, to make sure that you know what you're
doing. That catches a common error with range usage: confusing the initial dim
(which is usually small) with another index dim (perhaps of size 1000).
If the index variable is Empty, then
range() always returns the Empty
PDL. If the index variable is not Empty, indexing it always yields a boundary
violation. All non-barfing conditions are treated as truncation, since there
are no actual data to return.
EFFICIENCY: Because "range" isn't an affine transformation (it
involves lookup into a list of N-D indices), it is somewhat memory-inefficient
for long lists of ranges, and keeping dataflow open is much slower than for
affine transformations (which don't have to copy data around).
Doing operations on small subfields of a large range is inefficient because the
engine must flow the entire range back into the original PDL with every atomic
perl operation, even if you only touch a single element. One way to speed up
such code is to sever your range, so that PDL doesn't have to copy the data
with each operation, then copy the elements explicitly at the end of your
loop. Here's an example that labels each region in a range sequentially, using
many small operations rather than a single xvals assignment:
### How to make a collection of small ops run fast with range...
$a = $data->range($index, $sizes, $bound)->sever;
$aa = $data->range($index, $sizes, $bound);
map { $a($_ - 1) .= $_; } (1..$a->nelem); # Lots of little ops
$aa .= $a;
"range" is a perl front-end to a PP function, "rangeb".
Calling "rangeb" is marginally faster but requires that you include
all arguments.
DEVEL NOTES
* index thread dimensions are effectively clumped internally. This makes it
easier to loop over the index array but a little more brain-bending to tease
out the algorithm.
rangeb processes bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
rld¶
Signature: (indx 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);
rld does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
rle¶
Signature: (c(n); indx [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);
rle does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
xchg¶
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)
xchg does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
reorder¶
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
You do not need to specify all dimensions, only a complete set starting at
position 0. (Extra dimensions are left where they are). This means, for
example, that you can
reorder() the X and Y dimensions of an image, and
not care whether it is an RGB image with a third dimension running across
color plane.
Example:
pdl> $a = sequence(5,3,2); # Create a 3-d Array
pdl> 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]
]
]
pdl> 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.
mv does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
oneslice¶
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.
oneslice does not process bad values. It will set the bad-value flag of all
output piddles if the flag is set for any of the input piddles.
oslice¶
Signature: (P(); C(); char* str)
DEPRECATED: 'oslice' is the original 'slice' routine in pre-2.006_006 versions
of PDL. It is left here for reference but will disappear in PDL 3.000
Extract a rectangular slice of a piddle, from a string specifier.
"slice" was the original Swiss-army-knife PDL indexing routine, but is
largely superseded by the NiceSlice source prefilter and its associated nslice
method. It is still used as the basic underlying slicing engine for nslice,
and is especially useful in particular niche applications.
$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):
- :
- takes the whole dimension intact.
- ''
- (nothing) is a synonym for ":" (This means that
"$a->slice(':,3')" is equal to
"$a->slice(',3')").
- a
- slices only this value out of the corresponding dimension.
- (a)
- means the same as "a" by itself except that the resulting
dimension of length one is deleted (so if $a has dims "(3,4,5)"
then "$a->slice(':,(2),:')" has dimensions "(3,5)"
whereas "$a->slice(':,2,:')" has dimensions
"(3,1,5))".
- a:b
- slices the range a to b inclusive out of the dimension.
- a:b:c
- slices the range a to b, with step c (i.e.
"3:7:2" gives the indices "(3,5,7)"). This may be
confusing to Matlab users but several other packages already use this
syntax.
- '*'
- inserts an extra dimension of width 1 and
- '*a'
- inserts an extra (dummy) dimension of width a.
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.
oslice does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
using¶
Returns array of column numbers requested
line $pdl->using(1,2);
Plot, as a line, column 1 of $pdl vs. column 2
pdl> $pdl = rcols("file");
pdl> line $pdl->using(1,2);
diagonalI¶
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
diagonalI does not process bad values. It will set the bad-value flag of all
output piddles if the flag is set for any of the input piddles.
lags¶
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).
lags does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
splitdim¶
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).
splitdim does not process bad values. It will set the bad-value flag of all
output piddles if the flag is set for any of the input piddles.
rotate¶
Signature: (x(n); indx shift(); [oca]y(n))
Shift vector elements along with wrap. Flows data back&forth.
rotate does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
threadI¶
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
threadI does not process bad values. It will set the bad-value flag of all
output piddles if the flag is set for any of the input piddles.
identvaff¶
Signature: (P(); C())
A vaffine identity transformation (includes thread_id copying).
Mainly for internal use.
identvaff does not process bad values. It will set the bad-value flag of all
output piddles if the flag is set for any of the input piddles.
unthread¶
Signature: (P(); C(); int atind)
All threaded dimensions are made real again.
See [TBD Doc] for details and examples.
unthread does not process bad values. It will set the bad-value flag of all
output piddles if the flag is set for any of the input piddles.
dice¶
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.
pdl> $a = sequence(10,4)
pdl> 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]
]
pdl> p $a->dice([1,2],[0,3]) # Select columns 1,2 and rows 0,3
[
[ 1 2]
[31 32]
]
pdl> 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]
]
pdl> 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_axis¶
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);
pdl> $a = sequence(10,4)
pdl> $idx = pdl(1,2)
pdl> p $a->dice_axis(0,$idx) # Select columns
[
[ 1 2]
[11 12]
[21 22]
[31 32]
]
pdl> $t = $a->dice_axis(1,$idx) # Select rows
pdl> $t.=0
pdl> 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.
slice¶
$slice = $data->slice([2,3],'x',[2,2,0],"-1:1:-1", "*3");
Extract rectangular slices of a piddle, from a string specifier, an array ref
specifier, or a combination.
"slice" is the main method for extracting regions of PDLs and
manipulating their dimensionality. You can call it directly or via he
NiceSlice source prefilter that extends Perl syntax o include array slicing.
"slice" can extract regions along each dimension of a source PDL,
subsample or reverse those regions, dice each dimension by selecting a list of
locations along it, or basic PDL indexing routine. The selected subfield
remains connected to the original PDL via dataflow. In most cases this neither
allocates more memory nor slows down subsequent operations on either of the
two connected PDLs.
You pass in a list of arguments. Each term in the list controls the disposition
of one axis of the source PDL and/or returned PDL. Each term can be a
string-format cut specifier, a list ref that gives the same information
without recourse to string manipulation, or a PDL with up to 1 dimension
giving indices along that axis that should be selected.
If you want to pass in a single string specifier for the entire operation, you
can pass in a comma-delimited list as the first argument. "slice"
detects this condition and splits the string into a regular argument list.
This calling style is fully backwards compatible with "slice" calls
from before PDL 2.006.
STRING SYNTAX
If a particular argument to "slice" is a string, it is parsed as a
selection, an affine slice, or a dummy dimension depending on the form.
Leading or trailing whitespace in any part of each specifier is ignored
(though it is not ignored within numbers).
- "", ":", or "X" -- keep
- The empty string, ":", or "X" cause the entire
corresponding dimension to be kept unchanged.
- "<n>" -- selection
- A single number alone causes a single index to be selected from the
corresponding dimension. The dimension is kept (and reduced to size 1) in
the output.
- "(<n>)" -- selection and collapse
- A single number in parenthesis causes a single index to be selected from
the corresponding dimension. The dimension is discarded (completely
eliminated) in the output.
- "<n>:<m>" -- select an inclusive range
- Two numbers separated by a colon selects a range of values from the
corresponding axis, e.g. "3:4" selects elements 3 and 4 along
the corresponding axis, and reduces that axis to size 2 in the output.
Both numbers are regularized so that you can address the last element of
the axis with an index of " -1 ". If, after regularization, the
two numbers are the same, then exactly one element gets selected (just
like the "<n>" case). If, after regulariation, the second
number is lower than the first, then the resulting slice counts down
rather than up -- e.g. "-1:0" will return the entire axis, in
reversed order.
- "<n>:<m>:<s>" -- select a range with explicit
step
- If you include a third parameter, it is the stride of the extracted range.
For example, "0:-1:2" will sample every other element across the
complete dimension. Specifying a stride of 1 prevents autoreversal -- so
to ensure that your slice is *always* forward you can specify, e.g.,
"2:$n:1". In that case, an "impossible" slice gets an
Empty PDL (with 0 elements along the corresponding dimension), so you can
generate an Empty PDL with a slice of the form "2:1:1".
- "*<n>" -- insert a dummy dimension
- Dummy dimensions aren't present in the original source and are
"mocked up" to match dimensional slots, by repeating the data in
the original PDL some number of times. An asterisk followed by a number
produces a dummy dimension in the output, for example *2 will generate a
dimension of size 2 at the corresponding location in the output dim list.
Omitting the numeber (and using just an asterisk) inserts a dummy
dimension of size 1.
ARRAY REF SYNTAX
If you feed in an ARRAY ref as a slice term, then it can have 0-3 elements. The
first element is the start of the slice along the corresponding dim; the
second is the end; and the third is the stepsize. Different combinations of
inputs give the same flexibility as the string syntax.
- "[]" - keep dim intact
- An empty ARRAY ref keeps the entire corresponding dim
- "[ 'X' ]" - keep dim intact
- "[ '*',$n ]" - generate a dummy dim of size $n
- If $n is missing, you get a dummy dim of size 1.
- "[ $dex, , 0 ]" - collapse and discard dim
- $dex must be a single value. It is used to index the source, and the
corresponding dimension is discarded.
- "[ $start, $end ]" - collect inclusive slice
- In the simple two-number case, you get a slice that runs up or down (as
appropriate) to connect $start and $end.
- "[ $start, $end, $inc ]" - collect inclusive slice
- The three-number case works exactly like the three-number string case
above.
PDL args for dicing
If you pass in a 0- or 1-D PDL as a slicing argument, the corresponding
dimension is "diced" -- you get one position along the corresponding
dim, per element of the indexing PDL, e.g. "$a->slice(
pdl(3,4,9))" gives you elements 3, 4, and 9 along the 0 dim of $a.
Because dicing is not an affine transformation, it is slower than direct slicing
even though the syntax is convenient.
$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
$a->slice([1,3]); # Same as above three calls, but using array ref syntax
$a->slice([3,1]);
$a->slice([-2,1]);
sliceb¶
Signature: (P(); C(); SV *args)
info not available
sliceb does not process bad values. It will set the bad-value flag of all output
piddles if the flag is set for any of the input piddles.
BUGS¶
For the moment, you can't slice one of the zero-length dims of an empty piddle.
It is not clear how to implement this in a way that makes sense.
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).
AUTHOR¶
Copyright (C) 1997 Tuomas J. Lukka. Contributions by Craig DeForest,
deforest@boulder.swri.edu. Documentation contributions by David Mertens. 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.