File Coverage

blib/lib/PDLA/Slices.pm
Criterion Covered Total %
statement 90 102 88.2
branch 35 46 76.0
condition 9 18 50.0
subroutine 14 15 93.3
pod 0 9 0.0
total 148 190 77.8


line stmt bran cond sub pod time code
1              
2             #
3             # GENERATED WITH PDLA::PP! Don't modify!
4             #
5             package PDLA::Slices;
6              
7             @EXPORT_OK = qw( PDLA::PP affineinternal PDLA::PP s_identity PDLA::PP index PDLA::PP index1d PDLA::PP index2d indexND indexNDb PDLA::PP rangeb PDLA::PP rld PDLA::PP rle PDLA::PP flowconvert PDLA::PP converttypei PDLA::PP _clump_int PDLA::PP xchg PDLA::PP mv PDLA::PP oslice using PDLA::PP affine PDLA::PP diagonalI PDLA::PP lags PDLA::PP splitdim PDLA::PP rotate PDLA::PP threadI PDLA::PP identvaff PDLA::PP unthread dice dice_axis slice PDLA::PP sliceb );
8             %EXPORT_TAGS = (Func=>[@EXPORT_OK]);
9              
10 77     77   535 use PDLA::Core;
  77         149  
  77         527  
11 77     77   552 use PDLA::Exporter;
  77         180  
  77         759  
12 77     77   398 use DynaLoader;
  77         156  
  77         4772  
13              
14              
15              
16            
17             @ISA = ( 'PDLA::Exporter','DynaLoader' );
18             push @PDLA::Core::PP, __PACKAGE__;
19             bootstrap PDLA::Slices ;
20              
21              
22              
23              
24              
25             =head1 NAME
26              
27             PDLA::Slices -- Indexing, slicing, and dicing
28              
29             =head1 SYNOPSIS
30              
31             use PDLA;
32             $x = ones(3,3);
33             $y = $x->slice('-1:0,(1)');
34             $c = $x->dummy(2);
35              
36              
37             =head1 DESCRIPTION
38              
39             This package provides many of the powerful PerlDL core index
40             manipulation routines. These routines mostly allow two-way data flow,
41             so you can modify your data in the most convenient representation.
42             For example, you can make a 1000x1000 unit matrix with
43              
44             $x = zeroes(1000,1000);
45             $x->diagonal(0,1) ++;
46              
47             which is quite efficient. See L and L for
48             more examples.
49              
50             Slicing is so central to the PDLA language that a special compile-time
51             syntax has been introduced to handle it compactly; see L
52             for details.
53              
54             PDLA indexing and slicing functions usually include two-way data flow,
55             so that you can separate the actions of reshaping your data structures
56             and modifying the data themselves. Two special methods, L and
57             L, help you control the data flow connection between related
58             variables.
59              
60             $y = $x->slice("1:3"); # Slice maintains a link between $x and $y.
61             $y += 5; # $x is changed!
62              
63             If you want to force a physical copy and no data flow, you can copy or
64             sever the slice expression:
65              
66             $y = $x->slice("1:3")->copy;
67             $y += 5; # $x is not changed.
68              
69             $y = $x->slice("1:3")->sever;
70             $y += 5; # $x is not changed.
71              
72             The difference between C and C is that sever acts on (and
73             returns) its argument, while copy produces a disconnected copy. If you
74             say
75              
76             $y = $x->slice("1:3");
77             $c = $y->sever;
78              
79             then the variables C<$y> and C<$c> point to the same object but with
80             C<-Ecopy> they would not.
81              
82             =cut
83              
84 77     77   471 use PDLA::Core ':Internal';
  77         156  
  77         334  
85 77     77   523 use Scalar::Util 'blessed';
  77         168  
  77         41177  
86              
87              
88              
89              
90              
91              
92              
93             =head1 FUNCTIONS
94              
95              
96              
97             =cut
98              
99              
100              
101              
102              
103              
104             *affineinternal = \&PDLA::affineinternal;
105              
106              
107              
108              
109              
110             =head2 s_identity
111              
112             =for sig
113              
114             Signature: (P(); C())
115              
116             =for ref
117              
118             Internal vaffine identity function.
119              
120              
121              
122             =for bad
123              
124             s_identity processes bad values.
125             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
126              
127              
128             =cut
129              
130              
131              
132              
133              
134              
135             *s_identity = \&PDLA::s_identity;
136              
137              
138              
139              
140              
141             =head2 index
142              
143             =for sig
144              
145             Signature: (a(n); indx ind(); [oca] c())
146              
147             =for ref
148              
149             C, C, and C provide rudimentary index indirection.
150              
151             =for example
152              
153             $c = index($source,$ind);
154             $c = index1d($source,$ind);
155             $c = index2d($source2,$ind1,$ind2);
156              
157             use the C<$ind> variables as indices to look up values in C<$source>.
158             The three routines thread slightly differently.
159              
160             =over 3
161              
162             =item *
163              
164             C uses direct threading for 1-D indexing across the 0 dim
165             of C<$source>. It can thread over source thread dims or index thread
166             dims, but not (easily) both: If C<$source> has more than 1
167             dimension and C<$ind> has more than 0 dimensions, they must agree in
168             a threading sense.
169              
170             =item *
171              
172             C uses a single active dim in C<$ind> to produce a list of
173             indexed values in the 0 dim of the output - it is useful for
174             collapsing C<$source> by indexing with a single row of values along
175             C<$source>'s 0 dimension. The output has the same number of dims as
176             C<$source>. The 0 dim of the output has size 1 if C<$ind> is a
177             scalar, and the same size as the 0 dim of C<$ind> if it is not. If
178             C<$ind> and C<$source> both have more than 1 dim, then all dims higher
179             than 0 must agree in a threading sense.
180              
181             =item *
182              
183             C works like C but uses separate piddles for X and Y
184             coordinates. For more general N-dimensional indexing, see the
185             L syntax or L (in particular C,
186             C, and C).
187              
188             =back
189              
190             These functions are two-way, i.e. after
191              
192             $c = $x->index(pdl[0,5,8]);
193             $c .= pdl [0,2,4];
194              
195             the changes in C<$c> will flow back to C<$x>.
196              
197             C provids simple threading: multiple-dimensioned arrays are treated
198             as collections of 1-D arrays, so that
199              
200             $x = xvals(10,10)+10*yvals(10,10);
201             $y = $x->index(3);
202             $c = $x->index(9-xvals(10));
203              
204             puts a single column from C<$x> into C<$y>, and puts a single element
205             from each column of C<$x> into C<$c>. If you want to extract multiple
206             columns from an array in one operation, see L or
207             L.
208              
209              
210              
211             =for bad
212              
213             index barfs if any of the index values are bad.
214              
215             =cut
216              
217              
218              
219              
220              
221              
222             *index = \&PDLA::index;
223              
224              
225              
226              
227              
228             =head2 index1d
229              
230             =for sig
231              
232             Signature: (a(n); indx ind(m); [oca] c(m))
233              
234             =for ref
235              
236             C, C, and C provide rudimentary index indirection.
237              
238             =for example
239              
240             $c = index($source,$ind);
241             $c = index1d($source,$ind);
242             $c = index2d($source2,$ind1,$ind2);
243              
244             use the C<$ind> variables as indices to look up values in C<$source>.
245             The three routines thread slightly differently.
246              
247             =over 3
248              
249             =item *
250              
251             C uses direct threading for 1-D indexing across the 0 dim
252             of C<$source>. It can thread over source thread dims or index thread
253             dims, but not (easily) both: If C<$source> has more than 1
254             dimension and C<$ind> has more than 0 dimensions, they must agree in
255             a threading sense.
256              
257             =item *
258              
259             C uses a single active dim in C<$ind> to produce a list of
260             indexed values in the 0 dim of the output - it is useful for
261             collapsing C<$source> by indexing with a single row of values along
262             C<$source>'s 0 dimension. The output has the same number of dims as
263             C<$source>. The 0 dim of the output has size 1 if C<$ind> is a
264             scalar, and the same size as the 0 dim of C<$ind> if it is not. If
265             C<$ind> and C<$source> both have more than 1 dim, then all dims higher
266             than 0 must agree in a threading sense.
267              
268             =item *
269              
270             C works like C but uses separate piddles for X and Y
271             coordinates. For more general N-dimensional indexing, see the
272             L syntax or L (in particular C,
273             C, and C).
274              
275             =back
276              
277             These functions are two-way, i.e. after
278              
279             $c = $x->index(pdl[0,5,8]);
280             $c .= pdl [0,2,4];
281              
282             the changes in C<$c> will flow back to C<$x>.
283              
284             C provids simple threading: multiple-dimensioned arrays are treated
285             as collections of 1-D arrays, so that
286              
287             $x = xvals(10,10)+10*yvals(10,10);
288             $y = $x->index(3);
289             $c = $x->index(9-xvals(10));
290              
291             puts a single column from C<$x> into C<$y>, and puts a single element
292             from each column of C<$x> into C<$c>. If you want to extract multiple
293             columns from an array in one operation, see L or
294             L.
295              
296              
297              
298             =for bad
299              
300             index1d propagates BAD index elements to the output variable.
301              
302             =cut
303              
304              
305              
306              
307              
308              
309             *index1d = \&PDLA::index1d;
310              
311              
312              
313              
314              
315             =head2 index2d
316              
317             =for sig
318              
319             Signature: (a(na,nb); indx inda(); indx indb(); [oca] c())
320              
321             =for ref
322              
323             C, C, and C provide rudimentary index indirection.
324              
325             =for example
326              
327             $c = index($source,$ind);
328             $c = index1d($source,$ind);
329             $c = index2d($source2,$ind1,$ind2);
330              
331             use the C<$ind> variables as indices to look up values in C<$source>.
332             The three routines thread slightly differently.
333              
334             =over 3
335              
336             =item *
337              
338             C uses direct threading for 1-D indexing across the 0 dim
339             of C<$source>. It can thread over source thread dims or index thread
340             dims, but not (easily) both: If C<$source> has more than 1
341             dimension and C<$ind> has more than 0 dimensions, they must agree in
342             a threading sense.
343              
344             =item *
345              
346             C uses a single active dim in C<$ind> to produce a list of
347             indexed values in the 0 dim of the output - it is useful for
348             collapsing C<$source> by indexing with a single row of values along
349             C<$source>'s 0 dimension. The output has the same number of dims as
350             C<$source>. The 0 dim of the output has size 1 if C<$ind> is a
351             scalar, and the same size as the 0 dim of C<$ind> if it is not. If
352             C<$ind> and C<$source> both have more than 1 dim, then all dims higher
353             than 0 must agree in a threading sense.
354              
355             =item *
356              
357             C works like C but uses separate piddles for X and Y
358             coordinates. For more general N-dimensional indexing, see the
359             L syntax or L (in particular C,
360             C, and C).
361              
362             =back
363              
364             These functions are two-way, i.e. after
365              
366             $c = $x->index(pdl[0,5,8]);
367             $c .= pdl [0,2,4];
368              
369             the changes in C<$c> will flow back to C<$x>.
370              
371             C provids simple threading: multiple-dimensioned arrays are treated
372             as collections of 1-D arrays, so that
373              
374             $x = xvals(10,10)+10*yvals(10,10);
375             $y = $x->index(3);
376             $c = $x->index(9-xvals(10));
377              
378             puts a single column from C<$x> into C<$y>, and puts a single element
379             from each column of C<$x> into C<$c>. If you want to extract multiple
380             columns from an array in one operation, see L or
381             L.
382              
383              
384              
385             =for bad
386              
387             index2d barfs if either of the index values are bad.
388              
389             =cut
390              
391              
392              
393              
394              
395              
396             *index2d = \&PDLA::index2d;
397              
398              
399              
400              
401             =head2 indexNDb
402              
403             =for ref
404              
405             Backwards-compatibility alias for indexND
406              
407             =head2 indexND
408              
409             =for ref
410              
411             Find selected elements in an N-D piddle, with optional boundary handling
412              
413             =for example
414              
415             $out = $source->indexND( $index, [$method] )
416              
417             $source = 10*xvals(10,10) + yvals(10,10);
418             $index = pdl([[2,3],[4,5]],[[6,7],[8,9]]);
419             print $source->indexND( $index );
420              
421             [
422             [23 45]
423             [67 89]
424             ]
425              
426             IndexND collapses C<$index> by lookup into C<$source>. The
427             0th dimension of C<$index> is treated as coordinates in C<$source>, and
428             the return value has the same dimensions as the rest of C<$index>.
429             The returned elements are looked up from C<$source>. Dataflow
430             works -- propagated assignment flows back into C<$source>.
431              
432             IndexND and IndexNDb were originally separate routines but they are both
433             now implemented as a call to L, and have identical syntax to
434             one another.
435              
436             =cut
437              
438             sub PDLA::indexND {
439 5     5 0 119 my($source,$index, $boundary) = @_;
440 5         18 return PDLA::range($source,$index,undef,$boundary);
441             }
442              
443             *PDLA::indexNDb = \&PDLA::indexND;
444              
445              
446              
447              
448             sub PDLA::range {
449 16     16 0 538 my($source,$ind,$sz,$bound) = @_;
450              
451             # Convert to indx type up front (also handled in rangeb if necessary)
452 16 100 66     125 my $index = (ref $ind && UNIVERSAL::isa($ind,'PDLA') && $ind->type eq 'indx') ? $ind : indx($ind);
453 16 100       54 my $size = defined($sz) ? PDLA->pdl($sz) : undef;
454              
455              
456             # Handle empty PDLA case: return a properly constructed Empty.
457 16 100       69 if($index->isempty) {
458 4         10 my @sdims= $source->dims;
459 4         62 splice(@sdims, 0, $index->dim(0) + ($index->dim(0)==0)); # added term is to treat Empty[0] like a single empty coordinate
460 4 50       11 unshift(@sdims, $size->list) if(defined($size));
461 4         16 return PDLA->new_from_specification(0 x ($index->ndims-1), @sdims);
462             }
463              
464              
465 12 50       44 $index = $index->dummy(0,1) unless $index->ndims;
466              
467              
468             # Pack boundary string if necessary
469 12 100       27 if(defined $bound) {
470 5 100 66     47 if(ref $bound eq 'ARRAY') {
    100          
471 1         2 my ($s,$el);
472 1         4 foreach $el(@$bound) {
473 2 50       8 barf "Illegal boundary value '$el' in range"
474             unless( $el =~ m/^([0123fFtTeEpPmM])/ );
475 2         6 $s .= $1;
476             }
477 1         2 $bound = $s;
478             }
479             elsif($bound !~ m/^[0123ftepx]+$/ && $bound =~ m/^([0123ftepx])/i ) {
480 1         5 $bound = $1;
481             }
482             }
483              
484 77     77   608 no warnings; # shut up about passing undef into rangeb
  77         187  
  77         111095  
485 12         295 $source->rangeb($index,$size,$bound);
486             }
487              
488              
489              
490              
491             =head2 rangeb
492              
493             =for sig
494              
495             Signature: (P(); C(); SV *index; SV *size; SV *boundary)
496              
497             =for ref
498              
499             Engine for L
500              
501             =for example
502              
503             Same calling convention as L, but you must supply all
504             parameters. C is marginally faster as it makes a direct PP call,
505             avoiding the perl argument-parsing step.
506              
507              
508             =head2 range
509              
510             =for ref
511              
512             Extract selected chunks from a source piddle, with boundary conditions
513              
514             =for example
515              
516             $out = $source->range($index,[$size,[$boundary]])
517              
518             Returns elements or rectangular slices of the original piddle, indexed by
519             the C<$index> piddle. C<$source> is an N-dimensional piddle, and C<$index> is
520             a piddle whose first dimension has size up to N. Each row of C<$index> is
521             treated as coordinates of a single value or chunk from C<$source>, specifying
522             the location(s) to extract.
523              
524             If you specify a single index location, then range is essentially an expensive
525             slice, with controllable boundary conditions.
526              
527             B
528              
529             C<$index> and C<$size> can be piddles or array refs such as you would
530             feed to L and its ilk. If C<$index>'s 0th dimension
531             has size higher than the number of dimensions in C<$source>, then
532             C<$source> is treated as though it had trivial dummy dimensions of
533             size 1, up to the required size to be indexed by C<$index> -- so if
534             your source array is 1-D and your index array is a list of 3-vectors,
535             you get two dummy dimensions of size 1 on the end of your source array.
536              
537             You can extract single elements or N-D rectangular ranges from C<$source>,
538             by setting C<$size>. If C<$size> is undef or zero, then you get a single
539             sample for each row of C<$index>. This behavior is similar to
540             L, which is in fact implemented as a call to L.
541              
542             If C<$size> is positive then you get a range of values from C<$source> at
543             each location, and the output has extra dimensions allocated for them.
544             C<$size> can be a scalar, in which case it applies to all dimensions, or an
545             N-vector, in which case each element is applied independently to the
546             corresponding dimension in C<$source>. See below for details.
547              
548             C<$boundary> is a number, string, or list ref indicating the type of
549             boundary conditions to use when ranges reach the edge of C<$source>. If you
550             specify no boundary conditions the default is to forbid boundary violations
551             on all axes. If you specify exactly one boundary condition, it applies to
552             all axes. If you specify more (as elements of a list ref, or as a packed
553             string, see below), then they apply to dimensions in the order in which they
554             appear, and the last one applies to all subsequent dimensions. (This is
555             less difficult than it sounds; see the examples below).
556              
557             =over 3
558              
559             =item 0 (synonyms: 'f','forbid') B<(default)>
560              
561             Ranges are not allowed to cross the boundary of the original PDLA. Disallowed
562             ranges throw an error. The errors are thrown at evaluation time, not
563             at the time of the range call (this is the same behavior as L).
564              
565             =item 1 (synonyms: 't','truncate')
566              
567             Values outside the original piddle get BAD if you've got bad value
568             support compiled into your PDLA and set the badflag for the source PDLA;
569             or 0 if you haven't (you must set the badflag if you want BADs for out
570             of bound values, otherwise you get 0). Reverse dataflow works OK for
571             the portion of the child that is in-bounds. The out-of-bounds part of
572             the child is reset to (BAD|0) during each dataflow operation, but
573             execution continues.
574              
575             =item 2 (synonyms: 'e','x','extend')
576              
577             Values that would be outside the original piddle point instead to the
578             nearest allowed value within the piddle. See the CAVEAT below on
579             mappings that are not single valued.
580              
581             =item 3 (synonyms: 'p','periodic')
582              
583             Periodic boundary conditions apply: the numbers in $index are applied,
584             strict-modulo the corresponding dimensions of $source. This is equivalent to
585             duplicating the $source piddle throughout N-D space. See the CAVEAT below
586             about mappings that are not single valued.
587              
588             =item 4 (synonyms: 'm','mirror')
589              
590             Mirror-reflection periodic boundary conditions apply. See the CAVEAT
591             below about mappings that are not single valued.
592              
593             =back
594              
595             The boundary condition identifiers all begin with unique characters, so
596             you can feed in multiple boundary conditions as either a list ref or a
597             packed string. (The packed string is marginally faster to run). For
598             example, the four expressions [0,1], ['forbid','truncate'], ['f','t'],
599             and 'ft' all specify that violating the boundary in the 0th dimension
600             throws an error, and all other dimensions get truncated.
601              
602             If you feed in a single string, it is interpreted as a packed boundary
603             array if all of its characters are valid boundary specifiers (e.g. 'pet'),
604             but as a single word-style specifier if they are not (e.g. 'forbid').
605              
606             B
607              
608             The output threads over both C<$index> and C<$source>. Because implicit
609             threading can happen in a couple of ways, a little thought is needed. The
610             returned dimension list is stacked up like this:
611              
612             (index thread dims), (index dims (size)), (source thread dims)
613              
614             The first few dims of the output correspond to the extra dims of
615             C<$index> (beyond the 0 dim). They allow you to pick out individual
616             ranges from a large, threaded collection.
617              
618             The middle few dims of the output correspond to the size dims
619             specified in C<$size>, and contain the range of values that is extracted
620             at each location in C<$source>. Every nonzero element of C<$size> is copied to
621             the dimension list here, so that if you feed in (for example) C<$size
622             = [2,0,1]> you get an index dim list of C<(2,1)>.
623              
624             The last few dims of the output correspond to extra dims of C<$source> beyond
625             the number of dims indexed by C<$index>. These dims act like ordinary
626             thread dims, because adding more dims to C<$source> just tacks extra dims
627             on the end of the output. Each source thread dim ranges over the entire
628             corresponding dim of C<$source>.
629              
630             B: Dataflow is bidirectional.
631              
632             B:
633             Here are basic examples of C operation, showing how to get
634             ranges out of a small matrix. The first few examples show extraction
635             and selection of individual chunks. The last example shows
636             how to mark loci in the original matrix (using dataflow).
637              
638             pdla> $src = 10*xvals(10,5)+yvals(10,5)
639             pdla> print $src->range([2,3]) # Cut out a single element
640             23
641             pdla> print $src->range([2,3],1) # Cut out a single 1x1 block
642             [
643             [23]
644             ]
645             pdla> print $src->range([2,3], [2,1]) # Cut a 2x1 chunk
646             [
647             [23 33]
648             ]
649             pdla> print $src->range([[2,3]],[2,1]) # Trivial list of 1 chunk
650             [
651             [
652             [23]
653             [33]
654             ]
655             ]
656             pdla> print $src->range([[2,3],[0,1]], [2,1]) # two 2x1 chunks
657             [
658             [
659             [23 1]
660             [33 11]
661             ]
662             ]
663             pdla> # A 2x2 collection of 2x1 chunks
664             pdla> print $src->range([[[1,1],[2,2]],[[2,3],[0,1]]],[2,1])
665             [
666             [
667             [
668             [11 22]
669             [23 1]
670             ]
671             [
672             [21 32]
673             [33 11]
674             ]
675             ]
676             ]
677             pdla> $src = xvals(5,3)*10+yvals(5,3)
678             pdla> print $src->range(3,1) # Thread over y dimension in $src
679             [
680             [30]
681             [31]
682             [32]
683             ]
684              
685             pdla> $src = zeroes(5,4);
686             pdla> $src->range(pdl([2,3],[0,1]),pdl(2,1)) .= xvals(2,2,1) + 1
687             pdla> print $src
688             [
689             [0 0 0 0 0]
690             [2 2 0 0 0]
691             [0 0 0 0 0]
692             [0 0 1 1 0]
693             ]
694              
695             B: It's quite possible to select multiple ranges that
696             intersect. In that case, modifying the ranges doesn't have a
697             guaranteed result in the original PDLA -- the result is an arbitrary
698             choice among the valid values. For some things that's OK; but for
699             others it's not. In particular, this doesn't work:
700              
701             pdla> $photon_list = new PDLA::RandVar->sample(500)->reshape(2,250)*10
702             pdla> histogram = zeroes(10,10)
703             pdla> histogram->range($photon_list,1)++; #not what you wanted
704              
705             The reason is that if two photons land in the same bin, then that bin
706             doesn't get incremented twice. (That may get fixed in a later version...)
707              
708             B: If C<$index> has too many dimensions compared
709             to C<$source>, then $source is treated as though it had dummy
710             dimensions of size 1, up to the required number of dimensions. These
711             virtual dummy dimensions have the usual boundary conditions applied to
712             them.
713              
714             If the 0 dimension of C<$index> is ludicrously large (if its size is
715             more than 5 greater than the number of dims in the source PDLA) then
716             range will insist that you specify a size in every dimension, to make
717             sure that you know what you're doing. That catches a common error with
718             range usage: confusing the initial dim (which is usually small) with another
719             index dim (perhaps of size 1000).
720              
721             If the index variable is Empty, then range() always returns the Empty PDLA.
722             If the index variable is not Empty, indexing it always yields a boundary
723             violation. All non-barfing conditions are treated as truncation, since
724             there are no actual data to return.
725              
726             B: Because C isn't an affine transformation (it
727             involves lookup into a list of N-D indices), it is somewhat
728             memory-inefficient for long lists of ranges, and keeping dataflow open
729             is much slower than for affine transformations (which don't have to copy
730             data around).
731              
732             Doing operations on small subfields of a large range is inefficient
733             because the engine must flow the entire range back into the original
734             PDLA with every atomic perl operation, even if you only touch a single element.
735             One way to speed up such code is to sever your range, so that PDLA
736             doesn't have to copy the data with each operation, then copy the
737             elements explicitly at the end of your loop. Here's an example that
738             labels each region in a range sequentially, using many small
739             operations rather than a single xvals assignment:
740              
741             ### How to make a collection of small ops run fast with range...
742             $x = $data->range($index, $sizes, $bound)->sever;
743             $aa = $data->range($index, $sizes, $bound);
744             map { $x($_ - 1) .= $_; } (1..$x->nelem); # Lots of little ops
745             $aa .= $x;
746              
747             C is a perl front-end to a PP function, C. Calling
748             C is marginally faster but requires that you include all arguments.
749              
750             DEVEL NOTES
751              
752             * index thread dimensions are effectively clumped internally. This
753             makes it easier to loop over the index array but a little more brain-bending
754             to tease out the algorithm.
755              
756             =cut
757              
758              
759              
760             =for bad
761              
762             rangeb processes bad values.
763             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
764              
765              
766             =cut
767              
768              
769              
770              
771              
772              
773             *rangeb = \&PDLA::rangeb;
774              
775              
776              
777              
778              
779             =head2 rld
780              
781             =for sig
782              
783             Signature: (indx a(n); b(n); [o]c(m))
784              
785             =for ref
786              
787             Run-length decode a vector
788              
789             Given a vector C<$x> of the numbers of instances of values C<$y>, run-length
790             decode to C<$c>.
791              
792             =for example
793              
794             rld($x,$y,$c=null);
795              
796              
797              
798             =for bad
799              
800             rld does not process bad values.
801             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
802              
803              
804             =cut
805              
806              
807              
808              
809             sub PDLA::rld {
810 4     4 0 22 my ($x,$y) = @_;
811 4         6 my ($c);
812 4 50       9 if ($#_ == 2) {
813 0         0 $c = $_[2];
814             } else {
815             # XXX Need to improve emulation of threading in auto-generating c
816 4         45 my ($size) = $x->sumover->max;
817 4         14 my (@dims) = $x->dims;
818 4         6 shift @dims;
819 4         11 $c = $y->zeroes($size,@dims);
820             }
821 4         49 &PDLA::_rld_int($x,$y,$c);
822 4         15 $c;
823             }
824              
825              
826             *rld = \&PDLA::rld;
827              
828              
829              
830              
831              
832             =head2 rle
833              
834             =for sig
835              
836             Signature: (c(n); indx [o]a(m); [o]b(m))
837              
838             =for ref
839              
840             Run-length encode a vector
841              
842             Given vector C<$c>, generate a vector C<$x> with the number of each
843             element, and a vector C<$y> of the unique values. New in PDLA 2.017,
844             only the elements up to the first instance of C<0> in C<$x> are
845             returned, which makes the common use case of a 1-dimensional C<$c> simpler.
846             For threaded operation, C<$x> and C<$y> will be large enough
847             to hold the largest row of C<$y>, and only the elements up to the
848             first instance of C<0> in each row of C<$x> should be considered.
849              
850             =for example
851              
852             $c = floor(4*random(10));
853             rle($c,$x=null,$y=null);
854             #or
855             ($x,$y) = rle($c);
856              
857             #for $c of shape [10, 4]:
858             $c = floor(4*random(10,4));
859             ($x,$y) = rle($c);
860              
861             #to see the results of each row one at a time:
862             foreach (0..$c->dim(1)-1){
863             my ($as,$bs) = ($x(:,($_)),$y(:,($_)));
864             my ($ta,$tb) = where($as,$bs,$as!=0); #only the non-zero elements of $x
865             print $c(:,($_)) . " rle==> " , ($ta,$tb) , "\trld==> " . rld($ta,$tb) . "\n";
866             }
867              
868              
869              
870             =for bad
871              
872             rle does not process bad values.
873             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
874              
875              
876             =cut
877              
878              
879              
880              
881             sub PDLA::rle {
882 5     5 0 787 my $c = shift;
883 5 100       21 my ($x,$y) = @_==2 ? @_ : (null,null);
884 5         117 &PDLA::_rle_int($c,$x,$y);
885 5 100       316 my $max_ind = ($c->ndims<2) ? ($x!=0)->sumover-1 :
886             ($x!=0)->clump(1..$x->ndims-1)->sumover->max-1;
887 5         51 return ($x->slice("0:$max_ind"),$y->slice("0:$max_ind"));
888             }
889              
890              
891             *rle = \&PDLA::rle;
892              
893              
894              
895              
896              
897             *flowconvert = \&PDLA::flowconvert;
898              
899              
900              
901              
902              
903             *converttypei = \&PDLA::converttypei;
904              
905              
906              
907              
908              
909             *_clump_int = \&PDLA::_clump_int;
910              
911              
912              
913              
914              
915             =head2 xchg
916              
917             =for sig
918              
919             Signature: (P(); C(); int n1; int n2)
920              
921             =for ref
922              
923             exchange two dimensions
924              
925             Negative dimension indices count from the end.
926              
927             The command
928              
929             =for example
930              
931             $y = $x->xchg(2,3);
932              
933             creates C<$y> to be like C<$x> except that the dimensions 2 and 3
934             are exchanged with each other i.e.
935              
936             $y->at(5,3,2,8) == $x->at(5,3,8,2)
937              
938              
939              
940             =for bad
941              
942             xchg does not process bad values.
943             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
944              
945              
946             =cut
947              
948              
949              
950              
951              
952              
953             *xchg = \&PDLA::xchg;
954              
955              
956              
957              
958             =head2 reorder
959              
960             =for ref
961              
962             Re-orders the dimensions of a PDLA based on the supplied list.
963              
964             Similar to the L method, this method re-orders the dimensions
965             of a PDLA. While the L method swaps the position of two dimensions,
966             the reorder method can change the positions of many dimensions at
967             once.
968              
969             =for usage
970              
971             # Completely reverse the dimension order of a 6-Dim array.
972             $reOrderedPDLA = $pdl->reorder(5,4,3,2,1,0);
973              
974             The argument to reorder is an array representing where the current dimensions
975             should go in the new array. In the above usage, the argument to reorder
976             C<(5,4,3,2,1,0)>
977             indicates that the old dimensions (C<$pdl>'s dims) should be re-arranged to make the
978             new pdl (C<$reOrderPDLA>) according to the following:
979              
980             Old Position New Position
981             ------------ ------------
982             5 0
983             4 1
984             3 2
985             2 3
986             1 4
987             0 5
988              
989             You do not need to specify all dimensions, only a complete set
990             starting at position 0. (Extra dimensions are left where they are).
991             This means, for example, that you can reorder() the X and Y dimensions of
992             an image, and not care whether it is an RGB image with a third dimension running
993             across color plane.
994              
995             =for example
996              
997             Example:
998              
999             pdla> $x = sequence(5,3,2); # Create a 3-d Array
1000             pdla> p $x
1001             [
1002             [
1003             [ 0 1 2 3 4]
1004             [ 5 6 7 8 9]
1005             [10 11 12 13 14]
1006             ]
1007             [
1008             [15 16 17 18 19]
1009             [20 21 22 23 24]
1010             [25 26 27 28 29]
1011             ]
1012             ]
1013             pdla> p $x->reorder(2,1,0); # Reverse the order of the 3-D PDLA
1014             [
1015             [
1016             [ 0 15]
1017             [ 5 20]
1018             [10 25]
1019             ]
1020             [
1021             [ 1 16]
1022             [ 6 21]
1023             [11 26]
1024             ]
1025             [
1026             [ 2 17]
1027             [ 7 22]
1028             [12 27]
1029             ]
1030             [
1031             [ 3 18]
1032             [ 8 23]
1033             [13 28]
1034             ]
1035             [
1036             [ 4 19]
1037             [ 9 24]
1038             [14 29]
1039             ]
1040             ]
1041              
1042             The above is a simple example that could be duplicated by calling
1043             C<$x-Exchg(0,2)>, but it demonstrates the basic functionality of reorder.
1044              
1045             As this is an index function, any modifications to the
1046             result PDLA will change the parent.
1047              
1048             =cut
1049              
1050             sub PDLA::reorder {
1051 4     4 0 27 my ($pdl,@newDimOrder) = @_;
1052              
1053 4         11 my $arrayMax = $#newDimOrder;
1054              
1055             #Error Checking:
1056 4 50       24 if( $pdl->getndims < scalar(@newDimOrder) ){
1057 0         0 my $errString = "PDLA::reorder: Number of elements (".scalar(@newDimOrder).") in newDimOrder array exceeds\n";
1058 0         0 $errString .= "the number of dims in the supplied PDLA (".$pdl->getndims.")";
1059 0         0 barf($errString);
1060             }
1061              
1062             # Check to make sure all the dims are within bounds
1063 4         30 for my $i(0..$#newDimOrder) {
1064 12         25 my $dim = $newDimOrder[$i];
1065 12 50 33     66 if($dim < 0 || $dim > $#newDimOrder) {
1066 0         0 my $errString = "PDLA::reorder: Dim index $newDimOrder[$i] out of range in position $i\n(range is 0-$#newDimOrder)";
1067 0         0 barf($errString);
1068             }
1069             }
1070              
1071             # Checking that they are all present and also not duplicated is done by thread() [I think]
1072              
1073             # a quicker way to do the reorder
1074 4         23 return $pdl->thread(@newDimOrder)->unthread(0);
1075             }
1076              
1077              
1078              
1079              
1080              
1081             =head2 mv
1082              
1083             =for sig
1084              
1085             Signature: (P(); C(); int n1; int n2)
1086              
1087             =for ref
1088              
1089             move a dimension to another position
1090              
1091             The command
1092              
1093             =for example
1094              
1095             $y = $x->mv(4,1);
1096              
1097             creates C<$y> to be like C<$x> except that the dimension 4 is moved to the
1098             place 1, so:
1099              
1100             $y->at(1,2,3,4,5,6) == $x->at(1,5,2,3,4,6);
1101              
1102             The other dimensions are moved accordingly.
1103             Negative dimension indices count from the end.
1104              
1105              
1106             =for bad
1107              
1108             mv does not process bad values.
1109             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1110              
1111              
1112             =cut
1113              
1114              
1115              
1116              
1117              
1118              
1119             *mv = \&PDLA::mv;
1120              
1121              
1122              
1123              
1124              
1125             =head2 oslice
1126              
1127             =for sig
1128              
1129             Signature: (P(); C(); char* str)
1130              
1131             =for ref
1132              
1133             DEPRECATED: 'oslice' is the original 'slice' routine in pre-2.006_006
1134             versions of PDLA. It is left here for reference but will disappear in
1135             PDLA 3.000
1136              
1137             Extract a rectangular slice of a piddle, from a string specifier.
1138              
1139             C was the original Swiss-army-knife PDLA indexing routine, but is
1140             largely superseded by the L source prefilter
1141             and its associated L method. It is still used as the
1142             basic underlying slicing engine for L,
1143             and is especially useful in particular niche applications.
1144              
1145             =for example
1146              
1147             $x->slice('1:3'); # return the second to fourth elements of $x
1148             $x->slice('3:1'); # reverse the above
1149             $x->slice('-2:1'); # return last-but-one to second elements of $x
1150              
1151             The argument string is a comma-separated list of what to do
1152             for each dimension. The current formats include
1153             the following, where I, I and I are integers and can
1154             take legal array index values (including -1 etc):
1155              
1156             =over 8
1157              
1158             =item :
1159              
1160             takes the whole dimension intact.
1161              
1162             =item ''
1163              
1164             (nothing) is a synonym for ":"
1165             (This means that C<$x-Eslice(':,3')> is equal to C<$x-Eslice(',3')>).
1166              
1167             =item a
1168              
1169             slices only this value out of the corresponding dimension.
1170              
1171             =item (a)
1172              
1173             means the same as "a" by itself except that the resulting
1174             dimension of length one is deleted (so if C<$x> has dims C<(3,4,5)> then
1175             C<$x-Eslice(':,(2),:')> has dimensions C<(3,5)> whereas
1176             C<$x-Eslice(':,2,:')> has dimensions C<(3,1,5))>.
1177              
1178             =item a:b
1179              
1180             slices the range I to I inclusive out of the dimension.
1181              
1182             =item a:b:c
1183              
1184             slices the range I to I, with step I (i.e. C<3:7:2> gives the indices
1185             C<(3,5,7)>). This may be confusing to Matlab users but several other
1186             packages already use this syntax.
1187              
1188              
1189             =item '*'
1190              
1191             inserts an extra dimension of width 1 and
1192              
1193             =item '*a'
1194              
1195             inserts an extra (dummy) dimension of width I.
1196              
1197             =back
1198              
1199             An extension is planned for a later stage allowing
1200             C<$x-Eslice('(=1),(=1|5:8),3:6(=1),4:6')>
1201             to express a multidimensional diagonal of C<$x>.
1202              
1203             Trivial out-of-bounds slicing is allowed: if you slice a source
1204             dimension that doesn't exist, but only index the 0th element, then
1205             C treats the source as if there were a dummy dimension there.
1206             The following are all equivalent:
1207              
1208             xvals(5)->dummy(1,1)->slice('(2),0') # Add dummy dim, then slice
1209             xvals(5)->slice('(2),0') # Out-of-bounds slice adds dim.
1210             xvals(5)->slice((2),0) # NiceSlice syntax
1211             xvals(5)->((2))->dummy(0,1) # NiceSlice syntax
1212              
1213             This is an error:
1214              
1215             xvals(5)->slice('(2),1') # nontrivial out-of-bounds slice dies
1216              
1217             Because slicing doesn't directly manipulate the source and destination
1218             pdl -- it just sets up a transformation between them -- indexing errors
1219             often aren't reported until later. This is either a bug or a feature,
1220             depending on whether you prefer error-reporting clarity or speed of execution.
1221              
1222              
1223              
1224             =for bad
1225              
1226             oslice does not process bad values.
1227             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1228              
1229              
1230             =cut
1231              
1232              
1233              
1234              
1235              
1236              
1237             *oslice = \&PDLA::oslice;
1238              
1239              
1240              
1241              
1242             =head2 using
1243              
1244             =for ref
1245              
1246             Returns array of column numbers requested
1247              
1248             =for usage
1249              
1250             line $pdl->using(1,2);
1251              
1252             Plot, as a line, column 1 of C<$pdl> vs. column 2
1253              
1254             =for example
1255              
1256             pdla> $pdl = rcols("file");
1257             pdla> line $pdl->using(1,2);
1258              
1259             =cut
1260              
1261             *using = \&PDLA::using;
1262             sub PDLA::using {
1263 0     0 0 0 my ($x,@ind)=@_;
1264 0 0 0     0 @ind = list $ind[0] if (blessed($ind[0]) && $ind[0]->isa('PDLA'));
1265 0         0 foreach (@ind) {
1266 0         0 $_ = $x->slice("($_)");
1267             }
1268 0         0 @ind;
1269             }
1270              
1271              
1272              
1273              
1274              
1275             *affine = \&PDLA::affine;
1276              
1277              
1278              
1279              
1280              
1281             =head2 diagonalI
1282              
1283             =for sig
1284              
1285             Signature: (P(); C(); SV *list)
1286              
1287             =for ref
1288              
1289             Returns the multidimensional diagonal over the specified dimensions.
1290              
1291             The diagonal is placed at the first (by number) dimension that is
1292             diagonalized.
1293             The other diagonalized dimensions are removed. So if C<$x> has dimensions
1294             C<(5,3,5,4,6,5)> then after
1295              
1296             =for example
1297              
1298             $y = $x->diagonal(0,2,5);
1299              
1300             the piddle C<$y> has dimensions C<(5,3,4,6)> and
1301             C<$y-Eat(2,1,0,1)> refers
1302             to C<$x-Eat(2,1,2,0,1,2)>.
1303              
1304             NOTE: diagonal doesn't handle threadids correctly. XXX FIX
1305              
1306              
1307             =for bad
1308              
1309             diagonalI does not process bad values.
1310             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1311              
1312              
1313             =cut
1314              
1315              
1316              
1317              
1318              
1319              
1320             *diagonalI = \&PDLA::diagonalI;
1321              
1322              
1323              
1324              
1325              
1326             =head2 lags
1327              
1328             =for sig
1329              
1330             Signature: (P(); C(); int nthdim; int step; int n)
1331              
1332             =for ref
1333              
1334             Returns a piddle of lags to parent.
1335              
1336             Usage:
1337              
1338             =for usage
1339              
1340             $lags = $x->lags($nthdim,$step,$nlags);
1341              
1342             I.e. if C<$x> contains
1343              
1344             [0,1,2,3,4,5,6,7]
1345              
1346             then
1347              
1348             =for example
1349              
1350             $y = $x->lags(0,2,2);
1351              
1352             is a (5,2) matrix
1353              
1354             [2,3,4,5,6,7]
1355             [0,1,2,3,4,5]
1356              
1357             This order of returned indices is kept because the function is
1358             called "lags" i.e. the nth lag is n steps behind the original.
1359              
1360             C<$step> and C<$nlags> must be positive. C<$nthdim> can be
1361             negative and will then be counted from the last dim backwards
1362             in the usual way (-1 = last dim).
1363              
1364              
1365             =for bad
1366              
1367             lags does not process bad values.
1368             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1369              
1370              
1371             =cut
1372              
1373              
1374              
1375              
1376              
1377              
1378             *lags = \&PDLA::lags;
1379              
1380              
1381              
1382              
1383              
1384             =head2 splitdim
1385              
1386             =for sig
1387              
1388             Signature: (P(); C(); int nthdim; int nsp)
1389              
1390             =for ref
1391              
1392             Splits a dimension in the parent piddle (opposite of L)
1393              
1394             After
1395              
1396             =for example
1397              
1398             $y = $x->splitdim(2,3);
1399              
1400             the expression
1401              
1402             $y->at(6,4,m,n,3,6) == $x->at(6,4,m+3*n)
1403              
1404             is always true (C has to be less than 3).
1405              
1406              
1407             =for bad
1408              
1409             splitdim does not process bad values.
1410             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1411              
1412              
1413             =cut
1414              
1415              
1416              
1417              
1418              
1419              
1420             *splitdim = \&PDLA::splitdim;
1421              
1422              
1423              
1424              
1425              
1426             =head2 rotate
1427              
1428             =for sig
1429              
1430             Signature: (x(n); indx shift(); [oca]y(n))
1431              
1432             =for ref
1433              
1434             Shift vector elements along with wrap. Flows data back&forth.
1435              
1436              
1437             =for bad
1438              
1439             rotate does not process bad values.
1440             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1441              
1442              
1443             =cut
1444              
1445              
1446              
1447              
1448              
1449              
1450             *rotate = \&PDLA::rotate;
1451              
1452              
1453              
1454              
1455              
1456             =head2 threadI
1457              
1458             =for sig
1459              
1460             Signature: (P(); C(); int id; SV *list)
1461              
1462             =for ref
1463              
1464             internal
1465              
1466             Put some dimensions to a threadid.
1467              
1468             =for example
1469              
1470             $y = $x->threadI(0,1,5); # thread over dims 1,5 in id 1
1471              
1472              
1473              
1474             =for bad
1475              
1476             threadI does not process bad values.
1477             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1478              
1479              
1480             =cut
1481              
1482              
1483              
1484              
1485              
1486              
1487             *threadI = \&PDLA::threadI;
1488              
1489              
1490              
1491              
1492              
1493             =head2 identvaff
1494              
1495             =for sig
1496              
1497             Signature: (P(); C())
1498              
1499             =for ref
1500              
1501             A vaffine identity transformation (includes thread_id copying).
1502              
1503             Mainly for internal use.
1504              
1505              
1506             =for bad
1507              
1508             identvaff does not process bad values.
1509             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1510              
1511              
1512             =cut
1513              
1514              
1515              
1516              
1517              
1518              
1519             *identvaff = \&PDLA::identvaff;
1520              
1521              
1522              
1523              
1524              
1525             =head2 unthread
1526              
1527             =for sig
1528              
1529             Signature: (P(); C(); int atind)
1530              
1531             =for ref
1532              
1533             All threaded dimensions are made real again.
1534              
1535             See [TBD Doc] for details and examples.
1536              
1537              
1538             =for bad
1539              
1540             unthread does not process bad values.
1541             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1542              
1543              
1544             =cut
1545              
1546              
1547              
1548              
1549              
1550              
1551             *unthread = \&PDLA::unthread;
1552              
1553              
1554              
1555              
1556             =head2 dice
1557              
1558             =for ref
1559              
1560             Dice rows/columns/planes out of a PDLA using indexes for
1561             each dimension.
1562              
1563             This function can be used to extract irregular subsets
1564             along many dimension of a PDLA, e.g. only certain rows in an image,
1565             or planes in a cube. This can of course be done with
1566             the usual dimension tricks but this saves having to
1567             figure it out each time!
1568              
1569             This method is similar in functionality to the L
1570             method, but L requires that contiguous ranges or ranges
1571             with constant offset be extracted. ( i.e. L requires
1572             ranges of the form C<1,2,3,4,5> or C<2,4,6,8,10>). Because of this
1573             restriction, L is more memory efficient and slightly faster
1574             than dice
1575              
1576             =for usage
1577              
1578             $slice = $data->dice([0,2,6],[2,1,6]); # Dicing a 2-D array
1579              
1580             The arguments to dice are arrays (or 1D PDLAs) for each dimension
1581             in the PDLA. These arrays are used as indexes to which rows/columns/cubes,etc
1582             to dice-out (or extract) from the C<$data> PDLA.
1583              
1584             Use C to select all indices along a given dimension (compare also
1585             L). As usual (in slicing methods) trailing
1586             dimensions can be omitted implying C'es for those.
1587              
1588             =for example
1589              
1590             pdla> $x = sequence(10,4)
1591             pdla> p $x
1592             [
1593             [ 0 1 2 3 4 5 6 7 8 9]
1594             [10 11 12 13 14 15 16 17 18 19]
1595             [20 21 22 23 24 25 26 27 28 29]
1596             [30 31 32 33 34 35 36 37 38 39]
1597             ]
1598             pdla> p $x->dice([1,2],[0,3]) # Select columns 1,2 and rows 0,3
1599             [
1600             [ 1 2]
1601             [31 32]
1602             ]
1603             pdla> p $x->dice(X,[0,3])
1604             [
1605             [ 0 1 2 3 4 5 6 7 8 9]
1606             [30 31 32 33 34 35 36 37 38 39]
1607             ]
1608             pdla> p $x->dice([0,2,5])
1609             [
1610             [ 0 2 5]
1611             [10 12 15]
1612             [20 22 25]
1613             [30 32 35]
1614             ]
1615              
1616             As this is an index function, any modifications to the
1617             slice change the parent (use the C<.=> operator).
1618              
1619             =cut
1620              
1621             sub PDLA::dice {
1622              
1623 28     28 0 57 my $self = shift;
1624 28         63 my @dim_indexes = @_; # array of dimension indexes
1625              
1626             # Check that the number of dim indexes <=
1627             # number of dimensions in the PDLA
1628 28         53 my $no_indexes = scalar(@dim_indexes);
1629 28         96 my $noDims = $self->getndims;
1630 28 50       69 barf("PDLA::dice: Number of index arrays ($no_indexes) not equal to the dimensions of the PDLA ($noDims")
1631             if $no_indexes > $noDims;
1632 28         47 my $index;
1633             my $pdlIndex;
1634 28         41 my $outputPDLA=$self;
1635 28         41 my $indexNo = 0;
1636              
1637             # Go thru each index array and dice the input PDLA:
1638 28         64 foreach $index(@dim_indexes){
1639 32 100 66     131 $outputPDLA = $outputPDLA->dice_axis($indexNo,$index)
1640             unless !ref $index && $index eq 'X';
1641              
1642 32         188 $indexNo++;
1643             }
1644              
1645 28         215 return $outputPDLA;
1646             }
1647             *dice = \&PDLA::dice;
1648              
1649              
1650             =head2 dice_axis
1651              
1652             =for ref
1653              
1654             Dice rows/columns/planes from a single PDLA axis (dimension)
1655             using index along a specified axis
1656              
1657             This function can be used to extract irregular subsets
1658             along any dimension, e.g. only certain rows in an image,
1659             or planes in a cube. This can of course be done with
1660             the usual dimension tricks but this saves having to
1661             figure it out each time!
1662              
1663             =for usage
1664              
1665             $slice = $data->dice_axis($axis,$index);
1666              
1667             =for example
1668              
1669             pdla> $x = sequence(10,4)
1670             pdla> $idx = pdl(1,2)
1671             pdla> p $x->dice_axis(0,$idx) # Select columns
1672             [
1673             [ 1 2]
1674             [11 12]
1675             [21 22]
1676             [31 32]
1677             ]
1678             pdla> $t = $x->dice_axis(1,$idx) # Select rows
1679             pdla> $t.=0
1680             pdla> p $x
1681             [
1682             [ 0 1 2 3 4 5 6 7 8 9]
1683             [ 0 0 0 0 0 0 0 0 0 0]
1684             [ 0 0 0 0 0 0 0 0 0 0]
1685             [30 31 32 33 34 35 36 37 38 39]
1686             ]
1687              
1688             The trick to using this is that the index selects
1689             elements along the dimensions specified, so if you
1690             have a 2D image C will select certain C values
1691             - i.e. extract columns
1692              
1693             As this is an index function, any modifications to the
1694             slice change the parent.
1695              
1696             =cut
1697              
1698             sub PDLA::dice_axis {
1699 30     30 0 66 my($self,$axis,$idx) = @_;
1700              
1701             # Convert to PDLAs: array refs using new, otherwise use topdl:
1702 30 100       183 my $ix = (ref($idx) eq 'ARRAY') ? ref($self)->new($idx) : ref($self)->topdl($idx);
1703 30         119 my $n = $self->getndims;
1704 30         70 my $x = $ix->getndims;
1705 30 50       66 barf("index_axis: index must be <=1D") if $x>1;
1706 30         404 return $self->mv($axis,0)->index1d($ix)->mv(0,$axis);
1707             }
1708             *dice_axis = \&PDLA::dice_axis;
1709              
1710              
1711              
1712              
1713              
1714             =head2 slice
1715              
1716             =for usage
1717              
1718             $slice = $data->slice([2,3],'x',[2,2,0],"-1:1:-1", "*3");
1719              
1720             =for ref
1721              
1722             Extract rectangular slices of a piddle, from a string specifier,
1723             an array ref specifier, or a combination.
1724              
1725             C is the main method for extracting regions of PDLAs and
1726             manipulating their dimensionality. You can call it directly or
1727             via he L source prefilter that extends
1728             Perl syntax o include array slicing.
1729              
1730             C can extract regions along each dimension of a source PDLA,
1731             subsample or reverse those regions, dice each dimension by selecting a
1732             list of locations along it, or basic PDLA indexing routine. The
1733             selected subfield remains connected to the original PDLA via dataflow.
1734             In most cases this neither allocates more memory nor slows down
1735             subsequent operations on either of the two connected PDLAs.
1736              
1737             You pass in a list of arguments. Each term in the list controls
1738             the disposition of one axis of the source PDLA and/or returned PDLA.
1739             Each term can be a string-format cut specifier, a list ref that
1740             gives the same information without recourse to string manipulation,
1741             or a PDLA with up to 1 dimension giving indices along that axis that
1742             should be selected.
1743              
1744             If you want to pass in a single string specifier for the entire
1745             operation, you can pass in a comma-delimited list as the first
1746             argument. C detects this condition and splits the string
1747             into a regular argument list. This calling style is fully
1748             backwards compatible with C calls from before PDLA 2.006.
1749              
1750             B
1751              
1752             If a particular argument to C is a string, it is parsed as a
1753             selection, an affine slice, or a dummy dimension depending on the
1754             form. Leading or trailing whitespace in any part of each specifier is
1755             ignored (though it is not ignored within numbers).
1756              
1757             =over 3
1758              
1759             =item C<< '' >>, C<< : >>, or C<< X >> -- keep
1760              
1761             The empty string, C<:>, or C cause the entire corresponding
1762             dimension to be kept unchanged.
1763              
1764              
1765             =item C<< >> -- selection
1766              
1767             A single number alone causes a single index to be selected from the
1768             corresponding dimension. The dimension is kept (and reduced to size
1769             1) in the output.
1770              
1771             =item C<< () >> -- selection and collapse
1772              
1773             A single number in parenthesis causes a single index to be selected
1774             from the corresponding dimension. The dimension is discarded
1775             (completely eliminated) in the output.
1776              
1777             =item C<< : >> -- select an inclusive range
1778              
1779             Two numbers separated by a colon selects a range of values from the
1780             corresponding axis, e.g. C<< 3:4 >> selects elements 3 and 4 along the
1781             corresponding axis, and reduces that axis to size 2 in the output.
1782             Both numbers are regularized so that you can address the last element
1783             of the axis with an index of C< -1 >. If, after regularization, the
1784             two numbers are the same, then exactly one element gets selected (just
1785             like the C<< >> case). If, after regulariation, the second number
1786             is lower than the first, then the resulting slice counts down rather
1787             than up -- e.g. C<-1:0> will return the entire axis, in reversed
1788             order.
1789              
1790             =item C<< :: >> -- select a range with explicit step
1791              
1792             If you include a third parameter, it is the stride of the extracted
1793             range. For example, C<< 0:-1:2 >> will sample every other element
1794             across the complete dimension. Specifying a stride of 1 prevents
1795             autoreversal -- so to ensure that your slice is *always* forward
1796             you can specify, e.g., C<< 2:$n:1 >>. In that case, an "impossible"
1797             slice gets an Empty PDLA (with 0 elements along the corresponding
1798             dimension), so you can generate an Empty PDLA with a slice of the
1799             form C<< 2:1:1 >>.
1800              
1801             =item C<< * >> -- insert a dummy dimension
1802              
1803             Dummy dimensions aren't present in the original source and are
1804             "mocked up" to match dimensional slots, by repeating the data
1805             in the original PDLA some number of times. An asterisk followed
1806             by a number produces a dummy dimension in the output, for
1807             example C<< *2 >> will generate a dimension of size 2 at
1808             the corresponding location in the output dim list. Omitting
1809             the numeber (and using just an asterisk) inserts a dummy dimension
1810             of size 1.
1811              
1812             =back
1813              
1814             B
1815              
1816             If you feed in an ARRAY ref as a slice term, then it can have
1817             0-3 elements. The first element is the start of the slice along
1818             the corresponding dim; the second is the end; and the third is
1819             the stepsize. Different combinations of inputs give the same
1820             flexibility as the string syntax.
1821              
1822             =over 3
1823              
1824             =item C<< [] >> - keep dim intact
1825              
1826             An empty ARRAY ref keeps the entire corresponding dim
1827              
1828             =item C<< [ 'X' ] >> - keep dim intact
1829              
1830             =item C<< [ '*',$n ] >> - generate a dummy dim of size $n
1831              
1832             If $n is missing, you get a dummy dim of size 1.
1833              
1834             =item C<< [ $dex, , 0 ] >> - collapse and discard dim
1835              
1836             C<$dex> must be a single value. It is used to index
1837             the source, and the corresponding dimension is discarded.
1838              
1839             =item C<< [ $start, $end ] >> - collect inclusive slice
1840              
1841             In the simple two-number case, you get a slice that runs
1842             up or down (as appropriate) to connect $start and $end.
1843              
1844             =item C<< [ $start, $end, $inc ] >> - collect inclusive slice
1845              
1846             The three-number case works exactly like the three-number
1847             string case above.
1848              
1849             =back
1850              
1851             B
1852              
1853             If you pass in a 0- or 1-D PDLA as a slicing argument, the
1854             corresponding dimension is "diced" -- you get one position
1855             along the corresponding dim, per element of the indexing PDLA,
1856             e.g. C<< $x->slice( pdl(3,4,9)) >> gives you elements 3, 4, and
1857             9 along the 0 dim of C<< $x >>.
1858              
1859             Because dicing is not an affine transformation, it is slower than
1860             direct slicing even though the syntax is convenient.
1861              
1862              
1863             =for example
1864              
1865             $x->slice('1:3'); # return the second to fourth elements of $x
1866             $x->slice('3:1'); # reverse the above
1867             $x->slice('-2:1'); # return last-but-one to second elements of $x
1868              
1869             $x->slice([1,3]); # Same as above three calls, but using array ref syntax
1870             $x->slice([3,1]);
1871             $x->slice([-2,1]);
1872              
1873             =cut
1874              
1875              
1876             ##############################
1877             # 'slice' is now implemented as a small Perl wrapper around
1878             # a PP call. This permits unification of the former slice,
1879             # dice, and nslice into a single call. At the moment, dicing
1880             # is implemented a bit kludgily (it is detected in the Perl
1881             # front-end), but it is serviceable.
1882             # --CED 12-Sep-2013
1883              
1884             *slice = \&PDLA::slice;
1885             sub PDLA::slice (;@) {
1886 903     903 0 56943 my ($source, @others) = @_;
1887              
1888             # Deal with dicing. This is lame and slow compared to the
1889             # faster slicing, but works okay. We loop over each argument,
1890             # and if it's a PDLA we dispatch it in the most straightforward
1891             # way. Single-element and zero-element PDLAs are trivial and get
1892             # converted into slices for faster handling later.
1893              
1894 903         2468 for my $i(0..$#others) {
1895 1080 100 66     3676 if( blessed($others[$i]) && $others[$i]->isa('PDLA') ) {
1896 5         13 my $idx = $others[$i];
1897 5 50       32 if($idx->ndims > 1) {
1898 0         0 barf("slice: dicing parameters must be at most 1D (arg $i)\n");
1899             }
1900 5         23 my $nlm = $idx->nelem;
1901              
1902 5 100       21 if($nlm > 1) {
    100          
1903              
1904             #### More than one element - we have to dice (darn it).
1905 3         8 my $n = $source->getndims;
1906 3         54 $source = $source->mv($i,0)->index1d($idx)->mv(0,$i);
1907 3         25 $others[$i] = '';
1908              
1909             }
1910             elsif($nlm) {
1911              
1912             #### One element - convert to a regular slice.
1913 1         8 $others[$i] = $idx->flat->at(0);
1914              
1915             }
1916             else {
1917            
1918             #### Zero elements -- force an extended empty.
1919 1         13 $others[$i] = "1:0:1";
1920             }
1921             }
1922             }
1923              
1924 903         12486 PDLA::sliceb($source,\@others);
1925             }
1926              
1927              
1928              
1929              
1930              
1931             =head2 sliceb
1932              
1933             =for sig
1934              
1935             Signature: (P(); C(); SV *args)
1936              
1937              
1938             =for ref
1939              
1940             info not available
1941              
1942              
1943             =for bad
1944              
1945             sliceb does not process bad values.
1946             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
1947              
1948              
1949             =cut
1950              
1951              
1952              
1953              
1954              
1955              
1956             *sliceb = \&PDLA::sliceb;
1957              
1958              
1959              
1960             ;
1961              
1962              
1963             =head1 BUGS
1964              
1965             For the moment, you can't slice one of the zero-length dims of an
1966             empty piddle. It is not clear how to implement this in a way that makes
1967             sense.
1968              
1969             Many types of index errors are reported far from the indexing
1970             operation that caused them. This is caused by the underlying architecture:
1971             slice() sets up a mapping between variables, but that mapping isn't
1972             tested for correctness until it is used (potentially much later).
1973              
1974             =head1 AUTHOR
1975              
1976             Copyright (C) 1997 Tuomas J. Lukka. Contributions by
1977             Craig DeForest, deforest@boulder.swri.edu.
1978             Documentation contributions by David Mertens.
1979             All rights reserved. There is no warranty. You are allowed
1980             to redistribute this software / documentation under certain
1981             conditions. For details, see the file COPYING in the PDLA
1982             distribution. If this file is separated from the PDLA distribution,
1983             the copyright notice should be included in the file.
1984              
1985             =cut
1986              
1987              
1988              
1989              
1990              
1991             # Exit with OK status
1992              
1993             1;
1994              
1995