line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package PDL::NDBin; |
2
|
|
|
|
|
|
|
# ABSTRACT: Multidimensional binning & histogramming |
3
|
|
|
|
|
|
|
$PDL::NDBin::VERSION = '0.019'; |
4
|
3
|
|
|
3
|
|
855484
|
use strict; |
|
3
|
|
|
|
|
16
|
|
|
3
|
|
|
|
|
88
|
|
5
|
3
|
|
|
3
|
|
16
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
94
|
|
6
|
3
|
|
|
3
|
|
14
|
use Exporter; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
113
|
|
7
|
3
|
|
|
3
|
|
16
|
use List::Util qw( reduce ); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
191
|
|
8
|
3
|
|
|
3
|
|
1824
|
use List::MoreUtils qw( pairwise ); |
|
3
|
|
|
|
|
38622
|
|
|
3
|
|
|
|
|
28
|
|
9
|
3
|
|
|
3
|
|
4742
|
use Math::Round qw( nlowmult nhimult ); |
|
3
|
|
|
|
|
24234
|
|
|
3
|
|
|
|
|
184
|
|
10
|
3
|
|
|
3
|
|
21
|
use PDL::Lite; # do not import any functions into this namespace |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
20
|
|
11
|
3
|
|
|
3
|
|
1709
|
use PDL::NDBin::Iterator; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
95
|
|
12
|
3
|
|
|
3
|
|
1399
|
use PDL::NDBin::Actions_PP; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
46
|
|
13
|
3
|
|
|
3
|
|
1843
|
use PDL::NDBin::Utils_PP; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
22
|
|
14
|
3
|
|
|
3
|
|
1801
|
use Log::Any qw( $log ); |
|
3
|
|
|
|
|
25409
|
|
|
3
|
|
|
|
|
14
|
|
15
|
3
|
|
|
3
|
|
8559
|
use Data::Dumper; |
|
3
|
|
|
|
|
20688
|
|
|
3
|
|
|
|
|
195
|
|
16
|
3
|
|
|
3
|
|
1603
|
use UUID::Tiny qw( :std ); |
|
3
|
|
|
|
|
40478
|
|
|
3
|
|
|
|
|
574
|
|
17
|
3
|
|
|
3
|
|
38
|
use POSIX qw( ceil ); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
29
|
|
18
|
3
|
|
|
3
|
|
1171
|
use Params::Validate qw( validate validate_pos validate_with ARRAYREF CODEREF HASHREF SCALAR ); |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
220
|
|
19
|
3
|
|
|
3
|
|
20
|
use Carp; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
162
|
|
20
|
3
|
|
|
3
|
|
1465
|
use Class::Load qw( load_class ); |
|
3
|
|
|
|
|
36432
|
|
|
3
|
|
|
|
|
12943
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our @ISA = qw( Exporter ); |
24
|
|
|
|
|
|
|
our @EXPORT = qw( ); |
25
|
|
|
|
|
|
|
our @EXPORT_OK = qw( ndbinning ndbin ); |
26
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( all => [ qw( ndbinning ndbin ) ] ); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# the list of valid keys |
29
|
|
|
|
|
|
|
my %valid_key = map { $_ => 1 } qw( axes vars ); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my @axis_params = qw( max min n round step grid ); |
33
|
|
|
|
|
|
|
my ( %axis_params, %axis_flags ); |
34
|
|
|
|
|
|
|
@axis_params{@axis_params} = (1) x @axis_params; |
35
|
|
|
|
|
|
|
@axis_flags{@axis_params} = map { 1<<$_ } 0..@axis_params-1; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
my %axis_allowed = |
38
|
|
|
|
|
|
|
map { reduce( sub { $a | $b }, 0, @axis_flags{@$_} ) => 1 } |
39
|
|
|
|
|
|
|
[ ], |
40
|
|
|
|
|
|
|
[ qw( n ) ], |
41
|
|
|
|
|
|
|
[ qw( min ) ], |
42
|
|
|
|
|
|
|
[ qw( max ) ], |
43
|
|
|
|
|
|
|
[ qw( step ) ], |
44
|
|
|
|
|
|
|
[ qw( min step ) ], |
45
|
|
|
|
|
|
|
[ qw( max step ) ], |
46
|
|
|
|
|
|
|
[ qw( min n ) ], |
47
|
|
|
|
|
|
|
[ qw( max n ) ], |
48
|
|
|
|
|
|
|
[ qw( round n ) ], |
49
|
|
|
|
|
|
|
[ qw( round step ) ], |
50
|
|
|
|
|
|
|
[ qw( n step ) ], |
51
|
|
|
|
|
|
|
[ qw( n step round ) ], |
52
|
|
|
|
|
|
|
[ qw( min n step ) ], |
53
|
|
|
|
|
|
|
[ qw( max n step ) ], |
54
|
|
|
|
|
|
|
[ qw( min max n ) ], |
55
|
|
|
|
|
|
|
[ qw( min max step ) ], |
56
|
|
|
|
|
|
|
[ qw( grid ) ]; |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub add_axis |
59
|
|
|
|
|
|
|
{ |
60
|
272
|
|
|
272
|
1
|
6868
|
my $self = shift; |
61
|
272
|
|
|
|
|
5162
|
my %params = validate( @_, { |
62
|
|
|
|
|
|
|
max => 0, |
63
|
|
|
|
|
|
|
min => 0, |
64
|
|
|
|
|
|
|
n => 0, |
65
|
|
|
|
|
|
|
name => 1, |
66
|
|
|
|
|
|
|
pdl => 0, |
67
|
|
|
|
|
|
|
round => 0, |
68
|
|
|
|
|
|
|
step => 0, |
69
|
|
|
|
|
|
|
grid => 0, |
70
|
|
|
|
|
|
|
} ); |
71
|
269
|
|
|
|
|
1886
|
$log->tracef( 'adding axis with specs %s', \%params ); |
72
|
|
|
|
|
|
|
|
73
|
269
|
|
100
|
954
|
|
2488
|
my $pmask = reduce { $a | ($b||0) } 0, @axis_flags{ keys %params }; |
|
954
|
|
|
|
|
2388
|
|
74
|
|
|
|
|
|
|
croak( "inconsistent or incomplete parameters: ", keys %params ) |
75
|
269
|
50
|
|
|
|
1197
|
unless $axis_allowed{ $pmask }; |
76
|
|
|
|
|
|
|
|
77
|
269
|
|
|
|
|
490
|
push @{ $self->{axes} }, \%params; |
|
269
|
|
|
|
|
1105
|
|
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub add_var |
82
|
|
|
|
|
|
|
{ |
83
|
211
|
|
|
211
|
1
|
2231
|
my $self = shift; |
84
|
211
|
|
|
|
|
3373
|
my %params = validate( @_, { |
85
|
|
|
|
|
|
|
action => { type => CODEREF | HASHREF | SCALAR }, |
86
|
|
|
|
|
|
|
name => 1, |
87
|
|
|
|
|
|
|
pdl => 0, |
88
|
|
|
|
|
|
|
} ); |
89
|
211
|
|
|
|
|
1287
|
$log->tracef( 'adding variable with specs %s', \%params ); |
90
|
211
|
|
|
|
|
651
|
push @{ $self->{vars} }, \%params; |
|
211
|
|
|
|
|
633
|
|
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub new |
95
|
|
|
|
|
|
|
{ |
96
|
244
|
|
|
244
|
1
|
297097
|
my $class = shift; |
97
|
244
|
|
|
|
|
4398
|
my %params = validate( @_, { |
98
|
|
|
|
|
|
|
axes => { optional => 1, type => ARRAYREF }, |
99
|
|
|
|
|
|
|
vars => { optional => 1, type => ARRAYREF }, |
100
|
|
|
|
|
|
|
} ); |
101
|
244
|
50
|
|
|
|
1573
|
$log->debug( 'new: arguments = ' . Dumper \%params ) if $log->is_debug; |
102
|
244
|
|
|
|
|
2719
|
my $self = bless { axes => [], vars => [] }, $class; |
103
|
|
|
|
|
|
|
# axes |
104
|
244
|
|
100
|
|
|
844
|
$params{axes} ||= []; # be sure we can dereference |
105
|
244
|
|
|
|
|
349
|
my @axes = @{ $params{axes} }; |
|
244
|
|
|
|
|
512
|
|
106
|
244
|
|
|
|
|
489
|
for my $axis ( @axes ) { |
107
|
187
|
|
|
|
|
319
|
my @pat = ( 1 ); # one mandatory argument |
108
|
187
|
100
|
|
|
|
409
|
if( @$axis > 1 ) { push @pat, (0) x (@$axis - 1) } # followed by n-1 optional arguments |
|
177
|
|
|
|
|
444
|
|
109
|
187
|
|
|
|
|
1366
|
my( $name ) = validate_pos( @$axis, @pat ); |
110
|
186
|
|
|
|
|
502
|
shift @$axis; # remove name |
111
|
186
|
|
|
|
|
462
|
$self->add_axis( name => $name, @$axis ); |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
# vars |
114
|
240
|
|
100
|
|
|
811
|
$params{vars} ||= []; # be sure we can dereference |
115
|
240
|
|
|
|
|
322
|
my @vars = @{ $params{vars} }; |
|
240
|
|
|
|
|
483
|
|
116
|
240
|
|
|
|
|
416
|
for my $var ( @vars ) { |
117
|
108
|
|
|
|
|
644
|
my( $name, $action ) = validate_pos( @$var, 1, 1 ); |
118
|
108
|
|
|
|
|
324
|
$self->add_var( name => $name, action => $action ); |
119
|
|
|
|
|
|
|
} |
120
|
240
|
|
|
|
|
1076
|
return $self; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
124
|
1419
|
100
|
|
1419
|
1
|
20651
|
sub axes { wantarray ? @{ $_[0]->{axes} } : $_[0]->{axes} } |
|
1187
|
|
|
|
|
2486
|
|
125
|
1595
|
100
|
|
1595
|
1
|
8436
|
sub vars { wantarray ? @{ $_[0]->{vars} } : $_[0]->{vars} } |
|
1133
|
|
|
|
|
2398
|
|
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub _make_instance_hashref |
128
|
|
|
|
|
|
|
{ |
129
|
198
|
|
|
198
|
|
2926
|
my %params = validate_with( |
130
|
|
|
|
|
|
|
params => \@_, |
131
|
|
|
|
|
|
|
spec => { |
132
|
|
|
|
|
|
|
N => 1, |
133
|
|
|
|
|
|
|
class => 1, |
134
|
|
|
|
|
|
|
coderef => 0, |
135
|
|
|
|
|
|
|
}, |
136
|
|
|
|
|
|
|
allow_extra => 1, |
137
|
|
|
|
|
|
|
); |
138
|
198
|
|
|
|
|
1022
|
my $short_class = delete $params{class}; |
139
|
198
|
100
|
|
|
|
668
|
my $full_class = substr( $short_class, 0, 1 ) eq '+' |
140
|
|
|
|
|
|
|
? substr( $short_class, 1 ) |
141
|
|
|
|
|
|
|
: "PDL::NDBin::Action::$short_class"; |
142
|
198
|
|
|
|
|
676
|
load_class( $full_class ); |
143
|
198
|
|
|
|
|
14825
|
return $full_class->new( %params ); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub _make_instance |
147
|
|
|
|
|
|
|
{ |
148
|
198
|
|
|
198
|
|
2532
|
my %params = validate( @_, { |
149
|
|
|
|
|
|
|
action => 1, |
150
|
|
|
|
|
|
|
N => 1, |
151
|
|
|
|
|
|
|
} ); |
152
|
198
|
100
|
|
|
|
1091
|
if( ref $params{action} eq 'CODE' ) { |
|
|
100
|
|
|
|
|
|
153
|
|
|
|
|
|
|
return _make_instance_hashref( |
154
|
|
|
|
|
|
|
class => '+PDL::NDBin::Action::CodeRef', |
155
|
|
|
|
|
|
|
N => $params{N}, |
156
|
|
|
|
|
|
|
coderef => $params{action}, |
157
|
37
|
|
|
|
|
102
|
); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
elsif( ref $params{action} eq 'HASH' ) { |
160
|
|
|
|
|
|
|
return _make_instance_hashref( |
161
|
4
|
|
|
|
|
17
|
%{ $params{action} }, |
162
|
|
|
|
|
|
|
N => $params{N}, |
163
|
4
|
|
|
|
|
8
|
); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
else { |
166
|
|
|
|
|
|
|
return _make_instance_hashref( |
167
|
|
|
|
|
|
|
class => $params{action}, |
168
|
|
|
|
|
|
|
N => $params{N}, |
169
|
157
|
|
|
|
|
398
|
); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub feed |
175
|
|
|
|
|
|
|
{ |
176
|
242
|
|
|
242
|
1
|
11255
|
my $self = shift; |
177
|
242
|
|
|
|
|
559
|
my %pdls = @_; |
178
|
242
|
|
|
|
|
880
|
while( my( $name, $pdl ) = each %pdls ) { |
179
|
266
|
|
|
|
|
440
|
for my $v ( $self->axes, $self->vars ) { |
180
|
588
|
100
|
|
|
|
1866
|
$v->{pdl} = $pdl if $v->{name} eq $name; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub _check_all_pdls_present |
186
|
|
|
|
|
|
|
{ |
187
|
232
|
|
|
232
|
|
336
|
my $self = shift; |
188
|
232
|
|
|
|
|
273
|
my %warned_for; |
189
|
232
|
|
|
|
|
381
|
for my $v ( $self->axes, $self->vars ) { |
190
|
492
|
100
|
|
|
|
1015
|
next if defined $v->{pdl}; |
191
|
76
|
50
|
|
|
|
198
|
next if $v->{action} eq 'Count'; # those variables don't need data |
192
|
0
|
|
|
|
|
0
|
my $name = $v->{name}; |
193
|
0
|
0
|
|
|
|
0
|
next if $warned_for{ $name }; |
194
|
0
|
|
|
|
|
0
|
$log->error( "no data for $name" ); |
195
|
0
|
|
|
|
|
0
|
$warned_for{ $name }++; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub _check_pdl_length |
200
|
|
|
|
|
|
|
{ |
201
|
232
|
|
|
232
|
|
312
|
my $self = shift; |
202
|
|
|
|
|
|
|
# checking whether the lengths of all axes and variables are equal can |
203
|
|
|
|
|
|
|
# only be done here (in a loop), and not in autoscale_axis() |
204
|
232
|
|
|
|
|
310
|
my $length; |
205
|
232
|
|
|
|
|
337
|
for my $v ( $self->axes, $self->vars ) { |
206
|
492
|
100
|
|
|
|
1442
|
$length = $v->{pdl}->nelem unless defined $length; |
207
|
|
|
|
|
|
|
# variables don't always need a pdl, or may be happy with a |
208
|
|
|
|
|
|
|
# null pdl; let the action figure it out. |
209
|
|
|
|
|
|
|
# note that the test isempty() is not a good test for null |
210
|
|
|
|
|
|
|
# pdls, but until I have a better one, this will have to do |
211
|
492
|
100
|
100
|
|
|
1622
|
next if $v->{action} && ( ! defined $v->{pdl} || $v->{pdl}->isempty ); |
|
|
|
100
|
|
|
|
|
212
|
400
|
50
|
|
|
|
1890
|
if( $v->{pdl}->nelem != $length ) { |
213
|
|
|
|
|
|
|
croak( join '', 'number of elements (', |
214
|
0
|
|
|
|
|
0
|
$v->{pdl}->nelem, ") of '$v->{name}'", |
215
|
|
|
|
|
|
|
" is different from previous ($length)" ); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub autoscale_axis |
222
|
|
|
|
|
|
|
{ |
223
|
262
|
|
|
262
|
1
|
674
|
my $axis = shift; |
224
|
|
|
|
|
|
|
# return early if step, min, and n have already been calculated |
225
|
262
|
100
|
100
|
|
|
1090
|
if( defined $axis->{step} && defined $axis->{min} && defined $axis->{n} ) { |
|
|
|
100
|
|
|
|
|
226
|
157
|
|
|
|
|
423
|
$log->tracef( 'step, min, n already calculated for %s; not recalculating', $axis ); |
227
|
157
|
|
|
|
|
547
|
return; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
# first get & sanify the arguments |
230
|
105
|
50
|
|
|
|
235
|
croak( 'need coordinates' ) unless defined $axis->{pdl}; |
231
|
|
|
|
|
|
|
# return if axis is empty |
232
|
105
|
100
|
|
|
|
287
|
if( $axis->{pdl}->isempty ) { |
233
|
1
|
|
|
|
|
12
|
$axis->{n} = 0; |
234
|
1
|
|
|
|
|
3
|
return; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# return early if a grid has been supplied |
238
|
104
|
100
|
|
|
|
683
|
if( defined $axis->{grid} ) { |
239
|
|
|
|
|
|
|
|
240
|
9
|
|
|
|
|
27
|
$axis->{grid} = PDL::Core::topdl( $axis->{grid} ); |
241
|
|
|
|
|
|
|
croak( "grid supplied for %s must be one-dimensional with at least two elements", $axis ) |
242
|
9
|
50
|
33
|
|
|
173
|
if $axis->{grid}->nelem < 2 || $axis->{grid}->ndims > 1; |
243
|
9
|
|
|
|
|
83
|
_validate_grid( $axis->{grid} ); |
244
|
|
|
|
|
|
|
# number of bins is one less than number of bin edges |
245
|
6
|
|
|
|
|
22
|
$axis->{n} = $axis->{grid}->nelem - 1; |
246
|
6
|
|
|
|
|
20
|
$log->tracef( 'grid supplied for %s; no need to autoscale', $axis ); |
247
|
6
|
|
|
|
|
24
|
return; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
251
|
95
|
100
|
|
|
|
337
|
$axis->{min} = $axis->{pdl}->min unless defined $axis->{min}; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
|
254
|
95
|
100
|
|
|
|
4103
|
$axis->{max} = $axis->{pdl}->max unless defined $axis->{max}; |
255
|
95
|
100
|
66
|
|
|
3226
|
if( defined $axis->{round} and $axis->{round} > 0 ) { |
256
|
2
|
|
|
|
|
11
|
$axis->{min} = nlowmult( $axis->{round}, $axis->{min} ); |
257
|
2
|
|
|
|
|
32
|
$axis->{max} = nhimult( $axis->{round}, $axis->{max} ); |
258
|
|
|
|
|
|
|
} |
259
|
95
|
50
|
|
|
|
253
|
croak( 'max < min is invalid' ) if $axis->{max} < $axis->{min}; |
260
|
95
|
100
|
|
|
|
247
|
if( $axis->{pdl}->type >= PDL::float ) { |
261
|
64
|
100
|
|
|
|
2346
|
croak( 'cannot bin with min = max' ) if $axis->{min} == $axis->{max}; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
# calculate the range |
264
|
|
|
|
|
|
|
# for floating-point data, we need to augment the range by 1 unit - see |
265
|
|
|
|
|
|
|
# the discussion under IMPLEMENTATION NOTES for more details |
266
|
94
|
|
|
|
|
1272
|
my $range = $axis->{max} - $axis->{min}; |
267
|
94
|
100
|
|
|
|
198
|
if( $axis->{pdl}->type < PDL::float ) { |
268
|
31
|
|
|
|
|
820
|
$range += 1; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
# if step size has been supplied by user, check it |
271
|
94
|
100
|
|
|
|
1862
|
if( defined $axis->{step} ) { |
272
|
23
|
50
|
|
|
|
64
|
croak( 'step size must be > 0' ) unless $axis->{step} > 0; |
273
|
23
|
50
|
66
|
|
|
57
|
if( $axis->{pdl}->type < PDL::float && $axis->{step} < 1 ) { |
274
|
0
|
|
|
|
|
0
|
croak( "step size = $axis->{step} < 1 is not allowed when binning integral data" ); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
# number of bins I |
278
|
94
|
100
|
|
|
|
823
|
if( defined $axis->{n} ) { |
279
|
46
|
50
|
|
|
|
109
|
croak( 'number of bins must be > 0' ) unless $axis->{n} > 0; |
280
|
46
|
50
|
|
|
|
226
|
croak( 'number of bins must be integral' ) if ceil( $axis->{n} ) - $axis->{n} > 0; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
else { |
283
|
48
|
100
|
|
|
|
95
|
if( defined $axis->{step} ) { |
284
|
|
|
|
|
|
|
# data range and step size were verified above, |
285
|
|
|
|
|
|
|
# so the result of this calculation is |
286
|
|
|
|
|
|
|
# guaranteed to be > 0 |
287
|
23
|
|
|
|
|
149
|
$axis->{n} = ceil( $range / $axis->{step} ); |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
else { |
290
|
|
|
|
|
|
|
# if neither number of bins nor step size is defined, |
291
|
|
|
|
|
|
|
# use some reasonable default (which used to be the |
292
|
|
|
|
|
|
|
# behaviour of hist() in versions of PDL inferior to |
293
|
|
|
|
|
|
|
# 2.4.12) (see F) |
294
|
25
|
100
|
|
|
|
111
|
$axis->{n} = $axis->{pdl}->nelem > 100 ? 100 : $axis->{pdl}->nelem; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
# step size I |
298
|
|
|
|
|
|
|
# if we get here, the data range is certain to be larger than |
299
|
|
|
|
|
|
|
# zero, and I is sure to be defined and valid (either |
300
|
|
|
|
|
|
|
# because it was supplied explicitly and verified to be valid, |
301
|
|
|
|
|
|
|
# or because it was calculated automatically) |
302
|
94
|
100
|
|
|
|
245
|
if( ! defined $axis->{step} ) { |
303
|
|
|
|
|
|
|
# result of this calculation is guaranteed to be > 0 |
304
|
71
|
|
|
|
|
167
|
$axis->{step} = $range / $axis->{n}; |
305
|
71
|
100
|
|
|
|
156
|
if( $axis->{pdl}->type < PDL::float ) { |
306
|
23
|
100
|
|
|
|
699
|
croak( 'there are more bins than distinct values' ) if $axis->{step} < 1; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub autoscale |
313
|
|
|
|
|
|
|
{ |
314
|
232
|
|
|
232
|
1
|
329
|
my $self = shift; |
315
|
232
|
|
|
|
|
519
|
$self->feed( @_ ); |
316
|
232
|
|
|
|
|
566
|
$self->_check_all_pdls_present; |
317
|
232
|
|
|
|
|
538
|
$self->_check_pdl_length; |
318
|
232
|
|
|
|
|
545
|
autoscale_axis( $_ ) for $self->axes; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub labels |
323
|
|
|
|
|
|
|
{ |
324
|
8
|
|
|
8
|
1
|
578
|
my $self = shift; |
325
|
8
|
|
|
|
|
25
|
$self->autoscale( @_ ); |
326
|
|
|
|
|
|
|
my @list = map { |
327
|
8
|
|
|
|
|
44
|
my $axis = $_; |
|
10
|
|
|
|
|
57
|
|
328
|
|
|
|
|
|
|
|
329
|
10
|
100
|
|
|
|
19
|
if ( defined $axis->{grid} ) { |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
[ map { |
332
|
8
|
|
|
|
|
84
|
{ range => [ $axis->{grid}->at($_), $axis->{grid}->at($_+1) ] } |
333
|
3
|
|
|
|
|
12
|
} 0..$axis->{grid}->nelem -2 |
334
|
|
|
|
|
|
|
] |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
else { |
339
|
|
|
|
|
|
|
|
340
|
7
|
|
|
|
|
11
|
my ( $pdl, $min, $step ) = @{ $axis }{ qw( pdl min step ) }; |
|
7
|
|
|
|
|
17
|
|
341
|
|
|
|
|
|
|
[ map { |
342
|
|
|
|
|
|
|
{ # anonymous hash |
343
|
20
|
100
|
|
|
|
518
|
range => $pdl->type() >= PDL::float() |
|
|
100
|
|
|
|
|
|
344
|
|
|
|
|
|
|
? [ $min + $step*$_, $min + $step*($_+1) ] |
345
|
|
|
|
|
|
|
: $step > 1 |
346
|
|
|
|
|
|
|
? [ nhimult( 1, $min + $step*$_ ), nhimult( 1, $min + $step*($_+1) - 1 ) ] |
347
|
|
|
|
|
|
|
: $min + $step*$_ |
348
|
|
|
|
|
|
|
} |
349
|
7
|
|
|
|
|
18
|
} 0 .. $axis->{n}-1 ]; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
} $self->axes; |
354
|
|
|
|
|
|
|
|
355
|
16
|
50
|
|
|
|
320
|
return wantarray ? @list : \@list; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub process |
360
|
|
|
|
|
|
|
{ |
361
|
222
|
|
|
222
|
1
|
3230
|
my $self = shift; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# sanity check |
364
|
222
|
100
|
|
|
|
284
|
croak( 'no axes supplied' ) unless @{ $self->axes }; |
|
222
|
|
|
|
|
466
|
|
365
|
|
|
|
|
|
|
# default action, when no variables are given, is to produce a histogram |
366
|
220
|
100
|
|
|
|
289
|
$self->add_var( name => 'histogram', action => 'Count' ) unless @{ $self->vars }; |
|
220
|
|
|
|
|
392
|
|
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# |
369
|
220
|
|
|
|
|
599
|
$self->autoscale( @_ ); |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
# process axes |
372
|
215
|
|
|
|
|
1233
|
my $idx = 0; # flattened bin number |
373
|
215
|
|
|
|
|
295
|
my @n; # number of bins in each direction |
374
|
|
|
|
|
|
|
# find the last axis and flatten all axes into one dimension, working |
375
|
|
|
|
|
|
|
# our way backwards from the last to the first axis |
376
|
215
|
|
|
|
|
374
|
for my $axis ( reverse $self->axes ) { |
377
|
242
|
50
|
|
|
|
668
|
if ( $log->is_debug ) { |
378
|
0
|
|
|
|
|
0
|
$log->debug( 'input (' . $axis->{pdl}->info . ') = ' . $axis->{pdl} ); |
379
|
0
|
0
|
|
|
|
0
|
if ( ! defined $axis->{grid} ) { |
380
|
0
|
|
|
|
|
0
|
$log->debug( "bin with parameters step=$axis->{step}, min=$axis->{min}, n=$axis->{n}" ); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
else { |
383
|
0
|
|
|
|
|
0
|
$log->debug( "bin with parameters grid=$axis->{grid}" ); |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
} |
386
|
242
|
100
|
|
|
|
2045
|
croak( 'I cannot bin unless n > 0' ) unless $axis->{n} > 0; |
387
|
241
|
|
|
|
|
498
|
unshift @n, $axis->{n}; # remember that we are working backwards! |
388
|
241
|
100
|
|
|
|
473
|
if ( defined $axis->{grid} ) { |
389
|
3
|
|
|
|
|
159
|
$idx = $axis->{pdl}->_flatten_into_grid( $idx, $axis->{grid} ); |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
else { |
392
|
238
|
|
|
|
|
4925
|
$idx = $axis->{pdl}->_flatten_into( $idx, $axis->{step}, $axis->{min}, $axis->{n} ); |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
} |
395
|
214
|
50
|
|
|
|
703
|
$log->debug( 'idx (' . $idx->info . ') = ' . $idx ) if $log->is_debug; |
396
|
214
|
|
|
|
|
1695
|
$self->{n} = \@n; |
397
|
|
|
|
|
|
|
|
398
|
214
|
|
|
27
|
|
1384
|
my $N = reduce { $a * $b } @n; # total number of bins |
|
27
|
|
|
|
|
61
|
|
399
|
214
|
50
|
|
|
|
793
|
croak( 'I need at least one bin' ) unless $N; |
400
|
214
|
|
|
|
|
450
|
my @vars = map $_->{pdl}, $self->vars; |
401
|
214
|
|
100
|
|
|
769
|
$self->{instances} ||= [ map { _make_instance( N => $N, action => $_->{action} ) } $self->vars ]; |
|
198
|
|
|
|
|
442
|
|
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
# |
404
|
|
|
|
|
|
|
{ |
405
|
214
|
|
|
|
|
381
|
local $Data::Dumper::Terse = 1; |
|
214
|
|
|
|
|
381
|
|
406
|
214
|
|
|
|
|
626
|
$log->trace( 'process: $self = ' . Dumper $self ); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# now visit all the bins |
410
|
214
|
|
|
|
|
28927
|
my $iter = PDL::NDBin::Iterator->new( bins => \@n, array => \@vars, idx => $idx ); |
411
|
214
|
|
|
|
|
611
|
$log->debug( 'iterator object created: ' . Dumper $iter ); |
412
|
214
|
|
|
|
|
19341
|
while( $iter->advance ) { |
413
|
396
|
|
|
|
|
1016
|
my $i = $iter->var; |
414
|
396
|
|
|
|
|
1099
|
$self->{instances}->[ $i ]->process( $iter ); |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
211
|
|
|
|
|
1448
|
return $self; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub output |
422
|
|
|
|
|
|
|
{ |
423
|
187
|
|
|
187
|
1
|
1128
|
my $self = shift; |
424
|
187
|
50
|
|
|
|
427
|
return unless defined wantarray; |
425
|
187
|
100
|
|
|
|
453
|
unless( defined $self->{result} ) { |
426
|
|
|
|
|
|
|
# reshape output |
427
|
181
|
|
|
|
|
299
|
my $n = $self->{n}; |
428
|
181
|
|
|
|
|
237
|
my @output = map { $_->result } @{ $self->{instances} }; |
|
186
|
|
|
|
|
463
|
|
|
181
|
|
|
|
|
427
|
|
429
|
181
|
|
|
|
|
413
|
for my $pdl ( @output ) { $pdl->reshape( @$n ) } |
|
186
|
|
|
|
|
706
|
|
430
|
181
|
50
|
|
|
|
7632
|
if( $log->is_debug ) { $log->debug( 'output: output (' . $_->info . ') = ' . $_ ) for @output } |
|
0
|
|
|
|
|
0
|
|
431
|
181
|
|
|
186
|
|
2045
|
$self->{result} = { pairwise { $a->{name} => $b } @{ $self->vars }, @output }; |
|
186
|
|
|
|
|
765
|
|
|
181
|
|
|
|
|
740
|
|
432
|
181
|
50
|
|
|
|
751
|
if( $log->is_debug ) { $log->debug( 'output: result = ' . Dumper $self->{result} ) } |
|
0
|
|
|
|
|
0
|
|
433
|
|
|
|
|
|
|
} |
434
|
187
|
50
|
|
|
|
1758
|
return wantarray ? %{ $self->{result} } : $self->{result}; |
|
0
|
|
|
|
|
0
|
|
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
sub _consume (&\@) |
439
|
|
|
|
|
|
|
{ |
440
|
94
|
|
|
94
|
|
186
|
my ( $f, $list ) = @_; |
441
|
94
|
|
|
|
|
241
|
for my $i ( 0 .. $#$list ) { |
442
|
310
|
|
|
|
|
585
|
local *_ = \$list->[$i]; |
443
|
310
|
100
|
|
|
|
459
|
if( not $f->() ) { return splice @$list, 0, $i } |
|
32
|
|
|
|
|
158
|
|
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
# If we get here, either the list is empty, or all values in the list |
446
|
|
|
|
|
|
|
# meet the condition. In either case, splicing the entire list does |
447
|
|
|
|
|
|
|
# what we want. |
448
|
62
|
|
|
|
|
241
|
return splice @$list; |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
sub _expand_axes |
452
|
|
|
|
|
|
|
{ |
453
|
52
|
|
|
52
|
|
80
|
my ( @out, $hash, @num ); |
454
|
52
|
|
|
|
|
106
|
while( @_ ) { |
455
|
97
|
100
|
|
|
|
123
|
if( eval { $_[0]->isa('PDL') } ) { |
|
97
|
100
|
|
|
|
416
|
|
|
|
100
|
|
|
|
|
|
456
|
|
|
|
|
|
|
# a new axis; push the existing one on the output list |
457
|
58
|
50
|
|
|
|
131
|
push @out, $hash if $hash; |
458
|
58
|
|
|
|
|
183
|
$hash = { pdl => shift }; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
elsif( ref $_[0] eq 'HASH' ) { |
461
|
|
|
|
|
|
|
# the user has supplied a hash directly, which may or |
462
|
|
|
|
|
|
|
# may not yet contain a key-value pair pdl => $pdl |
463
|
26
|
50
|
|
|
|
60
|
$hash = { } unless $hash; |
464
|
26
|
|
|
|
|
68
|
push @out, { %$hash, %{ +shift } }; |
|
26
|
|
|
|
|
72
|
|
465
|
26
|
|
|
|
|
92
|
undef $hash; # do not collapse consecutive hashes into one, too confusing |
466
|
|
|
|
|
|
|
} |
467
|
30
|
|
|
30
|
|
351
|
elsif( @num = _consume { /^[-+]?(\d+(\.\d*)?|\.\d+)([Ee][-+]?\d+)?$/ } @_ ) { |
468
|
8
|
50
|
|
|
|
20
|
croak( 'no axis given' ) unless $hash; |
469
|
8
|
100
|
|
|
|
34
|
croak( "too many arguments to axis in `@num'" ) if @num > 3; |
470
|
|
|
|
|
|
|
# a series of floating-point numbers |
471
|
7
|
50
|
|
|
|
24
|
$hash->{min} = $num[0] if @num > 0; |
472
|
7
|
50
|
|
|
|
18
|
$hash->{max} = $num[1] if @num > 1; |
473
|
7
|
50
|
|
|
|
39
|
$hash->{step} = $num[2] if @num > 2; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
#elsif( @num = ( $_[0] =~ m{^((?:\d+(?:\.\d*)?|\.\d+)(?:[Ee][-+]?\d+)?/)+$}g ) and shift ) { |
476
|
|
|
|
|
|
|
# DOES NOT WORK YET - TODO |
477
|
|
|
|
|
|
|
# print "GMT-style axis spec found! (@num)\n"; |
478
|
|
|
|
|
|
|
# croak( 'no axis given' ) unless $hash; |
479
|
|
|
|
|
|
|
# croak( "too many arguments to axis in `@num'" ) if @num > 3; |
480
|
|
|
|
|
|
|
# # a string specification of the form 'min/max/step', a la GMT |
481
|
|
|
|
|
|
|
# $hash->{min} = $num[0] if @num > 0; |
482
|
|
|
|
|
|
|
# $hash->{max} = $num[1] if @num > 1; |
483
|
|
|
|
|
|
|
# $hash->{step} = $num[2] if @num > 2; |
484
|
|
|
|
|
|
|
#} |
485
|
|
|
|
|
|
|
else { |
486
|
5
|
|
|
|
|
60
|
croak( "while expanding axes: invalid argument at `@_'" ); |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
} |
489
|
46
|
100
|
|
|
|
183
|
push @out, $hash if $hash; |
490
|
46
|
|
|
|
|
102
|
return @out; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
|
494
|
115
|
|
|
115
|
|
319
|
sub _random_name { create_uuid( UUID_RANDOM ) } |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
sub ndbinning |
498
|
|
|
|
|
|
|
{ |
499
|
|
|
|
|
|
|
# |
500
|
26
|
|
|
26
|
1
|
17004
|
my $binner = __PACKAGE__->new; |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
# leading arguments are axes and axis specifications |
503
|
|
|
|
|
|
|
# |
504
|
|
|
|
|
|
|
# PDL overloads the `eq' and `ne' operators; by checking for a PDL |
505
|
|
|
|
|
|
|
# first, we avoid (invalid) comparisons between piddles and strings in |
506
|
|
|
|
|
|
|
# the `grep' |
507
|
26
|
100
|
|
148
|
|
105
|
my @leading = _consume { eval { $_->isa('PDL') } || ! $valid_key{ $_ } } @_; |
|
148
|
|
|
|
|
179
|
|
|
148
|
|
|
|
|
903
|
|
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# consume and process axes |
510
|
|
|
|
|
|
|
# axes require three numerical specifications following it |
511
|
26
|
|
66
|
|
|
127
|
while( @leading > 3 && eval { $leading[0]->isa('PDL') } && ! grep ref, @leading[ 1 .. 3 ] ) { |
|
32
|
|
100
|
|
|
229
|
|
512
|
31
|
|
|
|
|
102
|
my( $pdl, $step, $min, $n ) = splice @leading, 0, 4; |
513
|
31
|
|
|
|
|
72
|
$binner->add_axis( name => _random_name, pdl => $pdl, step => $step, min => $min, n => $n ); |
514
|
|
|
|
|
|
|
} |
515
|
26
|
100
|
|
|
|
55
|
if( @leading ) { croak( "error parsing arguments in `@leading'" ) } |
|
7
|
|
|
|
|
35
|
|
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
# remaining arguments are key => value pairs |
518
|
19
|
|
|
|
|
43
|
my $args = { @_ }; |
519
|
19
|
|
|
|
|
55
|
my @invalid_keys = grep ! $valid_key{ $_ }, keys %$args; |
520
|
19
|
50
|
|
|
|
35
|
croak( "invalid key(s) @invalid_keys" ) if @invalid_keys; |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# axes |
523
|
19
|
|
50
|
|
|
88
|
$args->{axes} ||= []; |
524
|
19
|
|
|
|
|
29
|
my @axes = @{ $args->{axes} }; |
|
19
|
|
|
|
|
33
|
|
525
|
19
|
|
|
|
|
34
|
for my $axis ( @axes ) { |
526
|
0
|
|
|
|
|
0
|
my $pdl = shift @$axis; |
527
|
0
|
|
|
|
|
0
|
$binner->add_axis( name => _random_name, pdl => $pdl, @$axis ); |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
# variables |
531
|
19
|
|
100
|
|
|
58
|
$args->{vars} ||= []; |
532
|
19
|
|
|
|
|
21
|
for my $var ( @{ $args->{vars} } ) { |
|
19
|
|
|
|
|
40
|
|
533
|
13
|
50
|
|
|
|
32
|
if( @$var == 2 ) { |
534
|
13
|
|
|
|
|
27
|
my( $pdl, $action ) = @$var; |
535
|
13
|
|
|
|
|
27
|
$binner->add_var( name => _random_name, pdl => $pdl, action => $action ); |
536
|
|
|
|
|
|
|
} |
537
|
0
|
|
|
|
|
0
|
else { croak( "wrong number of arguments for var: @$var" ) } |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# |
541
|
19
|
|
|
|
|
115
|
$binner->process; |
542
|
18
|
|
|
|
|
49
|
my $output = $binner->output; |
543
|
18
|
|
|
|
|
29
|
my @result = map $output->{ $_->{name} }, @{ $binner->vars }; |
|
18
|
|
|
|
|
28
|
|
544
|
18
|
50
|
|
|
|
232
|
return wantarray ? @result : $result[0]; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
sub ndbin |
549
|
|
|
|
|
|
|
{ |
550
|
|
|
|
|
|
|
# |
551
|
55
|
|
|
55
|
1
|
43752
|
my $binner = __PACKAGE__->new; |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# leading arguments are axes and axis specifications |
554
|
|
|
|
|
|
|
# |
555
|
|
|
|
|
|
|
# PDL overloads the `eq' and `ne' operators; by checking for a PDL |
556
|
|
|
|
|
|
|
# first, we avoid (invalid) comparisons between piddles and strings in |
557
|
|
|
|
|
|
|
# the `grep' |
558
|
55
|
100
|
|
132
|
|
250
|
if( my @leading = _consume { eval { $_->isa('PDL') } || ! $valid_key{ $_ } } @_ ) { |
|
132
|
100
|
|
|
|
491
|
|
|
132
|
|
|
|
|
905
|
|
559
|
52
|
|
|
|
|
129
|
my @axes = _expand_axes( @leading ); |
560
|
46
|
|
|
|
|
157
|
$binner->add_axis( name => _random_name, %$_ ) for @axes; |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
# remaining arguments are key => value pairs |
564
|
49
|
|
|
|
|
181
|
my $args = { @_ }; |
565
|
49
|
|
|
|
|
148
|
my @invalid_keys = grep ! $valid_key{ $_ }, keys %$args; |
566
|
49
|
50
|
|
|
|
109
|
croak( "invalid key(s) @invalid_keys" ) if @invalid_keys; |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
# axes |
569
|
49
|
|
100
|
|
|
212
|
$args->{axes} ||= []; |
570
|
49
|
|
|
|
|
84
|
my @axes = @{ $args->{axes} }; |
|
49
|
|
|
|
|
79
|
|
571
|
49
|
|
|
|
|
100
|
for my $axis ( @axes ) { |
572
|
3
|
|
|
|
|
6
|
my $pdl = shift @$axis; |
573
|
3
|
|
|
|
|
7
|
$binner->add_axis( name => _random_name, pdl => $pdl, @$axis ); |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# variables |
577
|
49
|
|
100
|
|
|
162
|
$args->{vars} ||= []; |
578
|
49
|
|
|
|
|
64
|
for my $var ( @{ $args->{vars} } ) { |
|
49
|
|
|
|
|
93
|
|
579
|
16
|
50
|
|
|
|
33
|
if( @$var == 2 ) { |
580
|
16
|
|
|
|
|
34
|
my( $pdl, $action ) = @$var; |
581
|
16
|
|
|
|
|
33
|
$binner->add_var( name => _random_name, pdl => $pdl, action => $action ); |
582
|
|
|
|
|
|
|
} |
583
|
0
|
|
|
|
|
0
|
else { croak( "wrong number of arguments for var: @$var" ) } |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
|
586
|
49
|
|
|
|
|
124
|
$binner->process; |
587
|
42
|
|
|
|
|
107
|
my $output = $binner->output; |
588
|
42
|
|
|
|
|
65
|
my @result = map $output->{ $_->{name} }, @{ $binner->vars }; |
|
42
|
|
|
|
|
71
|
|
589
|
42
|
50
|
|
|
|
451
|
return wantarray ? @result : $result[0]; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
1; |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
__END__ |