File Coverage

blib/lib/PDL/Dims.pm
Criterion Covered Total %
statement 6 6 100.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 8 8 100.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package PDL::Dims;
4              
5              
6             =head1 NAME
7              
8             PDL::Dims - Enhancement to PDL by using named dimensions.
9              
10             If PDL is about arrays, PDL::Dims turns them into hashes
11              
12             =head1 VERSION
13              
14             Version 0.01
15              
16             =cut
17              
18             our $VERSION = '0.010';
19              
20 1     1   15211 use strict;
  1         2  
  1         32  
21              
22              
23 1     1   433 use parent 'Exporter','PDL';
  1         239  
  1         4  
24             #use base 'PDL';
25             #@PDL::Dims::ISA=qw/PDL Exporter/;
26             use Scalar::Util qw/looks_like_number/;
27             use PDL::NiceSlice;
28             use Storable qw(dclone);
29             use PDL;
30             #use PDL::Lite;
31             #use PDL::Ufunc qw(min max);
32             #use PDL::Core qw(approx sclr);
33             #no PDL::IO::Pic;
34             use 5.012;
35             our @EXPORT=qw(diminfo dnumeric vals spacing is_sane i2pos pos2i initdim idx didx dimsize dimname sln rmdim nagg dinc dmin dmax nreduce nop ncop copy_dim active_slice nsqueeze);
36              
37              
38             my @keys = qw(pos size num spacing unit min max inc vals index dummy);
39              
40             sub _fix_old { # This fixes data stored from version <=0.002
41             my $self=shift;
42             for my $d (@{dimname($self)}) {
43             for my $p (keys %{$self->hdr->{$d}}) {
44             if ((my $n=$p) =~s/^dim//) {
45             #say "$p -> $n ", $self->hdr->{$d}->{$p};
46             $self->hdr->{$d}->{$n}=$self->hdr->{$d}->{$p};
47             #say "$p -> $n ", $self->hdr->{$d}->{$n};
48             delete $self->hdr->{$d}->{$p};
49             #say "$p -> $n ", $self->hdr->{$d}->{$n};
50             }
51             }
52             dnumeric($self,$d,1) unless ($d eq 'channel');
53             dimsize($self,$d,$self->dim(didx($self,$d)));
54             #say "$d size: ",dimsize($self,$d),' ',dmin($self,$d),' min; max: ',dmax($self,$d);
55             #say "spacing ",spacing($self,$d);
56             spacing($self,$d,1) if ($d eq qw/x y z t/);
57             if ($d eq 'channel') {
58             #say "Channel";
59             #say dimsize($self,$d);
60             spacing($self,$d,0);
61             dnumeric($self,$d,0);
62             }
63             if ($d eq 'channel' and dimsize($self,$d)==1) {
64             vals($self,$d,['combined',]);
65             #say "channel: ",@{vals($self,$d)};
66             }
67             if (!dimsize($self,$d)) {
68             #say "$d has size 1!";
69             dmax($self,$d,dmin($self,$d));
70             dinc($self,$d,0);
71             }
72             if (spacing($self,$d) and $d ne 't') {
73             dinc($self,$d,(dmax($self,$d)-dmin($self,$d))/((dimsize($self,$d)-1)||1)) ;
74             }
75             if ($d eq 't') {
76             #say "t: inc ",dinc($self,$d);
77             dmax($self,$d,dmin($self,$d)+(dimsize($self,$d)-1)*dinc($self,$d));
78             }
79             #say "$d size: ",dimsize($self,$d),' ',dmin($self,$d),' min; inc: ',dinc($self,$d),' inc - max ',dmax($self,$d);
80             }
81             }
82             # returns a list of all dims for one parameter -- intended as an auxillary for internal use only
83              
84             sub _dimpar {
85             my $self=shift;
86             my $p=shift; # par
87             #say "All of ".%{$self->hdr}.", $p";
88             return unless $p;
89             my @s;
90             for my $i (@{dimname($self)}) {
91             #say "name $i $p";
92             #next unless chomp $i;
93             #say "name $i: ",$self->hdr->{$i}->{$p};
94             barf ("Unknown dim $i") unless (ref ($self->hdr->{$i}) eq 'HASH');
95             push @s,$self->hdr->{$i}->{$p};
96             }
97             #say "Dims ".@{dimname($self)}."Par $p: @s";
98             return @s;
99             }
100              
101             sub dnumeric {
102             my $self=shift;
103             my $d=shift;
104             my $v=shift;
105             return [_dimpar($self,'num')] if (!$d and wantarray);
106             return [_dimpar($self,'num')] unless ($d);
107             return undef unless (ref ($self->hdr->{$d}) eq 'HASH');
108             #warn "numeric? $d $v.", $self->hdr->{num} ;#if ($d eq 'a' and $v==1);
109             #barf "numeric? $d $v!", $self->hdr->{num} if ($d eq 'a' and $v==1);
110             if (defined $v) {
111             #warn "numeric value? $d $v.", $self->hdr->{num} ;#if ($d eq 'a' and $v==1);
112             $self->hdr->{$d}->{num}=$v;
113             }
114             if ($self->hdr->{$d}->{num}) {
115             #warn "numeric: $d $v" if ($v and $d eq 'a');
116             #barf "Channel is not numeric ! " if ($d eq 'channel');
117             # for (vals($self,$d)) {looks_like_number $_ || barf "$d has non-numeric values";}
118             }
119             return $self->hdr->{$d}->{num};
120             }
121              
122             sub spacing {
123             my $self=shift;
124             my $d=shift; # dimname
125             my $v=shift; # value
126             return [_dimpar($self,'spacing')] if (!$d and wantarray);
127             return [_dimpar($self,'spacing')] unless ($d) ;
128             return undef unless (ref ($self->hdr->{$d}) eq 'HASH');
129             if (defined $v) {
130             int $v;
131             $self->hdr->{$d}->{spacing}=$v;
132             }
133             return $self->hdr->{$d}->{spacing}; #, $r{$d};
134             }
135              
136             sub diminfo {
137             my $self=shift;
138             my $str;
139             for my $n (dimname ($self)) {
140             $str.="$n\[".didx($self,$n)."]=>".dimsize($self,$n).", ";
141             }
142             $str.=$self->info;
143             return $str;
144             }
145             sub is_sane {
146             my $self=shift;
147             return "piddle" unless $self->isa('PDL');
148             return "name" unless dimname($self);
149             return "ndims" unless ($self->ndims==1+$#{dimname($self)});
150             #say "global done.";
151             for my $n (@{dimname($self)}) {
152             next unless (chomp $n);
153             # say "Checking dim $n for $self->hdr->{self}";
154             next unless (chomp $n);
155             return "size ".$n unless ($self->dim(didx($self,$n))==dimsize($self,$n));
156             return "index " .$n unless (idx($self,$n)
157             return "index " .$n unless (idx($self,$n)>=0);
158             # say "size and index";
159             if (spacing($self,$n)) {
160             # say "inc";
161             return "inc ".$n unless dinc($self,$n);
162             # say dmax($self,$n), dmin($self,$n)+dinc($self,$n)*(dimsize($self,$n)-1);
163             # say "minmax $n";
164             return "minmax ".$n unless (approx(dmax($self,$n)),
165             dmin($self,$n)+dinc($self,$n)*(dimsize($self,$n)-1));
166             # say "pos: $n";
167             # say (dmax($self,$n),i2pos($self,$n,pos2i($self,$n,dmax($self,$n))));
168             # say "Index: ",(pos2i($self,$n,dmax($self,$n)));
169             # say "Numeric: $n" unless (dnumeric( $self,$n));
170             return "pos ".$n unless (approx(dmax($self,$n),i2pos($self,$n,pos2i($self,$n,dmax($self,$n)))));
171             } else {
172             # say "vals $n";
173             return "vals ".$n unless (dimsize($self,$n)==$#{vals($self,$n)}+1);
174             # say "val_pos $n";
175             # say "Numeric: $n" unless (eval {dnumeric( $self,$n)});
176             #say i2pos($self,$n,dimsize($self,$n)-1);
177             #say pos2i($self,$n,i2pos($self,$n,dimsize($self,$n)-1))," 1";
178             #say (dimsize($self,$n) , 1+
179             #pos2i($self,$n,i2pos($self,$n,dimsize($self,$n)-1)));
180             return "pos ".$n unless (dimsize($self,$n)-1 == @{
181             pos2i($self,$n,i2pos($self,$n,dimsize($self,$n)-1))}-[-1]);
182             }
183             }
184             return 0;
185             }
186             sub dimsize { # sets size for a dim
187             my $self=shift;
188             my $d=shift; # dimname
189             my $v=shift; # value
190             #say "return all ", _dimpar($self,'size') if (!$d and wantarray);
191             return _dimpar($self,'size') if (!$d and wantarray);
192             return #([values %{$self->hdr->{dimsize}}]
193             # ,[keys %{$self->hdr->{dimsize}}],
194             #)
195             [_dimpar($self,'size')]
196             unless ($d) ;
197             #barf ("Unknown dim $d") unless (ref ($self->hdr->{$d}) eq 'HASH');
198             return undef unless (ref ($self->hdr->{$d}) eq 'HASH');
199             #say "size $d $v",$self->info;
200             if (defined $v) {
201             return undef unless (ref ($self->hdr->{$d}) eq 'HASH');
202             int $v;
203             $self->hdr->{$d}->{size}=$v;
204             idx($self,$d,$v-1) if (idx($self,$d)>=$v-1);
205             }
206             return $self->hdr->{$d}->{size}; #, $r{$d};
207             }# get/set name of a dim by number
208              
209             sub dimname {
210             my $self=shift;
211             my $d=shift; # dim number
212             my $n=shift; # new name
213             barf "Not a piddle!" unless $self->isa('PDL');
214             #say keys %{$self->hdr} unless defined $d;
215             return @{$self->hdr->{dimnames}} if (! defined ($d) and wantarray);
216             return $self->hdr->{dimnames} unless defined $d;
217             #barf "Unknown dim $d" unless (ref $self->hdr->{dimnames} eq 'HASH');
218             $self->hdr->{dimnames}->[$d]=$n if $n;
219             return $self->hdr->{dimnames}->[$d];
220             }
221              
222             sub dinc {
223             my $self=shift;
224             my $d=shift; # dimname
225             my $v=shift; # max
226             return _dimpar($self,'inc') if (!$d and wantarray);
227             return [_dimpar($self,'inc')] unless $d;
228             if (defined $v) {
229             #say "dinc: $d $v";
230             return undef unless (ref $self->hdr->{$d} eq 'HASH');
231             $self->hdr->{$d}->{inc}=$v;
232             spacing ($self,$d,1);
233             dnumeric ($self,$d,1);
234             $self->hdr->{$d}->{vals}=undef; #
235             }
236             return $self->hdr->{$d}->{inc}; #, $r{$d};
237             }
238              
239             sub dmax {
240             my $self=shift;
241             my $d=shift; # dimname
242             my $v=shift; # max
243             return _dimpar($self,'max') if (!$d and wantarray);
244             return [_dimpar($self,'max')] unless $d;
245             #say "$d ".$self->hdr;
246             return undef if (defined $v and ref $self->hdr->{$d} ne 'HASH');
247             $self->hdr->{$d}->{max}=$v if defined ($v);
248             return $self->hdr->{$d}->{max}; #, $r{$d};
249             }
250              
251             sub dmin {
252             my $self=shift;
253             my $d=shift; # dimname
254             my $v=shift; # min
255             return _dimpar($self,'min') if (!$d and wantarray);
256             return [_dimpar($self,'min')] unless $d;
257             return undef if (defined $v and ref $self->hdr->{$d} ne 'HASH');
258             #barf "Unknown dim $d" unless (ref $self->hdr->{$d} eq 'HASH');
259             $self->hdr->{$d}->{min}=$v if defined ($v);
260             return $self->hdr->{$d}->{min}; #, $r{$d};
261             }
262              
263              
264             sub didx { # set/get index - complementary to dimname
265             my $self=shift;
266             my $d=shift; # dimname
267             return _dimpar($self,'pos') if (!$d and wantarray);
268             return [_dimpar($self,'pos')] unless $d;
269             if (ref $d eq 'ARRAY') {
270             @$d;
271             } else {
272             my $n=shift; # new position
273             return if (ref $self->hdr->{$d} ne 'HASH');
274             barf "Unknown dim $d" unless (ref $self->hdr->{$d} eq 'HASH');
275             $self->hdr->{$d}->{pos}=$n if defined $n;
276             #say "type $self idx $d ".$self->hdr->{$d}->{pos};
277             return $self->hdr->{$d}->{pos};
278             }
279             }
280              
281             sub initdim {
282             my $self=shift;
283             my $d=shift || return ; # name
284             #say "Init dim $d ...";
285             $self->hdr; #ensure the header is intialised.
286             my %p=@_;
287             for my $k (keys %p) {
288             barf "Unkown parameter $k $p{$k}" unless ($k ~~ @keys);
289             }
290             #say "header: ",(keys %{$self->gethdr},);
291             if (ref $self->hdr->{$d} eq 'HASH'){ # dimname exists and is a hash
292             my $n= didx($self,$d);
293             if (defined $n) {
294             $p{pos}=$n; #just to make sure
295             barf "$d exists at pos $n! (".%{$self->hdr->{$d}}."\n";
296             } else {
297             #say (keys (%{$self->hdr->{$d}}),'-keys');
298             warn "$d is defined but not a dim! ",%{$self->hdr->{$d}};
299             }
300             } else {
301             $self->hdr->{ndims}=0 unless ($self->hdr->{ndims});
302             #say keys $self->hdr->{$d};
303             #say "pars: ",%p;
304             $self->hdr->{$d}=\%p;
305             #say "Creating dim $d at pos. $p{pos}; Ndims ".$self->hdr->{ndims};
306             if ((!defined $p{pos}) or ($p{pos}>$self->hdr->{ndims})) {
307             $p{pos}=$self->hdr->{ndims};
308             }
309             if ($p{pos}<$self->hdr->{ndims}) {
310             for (my $i=$self->hdr->{ndims}-1;$i>=$p{pos};$i--) {
311             #say dimname($self,$i)," initdim at pos $p{pos} ndims: ",$self->hdr->{ndims}, " $i";
312             dimname($self,$i+1,dimname($self,$i-0)); # shift the position up!
313             didx($self,dimname($self,$i),$i+1);
314             }
315             }
316             didx ($self,$d,$p{pos});
317             $self->hdr->{$d}=\%p;
318             dimname ($self,$p{pos},$d);
319             }
320             $p{size}=$self->dim($p{pos}) unless ($p{size});
321             warn "Size ($p{size}) does not mnatch piddle dim at pos $p{pos} ",$self->dim($p{pos})
322             unless ($p{size}==$self->dim($p{pos}));
323             dimsize ($self,$d,($p{size}||1));
324             spacing($self,$d,1) unless defined spacing($self,$d);
325             #say "P: ",%p;
326             #say "Dim $d: ",ref $p{vals},"; ",%p;
327             #say "Dim $d: ",@{$p{vals}} if (ref $p{vals}); #,"; ",@{$p{vals}};
328             #say "Set values $d",ref($p{vals});
329             if (ref ($p{vals}) eq 'ARRAY') {# or (dimsize($self,$d) == 1 and defined $p{val})) {# and !spacing($self,$d)) {
330             #say "Set values $d";
331             my @v=@{$p{vals}};
332             #say "Values: @v";
333             #barf "Wrong size of values list! $d " unless ($#{$p{vals}}==dimsize($self,$d)-1);
334             vals ($self,$d,$p{vals});
335             #warn "numeric $d" ,dnumeric($self,$d);#,($p{num}||1));
336             #dmin($self,$d,vals($self,$d,0));
337             #dmax($self,$d,vals($self,$d,dimsize($self,$d)));
338             }
339             unless (spacing($self,$d)){
340             #barf "$d !";
341             } else {
342             #say "equal spaced, numeric values $d";
343             $p{num}=1 unless defined $p{num};
344             if ($p{inc} and $p{max}) {
345             barf ("Increment and maximum don't fit! ($d min $p{min} max $p{max} inc $p{inc} "
346             .dimsize($self,$d))
347             unless (approx(pdl ($p{max}-$p{min}) , pdl((dimsize($self,$d)-1)*$p{inc} )));
348             } elsif ($p{inc}) {
349             $p{max}=$p{inc}*dimsize($self,$d)+$p{min};
350             } elsif ($p{max}) {
351             $p{inc}=($p{max}-$p{min})/((dimsize($self,$d)-1)||1);
352             } else {
353             $p{max}=dimsize($self,$d)-1;
354             $p{inc}=1;
355             }
356             dmin ($self,$d,$p{min}||0);
357             dinc ($self,$d,$p{inc});
358             dmax ($self,$d,$p{max}); #||(dimsize($self,$d)-1)*$p{inc};
359             spacing($self,$d,1);
360             dnumeric($self,$d,);
361             }
362             $self->hdr->{ndims}++;
363             #say "initdim: ndims ",$self->hdr->{ndims} , diminfo $self;
364             idx($self,$d,($p{index}||0));#dmin($self,$d)));
365             my $res=$self;
366             if ($p{dummy} ) { # insert dummy dimension of size size at pos.
367             say "dummy: $p{pos} $p{size}";
368             $res=$res->dummy($p{pos},$p{size});
369             }
370             $res->sethdr($self->hdr_copy);
371             #say diminfo ($res);
372             return $res;
373             #say "Done. ($d)";
374             }
375              
376             sub copy_dim {
377             my $old=shift;
378             my $new=shift;
379             my $dim=shift;
380             return unless $dim;
381            
382             #initdim($new,'dummy');
383             #say "old: $old; new: $new; dim: $dim";
384             my $d=dclone($old->hdr->{$dim});
385             #say "old $old new $new dim %$d";
386             #say "Copy to new: ",@{dimname $new};
387             #say %$d;
388             $$d{pos}=shift;
389             initdim($new,$dim,%$d);
390             }
391              
392             sub rmdim {
393             my $self=shift;
394             my $d=shift;
395             return unless defined $d;
396             #say "removing $d ".didx($self,$d);;
397             my $idx=didx($self,$d);
398             #say @{$self->hdr->{dimnames}},didx($self,$d); # cut out the array
399             splice @{$self->hdr->{dimnames}},$idx,1; # cut out the array
400             #say @{$self->hdr->{dimnames}},didx($self,$d); # cut out the array
401             for my $i ($idx..$self->hdr->{ndims}-1) {
402             didx($self,dimname($self,$i),$i); #update position of following dims
403             }
404             delete $self->hdr->{$d};
405             barf "This should be undefined! ",$self->hdr->{$d} if defined ($self->hdr->{$d});
406             #barf "This should be undefined! ",$self->hdr->{dimnamesd} if defined ($self->hdr->{$d});
407             $self->hdr->{ndims}--;
408             #say "rmdim: ",diminfo $self;
409             }
410              
411             sub unit {
412             #my $self=shift;
413             my $self=shift;
414             die "I don't have data to work on (unit)" unless defined $self->hdr;
415             #say "$self type array ";
416             my $index=shift;
417             return _dimpar($self,'unit') if (! defined ($index) and wantarray);
418             return [_dimpar($self,'unit')] unless defined $index;
419             #barf ("Unknown dim $index")
420             return undef unless (ref ($self->hdr->{$index}) eq 'HASH');
421             if (defined (my $v=shift)) {
422             $self->hdr->{$index}->{unit}=$v ;
423             }
424             return $self->hdr->{$index}->{unit};
425             }
426              
427             sub idx {
428             #my $self=shift;
429             my $self=shift;
430             barf "I don't have data to work on (idx)" unless defined $self->hdr;
431             #say "$self type array ";
432             my $index=shift;
433             return _dimpar($self,'index') if (! defined ($index) and wantarray);
434             return [_dimpar($self,'index')] unless defined $index;
435            
436             return undef unless (ref ($self->hdr->{$index}) eq 'HASH');
437             if (defined (my $v=shift)) {
438             $v<0? 0: $v;
439             $v>=dimsize($self,$index)? dimsize($self,$index)-1 : $v;
440             $self->hdr->{$index}->{index}=int $v ;
441             }
442             return $self->hdr->{$index}->{index};
443             }
444              
445             sub vals { #individual values of dims -- like the position along an axis in world coords., echo times
446             my $self=shift;
447             my $d=shift; #dim
448             return unless $d;
449             $self->hdr->{$d}->{vals}=[] unless defined $self->hdr->{$d}->{vals};
450             #say "Vals: $d ",@{$self->hdr->{$d}->{vals}};
451             my $i=shift; #index or array ref
452             if (defined $i) { # set the whole array or access individual points
453             #say "vals: $d $i";
454             if (ref $i eq 'ARRAY' and dimsize($self,$d) == $#{$i}+1) { #ref to values array
455             barf "Array size does not match dimsize" unless ($#$i==dimsize($self,$d)-1);
456             $self->hdr->{$d}->{vals}=$i ;
457             spacing ($self,$d,0); #->hdr->{$d}->{spacing}=0;
458             $self->hdr->{$d}->{inc}=undef;
459             for (vals($self,$d)) {looks_like_number $_ || dnumeric($self,$d,0);}
460              
461             if (dnumeric($self,$d)){
462             barf "not numeric @$i" if ($$i[0] eq 'a');
463             dmin($self,$d,min(pdl $i));
464             dmax($self,$d,max(pdl $i));
465             } else {
466             $self->hdr->{$d}->{max}=undef;
467             $self->hdr->{$d}->{min}=undef;
468             }
469             #say "$d: setting vals @$i";
470             } else { #individual values
471             my $v=shift; #value
472             if ( defined $v) {
473             $self->hdr->{$d}->{vals}->[$i]=$v ;
474             spacing ($self,$d,0); #->hdr->{$d}->{spacing}=0;
475             $self->hdr->{$d}->{inc}=undef;
476             for (vals($self,$d)) {looks_like_number $_ || dnumeric($self,$d,0);}
477             if (dnumeric($self,$d)){
478             #barf "not numeric $i" if ($i eq 'a');
479             dmin($self,$d,min(pdl $i));
480             dmax($self,$d,max(pdl $i));
481             } else {
482             $self->hdr->{$d}->{max}=undef;
483             $self->hdr->{$d}->{min}=undef;
484             }
485             }
486             if (spacing($self,$d)) {
487             return dmin($self,$d)+$i*dinc($self,$d);
488             }
489             return $self->hdr->{$d}->{vals}->[$i];
490             }
491             #} else {
492             }
493             if (spacing($self,$d)) {
494             return (list (dmin($self,$d)+dinc($self,$d)*sequence(dimsize($self,$d)))) if (wantarray);
495             return [list (dmin($self,$d)+dinc($self,$d)*sequence(dimsize($self,$d)))] unless wantarray;
496             }
497             if (wantarray) {
498             return @{$self->hdr->{$d}->{vals}};
499             } else {
500             return $self->hdr->{$d}->{vals};
501             }
502             }
503              
504              
505             #transformations between piddle and world coords.
506             sub i2pos{
507             my $self=shift; # dataset
508             my $d=shift || return; # dimname
509             my $i=shift ; #value
510             barf "Unknown dim $d" unless (ref $self->hdr->{$d} eq 'HASH');
511             $i=idx($self,$d) unless (defined $i);
512             if (spacing($self,$d)) {
513             return $i*dinc($self,$d)+dmin($self,$d);
514             } else {
515             return vals($self,$d,$i);
516             }
517             }
518              
519             sub pos2i{
520             my $self=shift;
521             (my $d=shift) || return;
522             my $i=shift ; # value
523             barf "Unknown dim $d" unless (ref $self->hdr->{$d} eq 'HASH');
524             if (spacing($self,$d)) {
525             return rint (($i-dmin($self,$d))/dinc($self,$d));
526             } else {
527             #say "searching for $i ",$self->hdr->{$d}->{num},".";
528             #say "Num? ",dnumeric($self,$d,undef);
529             my @a=vals($self,$d);
530             #say "Num? ",dnumeric($self,$d,undef);
531             #say "searching for $i ",$self->hdr->{$d}->{num},".";
532             my (@res)=grep { $a[$_] == $i } (0 .. $#a)if (dnumeric($self,$d));
533             my (@res)=grep { $a[$_] eq $i } (0 .. $#a)unless (dnumeric($self,$d));
534             #my (@res)=grep { chomp($a[$_]) eq chomp('c') } (0 .. $#a)unless (dnumeric($self,$d));
535              
536             #say "pos2i: returning @res";
537             if (wantarray) {
538             return @res ;
539             } else {
540             return $res[0];
541             }
542             }
543             }
544              
545             sub nsqueeze {
546             my $self=shift;
547             #my @except=@_;
548             #say $ret->info;
549             #ay $ret->info;
550             # my $d=shift;
551             my $ret;
552             # if (defined didx($slf,$d) {
553             # barf "size of $d is >1" if (dimsize($sslf,$d)-1);
554             # $ret=sln($ret,$d=>'(0)',);
555             # }
556             $ret=$self->squeeze;
557             $ret->sethdr($self->hdr_copy);
558             for my $i (@{dimname($self)}) {
559             #say "keeping $i ".dimsize($self,$i) unless (dimsize($self,$i)==1);
560             #say "Removing $i ".dimsize($self,$i) if (dimsize($self,$i)==1);
561             rmdim($ret,$i) if (dimsize($self,$i)==1);
562             }
563             #say "names: ",@{dimname($ret)};
564             #say "nsqueeze: return ",$ret->info, @{dimname($ret)};
565             return $ret;
566             }
567              
568             sub nagg { # aggregate function
569             #no PDL::NiceSlice;
570             my $self=shift;
571             barf "nagg: not a piddle!" unless $self->isa('PDL');
572             my $op=shift; #
573             my $d=shift; # dimension
574             #say "nagg: ",dimname($self);
575             return unless (defined didx($self,$d));
576             my $res=$self->mv(didx($self,$d),0);
577             #say $res->info;
578             if (eval {$res->can($op)}) {
579             $res=$res->$op(@_);
580             } else {
581             $res=&$op($res,@_);
582             }
583             barf "nagg: Result undefined for $op on $d." unless defined $res;
584             if (eval {$res->nelem} ) {
585             barf "not an aggregate function! $op", $self->info,$res->info if ($self->ndims==$res->ndims);
586             #if ($res->nelem==$self->nelem-1)
587             if ($res->ndims==$self->ndims-1)
588             {
589             $res->sethdr($self->hdr_copy);
590             # say "nagg: $d ",dimname($self);
591             rmdim ($res,$d);
592             # say "nagg: $d ",dimname($res);
593             }
594             }
595             #say "nagg: ",diminfo($res);
596             return ($res);
597             }
598             # boundaries of dims in appropriate units (mm, s, ..)
599              
600             sub active_slice :lvalue { #
601             my $self=shift;
602             my @except=@_;
603             my @idx=list (rint(pdl idx($self)));
604             #say "j ".idx($img{$type});
605             my @n=(dimname($self));
606             barf "active_slice: not consistent size $#n ",$self->ndims-1 unless ($#n==$self->ndims-1);
607             #say "self: @n";
608             my $str;
609             my @rm;
610             for my $i (0.. $#n) {
611             unless (/$n[$i]/ ~~ @except){
612             #say "Selecting $i $n[$i] $idx[$i]";
613             push @rm,$n[$i];
614             $str.="$idx[$i]";
615             }
616             $str.=',' unless ($i==$#n);
617             }
618             #say "$str ",$self->info;
619             my $ret=$self->slice($str); #->nsqueeze;
620             $ret+=0;
621             $ret->sethdr($self->hdr_copy);
622             #say $ret->info;
623             for my $i (0.. $#n) {
624             unless (/$n[$i]/ ~~ @except){
625             #say "$i $n[$i] ",idx($self,$n[$i]);
626             dimsize($ret,'channel',1);
627             #say "$i $n[$i] ",idx($self,$n[$i]);
628             dimsize($ret,$n[$i],1);
629             my $id=idx($ret,$n[$i]);
630             idx($ret,$n[$i],0);
631             vals($ret,$n[$i],0,vals($self,$n[$i],$id));
632             #dmin($ret,$n[$i],vals($self,$n[$i],$id));
633             #dmax($ret,$n[$i],vals($self,$n[$i],$id));
634             }
635             }
636             #say "active_slice: ",$self->info," return ",@{dimname($ret)},$ret->info;
637             $ret;
638             }
639              
640             sub nreduce { # analogue to PDL::Reduce, perform operation on named rather than numbered dims
641             my $self=shift;
642             my $op=shift; # operation - passed on to reduce
643             require PDL::Reduce;
644             my @list=@_;
645             my @d=map {didx($self,$_)} @list;
646             #say "reduce $op @d (@list)";
647             my $ret;
648             $ret= $self->reduce($op,@d);
649             $ret->sethdr($self->hdr_copy);
650             for my $d (@list) {
651             # say "removing $d";
652             rmdim ($ret,$d);
653             }
654             #say "nreduce: ",$ret->info, @{dimname($ret)};
655             return $ret;
656             }
657              
658             sub nop { # wrapper to functions like sin, exp, rotate operating on one named dimension
659             my $self=shift;
660             my $op=shift;
661             my $dim=shift;
662             my @a=@_;
663             my @n=@{dimname($self)};
664             #say "nop: (self) @n";
665             #say "nop: ",diminfo $self;
666             #my $arg=shift; # suitably shaped second argument
667             #say $self;
668             #say "dim $dim, pos ",didx($self,$dim)," ",%{$self->hdr->{$dim}};
669             $dim=dimname($self,0) unless defined $dim; # trivial
670             my $res=$self->mv(didx($self,$dim),0);
671             if ($op eq 'rotate'){
672             my $s=shift;
673             #say "schifing $res by $s";
674             $res=$res->rotate($s);
675             #say "schifing $res by $s";
676             } else {
677             #say "nop: ",diminfo $self,"op: $op, @a";
678             if (eval {$res->can($op)}) {
679             $res=$res->$op(@a,);
680             } else {
681             $res=&$op($res,@a);
682             }
683             }
684             $res=$res->mv(0,didx($self,$dim));
685             $res->sethdr($self->hdr_copy);
686             #say "self $self, op $res, mv ",$res->mv(0,didx($res,$dim));
687             #say "nop: return", $self->info,@{dimname($res)},$res->info;
688             return ($res);
689             }
690              
691             sub ncop { # named combine operation -- +*-/ ...
692             my $self=shift;
693             my $other=shift;
694             my $op=shift;
695             my $res;
696             #say "ncop: start self, other, ",$self->info, $other->info;
697             unless (eval {$self->isa('PDL')}) { # self is a scalar
698             $self=pdl($self);
699             if (eval {$self->can($op)}) {
700             $res=$self->$op($other,@_);
701             } else {
702             $res=&$op($self,$other,@_);
703             }
704             $res->sethdr($other->hdr_copy) if (eval {$other->isa('PDL')});# both are scalar
705             #say "ncop: other ",diminfo $other;
706             barf "ncop: $op changed dimensions. Use nagg or nreduce for aggregate functions"
707             unless ($other->nelem==$res->nelem);
708             #say "ncop: res ",diminfo $res;
709             return $res;
710             }
711             unless (eval {$other->isa('PDL')}) { # other is a scalar
712             if (eval {$self->can($op)}) {
713             $res=$self->$op($other,@_);
714             } else {
715             $res=&$op($self,$other,@_);
716             }
717             barf "ncop: $op changed dimensions. Use nagg or nreduce for aggregate functions"
718             unless ($self->nelem==$res->nelem);
719             $res->sethdr($self->hdr_copy);
720             return $res;
721             }
722             #say $self->info, $other->info;
723             my @d=@{dimname($self)};
724             my @e=@{dimname($other)};
725             #say "self @d other @e";
726             my $m=0;
727             my @nother=(); # new order in other
728             my @nself=(); # new order in self
729             my @tself=(); # thread dims
730             my @tother=();
731             my @aself;
732             my @aother;
733             my @add;
734             my @co=();
735             my $i=0;
736             my $j=0;
737             #say "keys self",keys %{$self->hdr};
738             #say "keys other",keys %{$other->hdr};
739             for my $ds (@d) {
740             my $n=didx($self,$ds);
741             #push @aself,$ds;
742             if (defined ($m=didx($other,$ds))) {
743             push @nself,$n;
744             push @nother,$m;
745            
746             # say "$ds $m $n";
747             # say "self $ds $m $n i $i";
748             push @co,$i+0;
749             #say "co sn @co";
750             $i++;
751             } else {
752             push @tself,$n;
753             # say "$ds $m $n i: $i ", ($other->ndims+$i);
754             push @co,($other->ndims+$j);
755             #say "co st @co";
756             $j++;
757             }
758             }
759             for my $ds (@e) {
760             #push @other,$ds;
761             my $n=didx($other,$ds);
762             if (defined ($m=didx($self,$ds))) {
763             1;
764             } else {
765             push @tother,$n;
766             push @add,$ds;
767             push @co,$i+0;
768             #say "co ot @co";
769             #say "other $ds $m $n";
770             $i++;
771             }
772             }
773             #say "Co: @co";
774             push @aother,@nother if defined ($nother[0]);
775             push @aother,@tother if defined ($tother[0]);
776             push @aself,@nself if defined ($nself[0]);
777             push @aself,@tself if defined ($tself[0]);
778             my $ns=$self->reorder(@aself);
779             my $no=$other->reorder(@aother);
780             #say "keys self",keys %{$self->hdr};
781             #say "keys other",keys %{$other->hdr};
782             for my $n (0..$#tother) { # fill in dummy dims
783             $ns=$ns->dummy($#nself+1,1);
784             }
785             #say "ncop: @aother @aself ",$ns->info,$no->info;
786             #say $self->info,$other->info;
787             #### perform the operation
788             if (eval {$ns->can($op)}) {
789             #unshift @_,0 if ($op eq "atan2" and $_[0] != 0);
790             $res=$ns->$op($no,@_);
791             } else{
792             #unshift @_,0 if ($op eq "atan2");# and $_[0] != 0);
793             $res=&$op($ns,$no,@_) ;
794             } #else {
795             # barf "This operation $op is neither a known method or function";
796             #say "ncop: ",$ns->info,$res->info;
797             #barf "ncop: $op changed dimensions. Use nagg or nreduce for aggregate functions"
798             #unless ($ns->nelem==$res->nelem);
799             $res=$res->reorder(@co);
800             #say "keys res:",keys %{$res->hdr};
801             #say %{$res->gethdr},"header.";
802             $res->sethdr($self->hdr_copy);
803             #say "keys self: ",%{$self->hdr};
804             #say "keys other: ",%{$other->hdr};
805             #say "keys res: ",%{$res->hdr};
806             #say "self: ",$self->hdr->{ndims};
807             #say "other ",$other->hdr->{ndims};
808             #say "res ",$res->hdr->{ndims};
809             #say "self: ",@{dimname($self)};
810             #say "other: ",@{dimname($other)};
811             #say "res: ",@{dimname($res)};
812             #$other->hdr;
813             my $i=$self->ndims;
814             for my $ds (0..$#add) {
815             #say "copy $add[$ds]",keys %{$res->hdr};
816             #initdim($res,$add[$ds]);
817             copy_dim($other,$res,$add[$ds],$i);
818             # say @{dimname($res)};
819             $i++;
820             }
821             $res->hdr->{ndims}=$i;
822             #say @{dimname($res)};
823             #say "Co @co";
824             #say "ncop: returning ... ".$res->info;
825             my $err=is_sane($res);
826             #barf "ncop: sanity check failed $err";
827             #say "ncop ",diminfo($res);
828             return $res;
829             }
830              
831             sub sln :lvalue { # returns a slice by dimnames and patterns
832             my $self=shift;
833             my %s=@_; # x=>'0:54:-2', t=>47, ... #
834             my $str;
835             #say "sln: args @_, ".$self->hdr->{dimnames},%s;
836             #say ("dimnames @{$self->dimname}");
837             my @n=@{$s{names}||dimname($self)};
838             #say "dims @n";
839             for my $i (0.. $#n) {
840             # say "$i $n[$i] $s{$n[$i]}";
841             $str.=$s{$n[$i]} if defined ($s{$n[$i]});
842             $str.=',' unless ($i==$#n);
843             }
844             #say "sln: slice string $str";
845             my $ret=$self->slice($str);
846             #say $ret->info;
847             $ret->sethdr($self->hdr_copy);
848             for my $d (@n) {
849             $str=$s{$d};
850             #say "$d $str";
851             next unless defined $str;
852             chomp $str;
853             if ($str =~/\(\s*\d+\s*\)/) { # e.g. (0) - reduce
854             rmdim ($ret,$d);
855             next;
856             }
857             $str=~m/([+-]?\d+)(:([+-]?\d+)(:([+-]?\d+))?)?/;
858             # say "$d: 1 $1 2 $2 3 $3 4 $4 5 $5";
859             my $step=int ($5)||1;
860             my $size=int abs((($3||$1)-$1)/$step)+1; #
861             my $min=int min pdl($1,$3);
862             my $max=int max pdl($1,$3);
863             #say "min $min max $max size $size str $str vals ";
864             dimsize($ret,$d,$size);
865             if (spacing ($self,$d)) {
866             dinc($ret,$d,$step*dinc($self,$d));
867             dmin($ret,$d,dmin($self,$d)+$step*dinc($self,$d)*($min % dimsize($self,$d)));
868             dmax($ret,$d,dmin($ret,$d)+$step*dinc($self,$d)*(dimsize($ret,$d)-1));
869             #dmax($ret,$d,vals($self,$d,$max % dimsize($self,$d)));
870             idx($ret,$d,sclr (pdl(idx($self,$d))->clip(0,dimsize($ret,$d)-1)));
871             say "sln: idx ($d):",idx($ret,$d);
872             } else {
873             #say "min $min max $max size $size str $str vals ";
874             #say "vals $d: ",vals($self,$d);
875            
876             if (dnumeric($self,$d)) {
877             my $v=pdl([vals($self,$d),])->($str) ;
878             vals($ret,$d,[vals($self,$d,[list $v])]);
879             idx($ret,$d,sclr (pdl(idx($self,$d))->clip(dmin($ret,$d),dmax($ret,$d))));
880             } else {
881             my $v=sequence(dimsize($self,$d))->($str);
882             my @values;
883             #say "vals: $d size $size str $str" ,$v->info;
884             for my $ix (0.. $v->nelem-1) {
885             #say "$ix $v ",$v($ix);
886             push @values,vals($self,$d,sclr ($v($ix)));
887             #say "$ix $v ",$v($ix);
888             }
889             vals($ret,$d,[@values]);
890             idx($ret,$d,0);
891             #say "sln, vals ($d): ", vals($ret,$d);
892             }
893             #vals($res,$d,list ();
894              
895             if (dnumeric($self,$d)) {
896             #dmin($ret,$d,min($v));
897             #dmax($ret,$d,min($v));
898             }
899             }
900             #dimsize($ret, $n,
901             }
902             #say "sln: return ",diminfo($ret);
903             $ret;
904              
905             }
906              
907             1;
908             #BEGIN {
909             # if ($_[0] eq q/-d/) {
910             # require Carp;
911             # $SIG{__DIE__} = sub {print Carp::longmess(@_); die;};
912             # }
913             #}
914              
915              
916             =head1 SYNOPSIS
917              
918             If PDL is about arrays, PDL::Dims makes them into hashes.
919              
920             What it provides is a framework for addressing data not by numbered indices in
921             numbered dimensions but by meaningful names and values.
922              
923             In PDL::Dims the user does not need to know the internal structure, i.e. order of
924             dimensions. It renders calls to functions like mv, reshape, reorder, ... unnecessary.
925              
926             use PDL::Dims;
927            
928             my $data= .... # some way to load data
929             print $data->Info;
930             # PDL: Double D [256,256,20,8,30]
931             # Now name the first dim x, running from -12 to 12 cm
932             initdim ($data, 'x',unit=>'cm',dmin=>-12,dmax=>12);
933             initdim ($data,'y',pos=>1,size=>256, # these are not necessary but you can set them explicitely
934             dmin=>-12, dinc=>0.078125, unit=>'cm' # min -12 max 8
935             initdim ($data,'n',vals=[@list]); # 20 objects with names in @list
936             initdim ($data,'t',spacing=>0,unit=>'s', vals=>[10,15,25,40,90,120,240,480); # sampled at different time points
937             initdim ($data,'z',min=>30,max=>28,unit=>'mm'); yet another way
938              
939             # x,y,z are equally spaced numeric, n is non-numeric, t is numeric but at arbitrary distances
940             ...
941              
942             # load or define $mask with dims x,y,z equal to that of data
943             $i=ncop($data,$mask,'mult',0); # multiply mask onto data.
944             # Since mask has only x,y,z, the dims of $data are unchanged.
945             # x,y,z, in $mask or $data must be either 1 or equal.
946            
947             # Calculate the average over my region of interest:
948             $sum=nreduce($i,'avg','x','y','z');
949            
950             ...
951              
952             Now you want to associate your images with other data recorded at each time point:
953             # $data2: PDL [8, 100] (t,pars)
954             $more_complex=ncop($data,$data2,'plus',0);
955             #This will produce a piddle of size [256,256,20,8,30,100]
956            
957             # if you want to average over every second object between n = 6 - 12:
958             $avg=nagg(sln($data,n=>'6:12:2'),'average','n');
959              
960              
961              
962             =head1 DESCRIPTION
963              
964             This module is an extension to PDL by giving the dimensions a meaningful name,
965             values or ranges. The module also provides wrappers to perform most PDL
966             operations based on named dimensions. Each dimension is supposed to have a unique name.
967              
968             If you prefer methods over functions, say
969              
970             bless $piddle, "PDL::Dims";
971              
972             Names of dims can be any string (x,y,z,t,city, country, lattitude, fruit,pet, ...)
973              
974             Each dim has its own hash with several important keys;
975              
976             =cut #my @keys = qw(pos size num spacing min max inc vals index dummy);
977              
978             =over
979              
980             =item * pos - dimension index 0..ndims-1
981              
982             =item * dimnames - a string by which the dim is accessed
983              
984             =item * index - current position within a dim. PDL::Dims knows the concept of a current position within a piddle
985              
986             =item * dummy - if true, initdim creates a dim of size at pos
987              
988             =item * num - dimension has numeric properties; if false, no min/max/inc are calculated. E.g. a dim pet may have values for dog, cat, fish, rabbit, mouse, parrot, min/max don't make sense in this case.
989              
990             =item * spacing - if true, values are evenly spaced; inc is undef if false
991              
992             =item * vals - list all values along a dim, if not evenly spaced each value is stored. Can cause memory issues in very large dims
993              
994             =item * min/max - minimum and maximum of numeric dimensions
995              
996             =item * inc - step between two indices in equally spaced dimensions
997              
998             =item * unit - the unit of vals.
999              
1000             =back
1001              
1002              
1003             =head1 SUBROUTINES/METHODS
1004              
1005              
1006              
1007             The module has two different types of functions.
1008              
1009             First, there are several utitility functions to manipulate and retrieve the dimension info.
1010             Currently, they only work on the metadata, no operations on the piddle are performed.
1011             It is your responsibility to call the appropriate function whenever piddle dims change.
1012              
1013             Then there are functions to perform most PDL operations based on named dimensions instead
1014             of numbered dims. Wrappers to slice (sln), reduce (nreduce) and other functions
1015             (nop, ncop) are implemented.
1016              
1017             The following parameters are currently used by PDL::Dims. It is *strongly* discouraged
1018             to access them directly except during calls to initdim. Use the functions listed below
1019             to manipulate and retrieve values.
1020              
1021             They are usually called like that:
1022              
1023             func ($piddle , [$dim, [value]]);
1024              
1025             if no dim is given, an array reference to all values are returned.
1026              
1027             Otherwise, it returns the given value for a particular $dim, setting it to $value if defined.
1028              
1029              
1030             =head2 diminfo
1031              
1032              
1033             $infostr = diminfo($piddle);
1034            
1035             An extended version of PDLs info, showing dimnames and sizes (from header).
1036              
1037             =head2 dimsize
1038              
1039             dimsize($piddle,[$dim,[$size]]);
1040              
1041             set/get dimension size of piddle by name.
1042              
1043             =head2 dimname
1044              
1045             dimname($piddle,[$position,[$name]]);
1046              
1047             set/get dimension size of piddle by name.
1048              
1049             =head2 idx
1050            
1051             idx($piddle,[$name,[$current]])
1052              
1053             set/get current index values by name
1054              
1055             =head2 didx
1056              
1057             didx($piddle,[$name,[$pos]]);
1058              
1059             get/set position of dims by their names
1060              
1061             =head2 i2pos
1062              
1063             =head2 pos2i
1064              
1065             i2pso($piddle,$dim,[$index]);
1066             pso2i($piddle,$dim,$value);
1067              
1068             Converts value from/to index. So you can say, for example, if you have a piddle counting stuff in different houses,
1069              
1070             sln($house,pets=>pos2i($house,pets,'dog'),rooms=>pos2i(housee,rooms,'kitchen'));
1071              
1072             something more realistic: Imagine you have two images of the same object but with different scaling and resolution or orientation. You want to extract what's between y = 10 and 20 cm of both images
1073              
1074             ya10=pos2i($a,'y',10);
1075             ya20=pos2i($a,'y',20);
1076             $slice=sln($a,y=>"$ya10:$ya20");
1077              
1078             or if you want to resample something, the index $yb in $b corresponds to the index $ya in $a:
1079              
1080             $ya=pos2i($a,'y',i2pos($b,'y',$yb));
1081              
1082              
1083              
1084             =head2 dmin
1085              
1086             dmin($piddle,[$dim,[$min]]);
1087              
1088             get/set minimum value for a dimension
1089              
1090             =head2 dmax
1091              
1092             dmax($piddle,[$name,[$max]]);
1093              
1094             get/set maximum value for a dimension
1095              
1096             =head2 dinc
1097              
1098             dinc($piddle,[$name,[$increment]]);
1099              
1100             get/set maximum value for a dimension
1101              
1102             =head2 vals
1103              
1104             vals($piddle,$dim,[$index ,[$val]| $array_ref])
1105              
1106             get/set values of an axis. As a third argument you can either supply an index,
1107             then you can access that element or a reference to an array of size dimsize supplying
1108             values for that dim.
1109              
1110             Please take a look on i2pos, pos2i, spacing and dnumeric to better understand the behaviour.
1111              
1112              
1113             =head2 unit
1114            
1115             unit($piddle,[$dim,[$unit]]);
1116              
1117             get/set the unit parameter. In the future, each assignment or operation
1118             should be units-avare, e.g. converting autmatically from mm to km or feet,
1119             preventing you from adding apples to peas ...
1120              
1121             =head2 spacing
1122              
1123             spacing ($piddle,[$dim,[$spacing]]);
1124              
1125             if true, the spacing between indices is assumed to be equal.
1126              
1127             =head2 dnumeric
1128            
1129             dnumeric ($piddl,[$dim,[$bool]]);
1130              
1131             get/set the flag if the piddle dim has numeric or other units. This has influence
1132             on vals, dmin, dmax, dinc.
1133              
1134             =head2 initdim
1135              
1136             initializes a dimenson
1137              
1138             usage:
1139             initdim($piddle,$dimname,[%args]);
1140              
1141             Arguments are the fields listed above. This should be called repeatedly after piddle
1142             creation to match the structure.
1143              
1144             If pos is not provided, the next free position is used. If you call
1145              
1146             initidim ($piddle,$name)
1147              
1148             N times on an N-dimensional piddle, it will create N dimensions with sizes corresponding to the
1149             dim of the piddle.
1150              
1151             =head2 rmdim
1152              
1153             removes a dminenso
1154              
1155             rmdim($piddle,$dim);
1156              
1157              
1158              
1159             =head2 copy_dim
1160              
1161             copies the diminfo from one piddle to the next.
1162              
1163             copy_dim($a,$b,$dim,[$pos]);
1164              
1165             calls initdim on $b with parameters from $a. You can supply a new position.
1166              
1167             =head2 sln
1168              
1169             sln ($piddle,%slices);
1170              
1171             This replaces slice and it's derivatives.
1172              
1173             perform slicing based on names. Returns correct dimension info. Unspecified
1174             dims are returned fully. If you want to squeeze, use
1175             sln($piddle, $dim=>"($value)");
1176            
1177             or nsqueeze on the result, if you want all squeezed. Both will do the necessary rmdim calls for you,
1178              
1179              
1180             Example:
1181             $sl=sln($a,x=>'0:10:2',t=>'4:',);
1182              
1183             You can omit dims; it parses each key-value pair and constructs a slice string,
1184             so what typically works for slice, works here.
1185              
1186             =head2 nop
1187              
1188             This is the way to perform non-aggregate operations on one piddle which work only on one dim,
1189             like e.g. rotate.
1190              
1191             usage:
1192             $res=nop($a,$operation,[@args]);
1193              
1194              
1195             =head2 ncop
1196              
1197             This is the way to perform any operations involving two operands when using PDL::Dims.
1198              
1199             operates on two piddles, combining them by names. Equally named dimensions have
1200             to obey the usual threding rules. For opertators like '+' use the named version
1201             and an additional argument of 0.
1202              
1203             usage:
1204             $c=ncop($a,$b,$operation,[@args]);
1205              
1206             =head2 nagg
1207              
1208             Use to perform aggregate functions, that reduce the dim by 1.
1209              
1210             nagg($piddle,$operation,$dim,[@args]);
1211              
1212             Use this to perform sumover, average, ...
1213              
1214              
1215             =head2 nreduce
1216              
1217             a wrapper around reduce (requires PDL::Reduce) calling with names instead.
1218              
1219             nreduce($piddle,$operations,@dimnames);
1220              
1221             =head2 active_slice
1222              
1223             A conveniance function, similar to sln, but it returns a slice at the current position (index).
1224              
1225             useage
1226              
1227             $slice=active_slice($piddle,@ignore);
1228              
1229             returns the current selection (as accessed by idx) as a slice. Returns full dims on supplied dim list.
1230              
1231             Call nsqueeze afterwards if that is what you want.
1232              
1233             =head2 nsqueeze
1234              
1235             A wrapper to squeeze. It makes the appropriate header updates (i.e. calls to rmdim).
1236              
1237              
1238             =head2 is_sane
1239              
1240             A sanity check for piddles. This is your friend when working with PDL::Dims!
1241              
1242             $err=is_sane($piddle)
1243              
1244              
1245             returns 0 upon success, otherwise the first inconsisteny found is returned. This may
1246             change in future releases.
1247              
1248             =head1 AUTHOR
1249              
1250             Ingo Schmid
1251              
1252              
1253              
1254              
1255             =head1 LICENSE AND COPYRIGHT
1256              
1257             Copyright 2014 Ingo Schmid.
1258              
1259             This program is free software; you can redistribute it and/or modify it
1260             under the terms of the the Artistic License (2.0). You may obtain a
1261             copy of the full license at:
1262              
1263             L
1264              
1265             Any use, modification, and distribution of the Standard or Modified
1266             Versions is governed by this Artistic License. By using, modifying or
1267             distributing the Package, you accept this license. Do not use, modify,
1268             or distribute the Package, if you do not accept this license.
1269              
1270             If your Modified Version has been derived from a Modified Version made
1271             by someone other than you, you are nevertheless required to ensure that
1272             your Modified Version complies with the requirements of this license.
1273              
1274             This license does not grant you the right to use any trademark, service
1275             mark, tradename, or logo of the Copyright Holder.
1276              
1277             This license includes the non-exclusive, worldwide, free-of-charge
1278             patent license to make, have made, use, offer to sell, sell, import and
1279             otherwise transfer the Package with respect to any patent claims
1280             licensable by the Copyright Holder that are necessarily infringed by the
1281             Package. If you institute patent litigation (including a cross-claim or
1282             counterclaim) against any party alleging that the Package constitutes
1283             direct or contributory patent infringement, then this Artistic License
1284             to you shall terminate on the date that such litigation is filed.
1285              
1286             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
1287             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
1288             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
1289             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
1290             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
1291             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
1292             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
1293             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1294              
1295              
1296             =cut
1297              
1298             1; # End of PDL::Dims