File Coverage

blib/lib/PDL/Dims.pm
Criterion Covered Total %
statement 356 529 67.3
branch 144 324 44.4
condition 26 70 37.1
subroutine 28 34 82.3
pod 25 25 100.0
total 579 982 58.9


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