| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
use strict; |
|
2
|
|
|
|
|
|
|
use warnings; |
|
3
|
|
|
|
|
|
|
use PDL::Types qw(ppdefs_all types); |
|
4
|
|
|
|
|
|
|
my $F = [map $_->ppsym, grep $_->real && !$_->integer, types()]; |
|
5
|
|
|
|
|
|
|
my $AF = [map $_->ppsym, grep !$_->integer, types]; |
|
6
|
|
|
|
|
|
|
$AF = [(grep $_ ne 'D', @$AF), 'D']; # so defaults to D if non-float given |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
{ no warnings 'once'; # pass info back to Makefile.PL |
|
9
|
|
|
|
|
|
|
$PDL::Core::Dev::EXTRAS{$::PDLMOD}{OBJECT} .= " $::PDLBASE-xoshiro256plus\$(OBJ_EXT)"; |
|
10
|
|
|
|
|
|
|
} |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
pp_addpm({At=>'Top'},<<'EOD'); |
|
13
|
|
|
|
|
|
|
use strict; |
|
14
|
|
|
|
|
|
|
use warnings; |
|
15
|
|
|
|
|
|
|
use PDL::Slices; |
|
16
|
|
|
|
|
|
|
use Carp; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
PDL::Primitive - primitive operations for pdl |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
This module provides some primitive and useful functions defined |
|
25
|
|
|
|
|
|
|
using PDL::PP and able to use the new indexing tricks. |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
See L for how to use indices creatively. |
|
28
|
|
|
|
|
|
|
For explanation of the signature format, see L. |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Pulls in PDL::Primitive, among other modules. |
|
33
|
|
|
|
|
|
|
use PDL; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Only pull in PDL::Primitive: |
|
36
|
|
|
|
|
|
|
use PDL::Primitive; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=cut |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
EOD |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
################################################################ |
|
43
|
|
|
|
|
|
|
# a whole bunch of quite basic functions for inner, outer |
|
44
|
|
|
|
|
|
|
# and matrix products (operations that are not normally |
|
45
|
|
|
|
|
|
|
# available via operator overloading) |
|
46
|
|
|
|
|
|
|
################################################################ |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
pp_def('inner', |
|
49
|
|
|
|
|
|
|
HandleBad => 1, |
|
50
|
|
|
|
|
|
|
Pars => 'a(n); b(n); [o]c();', |
|
51
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
52
|
|
|
|
|
|
|
Code => <<'EOF', |
|
53
|
|
|
|
|
|
|
complex long double tmp = 0; |
|
54
|
|
|
|
|
|
|
PDL_IF_BAD(int badflag = 0;,) |
|
55
|
|
|
|
|
|
|
loop(n) %{ |
|
56
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a()) || $ISBAD(b())) { badflag = 1; break; } |
|
57
|
|
|
|
|
|
|
else,) { tmp += $a() * $b(); } |
|
58
|
|
|
|
|
|
|
%} |
|
59
|
|
|
|
|
|
|
PDL_IF_BAD(if (badflag) { $SETBAD(c()); $PDLSTATESETBAD(c); } |
|
60
|
|
|
|
|
|
|
else,) { $c() = tmp; } |
|
61
|
|
|
|
|
|
|
EOF |
|
62
|
|
|
|
|
|
|
Doc => ' |
|
63
|
|
|
|
|
|
|
=for ref |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
Inner product over one dimension |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
c = sum_i a_i * b_i |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
See also L, L. |
|
70
|
|
|
|
|
|
|
', |
|
71
|
|
|
|
|
|
|
BadDoc => ' |
|
72
|
|
|
|
|
|
|
If C contains only bad data, |
|
73
|
|
|
|
|
|
|
C is set bad. Otherwise C will have its bad flag cleared, |
|
74
|
|
|
|
|
|
|
as it will not contain any bad values. |
|
75
|
|
|
|
|
|
|
', |
|
76
|
|
|
|
|
|
|
); # pp_def( inner ) |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
pp_def('outer', |
|
79
|
|
|
|
|
|
|
HandleBad => 1, |
|
80
|
|
|
|
|
|
|
Pars => 'a(n); b(m); [o]c(n,m);', |
|
81
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
82
|
|
|
|
|
|
|
Code => <<'EOF', |
|
83
|
|
|
|
|
|
|
loop(n,m) %{ |
|
84
|
|
|
|
|
|
|
PDL_IF_BAD(if ( $ISBAD(a()) || $ISBAD(b()) ) { $SETBAD(c()); continue; },) |
|
85
|
|
|
|
|
|
|
$c() = $a() * $b(); |
|
86
|
|
|
|
|
|
|
%} |
|
87
|
|
|
|
|
|
|
EOF |
|
88
|
|
|
|
|
|
|
Doc => ' |
|
89
|
|
|
|
|
|
|
=for ref |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
outer product over one dimension |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
Naturally, it is possible to achieve the effects of outer |
|
94
|
|
|
|
|
|
|
product simply by broadcasting over the "C<*>" |
|
95
|
|
|
|
|
|
|
operator but this function is provided for convenience. |
|
96
|
|
|
|
|
|
|
'); # pp_def( outer ) |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
99
|
|
|
|
|
|
|
=head2 x |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=for sig |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Signature: (a(i,z), b(x,i),[o]c(x,z)) |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=for ref |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Matrix multiplication |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
PDL overloads the C operator (normally the repeat operator) for |
|
110
|
|
|
|
|
|
|
matrix multiplication. The number of columns (size of the 0 |
|
111
|
|
|
|
|
|
|
dimension) in the left-hand argument must normally equal the number of |
|
112
|
|
|
|
|
|
|
rows (size of the 1 dimension) in the right-hand argument. |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
Row vectors are represented as (N x 1) two-dimensional PDLs, or you |
|
115
|
|
|
|
|
|
|
may be sloppy and use a one-dimensional PDL. Column vectors are |
|
116
|
|
|
|
|
|
|
represented as (1 x N) two-dimensional PDLs. |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Broadcasting occurs in the usual way, but as both the 0 and 1 dimension |
|
119
|
|
|
|
|
|
|
(if present) are included in the operation, you must be sure that |
|
120
|
|
|
|
|
|
|
you don't try to broadcast over either of those dims. |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
Of note, due to how Perl v5.14.0 and above implement operator overloading of |
|
123
|
|
|
|
|
|
|
the C operator, the use of parentheses for the left operand creates a list |
|
124
|
|
|
|
|
|
|
context, that is |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
pdl> ( $x * $y ) x $z |
|
127
|
|
|
|
|
|
|
ERROR: Argument "..." isn't numeric in repeat (x) ... |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
treats C<$z> as a numeric count for the list repeat operation and does not call |
|
130
|
|
|
|
|
|
|
the scalar form of the overloaded operator. To use the operator in this case, |
|
131
|
|
|
|
|
|
|
use a scalar context: |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
pdl> scalar( $x * $y ) x $z |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
or by calling L directly: |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
pdl> ( $x * $y )->matmult( $z ) |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
EXAMPLES |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
Here are some simple ways to define vectors and matrices: |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
pdl> $r = pdl(1,2); # A row vector |
|
144
|
|
|
|
|
|
|
pdl> $c = pdl([[3],[4]]); # A column vector |
|
145
|
|
|
|
|
|
|
pdl> $c = pdl(3,4)->(*1); # A column vector, using NiceSlice |
|
146
|
|
|
|
|
|
|
pdl> $m = pdl([[1,2],[3,4]]); # A 2x2 matrix |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Now that we have a few objects prepared, here is how to |
|
149
|
|
|
|
|
|
|
matrix-multiply them: |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
pdl> print $r x $m # row x matrix = row |
|
152
|
|
|
|
|
|
|
[ |
|
153
|
|
|
|
|
|
|
[ 7 10] |
|
154
|
|
|
|
|
|
|
] |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
pdl> print $m x $r # matrix x row = ERROR |
|
157
|
|
|
|
|
|
|
PDL: Dim mismatch in matmult of [2x2] x [2x1]: 2 != 1 |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
pdl> print $m x $c # matrix x column = column |
|
160
|
|
|
|
|
|
|
[ |
|
161
|
|
|
|
|
|
|
[ 5] |
|
162
|
|
|
|
|
|
|
[11] |
|
163
|
|
|
|
|
|
|
] |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
pdl> print $m x 2 # Trivial case: scalar mult. |
|
166
|
|
|
|
|
|
|
[ |
|
167
|
|
|
|
|
|
|
[2 4] |
|
168
|
|
|
|
|
|
|
[6 8] |
|
169
|
|
|
|
|
|
|
] |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
pdl> print $r x $c # row x column = scalar |
|
172
|
|
|
|
|
|
|
[ |
|
173
|
|
|
|
|
|
|
[11] |
|
174
|
|
|
|
|
|
|
] |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
pdl> print $c x $r # column x row = matrix |
|
177
|
|
|
|
|
|
|
[ |
|
178
|
|
|
|
|
|
|
[3 6] |
|
179
|
|
|
|
|
|
|
[4 8] |
|
180
|
|
|
|
|
|
|
] |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
INTERNALS |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
The mechanics of the multiplication are carried out by the |
|
185
|
|
|
|
|
|
|
L method. |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=cut |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
EOD |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
pp_def('matmult', |
|
192
|
|
|
|
|
|
|
HandleBad=>1, |
|
193
|
|
|
|
|
|
|
Pars => 'a(t,h); b(w,t); [o]c(w,h);', |
|
194
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
195
|
|
|
|
|
|
|
Overload => 'x', |
|
196
|
|
|
|
|
|
|
PMCode => pp_line_numbers(__LINE__, <<'EOPM'), |
|
197
|
|
|
|
|
|
|
sub PDL::matmult { |
|
198
|
|
|
|
|
|
|
my ($x,$y,$c) = @_; |
|
199
|
|
|
|
|
|
|
$y = PDL->topdl($y); |
|
200
|
|
|
|
|
|
|
$c = PDL->null if !UNIVERSAL::isa($c, 'PDL'); |
|
201
|
|
|
|
|
|
|
while($x->getndims < 2) {$x = $x->dummy(-1)} |
|
202
|
|
|
|
|
|
|
while($y->getndims < 2) {$y = $y->dummy(-1)} |
|
203
|
|
|
|
|
|
|
return ($c .= $x * $y) if( ($x->dim(0)==1 && $x->dim(1)==1) || |
|
204
|
|
|
|
|
|
|
($y->dim(0)==1 && $y->dim(1)==1) ); |
|
205
|
|
|
|
|
|
|
barf sprintf 'Dim mismatch in matmult of [%1$dx%2$d] x [%3$dx%4$d]: %1$d != %4$d',$x->dim(0),$x->dim(1),$y->dim(0),$y->dim(1) |
|
206
|
|
|
|
|
|
|
if $y->dim(1) != $x->dim(0); |
|
207
|
|
|
|
|
|
|
PDL::_matmult_int($x,$y,$c); |
|
208
|
|
|
|
|
|
|
$c; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
EOPM |
|
211
|
|
|
|
|
|
|
Code => <<'EOC', |
|
212
|
|
|
|
|
|
|
PDL_Indx tsiz = 8 * sizeof(double) / sizeof($GENERIC()); |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
// Cache the dimincs to avoid constant lookups |
|
215
|
|
|
|
|
|
|
PDL_Indx atdi = PDL_REPRINCS($PDL(a))[0]; |
|
216
|
|
|
|
|
|
|
PDL_Indx btdi = PDL_REPRINCS($PDL(b))[1]; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
broadcastloop %{ |
|
219
|
|
|
|
|
|
|
// Loop over tiles |
|
220
|
|
|
|
|
|
|
loop (h=::tsiz,w=::tsiz) %{ |
|
221
|
|
|
|
|
|
|
PDL_Indx h_outer = h, w_outer = w; |
|
222
|
|
|
|
|
|
|
// Zero the output for this tile |
|
223
|
|
|
|
|
|
|
loop (h=h_outer:h_outer+tsiz,w=w_outer:w_outer+tsiz) %{ $c() = 0; %} |
|
224
|
|
|
|
|
|
|
loop (t=::tsiz,h=h_outer:h_outer+tsiz,w=w_outer:w_outer+tsiz) %{ |
|
225
|
|
|
|
|
|
|
// Cache the accumulated value for the output |
|
226
|
|
|
|
|
|
|
$GENERIC() cc = $c(); |
|
227
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBADVAR(cc,c)) continue;,) |
|
228
|
|
|
|
|
|
|
// Cache data pointers before 't' run through tile |
|
229
|
|
|
|
|
|
|
$GENERIC() *ad = &($a()); |
|
230
|
|
|
|
|
|
|
$GENERIC() *bd = &($b()); |
|
231
|
|
|
|
|
|
|
// Hotspot - run the 't' summation |
|
232
|
|
|
|
|
|
|
PDL_Indx t_outer = t; |
|
233
|
|
|
|
|
|
|
PDL_IF_BAD(char c_isbad = 0;,) |
|
234
|
|
|
|
|
|
|
loop (t=t_outer:t_outer+tsiz) %{ |
|
235
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBADVAR(*ad,a) || $ISBADVAR(*bd,b)) { c_isbad = 1; break; },) |
|
236
|
|
|
|
|
|
|
cc += *ad * *bd; |
|
237
|
|
|
|
|
|
|
ad += atdi; |
|
238
|
|
|
|
|
|
|
bd += btdi; |
|
239
|
|
|
|
|
|
|
%} |
|
240
|
|
|
|
|
|
|
// put the output back to be further accumulated later |
|
241
|
|
|
|
|
|
|
PDL_IF_BAD(if (c_isbad) { $SETBAD(c()); continue; },) |
|
242
|
|
|
|
|
|
|
$c() = cc; |
|
243
|
|
|
|
|
|
|
%} |
|
244
|
|
|
|
|
|
|
%} |
|
245
|
|
|
|
|
|
|
%} |
|
246
|
|
|
|
|
|
|
EOC |
|
247
|
|
|
|
|
|
|
Doc => <<'EOD' |
|
248
|
|
|
|
|
|
|
=for ref |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Matrix multiplication |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Notionally, matrix multiplication $x x $y is equivalent to the |
|
253
|
|
|
|
|
|
|
broadcasting expression |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
$x->dummy(1)->inner($y->xchg(0,1)->dummy(2),$c); |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
but for large matrices that breaks CPU cache and is slow. Instead, |
|
258
|
|
|
|
|
|
|
matmult calculates its result in 32x32x32 tiles, to keep the memory |
|
259
|
|
|
|
|
|
|
footprint within cache as long as possible on most modern CPUs. |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
For usage, see L, a description of the overloaded 'x' operator |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
EOD |
|
264
|
|
|
|
|
|
|
); |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
pp_def('innerwt', |
|
267
|
|
|
|
|
|
|
HandleBad => 1, |
|
268
|
|
|
|
|
|
|
Pars => 'a(n); b(n); c(n); [o]d();', |
|
269
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
270
|
|
|
|
|
|
|
Code => <<'EOF', |
|
271
|
|
|
|
|
|
|
complex long double tmp = 0; |
|
272
|
|
|
|
|
|
|
PDL_IF_BAD(int flag = 0;,) |
|
273
|
|
|
|
|
|
|
loop(n) %{ |
|
274
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a()) || $ISBAD(b()) || $ISBAD(c())) continue;flag = 1;,) |
|
275
|
|
|
|
|
|
|
tmp += $a() * $b() * $c(); |
|
276
|
|
|
|
|
|
|
%} |
|
277
|
|
|
|
|
|
|
PDL_IF_BAD(if (!flag) { $SETBAD(d()); } |
|
278
|
|
|
|
|
|
|
else,) { $d() = tmp; } |
|
279
|
|
|
|
|
|
|
EOF |
|
280
|
|
|
|
|
|
|
Doc => ' |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=for ref |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Weighted (i.e. triple) inner product |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
d = sum_i a(i) b(i) c(i) |
|
287
|
|
|
|
|
|
|
' |
|
288
|
|
|
|
|
|
|
); |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
pp_def('inner2', |
|
291
|
|
|
|
|
|
|
HandleBad => 1, |
|
292
|
|
|
|
|
|
|
Pars => 'a(n); b(n,m); c(m); [o]d();', |
|
293
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
294
|
|
|
|
|
|
|
Code => <<'EOF', |
|
295
|
|
|
|
|
|
|
complex long double tmp = 0; |
|
296
|
|
|
|
|
|
|
PDL_IF_BAD(int flag = 0;,) |
|
297
|
|
|
|
|
|
|
loop(n,m) %{ |
|
298
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a()) || $ISBAD(b()) || $ISBAD(c())) continue;flag = 1;,) |
|
299
|
|
|
|
|
|
|
tmp += $a() * $b() * $c(); |
|
300
|
|
|
|
|
|
|
%} |
|
301
|
|
|
|
|
|
|
PDL_IF_BAD(if (!flag) { $SETBAD(d()); } |
|
302
|
|
|
|
|
|
|
else,) { $d() = tmp; } |
|
303
|
|
|
|
|
|
|
EOF |
|
304
|
|
|
|
|
|
|
Doc => ' |
|
305
|
|
|
|
|
|
|
=for ref |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Inner product of two vectors and a matrix |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
d = sum_ij a(i) b(i,j) c(j) |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Note that you should probably not broadcast over C and C since that would be |
|
312
|
|
|
|
|
|
|
very wasteful. Instead, you should use a temporary for C. |
|
313
|
|
|
|
|
|
|
' |
|
314
|
|
|
|
|
|
|
); |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
pp_def('inner2d', |
|
317
|
|
|
|
|
|
|
HandleBad => 1, |
|
318
|
|
|
|
|
|
|
Pars => 'a(n,m); b(n,m); [o]c();', |
|
319
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
320
|
|
|
|
|
|
|
Code => <<'EOF', |
|
321
|
|
|
|
|
|
|
complex long double tmp = 0; |
|
322
|
|
|
|
|
|
|
PDL_IF_BAD(int flag = 0;,) |
|
323
|
|
|
|
|
|
|
loop(n,m) %{ |
|
324
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a()) || $ISBAD(b())) continue;flag = 1;,) |
|
325
|
|
|
|
|
|
|
tmp += $a() * $b(); |
|
326
|
|
|
|
|
|
|
%} |
|
327
|
|
|
|
|
|
|
PDL_IF_BAD(if (!flag) { $SETBAD(c()); } |
|
328
|
|
|
|
|
|
|
else,) { $c() = tmp; } |
|
329
|
|
|
|
|
|
|
EOF |
|
330
|
|
|
|
|
|
|
Doc => ' |
|
331
|
|
|
|
|
|
|
=for ref |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
Inner product over 2 dimensions. |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Equivalent to |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
$c = inner($x->clump(2), $y->clump(2)) |
|
338
|
|
|
|
|
|
|
' |
|
339
|
|
|
|
|
|
|
); |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
pp_def('inner2t', |
|
342
|
|
|
|
|
|
|
HandleBad => 1, |
|
343
|
|
|
|
|
|
|
Pars => 'a(j,n); b(n,m); c(m,k); [t]tmp(n,k); [o]d(j,k);', |
|
344
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
345
|
|
|
|
|
|
|
Code => <<'EOF', |
|
346
|
|
|
|
|
|
|
loop(n,k) %{ |
|
347
|
|
|
|
|
|
|
complex long double tmp0 = 0; |
|
348
|
|
|
|
|
|
|
PDL_IF_BAD(int flag = 0;,) |
|
349
|
|
|
|
|
|
|
loop(m) %{ |
|
350
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(b()) || $ISBAD(c())) continue;flag = 1;,) |
|
351
|
|
|
|
|
|
|
tmp0 += $b() * $c(); |
|
352
|
|
|
|
|
|
|
%} |
|
353
|
|
|
|
|
|
|
PDL_IF_BAD(if (!flag) { $SETBAD(tmp()); } |
|
354
|
|
|
|
|
|
|
else,) { $tmp() = tmp0; } |
|
355
|
|
|
|
|
|
|
%} |
|
356
|
|
|
|
|
|
|
loop(j,k) %{ |
|
357
|
|
|
|
|
|
|
complex long double tmp1 = 0; |
|
358
|
|
|
|
|
|
|
PDL_IF_BAD(int flag = 0;,) |
|
359
|
|
|
|
|
|
|
loop(n) %{ |
|
360
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a()) || $ISBAD(tmp())) continue;flag = 1;,) |
|
361
|
|
|
|
|
|
|
tmp1 += $a() * $tmp(); |
|
362
|
|
|
|
|
|
|
%} |
|
363
|
|
|
|
|
|
|
PDL_IF_BAD(if (!flag) { $SETBAD(d()); } |
|
364
|
|
|
|
|
|
|
else,) { $d() = tmp1; } |
|
365
|
|
|
|
|
|
|
%} |
|
366
|
|
|
|
|
|
|
EOF |
|
367
|
|
|
|
|
|
|
Doc => ' |
|
368
|
|
|
|
|
|
|
=for ref |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
Efficient Triple matrix product C |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
Efficiency comes from by using the temporary C. This operation only |
|
373
|
|
|
|
|
|
|
scales as C whereas broadcasting using L would scale |
|
374
|
|
|
|
|
|
|
as C. |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
The reason for having this routine is that you do not need to |
|
377
|
|
|
|
|
|
|
have the same broadcast-dimensions for C as for the other arguments, |
|
378
|
|
|
|
|
|
|
which in case of large numbers of matrices makes this much more |
|
379
|
|
|
|
|
|
|
memory-efficient. |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
It is hoped that things like this could be taken care of as a kind of |
|
382
|
|
|
|
|
|
|
closure at some point. |
|
383
|
|
|
|
|
|
|
' |
|
384
|
|
|
|
|
|
|
); # pp_def inner2t() |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# a helper function for the cross product definition |
|
387
|
|
|
|
|
|
|
sub crassgn { |
|
388
|
|
|
|
|
|
|
"\$c(tri => $_[0]) = \$a(tri => $_[1])*\$b(tri => $_[2]) - |
|
389
|
|
|
|
|
|
|
\$a(tri => $_[2])*\$b(tri => $_[1]);" |
|
390
|
|
|
|
|
|
|
} |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
pp_def('crossp', |
|
393
|
|
|
|
|
|
|
Doc => <<'EOD', |
|
394
|
|
|
|
|
|
|
=for ref |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
Cross product of two 3D vectors |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
After |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=for example |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
$c = crossp $x, $y |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
the inner product C<$c*$x> and C<$c*$y> will be zero, i.e. C<$c> is |
|
405
|
|
|
|
|
|
|
orthogonal to C<$x> and C<$y> |
|
406
|
|
|
|
|
|
|
EOD |
|
407
|
|
|
|
|
|
|
Pars => 'a(tri=3); b(tri); [o] c(tri)', |
|
408
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
409
|
|
|
|
|
|
|
Code => |
|
410
|
|
|
|
|
|
|
crassgn(0,1,2)."\n". |
|
411
|
|
|
|
|
|
|
crassgn(1,2,0)."\n". |
|
412
|
|
|
|
|
|
|
crassgn(2,0,1), |
|
413
|
|
|
|
|
|
|
); |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
pp_def('norm', |
|
416
|
|
|
|
|
|
|
HandleBad => 1, |
|
417
|
|
|
|
|
|
|
Pars => 'vec(n); [o] norm(n)', |
|
418
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
419
|
|
|
|
|
|
|
Doc => 'Normalises a vector to unit Euclidean length |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
See also L, L. |
|
422
|
|
|
|
|
|
|
', |
|
423
|
|
|
|
|
|
|
Code => <<'EOF', |
|
424
|
|
|
|
|
|
|
long double sum=0; |
|
425
|
|
|
|
|
|
|
PDL_IF_BAD(int flag = 0;,) |
|
426
|
|
|
|
|
|
|
loop(n) %{ |
|
427
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(vec())) continue; flag = 1;,) |
|
428
|
|
|
|
|
|
|
sum += PDL_IF_GENTYPE_REAL( |
|
429
|
|
|
|
|
|
|
$vec()*$vec(), |
|
430
|
|
|
|
|
|
|
creall($vec())*creall($vec()) + cimagl($vec())*cimagl($vec()) |
|
431
|
|
|
|
|
|
|
); |
|
432
|
|
|
|
|
|
|
%} |
|
433
|
|
|
|
|
|
|
PDL_IF_BAD(if ( !flag ) { |
|
434
|
|
|
|
|
|
|
loop(n) %{ $SETBAD(norm()); %} |
|
435
|
|
|
|
|
|
|
continue; |
|
436
|
|
|
|
|
|
|
},) |
|
437
|
|
|
|
|
|
|
if (sum > 0) { |
|
438
|
|
|
|
|
|
|
sum = sqrtl(sum); |
|
439
|
|
|
|
|
|
|
loop(n) %{ |
|
440
|
|
|
|
|
|
|
PDL_IF_BAD(if ( $ISBAD(vec()) ) { $SETBAD(norm()); } |
|
441
|
|
|
|
|
|
|
else ,) { $norm() = $vec()/sum; } |
|
442
|
|
|
|
|
|
|
%} |
|
443
|
|
|
|
|
|
|
} else { |
|
444
|
|
|
|
|
|
|
loop(n) %{ |
|
445
|
|
|
|
|
|
|
PDL_IF_BAD(if ( $ISBAD(vec()) ) { $SETBAD(norm()); } |
|
446
|
|
|
|
|
|
|
else ,) { $norm() = $vec(); } |
|
447
|
|
|
|
|
|
|
%} |
|
448
|
|
|
|
|
|
|
} |
|
449
|
|
|
|
|
|
|
EOF |
|
450
|
|
|
|
|
|
|
); |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# this one was motivated by the need to compute |
|
453
|
|
|
|
|
|
|
# the circular mean efficiently |
|
454
|
|
|
|
|
|
|
# without it could not be done efficiently or without |
|
455
|
|
|
|
|
|
|
# creating large intermediates (check pdl-porters for |
|
456
|
|
|
|
|
|
|
# discussion) |
|
457
|
|
|
|
|
|
|
# see PDL::ImageND for info about the circ_mean function |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
pp_def( |
|
460
|
|
|
|
|
|
|
'indadd', |
|
461
|
|
|
|
|
|
|
HandleBad => 1, |
|
462
|
|
|
|
|
|
|
Pars => 'input(n); indx ind(n); [io] sum(m)', |
|
463
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
464
|
|
|
|
|
|
|
Code => <<'EOF', |
|
465
|
|
|
|
|
|
|
loop(n) %{ |
|
466
|
|
|
|
|
|
|
register PDL_Indx this_ind = $ind(); |
|
467
|
|
|
|
|
|
|
PDL_IF_BAD( |
|
468
|
|
|
|
|
|
|
if ($ISBADVAR(this_ind,ind)) $CROAK("bad index %"IND_FLAG, n); |
|
469
|
|
|
|
|
|
|
if ($ISBAD(input())) { $SETBAD(sum(m => this_ind)); continue; },) |
|
470
|
|
|
|
|
|
|
if (this_ind<0 || this_ind>=$SIZE(m)) |
|
471
|
|
|
|
|
|
|
$CROAK("invalid index %"IND_FLAG"; range 0..%"IND_FLAG, this_ind, $SIZE(m)); |
|
472
|
|
|
|
|
|
|
$sum(m => this_ind) += $input(); |
|
473
|
|
|
|
|
|
|
%} |
|
474
|
|
|
|
|
|
|
EOF |
|
475
|
|
|
|
|
|
|
BadDoc => 'The routine barfs on bad indices, and bad inputs set target outputs bad.', |
|
476
|
|
|
|
|
|
|
Doc=>' |
|
477
|
|
|
|
|
|
|
=for ref |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
Broadcasting index add: add C to the C element of C, i.e: |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sum(ind) += input |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=for example |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Simple example: |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
$x = 2; |
|
488
|
|
|
|
|
|
|
$ind = 3; |
|
489
|
|
|
|
|
|
|
$sum = zeroes(10); |
|
490
|
|
|
|
|
|
|
indadd($x,$ind, $sum); |
|
491
|
|
|
|
|
|
|
print $sum |
|
492
|
|
|
|
|
|
|
#Result: ( 2 added to element 3 of $sum) |
|
493
|
|
|
|
|
|
|
# [0 0 0 2 0 0 0 0 0 0] |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
Broadcasting example: |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
$x = pdl( 1,2,3); |
|
498
|
|
|
|
|
|
|
$ind = pdl( 1,4,6); |
|
499
|
|
|
|
|
|
|
$sum = zeroes(10); |
|
500
|
|
|
|
|
|
|
indadd($x,$ind, $sum); |
|
501
|
|
|
|
|
|
|
print $sum."\n"; |
|
502
|
|
|
|
|
|
|
#Result: ( 1, 2, and 3 added to elements 1,4,6 $sum) |
|
503
|
|
|
|
|
|
|
# [0 1 0 0 2 0 3 0 0 0] |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=cut |
|
506
|
|
|
|
|
|
|
'); |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
# 1D convolution |
|
509
|
|
|
|
|
|
|
# useful for broadcasted 1D filters |
|
510
|
|
|
|
|
|
|
pp_def('conv1d', |
|
511
|
|
|
|
|
|
|
Doc => << 'EOD', |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=for ref |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
1D convolution along first dimension |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
The m-th element of the discrete convolution of an input ndarray |
|
518
|
|
|
|
|
|
|
C<$a> of size C<$M>, and a kernel ndarray C<$kern> of size C<$P>, is |
|
519
|
|
|
|
|
|
|
calculated as |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
n = ($P-1)/2 |
|
522
|
|
|
|
|
|
|
==== |
|
523
|
|
|
|
|
|
|
\ |
|
524
|
|
|
|
|
|
|
($a conv1d $kern)[m] = > $a_ext[m - n] * $kern[n] |
|
525
|
|
|
|
|
|
|
/ |
|
526
|
|
|
|
|
|
|
==== |
|
527
|
|
|
|
|
|
|
n = -($P-1)/2 |
|
528
|
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
where C<$a_ext> is either the periodic (or reflected) extension of |
|
530
|
|
|
|
|
|
|
C<$a> so it is equal to C<$a> on C< 0..$M-1 > and equal to the |
|
531
|
|
|
|
|
|
|
corresponding periodic/reflected image of C<$a> outside that range. |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=for example |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
$con = conv1d sequence(10), pdl(-1,0,1); |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
$con = conv1d sequence(10), pdl(-1,0,1), {Boundary => 'reflect'}; |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
By default, periodic boundary conditions are assumed (i.e. wrap around). |
|
541
|
|
|
|
|
|
|
Alternatively, you can request reflective boundary conditions using |
|
542
|
|
|
|
|
|
|
the C option: |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
{Boundary => 'reflect'} # case in 'reflect' doesn't matter |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
The convolution is performed along the first dimension. To apply it across |
|
547
|
|
|
|
|
|
|
another dimension use the slicing routines, e.g. |
|
548
|
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
$y = $x->mv(2,0)->conv1d($kernel)->mv(0,2); # along third dim |
|
550
|
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
This function is useful for broadcasted filtering of 1D signals. |
|
552
|
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
Compare also L, L, |
|
554
|
|
|
|
|
|
|
L |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=for bad |
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
WARNING: C processes bad values in its inputs as |
|
559
|
|
|
|
|
|
|
the numeric value of C<< $pdl->badvalue >> so it is not |
|
560
|
|
|
|
|
|
|
recommended for processing pdls with bad values in them |
|
561
|
|
|
|
|
|
|
unless special care is taken. |
|
562
|
|
|
|
|
|
|
EOD |
|
563
|
|
|
|
|
|
|
Pars => 'a(m); kern(p); [o]b(m);', |
|
564
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
565
|
|
|
|
|
|
|
OtherPars => 'int reflect;', |
|
566
|
|
|
|
|
|
|
HandleBad => 0, |
|
567
|
|
|
|
|
|
|
PMCode => pp_line_numbers(__LINE__, <<'EOPM'), |
|
568
|
|
|
|
|
|
|
sub PDL::conv1d { |
|
569
|
|
|
|
|
|
|
my $opt = pop @_ if ref($_[-1]) eq 'HASH'; |
|
570
|
|
|
|
|
|
|
die 'Usage: conv1d( a(m), kern(p), [o]b(m), {Options} )' |
|
571
|
|
|
|
|
|
|
if @_<2 || @_>3; |
|
572
|
|
|
|
|
|
|
my($x,$kern) = @_; |
|
573
|
|
|
|
|
|
|
my $c = @_ == 3 ? $_[2] : PDL->null; |
|
574
|
|
|
|
|
|
|
PDL::_conv1d_int($x,$kern,$c, |
|
575
|
|
|
|
|
|
|
!(defined $opt && exists $$opt{Boundary}) ? 0 : |
|
576
|
|
|
|
|
|
|
lc $$opt{Boundary} eq "reflect"); |
|
577
|
|
|
|
|
|
|
return $c; |
|
578
|
|
|
|
|
|
|
} |
|
579
|
|
|
|
|
|
|
EOPM |
|
580
|
|
|
|
|
|
|
CHeader => ' |
|
581
|
|
|
|
|
|
|
/* Fast Modulus with proper negative behaviour */ |
|
582
|
|
|
|
|
|
|
#define REALMOD(a,b) while ((a)>=(b)) (a) -= (b); while ((a)<0) (a) += (b); |
|
583
|
|
|
|
|
|
|
', |
|
584
|
|
|
|
|
|
|
Code => ' |
|
585
|
|
|
|
|
|
|
int reflect = $COMP(reflect); |
|
586
|
|
|
|
|
|
|
PDL_Indx m_size = $SIZE(m), p_size = $SIZE(p); |
|
587
|
|
|
|
|
|
|
PDL_Indx poff = (p_size-1)/2; |
|
588
|
|
|
|
|
|
|
loop(m) %{ |
|
589
|
|
|
|
|
|
|
complex long double tmp = 0; |
|
590
|
|
|
|
|
|
|
loop(p) %{ |
|
591
|
|
|
|
|
|
|
PDL_Indx pflip = p_size - 1 - p, i2 = m+p - poff; |
|
592
|
|
|
|
|
|
|
if (reflect && i2<0) |
|
593
|
|
|
|
|
|
|
i2 = -i2; |
|
594
|
|
|
|
|
|
|
if (reflect && i2>=m_size) |
|
595
|
|
|
|
|
|
|
i2 = m_size-(i2-m_size+1); |
|
596
|
|
|
|
|
|
|
REALMOD(i2,m_size); |
|
597
|
|
|
|
|
|
|
tmp += $a(m=>i2) * $kern(p=>pflip); |
|
598
|
|
|
|
|
|
|
%} |
|
599
|
|
|
|
|
|
|
$b() = tmp; |
|
600
|
|
|
|
|
|
|
%} |
|
601
|
|
|
|
|
|
|
'); |
|
602
|
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
# this can be achieved by |
|
605
|
|
|
|
|
|
|
# ($x->dummy(0) == $y)->orover |
|
606
|
|
|
|
|
|
|
# but this one avoids a larger intermediate and potentially shortcuts |
|
607
|
|
|
|
|
|
|
pp_def('in', |
|
608
|
|
|
|
|
|
|
Pars => 'a(); b(n); [o] c()', |
|
609
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
610
|
|
|
|
|
|
|
Code => '$c() = 0; |
|
611
|
|
|
|
|
|
|
loop(n) %{ if ($a() == $b()) {$c() = 1; break;} %}', |
|
612
|
|
|
|
|
|
|
Doc => <<'EOD', |
|
613
|
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
=for ref |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
test if a is in the set of values b |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
=for example |
|
619
|
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
$goodmsk = $labels->in($goodlabels); |
|
621
|
|
|
|
|
|
|
print pdl(3,1,4,6,2)->in(pdl(2,3,3)); |
|
622
|
|
|
|
|
|
|
[1 0 0 0 1] |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
C is akin to the I of set theory. In principle, |
|
625
|
|
|
|
|
|
|
PDL broadcasting could be used to achieve its functionality by using a |
|
626
|
|
|
|
|
|
|
construct like |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
$msk = ($labels->dummy(0) == $goodlabels)->orover; |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
However, C doesn't create a (potentially large) intermediate |
|
631
|
|
|
|
|
|
|
and is generally faster. |
|
632
|
|
|
|
|
|
|
EOD |
|
633
|
|
|
|
|
|
|
); |
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
pp_add_exported ('', 'uniq'); |
|
636
|
|
|
|
|
|
|
pp_addpm (<< 'EOPM'); |
|
637
|
|
|
|
|
|
|
=head2 uniq |
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=for ref |
|
640
|
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
return all unique elements of an ndarray |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
The unique elements are returned in ascending order. |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=for example |
|
646
|
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
PDL> p pdl(2,2,2,4,0,-1,6,6)->uniq |
|
648
|
|
|
|
|
|
|
[-1 0 2 4 6] # 0 is returned 2nd (sorted order) |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
PDL> p pdl(2,2,2,4,nan,-1,6,6)->uniq |
|
651
|
|
|
|
|
|
|
[-1 2 4 6 nan] # NaN value is returned at end |
|
652
|
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
Note: The returned pdl is 1D; any structure of the input |
|
654
|
|
|
|
|
|
|
ndarray is lost. C values are never compare equal to |
|
655
|
|
|
|
|
|
|
any other values, even themselves. As a result, they are |
|
656
|
|
|
|
|
|
|
always unique. C returns the NaN values at the end |
|
657
|
|
|
|
|
|
|
of the result ndarray. This follows the Matlab usage. |
|
658
|
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
See L if you need the indices of the unique |
|
660
|
|
|
|
|
|
|
elements rather than the values. |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=for bad |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
Bad values are not considered unique by uniq and are ignored. |
|
665
|
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
$x=sequence(10); |
|
667
|
|
|
|
|
|
|
$x=$x->setbadif($x%3); |
|
668
|
|
|
|
|
|
|
print $x->uniq; |
|
669
|
|
|
|
|
|
|
[0 3 6 9] |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
=cut |
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
*uniq = \&PDL::uniq; |
|
674
|
|
|
|
|
|
|
# return unique elements of array |
|
675
|
|
|
|
|
|
|
# find as jumps in the sorted array |
|
676
|
|
|
|
|
|
|
# flattens in the process |
|
677
|
|
|
|
|
|
|
sub PDL::uniq { |
|
678
|
|
|
|
|
|
|
my ($arr) = @_; |
|
679
|
|
|
|
|
|
|
return $arr if($arr->nelem == 0); # The null list is unique (CED) |
|
680
|
|
|
|
|
|
|
return $arr->flat if($arr->nelem == 1); # singleton list is unique |
|
681
|
|
|
|
|
|
|
my $aflat = $arr->flat; |
|
682
|
|
|
|
|
|
|
my $srt = $aflat->where($aflat==$aflat)->qsort; # no NaNs or BADs for qsort |
|
683
|
|
|
|
|
|
|
my $nans = $aflat->where($aflat!=$aflat); |
|
684
|
|
|
|
|
|
|
my $uniq = ($srt->nelem > 1) ? $srt->where($srt != $srt->rotate(-1)) : $srt; |
|
685
|
|
|
|
|
|
|
# make sure we return something if there is only one value |
|
686
|
|
|
|
|
|
|
( |
|
687
|
|
|
|
|
|
|
$uniq->nelem > 0 ? $uniq : |
|
688
|
|
|
|
|
|
|
$srt->nelem == 0 ? $srt : |
|
689
|
|
|
|
|
|
|
PDL::pdl( ref($srt), [$srt->index(0)] ) |
|
690
|
|
|
|
|
|
|
)->append($nans); |
|
691
|
|
|
|
|
|
|
} |
|
692
|
|
|
|
|
|
|
EOPM |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
pp_add_exported ('', 'uniqind'); |
|
695
|
|
|
|
|
|
|
pp_addpm (<< 'EOPM'); |
|
696
|
|
|
|
|
|
|
=head2 uniqind |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
=for ref |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
Return the indices of all unique elements of an ndarray |
|
701
|
|
|
|
|
|
|
The order is in the order of the values to be consistent |
|
702
|
|
|
|
|
|
|
with uniq. C values never compare equal with any |
|
703
|
|
|
|
|
|
|
other value and so are always unique. This follows the |
|
704
|
|
|
|
|
|
|
Matlab usage. |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=for example |
|
707
|
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
PDL> p pdl(2,2,2,4,0,-1,6,6)->uniqind |
|
709
|
|
|
|
|
|
|
[5 4 1 3 6] # the 0 at index 4 is returned 2nd, but... |
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
PDL> p pdl(2,2,2,4,nan,-1,6,6)->uniqind |
|
712
|
|
|
|
|
|
|
[5 1 3 6 4] # ...the NaN at index 4 is returned at end |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
Note: The returned pdl is 1D; any structure of the input |
|
716
|
|
|
|
|
|
|
ndarray is lost. |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
See L if you want the unique values instead of the |
|
719
|
|
|
|
|
|
|
indices. |
|
720
|
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
=for bad |
|
722
|
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
Bad values are not considered unique by uniqind and are ignored. |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=cut |
|
726
|
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
*uniqind = \&PDL::uniqind; |
|
728
|
|
|
|
|
|
|
# return unique elements of array |
|
729
|
|
|
|
|
|
|
# find as jumps in the sorted array |
|
730
|
|
|
|
|
|
|
# flattens in the process |
|
731
|
|
|
|
|
|
|
sub PDL::uniqind { |
|
732
|
|
|
|
|
|
|
use PDL::Core 'barf'; |
|
733
|
|
|
|
|
|
|
my ($arr) = @_; |
|
734
|
|
|
|
|
|
|
return $arr if($arr->nelem == 0); # The null list is unique (CED) |
|
735
|
|
|
|
|
|
|
# Different from uniq we sort and store the result in an intermediary |
|
736
|
|
|
|
|
|
|
my $aflat = $arr->flat; |
|
737
|
|
|
|
|
|
|
my $nanind = which($aflat!=$aflat); # NaN indexes |
|
738
|
|
|
|
|
|
|
my $good = PDL->sequence(indx, $aflat->dims)->where($aflat==$aflat); # good indexes |
|
739
|
|
|
|
|
|
|
my $i_srt = $aflat->where($aflat==$aflat)->qsorti; # no BAD or NaN values for qsorti |
|
740
|
|
|
|
|
|
|
my $srt = $aflat->where($aflat==$aflat)->index($i_srt); |
|
741
|
|
|
|
|
|
|
my $uniqind; |
|
742
|
|
|
|
|
|
|
if ($srt->nelem > 0) { |
|
743
|
|
|
|
|
|
|
$uniqind = which($srt != $srt->rotate(-1)); |
|
744
|
|
|
|
|
|
|
$uniqind = $i_srt->slice('0') if $uniqind->isempty; |
|
745
|
|
|
|
|
|
|
} else { |
|
746
|
|
|
|
|
|
|
$uniqind = which($srt); |
|
747
|
|
|
|
|
|
|
} |
|
748
|
|
|
|
|
|
|
# Now map back to the original space |
|
749
|
|
|
|
|
|
|
my $ansind = $nanind; |
|
750
|
|
|
|
|
|
|
if ( $uniqind->nelem > 0 ) { |
|
751
|
|
|
|
|
|
|
$ansind = ($good->index($i_srt->index($uniqind)))->append($ansind); |
|
752
|
|
|
|
|
|
|
} else { |
|
753
|
|
|
|
|
|
|
$ansind = $uniqind->append($ansind); |
|
754
|
|
|
|
|
|
|
} |
|
755
|
|
|
|
|
|
|
return $ansind; |
|
756
|
|
|
|
|
|
|
} |
|
757
|
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
EOPM |
|
759
|
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
pp_add_exported ('', 'uniqvec'); |
|
761
|
|
|
|
|
|
|
pp_addpm (<< 'EOPM'); |
|
762
|
|
|
|
|
|
|
=head2 uniqvec |
|
763
|
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
=for ref |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
Return all unique vectors out of a collection |
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
NOTE: If any vectors in the input ndarray have NaN values |
|
769
|
|
|
|
|
|
|
they are returned at the end of the non-NaN ones. This is |
|
770
|
|
|
|
|
|
|
because, by definition, NaN values never compare equal with |
|
771
|
|
|
|
|
|
|
any other value. |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
NOTE: The current implementation does not sort the vectors |
|
774
|
|
|
|
|
|
|
containing NaN values. |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
The unique vectors are returned in lexicographically sorted |
|
777
|
|
|
|
|
|
|
ascending order. The 0th dimension of the input PDL is treated |
|
778
|
|
|
|
|
|
|
as a dimensional index within each vector, and the 1st and any |
|
779
|
|
|
|
|
|
|
higher dimensions are taken to run across vectors. The return |
|
780
|
|
|
|
|
|
|
value is always 2D; any structure of the input PDL (beyond using |
|
781
|
|
|
|
|
|
|
the 0th dimension for vector index) is lost. |
|
782
|
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
See also L for a unique list of scalars; and |
|
784
|
|
|
|
|
|
|
L for sorting a list of vectors |
|
785
|
|
|
|
|
|
|
lexicographcally. |
|
786
|
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
=for bad |
|
788
|
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
If a vector contains all bad values, it is ignored as in L. |
|
790
|
|
|
|
|
|
|
If some of the values are good, it is treated as a normal vector. For |
|
791
|
|
|
|
|
|
|
example, [1 2 BAD] and [BAD 2 3] could be returned, but [BAD BAD BAD] |
|
792
|
|
|
|
|
|
|
could not. Vectors containing BAD values will be returned after any |
|
793
|
|
|
|
|
|
|
non-NaN and non-BAD containing vectors, followed by the NaN vectors. |
|
794
|
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
=cut |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
sub PDL::uniqvec { |
|
798
|
|
|
|
|
|
|
my($pdl) = shift; |
|
799
|
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
return $pdl if ( $pdl->nelem == 0 || $pdl->ndims < 2 ); |
|
801
|
|
|
|
|
|
|
return $pdl if ( $pdl->slice("(0)")->nelem < 2 ); # slice isn't cheap but uniqvec isn't either |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
my $pdl2d = $pdl->clump(1..$pdl->ndims-1); |
|
804
|
|
|
|
|
|
|
my $ngood = $pdl2d->ngoodover; |
|
805
|
|
|
|
|
|
|
$pdl2d = $pdl2d->mv(0,-1)->dice($ngood->which)->mv(-1,0); # remove all-BAD vectors |
|
806
|
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
my $numnan = ($pdl2d!=$pdl2d)->sumover; # works since no all-BADs to confuse |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
my $presrt = $pdl2d->mv(0,-1)->dice($numnan->not->which)->mv(0,-1); # remove vectors with any NaN values |
|
810
|
|
|
|
|
|
|
my $nanvec = $pdl2d->mv(0,-1)->dice($numnan->which)->mv(0,-1); # the vectors with any NaN values |
|
811
|
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
my $srt = $presrt->qsortvec->mv(0,-1); # BADs are sorted by qsortvec |
|
813
|
|
|
|
|
|
|
my $srtdice = $srt; |
|
814
|
|
|
|
|
|
|
my $somebad = null; |
|
815
|
|
|
|
|
|
|
if ($srt->badflag) { |
|
816
|
|
|
|
|
|
|
$srtdice = $srt->dice($srt->mv(0,-1)->nbadover->not->which); |
|
817
|
|
|
|
|
|
|
$somebad = $srt->dice($srt->mv(0,-1)->nbadover->which); |
|
818
|
|
|
|
|
|
|
} |
|
819
|
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
my $uniq = $srtdice->nelem > 0 |
|
821
|
|
|
|
|
|
|
? ($srtdice != $srtdice->rotate(-1))->mv(0,-1)->orover->which |
|
822
|
|
|
|
|
|
|
: $srtdice->orover->which; |
|
823
|
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
my $ans = $uniq->nelem > 0 ? $srtdice->dice($uniq) : |
|
825
|
|
|
|
|
|
|
($srtdice->nelem > 0) ? $srtdice->slice("0,:") : |
|
826
|
|
|
|
|
|
|
$srtdice; |
|
827
|
|
|
|
|
|
|
return $ans->append($somebad)->append($nanvec->mv(0,-1))->mv(0,-1); |
|
828
|
|
|
|
|
|
|
} |
|
829
|
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
EOPM |
|
831
|
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
##################################################################### |
|
833
|
|
|
|
|
|
|
# clipping routines |
|
834
|
|
|
|
|
|
|
##################################################################### |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
# clipping |
|
837
|
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
for my $opt ( |
|
839
|
|
|
|
|
|
|
['hclip','PDLMIN'], |
|
840
|
|
|
|
|
|
|
['lclip','PDLMAX'] |
|
841
|
|
|
|
|
|
|
) { |
|
842
|
|
|
|
|
|
|
my $name = $opt->[0]; |
|
843
|
|
|
|
|
|
|
my $op = $opt->[1]; |
|
844
|
|
|
|
|
|
|
my $code = '$c() = '.$op.'($b(), $a());'; |
|
845
|
|
|
|
|
|
|
pp_def( |
|
846
|
|
|
|
|
|
|
$name, |
|
847
|
|
|
|
|
|
|
HandleBad => 1, |
|
848
|
|
|
|
|
|
|
Pars => 'a(); b(); [o] c()', |
|
849
|
|
|
|
|
|
|
Code => |
|
850
|
|
|
|
|
|
|
'PDL_IF_BAD(if ( $ISBAD(a()) || $ISBAD(b()) ) { |
|
851
|
|
|
|
|
|
|
$SETBAD(c()); |
|
852
|
|
|
|
|
|
|
} else,) { '.$code.' }', |
|
853
|
|
|
|
|
|
|
Doc => 'clip (threshold) C<$a> by C<$b> (C<$b> is '. |
|
854
|
|
|
|
|
|
|
($name eq 'hclip' ? 'upper' : 'lower').' bound)', |
|
855
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<"EOD"), |
|
856
|
|
|
|
|
|
|
sub PDL::$name { |
|
857
|
|
|
|
|
|
|
my (\$x,\$y) = \@_; |
|
858
|
|
|
|
|
|
|
my \$c; |
|
859
|
|
|
|
|
|
|
if (\$x->is_inplace) { |
|
860
|
|
|
|
|
|
|
\$x->set_inplace(0); \$c = \$x; |
|
861
|
|
|
|
|
|
|
} elsif (\@_ > 2) {\$c=\$_[2]} else {\$c=PDL->nullcreate(\$x)} |
|
862
|
|
|
|
|
|
|
PDL::_${name}_int(\$x,\$y,\$c); |
|
863
|
|
|
|
|
|
|
return \$c; |
|
864
|
|
|
|
|
|
|
} |
|
865
|
|
|
|
|
|
|
EOD |
|
866
|
|
|
|
|
|
|
); # pp_def $name |
|
867
|
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
} # for: my $opt |
|
869
|
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
pp_def('clip', |
|
871
|
|
|
|
|
|
|
HandleBad => 1, |
|
872
|
|
|
|
|
|
|
Pars => 'a(); l(); h(); [o] c()', |
|
873
|
|
|
|
|
|
|
Code => <<'EOBC', |
|
874
|
|
|
|
|
|
|
PDL_IF_BAD( |
|
875
|
|
|
|
|
|
|
if( $ISBAD(a()) || $ISBAD(l()) || $ISBAD(h()) ) { |
|
876
|
|
|
|
|
|
|
$SETBAD(c()); |
|
877
|
|
|
|
|
|
|
} else,) { |
|
878
|
|
|
|
|
|
|
$c() = PDLMIN($h(), PDLMAX($l(), $a())); |
|
879
|
|
|
|
|
|
|
} |
|
880
|
|
|
|
|
|
|
EOBC |
|
881
|
|
|
|
|
|
|
Doc => <<'EOD', |
|
882
|
|
|
|
|
|
|
=for ref |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
Clip (threshold) an ndarray by (optional) upper or lower bounds. |
|
885
|
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
=for usage |
|
887
|
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
$y = $x->clip(0,3); |
|
889
|
|
|
|
|
|
|
$c = $x->clip(undef, $x); |
|
890
|
|
|
|
|
|
|
EOD |
|
891
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOPM'), |
|
892
|
|
|
|
|
|
|
*clip = \&PDL::clip; |
|
893
|
|
|
|
|
|
|
sub PDL::clip { |
|
894
|
|
|
|
|
|
|
my($x, $l, $h) = @_; |
|
895
|
|
|
|
|
|
|
my $d; |
|
896
|
|
|
|
|
|
|
unless(defined($l) || defined($h)) { |
|
897
|
|
|
|
|
|
|
# Deal with pathological case |
|
898
|
|
|
|
|
|
|
if($x->is_inplace) { |
|
899
|
|
|
|
|
|
|
$x->set_inplace(0); |
|
900
|
|
|
|
|
|
|
return $x; |
|
901
|
|
|
|
|
|
|
} else { |
|
902
|
|
|
|
|
|
|
return $x->copy; |
|
903
|
|
|
|
|
|
|
} |
|
904
|
|
|
|
|
|
|
} |
|
905
|
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
if($x->is_inplace) { |
|
907
|
|
|
|
|
|
|
$x->set_inplace(0); $d = $x |
|
908
|
|
|
|
|
|
|
} elsif (@_ > 3) { |
|
909
|
|
|
|
|
|
|
$d=$_[3] |
|
910
|
|
|
|
|
|
|
} else { |
|
911
|
|
|
|
|
|
|
$d = PDL->nullcreate($x); |
|
912
|
|
|
|
|
|
|
} |
|
913
|
|
|
|
|
|
|
if(defined($l) && defined($h)) { |
|
914
|
|
|
|
|
|
|
PDL::_clip_int($x,$l,$h,$d); |
|
915
|
|
|
|
|
|
|
} elsif( defined($l) ) { |
|
916
|
|
|
|
|
|
|
PDL::_lclip_int($x,$l,$d); |
|
917
|
|
|
|
|
|
|
} elsif( defined($h) ) { |
|
918
|
|
|
|
|
|
|
PDL::_hclip_int($x,$h,$d); |
|
919
|
|
|
|
|
|
|
} else { |
|
920
|
|
|
|
|
|
|
die "This can't happen (clip contingency) - file a bug"; |
|
921
|
|
|
|
|
|
|
} |
|
922
|
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
return $d; |
|
924
|
|
|
|
|
|
|
} |
|
925
|
|
|
|
|
|
|
EOPM |
|
926
|
|
|
|
|
|
|
); # end of clip pp_def call |
|
927
|
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
############################################################ |
|
929
|
|
|
|
|
|
|
# elementary statistics and histograms |
|
930
|
|
|
|
|
|
|
############################################################ |
|
931
|
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
pp_def('wtstat', |
|
933
|
|
|
|
|
|
|
HandleBad => 1, |
|
934
|
|
|
|
|
|
|
Pars => 'a(n); wt(n); avg(); [o]b();', |
|
935
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
936
|
|
|
|
|
|
|
OtherPars => 'int deg', |
|
937
|
|
|
|
|
|
|
Code => <<'EOF', |
|
938
|
|
|
|
|
|
|
complex long double wtsum = 0; |
|
939
|
|
|
|
|
|
|
complex long double statsum = 0; |
|
940
|
|
|
|
|
|
|
PDL_IF_BAD(int flag = 0;,) |
|
941
|
|
|
|
|
|
|
loop(n) %{ |
|
942
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(wt()) || $ISBAD(a()) || $ISBAD(avg())) continue;flag = 1;,) |
|
943
|
|
|
|
|
|
|
PDL_Indx i; |
|
944
|
|
|
|
|
|
|
wtsum += $wt(); |
|
945
|
|
|
|
|
|
|
complex long double tmp=1; |
|
946
|
|
|
|
|
|
|
for(i=0; i<$COMP(deg); i++) |
|
947
|
|
|
|
|
|
|
tmp *= $a(); |
|
948
|
|
|
|
|
|
|
statsum += $wt() * (tmp - $avg()); |
|
949
|
|
|
|
|
|
|
%} |
|
950
|
|
|
|
|
|
|
PDL_IF_BAD(if (!flag) { $SETBAD(b()); $PDLSTATESETBAD(b); } |
|
951
|
|
|
|
|
|
|
else,) { $b() = statsum / wtsum; } |
|
952
|
|
|
|
|
|
|
EOF |
|
953
|
|
|
|
|
|
|
Doc => ' |
|
954
|
|
|
|
|
|
|
=for ref |
|
955
|
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
Weighted statistical moment of given degree |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
This calculates a weighted statistic over the vector C. |
|
959
|
|
|
|
|
|
|
The formula is |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
b() = (sum_i wt_i * (a_i ** degree - avg)) / (sum_i wt_i) |
|
962
|
|
|
|
|
|
|
', |
|
963
|
|
|
|
|
|
|
BadDoc => ' |
|
964
|
|
|
|
|
|
|
Bad values are ignored in any calculation; C<$b> will only |
|
965
|
|
|
|
|
|
|
have its bad flag set if the output contains any bad data. |
|
966
|
|
|
|
|
|
|
', |
|
967
|
|
|
|
|
|
|
); |
|
968
|
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
pp_def('statsover', |
|
970
|
|
|
|
|
|
|
HandleBad => 1, |
|
971
|
|
|
|
|
|
|
Pars => 'a(n); w(n); float+ [o]avg(); float+ [o]prms(); int+ [o]min(); int+ [o]max(); float+ [o]adev(); float+ [o]rms()', |
|
972
|
|
|
|
|
|
|
Code => <<'EOF', |
|
973
|
|
|
|
|
|
|
PDL_IF_GENTYPE_REAL(PDL_LDouble,PDL_CLDouble) tmp = 0, tmp1 = 0, diff = 0; |
|
974
|
|
|
|
|
|
|
$GENERIC(min) curmin = 0, curmax = 0; |
|
975
|
|
|
|
|
|
|
$GENERIC(w) norm = 0; |
|
976
|
|
|
|
|
|
|
int flag = 0; |
|
977
|
|
|
|
|
|
|
loop(n) %{ /* Accumulate sum and summed weight. */ |
|
978
|
|
|
|
|
|
|
/* perhaps should check w() for bad values too ? */ |
|
979
|
|
|
|
|
|
|
PDL_IF_BAD(if (!( $ISGOOD(a()) )) continue;,) |
|
980
|
|
|
|
|
|
|
tmp += $a()*$w(); |
|
981
|
|
|
|
|
|
|
norm += ($GENERIC(avg)) $w(); |
|
982
|
|
|
|
|
|
|
if (!flag) { curmin = $a(); curmax = $a(); flag=1; } |
|
983
|
|
|
|
|
|
|
if ($a() < curmin) { |
|
984
|
|
|
|
|
|
|
curmin = $a(); |
|
985
|
|
|
|
|
|
|
} else if ($a() > curmax) { |
|
986
|
|
|
|
|
|
|
curmax = $a(); |
|
987
|
|
|
|
|
|
|
} |
|
988
|
|
|
|
|
|
|
%} |
|
989
|
|
|
|
|
|
|
/* have at least one valid point if flag true */ |
|
990
|
|
|
|
|
|
|
PDL_IF_BAD(if ( !flag ) { |
|
991
|
|
|
|
|
|
|
$SETBAD(avg()); $PDLSTATESETBAD(avg); |
|
992
|
|
|
|
|
|
|
$SETBAD(rms()); $PDLSTATESETBAD(rms); |
|
993
|
|
|
|
|
|
|
$SETBAD(adev()); $PDLSTATESETBAD(adev); |
|
994
|
|
|
|
|
|
|
$SETBAD(min()); $PDLSTATESETBAD(min); |
|
995
|
|
|
|
|
|
|
$SETBAD(max()); $PDLSTATESETBAD(max); |
|
996
|
|
|
|
|
|
|
$SETBAD(prms()); $PDLSTATESETBAD(prms); |
|
997
|
|
|
|
|
|
|
continue; |
|
998
|
|
|
|
|
|
|
},) |
|
999
|
|
|
|
|
|
|
$avg() = tmp / norm; /* Find mean */ |
|
1000
|
|
|
|
|
|
|
$min() = curmin; |
|
1001
|
|
|
|
|
|
|
$max() = curmax; |
|
1002
|
|
|
|
|
|
|
/* Calculate the RMS and standard deviation. */ |
|
1003
|
|
|
|
|
|
|
tmp = 0; |
|
1004
|
|
|
|
|
|
|
loop(n) %{ |
|
1005
|
|
|
|
|
|
|
PDL_IF_BAD(if (!$ISGOOD(a())) continue;,) |
|
1006
|
|
|
|
|
|
|
diff = $a()-$avg(); |
|
1007
|
|
|
|
|
|
|
tmp += diff * diff * $w(); |
|
1008
|
|
|
|
|
|
|
tmp1 += PDL_IF_GENTYPE_REAL(fabsl,cabsl)(diff) * $w(); |
|
1009
|
|
|
|
|
|
|
%} |
|
1010
|
|
|
|
|
|
|
$rms() = sqrtl( tmp/norm ); |
|
1011
|
|
|
|
|
|
|
if (norm>1) |
|
1012
|
|
|
|
|
|
|
$prms() = sqrtl( tmp/(norm-1) ); |
|
1013
|
|
|
|
|
|
|
else |
|
1014
|
|
|
|
|
|
|
PDL_IF_BAD($SETBAD(prms()),$prms() = 0); |
|
1015
|
|
|
|
|
|
|
$adev() = tmp1 / norm ; |
|
1016
|
|
|
|
|
|
|
EOF |
|
1017
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOPM'), |
|
1018
|
|
|
|
|
|
|
sub PDL::statsover { |
|
1019
|
|
|
|
|
|
|
barf('Usage: ($mean,[$prms, $median, $min, $max, $adev, $rms]) = statsover($data,[$weights])') if @_>2; |
|
1020
|
|
|
|
|
|
|
my ($data, $weights) = @_; |
|
1021
|
|
|
|
|
|
|
$weights //= $data->ones(); |
|
1022
|
|
|
|
|
|
|
my $median = $data->medover; |
|
1023
|
|
|
|
|
|
|
my $mean = PDL->nullcreate($data); |
|
1024
|
|
|
|
|
|
|
my $rms = PDL->nullcreate($data); |
|
1025
|
|
|
|
|
|
|
my $min = PDL->nullcreate($data); |
|
1026
|
|
|
|
|
|
|
my $max = PDL->nullcreate($data); |
|
1027
|
|
|
|
|
|
|
my $adev = PDL->nullcreate($data); |
|
1028
|
|
|
|
|
|
|
my $prms = PDL->nullcreate($data); |
|
1029
|
|
|
|
|
|
|
PDL::_statsover_int($data, $weights, $mean, $prms, $min, $max, $adev, $rms); |
|
1030
|
|
|
|
|
|
|
wantarray ? ($mean, $prms, $median, $min, $max, $adev, $rms) : $mean; |
|
1031
|
|
|
|
|
|
|
} |
|
1032
|
|
|
|
|
|
|
EOPM |
|
1033
|
|
|
|
|
|
|
Doc => ' |
|
1034
|
|
|
|
|
|
|
=for ref |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
Calculate useful statistics over a dimension of an ndarray |
|
1037
|
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
=for usage |
|
1039
|
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
($mean,$prms,$median,$min,$max,$adev,$rms) = statsover($ndarray, $weights); |
|
1041
|
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
This utility function calculates various useful |
|
1043
|
|
|
|
|
|
|
quantities of an ndarray. These are: |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
=over 3 |
|
1046
|
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
=item * the mean: |
|
1048
|
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
MEAN = sum (x)/ N |
|
1050
|
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
with C being the number of elements in x |
|
1052
|
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
=item * the population RMS deviation from the mean: |
|
1054
|
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
PRMS = sqrt( sum( (x-mean(x))^2 )/(N-1) ) |
|
1056
|
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
The population deviation is the best-estimate of the deviation |
|
1058
|
|
|
|
|
|
|
of the population from which a sample is drawn. |
|
1059
|
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
=item * the median |
|
1061
|
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
The median is the 50th percentile data value. Median is found by |
|
1063
|
|
|
|
|
|
|
L, so WEIGHTING IS IGNORED FOR THE MEDIAN CALCULATION. |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
=item * the minimum |
|
1066
|
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
=item * the maximum |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
=item * the average absolute deviation: |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
AADEV = sum( abs(x-mean(x)) )/N |
|
1072
|
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
=item * RMS deviation from the mean: |
|
1074
|
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
RMS = sqrt(sum( (x-mean(x))^2 )/N) |
|
1076
|
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
(also known as the root-mean-square deviation, or the square root of the |
|
1078
|
|
|
|
|
|
|
variance) |
|
1079
|
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
=back |
|
1081
|
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
This operator is a projection operator so the calculation |
|
1083
|
|
|
|
|
|
|
will take place over the final dimension. Thus if the input |
|
1084
|
|
|
|
|
|
|
is N-dimensional each returned value will be N-1 dimensional, |
|
1085
|
|
|
|
|
|
|
to calculate the statistics for the entire ndarray either |
|
1086
|
|
|
|
|
|
|
use C directly on the ndarray or call C. |
|
1087
|
|
|
|
|
|
|
', |
|
1088
|
|
|
|
|
|
|
BadDoc =>' |
|
1089
|
|
|
|
|
|
|
Bad values are simply ignored in the calculation, effectively reducing |
|
1090
|
|
|
|
|
|
|
the sample size. If all data are bad then the output data are marked bad. |
|
1091
|
|
|
|
|
|
|
', |
|
1092
|
|
|
|
|
|
|
); |
|
1093
|
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
pp_add_exported('','stats'); |
|
1095
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
1096
|
|
|
|
|
|
|
=head2 stats |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=for ref |
|
1099
|
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
Calculates useful statistics on an ndarray |
|
1101
|
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
=for usage |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
($mean,$prms,$median,$min,$max,$adev,$rms) = stats($ndarray,[$weights]); |
|
1105
|
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
This utility calculates all the most useful quantities in one call. |
|
1107
|
|
|
|
|
|
|
It works the same way as L, except that the quantities are |
|
1108
|
|
|
|
|
|
|
calculated considering the entire input PDL as a single sample, rather |
|
1109
|
|
|
|
|
|
|
than as a collection of rows. See L for definitions of the |
|
1110
|
|
|
|
|
|
|
returned quantities. |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
=for bad |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
Bad values are handled; if all input values are bad, then all of the output |
|
1115
|
|
|
|
|
|
|
values are flagged bad. |
|
1116
|
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
=cut |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
*stats = \&PDL::stats; |
|
1120
|
|
|
|
|
|
|
sub PDL::stats { |
|
1121
|
|
|
|
|
|
|
barf('Usage: ($mean,[$rms]) = stats($data,[$weights])') if @_>2; |
|
1122
|
|
|
|
|
|
|
my ($data,$weights) = @_; |
|
1123
|
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
# Ensure that $weights is properly broadcasted over; this could be |
|
1125
|
|
|
|
|
|
|
# done rather more efficiently... |
|
1126
|
|
|
|
|
|
|
if(defined $weights) { |
|
1127
|
|
|
|
|
|
|
$weights = pdl($weights) unless UNIVERSAL::isa($weights,'PDL'); |
|
1128
|
|
|
|
|
|
|
if( ($weights->ndims != $data->ndims) or |
|
1129
|
|
|
|
|
|
|
(pdl($weights->dims) != pdl($data->dims))->or |
|
1130
|
|
|
|
|
|
|
) { |
|
1131
|
|
|
|
|
|
|
$weights = $weights + zeroes($data) |
|
1132
|
|
|
|
|
|
|
} |
|
1133
|
|
|
|
|
|
|
$weights = $weights->flat; |
|
1134
|
|
|
|
|
|
|
} |
|
1135
|
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
return PDL::statsover($data->flat,$weights); |
|
1137
|
|
|
|
|
|
|
} |
|
1138
|
|
|
|
|
|
|
EOD |
|
1139
|
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
my $histogram_doc = <<'EOD'; |
|
1141
|
|
|
|
|
|
|
=for ref |
|
1142
|
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
Calculates a histogram for given stepsize and minimum. |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
=for usage |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
$h = histogram($data, $step, $min, $numbins); |
|
1148
|
|
|
|
|
|
|
$hist = zeroes $numbins; # Put histogram in existing ndarray. |
|
1149
|
|
|
|
|
|
|
histogram($data, $hist, $step, $min, $numbins); |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
The histogram will contain C<$numbins> bins starting from C<$min>, each |
|
1152
|
|
|
|
|
|
|
C<$step> wide. The value in each bin is the number of |
|
1153
|
|
|
|
|
|
|
values in C<$data> that lie within the bin limits. |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
Data below the lower limit is put in the first bin, and data above the |
|
1157
|
|
|
|
|
|
|
upper limit is put in the last bin. |
|
1158
|
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
The output is reset in a different broadcastloop so that you |
|
1160
|
|
|
|
|
|
|
can take a histogram of C<$a(10,12)> into C<$b(15)> and get the result |
|
1161
|
|
|
|
|
|
|
you want. |
|
1162
|
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
For a higher-level interface, see L. |
|
1164
|
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
=for example |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
pdl> p histogram(pdl(1,1,2),1,0,3) |
|
1168
|
|
|
|
|
|
|
[0 2 1] |
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
=cut |
|
1171
|
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
EOD |
|
1173
|
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
my $whistogram_doc = <<'EOD'; |
|
1175
|
|
|
|
|
|
|
=for ref |
|
1176
|
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
Calculates a histogram from weighted data for given stepsize and minimum. |
|
1178
|
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
=for usage |
|
1180
|
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
$h = whistogram($data, $weights, $step, $min, $numbins); |
|
1182
|
|
|
|
|
|
|
$hist = zeroes $numbins; # Put histogram in existing ndarray. |
|
1183
|
|
|
|
|
|
|
whistogram($data, $weights, $hist, $step, $min, $numbins); |
|
1184
|
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
The histogram will contain C<$numbins> bins starting from C<$min>, each |
|
1186
|
|
|
|
|
|
|
C<$step> wide. The value in each bin is the sum of the values in C<$weights> |
|
1187
|
|
|
|
|
|
|
that correspond to values in C<$data> that lie within the bin limits. |
|
1188
|
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
Data below the lower limit is put in the first bin, and data above the |
|
1190
|
|
|
|
|
|
|
upper limit is put in the last bin. |
|
1191
|
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
The output is reset in a different broadcastloop so that you |
|
1193
|
|
|
|
|
|
|
can take a histogram of C<$a(10,12)> into C<$b(15)> and get the result |
|
1194
|
|
|
|
|
|
|
you want. |
|
1195
|
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
=for example |
|
1197
|
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
pdl> p whistogram(pdl(1,1,2), pdl(0.1,0.1,0.5), 1, 0, 4) |
|
1199
|
|
|
|
|
|
|
[0 0.2 0.5 0] |
|
1200
|
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
=cut |
|
1202
|
|
|
|
|
|
|
EOD |
|
1203
|
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
for( |
|
1205
|
|
|
|
|
|
|
{Name => 'histogram', |
|
1206
|
|
|
|
|
|
|
WeightPar => '', |
|
1207
|
|
|
|
|
|
|
HistType => 'int+', |
|
1208
|
|
|
|
|
|
|
HistOp => '+= 1', |
|
1209
|
|
|
|
|
|
|
Doc => $histogram_doc, |
|
1210
|
|
|
|
|
|
|
}, |
|
1211
|
|
|
|
|
|
|
{Name => 'whistogram', |
|
1212
|
|
|
|
|
|
|
WeightPar => 'float+ wt(n);', |
|
1213
|
|
|
|
|
|
|
HistType => 'float+', |
|
1214
|
|
|
|
|
|
|
HistOp => '+= $wt()', |
|
1215
|
|
|
|
|
|
|
Doc => $whistogram_doc, |
|
1216
|
|
|
|
|
|
|
} |
|
1217
|
|
|
|
|
|
|
) |
|
1218
|
|
|
|
|
|
|
{ |
|
1219
|
|
|
|
|
|
|
pp_def($_->{Name}, |
|
1220
|
|
|
|
|
|
|
Pars => 'in(n); '.$_->{WeightPar}.$_->{HistType}. '[o] hist(m)', |
|
1221
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
1222
|
|
|
|
|
|
|
# set outdim by Par! |
|
1223
|
|
|
|
|
|
|
OtherPars => 'double step; double min; IV msize => m', |
|
1224
|
|
|
|
|
|
|
HandleBad => 1, |
|
1225
|
|
|
|
|
|
|
RedoDimsCode => 'if ($SIZE(m) == 0) $CROAK("called with m dim of 0");', |
|
1226
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__-1, ' |
|
1227
|
|
|
|
|
|
|
register double min = $COMP(min), step = $COMP(step); |
|
1228
|
|
|
|
|
|
|
broadcastloop %{ |
|
1229
|
|
|
|
|
|
|
loop(m) %{ $hist() = 0; %} |
|
1230
|
|
|
|
|
|
|
loop(n) %{ |
|
1231
|
|
|
|
|
|
|
PDL_IF_BAD(if ( !$ISGOOD(in()) ) continue;,) |
|
1232
|
|
|
|
|
|
|
PDL_Indx j = round((($in()-min)/step)-0.5); |
|
1233
|
|
|
|
|
|
|
j = PDLMIN(PDLMAX(j, 0), $SIZE(m)-1); |
|
1234
|
|
|
|
|
|
|
($hist(m => j))'.$_->{HistOp}.'; |
|
1235
|
|
|
|
|
|
|
%} |
|
1236
|
|
|
|
|
|
|
%}'), |
|
1237
|
|
|
|
|
|
|
Doc=>$_->{Doc}); |
|
1238
|
|
|
|
|
|
|
} |
|
1239
|
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
my $histogram2d_doc = <<'EOD'; |
|
1241
|
|
|
|
|
|
|
=for ref |
|
1242
|
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
Calculates a 2d histogram. |
|
1244
|
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
=for usage |
|
1246
|
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
$h = histogram2d($datax, $datay, $stepx, $minx, |
|
1248
|
|
|
|
|
|
|
$nbinx, $stepy, $miny, $nbiny); |
|
1249
|
|
|
|
|
|
|
$hist = zeroes $nbinx, $nbiny; # Put histogram in existing ndarray. |
|
1250
|
|
|
|
|
|
|
histogram2d($datax, $datay, $hist, $stepx, $minx, |
|
1251
|
|
|
|
|
|
|
$nbinx, $stepy, $miny, $nbiny); |
|
1252
|
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
The histogram will contain C<$nbinx> x C<$nbiny> bins, with the lower |
|
1254
|
|
|
|
|
|
|
limits of the first one at C<($minx, $miny)>, and with bin size |
|
1255
|
|
|
|
|
|
|
C<($stepx, $stepy)>. |
|
1256
|
|
|
|
|
|
|
The value in each bin is the number of |
|
1257
|
|
|
|
|
|
|
values in C<$datax> and C<$datay> that lie within the bin limits. |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
Data below the lower limit is put in the first bin, and data above the |
|
1260
|
|
|
|
|
|
|
upper limit is put in the last bin. |
|
1261
|
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
=for example |
|
1263
|
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
pdl> p histogram2d(pdl(1,1,1,2,2),pdl(2,1,1,1,1),1,0,3,1,0,3) |
|
1265
|
|
|
|
|
|
|
[ |
|
1266
|
|
|
|
|
|
|
[0 0 0] |
|
1267
|
|
|
|
|
|
|
[0 2 2] |
|
1268
|
|
|
|
|
|
|
[0 1 0] |
|
1269
|
|
|
|
|
|
|
] |
|
1270
|
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
=cut |
|
1272
|
|
|
|
|
|
|
EOD |
|
1273
|
|
|
|
|
|
|
|
|
1274
|
|
|
|
|
|
|
my $whistogram2d_doc = <<'EOD'; |
|
1275
|
|
|
|
|
|
|
=for ref |
|
1276
|
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
Calculates a 2d histogram from weighted data. |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
=for usage |
|
1280
|
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
$h = whistogram2d($datax, $datay, $weights, |
|
1282
|
|
|
|
|
|
|
$stepx, $minx, $nbinx, $stepy, $miny, $nbiny); |
|
1283
|
|
|
|
|
|
|
$hist = zeroes $nbinx, $nbiny; # Put histogram in existing ndarray. |
|
1284
|
|
|
|
|
|
|
whistogram2d($datax, $datay, $weights, $hist, |
|
1285
|
|
|
|
|
|
|
$stepx, $minx, $nbinx, $stepy, $miny, $nbiny); |
|
1286
|
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
The histogram will contain C<$nbinx> x C<$nbiny> bins, with the lower |
|
1288
|
|
|
|
|
|
|
limits of the first one at C<($minx, $miny)>, and with bin size |
|
1289
|
|
|
|
|
|
|
C<($stepx, $stepy)>. |
|
1290
|
|
|
|
|
|
|
The value in each bin is the sum of the values in |
|
1291
|
|
|
|
|
|
|
C<$weights> that correspond to values in C<$datax> and C<$datay> that lie within the bin limits. |
|
1292
|
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
Data below the lower limit is put in the first bin, and data above the |
|
1294
|
|
|
|
|
|
|
upper limit is put in the last bin. |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
=for example |
|
1297
|
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
pdl> p whistogram2d(pdl(1,1,1,2,2),pdl(2,1,1,1,1),pdl(0.1,0.2,0.3,0.4,0.5),1,0,3,1,0,3) |
|
1299
|
|
|
|
|
|
|
[ |
|
1300
|
|
|
|
|
|
|
[ 0 0 0] |
|
1301
|
|
|
|
|
|
|
[ 0 0.5 0.9] |
|
1302
|
|
|
|
|
|
|
[ 0 0.1 0] |
|
1303
|
|
|
|
|
|
|
] |
|
1304
|
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
=cut |
|
1306
|
|
|
|
|
|
|
EOD |
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
for( |
|
1309
|
|
|
|
|
|
|
{Name => 'histogram2d', |
|
1310
|
|
|
|
|
|
|
WeightPar => '', |
|
1311
|
|
|
|
|
|
|
HistType => 'int+', |
|
1312
|
|
|
|
|
|
|
HistOp => '+= 1', |
|
1313
|
|
|
|
|
|
|
Doc => $histogram2d_doc, |
|
1314
|
|
|
|
|
|
|
}, |
|
1315
|
|
|
|
|
|
|
{Name => 'whistogram2d', |
|
1316
|
|
|
|
|
|
|
WeightPar => 'float+ wt(n);', |
|
1317
|
|
|
|
|
|
|
HistType => 'float+', |
|
1318
|
|
|
|
|
|
|
HistOp => '+= $wt()', |
|
1319
|
|
|
|
|
|
|
Doc => $whistogram2d_doc, |
|
1320
|
|
|
|
|
|
|
} |
|
1321
|
|
|
|
|
|
|
) |
|
1322
|
|
|
|
|
|
|
{ |
|
1323
|
|
|
|
|
|
|
pp_def($_->{Name}, |
|
1324
|
|
|
|
|
|
|
Pars => 'ina(n); inb(n); '.$_->{WeightPar}.$_->{HistType}. '[o] hist(ma,mb)', |
|
1325
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
1326
|
|
|
|
|
|
|
# set outdim by Par! |
|
1327
|
|
|
|
|
|
|
OtherPars => 'double stepa; double mina; IV masize => ma; |
|
1328
|
|
|
|
|
|
|
double stepb; double minb; IV mbsize => mb;', |
|
1329
|
|
|
|
|
|
|
HandleBad => 1, |
|
1330
|
|
|
|
|
|
|
RedoDimsCode => ' |
|
1331
|
|
|
|
|
|
|
if ($SIZE(ma) == 0) $CROAK("called with ma dim of 0"); |
|
1332
|
|
|
|
|
|
|
if ($SIZE(mb) == 0) $CROAK("called with mb dim of 0"); |
|
1333
|
|
|
|
|
|
|
', |
|
1334
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__-1, ' |
|
1335
|
|
|
|
|
|
|
register double mina = $COMP(mina), minb = $COMP(minb), stepa = $COMP(stepa), stepb = $COMP(stepb); |
|
1336
|
|
|
|
|
|
|
broadcastloop %{ |
|
1337
|
|
|
|
|
|
|
loop(ma,mb) %{ $hist() = 0; %} |
|
1338
|
|
|
|
|
|
|
loop(n) %{ |
|
1339
|
|
|
|
|
|
|
PDL_IF_BAD(if (!( $ISGOOD(ina()) && $ISGOOD(inb()) )) continue;,) |
|
1340
|
|
|
|
|
|
|
PDL_Indx ja = round((($ina()-mina)/stepa)-0.5); |
|
1341
|
|
|
|
|
|
|
PDL_Indx jb = round((($inb()-minb)/stepb)-0.5); |
|
1342
|
|
|
|
|
|
|
ja = PDLMIN(PDLMAX(ja, 0), $SIZE(ma)-1); |
|
1343
|
|
|
|
|
|
|
jb = PDLMIN(PDLMAX(jb, 0), $SIZE(mb)-1); |
|
1344
|
|
|
|
|
|
|
($hist(ma => ja,mb => jb))'.$_->{HistOp}.'; |
|
1345
|
|
|
|
|
|
|
%} |
|
1346
|
|
|
|
|
|
|
%}'), |
|
1347
|
|
|
|
|
|
|
Doc=> $_->{Doc}); |
|
1348
|
|
|
|
|
|
|
} |
|
1349
|
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
########################################################### |
|
1352
|
|
|
|
|
|
|
# a number of constructors: fibonacci, append, axisvalues & |
|
1353
|
|
|
|
|
|
|
# random numbers |
|
1354
|
|
|
|
|
|
|
########################################################### |
|
1355
|
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
pp_def('fibonacci', |
|
1357
|
|
|
|
|
|
|
Pars => 'i(n); [o]x(n)', |
|
1358
|
|
|
|
|
|
|
Inplace => 1, |
|
1359
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
1360
|
|
|
|
|
|
|
Doc=>'Constructor - a vector with Fibonacci\'s sequence', |
|
1361
|
|
|
|
|
|
|
PMFunc=>'', |
|
1362
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
1363
|
|
|
|
|
|
|
sub fibonacci { ref($_[0]) && ref($_[0]) ne 'PDL::Type' ? $_[0]->fibonacci : PDL->fibonacci(@_) } |
|
1364
|
|
|
|
|
|
|
sub PDL::fibonacci{ |
|
1365
|
|
|
|
|
|
|
my $x = &PDL::Core::_construct; |
|
1366
|
|
|
|
|
|
|
my $is_inplace = $x->is_inplace; |
|
1367
|
|
|
|
|
|
|
my ($in, $out) = $x->flat; |
|
1368
|
|
|
|
|
|
|
$out = $is_inplace ? $in->inplace : PDL->null; |
|
1369
|
|
|
|
|
|
|
PDL::_fibonacci_int($in, $out); |
|
1370
|
|
|
|
|
|
|
$out; |
|
1371
|
|
|
|
|
|
|
} |
|
1372
|
|
|
|
|
|
|
EOD |
|
1373
|
|
|
|
|
|
|
Code => ' |
|
1374
|
|
|
|
|
|
|
PDL_Indx i=0; |
|
1375
|
|
|
|
|
|
|
$GENERIC() x1, x2; |
|
1376
|
|
|
|
|
|
|
x1 = 1; x2 = 0; |
|
1377
|
|
|
|
|
|
|
loop(n) %{ |
|
1378
|
|
|
|
|
|
|
$x() = x1 + x2; |
|
1379
|
|
|
|
|
|
|
if (i++>0) { |
|
1380
|
|
|
|
|
|
|
x2 = x1; |
|
1381
|
|
|
|
|
|
|
x1 = $x(); |
|
1382
|
|
|
|
|
|
|
} |
|
1383
|
|
|
|
|
|
|
%} |
|
1384
|
|
|
|
|
|
|
'); |
|
1385
|
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
pp_def('append', |
|
1387
|
|
|
|
|
|
|
Pars => 'a(n); b(m); [o] c(mn=CALC($SIZE(n)+$SIZE(m)))', |
|
1388
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
1389
|
|
|
|
|
|
|
PMCode => pp_line_numbers(__LINE__-1, ' |
|
1390
|
|
|
|
|
|
|
sub PDL::append { |
|
1391
|
|
|
|
|
|
|
my ($i1, $i2, $o) = map PDL->topdl($_), @_; |
|
1392
|
|
|
|
|
|
|
$_ = empty() for grep $_->isnull, $i1, $i2; |
|
1393
|
|
|
|
|
|
|
my $nempty = grep $_->isempty, $i1, $i2; |
|
1394
|
|
|
|
|
|
|
if ($nempty == 2) { |
|
1395
|
|
|
|
|
|
|
my @dims = $i1->dims; |
|
1396
|
|
|
|
|
|
|
$dims[0] += $i2->dim(0); |
|
1397
|
|
|
|
|
|
|
return PDL->zeroes($i1->type, @dims); |
|
1398
|
|
|
|
|
|
|
} |
|
1399
|
|
|
|
|
|
|
$o //= PDL->null; |
|
1400
|
|
|
|
|
|
|
$o .= $i1->isempty ? $i2 : $i1, return $o if $nempty == 1; |
|
1401
|
|
|
|
|
|
|
PDL::_append_int($i1, $i2->convert($i1->type), $o); |
|
1402
|
|
|
|
|
|
|
$o; |
|
1403
|
|
|
|
|
|
|
} |
|
1404
|
|
|
|
|
|
|
'), |
|
1405
|
|
|
|
|
|
|
Code => 'PDL_Indx ns = $SIZE(n); |
|
1406
|
|
|
|
|
|
|
broadcastloop %{ |
|
1407
|
|
|
|
|
|
|
loop(n) %{ $c(mn => n) = $a(); %} |
|
1408
|
|
|
|
|
|
|
loop(mn=ns) %{ $c() = $b(m=>mn-ns); %} |
|
1409
|
|
|
|
|
|
|
%}', |
|
1410
|
|
|
|
|
|
|
Doc => ' |
|
1411
|
|
|
|
|
|
|
=for ref |
|
1412
|
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
append two ndarrays by concatenating along their first dimensions |
|
1414
|
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
=for example |
|
1416
|
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
$x = ones(2,4,7); |
|
1418
|
|
|
|
|
|
|
$y = sequence 5; |
|
1419
|
|
|
|
|
|
|
$c = $x->append($y); # size of $c is now (7,4,7) (a jumbo-ndarray ;) |
|
1420
|
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
C appends two ndarrays along their first dimensions. The rest of the |
|
1422
|
|
|
|
|
|
|
dimensions must be compatible in the broadcasting sense. The resulting |
|
1423
|
|
|
|
|
|
|
size of the first dimension is the sum of the sizes of the first dimensions |
|
1424
|
|
|
|
|
|
|
of the two argument ndarrays - i.e. C. |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
Similar functions include L (below), which can append more |
|
1427
|
|
|
|
|
|
|
than two ndarrays along an arbitrary dimension, and |
|
1428
|
|
|
|
|
|
|
L, which can append more than two ndarrays that all |
|
1429
|
|
|
|
|
|
|
have the same sized dimensions. |
|
1430
|
|
|
|
|
|
|
' |
|
1431
|
|
|
|
|
|
|
); |
|
1432
|
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
1434
|
|
|
|
|
|
|
=head2 glue |
|
1435
|
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
=for usage |
|
1437
|
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
$c = $x->glue(,$y,...) |
|
1439
|
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
=for ref |
|
1441
|
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
Glue two or more PDLs together along an arbitrary dimension |
|
1443
|
|
|
|
|
|
|
(N-D L). |
|
1444
|
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
Sticks $x, $y, and all following arguments together along the |
|
1446
|
|
|
|
|
|
|
specified dimension. All other dimensions must be compatible in the |
|
1447
|
|
|
|
|
|
|
broadcasting sense. |
|
1448
|
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
Glue is permissive, in the sense that every PDL is treated as having an |
|
1450
|
|
|
|
|
|
|
infinite number of trivial dimensions of order 1 -- so C<< $x->glue(3,$y) >> |
|
1451
|
|
|
|
|
|
|
works, even if $x and $y are only one dimensional. |
|
1452
|
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
If one of the PDLs has no elements, it is ignored. Likewise, if one |
|
1454
|
|
|
|
|
|
|
of them is actually the undefined value, it is treated as if it had no |
|
1455
|
|
|
|
|
|
|
elements. |
|
1456
|
|
|
|
|
|
|
|
|
1457
|
|
|
|
|
|
|
If the first parameter is a defined perl scalar rather than a pdl, |
|
1458
|
|
|
|
|
|
|
then it is taken as a dimension along which to glue everything else, |
|
1459
|
|
|
|
|
|
|
so you can say C<$cube = PDL::glue(3,@image_list);> if you like. |
|
1460
|
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
C is implemented in pdl, using a combination of L and |
|
1462
|
|
|
|
|
|
|
L. It should probably be updated (one day) to a pure PP |
|
1463
|
|
|
|
|
|
|
function. |
|
1464
|
|
|
|
|
|
|
|
|
1465
|
|
|
|
|
|
|
Similar functions include L (above), which appends |
|
1466
|
|
|
|
|
|
|
only two ndarrays along their first dimension, and |
|
1467
|
|
|
|
|
|
|
L, which can append more than two ndarrays that all |
|
1468
|
|
|
|
|
|
|
have the same sized dimensions. |
|
1469
|
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
=cut |
|
1471
|
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
sub PDL::glue{ |
|
1473
|
|
|
|
|
|
|
my($x) = shift; |
|
1474
|
|
|
|
|
|
|
my($dim) = shift; |
|
1475
|
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
($dim, $x) = ($x, $dim) if defined $x && !ref $x; |
|
1477
|
|
|
|
|
|
|
confess 'dimension must be Perl scalar' if ref $dim; |
|
1478
|
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
if(!defined $x || $x->nelem==0) { |
|
1480
|
|
|
|
|
|
|
return $x unless(@_); |
|
1481
|
|
|
|
|
|
|
return shift() if(@_<=1); |
|
1482
|
|
|
|
|
|
|
$x=shift; |
|
1483
|
|
|
|
|
|
|
return PDL::glue($x,$dim,@_); |
|
1484
|
|
|
|
|
|
|
} |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
if($dim - $x->dim(0) > 100) { |
|
1487
|
|
|
|
|
|
|
print STDERR "warning:: PDL::glue allocating >100 dimensions!\n"; |
|
1488
|
|
|
|
|
|
|
} |
|
1489
|
|
|
|
|
|
|
while($dim >= $x->ndims) { |
|
1490
|
|
|
|
|
|
|
$x = $x->dummy(-1,1); |
|
1491
|
|
|
|
|
|
|
} |
|
1492
|
|
|
|
|
|
|
$x = $x->xchg(0,$dim) if 0 != $dim; |
|
1493
|
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
while(scalar(@_)){ |
|
1495
|
|
|
|
|
|
|
my $y = shift; |
|
1496
|
|
|
|
|
|
|
next unless(defined $y && $y->nelem); |
|
1497
|
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
while($dim >= $y->ndims) { |
|
1499
|
|
|
|
|
|
|
$y = $y->dummy(-1,1); |
|
1500
|
|
|
|
|
|
|
} |
|
1501
|
|
|
|
|
|
|
$y = $y->xchg(0,$dim) if 0 != $dim; |
|
1502
|
|
|
|
|
|
|
$x = $x->append($y); |
|
1503
|
|
|
|
|
|
|
} |
|
1504
|
|
|
|
|
|
|
0 == $dim ? $x : $x->xchg(0,$dim); |
|
1505
|
|
|
|
|
|
|
} |
|
1506
|
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
EOD |
|
1508
|
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
pp_def( 'axisvalues', |
|
1510
|
|
|
|
|
|
|
Pars => 'i(n); [o]a(n)', |
|
1511
|
|
|
|
|
|
|
Inplace => 1, |
|
1512
|
|
|
|
|
|
|
Code => 'loop(n) %{ $a() = n; %}', |
|
1513
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
1514
|
|
|
|
|
|
|
Doc => undef, |
|
1515
|
|
|
|
|
|
|
); # pp_def: axisvalues |
|
1516
|
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
pp_add_macros( |
|
1518
|
|
|
|
|
|
|
CMPVEC => sub { |
|
1519
|
|
|
|
|
|
|
my ($a, $b, $dim, $ret, $anybad) = @_; |
|
1520
|
|
|
|
|
|
|
my $badbit = !defined $anybad ? '' : <
|
|
1521
|
|
|
|
|
|
|
PDL_IF_BAD(if (\$ISBAD($a) || \$ISBAD($b)) { $anybad = 1; break; } else,) |
|
1522
|
|
|
|
|
|
|
EOF |
|
1523
|
|
|
|
|
|
|
<
|
|
1524
|
|
|
|
|
|
|
$ret = 0; |
|
1525
|
|
|
|
|
|
|
loop($dim) %{ $badbit if ($a != $b) { $ret = $a < $b ? -1 : 1; break; } %} |
|
1526
|
|
|
|
|
|
|
EOF |
|
1527
|
|
|
|
|
|
|
}, |
|
1528
|
|
|
|
|
|
|
); |
|
1529
|
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
pp_def( |
|
1531
|
|
|
|
|
|
|
'cmpvec', |
|
1532
|
|
|
|
|
|
|
HandleBad => 1, |
|
1533
|
|
|
|
|
|
|
Pars => 'a(n); b(n); sbyte [o]c();', |
|
1534
|
|
|
|
|
|
|
Code => ' |
|
1535
|
|
|
|
|
|
|
PDL_IF_BAD(char anybad = 0;,) |
|
1536
|
|
|
|
|
|
|
broadcastloop %{ |
|
1537
|
|
|
|
|
|
|
$CMPVEC($a(), $b(), n, $c(), anybad); |
|
1538
|
|
|
|
|
|
|
PDL_IF_BAD(if (anybad) $SETBAD(c());,) |
|
1539
|
|
|
|
|
|
|
%} |
|
1540
|
|
|
|
|
|
|
PDL_IF_BAD(if (anybad) $PDLSTATESETBAD(c);,) |
|
1541
|
|
|
|
|
|
|
', |
|
1542
|
|
|
|
|
|
|
Doc => ' |
|
1543
|
|
|
|
|
|
|
=for ref |
|
1544
|
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
Compare two vectors lexicographically. |
|
1546
|
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
Returns -1 if a is less, 1 if greater, 0 if equal. |
|
1548
|
|
|
|
|
|
|
', |
|
1549
|
|
|
|
|
|
|
BadDoc => ' |
|
1550
|
|
|
|
|
|
|
The output is bad if any input values up to the point of inequality are |
|
1551
|
|
|
|
|
|
|
bad - any after are ignored. |
|
1552
|
|
|
|
|
|
|
', |
|
1553
|
|
|
|
|
|
|
); |
|
1554
|
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
pp_def( |
|
1556
|
|
|
|
|
|
|
'eqvec', |
|
1557
|
|
|
|
|
|
|
HandleBad => 1, |
|
1558
|
|
|
|
|
|
|
Pars => 'a(n); b(n); sbyte [o]c();', |
|
1559
|
|
|
|
|
|
|
Code => ' |
|
1560
|
|
|
|
|
|
|
PDL_IF_BAD(char anybad = 0;,) |
|
1561
|
|
|
|
|
|
|
broadcastloop %{ |
|
1562
|
|
|
|
|
|
|
$c() = 1; |
|
1563
|
|
|
|
|
|
|
loop(n) %{ |
|
1564
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a()) || $ISBAD(b())) { $SETBAD(c()); anybad = 1; break; } |
|
1565
|
|
|
|
|
|
|
else,) if ($a() != $b()) { $c() = 0; PDL_IF_BAD(,break;) } |
|
1566
|
|
|
|
|
|
|
%} |
|
1567
|
|
|
|
|
|
|
%} |
|
1568
|
|
|
|
|
|
|
PDL_IF_BAD(if (anybad) $PDLSTATESETBAD(c);,) |
|
1569
|
|
|
|
|
|
|
', |
|
1570
|
|
|
|
|
|
|
Doc => 'Compare two vectors, returning 1 if equal, 0 if not equal.', |
|
1571
|
|
|
|
|
|
|
BadDoc => 'The output is bad if any input values are bad.', |
|
1572
|
|
|
|
|
|
|
); |
|
1573
|
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
pp_def('enumvec', |
|
1575
|
|
|
|
|
|
|
Pars => 'v(M,N); indx [o]k(N)', |
|
1576
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOC'), |
|
1577
|
|
|
|
|
|
|
loop (N) %{ |
|
1578
|
|
|
|
|
|
|
PDL_Indx vn = N; /* preserve value of N into inner N loop */ |
|
1579
|
|
|
|
|
|
|
loop (N=vn) %{ |
|
1580
|
|
|
|
|
|
|
if (N == vn) { $k() = 0; continue; } /* no need to compare with self */ |
|
1581
|
|
|
|
|
|
|
char matches = 1; |
|
1582
|
|
|
|
|
|
|
loop (M) %{ |
|
1583
|
|
|
|
|
|
|
if ($v(N=>vn) == $v()) continue; |
|
1584
|
|
|
|
|
|
|
matches = 0; |
|
1585
|
|
|
|
|
|
|
break; |
|
1586
|
|
|
|
|
|
|
%} |
|
1587
|
|
|
|
|
|
|
if (matches) { |
|
1588
|
|
|
|
|
|
|
$k() = N-vn; |
|
1589
|
|
|
|
|
|
|
if (N == $SIZE(N)-1) vn = N; /* last one matched, so stop */ |
|
1590
|
|
|
|
|
|
|
} else { |
|
1591
|
|
|
|
|
|
|
vn = N-1; |
|
1592
|
|
|
|
|
|
|
break; |
|
1593
|
|
|
|
|
|
|
} |
|
1594
|
|
|
|
|
|
|
%} |
|
1595
|
|
|
|
|
|
|
N = vn; /* skip forward */ |
|
1596
|
|
|
|
|
|
|
%} |
|
1597
|
|
|
|
|
|
|
EOC |
|
1598
|
|
|
|
|
|
|
Doc =><<'EOD', |
|
1599
|
|
|
|
|
|
|
=for ref |
|
1600
|
|
|
|
|
|
|
|
|
1601
|
|
|
|
|
|
|
Enumerate a list of vectors with locally unique keys. |
|
1602
|
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
Given a sorted list of vectors $v, generate a vector $k containing locally unique keys for the elements of $v |
|
1604
|
|
|
|
|
|
|
(where an "element" is a vector of length $M occurring in $v). |
|
1605
|
|
|
|
|
|
|
|
|
1606
|
|
|
|
|
|
|
Note that the keys returned in $k are only unique over a run of a single vector in $v, |
|
1607
|
|
|
|
|
|
|
so that each unique vector in $v has at least one 0 (zero) index in $k associated with it. |
|
1608
|
|
|
|
|
|
|
If you need global keys, see enumvecg(). |
|
1609
|
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1611
|
|
|
|
|
|
|
EOD |
|
1612
|
|
|
|
|
|
|
); |
|
1613
|
|
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
##------------------------------------------------------ |
|
1615
|
|
|
|
|
|
|
## enumvecg() |
|
1616
|
|
|
|
|
|
|
pp_def('enumvecg', |
|
1617
|
|
|
|
|
|
|
Pars => 'v(M,N); indx [o]k(N)', |
|
1618
|
|
|
|
|
|
|
Code =><<'EOC', |
|
1619
|
|
|
|
|
|
|
if (!$SIZE(N)) return PDL_err; |
|
1620
|
|
|
|
|
|
|
PDL_Indx Nprev = 0, ki = $k(N=>0) = 0; |
|
1621
|
|
|
|
|
|
|
loop(N=1) %{ |
|
1622
|
|
|
|
|
|
|
loop (M) %{ |
|
1623
|
|
|
|
|
|
|
if ($v(N=>Nprev) == $v()) continue; |
|
1624
|
|
|
|
|
|
|
++ki; |
|
1625
|
|
|
|
|
|
|
break; |
|
1626
|
|
|
|
|
|
|
%} |
|
1627
|
|
|
|
|
|
|
$k() = ki; |
|
1628
|
|
|
|
|
|
|
Nprev = N; |
|
1629
|
|
|
|
|
|
|
%} |
|
1630
|
|
|
|
|
|
|
EOC |
|
1631
|
|
|
|
|
|
|
Doc =><<'EOD', |
|
1632
|
|
|
|
|
|
|
=for ref |
|
1633
|
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
Enumerate a list of vectors with globally unique keys. |
|
1635
|
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
Given a sorted list of vectors $v, generate a vector $k containing globally unique keys for the elements of $v |
|
1637
|
|
|
|
|
|
|
(where an "element" is a vector of length $M occurring in $v). |
|
1638
|
|
|
|
|
|
|
Basically does the same thing as: |
|
1639
|
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
$k = $v->vsearchvec($v->uniqvec); |
|
1641
|
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
... but somewhat more efficiently. |
|
1643
|
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1645
|
|
|
|
|
|
|
EOD |
|
1646
|
|
|
|
|
|
|
); |
|
1647
|
|
|
|
|
|
|
|
|
1648
|
|
|
|
|
|
|
pp_def('vsearchvec', |
|
1649
|
|
|
|
|
|
|
Pars => 'find(M); which(M,N); indx [o]found();', |
|
1650
|
|
|
|
|
|
|
Code => q( |
|
1651
|
|
|
|
|
|
|
int carp=0; |
|
1652
|
|
|
|
|
|
|
broadcastloop %{ |
|
1653
|
|
|
|
|
|
|
PDL_Indx n1=$SIZE(N)-1, nlo=-1, nhi=n1, nn; |
|
1654
|
|
|
|
|
|
|
int cmpval, is_asc_sorted; |
|
1655
|
|
|
|
|
|
|
// |
|
1656
|
|
|
|
|
|
|
//-- get sort direction |
|
1657
|
|
|
|
|
|
|
$CMPVEC($which(N=>n1),$which(N=>0),M,cmpval); |
|
1658
|
|
|
|
|
|
|
is_asc_sorted = (cmpval > 0); |
|
1659
|
|
|
|
|
|
|
// |
|
1660
|
|
|
|
|
|
|
//-- binary search |
|
1661
|
|
|
|
|
|
|
while (nhi-nlo > 1) { |
|
1662
|
|
|
|
|
|
|
nn = (nhi+nlo) >> 1; |
|
1663
|
|
|
|
|
|
|
$CMPVEC($find(),$which(N=>nn),M,cmpval); |
|
1664
|
|
|
|
|
|
|
if ((cmpval > 0) == is_asc_sorted) |
|
1665
|
|
|
|
|
|
|
nlo=nn; |
|
1666
|
|
|
|
|
|
|
else |
|
1667
|
|
|
|
|
|
|
nhi=nn; |
|
1668
|
|
|
|
|
|
|
} |
|
1669
|
|
|
|
|
|
|
if (nlo==-1) { |
|
1670
|
|
|
|
|
|
|
nhi=0; |
|
1671
|
|
|
|
|
|
|
} else if (nlo==n1) { |
|
1672
|
|
|
|
|
|
|
$CMPVEC($find(),$which(N=>n1),M,cmpval); |
|
1673
|
|
|
|
|
|
|
if (cmpval != 0) carp = 1; |
|
1674
|
|
|
|
|
|
|
nhi = n1; |
|
1675
|
|
|
|
|
|
|
} else { |
|
1676
|
|
|
|
|
|
|
nhi = nlo+1; |
|
1677
|
|
|
|
|
|
|
} |
|
1678
|
|
|
|
|
|
|
$found() = nhi; |
|
1679
|
|
|
|
|
|
|
%} |
|
1680
|
|
|
|
|
|
|
if (carp) warn("some values had to be extrapolated"); |
|
1681
|
|
|
|
|
|
|
), |
|
1682
|
|
|
|
|
|
|
Doc=><<'EOD' |
|
1683
|
|
|
|
|
|
|
=for ref |
|
1684
|
|
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
Routine for searching N-dimensional values - akin to vsearch() for vectors. |
|
1686
|
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
=for example |
|
1688
|
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
$found = vsearchvec($find, $which); |
|
1690
|
|
|
|
|
|
|
$nearest = $which->dice_axis(1,$found); |
|
1691
|
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
Returns for each row-vector in C<$find> the index along dimension N |
|
1693
|
|
|
|
|
|
|
of the least row vector of C<$which> |
|
1694
|
|
|
|
|
|
|
greater or equal to it. |
|
1695
|
|
|
|
|
|
|
C<$which> should be sorted in increasing order. |
|
1696
|
|
|
|
|
|
|
If the value of C<$find> is larger |
|
1697
|
|
|
|
|
|
|
than any member of C<$which>, the index to the last element of C<$which> is |
|
1698
|
|
|
|
|
|
|
returned. |
|
1699
|
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
See also: L. |
|
1701
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1702
|
|
|
|
|
|
|
EOD |
|
1703
|
|
|
|
|
|
|
); |
|
1704
|
|
|
|
|
|
|
|
|
1705
|
|
|
|
|
|
|
pp_def('unionvec', |
|
1706
|
|
|
|
|
|
|
Pars => 'a(M,NA); b(M,NB); [o]c(M,NC=CALC($SIZE(NA) + $SIZE(NB))); indx [o]nc()', |
|
1707
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
1708
|
|
|
|
|
|
|
sub PDL::unionvec { |
|
1709
|
|
|
|
|
|
|
my ($a,$b,$c,$nc) = @_; |
|
1710
|
|
|
|
|
|
|
$c = PDL->null if (!defined($nc)); |
|
1711
|
|
|
|
|
|
|
$nc = PDL->null if (!defined($nc)); |
|
1712
|
|
|
|
|
|
|
PDL::_unionvec_int($a,$b,$c,$nc); |
|
1713
|
|
|
|
|
|
|
return ($c,$nc) if (wantarray); |
|
1714
|
|
|
|
|
|
|
return $c->slice(",0:".($nc->max-1)); |
|
1715
|
|
|
|
|
|
|
} |
|
1716
|
|
|
|
|
|
|
EOD |
|
1717
|
|
|
|
|
|
|
Code => q( |
|
1718
|
|
|
|
|
|
|
PDL_Indx nai=0, nbi=0, nci=$SIZE(NC), sizeNA=$SIZE(NA), sizeNB=$SIZE(NB); |
|
1719
|
|
|
|
|
|
|
int cmpval; |
|
1720
|
|
|
|
|
|
|
loop (NC) %{ |
|
1721
|
|
|
|
|
|
|
if (nai < sizeNA && nbi < sizeNB) { |
|
1722
|
|
|
|
|
|
|
$CMPVEC($a(NA=>nai),$b(NB=>nbi),M,cmpval); |
|
1723
|
|
|
|
|
|
|
} |
|
1724
|
|
|
|
|
|
|
else if (nai < sizeNA) { cmpval = -1; } |
|
1725
|
|
|
|
|
|
|
else if (nbi < sizeNB) { cmpval = 1; } |
|
1726
|
|
|
|
|
|
|
else { nci=NC; break; } |
|
1727
|
|
|
|
|
|
|
// |
|
1728
|
|
|
|
|
|
|
if (cmpval < 0) { |
|
1729
|
|
|
|
|
|
|
//-- CASE: a < b |
|
1730
|
|
|
|
|
|
|
loop (M) %{ $c() = $a(NA=>nai); %} |
|
1731
|
|
|
|
|
|
|
nai++; |
|
1732
|
|
|
|
|
|
|
} |
|
1733
|
|
|
|
|
|
|
else if (cmpval > 0) { |
|
1734
|
|
|
|
|
|
|
//-- CASE: a > b |
|
1735
|
|
|
|
|
|
|
loop (M) %{ $c() = $b(NB=>nbi); %} |
|
1736
|
|
|
|
|
|
|
nbi++; |
|
1737
|
|
|
|
|
|
|
} |
|
1738
|
|
|
|
|
|
|
else { |
|
1739
|
|
|
|
|
|
|
//-- CASE: a == b |
|
1740
|
|
|
|
|
|
|
loop (M) %{ $c() = $a(NA=>nai); %} |
|
1741
|
|
|
|
|
|
|
nai++; |
|
1742
|
|
|
|
|
|
|
nbi++; |
|
1743
|
|
|
|
|
|
|
} |
|
1744
|
|
|
|
|
|
|
%} |
|
1745
|
|
|
|
|
|
|
$nc() = nci; |
|
1746
|
|
|
|
|
|
|
//-- zero unpopulated outputs |
|
1747
|
|
|
|
|
|
|
loop(NC=nci,M) %{ $c() = 0; %} |
|
1748
|
|
|
|
|
|
|
), |
|
1749
|
|
|
|
|
|
|
Doc=><<'EOD' |
|
1750
|
|
|
|
|
|
|
=for ref |
|
1751
|
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
Union of two vector-valued PDLs. |
|
1753
|
|
|
|
|
|
|
|
|
1754
|
|
|
|
|
|
|
Input PDLs $a() and $b() B be sorted in lexicographic order. |
|
1755
|
|
|
|
|
|
|
On return, $nc() holds the actual number of vector-values in the union. |
|
1756
|
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
In scalar context, slices $c() to the actual number of elements in the union |
|
1758
|
|
|
|
|
|
|
and returns the sliced PDL. |
|
1759
|
|
|
|
|
|
|
|
|
1760
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1761
|
|
|
|
|
|
|
EOD |
|
1762
|
|
|
|
|
|
|
); |
|
1763
|
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
pp_def('intersectvec', |
|
1765
|
|
|
|
|
|
|
Pars => 'a(M,NA); b(M,NB); [o]c(M,NC=CALC(PDLMIN($SIZE(NA),$SIZE(NB)))); indx [o]nc()', |
|
1766
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
1767
|
|
|
|
|
|
|
sub PDL::intersectvec { |
|
1768
|
|
|
|
|
|
|
my ($a,$b,$c,$nc) = @_; |
|
1769
|
|
|
|
|
|
|
$c = PDL->null if (!defined($c)); |
|
1770
|
|
|
|
|
|
|
$nc = PDL->null if (!defined($nc)); |
|
1771
|
|
|
|
|
|
|
PDL::_intersectvec_int($a,$b,$c,$nc); |
|
1772
|
|
|
|
|
|
|
return ($c,$nc) if (wantarray); |
|
1773
|
|
|
|
|
|
|
my $nc_max = $nc->max; |
|
1774
|
|
|
|
|
|
|
return ($nc_max > 0 |
|
1775
|
|
|
|
|
|
|
? $c->slice(",0:".($nc_max-1)) |
|
1776
|
|
|
|
|
|
|
: $c->reshape($c->dim(0), 0, ($c->dims)[2..($c->ndims-1)])); |
|
1777
|
|
|
|
|
|
|
} |
|
1778
|
|
|
|
|
|
|
EOD |
|
1779
|
|
|
|
|
|
|
Code => q( |
|
1780
|
|
|
|
|
|
|
PDL_Indx nai=0, nbi=0, nci=0, sizeNA=$SIZE(NA), sizeNB=$SIZE(NB), sizeNC=$SIZE(NC); |
|
1781
|
|
|
|
|
|
|
int cmpval; |
|
1782
|
|
|
|
|
|
|
for ( ; nci < sizeNC && nai < sizeNA && nbi < sizeNB; ) { |
|
1783
|
|
|
|
|
|
|
$CMPVEC($a(NA=>nai),$b(NB=>nbi),M,cmpval); |
|
1784
|
|
|
|
|
|
|
// |
|
1785
|
|
|
|
|
|
|
if (cmpval < 0) { |
|
1786
|
|
|
|
|
|
|
//-- CASE: a < b |
|
1787
|
|
|
|
|
|
|
nai++; |
|
1788
|
|
|
|
|
|
|
} |
|
1789
|
|
|
|
|
|
|
else if (cmpval > 0) { |
|
1790
|
|
|
|
|
|
|
//-- CASE: a > b |
|
1791
|
|
|
|
|
|
|
nbi++; |
|
1792
|
|
|
|
|
|
|
} |
|
1793
|
|
|
|
|
|
|
else { |
|
1794
|
|
|
|
|
|
|
//-- CASE: a == b |
|
1795
|
|
|
|
|
|
|
loop (M) %{ $c(NC=>nci) = $a(NA=>nai); %} |
|
1796
|
|
|
|
|
|
|
nai++; |
|
1797
|
|
|
|
|
|
|
nbi++; |
|
1798
|
|
|
|
|
|
|
nci++; |
|
1799
|
|
|
|
|
|
|
} |
|
1800
|
|
|
|
|
|
|
} |
|
1801
|
|
|
|
|
|
|
$nc() = nci; |
|
1802
|
|
|
|
|
|
|
//-- zero unpopulated outputs |
|
1803
|
|
|
|
|
|
|
loop(NC=nci,M) %{ $c() = 0; %} |
|
1804
|
|
|
|
|
|
|
), |
|
1805
|
|
|
|
|
|
|
Doc=><<'EOD' |
|
1806
|
|
|
|
|
|
|
=for ref |
|
1807
|
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
Intersection of two vector-valued PDLs. |
|
1809
|
|
|
|
|
|
|
Input PDLs $a() and $b() B be sorted in lexicographic order. |
|
1810
|
|
|
|
|
|
|
On return, $nc() holds the actual number of vector-values in the intersection. |
|
1811
|
|
|
|
|
|
|
|
|
1812
|
|
|
|
|
|
|
In scalar context, slices $c() to the actual number of elements in the intersection |
|
1813
|
|
|
|
|
|
|
and returns the sliced PDL. |
|
1814
|
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1816
|
|
|
|
|
|
|
EOD |
|
1817
|
|
|
|
|
|
|
); |
|
1818
|
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
pp_def('setdiffvec', |
|
1820
|
|
|
|
|
|
|
Pars => 'a(M,NA); b(M,NB); [o]c(M,NC=CALC($SIZE(NA))); indx [o]nc()', |
|
1821
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
1822
|
|
|
|
|
|
|
sub PDL::setdiffvec { |
|
1823
|
|
|
|
|
|
|
my ($a,$b,$c,$nc) = @_; |
|
1824
|
|
|
|
|
|
|
$c = PDL->null if (!defined($c)); |
|
1825
|
|
|
|
|
|
|
$nc = PDL->null if (!defined($nc)); |
|
1826
|
|
|
|
|
|
|
PDL::_setdiffvec_int($a,$b,$c,$nc); |
|
1827
|
|
|
|
|
|
|
return ($c,$nc) if (wantarray); |
|
1828
|
|
|
|
|
|
|
my $nc_max = $nc->max; |
|
1829
|
|
|
|
|
|
|
return ($nc_max > 0 |
|
1830
|
|
|
|
|
|
|
? $c->slice(",0:".($nc_max-1)) |
|
1831
|
|
|
|
|
|
|
: $c->reshape($c->dim(0), 0, ($c->dims)[2..($c->ndims-1)])); |
|
1832
|
|
|
|
|
|
|
} |
|
1833
|
|
|
|
|
|
|
EOD |
|
1834
|
|
|
|
|
|
|
Code => q( |
|
1835
|
|
|
|
|
|
|
PDL_Indx nai=0, nbi=0, nci=0, sizeNA=$SIZE(NA), sizeNB=$SIZE(NB), sizeNC=$SIZE(NC); |
|
1836
|
|
|
|
|
|
|
int cmpval; |
|
1837
|
|
|
|
|
|
|
for ( ; nci < sizeNC && nai < sizeNA && nbi < sizeNB ; ) { |
|
1838
|
|
|
|
|
|
|
$CMPVEC($a(NA=>nai),$b(NB=>nbi),M,cmpval); |
|
1839
|
|
|
|
|
|
|
// |
|
1840
|
|
|
|
|
|
|
if (cmpval < 0) { |
|
1841
|
|
|
|
|
|
|
//-- CASE: a < b |
|
1842
|
|
|
|
|
|
|
loop (M) %{ $c(NC=>nci) = $a(NA=>nai); %} |
|
1843
|
|
|
|
|
|
|
nai++; |
|
1844
|
|
|
|
|
|
|
nci++; |
|
1845
|
|
|
|
|
|
|
} |
|
1846
|
|
|
|
|
|
|
else if (cmpval > 0) { |
|
1847
|
|
|
|
|
|
|
//-- CASE: a > b |
|
1848
|
|
|
|
|
|
|
nbi++; |
|
1849
|
|
|
|
|
|
|
} |
|
1850
|
|
|
|
|
|
|
else { |
|
1851
|
|
|
|
|
|
|
//-- CASE: a == b |
|
1852
|
|
|
|
|
|
|
nai++; |
|
1853
|
|
|
|
|
|
|
nbi++; |
|
1854
|
|
|
|
|
|
|
} |
|
1855
|
|
|
|
|
|
|
} |
|
1856
|
|
|
|
|
|
|
for ( ; nci < sizeNC && nai < sizeNA ; nai++,nci++ ) { |
|
1857
|
|
|
|
|
|
|
loop (M) %{ $c(NC=>nci) = $a(NA=>nai); %} |
|
1858
|
|
|
|
|
|
|
} |
|
1859
|
|
|
|
|
|
|
$nc() = nci; |
|
1860
|
|
|
|
|
|
|
//-- zero unpopulated outputs |
|
1861
|
|
|
|
|
|
|
loop (NC=nci,M) %{ $c() = 0; %} |
|
1862
|
|
|
|
|
|
|
), |
|
1863
|
|
|
|
|
|
|
Doc=><<'EOD' |
|
1864
|
|
|
|
|
|
|
=for ref |
|
1865
|
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
Set-difference ($a() \ $b()) of two vector-valued PDLs. |
|
1867
|
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
Input PDLs $a() and $b() B be sorted in lexicographic order. |
|
1869
|
|
|
|
|
|
|
On return, $nc() holds the actual number of vector-values in the computed vector set. |
|
1870
|
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
In scalar context, slices $c() to the actual number of elements in the output vector set |
|
1872
|
|
|
|
|
|
|
and returns the sliced PDL. |
|
1873
|
|
|
|
|
|
|
|
|
1874
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1875
|
|
|
|
|
|
|
EOD |
|
1876
|
|
|
|
|
|
|
); |
|
1877
|
|
|
|
|
|
|
|
|
1878
|
|
|
|
|
|
|
pp_add_macros( |
|
1879
|
|
|
|
|
|
|
CMPVAL => sub { |
|
1880
|
|
|
|
|
|
|
my ($val1, $val2) = @_; |
|
1881
|
|
|
|
|
|
|
"(($val1) < ($val2) ? -1 : ($val1) > ($val2) ? 1 : 0)"; |
|
1882
|
|
|
|
|
|
|
}, |
|
1883
|
|
|
|
|
|
|
); |
|
1884
|
|
|
|
|
|
|
|
|
1885
|
|
|
|
|
|
|
pp_def('union_sorted', |
|
1886
|
|
|
|
|
|
|
Pars => 'a(NA); b(NB); [o]c(NC=CALC($SIZE(NA) + $SIZE(NB))); indx [o]nc()', |
|
1887
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
1888
|
|
|
|
|
|
|
sub PDL::union_sorted { |
|
1889
|
|
|
|
|
|
|
my ($a,$b,$c,$nc) = @_; |
|
1890
|
|
|
|
|
|
|
$c = PDL->null if (!defined($c)); |
|
1891
|
|
|
|
|
|
|
$nc = PDL->null if (!defined($nc)); |
|
1892
|
|
|
|
|
|
|
PDL::_union_sorted_int($a,$b,$c,$nc); |
|
1893
|
|
|
|
|
|
|
return ($c,$nc) if (wantarray); |
|
1894
|
|
|
|
|
|
|
return $c->slice("0:".($nc->max-1)); |
|
1895
|
|
|
|
|
|
|
} |
|
1896
|
|
|
|
|
|
|
EOD |
|
1897
|
|
|
|
|
|
|
Code => q( |
|
1898
|
|
|
|
|
|
|
PDL_Indx nai=0, nbi=0, nci=$SIZE(NC), sizeNA=$SIZE(NA), sizeNB=$SIZE(NB); |
|
1899
|
|
|
|
|
|
|
int cmpval; |
|
1900
|
|
|
|
|
|
|
loop (NC) %{ |
|
1901
|
|
|
|
|
|
|
if (nai < sizeNA && nbi < sizeNB) { |
|
1902
|
|
|
|
|
|
|
cmpval = $CMPVAL($a(NA=>nai), $b(NB=>nbi)); |
|
1903
|
|
|
|
|
|
|
} |
|
1904
|
|
|
|
|
|
|
else if (nai < sizeNA) { cmpval = -1; } |
|
1905
|
|
|
|
|
|
|
else if (nbi < sizeNB) { cmpval = 1; } |
|
1906
|
|
|
|
|
|
|
else { nci = NC; break; } |
|
1907
|
|
|
|
|
|
|
// |
|
1908
|
|
|
|
|
|
|
if (cmpval < 0) { |
|
1909
|
|
|
|
|
|
|
//-- CASE: a < b |
|
1910
|
|
|
|
|
|
|
$c() = $a(NA=>nai); |
|
1911
|
|
|
|
|
|
|
nai++; |
|
1912
|
|
|
|
|
|
|
} |
|
1913
|
|
|
|
|
|
|
else if (cmpval > 0) { |
|
1914
|
|
|
|
|
|
|
//-- CASE: a > b |
|
1915
|
|
|
|
|
|
|
$c() = $b(NB=>nbi); |
|
1916
|
|
|
|
|
|
|
nbi++; |
|
1917
|
|
|
|
|
|
|
} |
|
1918
|
|
|
|
|
|
|
else { |
|
1919
|
|
|
|
|
|
|
//-- CASE: a == b |
|
1920
|
|
|
|
|
|
|
$c() = $a(NA=>nai); |
|
1921
|
|
|
|
|
|
|
nai++; |
|
1922
|
|
|
|
|
|
|
nbi++; |
|
1923
|
|
|
|
|
|
|
} |
|
1924
|
|
|
|
|
|
|
%} |
|
1925
|
|
|
|
|
|
|
$nc() = nci; |
|
1926
|
|
|
|
|
|
|
loop (NC=nci) %{ |
|
1927
|
|
|
|
|
|
|
//-- zero unpopulated outputs |
|
1928
|
|
|
|
|
|
|
$c() = 0; |
|
1929
|
|
|
|
|
|
|
%} |
|
1930
|
|
|
|
|
|
|
), |
|
1931
|
|
|
|
|
|
|
Doc=><<'EOD' |
|
1932
|
|
|
|
|
|
|
=for ref |
|
1933
|
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
Union of two flat sorted unique-valued PDLs. |
|
1935
|
|
|
|
|
|
|
Input PDLs $a() and $b() B be sorted in lexicographic order and contain no duplicates. |
|
1936
|
|
|
|
|
|
|
On return, $nc() holds the actual number of values in the union. |
|
1937
|
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
In scalar context, reshapes $c() to the actual number of elements in the union and returns it. |
|
1939
|
|
|
|
|
|
|
|
|
1940
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1941
|
|
|
|
|
|
|
EOD |
|
1942
|
|
|
|
|
|
|
); |
|
1943
|
|
|
|
|
|
|
|
|
1944
|
|
|
|
|
|
|
pp_def('intersect_sorted', |
|
1945
|
|
|
|
|
|
|
Pars => 'a(NA); b(NB); [o]c(NC=CALC(PDLMIN($SIZE(NA),$SIZE(NB)))); indx [o]nc()', |
|
1946
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
1947
|
|
|
|
|
|
|
sub PDL::intersect_sorted { |
|
1948
|
|
|
|
|
|
|
my ($a,$b,$c,$nc) = @_; |
|
1949
|
|
|
|
|
|
|
$c = PDL->null if (!defined($c)); |
|
1950
|
|
|
|
|
|
|
$nc = PDL->null if (!defined($nc)); |
|
1951
|
|
|
|
|
|
|
PDL::_intersect_sorted_int($a,$b,$c,$nc); |
|
1952
|
|
|
|
|
|
|
return ($c,$nc) if (wantarray); |
|
1953
|
|
|
|
|
|
|
my $nc_max = $nc->max; |
|
1954
|
|
|
|
|
|
|
return ($nc_max > 0 |
|
1955
|
|
|
|
|
|
|
? $c->slice("0:".($nc_max-1)) |
|
1956
|
|
|
|
|
|
|
: $c->reshape(0, ($c->dims)[1..($c->ndims-1)])); |
|
1957
|
|
|
|
|
|
|
} |
|
1958
|
|
|
|
|
|
|
EOD |
|
1959
|
|
|
|
|
|
|
Code => q( |
|
1960
|
|
|
|
|
|
|
PDL_Indx nai=0, nbi=0, nci=0, sizeNA=$SIZE(NA), sizeNB=$SIZE(NB), sizeNC=$SIZE(NC); |
|
1961
|
|
|
|
|
|
|
int cmpval; |
|
1962
|
|
|
|
|
|
|
for ( ; nci < sizeNC && nai < sizeNA && nbi < sizeNB; ) { |
|
1963
|
|
|
|
|
|
|
cmpval = $CMPVAL($a(NA=>nai),$b(NB=>nbi)); |
|
1964
|
|
|
|
|
|
|
// |
|
1965
|
|
|
|
|
|
|
if (cmpval < 0) { |
|
1966
|
|
|
|
|
|
|
//-- CASE: a < b |
|
1967
|
|
|
|
|
|
|
nai++; |
|
1968
|
|
|
|
|
|
|
} |
|
1969
|
|
|
|
|
|
|
else if (cmpval > 0) { |
|
1970
|
|
|
|
|
|
|
//-- CASE: a > b |
|
1971
|
|
|
|
|
|
|
nbi++; |
|
1972
|
|
|
|
|
|
|
} |
|
1973
|
|
|
|
|
|
|
else { |
|
1974
|
|
|
|
|
|
|
//-- CASE: a == b |
|
1975
|
|
|
|
|
|
|
$c(NC=>nci) = $a(NA=>nai); |
|
1976
|
|
|
|
|
|
|
nai++; |
|
1977
|
|
|
|
|
|
|
nbi++; |
|
1978
|
|
|
|
|
|
|
nci++; |
|
1979
|
|
|
|
|
|
|
} |
|
1980
|
|
|
|
|
|
|
} |
|
1981
|
|
|
|
|
|
|
$nc() = nci; |
|
1982
|
|
|
|
|
|
|
for ( ; nci < sizeNC; nci++) { |
|
1983
|
|
|
|
|
|
|
//-- zero unpopulated outputs |
|
1984
|
|
|
|
|
|
|
$c(NC=>nci) = 0; |
|
1985
|
|
|
|
|
|
|
} |
|
1986
|
|
|
|
|
|
|
), |
|
1987
|
|
|
|
|
|
|
Doc=><<'EOD' |
|
1988
|
|
|
|
|
|
|
=for ref |
|
1989
|
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
Intersection of two flat sorted unique-valued PDLs. |
|
1991
|
|
|
|
|
|
|
Input PDLs $a() and $b() B be sorted in lexicographic order and contain no duplicates. |
|
1992
|
|
|
|
|
|
|
On return, $nc() holds the actual number of values in the intersection. |
|
1993
|
|
|
|
|
|
|
|
|
1994
|
|
|
|
|
|
|
In scalar context, reshapes $c() to the actual number of elements in the intersection and returns it. |
|
1995
|
|
|
|
|
|
|
|
|
1996
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
1997
|
|
|
|
|
|
|
EOD |
|
1998
|
|
|
|
|
|
|
); |
|
1999
|
|
|
|
|
|
|
|
|
2000
|
|
|
|
|
|
|
pp_def('setdiff_sorted', |
|
2001
|
|
|
|
|
|
|
Pars => 'a(NA); b(NB); [o]c(NC=CALC($SIZE(NA))); indx [o]nc()', |
|
2002
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
2003
|
|
|
|
|
|
|
sub PDL::setdiff_sorted { |
|
2004
|
|
|
|
|
|
|
my ($a,$b,$c,$nc) = @_; |
|
2005
|
|
|
|
|
|
|
$c = PDL->null if (!defined($c)); |
|
2006
|
|
|
|
|
|
|
$nc = PDL->null if (!defined($nc)); |
|
2007
|
|
|
|
|
|
|
PDL::_setdiff_sorted_int($a,$b,$c,$nc); |
|
2008
|
|
|
|
|
|
|
return ($c,$nc) if (wantarray); |
|
2009
|
|
|
|
|
|
|
my $nc_max = $nc->max; |
|
2010
|
|
|
|
|
|
|
return ($nc_max > 0 |
|
2011
|
|
|
|
|
|
|
? $c->slice("0:".($nc_max-1)) |
|
2012
|
|
|
|
|
|
|
: $c->reshape(0, ($c->dims)[1..($c->ndims-1)])); |
|
2013
|
|
|
|
|
|
|
} |
|
2014
|
|
|
|
|
|
|
EOD |
|
2015
|
|
|
|
|
|
|
Code => q( |
|
2016
|
|
|
|
|
|
|
PDL_Indx nai=0, nbi=0, nci=0, sizeNA=$SIZE(NA), sizeNB=$SIZE(NB), sizeNC=$SIZE(NC); |
|
2017
|
|
|
|
|
|
|
int cmpval; |
|
2018
|
|
|
|
|
|
|
for ( ; nci < sizeNC && nai < sizeNA && nbi < sizeNB ; ) { |
|
2019
|
|
|
|
|
|
|
cmpval = $CMPVAL($a(NA=>nai),$b(NB=>nbi)); |
|
2020
|
|
|
|
|
|
|
// |
|
2021
|
|
|
|
|
|
|
if (cmpval < 0) { |
|
2022
|
|
|
|
|
|
|
//-- CASE: a < b |
|
2023
|
|
|
|
|
|
|
$c(NC=>nci) = $a(NA=>nai); |
|
2024
|
|
|
|
|
|
|
nai++; |
|
2025
|
|
|
|
|
|
|
nci++; |
|
2026
|
|
|
|
|
|
|
} |
|
2027
|
|
|
|
|
|
|
else if (cmpval > 0) { |
|
2028
|
|
|
|
|
|
|
//-- CASE: a > b |
|
2029
|
|
|
|
|
|
|
nbi++; |
|
2030
|
|
|
|
|
|
|
} |
|
2031
|
|
|
|
|
|
|
else { |
|
2032
|
|
|
|
|
|
|
//-- CASE: a == b |
|
2033
|
|
|
|
|
|
|
nai++; |
|
2034
|
|
|
|
|
|
|
nbi++; |
|
2035
|
|
|
|
|
|
|
} |
|
2036
|
|
|
|
|
|
|
} |
|
2037
|
|
|
|
|
|
|
for ( ; nci < sizeNC && nai < sizeNA ; nai++,nci++ ) { |
|
2038
|
|
|
|
|
|
|
$c(NC=>nci) = $a(NA=>nai); |
|
2039
|
|
|
|
|
|
|
} |
|
2040
|
|
|
|
|
|
|
$nc() = nci; |
|
2041
|
|
|
|
|
|
|
for ( ; nci < sizeNC; nci++) { |
|
2042
|
|
|
|
|
|
|
//-- zero unpopulated outputs |
|
2043
|
|
|
|
|
|
|
$c(NC=>nci) = 0; |
|
2044
|
|
|
|
|
|
|
} |
|
2045
|
|
|
|
|
|
|
), |
|
2046
|
|
|
|
|
|
|
Doc=><<'EOD' |
|
2047
|
|
|
|
|
|
|
=for ref |
|
2048
|
|
|
|
|
|
|
|
|
2049
|
|
|
|
|
|
|
Set-difference ($a() \ $b()) of two flat sorted unique-valued PDLs. |
|
2050
|
|
|
|
|
|
|
|
|
2051
|
|
|
|
|
|
|
Input PDLs $a() and $b() B be sorted in lexicographic order and contain no duplicate values. |
|
2052
|
|
|
|
|
|
|
On return, $nc() holds the actual number of values in the computed vector set. |
|
2053
|
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
In scalar context, reshapes $c() to the actual number of elements in the difference set and returns it. |
|
2055
|
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
2057
|
|
|
|
|
|
|
EOD |
|
2058
|
|
|
|
|
|
|
); |
|
2059
|
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
pp_def('vcos', |
|
2061
|
|
|
|
|
|
|
Pars => join('', |
|
2062
|
|
|
|
|
|
|
"a(M,N);", ##-- logical (D,T) |
|
2063
|
|
|
|
|
|
|
"b(M);", ##-- logical (D,1) |
|
2064
|
|
|
|
|
|
|
"float+ [o]vcos(N);", ##-- logical (T) |
|
2065
|
|
|
|
|
|
|
), |
|
2066
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
2067
|
|
|
|
|
|
|
HandleBad => 1, |
|
2068
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
2069
|
|
|
|
|
|
|
broadcastloop %{ |
|
2070
|
|
|
|
|
|
|
$GENERIC(vcos) bnorm = 0; |
|
2071
|
|
|
|
|
|
|
loop(M) %{ |
|
2072
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(b())) continue;,) |
|
2073
|
|
|
|
|
|
|
bnorm += $b() * $b(); |
|
2074
|
|
|
|
|
|
|
%} |
|
2075
|
|
|
|
|
|
|
if (bnorm == 0) { |
|
2076
|
|
|
|
|
|
|
/*-- null-vector b(): set all vcos()=NAN --*/ |
|
2077
|
|
|
|
|
|
|
loop (N) %{ $vcos() = NAN; %} |
|
2078
|
|
|
|
|
|
|
continue; |
|
2079
|
|
|
|
|
|
|
} |
|
2080
|
|
|
|
|
|
|
bnorm = sqrtl(bnorm); |
|
2081
|
|
|
|
|
|
|
/*-- usual case: compute values for N-slice of b() --*/ |
|
2082
|
|
|
|
|
|
|
loop (N) %{ |
|
2083
|
|
|
|
|
|
|
$GENERIC(vcos) anorm = 0, vval = 0; |
|
2084
|
|
|
|
|
|
|
loop (M) %{ |
|
2085
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a())) continue;,) |
|
2086
|
|
|
|
|
|
|
$GENERIC(vcos) aval = $a(); |
|
2087
|
|
|
|
|
|
|
anorm += aval * aval; |
|
2088
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(b())) continue;,) |
|
2089
|
|
|
|
|
|
|
vval += aval * $b(); |
|
2090
|
|
|
|
|
|
|
%} |
|
2091
|
|
|
|
|
|
|
/*-- normalize --*/ |
|
2092
|
|
|
|
|
|
|
anorm = sqrtl(anorm); |
|
2093
|
|
|
|
|
|
|
if (anorm != 0) { |
|
2094
|
|
|
|
|
|
|
/*-- usual case a(), b() non-null --*/ |
|
2095
|
|
|
|
|
|
|
$vcos() = vval / (anorm * bnorm); |
|
2096
|
|
|
|
|
|
|
} else { |
|
2097
|
|
|
|
|
|
|
/*-- null-vector a(): set vcos()=NAN --*/ |
|
2098
|
|
|
|
|
|
|
$vcos() = NAN; |
|
2099
|
|
|
|
|
|
|
} |
|
2100
|
|
|
|
|
|
|
%} |
|
2101
|
|
|
|
|
|
|
%} |
|
2102
|
|
|
|
|
|
|
if ( $PDLSTATEISBAD(a) || $PDLSTATEISBAD(b) ) |
|
2103
|
|
|
|
|
|
|
$PDLSTATESETBAD(vcos); |
|
2104
|
|
|
|
|
|
|
EOF |
|
2105
|
|
|
|
|
|
|
Doc => q{ |
|
2106
|
|
|
|
|
|
|
Computes the vector cosine similarity of a dense vector $b() with respect |
|
2107
|
|
|
|
|
|
|
to each row $a(*,i) of a dense PDL $a(). This is basically the same |
|
2108
|
|
|
|
|
|
|
thing as: |
|
2109
|
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
inner($a, $b) / $a->magnover * $b->magnover |
|
2111
|
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
... but should be much faster to compute, and avoids allocating |
|
2113
|
|
|
|
|
|
|
potentially large temporaries for the vector magnitudes. Output values |
|
2114
|
|
|
|
|
|
|
in $vcos() are cosine similarities in the range [-1,1], except for |
|
2115
|
|
|
|
|
|
|
zero-magnitude vectors which will result in NaN values in $vcos(). |
|
2116
|
|
|
|
|
|
|
|
|
2117
|
|
|
|
|
|
|
You can use PDL broadcasting to batch-compute distances for multiple $b() |
|
2118
|
|
|
|
|
|
|
vectors simultaneously: |
|
2119
|
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
$bx = random($M, $NB); ##-- get $NB random vectors of size $N |
|
2121
|
|
|
|
|
|
|
$vcos = vcos($a,$bx); ##-- $vcos(i,j) ~ sim($a(,i),$b(,j)) |
|
2122
|
|
|
|
|
|
|
|
|
2123
|
|
|
|
|
|
|
Contributed by Bryan Jurish Emoocow@cpan.orgE. |
|
2124
|
|
|
|
|
|
|
}, |
|
2125
|
|
|
|
|
|
|
BadDoc=> q{ |
|
2126
|
|
|
|
|
|
|
vcos() will set the bad status flag on the output $vcos() if |
|
2127
|
|
|
|
|
|
|
it is set on either of the inputs $a() or $b(), but BAD values |
|
2128
|
|
|
|
|
|
|
will otherwise be ignored for computing the cosine similarity. |
|
2129
|
|
|
|
|
|
|
}, |
|
2130
|
|
|
|
|
|
|
); |
|
2131
|
|
|
|
|
|
|
|
|
2132
|
|
|
|
|
|
|
pp_addhdr(<<'EOH'); |
|
2133
|
|
|
|
|
|
|
extern int pdl_srand_threads; |
|
2134
|
|
|
|
|
|
|
extern uint64_t *pdl_rand_state; |
|
2135
|
|
|
|
|
|
|
void pdl_srand(uint64_t **s, uint64_t seed, int n); |
|
2136
|
|
|
|
|
|
|
double pdl_drand(uint64_t *s); |
|
2137
|
|
|
|
|
|
|
#define PDL_MAYBE_SRAND \ |
|
2138
|
|
|
|
|
|
|
if (pdl_srand_threads < 0) \ |
|
2139
|
|
|
|
|
|
|
pdl_srand(&pdl_rand_state, PDL->pdl_seed(), PDL->online_cpus()); |
|
2140
|
|
|
|
|
|
|
#define PDL_RAND_SET_OFFSET(v, thr, pdl) \ |
|
2141
|
|
|
|
|
|
|
if (v < 0) { \ |
|
2142
|
|
|
|
|
|
|
if (thr.mag_nthr >= 0) { \ |
|
2143
|
|
|
|
|
|
|
int thr_no = PDL->magic_get_thread(pdl); \ |
|
2144
|
|
|
|
|
|
|
if (thr_no < 0) return PDL->make_error_simple(PDL_EFATAL, "Invalid pdl_magic_get_thread!"); \ |
|
2145
|
|
|
|
|
|
|
v = thr_no == 0 ? thr_no : thr_no % PDL->online_cpus(); \ |
|
2146
|
|
|
|
|
|
|
} else { \ |
|
2147
|
|
|
|
|
|
|
v = 0; \ |
|
2148
|
|
|
|
|
|
|
} \ |
|
2149
|
|
|
|
|
|
|
} |
|
2150
|
|
|
|
|
|
|
EOH |
|
2151
|
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
pp_def( |
|
2153
|
|
|
|
|
|
|
'srandom', |
|
2154
|
|
|
|
|
|
|
Pars=>'a();', |
|
2155
|
|
|
|
|
|
|
GenericTypes => ['Q'], |
|
2156
|
|
|
|
|
|
|
Code => <<'EOF', |
|
2157
|
|
|
|
|
|
|
pdl_srand(&pdl_rand_state, (uint64_t)$a(), PDL->online_cpus()); |
|
2158
|
|
|
|
|
|
|
EOF |
|
2159
|
|
|
|
|
|
|
NoPthread => 1, |
|
2160
|
|
|
|
|
|
|
HaveBroadcasting => 0, |
|
2161
|
|
|
|
|
|
|
Doc=> <<'EOF', |
|
2162
|
|
|
|
|
|
|
=for ref |
|
2163
|
|
|
|
|
|
|
|
|
2164
|
|
|
|
|
|
|
Seed random-number generator with a 64-bit int. Will generate seed data |
|
2165
|
|
|
|
|
|
|
for a number of threads equal to the return-value of |
|
2166
|
|
|
|
|
|
|
L. |
|
2167
|
|
|
|
|
|
|
As of 2.062, the generator changed from Perl's generator to xoshiro256++ |
|
2168
|
|
|
|
|
|
|
(see L). |
|
2169
|
|
|
|
|
|
|
Before PDL 2.090, this was called C, but was renamed to avoid |
|
2170
|
|
|
|
|
|
|
clashing with Perl's built-in. |
|
2171
|
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
=for usage |
|
2173
|
|
|
|
|
|
|
|
|
2174
|
|
|
|
|
|
|
srandom(); # uses current time |
|
2175
|
|
|
|
|
|
|
srandom(5); # fixed number e.g. for testing |
|
2176
|
|
|
|
|
|
|
|
|
2177
|
|
|
|
|
|
|
EOF |
|
2178
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
2179
|
|
|
|
|
|
|
*srandom = \&PDL::srandom; |
|
2180
|
|
|
|
|
|
|
sub PDL::srandom { PDL::_srandom_int($_[0] // PDL::Core::seed()) } |
|
2181
|
|
|
|
|
|
|
EOD |
|
2182
|
|
|
|
|
|
|
); |
|
2183
|
|
|
|
|
|
|
|
|
2184
|
|
|
|
|
|
|
pp_def( |
|
2185
|
|
|
|
|
|
|
'random', |
|
2186
|
|
|
|
|
|
|
Pars=>'[o] a();', |
|
2187
|
|
|
|
|
|
|
PMFunc => '', |
|
2188
|
|
|
|
|
|
|
Code => <<'EOF', |
|
2189
|
|
|
|
|
|
|
PDL_MAYBE_SRAND |
|
2190
|
|
|
|
|
|
|
int rand_offset = -1; |
|
2191
|
|
|
|
|
|
|
broadcastloop %{ |
|
2192
|
|
|
|
|
|
|
PDL_RAND_SET_OFFSET(rand_offset, $PRIV(broadcast), $PDL(a)); |
|
2193
|
|
|
|
|
|
|
$a() = pdl_drand(pdl_rand_state + 4*rand_offset); |
|
2194
|
|
|
|
|
|
|
%} |
|
2195
|
|
|
|
|
|
|
EOF |
|
2196
|
|
|
|
|
|
|
Doc=> <<'EOF', |
|
2197
|
|
|
|
|
|
|
=for ref |
|
2198
|
|
|
|
|
|
|
|
|
2199
|
|
|
|
|
|
|
Constructor which returns ndarray of random numbers, real data-types only. |
|
2200
|
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
=for usage |
|
2202
|
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
$x = random([type], $nx, $ny, $nz,...); |
|
2204
|
|
|
|
|
|
|
$x = random $y; |
|
2205
|
|
|
|
|
|
|
|
|
2206
|
|
|
|
|
|
|
etc (see L). |
|
2207
|
|
|
|
|
|
|
|
|
2208
|
|
|
|
|
|
|
This is the uniform distribution between 0 and 1 (assumedly |
|
2209
|
|
|
|
|
|
|
excluding 1 itself). The arguments are the same as C |
|
2210
|
|
|
|
|
|
|
(q.v.) - i.e. one can specify dimensions, types or give |
|
2211
|
|
|
|
|
|
|
a template. |
|
2212
|
|
|
|
|
|
|
|
|
2213
|
|
|
|
|
|
|
You can use the PDL function L to seed the random generator. |
|
2214
|
|
|
|
|
|
|
If it has not been called yet, it will be with the current time. |
|
2215
|
|
|
|
|
|
|
As of 2.062, the generator changed from Perl's generator to xoshiro256++ |
|
2216
|
|
|
|
|
|
|
(see L). |
|
2217
|
|
|
|
|
|
|
EOF |
|
2218
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
2219
|
|
|
|
|
|
|
sub random { ref($_[0]) && ref($_[0]) ne 'PDL::Type' ? $_[0]->random : PDL->random(@_) } |
|
2220
|
|
|
|
|
|
|
sub PDL::random { |
|
2221
|
|
|
|
|
|
|
splice @_, 1, 0, double() if !ref($_[0]) and @_<=1; |
|
2222
|
|
|
|
|
|
|
my $x = &PDL::Core::_construct; |
|
2223
|
|
|
|
|
|
|
PDL::_random_int($x); |
|
2224
|
|
|
|
|
|
|
return $x; |
|
2225
|
|
|
|
|
|
|
} |
|
2226
|
|
|
|
|
|
|
EOD |
|
2227
|
|
|
|
|
|
|
); |
|
2228
|
|
|
|
|
|
|
|
|
2229
|
|
|
|
|
|
|
pp_def( |
|
2230
|
|
|
|
|
|
|
'randsym', |
|
2231
|
|
|
|
|
|
|
Pars=>'[o] a();', |
|
2232
|
|
|
|
|
|
|
PMFunc => '', |
|
2233
|
|
|
|
|
|
|
Code => <<'EOF', |
|
2234
|
|
|
|
|
|
|
PDL_MAYBE_SRAND |
|
2235
|
|
|
|
|
|
|
int rand_offset = -1; |
|
2236
|
|
|
|
|
|
|
broadcastloop %{ |
|
2237
|
|
|
|
|
|
|
PDL_RAND_SET_OFFSET(rand_offset, $PRIV(broadcast), $PDL(a)); |
|
2238
|
|
|
|
|
|
|
long double tmp; |
|
2239
|
|
|
|
|
|
|
do tmp = pdl_drand(pdl_rand_state + 4*rand_offset); while (tmp == 0.0); /* 0 < tmp < 1 */ |
|
2240
|
|
|
|
|
|
|
$a() = tmp; |
|
2241
|
|
|
|
|
|
|
%} |
|
2242
|
|
|
|
|
|
|
EOF |
|
2243
|
|
|
|
|
|
|
Doc=> <<'EOF', |
|
2244
|
|
|
|
|
|
|
=for ref |
|
2245
|
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
Constructor which returns ndarray of random numbers, real data-types only. |
|
2247
|
|
|
|
|
|
|
|
|
2248
|
|
|
|
|
|
|
=for usage |
|
2249
|
|
|
|
|
|
|
|
|
2250
|
|
|
|
|
|
|
$x = randsym([type], $nx, $ny, $nz,...); |
|
2251
|
|
|
|
|
|
|
$x = randsym $y; |
|
2252
|
|
|
|
|
|
|
|
|
2253
|
|
|
|
|
|
|
etc (see L). |
|
2254
|
|
|
|
|
|
|
|
|
2255
|
|
|
|
|
|
|
This is the uniform distribution between 0 and 1 (excluding both 0 and |
|
2256
|
|
|
|
|
|
|
1, cf L). The arguments are the same as C (q.v.) - |
|
2257
|
|
|
|
|
|
|
i.e. one can specify dimensions, types or give a template. |
|
2258
|
|
|
|
|
|
|
|
|
2259
|
|
|
|
|
|
|
You can use the PDL function L to seed the random generator. |
|
2260
|
|
|
|
|
|
|
If it has not been called yet, it will be with the current time. |
|
2261
|
|
|
|
|
|
|
EOF |
|
2262
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
2263
|
|
|
|
|
|
|
sub randsym { ref($_[0]) && ref($_[0]) ne 'PDL::Type' ? $_[0]->randsym : PDL->randsym(@_) } |
|
2264
|
|
|
|
|
|
|
sub PDL::randsym { |
|
2265
|
|
|
|
|
|
|
splice @_, 1, 0, double() if !ref($_[0]) and @_<=1; |
|
2266
|
|
|
|
|
|
|
my $x = &PDL::Core::_construct; |
|
2267
|
|
|
|
|
|
|
PDL::_randsym_int($x); |
|
2268
|
|
|
|
|
|
|
return $x; |
|
2269
|
|
|
|
|
|
|
} |
|
2270
|
|
|
|
|
|
|
EOD |
|
2271
|
|
|
|
|
|
|
); |
|
2272
|
|
|
|
|
|
|
|
|
2273
|
|
|
|
|
|
|
pp_add_exported('','grandom'); |
|
2274
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
2275
|
|
|
|
|
|
|
=head2 grandom |
|
2276
|
|
|
|
|
|
|
|
|
2277
|
|
|
|
|
|
|
=for ref |
|
2278
|
|
|
|
|
|
|
|
|
2279
|
|
|
|
|
|
|
Constructor which returns ndarray of Gaussian random numbers |
|
2280
|
|
|
|
|
|
|
|
|
2281
|
|
|
|
|
|
|
=for usage |
|
2282
|
|
|
|
|
|
|
|
|
2283
|
|
|
|
|
|
|
$x = grandom([type], $nx, $ny, $nz,...); |
|
2284
|
|
|
|
|
|
|
$x = grandom $y; |
|
2285
|
|
|
|
|
|
|
|
|
2286
|
|
|
|
|
|
|
etc (see L). |
|
2287
|
|
|
|
|
|
|
|
|
2288
|
|
|
|
|
|
|
This is generated using the math library routine C. |
|
2289
|
|
|
|
|
|
|
|
|
2290
|
|
|
|
|
|
|
Mean = 0, Stddev = 1 |
|
2291
|
|
|
|
|
|
|
|
|
2292
|
|
|
|
|
|
|
You can use the PDL function L to seed the random generator. |
|
2293
|
|
|
|
|
|
|
If it has not been called yet, it will be with the current time. |
|
2294
|
|
|
|
|
|
|
|
|
2295
|
|
|
|
|
|
|
=cut |
|
2296
|
|
|
|
|
|
|
|
|
2297
|
|
|
|
|
|
|
sub grandom { ref($_[0]) && ref($_[0]) ne 'PDL::Type' ? $_[0]->grandom : PDL->grandom(@_) } |
|
2298
|
|
|
|
|
|
|
sub PDL::grandom { |
|
2299
|
|
|
|
|
|
|
my $x = &PDL::Core::_construct; |
|
2300
|
|
|
|
|
|
|
use PDL::Math 'ndtri'; |
|
2301
|
|
|
|
|
|
|
$x .= ndtri(randsym($x)); |
|
2302
|
|
|
|
|
|
|
return $x; |
|
2303
|
|
|
|
|
|
|
} |
|
2304
|
|
|
|
|
|
|
EOD |
|
2305
|
|
|
|
|
|
|
|
|
2306
|
|
|
|
|
|
|
############################################################### |
|
2307
|
|
|
|
|
|
|
# binary searches in an ndarray; various forms |
|
2308
|
|
|
|
|
|
|
############################################################### |
|
2309
|
|
|
|
|
|
|
|
|
2310
|
|
|
|
|
|
|
# generic front end; defaults to vsearch_sample for backwards compatibility |
|
2311
|
|
|
|
|
|
|
|
|
2312
|
|
|
|
|
|
|
pp_add_exported('','vsearch'); |
|
2313
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
2314
|
|
|
|
|
|
|
=head2 vsearch |
|
2315
|
|
|
|
|
|
|
|
|
2316
|
|
|
|
|
|
|
=for sig |
|
2317
|
|
|
|
|
|
|
|
|
2318
|
|
|
|
|
|
|
Signature: ( vals(); xs(n); [o] indx(); [\%options] ) |
|
2319
|
|
|
|
|
|
|
|
|
2320
|
|
|
|
|
|
|
=for ref |
|
2321
|
|
|
|
|
|
|
|
|
2322
|
|
|
|
|
|
|
Efficiently search for values in a sorted ndarray, returning indices. |
|
2323
|
|
|
|
|
|
|
|
|
2324
|
|
|
|
|
|
|
=for usage |
|
2325
|
|
|
|
|
|
|
|
|
2326
|
|
|
|
|
|
|
$idx = vsearch( $vals, $x, [\%options] ); |
|
2327
|
|
|
|
|
|
|
vsearch( $vals, $x, $idx, [\%options ] ); |
|
2328
|
|
|
|
|
|
|
|
|
2329
|
|
|
|
|
|
|
B performs a binary search in the ordered ndarray C<$x>, |
|
2330
|
|
|
|
|
|
|
for the values from C<$vals> ndarray, returning indices into C<$x>. |
|
2331
|
|
|
|
|
|
|
What is a "match", and the meaning of the returned indices, are determined |
|
2332
|
|
|
|
|
|
|
by the options. |
|
2333
|
|
|
|
|
|
|
|
|
2334
|
|
|
|
|
|
|
The C option indicates which method of searching to use, and may |
|
2335
|
|
|
|
|
|
|
be one of: |
|
2336
|
|
|
|
|
|
|
|
|
2337
|
|
|
|
|
|
|
=over |
|
2338
|
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
=item C |
|
2340
|
|
|
|
|
|
|
|
|
2341
|
|
|
|
|
|
|
invoke L|/vsearch_sample>, returning indices appropriate for sampling |
|
2342
|
|
|
|
|
|
|
within a distribution. |
|
2343
|
|
|
|
|
|
|
|
|
2344
|
|
|
|
|
|
|
=item C |
|
2345
|
|
|
|
|
|
|
|
|
2346
|
|
|
|
|
|
|
invoke L|/vsearch_insert_leftmost>, returning the left-most possible |
|
2347
|
|
|
|
|
|
|
insertion point which still leaves the ndarray sorted. |
|
2348
|
|
|
|
|
|
|
|
|
2349
|
|
|
|
|
|
|
=item C |
|
2350
|
|
|
|
|
|
|
|
|
2351
|
|
|
|
|
|
|
invoke L|/vsearch_insert_rightmost>, returning the right-most possible |
|
2352
|
|
|
|
|
|
|
insertion point which still leaves the ndarray sorted. |
|
2353
|
|
|
|
|
|
|
|
|
2354
|
|
|
|
|
|
|
=item C |
|
2355
|
|
|
|
|
|
|
|
|
2356
|
|
|
|
|
|
|
invoke L|/vsearch_match>, returning the index of a matching element, |
|
2357
|
|
|
|
|
|
|
else -(insertion point + 1) |
|
2358
|
|
|
|
|
|
|
|
|
2359
|
|
|
|
|
|
|
=item C |
|
2360
|
|
|
|
|
|
|
|
|
2361
|
|
|
|
|
|
|
invoke L|/vsearch_bin_inclusive>, returning an index appropriate for binning |
|
2362
|
|
|
|
|
|
|
on a grid where the left bin edges are I of the bin. See |
|
2363
|
|
|
|
|
|
|
below for further explanation of the bin. |
|
2364
|
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
=item C |
|
2366
|
|
|
|
|
|
|
|
|
2367
|
|
|
|
|
|
|
invoke L|/vsearch_bin_exclusive>, returning an index appropriate for binning |
|
2368
|
|
|
|
|
|
|
on a grid where the left bin edges are I of the bin. See |
|
2369
|
|
|
|
|
|
|
below for further explanation of the bin. |
|
2370
|
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
=back |
|
2372
|
|
|
|
|
|
|
|
|
2373
|
|
|
|
|
|
|
The default value of C is C. |
|
2374
|
|
|
|
|
|
|
|
|
2375
|
|
|
|
|
|
|
=for example |
|
2376
|
|
|
|
|
|
|
|
|
2377
|
|
|
|
|
|
|
use PDL; |
|
2378
|
|
|
|
|
|
|
|
|
2379
|
|
|
|
|
|
|
my @modes = qw( sample insert_leftmost insert_rightmost match |
|
2380
|
|
|
|
|
|
|
bin_inclusive bin_exclusive ); |
|
2381
|
|
|
|
|
|
|
|
|
2382
|
|
|
|
|
|
|
# Generate a sequence of 3 zeros, 3 ones, ..., 3 fours. |
|
2383
|
|
|
|
|
|
|
my $x = zeroes(3,5)->yvals->flat; |
|
2384
|
|
|
|
|
|
|
|
|
2385
|
|
|
|
|
|
|
for my $mode ( @modes ) { |
|
2386
|
|
|
|
|
|
|
# if the value is in $x |
|
2387
|
|
|
|
|
|
|
my $contained = 2; |
|
2388
|
|
|
|
|
|
|
my $idx_contained = vsearch( $contained, $x, { mode => $mode } ); |
|
2389
|
|
|
|
|
|
|
my $x_contained = $x->copy; |
|
2390
|
|
|
|
|
|
|
$x_contained->slice( $idx_contained ) .= 9; |
|
2391
|
|
|
|
|
|
|
|
|
2392
|
|
|
|
|
|
|
# if the value is not in $x |
|
2393
|
|
|
|
|
|
|
my $not_contained = 1.5; |
|
2394
|
|
|
|
|
|
|
my $idx_not_contained = vsearch( $not_contained, $x, { mode => $mode } ); |
|
2395
|
|
|
|
|
|
|
my $x_not_contained = $x->copy; |
|
2396
|
|
|
|
|
|
|
$x_not_contained->slice( $idx_not_contained ) .= 9; |
|
2397
|
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
print sprintf("%-23s%30s\n", '$x', $x); |
|
2399
|
|
|
|
|
|
|
print sprintf("%-23s%30s\n", "$mode ($contained)", $x_contained); |
|
2400
|
|
|
|
|
|
|
print sprintf("%-23s%30s\n\n", "$mode ($not_contained)", $x_not_contained); |
|
2401
|
|
|
|
|
|
|
} |
|
2402
|
|
|
|
|
|
|
|
|
2403
|
|
|
|
|
|
|
# $x [0 0 0 1 1 1 2 2 2 3 3 3 4 4 4] |
|
2404
|
|
|
|
|
|
|
# sample (2) [0 0 0 1 1 1 9 2 2 3 3 3 4 4 4] |
|
2405
|
|
|
|
|
|
|
# sample (1.5) [0 0 0 1 1 1 9 2 2 3 3 3 4 4 4] |
|
2406
|
|
|
|
|
|
|
# |
|
2407
|
|
|
|
|
|
|
# $x [0 0 0 1 1 1 2 2 2 3 3 3 4 4 4] |
|
2408
|
|
|
|
|
|
|
# insert_leftmost (2) [0 0 0 1 1 1 9 2 2 3 3 3 4 4 4] |
|
2409
|
|
|
|
|
|
|
# insert_leftmost (1.5) [0 0 0 1 1 1 9 2 2 3 3 3 4 4 4] |
|
2410
|
|
|
|
|
|
|
# |
|
2411
|
|
|
|
|
|
|
# $x [0 0 0 1 1 1 2 2 2 3 3 3 4 4 4] |
|
2412
|
|
|
|
|
|
|
# insert_rightmost (2) [0 0 0 1 1 1 2 2 2 9 3 3 4 4 4] |
|
2413
|
|
|
|
|
|
|
# insert_rightmost (1.5) [0 0 0 1 1 1 9 2 2 3 3 3 4 4 4] |
|
2414
|
|
|
|
|
|
|
# |
|
2415
|
|
|
|
|
|
|
# $x [0 0 0 1 1 1 2 2 2 3 3 3 4 4 4] |
|
2416
|
|
|
|
|
|
|
# match (2) [0 0 0 1 1 1 2 9 2 3 3 3 4 4 4] |
|
2417
|
|
|
|
|
|
|
# match (1.5) [0 0 0 1 1 1 2 2 9 3 3 3 4 4 4] |
|
2418
|
|
|
|
|
|
|
# |
|
2419
|
|
|
|
|
|
|
# $x [0 0 0 1 1 1 2 2 2 3 3 3 4 4 4] |
|
2420
|
|
|
|
|
|
|
# bin_inclusive (2) [0 0 0 1 1 1 2 2 9 3 3 3 4 4 4] |
|
2421
|
|
|
|
|
|
|
# bin_inclusive (1.5) [0 0 0 1 1 9 2 2 2 3 3 3 4 4 4] |
|
2422
|
|
|
|
|
|
|
# |
|
2423
|
|
|
|
|
|
|
# $x [0 0 0 1 1 1 2 2 2 3 3 3 4 4 4] |
|
2424
|
|
|
|
|
|
|
# bin_exclusive (2) [0 0 0 1 1 9 2 2 2 3 3 3 4 4 4] |
|
2425
|
|
|
|
|
|
|
# bin_exclusive (1.5) [0 0 0 1 1 9 2 2 2 3 3 3 4 4 4] |
|
2426
|
|
|
|
|
|
|
|
|
2427
|
|
|
|
|
|
|
|
|
2428
|
|
|
|
|
|
|
Also see |
|
2429
|
|
|
|
|
|
|
L|/vsearch_sample>, |
|
2430
|
|
|
|
|
|
|
L|/vsearch_insert_leftmost>, |
|
2431
|
|
|
|
|
|
|
L|/vsearch_insert_rightmost>, |
|
2432
|
|
|
|
|
|
|
L|/vsearch_match>, |
|
2433
|
|
|
|
|
|
|
L|/vsearch_bin_inclusive>, and |
|
2434
|
|
|
|
|
|
|
L|/vsearch_bin_exclusive> |
|
2435
|
|
|
|
|
|
|
|
|
2436
|
|
|
|
|
|
|
=cut |
|
2437
|
|
|
|
|
|
|
|
|
2438
|
|
|
|
|
|
|
sub vsearch { |
|
2439
|
|
|
|
|
|
|
my $opt = 'HASH' eq ref $_[-1] |
|
2440
|
|
|
|
|
|
|
? pop |
|
2441
|
|
|
|
|
|
|
: { mode => 'sample' }; |
|
2442
|
|
|
|
|
|
|
|
|
2443
|
|
|
|
|
|
|
croak( "unknown options to vsearch\n" ) |
|
2444
|
|
|
|
|
|
|
if ( ! defined $opt->{mode} && keys %$opt ) |
|
2445
|
|
|
|
|
|
|
|| keys %$opt > 1; |
|
2446
|
|
|
|
|
|
|
|
|
2447
|
|
|
|
|
|
|
my $mode = $opt->{mode}; |
|
2448
|
|
|
|
|
|
|
goto |
|
2449
|
|
|
|
|
|
|
$mode eq 'sample' ? \&vsearch_sample |
|
2450
|
|
|
|
|
|
|
: $mode eq 'insert_leftmost' ? \&vsearch_insert_leftmost |
|
2451
|
|
|
|
|
|
|
: $mode eq 'insert_rightmost' ? \&vsearch_insert_rightmost |
|
2452
|
|
|
|
|
|
|
: $mode eq 'match' ? \&vsearch_match |
|
2453
|
|
|
|
|
|
|
: $mode eq 'bin_inclusive' ? \&vsearch_bin_inclusive |
|
2454
|
|
|
|
|
|
|
: $mode eq 'bin_exclusive' ? \&vsearch_bin_exclusive |
|
2455
|
|
|
|
|
|
|
: croak( "unknown vsearch mode: $mode\n" ); |
|
2456
|
|
|
|
|
|
|
} |
|
2457
|
|
|
|
|
|
|
|
|
2458
|
|
|
|
|
|
|
*PDL::vsearch = \&vsearch; |
|
2459
|
|
|
|
|
|
|
|
|
2460
|
|
|
|
|
|
|
EOD |
|
2461
|
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
use Text::Tabs qw[ expand ]; |
|
2463
|
|
|
|
|
|
|
sub undent { |
|
2464
|
|
|
|
|
|
|
my $txt = expand( shift ); |
|
2465
|
|
|
|
|
|
|
|
|
2466
|
|
|
|
|
|
|
$txt =~ s/^([ \t]+)-{4}.*$//m; |
|
2467
|
|
|
|
|
|
|
$txt =~ s/^$1//mg |
|
2468
|
|
|
|
|
|
|
if defined $1; |
|
2469
|
|
|
|
|
|
|
$txt; |
|
2470
|
|
|
|
|
|
|
} |
|
2471
|
|
|
|
|
|
|
|
|
2472
|
|
|
|
|
|
|
for my $func ( [ |
|
2473
|
|
|
|
|
|
|
vsearch_sample => { |
|
2474
|
|
|
|
|
|
|
low => -1, |
|
2475
|
|
|
|
|
|
|
high => '$SIZE(n)', |
|
2476
|
|
|
|
|
|
|
up => '($x(n => n1) > $x(n => 0))', |
|
2477
|
|
|
|
|
|
|
code => q[ |
|
2478
|
|
|
|
|
|
|
while ( high - low > 1 ) { |
|
2479
|
|
|
|
|
|
|
mid = %MID%; |
|
2480
|
|
|
|
|
|
|
if ( ( value > $x(n => mid ) ) == up ) low = mid; |
|
2481
|
|
|
|
|
|
|
else high = mid; |
|
2482
|
|
|
|
|
|
|
} |
|
2483
|
|
|
|
|
|
|
$idx() = low >= n1 ? n1 |
|
2484
|
|
|
|
|
|
|
: up ? low + 1 |
|
2485
|
|
|
|
|
|
|
: PDLMAX(low, 0); |
|
2486
|
|
|
|
|
|
|
---- |
|
2487
|
|
|
|
|
|
|
], |
|
2488
|
|
|
|
|
|
|
ref => |
|
2489
|
|
|
|
|
|
|
'Search for values in a sorted array, return index appropriate for sampling from a distribution', |
|
2490
|
|
|
|
|
|
|
|
|
2491
|
|
|
|
|
|
|
doc_pre => q[ |
|
2492
|
|
|
|
|
|
|
B<%FUNC%> returns an index I for each value I of C<$vals> appropriate |
|
2493
|
|
|
|
|
|
|
for sampling C<$vals> |
|
2494
|
|
|
|
|
|
|
---- |
|
2495
|
|
|
|
|
|
|
], |
|
2496
|
|
|
|
|
|
|
doc_incr => q[ |
|
2497
|
|
|
|
|
|
|
V <= x[0] : I = 0 |
|
2498
|
|
|
|
|
|
|
x[0] < V <= x[-1] : I s.t. x[I-1] < V <= x[I] |
|
2499
|
|
|
|
|
|
|
x[-1] < V : I = $x->nelem -1 |
|
2500
|
|
|
|
|
|
|
---- |
|
2501
|
|
|
|
|
|
|
], |
|
2502
|
|
|
|
|
|
|
|
|
2503
|
|
|
|
|
|
|
doc_decr => q[ |
|
2504
|
|
|
|
|
|
|
V > x[0] : I = 0 |
|
2505
|
|
|
|
|
|
|
x[0] >= V > x[-1] : I s.t. x[I] >= V > x[I+1] |
|
2506
|
|
|
|
|
|
|
x[-1] >= V : I = $x->nelem - 1 |
|
2507
|
|
|
|
|
|
|
---- |
|
2508
|
|
|
|
|
|
|
], |
|
2509
|
|
|
|
|
|
|
|
|
2510
|
|
|
|
|
|
|
doc_post => q[ |
|
2511
|
|
|
|
|
|
|
If all elements of C<$x> are equal, I<< I = $x->nelem - 1 >>. |
|
2512
|
|
|
|
|
|
|
|
|
2513
|
|
|
|
|
|
|
If C<$x> contains duplicated elements, I is the index of the |
|
2514
|
|
|
|
|
|
|
leftmost (by position in array) duplicate if I matches. |
|
2515
|
|
|
|
|
|
|
|
|
2516
|
|
|
|
|
|
|
=for example |
|
2517
|
|
|
|
|
|
|
|
|
2518
|
|
|
|
|
|
|
This function is useful e.g. when you have a list of probabilities |
|
2519
|
|
|
|
|
|
|
for events and want to generate indices to events: |
|
2520
|
|
|
|
|
|
|
|
|
2521
|
|
|
|
|
|
|
$x = pdl(.01,.86,.93,1); # Barnsley IFS probabilities cumulatively |
|
2522
|
|
|
|
|
|
|
$y = random 20; |
|
2523
|
|
|
|
|
|
|
$c = %FUNC%($y, $x); # Now, $c will have the appropriate distr. |
|
2524
|
|
|
|
|
|
|
|
|
2525
|
|
|
|
|
|
|
It is possible to use the L |
|
2526
|
|
|
|
|
|
|
function to obtain cumulative probabilities from absolute probabilities. |
|
2527
|
|
|
|
|
|
|
---- |
|
2528
|
|
|
|
|
|
|
], |
|
2529
|
|
|
|
|
|
|
|
|
2530
|
|
|
|
|
|
|
}, |
|
2531
|
|
|
|
|
|
|
], |
|
2532
|
|
|
|
|
|
|
|
|
2533
|
|
|
|
|
|
|
[ |
|
2534
|
|
|
|
|
|
|
# return left-most possible insertion point. |
|
2535
|
|
|
|
|
|
|
# lowest index where x[i] >= value |
|
2536
|
|
|
|
|
|
|
vsearch_insert_leftmost => { |
|
2537
|
|
|
|
|
|
|
low => 0, |
|
2538
|
|
|
|
|
|
|
high => 'n1', |
|
2539
|
|
|
|
|
|
|
code => q[ |
|
2540
|
|
|
|
|
|
|
while (low <= high ) { |
|
2541
|
|
|
|
|
|
|
mid = %MID%; |
|
2542
|
|
|
|
|
|
|
if ( ( $x(n => mid) >= value ) == up ) high = mid - 1; |
|
2543
|
|
|
|
|
|
|
else low = mid + 1; |
|
2544
|
|
|
|
|
|
|
} |
|
2545
|
|
|
|
|
|
|
$idx() = up ? low : high; |
|
2546
|
|
|
|
|
|
|
], |
|
2547
|
|
|
|
|
|
|
ref => |
|
2548
|
|
|
|
|
|
|
'Determine the insertion point for values in a sorted array, inserting before duplicates.', |
|
2549
|
|
|
|
|
|
|
|
|
2550
|
|
|
|
|
|
|
doc_pre => q[ |
|
2551
|
|
|
|
|
|
|
B<%FUNC%> returns an index I for each value I of |
|
2552
|
|
|
|
|
|
|
C<$vals> equal to the leftmost position (by index in array) within |
|
2553
|
|
|
|
|
|
|
C<$x> that I may be inserted and still maintain the order in |
|
2554
|
|
|
|
|
|
|
C<$x>. |
|
2555
|
|
|
|
|
|
|
|
|
2556
|
|
|
|
|
|
|
Insertion at index I involves shifting elements I and higher of |
|
2557
|
|
|
|
|
|
|
C<$x> to the right by one and setting the now empty element at index |
|
2558
|
|
|
|
|
|
|
I to I. |
|
2559
|
|
|
|
|
|
|
---- |
|
2560
|
|
|
|
|
|
|
], |
|
2561
|
|
|
|
|
|
|
doc_incr => q[ |
|
2562
|
|
|
|
|
|
|
V <= x[0] : I = 0 |
|
2563
|
|
|
|
|
|
|
x[0] < V <= x[-1] : I s.t. x[I-1] < V <= x[I] |
|
2564
|
|
|
|
|
|
|
x[-1] < V : I = $x->nelem |
|
2565
|
|
|
|
|
|
|
---- |
|
2566
|
|
|
|
|
|
|
], |
|
2567
|
|
|
|
|
|
|
|
|
2568
|
|
|
|
|
|
|
doc_decr => q[ |
|
2569
|
|
|
|
|
|
|
V > x[0] : I = -1 |
|
2570
|
|
|
|
|
|
|
x[0] >= V >= x[-1] : I s.t. x[I] >= V > x[I+1] |
|
2571
|
|
|
|
|
|
|
x[-1] >= V : I = $x->nelem -1 |
|
2572
|
|
|
|
|
|
|
---- |
|
2573
|
|
|
|
|
|
|
], |
|
2574
|
|
|
|
|
|
|
|
|
2575
|
|
|
|
|
|
|
doc_post => q[ |
|
2576
|
|
|
|
|
|
|
If all elements of C<$x> are equal, |
|
2577
|
|
|
|
|
|
|
|
|
2578
|
|
|
|
|
|
|
i = 0 |
|
2579
|
|
|
|
|
|
|
|
|
2580
|
|
|
|
|
|
|
If C<$x> contains duplicated elements, I is the index of the |
|
2581
|
|
|
|
|
|
|
leftmost (by index in array) duplicate if I matches. |
|
2582
|
|
|
|
|
|
|
---- |
|
2583
|
|
|
|
|
|
|
], |
|
2584
|
|
|
|
|
|
|
|
|
2585
|
|
|
|
|
|
|
}, |
|
2586
|
|
|
|
|
|
|
], |
|
2587
|
|
|
|
|
|
|
|
|
2588
|
|
|
|
|
|
|
[ |
|
2589
|
|
|
|
|
|
|
# return right-most possible insertion point. |
|
2590
|
|
|
|
|
|
|
# lowest index where x[i] > value |
|
2591
|
|
|
|
|
|
|
vsearch_insert_rightmost => { |
|
2592
|
|
|
|
|
|
|
low => 0, |
|
2593
|
|
|
|
|
|
|
high => 'n1', |
|
2594
|
|
|
|
|
|
|
code => q[ |
|
2595
|
|
|
|
|
|
|
while (low <= high ) { |
|
2596
|
|
|
|
|
|
|
mid = %MID%; |
|
2597
|
|
|
|
|
|
|
if ( ( $x(n => mid) > value ) == up ) high = mid - 1; |
|
2598
|
|
|
|
|
|
|
else low = mid + 1; |
|
2599
|
|
|
|
|
|
|
} |
|
2600
|
|
|
|
|
|
|
$idx() = up ? low : high; |
|
2601
|
|
|
|
|
|
|
], |
|
2602
|
|
|
|
|
|
|
ref => |
|
2603
|
|
|
|
|
|
|
'Determine the insertion point for values in a sorted array, inserting after duplicates.', |
|
2604
|
|
|
|
|
|
|
|
|
2605
|
|
|
|
|
|
|
doc_pre => q[ |
|
2606
|
|
|
|
|
|
|
B<%FUNC%> returns an index I for each value I of |
|
2607
|
|
|
|
|
|
|
C<$vals> equal to the rightmost position (by index in array) within |
|
2608
|
|
|
|
|
|
|
C<$x> that I may be inserted and still maintain the order in |
|
2609
|
|
|
|
|
|
|
C<$x>. |
|
2610
|
|
|
|
|
|
|
|
|
2611
|
|
|
|
|
|
|
Insertion at index I involves shifting elements I and higher of |
|
2612
|
|
|
|
|
|
|
C<$x> to the right by one and setting the now empty element at index |
|
2613
|
|
|
|
|
|
|
I to I. |
|
2614
|
|
|
|
|
|
|
---- |
|
2615
|
|
|
|
|
|
|
], |
|
2616
|
|
|
|
|
|
|
doc_incr => q[ |
|
2617
|
|
|
|
|
|
|
V < x[0] : I = 0 |
|
2618
|
|
|
|
|
|
|
x[0] <= V < x[-1] : I s.t. x[I-1] <= V < x[I] |
|
2619
|
|
|
|
|
|
|
x[-1] <= V : I = $x->nelem |
|
2620
|
|
|
|
|
|
|
---- |
|
2621
|
|
|
|
|
|
|
], |
|
2622
|
|
|
|
|
|
|
|
|
2623
|
|
|
|
|
|
|
doc_decr => q[ |
|
2624
|
|
|
|
|
|
|
V >= x[0] : I = -1 |
|
2625
|
|
|
|
|
|
|
x[0] > V >= x[-1] : I s.t. x[I] >= V > x[I+1] |
|
2626
|
|
|
|
|
|
|
x[-1] > V : I = $x->nelem -1 |
|
2627
|
|
|
|
|
|
|
---- |
|
2628
|
|
|
|
|
|
|
], |
|
2629
|
|
|
|
|
|
|
|
|
2630
|
|
|
|
|
|
|
doc_post => q[ |
|
2631
|
|
|
|
|
|
|
If all elements of C<$x> are equal, |
|
2632
|
|
|
|
|
|
|
|
|
2633
|
|
|
|
|
|
|
i = $x->nelem - 1 |
|
2634
|
|
|
|
|
|
|
|
|
2635
|
|
|
|
|
|
|
If C<$x> contains duplicated elements, I is the index of the |
|
2636
|
|
|
|
|
|
|
leftmost (by index in array) duplicate if I matches. |
|
2637
|
|
|
|
|
|
|
---- |
|
2638
|
|
|
|
|
|
|
], |
|
2639
|
|
|
|
|
|
|
|
|
2640
|
|
|
|
|
|
|
}, |
|
2641
|
|
|
|
|
|
|
|
|
2642
|
|
|
|
|
|
|
], |
|
2643
|
|
|
|
|
|
|
[ |
|
2644
|
|
|
|
|
|
|
# return index of matching element, else -( insertion point + 1 ) |
|
2645
|
|
|
|
|
|
|
# patterned after the Java binarySearch interface; see |
|
2646
|
|
|
|
|
|
|
# http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html |
|
2647
|
|
|
|
|
|
|
vsearch_match => { |
|
2648
|
|
|
|
|
|
|
low => 0, |
|
2649
|
|
|
|
|
|
|
high => 'n1', |
|
2650
|
|
|
|
|
|
|
code => q[ |
|
2651
|
|
|
|
|
|
|
int done = 0; |
|
2652
|
|
|
|
|
|
|
|
|
2653
|
|
|
|
|
|
|
while (low <= high ) { |
|
2654
|
|
|
|
|
|
|
$GENERIC() mid_value; |
|
2655
|
|
|
|
|
|
|
|
|
2656
|
|
|
|
|
|
|
mid = %MID%; |
|
2657
|
|
|
|
|
|
|
|
|
2658
|
|
|
|
|
|
|
mid_value = $x(n=>mid); |
|
2659
|
|
|
|
|
|
|
|
|
2660
|
|
|
|
|
|
|
if ( up ) { |
|
2661
|
|
|
|
|
|
|
if ( mid_value > value ) { high = mid - 1; } |
|
2662
|
|
|
|
|
|
|
else if ( mid_value < value ) { low = mid + 1; } |
|
2663
|
|
|
|
|
|
|
else { done = 1; break; } |
|
2664
|
|
|
|
|
|
|
} |
|
2665
|
|
|
|
|
|
|
else { |
|
2666
|
|
|
|
|
|
|
if ( mid_value < value ) { high = mid - 1; } |
|
2667
|
|
|
|
|
|
|
else if ( mid_value > value ) { low = mid + 1; } |
|
2668
|
|
|
|
|
|
|
else { done = 1; break; } |
|
2669
|
|
|
|
|
|
|
} |
|
2670
|
|
|
|
|
|
|
} |
|
2671
|
|
|
|
|
|
|
$idx() = done ? mid |
|
2672
|
|
|
|
|
|
|
: up ? - ( low + 1 ) |
|
2673
|
|
|
|
|
|
|
: - ( high + 1 ); |
|
2674
|
|
|
|
|
|
|
], |
|
2675
|
|
|
|
|
|
|
ref => 'Match values against a sorted array.', |
|
2676
|
|
|
|
|
|
|
|
|
2677
|
|
|
|
|
|
|
doc_pre => q[ |
|
2678
|
|
|
|
|
|
|
B<%FUNC%> returns an index I for each value I of |
|
2679
|
|
|
|
|
|
|
C<$vals>. If I matches an element in C<$x>, I is the |
|
2680
|
|
|
|
|
|
|
index of that element, otherwise it is I<-( insertion_point + 1 )>, |
|
2681
|
|
|
|
|
|
|
where I is an index in C<$x> where I may be |
|
2682
|
|
|
|
|
|
|
inserted while maintaining the order in C<$x>. If C<$x> has |
|
2683
|
|
|
|
|
|
|
duplicated values, I may refer to any of them. |
|
2684
|
|
|
|
|
|
|
---- |
|
2685
|
|
|
|
|
|
|
], |
|
2686
|
|
|
|
|
|
|
|
|
2687
|
|
|
|
|
|
|
}, |
|
2688
|
|
|
|
|
|
|
], |
|
2689
|
|
|
|
|
|
|
[ |
|
2690
|
|
|
|
|
|
|
# x[i] is the INclusive left edge of the bin |
|
2691
|
|
|
|
|
|
|
# return i, s.t. x[i] <= value < x[i+1]. |
|
2692
|
|
|
|
|
|
|
# returns -1 if x[0] > value |
|
2693
|
|
|
|
|
|
|
# returns N-1 if x[-1] <= value |
|
2694
|
|
|
|
|
|
|
vsearch_bin_inclusive => { |
|
2695
|
|
|
|
|
|
|
low => 0, |
|
2696
|
|
|
|
|
|
|
high => 'n1', |
|
2697
|
|
|
|
|
|
|
code => q[ |
|
2698
|
|
|
|
|
|
|
while (low <= high ) { |
|
2699
|
|
|
|
|
|
|
mid = %MID%; |
|
2700
|
|
|
|
|
|
|
if ( ( $x(n => mid) <= value ) == up ) low = mid + 1; |
|
2701
|
|
|
|
|
|
|
else high = mid - 1; |
|
2702
|
|
|
|
|
|
|
} |
|
2703
|
|
|
|
|
|
|
$idx() = up ? high: low; |
|
2704
|
|
|
|
|
|
|
], |
|
2705
|
|
|
|
|
|
|
ref => |
|
2706
|
|
|
|
|
|
|
'Determine the index for values in a sorted array of bins, lower bound inclusive.', |
|
2707
|
|
|
|
|
|
|
|
|
2708
|
|
|
|
|
|
|
doc_pre => q[ |
|
2709
|
|
|
|
|
|
|
C<$x> represents the edges of contiguous bins, with the first and |
|
2710
|
|
|
|
|
|
|
last elements representing the outer edges of the outer bins, and the |
|
2711
|
|
|
|
|
|
|
inner elements the shared bin edges. |
|
2712
|
|
|
|
|
|
|
|
|
2713
|
|
|
|
|
|
|
The lower bound of a bin is inclusive to the bin, its outer bound is exclusive to it. |
|
2714
|
|
|
|
|
|
|
B<%FUNC%> returns an index I for each value I of C<$vals> |
|
2715
|
|
|
|
|
|
|
---- |
|
2716
|
|
|
|
|
|
|
], |
|
2717
|
|
|
|
|
|
|
doc_incr => q[ |
|
2718
|
|
|
|
|
|
|
V < x[0] : I = -1 |
|
2719
|
|
|
|
|
|
|
x[0] <= V < x[-1] : I s.t. x[I] <= V < x[I+1] |
|
2720
|
|
|
|
|
|
|
x[-1] <= V : I = $x->nelem - 1 |
|
2721
|
|
|
|
|
|
|
---- |
|
2722
|
|
|
|
|
|
|
], |
|
2723
|
|
|
|
|
|
|
|
|
2724
|
|
|
|
|
|
|
doc_decr => q[ |
|
2725
|
|
|
|
|
|
|
V >= x[0] : I = 0 |
|
2726
|
|
|
|
|
|
|
x[0] > V >= x[-1] : I s.t. x[I+1] > V >= x[I] |
|
2727
|
|
|
|
|
|
|
x[-1] > V : I = $x->nelem |
|
2728
|
|
|
|
|
|
|
---- |
|
2729
|
|
|
|
|
|
|
], |
|
2730
|
|
|
|
|
|
|
|
|
2731
|
|
|
|
|
|
|
doc_post => q[ |
|
2732
|
|
|
|
|
|
|
If all elements of C<$x> are equal, |
|
2733
|
|
|
|
|
|
|
|
|
2734
|
|
|
|
|
|
|
i = $x->nelem - 1 |
|
2735
|
|
|
|
|
|
|
|
|
2736
|
|
|
|
|
|
|
If C<$x> contains duplicated elements, I is the index of the |
|
2737
|
|
|
|
|
|
|
righmost (by index in array) duplicate if I matches. |
|
2738
|
|
|
|
|
|
|
---- |
|
2739
|
|
|
|
|
|
|
], |
|
2740
|
|
|
|
|
|
|
|
|
2741
|
|
|
|
|
|
|
}, |
|
2742
|
|
|
|
|
|
|
], |
|
2743
|
|
|
|
|
|
|
|
|
2744
|
|
|
|
|
|
|
[ |
|
2745
|
|
|
|
|
|
|
# x[i] is the EXclusive left edge of the bin |
|
2746
|
|
|
|
|
|
|
# return i, s.t. x[i] < value <= x[i+1]. |
|
2747
|
|
|
|
|
|
|
# returns -1 if x[0] >= value |
|
2748
|
|
|
|
|
|
|
# returns N-1 if x[-1] < value |
|
2749
|
|
|
|
|
|
|
vsearch_bin_exclusive => { |
|
2750
|
|
|
|
|
|
|
low => 0, |
|
2751
|
|
|
|
|
|
|
high => 'n1', |
|
2752
|
|
|
|
|
|
|
code => q[ |
|
2753
|
|
|
|
|
|
|
while (low <= high ) { |
|
2754
|
|
|
|
|
|
|
mid = %MID%; |
|
2755
|
|
|
|
|
|
|
if ( ( $x(n => mid) < value ) == up ) low = mid + 1; |
|
2756
|
|
|
|
|
|
|
else high = mid - 1; |
|
2757
|
|
|
|
|
|
|
} |
|
2758
|
|
|
|
|
|
|
$idx() = up ? high: low; |
|
2759
|
|
|
|
|
|
|
], |
|
2760
|
|
|
|
|
|
|
ref => |
|
2761
|
|
|
|
|
|
|
'Determine the index for values in a sorted array of bins, lower bound exclusive.', |
|
2762
|
|
|
|
|
|
|
|
|
2763
|
|
|
|
|
|
|
doc_pre => q[ |
|
2764
|
|
|
|
|
|
|
C<$x> represents the edges of contiguous bins, with the first and |
|
2765
|
|
|
|
|
|
|
last elements representing the outer edges of the outer bins, and the |
|
2766
|
|
|
|
|
|
|
inner elements the shared bin edges. |
|
2767
|
|
|
|
|
|
|
|
|
2768
|
|
|
|
|
|
|
The lower bound of a bin is exclusive to the bin, its upper bound is inclusive to it. |
|
2769
|
|
|
|
|
|
|
B<%FUNC%> returns an index I for each value I of C<$vals>. |
|
2770
|
|
|
|
|
|
|
---- |
|
2771
|
|
|
|
|
|
|
], |
|
2772
|
|
|
|
|
|
|
doc_incr => q[ |
|
2773
|
|
|
|
|
|
|
V <= x[0] : I = -1 |
|
2774
|
|
|
|
|
|
|
x[0] < V <= x[-1] : I s.t. x[I] < V <= x[I+1] |
|
2775
|
|
|
|
|
|
|
x[-1] < V : I = $x->nelem - 1 |
|
2776
|
|
|
|
|
|
|
---- |
|
2777
|
|
|
|
|
|
|
], |
|
2778
|
|
|
|
|
|
|
|
|
2779
|
|
|
|
|
|
|
doc_decr => q[ |
|
2780
|
|
|
|
|
|
|
V > x[0] : I = 0 |
|
2781
|
|
|
|
|
|
|
x[0] >= V > x[-1] : I s.t. x[I-1] >= V > x[I] |
|
2782
|
|
|
|
|
|
|
x[-1] >= V : I = $x->nelem |
|
2783
|
|
|
|
|
|
|
---- |
|
2784
|
|
|
|
|
|
|
], |
|
2785
|
|
|
|
|
|
|
|
|
2786
|
|
|
|
|
|
|
doc_post => q[ |
|
2787
|
|
|
|
|
|
|
If all elements of C<$x> are equal, |
|
2788
|
|
|
|
|
|
|
|
|
2789
|
|
|
|
|
|
|
i = $x->nelem - 1 |
|
2790
|
|
|
|
|
|
|
|
|
2791
|
|
|
|
|
|
|
If C<$x> contains duplicated elements, I is the index of the |
|
2792
|
|
|
|
|
|
|
righmost (by index in array) duplicate if I matches. |
|
2793
|
|
|
|
|
|
|
---- |
|
2794
|
|
|
|
|
|
|
], |
|
2795
|
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
} |
|
2797
|
|
|
|
|
|
|
], |
|
2798
|
|
|
|
|
|
|
|
|
2799
|
|
|
|
|
|
|
) |
|
2800
|
|
|
|
|
|
|
|
|
2801
|
|
|
|
|
|
|
{ |
|
2802
|
|
|
|
|
|
|
my ( $func, $algo ) = @$func; |
|
2803
|
|
|
|
|
|
|
|
|
2804
|
|
|
|
|
|
|
my %replace = ( |
|
2805
|
|
|
|
|
|
|
# calculate midpoint of range; ensure we don't overflow |
|
2806
|
|
|
|
|
|
|
# (low+high)>>1 for large values of low + high |
|
2807
|
|
|
|
|
|
|
# see sf.net bug #360 |
|
2808
|
|
|
|
|
|
|
'%MID%' => 'low + (( high - low )>> 1);', |
|
2809
|
|
|
|
|
|
|
|
|
2810
|
|
|
|
|
|
|
# determine which way the data are sorted. vsearch_sample |
|
2811
|
|
|
|
|
|
|
# overrides this. |
|
2812
|
|
|
|
|
|
|
'%UP%' => '$x(n => n1) >= $x(n => 0)', |
|
2813
|
|
|
|
|
|
|
|
|
2814
|
|
|
|
|
|
|
'%FUNC%' => $func, |
|
2815
|
|
|
|
|
|
|
|
|
2816
|
|
|
|
|
|
|
'%PRE%' => undent( |
|
2817
|
|
|
|
|
|
|
q[ |
|
2818
|
|
|
|
|
|
|
%DOC_PRE% |
|
2819
|
|
|
|
|
|
|
---- |
|
2820
|
|
|
|
|
|
|
] |
|
2821
|
|
|
|
|
|
|
), |
|
2822
|
|
|
|
|
|
|
|
|
2823
|
|
|
|
|
|
|
|
|
2824
|
|
|
|
|
|
|
|
|
2825
|
|
|
|
|
|
|
'%BODY%' => undent( |
|
2826
|
|
|
|
|
|
|
q[ |
|
2827
|
|
|
|
|
|
|
I has the following properties: |
|
2828
|
|
|
|
|
|
|
|
|
2829
|
|
|
|
|
|
|
=over |
|
2830
|
|
|
|
|
|
|
|
|
2831
|
|
|
|
|
|
|
=item * |
|
2832
|
|
|
|
|
|
|
|
|
2833
|
|
|
|
|
|
|
if C<$x> is sorted in increasing order |
|
2834
|
|
|
|
|
|
|
|
|
2835
|
|
|
|
|
|
|
%DOC_INCR% |
|
2836
|
|
|
|
|
|
|
|
|
2837
|
|
|
|
|
|
|
=item * |
|
2838
|
|
|
|
|
|
|
|
|
2839
|
|
|
|
|
|
|
if C<$x> is sorted in decreasing order |
|
2840
|
|
|
|
|
|
|
|
|
2841
|
|
|
|
|
|
|
%DOC_DECR% |
|
2842
|
|
|
|
|
|
|
|
|
2843
|
|
|
|
|
|
|
=back |
|
2844
|
|
|
|
|
|
|
---- |
|
2845
|
|
|
|
|
|
|
] |
|
2846
|
|
|
|
|
|
|
), |
|
2847
|
|
|
|
|
|
|
|
|
2848
|
|
|
|
|
|
|
'%POST%' => undent( |
|
2849
|
|
|
|
|
|
|
q[ |
|
2850
|
|
|
|
|
|
|
%DOC_POST% |
|
2851
|
|
|
|
|
|
|
---- |
|
2852
|
|
|
|
|
|
|
] |
|
2853
|
|
|
|
|
|
|
), |
|
2854
|
|
|
|
|
|
|
|
|
2855
|
|
|
|
|
|
|
map { ( "%\U$_%" => undent( $algo->{$_} ) ) } keys %$algo, |
|
2856
|
|
|
|
|
|
|
); |
|
2857
|
|
|
|
|
|
|
|
|
2858
|
|
|
|
|
|
|
$replace{'%PRE%'} = '' unless defined $replace{'%DOC_PRE%'}; |
|
2859
|
|
|
|
|
|
|
$replace{'%BODY%'} = '' |
|
2860
|
|
|
|
|
|
|
unless defined $replace{'%DOC_INCR%'} || defined $replace{'%DOC_DECR%'}; |
|
2861
|
|
|
|
|
|
|
$replace{'%POST%'} = '' unless defined $replace{'%DOC_POST%'}; |
|
2862
|
|
|
|
|
|
|
|
|
2863
|
|
|
|
|
|
|
|
|
2864
|
|
|
|
|
|
|
my $code = undent q[ |
|
2865
|
|
|
|
|
|
|
loop(n) %{ |
|
2866
|
|
|
|
|
|
|
if ( $ISGOOD(vals()) ) { |
|
2867
|
|
|
|
|
|
|
PDL_Indx n1 = $SIZE(n)-1; |
|
2868
|
|
|
|
|
|
|
PDL_Indx low = %LOW%; |
|
2869
|
|
|
|
|
|
|
PDL_Indx high = %HIGH%; |
|
2870
|
|
|
|
|
|
|
PDL_Indx mid; |
|
2871
|
|
|
|
|
|
|
|
|
2872
|
|
|
|
|
|
|
$GENERIC() value = $vals(); |
|
2873
|
|
|
|
|
|
|
|
|
2874
|
|
|
|
|
|
|
/* determine sort order of data */ |
|
2875
|
|
|
|
|
|
|
int up = %UP%; |
|
2876
|
|
|
|
|
|
|
%CODE% |
|
2877
|
|
|
|
|
|
|
} |
|
2878
|
|
|
|
|
|
|
|
|
2879
|
|
|
|
|
|
|
else { |
|
2880
|
|
|
|
|
|
|
$SETBAD(idx()); |
|
2881
|
|
|
|
|
|
|
} |
|
2882
|
|
|
|
|
|
|
%} |
|
2883
|
|
|
|
|
|
|
---- |
|
2884
|
|
|
|
|
|
|
]; |
|
2885
|
|
|
|
|
|
|
|
|
2886
|
|
|
|
|
|
|
my $doc = undent q[ |
|
2887
|
|
|
|
|
|
|
=for ref |
|
2888
|
|
|
|
|
|
|
|
|
2889
|
|
|
|
|
|
|
%REF% |
|
2890
|
|
|
|
|
|
|
|
|
2891
|
|
|
|
|
|
|
=for usage |
|
2892
|
|
|
|
|
|
|
|
|
2893
|
|
|
|
|
|
|
$idx = %FUNC%($vals, $x); |
|
2894
|
|
|
|
|
|
|
|
|
2895
|
|
|
|
|
|
|
C<$x> must be sorted, but may be in decreasing or increasing |
|
2896
|
|
|
|
|
|
|
order. if C<$x> is empty, then all values in C<$idx> will be |
|
2897
|
|
|
|
|
|
|
set to the bad value. |
|
2898
|
|
|
|
|
|
|
|
|
2899
|
|
|
|
|
|
|
%PRE% |
|
2900
|
|
|
|
|
|
|
%BODY% |
|
2901
|
|
|
|
|
|
|
%POST% |
|
2902
|
|
|
|
|
|
|
---- |
|
2903
|
|
|
|
|
|
|
]; |
|
2904
|
|
|
|
|
|
|
|
|
2905
|
|
|
|
|
|
|
|
|
2906
|
|
|
|
|
|
|
# redo until nothing changes |
|
2907
|
|
|
|
|
|
|
for my $tref ( \$code, \$doc ) { |
|
2908
|
|
|
|
|
|
|
1 while $$tref =~ s/(%[\w_]+%)/$replace{$1}/ge; |
|
2909
|
|
|
|
|
|
|
} |
|
2910
|
|
|
|
|
|
|
|
|
2911
|
|
|
|
|
|
|
pp_def( |
|
2912
|
|
|
|
|
|
|
$func, |
|
2913
|
|
|
|
|
|
|
HandleBad => 1, |
|
2914
|
|
|
|
|
|
|
BadDoc => 'bad values in vals() result in bad values in idx()', |
|
2915
|
|
|
|
|
|
|
Pars => 'vals(); x(n); indx [o]idx()', |
|
2916
|
|
|
|
|
|
|
GenericTypes => $F, # too restrictive ? |
|
2917
|
|
|
|
|
|
|
Code => $code, |
|
2918
|
|
|
|
|
|
|
Doc => $doc, |
|
2919
|
|
|
|
|
|
|
); |
|
2920
|
|
|
|
|
|
|
} |
|
2921
|
|
|
|
|
|
|
|
|
2922
|
|
|
|
|
|
|
############################################################### |
|
2923
|
|
|
|
|
|
|
# routines somehow related to interpolation |
|
2924
|
|
|
|
|
|
|
############################################################### |
|
2925
|
|
|
|
|
|
|
|
|
2926
|
|
|
|
|
|
|
pp_def('interpolate', |
|
2927
|
|
|
|
|
|
|
HandleBad => 0, |
|
2928
|
|
|
|
|
|
|
BadDoc => 'needs major (?) work to handles bad values', |
|
2929
|
|
|
|
|
|
|
Pars => '!complex xi(); !complex x(n); y(n); [o] yi(); int [o] err()', |
|
2930
|
|
|
|
|
|
|
GenericTypes => $AF, |
|
2931
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
2932
|
|
|
|
|
|
|
PDL_Indx n = $SIZE(n), n1 = n-1; |
|
2933
|
|
|
|
|
|
|
broadcastloop %{ |
|
2934
|
|
|
|
|
|
|
PDL_Indx jl = -1, jh = n; |
|
2935
|
|
|
|
|
|
|
int carp = 0, up = ($x(n => n1) > $x(n => 0)); |
|
2936
|
|
|
|
|
|
|
while (jh-jl > 1) { /* binary search */ |
|
2937
|
|
|
|
|
|
|
PDL_Indx m = (jh+jl) >> 1; |
|
2938
|
|
|
|
|
|
|
if (($xi() > $x(n => m)) == up) |
|
2939
|
|
|
|
|
|
|
jl = m; |
|
2940
|
|
|
|
|
|
|
else |
|
2941
|
|
|
|
|
|
|
jh = m; |
|
2942
|
|
|
|
|
|
|
} |
|
2943
|
|
|
|
|
|
|
if (jl == -1) { |
|
2944
|
|
|
|
|
|
|
if ($xi() != $x(n => 0)) carp = 1; |
|
2945
|
|
|
|
|
|
|
jl = 0; |
|
2946
|
|
|
|
|
|
|
} else if (jh == n) { |
|
2947
|
|
|
|
|
|
|
if ($xi() != $x(n => n1)) carp = 1; |
|
2948
|
|
|
|
|
|
|
jl = n1-1; |
|
2949
|
|
|
|
|
|
|
} |
|
2950
|
|
|
|
|
|
|
jh = jl+1; |
|
2951
|
|
|
|
|
|
|
$GENERIC() d = $x(n=>jh) - $x(n=>jl); |
|
2952
|
|
|
|
|
|
|
if (d == 0) $CROAK("identical abscissas"); |
|
2953
|
|
|
|
|
|
|
d = ($x(n=>jh) - $xi())/d; |
|
2954
|
|
|
|
|
|
|
$yi() = d*$y(n => jl) + (1-d)*$y(n => jh); |
|
2955
|
|
|
|
|
|
|
$err() = carp; |
|
2956
|
|
|
|
|
|
|
%} |
|
2957
|
|
|
|
|
|
|
EOF |
|
2958
|
|
|
|
|
|
|
Doc => <<'EOD', |
|
2959
|
|
|
|
|
|
|
=for ref |
|
2960
|
|
|
|
|
|
|
|
|
2961
|
|
|
|
|
|
|
routine for 1D linear interpolation |
|
2962
|
|
|
|
|
|
|
|
|
2963
|
|
|
|
|
|
|
Given a set of points C<($x,$y)>, use linear interpolation |
|
2964
|
|
|
|
|
|
|
to find the values C<$yi> at a set of points C<$xi>. |
|
2965
|
|
|
|
|
|
|
|
|
2966
|
|
|
|
|
|
|
C uses a binary search to find the suspects, er..., |
|
2967
|
|
|
|
|
|
|
interpolation indices and therefore abscissas (ie C<$x>) |
|
2968
|
|
|
|
|
|
|
have to be I ordered (increasing or decreasing). |
|
2969
|
|
|
|
|
|
|
For interpolation at lots of |
|
2970
|
|
|
|
|
|
|
closely spaced abscissas an approach that uses the last index found as |
|
2971
|
|
|
|
|
|
|
a start for the next search can be faster (compare Numerical Recipes |
|
2972
|
|
|
|
|
|
|
C routine). Feel free to implement that on top of the binary |
|
2973
|
|
|
|
|
|
|
search if you like. For out of bounds values it just does a linear |
|
2974
|
|
|
|
|
|
|
extrapolation and sets the corresponding element of C<$err> to 1, |
|
2975
|
|
|
|
|
|
|
which is otherwise 0. |
|
2976
|
|
|
|
|
|
|
|
|
2977
|
|
|
|
|
|
|
See also L, which uses the same routine, |
|
2978
|
|
|
|
|
|
|
differing only in the handling of extrapolation - an error message |
|
2979
|
|
|
|
|
|
|
is printed rather than returning an error ndarray. |
|
2980
|
|
|
|
|
|
|
|
|
2981
|
|
|
|
|
|
|
Note that C can use complex values for C<$y> and C<$yi> but |
|
2982
|
|
|
|
|
|
|
C<$x> and C<$xi> must be real. |
|
2983
|
|
|
|
|
|
|
EOD |
|
2984
|
|
|
|
|
|
|
); |
|
2985
|
|
|
|
|
|
|
|
|
2986
|
|
|
|
|
|
|
pp_add_exported('', 'interpol'); |
|
2987
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
2988
|
|
|
|
|
|
|
=head2 interpol |
|
2989
|
|
|
|
|
|
|
|
|
2990
|
|
|
|
|
|
|
=for sig |
|
2991
|
|
|
|
|
|
|
|
|
2992
|
|
|
|
|
|
|
Signature: (xi(); x(n); y(n); [o] yi()) |
|
2993
|
|
|
|
|
|
|
|
|
2994
|
|
|
|
|
|
|
=for ref |
|
2995
|
|
|
|
|
|
|
|
|
2996
|
|
|
|
|
|
|
routine for 1D linear interpolation |
|
2997
|
|
|
|
|
|
|
|
|
2998
|
|
|
|
|
|
|
=for usage |
|
2999
|
|
|
|
|
|
|
|
|
3000
|
|
|
|
|
|
|
$yi = interpol($xi, $x, $y) |
|
3001
|
|
|
|
|
|
|
|
|
3002
|
|
|
|
|
|
|
C uses the same search method as L, |
|
3003
|
|
|
|
|
|
|
hence C<$x> must be I ordered (either increasing or decreasing). |
|
3004
|
|
|
|
|
|
|
The difference occurs in the handling of out-of-bounds values; here |
|
3005
|
|
|
|
|
|
|
an error message is printed. |
|
3006
|
|
|
|
|
|
|
|
|
3007
|
|
|
|
|
|
|
=cut |
|
3008
|
|
|
|
|
|
|
|
|
3009
|
|
|
|
|
|
|
# kept in for backwards compatibility |
|
3010
|
|
|
|
|
|
|
sub interpol ($$$;$) { |
|
3011
|
|
|
|
|
|
|
my $xi = shift; |
|
3012
|
|
|
|
|
|
|
my $x = shift; |
|
3013
|
|
|
|
|
|
|
my $y = shift; |
|
3014
|
|
|
|
|
|
|
my $yi = @_ == 1 ? $_[0] : PDL->null; |
|
3015
|
|
|
|
|
|
|
interpolate( $xi, $x, $y, $yi, my $err = PDL->null ); |
|
3016
|
|
|
|
|
|
|
print "some values had to be extrapolated\n" |
|
3017
|
|
|
|
|
|
|
if any $err; |
|
3018
|
|
|
|
|
|
|
return $yi if @_ == 0; |
|
3019
|
|
|
|
|
|
|
} # sub: interpol() |
|
3020
|
|
|
|
|
|
|
*PDL::interpol = \&interpol; |
|
3021
|
|
|
|
|
|
|
|
|
3022
|
|
|
|
|
|
|
EOD |
|
3023
|
|
|
|
|
|
|
|
|
3024
|
|
|
|
|
|
|
pp_add_exported('','interpND'); |
|
3025
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
3026
|
|
|
|
|
|
|
=head2 interpND |
|
3027
|
|
|
|
|
|
|
|
|
3028
|
|
|
|
|
|
|
=for ref |
|
3029
|
|
|
|
|
|
|
|
|
3030
|
|
|
|
|
|
|
Interpolate values from an N-D ndarray, with switchable method |
|
3031
|
|
|
|
|
|
|
|
|
3032
|
|
|
|
|
|
|
=for example |
|
3033
|
|
|
|
|
|
|
|
|
3034
|
|
|
|
|
|
|
$source = 10*xvals(10,10) + yvals(10,10); |
|
3035
|
|
|
|
|
|
|
$index = pdl([[2.2,3.5],[4.1,5.0]],[[6.0,7.4],[8,9]]); |
|
3036
|
|
|
|
|
|
|
print $source->interpND( $index ); |
|
3037
|
|
|
|
|
|
|
|
|
3038
|
|
|
|
|
|
|
InterpND acts like L, |
|
3039
|
|
|
|
|
|
|
collapsing C<$index> by lookup |
|
3040
|
|
|
|
|
|
|
into C<$source>; but it does interpolation rather than direct sampling. |
|
3041
|
|
|
|
|
|
|
The interpolation method and boundary condition are switchable via |
|
3042
|
|
|
|
|
|
|
an options hash. |
|
3043
|
|
|
|
|
|
|
|
|
3044
|
|
|
|
|
|
|
By default, linear or sample interpolation is used, with constant |
|
3045
|
|
|
|
|
|
|
value outside the boundaries of the source pdl. No dataflow occurs, |
|
3046
|
|
|
|
|
|
|
because in general the output is computed rather than indexed. |
|
3047
|
|
|
|
|
|
|
|
|
3048
|
|
|
|
|
|
|
All the interpolation methods treat the pixels as value-centered, so |
|
3049
|
|
|
|
|
|
|
the C method will return C<< $a->(0) >> for coordinate values on |
|
3050
|
|
|
|
|
|
|
the set [-0.5,0.5], and all methods will return C<< $a->(1) >> for |
|
3051
|
|
|
|
|
|
|
a coordinate value of exactly 1. |
|
3052
|
|
|
|
|
|
|
|
|
3053
|
|
|
|
|
|
|
Recognized options: |
|
3054
|
|
|
|
|
|
|
|
|
3055
|
|
|
|
|
|
|
=over 3 |
|
3056
|
|
|
|
|
|
|
|
|
3057
|
|
|
|
|
|
|
=item method |
|
3058
|
|
|
|
|
|
|
|
|
3059
|
|
|
|
|
|
|
Values can be: |
|
3060
|
|
|
|
|
|
|
|
|
3061
|
|
|
|
|
|
|
=over 3 |
|
3062
|
|
|
|
|
|
|
|
|
3063
|
|
|
|
|
|
|
=item * 0, s, sample, Sample (default for integer source types) |
|
3064
|
|
|
|
|
|
|
|
|
3065
|
|
|
|
|
|
|
The nearest value is taken. Pixels are regarded as centered on their |
|
3066
|
|
|
|
|
|
|
respective integer coordinates (no offset from the linear case). |
|
3067
|
|
|
|
|
|
|
|
|
3068
|
|
|
|
|
|
|
=item * 1, l, linear, Linear (default for floating point source types) |
|
3069
|
|
|
|
|
|
|
|
|
3070
|
|
|
|
|
|
|
The values are N-linearly interpolated from an N-dimensional cube of size 2. |
|
3071
|
|
|
|
|
|
|
|
|
3072
|
|
|
|
|
|
|
=item * 3, c, cube, cubic, Cubic |
|
3073
|
|
|
|
|
|
|
|
|
3074
|
|
|
|
|
|
|
The values are interpolated using a local cubic fit to the data. The |
|
3075
|
|
|
|
|
|
|
fit is constrained to match the original data and its derivative at the |
|
3076
|
|
|
|
|
|
|
data points. The second derivative of the fit is not continuous at the |
|
3077
|
|
|
|
|
|
|
data points. Multidimensional datasets are interpolated by the |
|
3078
|
|
|
|
|
|
|
successive-collapse method. |
|
3079
|
|
|
|
|
|
|
|
|
3080
|
|
|
|
|
|
|
(Note that the constraint on the first derivative causes a small amount |
|
3081
|
|
|
|
|
|
|
of ringing around sudden features such as step functions). |
|
3082
|
|
|
|
|
|
|
|
|
3083
|
|
|
|
|
|
|
=item * f, fft, fourier, Fourier |
|
3084
|
|
|
|
|
|
|
|
|
3085
|
|
|
|
|
|
|
The source is Fourier transformed, and the interpolated values are |
|
3086
|
|
|
|
|
|
|
explicitly calculated from the coefficients. The boundary condition |
|
3087
|
|
|
|
|
|
|
option is ignored -- periodic boundaries are imposed. |
|
3088
|
|
|
|
|
|
|
|
|
3089
|
|
|
|
|
|
|
If you pass in the option "fft", and it is a list (ARRAY) ref, then it |
|
3090
|
|
|
|
|
|
|
is a stash for the magnitude and phase of the source FFT. If the list |
|
3091
|
|
|
|
|
|
|
has two elements then they are taken as already computed; otherwise |
|
3092
|
|
|
|
|
|
|
they are calculated and put in the stash. |
|
3093
|
|
|
|
|
|
|
|
|
3094
|
|
|
|
|
|
|
=back |
|
3095
|
|
|
|
|
|
|
|
|
3096
|
|
|
|
|
|
|
=item b, bound, boundary, Boundary |
|
3097
|
|
|
|
|
|
|
|
|
3098
|
|
|
|
|
|
|
This option is passed unmodified into L, |
|
3099
|
|
|
|
|
|
|
which is used as the indexing engine for the interpolation. |
|
3100
|
|
|
|
|
|
|
Some current allowed values are 'extend', 'periodic', 'truncate', and 'mirror' |
|
3101
|
|
|
|
|
|
|
(default is 'truncate'). |
|
3102
|
|
|
|
|
|
|
|
|
3103
|
|
|
|
|
|
|
=item bad |
|
3104
|
|
|
|
|
|
|
|
|
3105
|
|
|
|
|
|
|
contains the fill value used for 'truncate' boundary. (default 0) |
|
3106
|
|
|
|
|
|
|
|
|
3107
|
|
|
|
|
|
|
=item fft |
|
3108
|
|
|
|
|
|
|
|
|
3109
|
|
|
|
|
|
|
An array ref whose associated list is used to stash the FFT of the source |
|
3110
|
|
|
|
|
|
|
data, for the FFT method. |
|
3111
|
|
|
|
|
|
|
|
|
3112
|
|
|
|
|
|
|
=back |
|
3113
|
|
|
|
|
|
|
|
|
3114
|
|
|
|
|
|
|
=cut |
|
3115
|
|
|
|
|
|
|
|
|
3116
|
|
|
|
|
|
|
*interpND = *PDL::interpND; |
|
3117
|
|
|
|
|
|
|
sub PDL::interpND { |
|
3118
|
|
|
|
|
|
|
my $source = shift; |
|
3119
|
|
|
|
|
|
|
my $index = shift; |
|
3120
|
|
|
|
|
|
|
my $options = shift; |
|
3121
|
|
|
|
|
|
|
|
|
3122
|
|
|
|
|
|
|
barf 'Usage: interpND($source,$index[,{%options}])' |
|
3123
|
|
|
|
|
|
|
if(defined $options and ref $options ne 'HASH'); |
|
3124
|
|
|
|
|
|
|
|
|
3125
|
|
|
|
|
|
|
my $opt = defined $options ? $options : {}; |
|
3126
|
|
|
|
|
|
|
|
|
3127
|
|
|
|
|
|
|
my $method = $opt->{m} || $opt->{meth} || $opt->{method} || $opt->{Method}; |
|
3128
|
|
|
|
|
|
|
$method //= $source->type->integer ? 'sample' : 'linear'; |
|
3129
|
|
|
|
|
|
|
|
|
3130
|
|
|
|
|
|
|
my $boundary = $opt->{b} || $opt->{boundary} || $opt->{Boundary} || $opt->{bound} || $opt->{Bound} || 'extend'; |
|
3131
|
|
|
|
|
|
|
my $bad = $opt->{bad} || $opt->{Bad} || 0.0; |
|
3132
|
|
|
|
|
|
|
|
|
3133
|
|
|
|
|
|
|
return $source->range(PDL::Math::floor($index+0.5),0,$boundary) |
|
3134
|
|
|
|
|
|
|
if $method =~ m/^s(am(p(le)?)?)?/i; |
|
3135
|
|
|
|
|
|
|
|
|
3136
|
|
|
|
|
|
|
if (($method eq 1) || $method =~ m/^l(in(ear)?)?/i) { |
|
3137
|
|
|
|
|
|
|
## key: (ith = index broadcast; cth = cube broadcast; sth = source broadcast) |
|
3138
|
|
|
|
|
|
|
my $d = $index->dim(0); |
|
3139
|
|
|
|
|
|
|
my $di = $index->ndims - 1; |
|
3140
|
|
|
|
|
|
|
|
|
3141
|
|
|
|
|
|
|
# Grab a 2-on-a-side n-cube around each desired pixel |
|
3142
|
|
|
|
|
|
|
my $samp = $source->range($index->floor,2,$boundary); # (ith, cth, sth) |
|
3143
|
|
|
|
|
|
|
|
|
3144
|
|
|
|
|
|
|
# Reorder to put the cube dimensions in front and convert to a list |
|
3145
|
|
|
|
|
|
|
$samp = $samp->reorder( $di .. $di+$d-1, |
|
3146
|
|
|
|
|
|
|
0 .. $di-1, |
|
3147
|
|
|
|
|
|
|
$di+$d .. $samp->ndims-1) # (cth, ith, sth) |
|
3148
|
|
|
|
|
|
|
->clump($d); # (clst, ith, sth) |
|
3149
|
|
|
|
|
|
|
|
|
3150
|
|
|
|
|
|
|
# Enumerate the corners of an n-cube and convert to a list |
|
3151
|
|
|
|
|
|
|
# (the 'x' is the normal perl repeat operator) |
|
3152
|
|
|
|
|
|
|
my $crnr = PDL::Basic::ndcoords( (2) x $index->dim(0) ) # (index,cth) |
|
3153
|
|
|
|
|
|
|
->mv(0,-1)->clump($index->dim(0))->mv(-1,0); # (index, clst) |
|
3154
|
|
|
|
|
|
|
# a & b are the weighting coefficients. |
|
3155
|
|
|
|
|
|
|
my($x,$y); |
|
3156
|
|
|
|
|
|
|
$index->where( 0 * $index ) .= -10; # Change NaN to invalid |
|
3157
|
|
|
|
|
|
|
{ |
|
3158
|
|
|
|
|
|
|
my $bb = PDL::Math::floor($index); |
|
3159
|
|
|
|
|
|
|
$x = ($index - $bb) -> dummy(1,$crnr->dim(1)); # index, clst, ith |
|
3160
|
|
|
|
|
|
|
$y = ($bb + 1 - $index) -> dummy(1,$crnr->dim(1)); # index, clst, ith |
|
3161
|
|
|
|
|
|
|
} |
|
3162
|
|
|
|
|
|
|
|
|
3163
|
|
|
|
|
|
|
# Use 1/0 corners to select which multiplier happens, multiply |
|
3164
|
|
|
|
|
|
|
# 'em all together to get sample weights, and sum to get the answer. |
|
3165
|
|
|
|
|
|
|
my $out0 = ( ($x * ($crnr==1) + $y * ($crnr==0)) #index, clst, ith |
|
3166
|
|
|
|
|
|
|
-> prodover #clst, ith |
|
3167
|
|
|
|
|
|
|
); |
|
3168
|
|
|
|
|
|
|
|
|
3169
|
|
|
|
|
|
|
my $out = ($out0 * $samp)->sumover; # ith, sth |
|
3170
|
|
|
|
|
|
|
|
|
3171
|
|
|
|
|
|
|
# Work around BAD-not-being-contagious bug in PDL <= 2.6 bad handling code --CED 3-April-2013 |
|
3172
|
|
|
|
|
|
|
if ($source->badflag) { |
|
3173
|
|
|
|
|
|
|
my $baddies = $samp->isbad->orover; |
|
3174
|
|
|
|
|
|
|
$out = $out->setbadif($baddies); |
|
3175
|
|
|
|
|
|
|
} |
|
3176
|
|
|
|
|
|
|
|
|
3177
|
|
|
|
|
|
|
$out = $out->convert($source->type->enum) if $out->type != $source->type; |
|
3178
|
|
|
|
|
|
|
return $out; |
|
3179
|
|
|
|
|
|
|
|
|
3180
|
|
|
|
|
|
|
} elsif(($method eq 3) || $method =~ m/^c(u(b(e|ic)?)?)?/i) { |
|
3181
|
|
|
|
|
|
|
|
|
3182
|
|
|
|
|
|
|
my ($d,@di) = $index->dims; |
|
3183
|
|
|
|
|
|
|
my $di = $index->ndims - 1; |
|
3184
|
|
|
|
|
|
|
|
|
3185
|
|
|
|
|
|
|
# Grab a 4-on-a-side n-cube around each desired pixel |
|
3186
|
|
|
|
|
|
|
my $samp = $source->range($index->floor - 1,4,$boundary) #ith, cth, sth |
|
3187
|
|
|
|
|
|
|
->reorder( $di .. $di+$d-1, 0..$di-1, $di+$d .. $source->ndims-1 ); |
|
3188
|
|
|
|
|
|
|
# (cth, ith, sth) |
|
3189
|
|
|
|
|
|
|
|
|
3190
|
|
|
|
|
|
|
# Make a cube of the subpixel offsets, and expand its dims to |
|
3191
|
|
|
|
|
|
|
# a 4-on-a-side N-1 cube, to match the slices of $samp (used below). |
|
3192
|
|
|
|
|
|
|
my $y = $index - $index->floor; |
|
3193
|
|
|
|
|
|
|
for my $i(1..$d-1) { |
|
3194
|
|
|
|
|
|
|
$y = $y->dummy($i,4); |
|
3195
|
|
|
|
|
|
|
} |
|
3196
|
|
|
|
|
|
|
|
|
3197
|
|
|
|
|
|
|
# Collapse by interpolation, one dimension at a time... |
|
3198
|
|
|
|
|
|
|
for my $i(0..$d-1) { |
|
3199
|
|
|
|
|
|
|
my $a0 = $samp->slice("(1)"); # Just-under-sample |
|
3200
|
|
|
|
|
|
|
my $a1 = $samp->slice("(2)"); # Just-over-sample |
|
3201
|
|
|
|
|
|
|
my $a1a0 = $a1 - $a0; |
|
3202
|
|
|
|
|
|
|
|
|
3203
|
|
|
|
|
|
|
my $gradient = 0.5 * ($samp->slice("2:3")-$samp->slice("0:1")); |
|
3204
|
|
|
|
|
|
|
my $s0 = $gradient->slice("(0)"); # Just-under-gradient |
|
3205
|
|
|
|
|
|
|
my $s1 = $gradient->slice("(1)"); # Just-over-gradient |
|
3206
|
|
|
|
|
|
|
|
|
3207
|
|
|
|
|
|
|
my $bb = $y->slice("($i)"); |
|
3208
|
|
|
|
|
|
|
|
|
3209
|
|
|
|
|
|
|
# Collapse the sample... |
|
3210
|
|
|
|
|
|
|
$samp = ( $a0 + |
|
3211
|
|
|
|
|
|
|
$bb * ( |
|
3212
|
|
|
|
|
|
|
$s0 + |
|
3213
|
|
|
|
|
|
|
$bb * ( (3 * $a1a0 - 2*$s0 - $s1) + |
|
3214
|
|
|
|
|
|
|
$bb * ( $s1 + $s0 - 2*$a1a0 ) |
|
3215
|
|
|
|
|
|
|
) |
|
3216
|
|
|
|
|
|
|
) |
|
3217
|
|
|
|
|
|
|
); |
|
3218
|
|
|
|
|
|
|
|
|
3219
|
|
|
|
|
|
|
# "Collapse" the subpixel offset... |
|
3220
|
|
|
|
|
|
|
$y = $y->slice(":,($i)"); |
|
3221
|
|
|
|
|
|
|
} |
|
3222
|
|
|
|
|
|
|
|
|
3223
|
|
|
|
|
|
|
$samp = $samp->convert($source->type->enum) if $samp->type != $source->type; |
|
3224
|
|
|
|
|
|
|
return $samp; |
|
3225
|
|
|
|
|
|
|
|
|
3226
|
|
|
|
|
|
|
} elsif($method =~ m/^f(ft|ourier)?/i) { |
|
3227
|
|
|
|
|
|
|
|
|
3228
|
|
|
|
|
|
|
require PDL::FFT; |
|
3229
|
|
|
|
|
|
|
my $fftref = $opt->{fft}; |
|
3230
|
|
|
|
|
|
|
$fftref = [] unless(ref $fftref eq 'ARRAY'); |
|
3231
|
|
|
|
|
|
|
if(@$fftref != 2) { |
|
3232
|
|
|
|
|
|
|
my $x = $source->copy; |
|
3233
|
|
|
|
|
|
|
my $y = zeroes($source); |
|
3234
|
|
|
|
|
|
|
PDL::FFT::fftnd($x,$y); |
|
3235
|
|
|
|
|
|
|
$fftref->[0] = sqrt($x*$x+$y*$y) / $x->nelem; |
|
3236
|
|
|
|
|
|
|
$fftref->[1] = - atan2($y,$x); |
|
3237
|
|
|
|
|
|
|
} |
|
3238
|
|
|
|
|
|
|
|
|
3239
|
|
|
|
|
|
|
my $i; |
|
3240
|
|
|
|
|
|
|
my $c = PDL::Basic::ndcoords($source); # (dim, source-dims) |
|
3241
|
|
|
|
|
|
|
for $i(1..$index->ndims-1) { |
|
3242
|
|
|
|
|
|
|
$c = $c->dummy($i,$index->dim($i)) |
|
3243
|
|
|
|
|
|
|
} |
|
3244
|
|
|
|
|
|
|
my $id = $index->ndims-1; |
|
3245
|
|
|
|
|
|
|
my $phase = (($c * $index * 3.14159 * 2 / pdl($source->dims)) |
|
3246
|
|
|
|
|
|
|
->sumover) # (index-dims, source-dims) |
|
3247
|
|
|
|
|
|
|
->reorder($id..$id+$source->ndims-1,0..$id-1); # (src, index) |
|
3248
|
|
|
|
|
|
|
|
|
3249
|
|
|
|
|
|
|
my $phref = $fftref->[1]->copy; # (source-dims) |
|
3250
|
|
|
|
|
|
|
my $mag = $fftref->[0]->copy; # (source-dims) |
|
3251
|
|
|
|
|
|
|
|
|
3252
|
|
|
|
|
|
|
for $i(1..$index->ndims-1) { |
|
3253
|
|
|
|
|
|
|
$phref = $phref->dummy(-1,$index->dim($i)); |
|
3254
|
|
|
|
|
|
|
$mag = $mag->dummy(-1,$index->dim($i)); |
|
3255
|
|
|
|
|
|
|
} |
|
3256
|
|
|
|
|
|
|
my $out = cos($phase + $phref ) * $mag; |
|
3257
|
|
|
|
|
|
|
$out = $out->clump($source->ndims)->sumover; |
|
3258
|
|
|
|
|
|
|
$out = $out->convert($source->type->enum) if $out->type != $source->type; |
|
3259
|
|
|
|
|
|
|
return $out; |
|
3260
|
|
|
|
|
|
|
} else { |
|
3261
|
|
|
|
|
|
|
barf("interpND: unknown method '$method'; valid ones are 'linear' and 'sample'.\n"); |
|
3262
|
|
|
|
|
|
|
} |
|
3263
|
|
|
|
|
|
|
} |
|
3264
|
|
|
|
|
|
|
|
|
3265
|
|
|
|
|
|
|
EOD |
|
3266
|
|
|
|
|
|
|
|
|
3267
|
|
|
|
|
|
|
############################################################## |
|
3268
|
|
|
|
|
|
|
# things related to indexing: one2nd, which, where |
|
3269
|
|
|
|
|
|
|
############################################################## |
|
3270
|
|
|
|
|
|
|
|
|
3271
|
|
|
|
|
|
|
pp_add_exported("", 'one2nd'); |
|
3272
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
3273
|
|
|
|
|
|
|
=head2 one2nd |
|
3274
|
|
|
|
|
|
|
|
|
3275
|
|
|
|
|
|
|
=for ref |
|
3276
|
|
|
|
|
|
|
|
|
3277
|
|
|
|
|
|
|
Converts a one dimensional index ndarray to a set of ND coordinates |
|
3278
|
|
|
|
|
|
|
|
|
3279
|
|
|
|
|
|
|
=for usage |
|
3280
|
|
|
|
|
|
|
|
|
3281
|
|
|
|
|
|
|
@coords=one2nd($x, $indices) |
|
3282
|
|
|
|
|
|
|
|
|
3283
|
|
|
|
|
|
|
returns an array of ndarrays containing the ND indexes corresponding to |
|
3284
|
|
|
|
|
|
|
the one dimensional list indices. The indices are assumed to |
|
3285
|
|
|
|
|
|
|
correspond to array C<$x> clumped using C. This routine is |
|
3286
|
|
|
|
|
|
|
used in the old vector form of L, but is useful on |
|
3287
|
|
|
|
|
|
|
its own occasionally. |
|
3288
|
|
|
|
|
|
|
|
|
3289
|
|
|
|
|
|
|
Returned ndarrays have the L datatype. C<$indices> can have |
|
3290
|
|
|
|
|
|
|
values larger than C<< $x->nelem >> but negative values in C<$indices> |
|
3291
|
|
|
|
|
|
|
will not give the answer you expect. |
|
3292
|
|
|
|
|
|
|
|
|
3293
|
|
|
|
|
|
|
=for example |
|
3294
|
|
|
|
|
|
|
|
|
3295
|
|
|
|
|
|
|
pdl> $x=pdl [[[1,2],[-1,1]], [[0,-3],[3,2]]]; $c=$x->clump(-1) |
|
3296
|
|
|
|
|
|
|
pdl> $maxind=maximum_ind($c); p $maxind; |
|
3297
|
|
|
|
|
|
|
6 |
|
3298
|
|
|
|
|
|
|
pdl> print one2nd($x, maximum_ind($c)) |
|
3299
|
|
|
|
|
|
|
0 1 1 |
|
3300
|
|
|
|
|
|
|
pdl> p $x->at(0,1,1) |
|
3301
|
|
|
|
|
|
|
3 |
|
3302
|
|
|
|
|
|
|
|
|
3303
|
|
|
|
|
|
|
=cut |
|
3304
|
|
|
|
|
|
|
|
|
3305
|
|
|
|
|
|
|
*one2nd = \&PDL::one2nd; |
|
3306
|
|
|
|
|
|
|
sub PDL::one2nd { |
|
3307
|
|
|
|
|
|
|
barf "Usage: one2nd \$array, \$indices\n" if @_ != 2; |
|
3308
|
|
|
|
|
|
|
my ($x, $ind)=@_; |
|
3309
|
|
|
|
|
|
|
my @dimension=$x->dims; |
|
3310
|
|
|
|
|
|
|
$ind = indx($ind); |
|
3311
|
|
|
|
|
|
|
my(@index); |
|
3312
|
|
|
|
|
|
|
my $count=0; |
|
3313
|
|
|
|
|
|
|
foreach (@dimension) { |
|
3314
|
|
|
|
|
|
|
$index[$count++]=$ind % $_; |
|
3315
|
|
|
|
|
|
|
$ind /= $_; |
|
3316
|
|
|
|
|
|
|
} |
|
3317
|
|
|
|
|
|
|
return @index; |
|
3318
|
|
|
|
|
|
|
} |
|
3319
|
|
|
|
|
|
|
|
|
3320
|
|
|
|
|
|
|
EOD |
|
3321
|
|
|
|
|
|
|
|
|
3322
|
|
|
|
|
|
|
my $doc_which = <<'EOD'; |
|
3323
|
|
|
|
|
|
|
|
|
3324
|
|
|
|
|
|
|
=for ref |
|
3325
|
|
|
|
|
|
|
|
|
3326
|
|
|
|
|
|
|
Returns indices of non-zero values from a 1-D PDL |
|
3327
|
|
|
|
|
|
|
|
|
3328
|
|
|
|
|
|
|
=for usage |
|
3329
|
|
|
|
|
|
|
|
|
3330
|
|
|
|
|
|
|
$i = which($mask); |
|
3331
|
|
|
|
|
|
|
|
|
3332
|
|
|
|
|
|
|
returns a pdl with indices for all those elements that are nonzero in |
|
3333
|
|
|
|
|
|
|
the mask. Note that the returned indices will be 1D. If you feed in a |
|
3334
|
|
|
|
|
|
|
multidimensional mask, it will be flattened before the indices are |
|
3335
|
|
|
|
|
|
|
calculated. See also L for multidimensional masks. |
|
3336
|
|
|
|
|
|
|
|
|
3337
|
|
|
|
|
|
|
If you want to index into the original mask or a similar ndarray |
|
3338
|
|
|
|
|
|
|
with output from C, remember to flatten it before calling index: |
|
3339
|
|
|
|
|
|
|
|
|
3340
|
|
|
|
|
|
|
$data = random 5, 5; |
|
3341
|
|
|
|
|
|
|
$idx = which $data > 0.5; # $idx is now 1D |
|
3342
|
|
|
|
|
|
|
$bigsum = $data->flat->index($idx)->sum; # flatten before indexing |
|
3343
|
|
|
|
|
|
|
|
|
3344
|
|
|
|
|
|
|
Compare also L for similar functionality. |
|
3345
|
|
|
|
|
|
|
|
|
3346
|
|
|
|
|
|
|
SEE ALSO: |
|
3347
|
|
|
|
|
|
|
|
|
3348
|
|
|
|
|
|
|
L returns separately the indices of both nonzero and zero |
|
3349
|
|
|
|
|
|
|
values in the mask. |
|
3350
|
|
|
|
|
|
|
|
|
3351
|
|
|
|
|
|
|
L returns separately slices of both nonzero and zero |
|
3352
|
|
|
|
|
|
|
values in the mask. |
|
3353
|
|
|
|
|
|
|
|
|
3354
|
|
|
|
|
|
|
L returns associated values from a data PDL, rather than |
|
3355
|
|
|
|
|
|
|
indices into the mask PDL. |
|
3356
|
|
|
|
|
|
|
|
|
3357
|
|
|
|
|
|
|
L returns N-D indices into a multidimensional PDL. |
|
3358
|
|
|
|
|
|
|
|
|
3359
|
|
|
|
|
|
|
=for example |
|
3360
|
|
|
|
|
|
|
|
|
3361
|
|
|
|
|
|
|
pdl> $x = sequence(10); p $x |
|
3362
|
|
|
|
|
|
|
[0 1 2 3 4 5 6 7 8 9] |
|
3363
|
|
|
|
|
|
|
pdl> $indx = which($x>6); p $indx |
|
3364
|
|
|
|
|
|
|
[7 8 9] |
|
3365
|
|
|
|
|
|
|
|
|
3366
|
|
|
|
|
|
|
=cut |
|
3367
|
|
|
|
|
|
|
|
|
3368
|
|
|
|
|
|
|
EOD |
|
3369
|
|
|
|
|
|
|
|
|
3370
|
|
|
|
|
|
|
my $doc_which_both = <<'EOD'; |
|
3371
|
|
|
|
|
|
|
|
|
3372
|
|
|
|
|
|
|
=for ref |
|
3373
|
|
|
|
|
|
|
|
|
3374
|
|
|
|
|
|
|
Returns indices of nonzero and zero values in a mask PDL |
|
3375
|
|
|
|
|
|
|
|
|
3376
|
|
|
|
|
|
|
=for usage |
|
3377
|
|
|
|
|
|
|
|
|
3378
|
|
|
|
|
|
|
($i, $c_i) = which_both($mask); |
|
3379
|
|
|
|
|
|
|
|
|
3380
|
|
|
|
|
|
|
This works just as L, but the complement of C<$i> will be in |
|
3381
|
|
|
|
|
|
|
C<$c_i>. |
|
3382
|
|
|
|
|
|
|
|
|
3383
|
|
|
|
|
|
|
=for example |
|
3384
|
|
|
|
|
|
|
|
|
3385
|
|
|
|
|
|
|
pdl> p $x = sequence(10) |
|
3386
|
|
|
|
|
|
|
[0 1 2 3 4 5 6 7 8 9] |
|
3387
|
|
|
|
|
|
|
pdl> ($big, $small) = which_both($x >= 5); p "$big\n$small" |
|
3388
|
|
|
|
|
|
|
[5 6 7 8 9] |
|
3389
|
|
|
|
|
|
|
[0 1 2 3 4] |
|
3390
|
|
|
|
|
|
|
|
|
3391
|
|
|
|
|
|
|
See also L for the n-dimensional version. |
|
3392
|
|
|
|
|
|
|
|
|
3393
|
|
|
|
|
|
|
=cut |
|
3394
|
|
|
|
|
|
|
|
|
3395
|
|
|
|
|
|
|
EOD |
|
3396
|
|
|
|
|
|
|
|
|
3397
|
|
|
|
|
|
|
for ( |
|
3398
|
|
|
|
|
|
|
{Name=>'which', |
|
3399
|
|
|
|
|
|
|
Pars => 'mask(n); indx [o] inds(n); indx [o]lastout()', |
|
3400
|
|
|
|
|
|
|
Variables => 'PDL_Indx dm=0;', |
|
3401
|
|
|
|
|
|
|
Elseclause => "", |
|
3402
|
|
|
|
|
|
|
Outclause => '$lastout() = dm; loop(n=dm) %{ $inds() = -1; %}', |
|
3403
|
|
|
|
|
|
|
Doc => $doc_which, |
|
3404
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
3405
|
|
|
|
|
|
|
sub which { my ($this,$out) = @_; |
|
3406
|
|
|
|
|
|
|
$this = $this->flat; |
|
3407
|
|
|
|
|
|
|
$out //= $this->nullcreate; |
|
3408
|
|
|
|
|
|
|
PDL::_which_int($this,$out,my $lastout = $this->nullcreate); |
|
3409
|
|
|
|
|
|
|
my $lastoutmax = $lastout->max->sclr; |
|
3410
|
|
|
|
|
|
|
$lastoutmax ? $out->slice('0:'.($lastoutmax-1))->sever : empty(indx); |
|
3411
|
|
|
|
|
|
|
} |
|
3412
|
|
|
|
|
|
|
*PDL::which = \&which; |
|
3413
|
|
|
|
|
|
|
EOD |
|
3414
|
|
|
|
|
|
|
}, |
|
3415
|
|
|
|
|
|
|
{Name => 'which_both', |
|
3416
|
|
|
|
|
|
|
Pars => 'mask(n); indx [o] inds(n); indx [o]notinds(n); indx [o]lastout(); indx [o]lastoutn()', |
|
3417
|
|
|
|
|
|
|
Variables => 'PDL_Indx dm=0; int dm2=0;', |
|
3418
|
|
|
|
|
|
|
Elseclause => "else { \n \$notinds(n => dm2)=n; \n dm2++;\n }", |
|
3419
|
|
|
|
|
|
|
Outclause => '$lastout() = dm; $lastoutn() = dm2; loop(n=dm) %{ $inds() = -1; %} loop(n=dm2) %{ $notinds() = -1; %}', |
|
3420
|
|
|
|
|
|
|
Doc => $doc_which_both, |
|
3421
|
|
|
|
|
|
|
PMCode=>pp_line_numbers(__LINE__, <<'EOD'), |
|
3422
|
|
|
|
|
|
|
sub which_both { my ($this,$outi,$outni) = @_; |
|
3423
|
|
|
|
|
|
|
$this = $this->flat; |
|
3424
|
|
|
|
|
|
|
$outi //= $this->nullcreate; |
|
3425
|
|
|
|
|
|
|
$outni //= $this->nullcreate; |
|
3426
|
|
|
|
|
|
|
PDL::_which_both_int($this,$outi,$outni,my $lastout = $this->nullcreate,my $lastoutn = $this->nullcreate); |
|
3427
|
|
|
|
|
|
|
my $lastoutmax = $lastout->max->sclr; |
|
3428
|
|
|
|
|
|
|
$outi = $lastoutmax ? $outi->slice('0:'.($lastoutmax-1))->sever : empty(indx); |
|
3429
|
|
|
|
|
|
|
return $outi if !wantarray; |
|
3430
|
|
|
|
|
|
|
my $lastoutnmax = $lastoutn->max->sclr; |
|
3431
|
|
|
|
|
|
|
($outi, $lastoutnmax ? $outni->slice('0:'.($lastoutnmax-1))->sever : empty(indx)); |
|
3432
|
|
|
|
|
|
|
} |
|
3433
|
|
|
|
|
|
|
*PDL::which_both = \&which_both; |
|
3434
|
|
|
|
|
|
|
EOD |
|
3435
|
|
|
|
|
|
|
} |
|
3436
|
|
|
|
|
|
|
) |
|
3437
|
|
|
|
|
|
|
{ |
|
3438
|
|
|
|
|
|
|
pp_def($_->{Name}, |
|
3439
|
|
|
|
|
|
|
HandleBad => 1, |
|
3440
|
|
|
|
|
|
|
Doc => $_->{Doc}, |
|
3441
|
|
|
|
|
|
|
Pars => $_->{Pars}, |
|
3442
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
3443
|
|
|
|
|
|
|
PMCode => $_->{PMCode}, |
|
3444
|
|
|
|
|
|
|
Code => $_->{Variables} .' |
|
3445
|
|
|
|
|
|
|
loop(n) %{ |
|
3446
|
|
|
|
|
|
|
if ( $mask() PDL_IF_BAD(&& $ISGOOD($mask()),) ) { |
|
3447
|
|
|
|
|
|
|
$inds(n => dm) = n; |
|
3448
|
|
|
|
|
|
|
dm++; |
|
3449
|
|
|
|
|
|
|
}'.$_->{Elseclause}.' |
|
3450
|
|
|
|
|
|
|
%}'.$_->{Outclause}, |
|
3451
|
|
|
|
|
|
|
); |
|
3452
|
|
|
|
|
|
|
} |
|
3453
|
|
|
|
|
|
|
|
|
3454
|
|
|
|
|
|
|
pp_def('whichover', |
|
3455
|
|
|
|
|
|
|
HandleBad => 1, |
|
3456
|
|
|
|
|
|
|
Inplace => 1, |
|
3457
|
|
|
|
|
|
|
Pars => 'a(n); [o]o(n)', |
|
3458
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
3459
|
|
|
|
|
|
|
Code => <<'EOF', |
|
3460
|
|
|
|
|
|
|
PDL_Indx last = 0; |
|
3461
|
|
|
|
|
|
|
loop(n) %{ |
|
3462
|
|
|
|
|
|
|
if ($a() PDL_IF_BAD(&& $ISGOOD($a()),)) $o(n=>last++) = n; |
|
3463
|
|
|
|
|
|
|
%} |
|
3464
|
|
|
|
|
|
|
loop(n=last) %{ $o() = -1; %} |
|
3465
|
|
|
|
|
|
|
EOF |
|
3466
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
3467
|
|
|
|
|
|
|
=for ref |
|
3468
|
|
|
|
|
|
|
|
|
3469
|
|
|
|
|
|
|
Collects the coordinates of non-zero, non-bad values in each 1D mask in |
|
3470
|
|
|
|
|
|
|
ndarray at the start of the output, and fills the rest with -1. |
|
3471
|
|
|
|
|
|
|
|
|
3472
|
|
|
|
|
|
|
By using L etc. it is possible to use I dimension. |
|
3473
|
|
|
|
|
|
|
|
|
3474
|
|
|
|
|
|
|
=for example |
|
3475
|
|
|
|
|
|
|
|
|
3476
|
|
|
|
|
|
|
my $a = pdl q[3 4 2 3 2 3 1]; |
|
3477
|
|
|
|
|
|
|
my $b = $a->uniq; |
|
3478
|
|
|
|
|
|
|
my $c = +($a->dummy(0) == $b)->transpose; |
|
3479
|
|
|
|
|
|
|
print $c, $c->whichover; |
|
3480
|
|
|
|
|
|
|
# [ |
|
3481
|
|
|
|
|
|
|
# [0 0 0 0 0 0 1] |
|
3482
|
|
|
|
|
|
|
# [0 0 1 0 1 0 0] |
|
3483
|
|
|
|
|
|
|
# [1 0 0 1 0 1 0] |
|
3484
|
|
|
|
|
|
|
# [0 1 0 0 0 0 0] |
|
3485
|
|
|
|
|
|
|
# ] |
|
3486
|
|
|
|
|
|
|
# [ |
|
3487
|
|
|
|
|
|
|
# [ 6 -1 -1 -1 -1 -1 -1] |
|
3488
|
|
|
|
|
|
|
# [ 2 4 -1 -1 -1 -1 -1] |
|
3489
|
|
|
|
|
|
|
# [ 0 3 5 -1 -1 -1 -1] |
|
3490
|
|
|
|
|
|
|
# [ 1 -1 -1 -1 -1 -1 -1] |
|
3491
|
|
|
|
|
|
|
# ] |
|
3492
|
|
|
|
|
|
|
|
|
3493
|
|
|
|
|
|
|
EOF |
|
3494
|
|
|
|
|
|
|
); |
|
3495
|
|
|
|
|
|
|
|
|
3496
|
|
|
|
|
|
|
pp_def('approx_artol', |
|
3497
|
|
|
|
|
|
|
Pars => 'got(); expected(); sbyte [o] result()', |
|
3498
|
|
|
|
|
|
|
OtherPars => 'double atol; double rtol', |
|
3499
|
|
|
|
|
|
|
OtherParsDefaults => { atol => 1e-6, rtol => 0 }, |
|
3500
|
|
|
|
|
|
|
GenericTypes => [ppdefs_all], |
|
3501
|
|
|
|
|
|
|
ArgOrder => 1, |
|
3502
|
|
|
|
|
|
|
HandleBad => 1, |
|
3503
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
3504
|
|
|
|
|
|
|
double atol2 = $COMP(atol)*$COMP(atol), rtol2 = $COMP(rtol)*$COMP(rtol); |
|
3505
|
|
|
|
|
|
|
PDL_IF_BAD(char got_badflag = !!$PDLSTATEISBAD(got); char exp_badflag = !!$PDLSTATEISBAD(expected);,) |
|
3506
|
|
|
|
|
|
|
broadcastloop %{ |
|
3507
|
|
|
|
|
|
|
$GENERIC() expctd = $expected(); |
|
3508
|
|
|
|
|
|
|
if (PDL_ISNAN_$PPSYM()($got()) && PDL_ISNAN_$PPSYM()(expctd)) { $result() = 1; continue; } |
|
3509
|
|
|
|
|
|
|
if (PDL_ISNAN_$PPSYM()($got()) || PDL_ISNAN_$PPSYM()(expctd)) { $result() = 0; continue; } |
|
3510
|
|
|
|
|
|
|
PDL_IF_BAD( |
|
3511
|
|
|
|
|
|
|
if ((got_badflag && $ISBAD(got())) && (exp_badflag && $ISBADVAR(expctd,expected))) { $result() = 1; continue; } |
|
3512
|
|
|
|
|
|
|
if ((got_badflag && $ISBAD(got())) || (exp_badflag && $ISBADVAR(expctd,expected))) { $result() = 0; continue; } |
|
3513
|
|
|
|
|
|
|
,) |
|
3514
|
|
|
|
|
|
|
if ($got() == expctd) { $result() = 1; continue; } |
|
3515
|
|
|
|
|
|
|
$GENERIC() diff = $got() - expctd; |
|
3516
|
|
|
|
|
|
|
double abs_diff2 = PDL_IF_GENTYPE_REAL( |
|
3517
|
|
|
|
|
|
|
diff * diff, |
|
3518
|
|
|
|
|
|
|
(creall(diff) * creall(diff)) + (cimagl(diff) * cimagl(diff)) |
|
3519
|
|
|
|
|
|
|
); |
|
3520
|
|
|
|
|
|
|
if (abs_diff2 <= atol2) { $result() = 1; continue; } |
|
3521
|
|
|
|
|
|
|
double rel_diff2 = rtol2 * PDL_IF_GENTYPE_REAL( |
|
3522
|
|
|
|
|
|
|
expctd * expctd, |
|
3523
|
|
|
|
|
|
|
((creall(expctd) * creall(expctd)) + (cimagl(expctd) * cimagl(expctd))) |
|
3524
|
|
|
|
|
|
|
); |
|
3525
|
|
|
|
|
|
|
if (abs_diff2 <= rel_diff2) { $result() = 1; continue; } |
|
3526
|
|
|
|
|
|
|
$result() = 0; |
|
3527
|
|
|
|
|
|
|
%} |
|
3528
|
|
|
|
|
|
|
EOF |
|
3529
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
3530
|
|
|
|
|
|
|
=for ref |
|
3531
|
|
|
|
|
|
|
|
|
3532
|
|
|
|
|
|
|
Returns C mask whether C<< abs($got()-$expected())> <= >> either |
|
3533
|
|
|
|
|
|
|
absolute or relative (C * C<$expected()>) tolerances. |
|
3534
|
|
|
|
|
|
|
|
|
3535
|
|
|
|
|
|
|
Relative tolerance defaults to zero, and absolute tolerance defaults to |
|
3536
|
|
|
|
|
|
|
C<1e-6>, for compatibility with L. |
|
3537
|
|
|
|
|
|
|
|
|
3538
|
|
|
|
|
|
|
Works with complex numbers, and to avoid expensive Cing uses the |
|
3539
|
|
|
|
|
|
|
squares of the input quantities and differences. Bear this in mind for |
|
3540
|
|
|
|
|
|
|
numbers outside the range (for C) of about C<1e-154..1e154>. |
|
3541
|
|
|
|
|
|
|
|
|
3542
|
|
|
|
|
|
|
Handles Cs by showing them approximately equal (i.e. true in the |
|
3543
|
|
|
|
|
|
|
output) if both values are C, and not otherwise. |
|
3544
|
|
|
|
|
|
|
|
|
3545
|
|
|
|
|
|
|
Adapted from code by Edward Baudrez, test changed from C<< < >> to C<< <= >>. |
|
3546
|
|
|
|
|
|
|
EOF |
|
3547
|
|
|
|
|
|
|
BadDoc => <<'EOF', |
|
3548
|
|
|
|
|
|
|
Handles bad values similarly to Cs, above. This includes if only |
|
3549
|
|
|
|
|
|
|
one of the two input ndarrays has their badflag true. |
|
3550
|
|
|
|
|
|
|
EOF |
|
3551
|
|
|
|
|
|
|
); |
|
3552
|
|
|
|
|
|
|
|
|
3553
|
|
|
|
|
|
|
pp_add_exported("", 'where'); |
|
3554
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
3555
|
|
|
|
|
|
|
=head2 where |
|
3556
|
|
|
|
|
|
|
|
|
3557
|
|
|
|
|
|
|
=for ref |
|
3558
|
|
|
|
|
|
|
|
|
3559
|
|
|
|
|
|
|
Use a mask to select values from one or more data PDLs |
|
3560
|
|
|
|
|
|
|
|
|
3561
|
|
|
|
|
|
|
C accepts one or more data ndarrays and a mask ndarray. It |
|
3562
|
|
|
|
|
|
|
returns a list of output ndarrays, corresponding to the input data |
|
3563
|
|
|
|
|
|
|
ndarrays. Each output ndarray is a 1-dimensional list of values in its |
|
3564
|
|
|
|
|
|
|
corresponding data ndarray. The values are drawn from locations where |
|
3565
|
|
|
|
|
|
|
the mask is nonzero. |
|
3566
|
|
|
|
|
|
|
|
|
3567
|
|
|
|
|
|
|
The output PDLs are still connected to the original data PDLs, for the |
|
3568
|
|
|
|
|
|
|
purpose of dataflow. |
|
3569
|
|
|
|
|
|
|
|
|
3570
|
|
|
|
|
|
|
C combines the functionality of L and L |
|
3571
|
|
|
|
|
|
|
into a single operation. |
|
3572
|
|
|
|
|
|
|
|
|
3573
|
|
|
|
|
|
|
BUGS: |
|
3574
|
|
|
|
|
|
|
|
|
3575
|
|
|
|
|
|
|
While C works OK for most N-dimensional cases, it does not |
|
3576
|
|
|
|
|
|
|
broadcast properly over (for example) the (N+1)th dimension in data |
|
3577
|
|
|
|
|
|
|
that is compared to an N-dimensional mask. Use C for that. |
|
3578
|
|
|
|
|
|
|
|
|
3579
|
|
|
|
|
|
|
=for example |
|
3580
|
|
|
|
|
|
|
|
|
3581
|
|
|
|
|
|
|
$i = $x->where($x+5 > 0); # $i contains those elements of $x |
|
3582
|
|
|
|
|
|
|
# where mask ($x+5 > 0) is 1 |
|
3583
|
|
|
|
|
|
|
$i .= -5; # Set those elements (of $x) to -5. Together, these |
|
3584
|
|
|
|
|
|
|
# commands clamp $x to a maximum of -5. |
|
3585
|
|
|
|
|
|
|
|
|
3586
|
|
|
|
|
|
|
It is also possible to use the same mask for several ndarrays with |
|
3587
|
|
|
|
|
|
|
the same call: |
|
3588
|
|
|
|
|
|
|
|
|
3589
|
|
|
|
|
|
|
($i,$j,$k) = where($x,$y,$z, $x+5>0); |
|
3590
|
|
|
|
|
|
|
|
|
3591
|
|
|
|
|
|
|
Note: C<$i> is always 1-D, even if C<$x> is E1-D. |
|
3592
|
|
|
|
|
|
|
|
|
3593
|
|
|
|
|
|
|
WARNING: The first argument |
|
3594
|
|
|
|
|
|
|
(the values) and the second argument (the mask) currently have to have |
|
3595
|
|
|
|
|
|
|
the exact same dimensions (or horrible things happen). You *cannot* |
|
3596
|
|
|
|
|
|
|
broadcast over a smaller mask, for example. |
|
3597
|
|
|
|
|
|
|
|
|
3598
|
|
|
|
|
|
|
=cut |
|
3599
|
|
|
|
|
|
|
|
|
3600
|
|
|
|
|
|
|
sub PDL::where :lvalue { |
|
3601
|
|
|
|
|
|
|
barf "Usage: where( \$pdl1, ..., \$pdlN, \$mask )\n" if @_ == 1; |
|
3602
|
|
|
|
|
|
|
my $mask = pop->flat->which; |
|
3603
|
|
|
|
|
|
|
@_ == 1 ? $_[0]->flat->index($mask) : map $_->flat->index($mask), @_; |
|
3604
|
|
|
|
|
|
|
} |
|
3605
|
|
|
|
|
|
|
*where = \&PDL::where; |
|
3606
|
|
|
|
|
|
|
|
|
3607
|
|
|
|
|
|
|
EOD |
|
3608
|
|
|
|
|
|
|
|
|
3609
|
|
|
|
|
|
|
pp_add_exported("", 'where_both'); |
|
3610
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
3611
|
|
|
|
|
|
|
=head2 where_both |
|
3612
|
|
|
|
|
|
|
|
|
3613
|
|
|
|
|
|
|
=for ref |
|
3614
|
|
|
|
|
|
|
|
|
3615
|
|
|
|
|
|
|
Returns slices (non-zero in mask, zero) of an ndarray according to a mask |
|
3616
|
|
|
|
|
|
|
|
|
3617
|
|
|
|
|
|
|
=for usage |
|
3618
|
|
|
|
|
|
|
|
|
3619
|
|
|
|
|
|
|
($match_vals, $non_match_vals) = where_both($pdl, $mask); |
|
3620
|
|
|
|
|
|
|
|
|
3621
|
|
|
|
|
|
|
This works like L, but (flattened) data-flowing slices |
|
3622
|
|
|
|
|
|
|
rather than index-sets are returned. |
|
3623
|
|
|
|
|
|
|
|
|
3624
|
|
|
|
|
|
|
=for example |
|
3625
|
|
|
|
|
|
|
|
|
3626
|
|
|
|
|
|
|
pdl> p $x = sequence(10) + 2 |
|
3627
|
|
|
|
|
|
|
[2 3 4 5 6 7 8 9 10 11] |
|
3628
|
|
|
|
|
|
|
pdl> ($big, $small) = where_both($x, $x > 5); p "$big\n$small" |
|
3629
|
|
|
|
|
|
|
[6 7 8 9 10 11] |
|
3630
|
|
|
|
|
|
|
[2 3 4 5] |
|
3631
|
|
|
|
|
|
|
pdl> p $big += 2, $small -= 1 |
|
3632
|
|
|
|
|
|
|
[8 9 10 11 12 13] [1 2 3 4] |
|
3633
|
|
|
|
|
|
|
pdl> p $x |
|
3634
|
|
|
|
|
|
|
[1 2 3 4 8 9 10 11 12 13] |
|
3635
|
|
|
|
|
|
|
|
|
3636
|
|
|
|
|
|
|
=cut |
|
3637
|
|
|
|
|
|
|
|
|
3638
|
|
|
|
|
|
|
sub PDL::where_both { |
|
3639
|
|
|
|
|
|
|
barf "Usage: where_both(\$pdl, \$mask)\n" if @_ != 2; |
|
3640
|
|
|
|
|
|
|
my ($arr, $mask) = @_; # $mask has 0==false, 1==true |
|
3641
|
|
|
|
|
|
|
my $arr_flat = $arr->flat; |
|
3642
|
|
|
|
|
|
|
map $arr_flat->index1d($_), PDL::which_both($mask); |
|
3643
|
|
|
|
|
|
|
} |
|
3644
|
|
|
|
|
|
|
*where_both = \&PDL::where_both; |
|
3645
|
|
|
|
|
|
|
EOD |
|
3646
|
|
|
|
|
|
|
|
|
3647
|
|
|
|
|
|
|
pp_add_exported("", 'whereND whereND_both'); |
|
3648
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
3649
|
|
|
|
|
|
|
=head2 whereND |
|
3650
|
|
|
|
|
|
|
|
|
3651
|
|
|
|
|
|
|
=for ref |
|
3652
|
|
|
|
|
|
|
|
|
3653
|
|
|
|
|
|
|
C with support for ND masks and broadcasting |
|
3654
|
|
|
|
|
|
|
|
|
3655
|
|
|
|
|
|
|
C accepts one or more data ndarrays and a |
|
3656
|
|
|
|
|
|
|
mask ndarray. It returns a list of output ndarrays, |
|
3657
|
|
|
|
|
|
|
corresponding to the input data ndarrays. The values |
|
3658
|
|
|
|
|
|
|
are drawn from locations where the mask is nonzero. |
|
3659
|
|
|
|
|
|
|
|
|
3660
|
|
|
|
|
|
|
C differs from C in that the mask |
|
3661
|
|
|
|
|
|
|
dimensionality is preserved which allows for |
|
3662
|
|
|
|
|
|
|
proper broadcasting of the selection operation over |
|
3663
|
|
|
|
|
|
|
higher dimensions. |
|
3664
|
|
|
|
|
|
|
|
|
3665
|
|
|
|
|
|
|
As with C the output PDLs are still connected |
|
3666
|
|
|
|
|
|
|
to the original data PDLs, for the purpose of dataflow. |
|
3667
|
|
|
|
|
|
|
|
|
3668
|
|
|
|
|
|
|
=for usage |
|
3669
|
|
|
|
|
|
|
|
|
3670
|
|
|
|
|
|
|
$sdata = whereND $data, $mask |
|
3671
|
|
|
|
|
|
|
($s1, $s2, ..., $sn) = whereND $d1, $d2, ..., $dn, $mask |
|
3672
|
|
|
|
|
|
|
|
|
3673
|
|
|
|
|
|
|
where |
|
3674
|
|
|
|
|
|
|
|
|
3675
|
|
|
|
|
|
|
$data is M dimensional |
|
3676
|
|
|
|
|
|
|
$mask is N < M dimensional |
|
3677
|
|
|
|
|
|
|
dims($data) 1..N == dims($mask) 1..N |
|
3678
|
|
|
|
|
|
|
with broadcasting over N+1 to M dimensions |
|
3679
|
|
|
|
|
|
|
|
|
3680
|
|
|
|
|
|
|
=for example |
|
3681
|
|
|
|
|
|
|
|
|
3682
|
|
|
|
|
|
|
$data = sequence(4,3,2); # example data array |
|
3683
|
|
|
|
|
|
|
$mask4 = (random(4)>0.5); # example 1-D mask array, has $n4 true values |
|
3684
|
|
|
|
|
|
|
$mask43 = (random(4,3)>0.5); # example 2-D mask array, has $n43 true values |
|
3685
|
|
|
|
|
|
|
$sdat4 = whereND $data, $mask4; # $sdat4 is a [$n4,3,2] pdl |
|
3686
|
|
|
|
|
|
|
$sdat43 = whereND $data, $mask43; # $sdat43 is a [$n43,2] pdl |
|
3687
|
|
|
|
|
|
|
|
|
3688
|
|
|
|
|
|
|
Just as with C, you can use the returned value in an |
|
3689
|
|
|
|
|
|
|
assignment. That means that both of these examples are valid: |
|
3690
|
|
|
|
|
|
|
|
|
3691
|
|
|
|
|
|
|
# Used to create a new slice stored in $sdat4: |
|
3692
|
|
|
|
|
|
|
$sdat4 = $data->whereND($mask4); |
|
3693
|
|
|
|
|
|
|
$sdat4 .= 0; |
|
3694
|
|
|
|
|
|
|
# Used in lvalue context: |
|
3695
|
|
|
|
|
|
|
$data->whereND($mask4) .= 0; |
|
3696
|
|
|
|
|
|
|
|
|
3697
|
|
|
|
|
|
|
SEE ALSO: |
|
3698
|
|
|
|
|
|
|
|
|
3699
|
|
|
|
|
|
|
L returns N-D indices into a multidimensional PDL, from a mask. |
|
3700
|
|
|
|
|
|
|
|
|
3701
|
|
|
|
|
|
|
=cut |
|
3702
|
|
|
|
|
|
|
|
|
3703
|
|
|
|
|
|
|
sub PDL::whereND :lvalue { |
|
3704
|
|
|
|
|
|
|
barf "Usage: whereND( \$pdl1, ..., \$pdlN, \$mask )\n" if @_ == 1; |
|
3705
|
|
|
|
|
|
|
my $mask = pop @_; # $mask has 0==false, 1==true |
|
3706
|
|
|
|
|
|
|
my @to_return; |
|
3707
|
|
|
|
|
|
|
my $n = PDL::sum($mask); |
|
3708
|
|
|
|
|
|
|
my $maskndims = $mask->ndims; |
|
3709
|
|
|
|
|
|
|
foreach my $arr (@_) { |
|
3710
|
|
|
|
|
|
|
# count the number of dims in $mask and $arr |
|
3711
|
|
|
|
|
|
|
# $mask = a b c d e f..... |
|
3712
|
|
|
|
|
|
|
my @idims = dims($arr); |
|
3713
|
|
|
|
|
|
|
splice @idims, 0, $maskndims; # pop off the number of dims in $mask |
|
3714
|
|
|
|
|
|
|
if (!$n or $arr->isempty) { |
|
3715
|
|
|
|
|
|
|
push @to_return, PDL->zeroes($arr->type, $n, @idims); |
|
3716
|
|
|
|
|
|
|
next; |
|
3717
|
|
|
|
|
|
|
} |
|
3718
|
|
|
|
|
|
|
my $sub_i = $mask * ones($arr); |
|
3719
|
|
|
|
|
|
|
my $where_sub_i = PDL::where($arr, $sub_i); |
|
3720
|
|
|
|
|
|
|
my $ndim = 0; |
|
3721
|
|
|
|
|
|
|
foreach my $id ($n, @idims[0..($#idims-1)]) { |
|
3722
|
|
|
|
|
|
|
$where_sub_i = $where_sub_i->splitdim($ndim++,$id) if $n>0; |
|
3723
|
|
|
|
|
|
|
} |
|
3724
|
|
|
|
|
|
|
push @to_return, $where_sub_i; |
|
3725
|
|
|
|
|
|
|
} |
|
3726
|
|
|
|
|
|
|
return (@to_return == 1) ? $to_return[0] : @to_return; |
|
3727
|
|
|
|
|
|
|
} |
|
3728
|
|
|
|
|
|
|
*whereND = \&PDL::whereND; |
|
3729
|
|
|
|
|
|
|
|
|
3730
|
|
|
|
|
|
|
=head2 whereND_both |
|
3731
|
|
|
|
|
|
|
|
|
3732
|
|
|
|
|
|
|
=for ref |
|
3733
|
|
|
|
|
|
|
|
|
3734
|
|
|
|
|
|
|
C with support for ND masks and broadcasting |
|
3735
|
|
|
|
|
|
|
|
|
3736
|
|
|
|
|
|
|
This works like L, but data-flowing slices |
|
3737
|
|
|
|
|
|
|
rather than index-sets are returned. |
|
3738
|
|
|
|
|
|
|
|
|
3739
|
|
|
|
|
|
|
C differs from C in that the mask |
|
3740
|
|
|
|
|
|
|
dimensionality is preserved which allows for |
|
3741
|
|
|
|
|
|
|
proper broadcasting of the selection operation over |
|
3742
|
|
|
|
|
|
|
higher dimensions. |
|
3743
|
|
|
|
|
|
|
|
|
3744
|
|
|
|
|
|
|
As with C the output PDLs are still connected |
|
3745
|
|
|
|
|
|
|
to the original data PDLs, for the purpose of dataflow. |
|
3746
|
|
|
|
|
|
|
|
|
3747
|
|
|
|
|
|
|
=for usage |
|
3748
|
|
|
|
|
|
|
|
|
3749
|
|
|
|
|
|
|
($match_vals, $non_match_vals) = whereND_both($pdl, $mask); |
|
3750
|
|
|
|
|
|
|
|
|
3751
|
|
|
|
|
|
|
=cut |
|
3752
|
|
|
|
|
|
|
|
|
3753
|
|
|
|
|
|
|
sub PDL::whereND_both :lvalue { |
|
3754
|
|
|
|
|
|
|
barf "Usage: whereND_both(\$pdl, \$mask)\n" if @_ != 2; |
|
3755
|
|
|
|
|
|
|
my ($arr, $mask) = @_; # $mask has 0==false, 1==true |
|
3756
|
|
|
|
|
|
|
map $arr->indexND($_), PDL::whichND_both($mask); |
|
3757
|
|
|
|
|
|
|
} |
|
3758
|
|
|
|
|
|
|
*whereND_both = \&PDL::whereND_both; |
|
3759
|
|
|
|
|
|
|
EOD |
|
3760
|
|
|
|
|
|
|
|
|
3761
|
|
|
|
|
|
|
pp_add_exported("", 'whichND whichND_both'); |
|
3762
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
3763
|
|
|
|
|
|
|
=head2 whichND |
|
3764
|
|
|
|
|
|
|
|
|
3765
|
|
|
|
|
|
|
=for ref |
|
3766
|
|
|
|
|
|
|
|
|
3767
|
|
|
|
|
|
|
Return the coordinates of non-zero values in a mask. |
|
3768
|
|
|
|
|
|
|
|
|
3769
|
|
|
|
|
|
|
=for usage |
|
3770
|
|
|
|
|
|
|
|
|
3771
|
|
|
|
|
|
|
WhichND returns the N-dimensional coordinates of each nonzero value in |
|
3772
|
|
|
|
|
|
|
a mask PDL with any number of dimensions. The returned values arrive |
|
3773
|
|
|
|
|
|
|
as an array-of-vectors suitable for use in |
|
3774
|
|
|
|
|
|
|
L or L. |
|
3775
|
|
|
|
|
|
|
|
|
3776
|
|
|
|
|
|
|
$coords = whichND($mask); |
|
3777
|
|
|
|
|
|
|
|
|
3778
|
|
|
|
|
|
|
returns a PDL containing the coordinates of the elements that are non-zero |
|
3779
|
|
|
|
|
|
|
in C<$mask>, suitable for use in L. The 0th dimension contains the |
|
3780
|
|
|
|
|
|
|
full coordinate listing of each point; the 1st dimension lists all the points. |
|
3781
|
|
|
|
|
|
|
For example, if $mask has rank 4 and 100 matching elements, then $coords has |
|
3782
|
|
|
|
|
|
|
dimension 4x100. |
|
3783
|
|
|
|
|
|
|
|
|
3784
|
|
|
|
|
|
|
If no such elements exist, then whichND returns a structured empty PDL: |
|
3785
|
|
|
|
|
|
|
an Nx0 PDL that contains no values (but matches, broadcasting-wise, with |
|
3786
|
|
|
|
|
|
|
the vectors that would be produced if such elements existed). |
|
3787
|
|
|
|
|
|
|
|
|
3788
|
|
|
|
|
|
|
DEPRECATED BEHAVIOR IN LIST CONTEXT: |
|
3789
|
|
|
|
|
|
|
|
|
3790
|
|
|
|
|
|
|
whichND once delivered different values in list context than in scalar |
|
3791
|
|
|
|
|
|
|
context, for historical reasons. In list context, it returned the |
|
3792
|
|
|
|
|
|
|
coordinates transposed, as a collection of 1-PDLs (one per dimension) |
|
3793
|
|
|
|
|
|
|
in a list. This usage is deprecated in PDL 2.4.10, and will cause a |
|
3794
|
|
|
|
|
|
|
warning to be issued every time it is encountered. To avoid the |
|
3795
|
|
|
|
|
|
|
warning, you can set the global variable "$PDL::whichND" to 's' to |
|
3796
|
|
|
|
|
|
|
get scalar behavior in all contexts, or to 'l' to get list behavior in |
|
3797
|
|
|
|
|
|
|
list context. |
|
3798
|
|
|
|
|
|
|
|
|
3799
|
|
|
|
|
|
|
In later versions of PDL, the deprecated behavior will disappear. Deprecated |
|
3800
|
|
|
|
|
|
|
list context whichND expressions can be replaced with: |
|
3801
|
|
|
|
|
|
|
|
|
3802
|
|
|
|
|
|
|
@list = $x->whichND->mv(0,-1)->dog; |
|
3803
|
|
|
|
|
|
|
|
|
3804
|
|
|
|
|
|
|
SEE ALSO: |
|
3805
|
|
|
|
|
|
|
|
|
3806
|
|
|
|
|
|
|
L finds coordinates of nonzero values in a 1-D mask. |
|
3807
|
|
|
|
|
|
|
|
|
3808
|
|
|
|
|
|
|
L extracts values from a data PDL that are associated |
|
3809
|
|
|
|
|
|
|
with nonzero values in a mask PDL. |
|
3810
|
|
|
|
|
|
|
|
|
3811
|
|
|
|
|
|
|
L can be fed the coordinates to return the values. |
|
3812
|
|
|
|
|
|
|
|
|
3813
|
|
|
|
|
|
|
=for example |
|
3814
|
|
|
|
|
|
|
|
|
3815
|
|
|
|
|
|
|
pdl> $s=sequence(10,10,3,4) |
|
3816
|
|
|
|
|
|
|
pdl> ($x, $y, $z, $w)=whichND($s == 203); p $x, $y, $z, $w |
|
3817
|
|
|
|
|
|
|
[3] [0] [2] [0] |
|
3818
|
|
|
|
|
|
|
pdl> print $s->at(list(cat($x,$y,$z,$w))) |
|
3819
|
|
|
|
|
|
|
203 |
|
3820
|
|
|
|
|
|
|
|
|
3821
|
|
|
|
|
|
|
=cut |
|
3822
|
|
|
|
|
|
|
|
|
3823
|
|
|
|
|
|
|
sub _one2nd { |
|
3824
|
|
|
|
|
|
|
my ($mask, $ind) = @_; |
|
3825
|
|
|
|
|
|
|
my $ndims = my @mdims = $mask->dims; |
|
3826
|
|
|
|
|
|
|
# In the empty case, explicitly return the correct type of structured empty |
|
3827
|
|
|
|
|
|
|
return PDL->new_from_specification(indx, $ndims, 0) if !$ind->nelem; |
|
3828
|
|
|
|
|
|
|
my $mult = ones(indx, $ndims); |
|
3829
|
|
|
|
|
|
|
$mult->index($_+1) .= $mult->index($_) * $mdims[$_] for 0..$#mdims-1; |
|
3830
|
|
|
|
|
|
|
for my $i (0..$#mdims) { |
|
3831
|
|
|
|
|
|
|
my $s = $ind->index($i); |
|
3832
|
|
|
|
|
|
|
$s /= $mult->index($i); |
|
3833
|
|
|
|
|
|
|
$s %= $mdims[$i]; |
|
3834
|
|
|
|
|
|
|
} |
|
3835
|
|
|
|
|
|
|
$ind; |
|
3836
|
|
|
|
|
|
|
} |
|
3837
|
|
|
|
|
|
|
|
|
3838
|
|
|
|
|
|
|
*whichND = \&PDL::whichND; |
|
3839
|
|
|
|
|
|
|
sub PDL::whichND { |
|
3840
|
|
|
|
|
|
|
my $mask = PDL->topdl(shift); |
|
3841
|
|
|
|
|
|
|
|
|
3842
|
|
|
|
|
|
|
# List context: generate a perl list by dimension |
|
3843
|
|
|
|
|
|
|
if(wantarray) { |
|
3844
|
|
|
|
|
|
|
if(!defined($PDL::whichND)) { |
|
3845
|
|
|
|
|
|
|
printf STDERR "whichND: WARNING - list context deprecated. Set \$PDL::whichND. Details in pod."; |
|
3846
|
|
|
|
|
|
|
} elsif($PDL::whichND =~ m/l/i) { |
|
3847
|
|
|
|
|
|
|
# old list context enabled by setting $PDL::whichND to 'l' |
|
3848
|
|
|
|
|
|
|
return $mask->one2nd($mask->flat->which); |
|
3849
|
|
|
|
|
|
|
} |
|
3850
|
|
|
|
|
|
|
# if $PDL::whichND does not contain 'l' or 'L', fall through to scalar context |
|
3851
|
|
|
|
|
|
|
} |
|
3852
|
|
|
|
|
|
|
|
|
3853
|
|
|
|
|
|
|
# Scalar context: generate an N-D index ndarray |
|
3854
|
|
|
|
|
|
|
my $ndims = $mask->getndims; |
|
3855
|
|
|
|
|
|
|
return PDL->new_from_specification(indx,$ndims,0) if !$mask->nelem; |
|
3856
|
|
|
|
|
|
|
return $mask ? pdl(indx,0) : PDL->new_from_specification(indx,0) if !$ndims; |
|
3857
|
|
|
|
|
|
|
_one2nd($mask, $mask->flat->which->dummy(0,$ndims)->sever); |
|
3858
|
|
|
|
|
|
|
} |
|
3859
|
|
|
|
|
|
|
|
|
3860
|
|
|
|
|
|
|
=head2 whichND_both |
|
3861
|
|
|
|
|
|
|
|
|
3862
|
|
|
|
|
|
|
=for ref |
|
3863
|
|
|
|
|
|
|
|
|
3864
|
|
|
|
|
|
|
Return the coordinates of non-zero values in a mask. |
|
3865
|
|
|
|
|
|
|
|
|
3866
|
|
|
|
|
|
|
=for usage |
|
3867
|
|
|
|
|
|
|
|
|
3868
|
|
|
|
|
|
|
Like L, but returns the N-dimensional coordinates (like |
|
3869
|
|
|
|
|
|
|
L) of the nonzero, zero values in the mask PDL. The |
|
3870
|
|
|
|
|
|
|
returned values arrive as an array-of-vectors suitable for use in |
|
3871
|
|
|
|
|
|
|
L or L. |
|
3872
|
|
|
|
|
|
|
Added in 2.099. |
|
3873
|
|
|
|
|
|
|
|
|
3874
|
|
|
|
|
|
|
($nonzero_coords, $zero_coords) = whichND_both($mask); |
|
3875
|
|
|
|
|
|
|
|
|
3876
|
|
|
|
|
|
|
SEE ALSO: |
|
3877
|
|
|
|
|
|
|
|
|
3878
|
|
|
|
|
|
|
L finds coordinates of nonzero values in a 1-D mask. |
|
3879
|
|
|
|
|
|
|
|
|
3880
|
|
|
|
|
|
|
L extracts values from a data PDL that are associated |
|
3881
|
|
|
|
|
|
|
with nonzero values in a mask PDL. |
|
3882
|
|
|
|
|
|
|
|
|
3883
|
|
|
|
|
|
|
L can be fed the coordinates to return the values. |
|
3884
|
|
|
|
|
|
|
|
|
3885
|
|
|
|
|
|
|
=for example |
|
3886
|
|
|
|
|
|
|
|
|
3887
|
|
|
|
|
|
|
pdl> $s=sequence(10,10,3,4) |
|
3888
|
|
|
|
|
|
|
pdl> ($x, $y, $z, $w)=whichND($s == 203); p $x, $y, $z, $w |
|
3889
|
|
|
|
|
|
|
[3] [0] [2] [0] |
|
3890
|
|
|
|
|
|
|
pdl> print $s->at(list(cat($x,$y,$z,$w))) |
|
3891
|
|
|
|
|
|
|
203 |
|
3892
|
|
|
|
|
|
|
|
|
3893
|
|
|
|
|
|
|
=cut |
|
3894
|
|
|
|
|
|
|
|
|
3895
|
|
|
|
|
|
|
*whichND_both = \&PDL::whichND_both; |
|
3896
|
|
|
|
|
|
|
sub PDL::whichND_both { |
|
3897
|
|
|
|
|
|
|
my $mask = PDL->topdl(shift); |
|
3898
|
|
|
|
|
|
|
return ((PDL->new_from_specification(indx,$mask->ndims,0))x2) if !$mask->nelem; |
|
3899
|
|
|
|
|
|
|
my $ndims = $mask->getndims; |
|
3900
|
|
|
|
|
|
|
if (!$ndims) { |
|
3901
|
|
|
|
|
|
|
my ($t, $f) = (pdl(indx,0), PDL->new_from_specification(indx,0)); |
|
3902
|
|
|
|
|
|
|
return $mask ? ($t,$f) : ($f,$t); |
|
3903
|
|
|
|
|
|
|
} |
|
3904
|
|
|
|
|
|
|
map _one2nd($mask, $_->dummy(0,$ndims)->sever), $mask->flat->which_both; |
|
3905
|
|
|
|
|
|
|
} |
|
3906
|
|
|
|
|
|
|
EOD |
|
3907
|
|
|
|
|
|
|
|
|
3908
|
|
|
|
|
|
|
# |
|
3909
|
|
|
|
|
|
|
# Set operations suited for manipulation of the operations above. |
|
3910
|
|
|
|
|
|
|
# |
|
3911
|
|
|
|
|
|
|
|
|
3912
|
|
|
|
|
|
|
pp_add_exported("", 'setops'); |
|
3913
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
3914
|
|
|
|
|
|
|
=head2 setops |
|
3915
|
|
|
|
|
|
|
|
|
3916
|
|
|
|
|
|
|
=for ref |
|
3917
|
|
|
|
|
|
|
|
|
3918
|
|
|
|
|
|
|
Implements simple set operations like union and intersection |
|
3919
|
|
|
|
|
|
|
|
|
3920
|
|
|
|
|
|
|
=for usage |
|
3921
|
|
|
|
|
|
|
|
|
3922
|
|
|
|
|
|
|
Usage: $set = setops($x, , $y); |
|
3923
|
|
|
|
|
|
|
|
|
3924
|
|
|
|
|
|
|
The operator can be C, C or C. This is then applied |
|
3925
|
|
|
|
|
|
|
to C<$x> viewed as a set and C<$y> viewed as a set. Set theory says |
|
3926
|
|
|
|
|
|
|
that a set may not have two or more identical elements, but setops |
|
3927
|
|
|
|
|
|
|
takes care of this for you, so C<$x=pdl(1,1,2)> is OK. The functioning |
|
3928
|
|
|
|
|
|
|
is as follows: |
|
3929
|
|
|
|
|
|
|
|
|
3930
|
|
|
|
|
|
|
=over |
|
3931
|
|
|
|
|
|
|
|
|
3932
|
|
|
|
|
|
|
=item C |
|
3933
|
|
|
|
|
|
|
|
|
3934
|
|
|
|
|
|
|
The resulting vector will contain the elements that are either in C<$x> |
|
3935
|
|
|
|
|
|
|
I in C<$y> or both. This is the union in set operation terms |
|
3936
|
|
|
|
|
|
|
|
|
3937
|
|
|
|
|
|
|
=item C |
|
3938
|
|
|
|
|
|
|
|
|
3939
|
|
|
|
|
|
|
The resulting vector will contain the elements that are either in C<$x> |
|
3940
|
|
|
|
|
|
|
or C<$y>, but not in both. This is |
|
3941
|
|
|
|
|
|
|
|
|
3942
|
|
|
|
|
|
|
Union($x, $y) - Intersection($x, $y) |
|
3943
|
|
|
|
|
|
|
|
|
3944
|
|
|
|
|
|
|
in set operation terms. |
|
3945
|
|
|
|
|
|
|
|
|
3946
|
|
|
|
|
|
|
=item C |
|
3947
|
|
|
|
|
|
|
|
|
3948
|
|
|
|
|
|
|
The resulting vector will contain the intersection of C<$x> and C<$y>, so |
|
3949
|
|
|
|
|
|
|
the elements that are in both C<$x> and C<$y>. Note that for convenience |
|
3950
|
|
|
|
|
|
|
this operation is also aliased to L. |
|
3951
|
|
|
|
|
|
|
|
|
3952
|
|
|
|
|
|
|
=back |
|
3953
|
|
|
|
|
|
|
|
|
3954
|
|
|
|
|
|
|
It should be emphasized that these routines are used when one or both of |
|
3955
|
|
|
|
|
|
|
the sets C<$x>, C<$y> are hard to calculate or that you get from a separate |
|
3956
|
|
|
|
|
|
|
subroutine. |
|
3957
|
|
|
|
|
|
|
|
|
3958
|
|
|
|
|
|
|
Finally IDL users might be familiar with Craig Markwardt's C |
|
3959
|
|
|
|
|
|
|
routine which has inspired this routine although it was written independently |
|
3960
|
|
|
|
|
|
|
However the present routine has a few less options (but see the examples) |
|
3961
|
|
|
|
|
|
|
|
|
3962
|
|
|
|
|
|
|
=for example |
|
3963
|
|
|
|
|
|
|
|
|
3964
|
|
|
|
|
|
|
You will very often use these functions on an index vector, so that is |
|
3965
|
|
|
|
|
|
|
what we will show here. We will in fact something slightly silly. First |
|
3966
|
|
|
|
|
|
|
we will find all squares that are also cubes below 10000. |
|
3967
|
|
|
|
|
|
|
|
|
3968
|
|
|
|
|
|
|
Create a sequence vector: |
|
3969
|
|
|
|
|
|
|
|
|
3970
|
|
|
|
|
|
|
pdl> $x = sequence(10000) |
|
3971
|
|
|
|
|
|
|
|
|
3972
|
|
|
|
|
|
|
Find all odd and even elements: |
|
3973
|
|
|
|
|
|
|
|
|
3974
|
|
|
|
|
|
|
pdl> ($even, $odd) = which_both( ($x % 2) == 0) |
|
3975
|
|
|
|
|
|
|
|
|
3976
|
|
|
|
|
|
|
Find all squares |
|
3977
|
|
|
|
|
|
|
|
|
3978
|
|
|
|
|
|
|
pdl> $squares= which(ceil(sqrt($x)) == floor(sqrt($x))) |
|
3979
|
|
|
|
|
|
|
|
|
3980
|
|
|
|
|
|
|
Find all cubes (being careful with roundoff error!) |
|
3981
|
|
|
|
|
|
|
|
|
3982
|
|
|
|
|
|
|
pdl> $cubes= which(ceil($x**(1.0/3.0)) == floor($x**(1.0/3.0)+1e-6)) |
|
3983
|
|
|
|
|
|
|
|
|
3984
|
|
|
|
|
|
|
Then find all squares that are cubes: |
|
3985
|
|
|
|
|
|
|
|
|
3986
|
|
|
|
|
|
|
pdl> $both = setops($squares, 'AND', $cubes) |
|
3987
|
|
|
|
|
|
|
|
|
3988
|
|
|
|
|
|
|
And print these (assumes that C is loaded!) |
|
3989
|
|
|
|
|
|
|
|
|
3990
|
|
|
|
|
|
|
pdl> p $x($both) |
|
3991
|
|
|
|
|
|
|
[0 1 64 729 4096] |
|
3992
|
|
|
|
|
|
|
|
|
3993
|
|
|
|
|
|
|
Then find all numbers that are either cubes or squares, but not both: |
|
3994
|
|
|
|
|
|
|
|
|
3995
|
|
|
|
|
|
|
pdl> $cube_xor_square = setops($squares, 'XOR', $cubes) |
|
3996
|
|
|
|
|
|
|
|
|
3997
|
|
|
|
|
|
|
pdl> p $cube_xor_square->nelem() |
|
3998
|
|
|
|
|
|
|
112 |
|
3999
|
|
|
|
|
|
|
|
|
4000
|
|
|
|
|
|
|
So there are a total of 112 of these! |
|
4001
|
|
|
|
|
|
|
|
|
4002
|
|
|
|
|
|
|
Finally find all odd squares: |
|
4003
|
|
|
|
|
|
|
|
|
4004
|
|
|
|
|
|
|
pdl> $odd_squares = setops($squares, 'AND', $odd) |
|
4005
|
|
|
|
|
|
|
|
|
4006
|
|
|
|
|
|
|
|
|
4007
|
|
|
|
|
|
|
Another common occurrence is to want to get all objects that are |
|
4008
|
|
|
|
|
|
|
in C<$x> and in the complement of C<$y>. But it is almost always best |
|
4009
|
|
|
|
|
|
|
to create the complement explicitly since the universe that both are |
|
4010
|
|
|
|
|
|
|
taken from is not known. Thus use L if possible |
|
4011
|
|
|
|
|
|
|
to keep track of complements. |
|
4012
|
|
|
|
|
|
|
|
|
4013
|
|
|
|
|
|
|
If this is impossible the best approach is to make a temporary: |
|
4014
|
|
|
|
|
|
|
|
|
4015
|
|
|
|
|
|
|
This creates an index vector the size of the universe of the sets and |
|
4016
|
|
|
|
|
|
|
set all elements in C<$y> to 0 |
|
4017
|
|
|
|
|
|
|
|
|
4018
|
|
|
|
|
|
|
pdl> $tmp = ones($n_universe); $tmp($y) .= 0; |
|
4019
|
|
|
|
|
|
|
|
|
4020
|
|
|
|
|
|
|
This then finds the complement of C<$y> |
|
4021
|
|
|
|
|
|
|
|
|
4022
|
|
|
|
|
|
|
pdl> $C_b = which($tmp == 1); |
|
4023
|
|
|
|
|
|
|
|
|
4024
|
|
|
|
|
|
|
and this does the final selection: |
|
4025
|
|
|
|
|
|
|
|
|
4026
|
|
|
|
|
|
|
pdl> $set = setops($x, 'AND', $C_b) |
|
4027
|
|
|
|
|
|
|
|
|
4028
|
|
|
|
|
|
|
=cut |
|
4029
|
|
|
|
|
|
|
|
|
4030
|
|
|
|
|
|
|
*setops = \&PDL::setops; |
|
4031
|
|
|
|
|
|
|
|
|
4032
|
|
|
|
|
|
|
sub PDL::setops { |
|
4033
|
|
|
|
|
|
|
|
|
4034
|
|
|
|
|
|
|
my ($x, $op, $y)=@_; |
|
4035
|
|
|
|
|
|
|
|
|
4036
|
|
|
|
|
|
|
# Check that $x and $y are 1D. |
|
4037
|
|
|
|
|
|
|
if ($x->ndims() > 1 || $y->ndims() > 1) { |
|
4038
|
|
|
|
|
|
|
warn 'setops: $x and $y must be 1D - flattening them!'."\n"; |
|
4039
|
|
|
|
|
|
|
$x = $x->flat; |
|
4040
|
|
|
|
|
|
|
$y = $y->flat; |
|
4041
|
|
|
|
|
|
|
} |
|
4042
|
|
|
|
|
|
|
|
|
4043
|
|
|
|
|
|
|
#Make sure there are no duplicate elements. |
|
4044
|
|
|
|
|
|
|
$x=$x->uniq; |
|
4045
|
|
|
|
|
|
|
$y=$y->uniq; |
|
4046
|
|
|
|
|
|
|
|
|
4047
|
|
|
|
|
|
|
my $result; |
|
4048
|
|
|
|
|
|
|
|
|
4049
|
|
|
|
|
|
|
if ($op eq 'OR') { |
|
4050
|
|
|
|
|
|
|
# Easy... |
|
4051
|
|
|
|
|
|
|
$result = uniq(append($x, $y)); |
|
4052
|
|
|
|
|
|
|
} elsif ($op eq 'XOR') { |
|
4053
|
|
|
|
|
|
|
# Make ordered list of set union. |
|
4054
|
|
|
|
|
|
|
my $union = append($x, $y)->qsort; |
|
4055
|
|
|
|
|
|
|
# Index lists. |
|
4056
|
|
|
|
|
|
|
my $s1=zeroes(byte, $union->nelem()); |
|
4057
|
|
|
|
|
|
|
my $s2=zeroes(byte, $union->nelem()); |
|
4058
|
|
|
|
|
|
|
|
|
4059
|
|
|
|
|
|
|
# Find indices which are duplicated - these are to be excluded |
|
4060
|
|
|
|
|
|
|
# |
|
4061
|
|
|
|
|
|
|
# We do this by comparing x with x shifted each way. |
|
4062
|
|
|
|
|
|
|
my $i1 = which($union != rotate($union, 1)); |
|
4063
|
|
|
|
|
|
|
my $i2 = which($union != rotate($union, -1)); |
|
4064
|
|
|
|
|
|
|
# |
|
4065
|
|
|
|
|
|
|
# We then mark/mask these in the s1 and s2 arrays to indicate which ones |
|
4066
|
|
|
|
|
|
|
# are not equal to their neighbours. |
|
4067
|
|
|
|
|
|
|
# |
|
4068
|
|
|
|
|
|
|
my $ts; |
|
4069
|
|
|
|
|
|
|
($ts = $s1->index($i1)) .= byte(1) if $i1->nelem() > 0; |
|
4070
|
|
|
|
|
|
|
($ts = $s2->index($i2)) .= byte(1) if $i2->nelem() > 0; |
|
4071
|
|
|
|
|
|
|
|
|
4072
|
|
|
|
|
|
|
my $inds=which($s1 == $s2); |
|
4073
|
|
|
|
|
|
|
|
|
4074
|
|
|
|
|
|
|
if ($inds->nelem() > 0) { |
|
4075
|
|
|
|
|
|
|
return $union->index($inds); |
|
4076
|
|
|
|
|
|
|
} else { |
|
4077
|
|
|
|
|
|
|
return $inds; |
|
4078
|
|
|
|
|
|
|
} |
|
4079
|
|
|
|
|
|
|
|
|
4080
|
|
|
|
|
|
|
} elsif ($op eq 'AND') { |
|
4081
|
|
|
|
|
|
|
# The intersection of the arrays. |
|
4082
|
|
|
|
|
|
|
return $x if $x->isempty; |
|
4083
|
|
|
|
|
|
|
return $y if $y->isempty; |
|
4084
|
|
|
|
|
|
|
# Make ordered list of set union. |
|
4085
|
|
|
|
|
|
|
my $union = append($x, $y)->qsort; |
|
4086
|
|
|
|
|
|
|
return $union->where($union == rotate($union, -1))->uniq; |
|
4087
|
|
|
|
|
|
|
} else { |
|
4088
|
|
|
|
|
|
|
print "The operation $op is not known!"; |
|
4089
|
|
|
|
|
|
|
return -1; |
|
4090
|
|
|
|
|
|
|
} |
|
4091
|
|
|
|
|
|
|
|
|
4092
|
|
|
|
|
|
|
} |
|
4093
|
|
|
|
|
|
|
EOD |
|
4094
|
|
|
|
|
|
|
|
|
4095
|
|
|
|
|
|
|
pp_add_exported("", 'intersect'); |
|
4096
|
|
|
|
|
|
|
pp_addpm(<<'EOD'); |
|
4097
|
|
|
|
|
|
|
=head2 intersect |
|
4098
|
|
|
|
|
|
|
|
|
4099
|
|
|
|
|
|
|
=for ref |
|
4100
|
|
|
|
|
|
|
|
|
4101
|
|
|
|
|
|
|
Calculate the intersection of two ndarrays |
|
4102
|
|
|
|
|
|
|
|
|
4103
|
|
|
|
|
|
|
=for usage |
|
4104
|
|
|
|
|
|
|
|
|
4105
|
|
|
|
|
|
|
Usage: $set = intersect($x, $y); |
|
4106
|
|
|
|
|
|
|
|
|
4107
|
|
|
|
|
|
|
This routine is merely a simple interface to L. See |
|
4108
|
|
|
|
|
|
|
that for more information |
|
4109
|
|
|
|
|
|
|
|
|
4110
|
|
|
|
|
|
|
=for example |
|
4111
|
|
|
|
|
|
|
|
|
4112
|
|
|
|
|
|
|
Find all numbers less that 100 that are of the form 2*y and 3*x |
|
4113
|
|
|
|
|
|
|
|
|
4114
|
|
|
|
|
|
|
pdl> $x=sequence(100) |
|
4115
|
|
|
|
|
|
|
pdl> $factor2 = which( ($x % 2) == 0) |
|
4116
|
|
|
|
|
|
|
pdl> $factor3 = which( ($x % 3) == 0) |
|
4117
|
|
|
|
|
|
|
pdl> $ii=intersect($factor2, $factor3) |
|
4118
|
|
|
|
|
|
|
pdl> p $x($ii) |
|
4119
|
|
|
|
|
|
|
[0 6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96] |
|
4120
|
|
|
|
|
|
|
|
|
4121
|
|
|
|
|
|
|
=cut |
|
4122
|
|
|
|
|
|
|
|
|
4123
|
|
|
|
|
|
|
*intersect = \&PDL::intersect; |
|
4124
|
|
|
|
|
|
|
|
|
4125
|
|
|
|
|
|
|
sub PDL::intersect { setops($_[0], 'AND', $_[1]) } |
|
4126
|
|
|
|
|
|
|
EOD |
|
4127
|
|
|
|
|
|
|
|
|
4128
|
|
|
|
|
|
|
pp_add_macros( |
|
4129
|
|
|
|
|
|
|
PCHDF => sub {my ($k, $x, $s, $out) = @_; ' |
|
4130
|
|
|
|
|
|
|
/* PDL version: K, X, S are var names, 4th param output */ |
|
4131
|
|
|
|
|
|
|
/* ***PURPOSE Computes divided differences for DPCHCE and DPCHSP */ |
|
4132
|
|
|
|
|
|
|
/* DPCHDF: DPCHIP Finite Difference Formula */ |
|
4133
|
|
|
|
|
|
|
/* Uses a divided difference formulation to compute a K-point approx- */ |
|
4134
|
|
|
|
|
|
|
/* imation to the derivative at X(K) based on the data in X and S. */ |
|
4135
|
|
|
|
|
|
|
/* Called by DPCHCE and DPCHSP to compute 3- and 4-point boundary */ |
|
4136
|
|
|
|
|
|
|
/* derivative approximations. */ |
|
4137
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */ |
|
4138
|
|
|
|
|
|
|
/* On input: */ |
|
4139
|
|
|
|
|
|
|
/* K is the order of the desired derivative approximation. */ |
|
4140
|
|
|
|
|
|
|
/* K must be at least 3 (error return if not). */ |
|
4141
|
|
|
|
|
|
|
/* X contains the K values of the independent variable. */ |
|
4142
|
|
|
|
|
|
|
/* X need not be ordered, but the values **MUST** be */ |
|
4143
|
|
|
|
|
|
|
/* distinct. (Not checked here.) */ |
|
4144
|
|
|
|
|
|
|
/* S contains the associated slope values: */ |
|
4145
|
|
|
|
|
|
|
/* S(I) = (F(I+1)-F(I))/(X(I+1)-X(I)), I=1(1)K-1. */ |
|
4146
|
|
|
|
|
|
|
/* (Note that S need only be of length K-1.) */ |
|
4147
|
|
|
|
|
|
|
/* On return: */ |
|
4148
|
|
|
|
|
|
|
/* S will be destroyed. */ |
|
4149
|
|
|
|
|
|
|
/* IERR will be set to -1 if K.LT.2 . */ |
|
4150
|
|
|
|
|
|
|
/* DPCHDF will be set to the desired derivative approximation if */ |
|
4151
|
|
|
|
|
|
|
/* IERR=0 or to zero if IERR=-1. */ |
|
4152
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */ |
|
4153
|
|
|
|
|
|
|
/* ***SEE ALSO DPCHCE, DPCHSP */ |
|
4154
|
|
|
|
|
|
|
/* ***REFERENCES Carl de Boor, A Practical Guide to Splines, Springer- */ |
|
4155
|
|
|
|
|
|
|
/* Verlag, New York, 1978, pp. 10-16. */ |
|
4156
|
|
|
|
|
|
|
/* CHECK FOR LEGAL VALUE OF K. */ |
|
4157
|
|
|
|
|
|
|
{ |
|
4158
|
|
|
|
|
|
|
/* Local variables */ |
|
4159
|
|
|
|
|
|
|
PDL_Indx i, j, k_cached = '.$k.'; |
|
4160
|
|
|
|
|
|
|
$GENERIC() *x = '.$x.', *s = '.$s.'; |
|
4161
|
|
|
|
|
|
|
if (k_cached < 3) $CROAK("K LESS THAN THREE"); |
|
4162
|
|
|
|
|
|
|
/* COMPUTE COEFFICIENTS OF INTERPOLATING POLYNOMIAL. */ |
|
4163
|
|
|
|
|
|
|
for (j = 2; j < k_cached; ++j) { |
|
4164
|
|
|
|
|
|
|
PDL_Indx itmp = k_cached - j; |
|
4165
|
|
|
|
|
|
|
for (i = 0; i < itmp; ++i) |
|
4166
|
|
|
|
|
|
|
s[i] = (s[i+1] - s[i]) / (x[i + j] - x[i]); |
|
4167
|
|
|
|
|
|
|
} |
|
4168
|
|
|
|
|
|
|
/* EVALUATE DERIVATIVE AT X(K). */ |
|
4169
|
|
|
|
|
|
|
$GENERIC() value = s[0]; |
|
4170
|
|
|
|
|
|
|
for (i = 1; i < k_cached-1; ++i) |
|
4171
|
|
|
|
|
|
|
value = s[i] + value * (x[k_cached-1] - x[i]); |
|
4172
|
|
|
|
|
|
|
'.$out.' = value; |
|
4173
|
|
|
|
|
|
|
} |
|
4174
|
|
|
|
|
|
|
'}, |
|
4175
|
|
|
|
|
|
|
SIGN => sub {my ($a, $b) = @_; "(($b) >= 0 ? PDL_ABS($a) : -PDL_ABS($a))"}, |
|
4176
|
|
|
|
|
|
|
PCHST => sub {my ($a, $b) = @_; |
|
4177
|
|
|
|
|
|
|
"((($a) == 0. || ($b) == 0.) ? 0. : \$SIGN(1, ($a)) * \$SIGN(1, ($b)))" |
|
4178
|
|
|
|
|
|
|
}, |
|
4179
|
|
|
|
|
|
|
CHFIE => sub {my ($x1, $x2, $f1, $f2, $d1, $d2, $a, $b, $out) = @_; ' |
|
4180
|
|
|
|
|
|
|
/* ***PURPOSE Evaluates integral of a single cubic for DPCHIA */ |
|
4181
|
|
|
|
|
|
|
/* DCHFIE: Cubic Hermite Function Integral Evaluator. */ |
|
4182
|
|
|
|
|
|
|
/* Called by DPCHIA to evaluate the integral of a single cubic (in */ |
|
4183
|
|
|
|
|
|
|
/* Hermite form) over an arbitrary interval (A,B). */ |
|
4184
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */ |
|
4185
|
|
|
|
|
|
|
/* Parameters: */ |
|
4186
|
|
|
|
|
|
|
/* VALUE -- (output) value of the requested integral. */ |
|
4187
|
|
|
|
|
|
|
/* X1,X2 -- (input) endpoints if interval of definition of cubic. */ |
|
4188
|
|
|
|
|
|
|
/* F1,F2 -- (input) function values at the ends of the interval. */ |
|
4189
|
|
|
|
|
|
|
/* D1,D2 -- (input) derivative values at the ends of the interval. */ |
|
4190
|
|
|
|
|
|
|
/* A,B -- (input) endpoints of interval of integration. */ |
|
4191
|
|
|
|
|
|
|
/* ***SEE ALSO DPCHIA */ |
|
4192
|
|
|
|
|
|
|
/* Programming notes: */ |
|
4193
|
|
|
|
|
|
|
/* 1. There is no error return from this routine because zero is */ |
|
4194
|
|
|
|
|
|
|
/* indeed the mathematically correct answer when X1.EQ.X2 . */ |
|
4195
|
|
|
|
|
|
|
do { |
|
4196
|
|
|
|
|
|
|
if ('.$x1.' == '.$x2.') { |
|
4197
|
|
|
|
|
|
|
'.$out.' = 0.; break; |
|
4198
|
|
|
|
|
|
|
} |
|
4199
|
|
|
|
|
|
|
$GENERIC() h = '.$x2.' - '.$x1.'; |
|
4200
|
|
|
|
|
|
|
$GENERIC() ta1 = ('.$a.' - '.$x1.') / h; |
|
4201
|
|
|
|
|
|
|
$GENERIC() ta2 = ('.$x2.' - '.$a.') / h; |
|
4202
|
|
|
|
|
|
|
$GENERIC() tb1 = ('.$b.' - '.$x1.') / h; |
|
4203
|
|
|
|
|
|
|
$GENERIC() tb2 = ('.$x2.' - '.$b.') / h; |
|
4204
|
|
|
|
|
|
|
/* Computing 3rd power */ |
|
4205
|
|
|
|
|
|
|
$GENERIC() ua1 = ta1 * (ta1 * ta1); |
|
4206
|
|
|
|
|
|
|
$GENERIC() phia1 = ua1 * (2. - ta1); |
|
4207
|
|
|
|
|
|
|
$GENERIC() psia1 = ua1 * (3. * ta1 - 4.); |
|
4208
|
|
|
|
|
|
|
/* Computing 3rd power */ |
|
4209
|
|
|
|
|
|
|
$GENERIC() ua2 = ta2 * (ta2 * ta2); |
|
4210
|
|
|
|
|
|
|
$GENERIC() phia2 = ua2 * (2. - ta2); |
|
4211
|
|
|
|
|
|
|
$GENERIC() psia2 = -ua2 * (3. * ta2 - 4.); |
|
4212
|
|
|
|
|
|
|
/* Computing 3rd power */ |
|
4213
|
|
|
|
|
|
|
$GENERIC() ub1 = tb1 * (tb1 * tb1); |
|
4214
|
|
|
|
|
|
|
$GENERIC() phib1 = ub1 * (2. - tb1); |
|
4215
|
|
|
|
|
|
|
$GENERIC() psib1 = ub1 * (3. * tb1 - 4.); |
|
4216
|
|
|
|
|
|
|
/* Computing 3rd power */ |
|
4217
|
|
|
|
|
|
|
$GENERIC() ub2 = tb2 * (tb2 * tb2); |
|
4218
|
|
|
|
|
|
|
$GENERIC() phib2 = ub2 * (2. - tb2); |
|
4219
|
|
|
|
|
|
|
$GENERIC() psib2 = -ub2 * (3. * tb2 - 4.); |
|
4220
|
|
|
|
|
|
|
$GENERIC() fterm = '.$f1.' * (phia2 - phib2) + '.$f2.' * (phib1 - phia1); |
|
4221
|
|
|
|
|
|
|
$GENERIC() dterm = ('.$d1.' * (psia2 - psib2) + '.$d2.' * (psib1 - psia1)) * (h / 6.); |
|
4222
|
|
|
|
|
|
|
'.$out.' = 0.5 * h * (fterm + dterm); |
|
4223
|
|
|
|
|
|
|
} while(0) |
|
4224
|
|
|
|
|
|
|
'}, |
|
4225
|
|
|
|
|
|
|
PCHID => sub {my ($ia, $ib, $out) = @_; ' |
|
4226
|
|
|
|
|
|
|
/* Programming notes: */ |
|
4227
|
|
|
|
|
|
|
/* 1. This routine uses a special formula that is valid only for */ |
|
4228
|
|
|
|
|
|
|
/* integrals whose limits coincide with data values. This is */ |
|
4229
|
|
|
|
|
|
|
/* mathematically equivalent to, but much more efficient than, */ |
|
4230
|
|
|
|
|
|
|
/* calls to DCHFIE. */ |
|
4231
|
|
|
|
|
|
|
/* VALIDITY-CHECK ARGUMENTS. */ |
|
4232
|
|
|
|
|
|
|
do { |
|
4233
|
|
|
|
|
|
|
/* FUNCTION DEFINITION IS OK, GO ON. */ |
|
4234
|
|
|
|
|
|
|
$skip() = 1; |
|
4235
|
|
|
|
|
|
|
if ('.$ia.' < 0 || '.$ia.' > $SIZE(n)-1 || '.$ib.' < 0 || '.$ib.' > $SIZE(n)-1) { |
|
4236
|
|
|
|
|
|
|
$ierr() = -4; |
|
4237
|
|
|
|
|
|
|
$CROAK("IA OR IB OUT OF RANGE"); |
|
4238
|
|
|
|
|
|
|
} |
|
4239
|
|
|
|
|
|
|
$ierr() = 0; |
|
4240
|
|
|
|
|
|
|
/* COMPUTE INTEGRAL VALUE. */ |
|
4241
|
|
|
|
|
|
|
if ('.$ia.' == '.$ib.') { '.$out.' = 0; continue; } |
|
4242
|
|
|
|
|
|
|
PDL_Indx low = PDLMIN('.$ia.','.$ib.'), iup = PDLMAX('.$ia.','.$ib.'); |
|
4243
|
|
|
|
|
|
|
$GENERIC() sum = 0.; |
|
4244
|
|
|
|
|
|
|
loop (n=low:iup) %{ |
|
4245
|
|
|
|
|
|
|
$GENERIC() h = $x(n=>n+1) - $x(); |
|
4246
|
|
|
|
|
|
|
sum += h * ($f() + $f(n=>n+1) + ($d() - $d(n=>n+1)) * (h / 6.)); |
|
4247
|
|
|
|
|
|
|
%} |
|
4248
|
|
|
|
|
|
|
'.$out.' = 0.5 * ('.$ia.' > '.$ib.' ? -sum : sum); |
|
4249
|
|
|
|
|
|
|
} while(0) |
|
4250
|
|
|
|
|
|
|
'}, |
|
4251
|
|
|
|
|
|
|
CHFD => sub {my ($do_deriv) = @_; ' |
|
4252
|
|
|
|
|
|
|
/* Programming notes: */ |
|
4253
|
|
|
|
|
|
|
/* 2. Most of the coding between the call to DCHFDV and the end of */ |
|
4254
|
|
|
|
|
|
|
/* the IR-loop could be eliminated if it were permissible to */ |
|
4255
|
|
|
|
|
|
|
/* assume that XE is ordered relative to X. */ |
|
4256
|
|
|
|
|
|
|
/* 3. DCHFDV does not assume that X1 is less than X2. thus, it would */ |
|
4257
|
|
|
|
|
|
|
/* be possible to write a version of DPCHFD that assumes a strict- */ |
|
4258
|
|
|
|
|
|
|
/* ly decreasing X-array by simply running the IR-loop backwards */ |
|
4259
|
|
|
|
|
|
|
/* (and reversing the order of appropriate tests). */ |
|
4260
|
|
|
|
|
|
|
/* 4. The present code has a minor bug, which I have decided is not */ |
|
4261
|
|
|
|
|
|
|
/* worth the effort that would be required to fix it. */ |
|
4262
|
|
|
|
|
|
|
/* If XE contains points in [X(N-1),X(N)], followed by points .LT. */ |
|
4263
|
|
|
|
|
|
|
/* X(N-1), followed by points .GT.X(N), the extrapolation points */ |
|
4264
|
|
|
|
|
|
|
/* will be counted (at least) twice in the total returned in IERR. */ |
|
4265
|
|
|
|
|
|
|
/* VALIDITY-CHECK ARGUMENTS. */ |
|
4266
|
|
|
|
|
|
|
if (!$skip()) { |
|
4267
|
|
|
|
|
|
|
loop (n=1) %{ |
|
4268
|
|
|
|
|
|
|
if ($x() > $x(n=>n-1)) continue; |
|
4269
|
|
|
|
|
|
|
$ierr() = -3; |
|
4270
|
|
|
|
|
|
|
$CROAK("X-ARRAY NOT STRICTLY INCREASING"); |
|
4271
|
|
|
|
|
|
|
%} |
|
4272
|
|
|
|
|
|
|
} |
|
4273
|
|
|
|
|
|
|
/* FUNCTION DEFINITION IS OK, GO ON. */ |
|
4274
|
|
|
|
|
|
|
$ierr() = 0; |
|
4275
|
|
|
|
|
|
|
$skip() = 1; |
|
4276
|
|
|
|
|
|
|
/* LOOP OVER INTERVALS. ( INTERVAL INDEX IS IL = IR-1 . ) */ |
|
4277
|
|
|
|
|
|
|
/* ( INTERVAL IS X(IL).LE.X.LT.X(IR) . ) */ |
|
4278
|
|
|
|
|
|
|
PDL_Indx n = $SIZE(n), ne = $SIZE(ne); |
|
4279
|
|
|
|
|
|
|
PDL_Indx jfirst = 0, ir; |
|
4280
|
|
|
|
|
|
|
for (ir = 1; ir < n && jfirst < ne; ++ir) { |
|
4281
|
|
|
|
|
|
|
/* SKIP OUT OF LOOP IF HAVE PROCESSED ALL EVALUATION POINTS. */ |
|
4282
|
|
|
|
|
|
|
/* LOCATE ALL POINTS IN INTERVAL. */ |
|
4283
|
|
|
|
|
|
|
char located = 0; |
|
4284
|
|
|
|
|
|
|
PDL_Indx j = jfirst; |
|
4285
|
|
|
|
|
|
|
loop (ne=jfirst) %{ |
|
4286
|
|
|
|
|
|
|
j = ne; |
|
4287
|
|
|
|
|
|
|
if ($xe() >= $x(n=>ir)) { |
|
4288
|
|
|
|
|
|
|
located = 1; |
|
4289
|
|
|
|
|
|
|
break; |
|
4290
|
|
|
|
|
|
|
} |
|
4291
|
|
|
|
|
|
|
%} |
|
4292
|
|
|
|
|
|
|
if (!located || ir == n-1) |
|
4293
|
|
|
|
|
|
|
j = ne; |
|
4294
|
|
|
|
|
|
|
/* HAVE LOCATED FIRST POINT BEYOND INTERVAL. */ |
|
4295
|
|
|
|
|
|
|
PDL_Indx nj = j - jfirst; |
|
4296
|
|
|
|
|
|
|
/* SKIP EVALUATION IF NO POINTS IN INTERVAL. */ |
|
4297
|
|
|
|
|
|
|
if (nj == 0) |
|
4298
|
|
|
|
|
|
|
continue; |
|
4299
|
|
|
|
|
|
|
/* EVALUATE CUBIC AT XE(I), I = JFIRST (1) J-1 . */ |
|
4300
|
|
|
|
|
|
|
/* ---------------------------------------------------------------- */ |
|
4301
|
|
|
|
|
|
|
PDL_Indx next[] = {0,0}; |
|
4302
|
|
|
|
|
|
|
do { /* inline dchfdv */ |
|
4303
|
|
|
|
|
|
|
/* Local variables */ |
|
4304
|
|
|
|
|
|
|
$GENERIC() x1 = $x(n=>ir-1), x2 = $x(n=>ir); |
|
4305
|
|
|
|
|
|
|
$GENERIC() f1 = $f(n=>ir-1), f2 = $f(n=>ir); |
|
4306
|
|
|
|
|
|
|
$GENERIC() d1 = $d(n=>ir-1), d2 = $d(n=>ir); |
|
4307
|
|
|
|
|
|
|
$GENERIC() h = x2 - x1; |
|
4308
|
|
|
|
|
|
|
if (h == 0.) |
|
4309
|
|
|
|
|
|
|
$CROAK("INTERVAL ENDPOINTS EQUAL"); |
|
4310
|
|
|
|
|
|
|
/* INITIALIZE. */ |
|
4311
|
|
|
|
|
|
|
$GENERIC() xmi = PDLMIN(0.,h); |
|
4312
|
|
|
|
|
|
|
$GENERIC() xma = PDLMAX(0.,h); |
|
4313
|
|
|
|
|
|
|
/* COMPUTE CUBIC COEFFICIENTS (EXPANDED ABOUT X1). */ |
|
4314
|
|
|
|
|
|
|
$GENERIC() delta = (f2 - f1) / h; |
|
4315
|
|
|
|
|
|
|
$GENERIC() del1 = (d1 - delta) / h; |
|
4316
|
|
|
|
|
|
|
$GENERIC() del2 = (d2 - delta) / h; |
|
4317
|
|
|
|
|
|
|
/* (DELTA IS NO LONGER NEEDED.) */ |
|
4318
|
|
|
|
|
|
|
$GENERIC() c2 = -(del1 + del1 + del2); |
|
4319
|
|
|
|
|
|
|
'.($do_deriv ? '$GENERIC() c2t2 = c2 + c2;' : '').' |
|
4320
|
|
|
|
|
|
|
$GENERIC() c3 = (del1 + del2) / h; |
|
4321
|
|
|
|
|
|
|
/* (H, DEL1 AND DEL2 ARE NO LONGER NEEDED.) */ |
|
4322
|
|
|
|
|
|
|
'.($do_deriv ? '$GENERIC() c3t3 = c3 + c3 + c3;' : '').' |
|
4323
|
|
|
|
|
|
|
/* EVALUATION LOOP. */ |
|
4324
|
|
|
|
|
|
|
loop (ne=:nj) %{ |
|
4325
|
|
|
|
|
|
|
$GENERIC() x = $xe(ne=>ne+jfirst) - x1; |
|
4326
|
|
|
|
|
|
|
$fe(ne=>ne+jfirst) = f1 + x * (d1 + x * (c2 + x * c3)); |
|
4327
|
|
|
|
|
|
|
'.($do_deriv ? '$de(ne=>ne+jfirst) = d1 + x * (c2t2 + x * c3t3);' : '').' |
|
4328
|
|
|
|
|
|
|
/* COUNT EXTRAPOLATION POINTS. */ |
|
4329
|
|
|
|
|
|
|
if (x < xmi) |
|
4330
|
|
|
|
|
|
|
++next[0]; |
|
4331
|
|
|
|
|
|
|
if (x > xma) |
|
4332
|
|
|
|
|
|
|
++next[1]; |
|
4333
|
|
|
|
|
|
|
/* (NOTE REDUNDANCY--IF EITHER CONDITION IS TRUE, OTHER IS FALSE.) */ |
|
4334
|
|
|
|
|
|
|
%} |
|
4335
|
|
|
|
|
|
|
} while (0); /* end inline dchfdv */ |
|
4336
|
|
|
|
|
|
|
/* ---------------------------------------------------------------- */ |
|
4337
|
|
|
|
|
|
|
if (next[1] != 0) { |
|
4338
|
|
|
|
|
|
|
/* IN THE CURRENT SET OF XE-POINTS, THERE ARE NEXT(2) TO THE */ |
|
4339
|
|
|
|
|
|
|
/* RIGHT OF X(IR). */ |
|
4340
|
|
|
|
|
|
|
/* THESE ARE ACTUALLY EXTRAPOLATION POINTS. */ |
|
4341
|
|
|
|
|
|
|
$ierr() += next[1]; |
|
4342
|
|
|
|
|
|
|
} |
|
4343
|
|
|
|
|
|
|
if (next[0] != 0) { |
|
4344
|
|
|
|
|
|
|
/* IN THE CURRENT SET OF XE-POINTS, THERE ARE NEXT(1) TO THE */ |
|
4345
|
|
|
|
|
|
|
/* LEFT OF X(IR-1). */ |
|
4346
|
|
|
|
|
|
|
if (ir < 2) { |
|
4347
|
|
|
|
|
|
|
/* THESE ARE ACTUALLY EXTRAPOLATION POINTS. */ |
|
4348
|
|
|
|
|
|
|
$ierr() += next[0]; |
|
4349
|
|
|
|
|
|
|
jfirst = j; |
|
4350
|
|
|
|
|
|
|
continue; |
|
4351
|
|
|
|
|
|
|
} |
|
4352
|
|
|
|
|
|
|
/* XE IS NOT ORDERED RELATIVE TO X, SO MUST ADJUST */ |
|
4353
|
|
|
|
|
|
|
/* EVALUATION INTERVAL. */ |
|
4354
|
|
|
|
|
|
|
/* FIRST, LOCATE FIRST POINT TO LEFT OF X(IR-1). */ |
|
4355
|
|
|
|
|
|
|
located = 0; |
|
4356
|
|
|
|
|
|
|
PDL_Indx i = jfirst; |
|
4357
|
|
|
|
|
|
|
loop (ne=jfirst:j) %{ |
|
4358
|
|
|
|
|
|
|
i = ne; |
|
4359
|
|
|
|
|
|
|
if ($xe() < $x(n=>ir-1)) { |
|
4360
|
|
|
|
|
|
|
located = 1; |
|
4361
|
|
|
|
|
|
|
break; |
|
4362
|
|
|
|
|
|
|
} |
|
4363
|
|
|
|
|
|
|
%} |
|
4364
|
|
|
|
|
|
|
if (!located) { |
|
4365
|
|
|
|
|
|
|
/* NOTE-- CANNOT DROP THROUGH HERE UNLESS THERE IS AN ERROR */ |
|
4366
|
|
|
|
|
|
|
/* IN DCHFDV. */ |
|
4367
|
|
|
|
|
|
|
$ierr() = -5; |
|
4368
|
|
|
|
|
|
|
$CROAK("ERROR RETURN FROM DCHFDV -- FATAL"); |
|
4369
|
|
|
|
|
|
|
} |
|
4370
|
|
|
|
|
|
|
/* RESET J. (THIS WILL BE THE NEW JFIRST.) */ |
|
4371
|
|
|
|
|
|
|
j = i; |
|
4372
|
|
|
|
|
|
|
/* NOW FIND OUT HOW FAR TO BACK UP IN THE X-ARRAY. */ |
|
4373
|
|
|
|
|
|
|
loop (n=:ir) %{ |
|
4374
|
|
|
|
|
|
|
i = n; |
|
4375
|
|
|
|
|
|
|
if ($xe(ne=>j) < $x()) |
|
4376
|
|
|
|
|
|
|
break; |
|
4377
|
|
|
|
|
|
|
%} |
|
4378
|
|
|
|
|
|
|
/* NB-- CAN NEVER DROP THROUGH HERE, SINCE XE(J).LT.X(IR-1). */ |
|
4379
|
|
|
|
|
|
|
/* AT THIS POINT, EITHER XE(J) .LT. X(1) */ |
|
4380
|
|
|
|
|
|
|
/* OR X(I-1) .LE. XE(J) .LT. X(I) . */ |
|
4381
|
|
|
|
|
|
|
/* RESET IR, RECOGNIZING THAT IT WILL BE INCREMENTED BEFORE */ |
|
4382
|
|
|
|
|
|
|
/* CYCLING. */ |
|
4383
|
|
|
|
|
|
|
/* Computing MAX */ |
|
4384
|
|
|
|
|
|
|
ir = PDLMAX(0,i-1); |
|
4385
|
|
|
|
|
|
|
} |
|
4386
|
|
|
|
|
|
|
jfirst = j; |
|
4387
|
|
|
|
|
|
|
/* END OF IR-LOOP. */ |
|
4388
|
|
|
|
|
|
|
} |
|
4389
|
|
|
|
|
|
|
'}, |
|
4390
|
|
|
|
|
|
|
); |
|
4391
|
|
|
|
|
|
|
|
|
4392
|
|
|
|
|
|
|
pp_def('pchip_chim', |
|
4393
|
|
|
|
|
|
|
Pars => 'x(n); f(n); [o]d(n); indx [o]ierr();', |
|
4394
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
4395
|
|
|
|
|
|
|
if ($SIZE(n) < 2) $CROAK("NUMBER OF DATA POINTS LESS THAN TWO"); |
|
4396
|
|
|
|
|
|
|
EOF |
|
4397
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
4398
|
|
|
|
|
|
|
/* Local variables */ |
|
4399
|
|
|
|
|
|
|
$GENERIC() dmax, hsumt3; |
|
4400
|
|
|
|
|
|
|
PDL_Indx n = $SIZE(n); |
|
4401
|
|
|
|
|
|
|
/* VALIDITY-CHECK ARGUMENTS. */ |
|
4402
|
|
|
|
|
|
|
loop (n=1) %{ |
|
4403
|
|
|
|
|
|
|
if ($x() > $x(n=>n-1)) continue; |
|
4404
|
|
|
|
|
|
|
$ierr() = -1; |
|
4405
|
|
|
|
|
|
|
$CROAK("X-ARRAY NOT STRICTLY INCREASING"); |
|
4406
|
|
|
|
|
|
|
%} |
|
4407
|
|
|
|
|
|
|
/* FUNCTION DEFINITION IS OK, GO ON. */ |
|
4408
|
|
|
|
|
|
|
$ierr() = 0; |
|
4409
|
|
|
|
|
|
|
$GENERIC() h1 = $x(n=>1) - $x(n=>0); |
|
4410
|
|
|
|
|
|
|
$GENERIC() del1 = ($f(n=>1) - $f(n=>0)) / h1; |
|
4411
|
|
|
|
|
|
|
$GENERIC() dsave = del1; |
|
4412
|
|
|
|
|
|
|
/* SPECIAL CASE N=2 -- USE LINEAR INTERPOLATION. */ |
|
4413
|
|
|
|
|
|
|
if (n <= 2) { |
|
4414
|
|
|
|
|
|
|
$d(n=>0) = $d(n=>1) = del1; |
|
4415
|
|
|
|
|
|
|
continue; |
|
4416
|
|
|
|
|
|
|
} |
|
4417
|
|
|
|
|
|
|
/* NORMAL CASE (N .GE. 3). */ |
|
4418
|
|
|
|
|
|
|
$GENERIC() h2 = $x(n=>2) - $x(n=>1); |
|
4419
|
|
|
|
|
|
|
$GENERIC() del2 = ($f(n=>2) - $f(n=>1)) / h2; |
|
4420
|
|
|
|
|
|
|
/* SET D(1) VIA NON-CENTERED THREE-POINT FORMULA, ADJUSTED TO BE */ |
|
4421
|
|
|
|
|
|
|
/* SHAPE-PRESERVING. */ |
|
4422
|
|
|
|
|
|
|
$GENERIC() hsum = h1 + h2; |
|
4423
|
|
|
|
|
|
|
$GENERIC() w1 = (h1 + hsum) / hsum; |
|
4424
|
|
|
|
|
|
|
$GENERIC() w2 = -h1 / hsum; |
|
4425
|
|
|
|
|
|
|
$d(n=>0) = w1 * del1 + w2 * del2; |
|
4426
|
|
|
|
|
|
|
if ($PCHST($d(n=>0), del1) <= 0.) { |
|
4427
|
|
|
|
|
|
|
$d(n=>0) = 0.; |
|
4428
|
|
|
|
|
|
|
} else if ($PCHST(del1, del2) < 0.) { |
|
4429
|
|
|
|
|
|
|
/* NEED DO THIS CHECK ONLY IF MONOTONICITY SWITCHES. */ |
|
4430
|
|
|
|
|
|
|
dmax = 3. * del1; |
|
4431
|
|
|
|
|
|
|
if (PDL_ABS($d(n=>0)) > PDL_ABS(dmax)) { |
|
4432
|
|
|
|
|
|
|
$d(n=>0) = dmax; |
|
4433
|
|
|
|
|
|
|
} |
|
4434
|
|
|
|
|
|
|
} |
|
4435
|
|
|
|
|
|
|
/* LOOP THROUGH INTERIOR POINTS. */ |
|
4436
|
|
|
|
|
|
|
loop (n=1:-1) %{ |
|
4437
|
|
|
|
|
|
|
if (n != 1) { |
|
4438
|
|
|
|
|
|
|
h1 = h2; |
|
4439
|
|
|
|
|
|
|
h2 = $x(n=>n+1) - $x(); |
|
4440
|
|
|
|
|
|
|
hsum = h1 + h2; |
|
4441
|
|
|
|
|
|
|
del1 = del2; |
|
4442
|
|
|
|
|
|
|
del2 = ($f(n=>n+1) - $f()) / h2; |
|
4443
|
|
|
|
|
|
|
} |
|
4444
|
|
|
|
|
|
|
/* SET D(I)=0 UNLESS DATA ARE STRICTLY MONOTONIC. */ |
|
4445
|
|
|
|
|
|
|
$d() = 0.; |
|
4446
|
|
|
|
|
|
|
$GENERIC() dtmp = $PCHST(del1, del2); |
|
4447
|
|
|
|
|
|
|
if (dtmp <= 0) { |
|
4448
|
|
|
|
|
|
|
if (dtmp == 0.) { |
|
4449
|
|
|
|
|
|
|
/* COUNT NUMBER OF CHANGES IN DIRECTION OF MONOTONICITY. */ |
|
4450
|
|
|
|
|
|
|
if (del2 == 0.) { |
|
4451
|
|
|
|
|
|
|
continue; |
|
4452
|
|
|
|
|
|
|
} |
|
4453
|
|
|
|
|
|
|
if ($PCHST(dsave, del2) < 0.) { |
|
4454
|
|
|
|
|
|
|
++($ierr()); |
|
4455
|
|
|
|
|
|
|
} |
|
4456
|
|
|
|
|
|
|
dsave = del2; |
|
4457
|
|
|
|
|
|
|
continue; |
|
4458
|
|
|
|
|
|
|
} |
|
4459
|
|
|
|
|
|
|
++($ierr()); |
|
4460
|
|
|
|
|
|
|
dsave = del2; |
|
4461
|
|
|
|
|
|
|
continue; |
|
4462
|
|
|
|
|
|
|
} |
|
4463
|
|
|
|
|
|
|
/* USE BRODLIE MODIFICATION OF BUTLAND FORMULA. */ |
|
4464
|
|
|
|
|
|
|
hsumt3 = hsum + hsum + hsum; |
|
4465
|
|
|
|
|
|
|
w1 = (hsum + h1) / hsumt3; |
|
4466
|
|
|
|
|
|
|
w2 = (hsum + h2) / hsumt3; |
|
4467
|
|
|
|
|
|
|
/* Computing MAX */ |
|
4468
|
|
|
|
|
|
|
dmax = PDLMAX(PDL_ABS(del1),PDL_ABS(del2)); |
|
4469
|
|
|
|
|
|
|
/* Computing MIN */ |
|
4470
|
|
|
|
|
|
|
$GENERIC() dmin = PDLMIN(PDL_ABS(del1),PDL_ABS(del2)); |
|
4471
|
|
|
|
|
|
|
$GENERIC() drat1 = del1 / dmax; |
|
4472
|
|
|
|
|
|
|
$GENERIC() drat2 = del2 / dmax; |
|
4473
|
|
|
|
|
|
|
$d() = dmin / (w1 * drat1 + w2 * drat2); |
|
4474
|
|
|
|
|
|
|
%} |
|
4475
|
|
|
|
|
|
|
/* SET D(N) VIA NON-CENTERED THREE-POINT FORMULA, ADJUSTED TO BE */ |
|
4476
|
|
|
|
|
|
|
/* SHAPE-PRESERVING. */ |
|
4477
|
|
|
|
|
|
|
w1 = -h2 / hsum; |
|
4478
|
|
|
|
|
|
|
w2 = (h2 + hsum) / hsum; |
|
4479
|
|
|
|
|
|
|
$d(n=>n-1) = w1 * del1 + w2 * del2; |
|
4480
|
|
|
|
|
|
|
if ($PCHST($d(n=>n-1), del2) <= 0.) { |
|
4481
|
|
|
|
|
|
|
$d(n=>n-1) = 0.; |
|
4482
|
|
|
|
|
|
|
} else if ($PCHST(del1, del2) < 0.) { |
|
4483
|
|
|
|
|
|
|
/* NEED DO THIS CHECK ONLY IF MONOTONICITY SWITCHES. */ |
|
4484
|
|
|
|
|
|
|
dmax = 3. * del2; |
|
4485
|
|
|
|
|
|
|
if (PDL_ABS($d(n=>n-1)) > PDL_ABS(dmax)) { |
|
4486
|
|
|
|
|
|
|
$d(n=>n-1) = dmax; |
|
4487
|
|
|
|
|
|
|
} |
|
4488
|
|
|
|
|
|
|
} |
|
4489
|
|
|
|
|
|
|
EOF |
|
4490
|
|
|
|
|
|
|
ParamDesc => { |
|
4491
|
|
|
|
|
|
|
x => 'ordinate data', |
|
4492
|
|
|
|
|
|
|
f => <<'EOF', |
|
4493
|
|
|
|
|
|
|
array of dependent variable values to be |
|
4494
|
|
|
|
|
|
|
interpolated. F(I) is value corresponding to |
|
4495
|
|
|
|
|
|
|
X(I). C is designed for monotonic data, but it will |
|
4496
|
|
|
|
|
|
|
work for any F-array. It will force extrema at points where |
|
4497
|
|
|
|
|
|
|
monotonicity switches direction. If some other treatment of |
|
4498
|
|
|
|
|
|
|
switch points is desired, DPCHIC should be used instead. |
|
4499
|
|
|
|
|
|
|
EOF |
|
4500
|
|
|
|
|
|
|
d => <<'EOF', |
|
4501
|
|
|
|
|
|
|
array of derivative values at the data |
|
4502
|
|
|
|
|
|
|
points. If the data are monotonic, these values will |
|
4503
|
|
|
|
|
|
|
determine a monotone cubic Hermite function. |
|
4504
|
|
|
|
|
|
|
EOF |
|
4505
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
4506
|
|
|
|
|
|
|
Error status: |
|
4507
|
|
|
|
|
|
|
|
|
4508
|
|
|
|
|
|
|
=over |
|
4509
|
|
|
|
|
|
|
|
|
4510
|
|
|
|
|
|
|
=item * |
|
4511
|
|
|
|
|
|
|
|
|
4512
|
|
|
|
|
|
|
0 if successful. |
|
4513
|
|
|
|
|
|
|
|
|
4514
|
|
|
|
|
|
|
=item * |
|
4515
|
|
|
|
|
|
|
|
|
4516
|
|
|
|
|
|
|
E 0 if there were C switches in the direction of |
|
4517
|
|
|
|
|
|
|
monotonicity (data still valid). |
|
4518
|
|
|
|
|
|
|
|
|
4519
|
|
|
|
|
|
|
=item * |
|
4520
|
|
|
|
|
|
|
|
|
4521
|
|
|
|
|
|
|
-1 if C 2>. |
|
4522
|
|
|
|
|
|
|
|
|
4523
|
|
|
|
|
|
|
=item * |
|
4524
|
|
|
|
|
|
|
|
|
4525
|
|
|
|
|
|
|
-3 if C<$x> is not strictly increasing. |
|
4526
|
|
|
|
|
|
|
|
|
4527
|
|
|
|
|
|
|
=back |
|
4528
|
|
|
|
|
|
|
|
|
4529
|
|
|
|
|
|
|
(The D-array has not been changed in any of these cases.) |
|
4530
|
|
|
|
|
|
|
NOTE: The above errors are checked in the order listed, |
|
4531
|
|
|
|
|
|
|
and following arguments have B been validated. |
|
4532
|
|
|
|
|
|
|
EOF |
|
4533
|
|
|
|
|
|
|
}, |
|
4534
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
4535
|
|
|
|
|
|
|
=for ref |
|
4536
|
|
|
|
|
|
|
|
|
4537
|
|
|
|
|
|
|
Calculate the derivatives of (x,f(x)) using cubic Hermite interpolation. |
|
4538
|
|
|
|
|
|
|
|
|
4539
|
|
|
|
|
|
|
Calculate the derivatives needed to determine a monotone piecewise |
|
4540
|
|
|
|
|
|
|
cubic Hermite interpolant to the given set of points (C<$x,$f>, |
|
4541
|
|
|
|
|
|
|
where C<$x> is strictly increasing). |
|
4542
|
|
|
|
|
|
|
The resulting set of points - C<$x,$f,$d>, referred to |
|
4543
|
|
|
|
|
|
|
as the cubic Hermite representation - can then be used in |
|
4544
|
|
|
|
|
|
|
other functions, such as L, L, |
|
4545
|
|
|
|
|
|
|
and L. |
|
4546
|
|
|
|
|
|
|
|
|
4547
|
|
|
|
|
|
|
The boundary conditions are compatible with monotonicity, |
|
4548
|
|
|
|
|
|
|
and if the data are only piecewise monotonic, the interpolant |
|
4549
|
|
|
|
|
|
|
will have an extremum at the switch points; for more control |
|
4550
|
|
|
|
|
|
|
over these issues use L. |
|
4551
|
|
|
|
|
|
|
|
|
4552
|
|
|
|
|
|
|
References: |
|
4553
|
|
|
|
|
|
|
|
|
4554
|
|
|
|
|
|
|
1. F. N. Fritsch and J. Butland, A method for constructing |
|
4555
|
|
|
|
|
|
|
local monotone piecewise cubic interpolants, SIAM |
|
4556
|
|
|
|
|
|
|
Journal on Scientific and Statistical Computing 5, 2 |
|
4557
|
|
|
|
|
|
|
(June 1984), pp. 300-304. |
|
4558
|
|
|
|
|
|
|
|
|
4559
|
|
|
|
|
|
|
F. N. Fritsch and R. E. Carlson, Monotone piecewise |
|
4560
|
|
|
|
|
|
|
cubic interpolation, SIAM Journal on Numerical Analysis |
|
4561
|
|
|
|
|
|
|
17, 2 (April 1980), pp. 238-246. |
|
4562
|
|
|
|
|
|
|
EOF |
|
4563
|
|
|
|
|
|
|
); |
|
4564
|
|
|
|
|
|
|
|
|
4565
|
|
|
|
|
|
|
pp_def('pchip_chic', |
|
4566
|
|
|
|
|
|
|
Pars => 'sbyte ic(two=2); vc(two=2); mflag(); x(n); f(n); |
|
4567
|
|
|
|
|
|
|
[o]d(n); indx [o]ierr(); |
|
4568
|
|
|
|
|
|
|
[t]h(nless1=CALC($SIZE(n)-1)); [t]slope(nless1);', |
|
4569
|
|
|
|
|
|
|
GenericTypes => $F, |
|
4570
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
4571
|
|
|
|
|
|
|
if ($SIZE(n) < 2) $CROAK("NUMBER OF DATA POINTS LESS THAN TWO"); |
|
4572
|
|
|
|
|
|
|
EOF |
|
4573
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
4574
|
|
|
|
|
|
|
const $GENERIC() d1mach = $TFDE(FLT_EPSILON,DBL_EPSILON,LDBL_EPSILON); |
|
4575
|
|
|
|
|
|
|
/* VALIDITY-CHECK ARGUMENTS. */ |
|
4576
|
|
|
|
|
|
|
loop (n=1) %{ |
|
4577
|
|
|
|
|
|
|
if ($x() > $x(n=>n-1)) continue; |
|
4578
|
|
|
|
|
|
|
$ierr() = -1; |
|
4579
|
|
|
|
|
|
|
$CROAK("X-ARRAY NOT STRICTLY INCREASING"); |
|
4580
|
|
|
|
|
|
|
%} |
|
4581
|
|
|
|
|
|
|
PDL_Indx ibeg = $ic(two=>0), iend = $ic(two=>1), n = $SIZE(n); |
|
4582
|
|
|
|
|
|
|
$ierr() = 0; |
|
4583
|
|
|
|
|
|
|
if (PDL_ABS(ibeg) > 5) |
|
4584
|
|
|
|
|
|
|
--($ierr()); |
|
4585
|
|
|
|
|
|
|
if (PDL_ABS(iend) > 5) |
|
4586
|
|
|
|
|
|
|
$ierr() += -2; |
|
4587
|
|
|
|
|
|
|
if ($ierr() < 0) { |
|
4588
|
|
|
|
|
|
|
$ierr() += -3; |
|
4589
|
|
|
|
|
|
|
$CROAK("IC OUT OF RANGE"); |
|
4590
|
|
|
|
|
|
|
} |
|
4591
|
|
|
|
|
|
|
/* FUNCTION DEFINITION IS OK -- GO ON. */ |
|
4592
|
|
|
|
|
|
|
/* SET UP H AND SLOPE ARRAYS. */ |
|
4593
|
|
|
|
|
|
|
loop (nless1) %{ |
|
4594
|
|
|
|
|
|
|
$h() = $x(n=>nless1+1) - $x(n=>nless1); |
|
4595
|
|
|
|
|
|
|
$slope() = $f(n=>nless1+1) - $f(n=>nless1); |
|
4596
|
|
|
|
|
|
|
%} |
|
4597
|
|
|
|
|
|
|
/* SPECIAL CASE N=2 -- USE LINEAR INTERPOLATION. */ |
|
4598
|
|
|
|
|
|
|
if ($SIZE(nless1) <= 1) { |
|
4599
|
|
|
|
|
|
|
$d(n=>0) = $d(n=>1) = $slope(nless1=>0); |
|
4600
|
|
|
|
|
|
|
} else { |
|
4601
|
|
|
|
|
|
|
/* NORMAL CASE (N .GE. 3) . */ |
|
4602
|
|
|
|
|
|
|
/* SET INTERIOR DERIVATIVES AND DEFAULT END CONDITIONS. */ |
|
4603
|
|
|
|
|
|
|
do { /* inline dpchci */ |
|
4604
|
|
|
|
|
|
|
/* Local variables */ |
|
4605
|
|
|
|
|
|
|
$GENERIC() del1 = $slope(nless1=>0); |
|
4606
|
|
|
|
|
|
|
/* SPECIAL CASE N=2 is dealt with in separate branch above */ |
|
4607
|
|
|
|
|
|
|
/* NORMAL CASE (N .GE. 3). */ |
|
4608
|
|
|
|
|
|
|
$GENERIC() del2 = $slope(nless1=>1); |
|
4609
|
|
|
|
|
|
|
/* SET D(1) VIA NON-CENTERED THREE-POINT FORMULA, ADJUSTED TO BE */ |
|
4610
|
|
|
|
|
|
|
/* SHAPE-PRESERVING. */ |
|
4611
|
|
|
|
|
|
|
$GENERIC() hsum = $h(nless1=>0) + $h(nless1=>1); |
|
4612
|
|
|
|
|
|
|
$GENERIC() w1 = ($h(nless1=>0) + hsum) / hsum; |
|
4613
|
|
|
|
|
|
|
$GENERIC() w2 = -$h(nless1=>0) / hsum; |
|
4614
|
|
|
|
|
|
|
$d(n=>0) = w1 * del1 + w2 * del2; |
|
4615
|
|
|
|
|
|
|
if ($PCHST($d(n=>0), del1) <= 0.) { |
|
4616
|
|
|
|
|
|
|
$d(n=>0) = 0.; |
|
4617
|
|
|
|
|
|
|
} else if ($PCHST(del1, del2) < 0.) { |
|
4618
|
|
|
|
|
|
|
/* NEED DO THIS CHECK ONLY IF MONOTONICITY SWITCHES. */ |
|
4619
|
|
|
|
|
|
|
$GENERIC() dmax = 3. * del1; |
|
4620
|
|
|
|
|
|
|
if (PDL_ABS($d(n=>0)) > PDL_ABS(dmax)) |
|
4621
|
|
|
|
|
|
|
$d(n=>0) = dmax; |
|
4622
|
|
|
|
|
|
|
} |
|
4623
|
|
|
|
|
|
|
/* LOOP THROUGH INTERIOR POINTS. */ |
|
4624
|
|
|
|
|
|
|
loop (nless1=1) %{ |
|
4625
|
|
|
|
|
|
|
if (nless1 != 1) { |
|
4626
|
|
|
|
|
|
|
hsum = $h(nless1=>nless1-1) + $h(); |
|
4627
|
|
|
|
|
|
|
del1 = del2; |
|
4628
|
|
|
|
|
|
|
del2 = $slope(); |
|
4629
|
|
|
|
|
|
|
} |
|
4630
|
|
|
|
|
|
|
/* SET D(I)=0 UNLESS DATA ARE STRICTLY MONOTONIC. */ |
|
4631
|
|
|
|
|
|
|
$d(n=>nless1) = 0.; |
|
4632
|
|
|
|
|
|
|
if ($PCHST(del1, del2) <= 0.) |
|
4633
|
|
|
|
|
|
|
continue; |
|
4634
|
|
|
|
|
|
|
/* USE BRODLIE MODIFICATION OF BUTLAND FORMULA. */ |
|
4635
|
|
|
|
|
|
|
$GENERIC() hsumt3 = hsum + hsum + hsum; |
|
4636
|
|
|
|
|
|
|
w1 = (hsum + $h(nless1=>nless1-1)) / hsumt3; |
|
4637
|
|
|
|
|
|
|
w2 = (hsum + $h()) / hsumt3; |
|
4638
|
|
|
|
|
|
|
/* Computing MAX */ |
|
4639
|
|
|
|
|
|
|
$GENERIC() dmax = PDLMAX(PDL_ABS(del1),PDL_ABS(del2)); |
|
4640
|
|
|
|
|
|
|
/* Computing MIN */ |
|
4641
|
|
|
|
|
|
|
$GENERIC() dmin = PDLMIN(PDL_ABS(del1),PDL_ABS(del2)); |
|
4642
|
|
|
|
|
|
|
$GENERIC() drat1 = del1 / dmax, drat2 = del2 / dmax; |
|
4643
|
|
|
|
|
|
|
$d(n=>nless1) = dmin / (w1 * drat1 + w2 * drat2); |
|
4644
|
|
|
|
|
|
|
%} |
|
4645
|
|
|
|
|
|
|
/* SET D(N) VIA NON-CENTERED THREE-POINT FORMULA, ADJUSTED TO BE */ |
|
4646
|
|
|
|
|
|
|
/* SHAPE-PRESERVING. */ |
|
4647
|
|
|
|
|
|
|
w1 = -$h(nless1=>n-2) / hsum; |
|
4648
|
|
|
|
|
|
|
w2 = ($h(nless1=>n-2) + hsum) / hsum; |
|
4649
|
|
|
|
|
|
|
$d(n=>n-1) = w1 * del1 + w2 * del2; |
|
4650
|
|
|
|
|
|
|
if ($PCHST($d(n=>n-1), del2) <= 0.) { |
|
4651
|
|
|
|
|
|
|
$d(n=>n-1) = 0.; |
|
4652
|
|
|
|
|
|
|
} else if ($PCHST(del1, del2) < 0.) { |
|
4653
|
|
|
|
|
|
|
/* NEED DO THIS CHECK ONLY IF MONOTONICITY SWITCHES. */ |
|
4654
|
|
|
|
|
|
|
$GENERIC() dmax = 3. * del2; |
|
4655
|
|
|
|
|
|
|
if (PDL_ABS($d(n=>n-1)) > PDL_ABS(dmax)) |
|
4656
|
|
|
|
|
|
|
$d(n=>n-1) = dmax; |
|
4657
|
|
|
|
|
|
|
} |
|
4658
|
|
|
|
|
|
|
} while (0); /* end inline dpchci */ |
|
4659
|
|
|
|
|
|
|
/* SET DERIVATIVES AT POINTS WHERE MONOTONICITY SWITCHES DIRECTION. */ |
|
4660
|
|
|
|
|
|
|
if ($mflag() != 0.) { |
|
4661
|
|
|
|
|
|
|
do { /* inline dpchcs */ |
|
4662
|
|
|
|
|
|
|
/* ***PURPOSE Adjusts derivative values for DPCHIC */ |
|
4663
|
|
|
|
|
|
|
/* DPCHCS: DPCHIC Monotonicity Switch Derivative Setter. */ |
|
4664
|
|
|
|
|
|
|
/* Called by DPCHIC to adjust the values of D in the vicinity of a */ |
|
4665
|
|
|
|
|
|
|
/* switch in direction of monotonicity, to produce a more "visually */ |
|
4666
|
|
|
|
|
|
|
/* pleasing" curve than that given by DPCHIM . */ |
|
4667
|
|
|
|
|
|
|
static const $GENERIC() fudge = 4.; |
|
4668
|
|
|
|
|
|
|
/* Local variables */ |
|
4669
|
|
|
|
|
|
|
PDL_Indx k; |
|
4670
|
|
|
|
|
|
|
$GENERIC() del[3], fact, dfmx; |
|
4671
|
|
|
|
|
|
|
$GENERIC() dext, dfloc, slmax, wtave[2]; |
|
4672
|
|
|
|
|
|
|
/* INITIALIZE. */ |
|
4673
|
|
|
|
|
|
|
/* LOOP OVER SEGMENTS. */ |
|
4674
|
|
|
|
|
|
|
loop (nless1=1) %{ |
|
4675
|
|
|
|
|
|
|
$GENERIC() dtmp = $PCHST($slope(nless1=>nless1-1), $slope()); |
|
4676
|
|
|
|
|
|
|
if (dtmp > 0.) { |
|
4677
|
|
|
|
|
|
|
continue; |
|
4678
|
|
|
|
|
|
|
} |
|
4679
|
|
|
|
|
|
|
if (dtmp != 0.) { |
|
4680
|
|
|
|
|
|
|
/* ....... SLOPE SWITCHES MONOTONICITY AT I-TH POINT ..................... */ |
|
4681
|
|
|
|
|
|
|
/* DO NOT CHANGE D IF 'UP-DOWN-UP'. */ |
|
4682
|
|
|
|
|
|
|
if (nless1 > 1) { |
|
4683
|
|
|
|
|
|
|
if ($PCHST($slope(nless1=>nless1-2), $slope()) > 0.) |
|
4684
|
|
|
|
|
|
|
continue; |
|
4685
|
|
|
|
|
|
|
/* -------------------------- */ |
|
4686
|
|
|
|
|
|
|
} |
|
4687
|
|
|
|
|
|
|
if (nless1 < $SIZE(nless1)-1 && $PCHST($slope(nless1=>nless1+1), $slope(nless1=>nless1-1)) > 0.) |
|
4688
|
|
|
|
|
|
|
continue; |
|
4689
|
|
|
|
|
|
|
/* ---------------------------- */ |
|
4690
|
|
|
|
|
|
|
/* ....... COMPUTE PROVISIONAL VALUE FOR D(1,I). */ |
|
4691
|
|
|
|
|
|
|
dext = $h() / ($h(nless1=>nless1-1) + $h()) * $slope(nless1=>nless1-1) + |
|
4692
|
|
|
|
|
|
|
$h(nless1=>nless1-1) / ($h(nless1=>nless1-1) + $h()) * $slope(); |
|
4693
|
|
|
|
|
|
|
/* ....... DETERMINE WHICH INTERVAL CONTAINS THE EXTREMUM. */ |
|
4694
|
|
|
|
|
|
|
dtmp = $PCHST(dext, $slope(nless1=>nless1-1)); |
|
4695
|
|
|
|
|
|
|
if (dtmp == 0) { |
|
4696
|
|
|
|
|
|
|
continue; |
|
4697
|
|
|
|
|
|
|
} |
|
4698
|
|
|
|
|
|
|
if (dtmp < 0.) { |
|
4699
|
|
|
|
|
|
|
/* DEXT AND SLOPE(I-1) HAVE OPPOSITE SIGNS -- */ |
|
4700
|
|
|
|
|
|
|
/* EXTREMUM IS IN (X(I-1),X(I)). */ |
|
4701
|
|
|
|
|
|
|
k = nless1; |
|
4702
|
|
|
|
|
|
|
/* SET UP TO COMPUTE NEW VALUES FOR D(1,I-1) AND D(1,I). */ |
|
4703
|
|
|
|
|
|
|
wtave[1] = dext; |
|
4704
|
|
|
|
|
|
|
if (k > 1) { |
|
4705
|
|
|
|
|
|
|
wtave[0] = $h(nless1=>k-1) / ($h(nless1=>k-2) + $h(nless1=>k-1)) * $slope(nless1=>k-2) + |
|
4706
|
|
|
|
|
|
|
$h(nless1=>k-2) / ($h(nless1=>k-2) + $h(nless1=>k)) * $slope(nless1=>k-1); |
|
4707
|
|
|
|
|
|
|
} |
|
4708
|
|
|
|
|
|
|
} else { |
|
4709
|
|
|
|
|
|
|
/* DEXT AND SLOPE(I) HAVE OPPOSITE SIGNS -- */ |
|
4710
|
|
|
|
|
|
|
/* EXTREMUM IS IN (X(I),X(I+1)). */ |
|
4711
|
|
|
|
|
|
|
k = nless1 + 1; |
|
4712
|
|
|
|
|
|
|
/* SET UP TO COMPUTE NEW VALUES FOR D(1,I) AND D(1,I+1). */ |
|
4713
|
|
|
|
|
|
|
wtave[0] = dext; |
|
4714
|
|
|
|
|
|
|
if (k < nless1) { |
|
4715
|
|
|
|
|
|
|
wtave[1] = $h(nless1=>k) / ($h(nless1=>k-1) + $h(nless1=>k)) * $slope(nless1=>k-1) + $h(nless1=>k-1) |
|
4716
|
|
|
|
|
|
|
/ ($h(nless1=>k-1) + $h(nless1=>k)) * $slope(nless1=>k); |
|
4717
|
|
|
|
|
|
|
} |
|
4718
|
|
|
|
|
|
|
} |
|
4719
|
|
|
|
|
|
|
} else { |
|
4720
|
|
|
|
|
|
|
/* ....... AT LEAST ONE OF SLOPE(I-1) AND SLOPE(I) IS ZERO -- */ |
|
4721
|
|
|
|
|
|
|
/* CHECK FOR FLAT-TOPPED PEAK ....................... */ |
|
4722
|
|
|
|
|
|
|
if (nless1 == $SIZE(nless1)-1 || $PCHST($slope(nless1=>nless1-1), $slope(nless1=>nless1+1)) >= 0.) |
|
4723
|
|
|
|
|
|
|
continue; |
|
4724
|
|
|
|
|
|
|
/* ----------------------------- */ |
|
4725
|
|
|
|
|
|
|
/* WE HAVE FLAT-TOPPED PEAK ON (X(I),X(I+1)). */ |
|
4726
|
|
|
|
|
|
|
k = nless1+1; |
|
4727
|
|
|
|
|
|
|
/* SET UP TO COMPUTE NEW VALUES FOR D(1,I) AND D(1,I+1). */ |
|
4728
|
|
|
|
|
|
|
wtave[0] = $h(nless1=>k-1) / ($h(nless1=>k-2) + $h(nless1=>k-1)) * $slope(nless1=>k-2) + $h(nless1=>k-2) |
|
4729
|
|
|
|
|
|
|
/ ($h(nless1=>k-2) + $h(nless1=>k-1)) * $slope(nless1=>k-1); |
|
4730
|
|
|
|
|
|
|
wtave[1] = $h(nless1=>k) / ($h(nless1=>k-1) + $h(nless1=>k)) * $slope(nless1=>k-1) + $h(nless1=>k-1) / ( |
|
4731
|
|
|
|
|
|
|
$h(nless1=>k-1) + $h(nless1=>k)) * $slope(nless1=>k); |
|
4732
|
|
|
|
|
|
|
} |
|
4733
|
|
|
|
|
|
|
/* ....... AT THIS POINT WE HAVE DETERMINED THAT THERE WILL BE AN EXTREMUM */ |
|
4734
|
|
|
|
|
|
|
/* ON (X(K),X(K+1)), WHERE K=I OR I-1, AND HAVE SET ARRAY WTAVE-- */ |
|
4735
|
|
|
|
|
|
|
/* WTAVE(1) IS A WEIGHTED AVERAGE OF SLOPE(K-1) AND SLOPE(K), */ |
|
4736
|
|
|
|
|
|
|
/* IF K.GT.1 */ |
|
4737
|
|
|
|
|
|
|
/* WTAVE(2) IS A WEIGHTED AVERAGE OF SLOPE(K) AND SLOPE(K+1), */ |
|
4738
|
|
|
|
|
|
|
/* IF K.LT.N-1 */ |
|
4739
|
|
|
|
|
|
|
slmax = PDL_ABS($slope(nless1=>k-1)); |
|
4740
|
|
|
|
|
|
|
if (k > 1) { |
|
4741
|
|
|
|
|
|
|
/* Computing MAX */ |
|
4742
|
|
|
|
|
|
|
slmax = PDLMAX(slmax,PDL_ABS($slope(nless1=>k-2))); |
|
4743
|
|
|
|
|
|
|
} |
|
4744
|
|
|
|
|
|
|
if (k < nless1) { |
|
4745
|
|
|
|
|
|
|
/* Computing MAX */ |
|
4746
|
|
|
|
|
|
|
slmax = PDLMAX(slmax,PDL_ABS($slope(nless1=>k))); |
|
4747
|
|
|
|
|
|
|
} |
|
4748
|
|
|
|
|
|
|
if (k > 1) { |
|
4749
|
|
|
|
|
|
|
del[0] = $slope(nless1=>k-2) / slmax; |
|
4750
|
|
|
|
|
|
|
} |
|
4751
|
|
|
|
|
|
|
del[1] = $slope(nless1=>k-1) / slmax; |
|
4752
|
|
|
|
|
|
|
if (k < nless1) { |
|
4753
|
|
|
|
|
|
|
del[2] = $slope(nless1=>k) / slmax; |
|
4754
|
|
|
|
|
|
|
} |
|
4755
|
|
|
|
|
|
|
if (k > 1 && k < nless1) { |
|
4756
|
|
|
|
|
|
|
/* NORMAL CASE -- EXTREMUM IS NOT IN A BOUNDARY INTERVAL. */ |
|
4757
|
|
|
|
|
|
|
fact = fudge * PDL_ABS(del[2] * (del[0] - del[1]) * (wtave[1] / slmax)); |
|
4758
|
|
|
|
|
|
|
$d(n=>k-1) += PDLMIN(fact,1.) * (wtave[0] - $d(n=>k-1)); |
|
4759
|
|
|
|
|
|
|
fact = fudge * PDL_ABS(del[0] * (del[2] - del[1]) * (wtave[0] / slmax)); |
|
4760
|
|
|
|
|
|
|
$d(n=>k) += PDLMIN(fact,1.) * (wtave[1] - $d(n=>k)); |
|
4761
|
|
|
|
|
|
|
} else { |
|
4762
|
|
|
|
|
|
|
/* SPECIAL CASE K=1 (WHICH CAN OCCUR ONLY IF I=2) OR */ |
|
4763
|
|
|
|
|
|
|
/* K=NLESS1 (WHICH CAN OCCUR ONLY IF I=NLESS1). */ |
|
4764
|
|
|
|
|
|
|
fact = fudge * PDL_ABS(del[1]); |
|
4765
|
|
|
|
|
|
|
$d(n=>nless1) = PDLMIN(fact,1.) * wtave[nless1+1 - k]; |
|
4766
|
|
|
|
|
|
|
/* NOTE THAT I-K+1 = 1 IF K=I (=NLESS1), */ |
|
4767
|
|
|
|
|
|
|
/* I-K+1 = 2 IF K=I-1(=1). */ |
|
4768
|
|
|
|
|
|
|
} |
|
4769
|
|
|
|
|
|
|
/* ....... ADJUST IF NECESSARY TO LIMIT EXCURSIONS FROM DATA. */ |
|
4770
|
|
|
|
|
|
|
if ($mflag() <= 0.) { |
|
4771
|
|
|
|
|
|
|
continue; |
|
4772
|
|
|
|
|
|
|
} |
|
4773
|
|
|
|
|
|
|
dfloc = $h(nless1=>k-1) * PDL_ABS($slope(nless1=>k-1)); |
|
4774
|
|
|
|
|
|
|
if (k > 1) { |
|
4775
|
|
|
|
|
|
|
/* Computing MAX */ |
|
4776
|
|
|
|
|
|
|
dfloc = PDLMAX(dfloc,$h(nless1=>k-2) * PDL_ABS($slope(nless1=>k-2))); |
|
4777
|
|
|
|
|
|
|
} |
|
4778
|
|
|
|
|
|
|
if (k < nless1) { |
|
4779
|
|
|
|
|
|
|
/* Computing MAX */ |
|
4780
|
|
|
|
|
|
|
dfloc = PDLMAX(dfloc,$h(nless1=>k) * PDL_ABS($slope(nless1=>k))); |
|
4781
|
|
|
|
|
|
|
} |
|
4782
|
|
|
|
|
|
|
dfmx = $mflag() * dfloc; |
|
4783
|
|
|
|
|
|
|
PDL_Indx indx = nless1 - k; |
|
4784
|
|
|
|
|
|
|
/* INDX = 1 IF K=I, 2 IF K=I-1. */ |
|
4785
|
|
|
|
|
|
|
/* --------------------------------------------------------------- */ |
|
4786
|
|
|
|
|
|
|
do { /* inline dpchsw */ |
|
4787
|
|
|
|
|
|
|
/* NOTATION AND GENERAL REMARKS. */ |
|
4788
|
|
|
|
|
|
|
/* RHO IS THE RATIO OF THE DATA SLOPE TO THE DERIVATIVE BEING TESTED. */ |
|
4789
|
|
|
|
|
|
|
/* LAMBDA IS THE RATIO OF D2 TO D1. */ |
|
4790
|
|
|
|
|
|
|
/* THAT = T-HAT(RHO) IS THE NORMALIZED LOCATION OF THE EXTREMUM. */ |
|
4791
|
|
|
|
|
|
|
/* PHI IS THE NORMALIZED VALUE OF P(X)-F1 AT X = XHAT = X-HAT(RHO), */ |
|
4792
|
|
|
|
|
|
|
/* WHERE THAT = (XHAT - X1)/H . */ |
|
4793
|
|
|
|
|
|
|
/* THAT IS, P(XHAT)-F1 = D*H*PHI, WHERE D=D1 OR D2. */ |
|
4794
|
|
|
|
|
|
|
/* SIMILARLY, P(XHAT)-F2 = D*H*(PHI-RHO) . */ |
|
4795
|
|
|
|
|
|
|
/* Local variables */ |
|
4796
|
|
|
|
|
|
|
$GENERIC() cp, nu, phi, rho, hphi, that, sigma, small; |
|
4797
|
|
|
|
|
|
|
$GENERIC() lambda, radcal; |
|
4798
|
|
|
|
|
|
|
$GENERIC() d1 = $d(n=>k-1), d2 = $d(n=>k), h2 = $h(nless1=>k-1), slope2 = $slope(nless1=>k-1); |
|
4799
|
|
|
|
|
|
|
/* Initialized data */ |
|
4800
|
|
|
|
|
|
|
static const $GENERIC() fact = 100.; |
|
4801
|
|
|
|
|
|
|
/* THIRD SHOULD BE SLIGHTLY LESS THAN 1/3. */ |
|
4802
|
|
|
|
|
|
|
static const $GENERIC() third = .33333; |
|
4803
|
|
|
|
|
|
|
/* SMALL SHOULD BE A FEW ORDERS OF MAGNITUDE GREATER THAN MACHEPS. */ |
|
4804
|
|
|
|
|
|
|
small = fact * d1mach; |
|
4805
|
|
|
|
|
|
|
/* DO MAIN CALCULATION. */ |
|
4806
|
|
|
|
|
|
|
if (d1 == 0.) { |
|
4807
|
|
|
|
|
|
|
/* SPECIAL CASE -- D1.EQ.ZERO . */ |
|
4808
|
|
|
|
|
|
|
/* IF D2 IS ALSO ZERO, THIS ROUTINE SHOULD NOT HAVE BEEN CALLED. */ |
|
4809
|
|
|
|
|
|
|
if (d2 == 0.) { |
|
4810
|
|
|
|
|
|
|
$ierr() = -1; |
|
4811
|
|
|
|
|
|
|
$CROAK("D1 AND/OR D2 INVALID"); |
|
4812
|
|
|
|
|
|
|
} |
|
4813
|
|
|
|
|
|
|
rho = slope2 / d2; |
|
4814
|
|
|
|
|
|
|
/* EXTREMUM IS OUTSIDE INTERVAL WHEN RHO .GE. 1/3 . */ |
|
4815
|
|
|
|
|
|
|
if (rho >= third) { |
|
4816
|
|
|
|
|
|
|
$ierr() = 0; break; |
|
4817
|
|
|
|
|
|
|
} |
|
4818
|
|
|
|
|
|
|
that = 2. * (3. * rho - 1.) / (3. * (2. * rho - 1.)); |
|
4819
|
|
|
|
|
|
|
/* Computing 2nd power */ |
|
4820
|
|
|
|
|
|
|
phi = that * that * ((3. * rho - 1.) / 3.); |
|
4821
|
|
|
|
|
|
|
/* CONVERT TO DISTANCE FROM F2 IF IEXTRM.NE.1 . */ |
|
4822
|
|
|
|
|
|
|
if (indx != 3) { |
|
4823
|
|
|
|
|
|
|
phi -= rho; |
|
4824
|
|
|
|
|
|
|
} |
|
4825
|
|
|
|
|
|
|
/* TEST FOR EXCEEDING LIMIT, AND ADJUST ACCORDINGLY. */ |
|
4826
|
|
|
|
|
|
|
hphi = h2 * PDL_ABS(phi); |
|
4827
|
|
|
|
|
|
|
if (hphi * PDL_ABS(d2) > dfmx) { |
|
4828
|
|
|
|
|
|
|
/* AT THIS POINT, HPHI.GT.0, SO DIVIDE IS OK. */ |
|
4829
|
|
|
|
|
|
|
d2 = $SIGN(dfmx / hphi, d2); |
|
4830
|
|
|
|
|
|
|
} |
|
4831
|
|
|
|
|
|
|
} else { |
|
4832
|
|
|
|
|
|
|
rho = slope2 / d1; |
|
4833
|
|
|
|
|
|
|
lambda = -(d2) / d1; |
|
4834
|
|
|
|
|
|
|
if (d2 == 0.) { |
|
4835
|
|
|
|
|
|
|
/* SPECIAL CASE -- D2.EQ.ZERO . */ |
|
4836
|
|
|
|
|
|
|
/* EXTREMUM IS OUTSIDE INTERVAL WHEN RHO .GE. 1/3 . */ |
|
4837
|
|
|
|
|
|
|
if (rho >= third) { |
|
4838
|
|
|
|
|
|
|
$ierr() = 0; break; |
|
4839
|
|
|
|
|
|
|
} |
|
4840
|
|
|
|
|
|
|
cp = 2. - 3. * rho; |
|
4841
|
|
|
|
|
|
|
nu = 1. - 2. * rho; |
|
4842
|
|
|
|
|
|
|
that = 1. / (3. * nu); |
|
4843
|
|
|
|
|
|
|
} else { |
|
4844
|
|
|
|
|
|
|
if (lambda <= 0.) { |
|
4845
|
|
|
|
|
|
|
$ierr() = -1; |
|
4846
|
|
|
|
|
|
|
$CROAK("D1 AND/OR D2 INVALID"); |
|
4847
|
|
|
|
|
|
|
} |
|
4848
|
|
|
|
|
|
|
/* NORMAL CASE -- D1 AND D2 BOTH NONZERO, OPPOSITE SIGNS. */ |
|
4849
|
|
|
|
|
|
|
nu = 1. - lambda - 2. * rho; |
|
4850
|
|
|
|
|
|
|
sigma = 1. - rho; |
|
4851
|
|
|
|
|
|
|
cp = nu + sigma; |
|
4852
|
|
|
|
|
|
|
if (PDL_ABS(nu) > small) { |
|
4853
|
|
|
|
|
|
|
/* Computing 2nd power */ |
|
4854
|
|
|
|
|
|
|
radcal = (nu - (2. * rho + 1.)) * nu + sigma * sigma; |
|
4855
|
|
|
|
|
|
|
if (radcal < 0.) { |
|
4856
|
|
|
|
|
|
|
$ierr() = -2; |
|
4857
|
|
|
|
|
|
|
$CROAK("NEGATIVE RADICAL"); |
|
4858
|
|
|
|
|
|
|
} |
|
4859
|
|
|
|
|
|
|
that = (cp - sqrt(radcal)) / (3. * nu); |
|
4860
|
|
|
|
|
|
|
} else { |
|
4861
|
|
|
|
|
|
|
that = 1. / (2. * sigma); |
|
4862
|
|
|
|
|
|
|
} |
|
4863
|
|
|
|
|
|
|
} |
|
4864
|
|
|
|
|
|
|
phi = that * ((nu * that - cp) * that + 1.); |
|
4865
|
|
|
|
|
|
|
/* CONVERT TO DISTANCE FROM F2 IF IEXTRM.NE.1 . */ |
|
4866
|
|
|
|
|
|
|
if (indx != 3) { |
|
4867
|
|
|
|
|
|
|
phi -= rho; |
|
4868
|
|
|
|
|
|
|
} |
|
4869
|
|
|
|
|
|
|
/* TEST FOR EXCEEDING LIMIT, AND ADJUST ACCORDINGLY. */ |
|
4870
|
|
|
|
|
|
|
hphi = h2 * PDL_ABS(phi); |
|
4871
|
|
|
|
|
|
|
if (hphi * PDL_ABS(d1) > dfmx) { |
|
4872
|
|
|
|
|
|
|
/* AT THIS POINT, HPHI.GT.0, SO DIVIDE IS OK. */ |
|
4873
|
|
|
|
|
|
|
d1 = $SIGN(dfmx / hphi, d1); |
|
4874
|
|
|
|
|
|
|
d2 = -lambda * d1; |
|
4875
|
|
|
|
|
|
|
} |
|
4876
|
|
|
|
|
|
|
} |
|
4877
|
|
|
|
|
|
|
$ierr() = 0; |
|
4878
|
|
|
|
|
|
|
} while (0); /* end inline dpchsw */ |
|
4879
|
|
|
|
|
|
|
/* --------------------------------------------------------------- */ |
|
4880
|
|
|
|
|
|
|
if ($ierr() != 0) { |
|
4881
|
|
|
|
|
|
|
break; |
|
4882
|
|
|
|
|
|
|
} |
|
4883
|
|
|
|
|
|
|
%} /* ....... END OF SEGMENT LOOP. */ |
|
4884
|
|
|
|
|
|
|
} while (0); /* end inline dpchcs */ |
|
4885
|
|
|
|
|
|
|
} |
|
4886
|
|
|
|
|
|
|
} |
|
4887
|
|
|
|
|
|
|
/* SET END CONDITIONS. */ |
|
4888
|
|
|
|
|
|
|
if (ibeg == 0 && iend == 0) |
|
4889
|
|
|
|
|
|
|
continue; |
|
4890
|
|
|
|
|
|
|
/* ------------------------------------------------------- */ |
|
4891
|
|
|
|
|
|
|
do { /* inline dpchce */ |
|
4892
|
|
|
|
|
|
|
/* Local variables */ |
|
4893
|
|
|
|
|
|
|
PDL_Indx j, k, ibeg = $ic(two=>0), iend = $ic(two=>1); |
|
4894
|
|
|
|
|
|
|
$GENERIC() stemp[3], xtemp[4]; |
|
4895
|
|
|
|
|
|
|
/* SET TO DEFAULT BOUNDARY CONDITIONS IF N IS TOO SMALL. */ |
|
4896
|
|
|
|
|
|
|
if (PDL_ABS(ibeg) > n) |
|
4897
|
|
|
|
|
|
|
ibeg = 0; |
|
4898
|
|
|
|
|
|
|
if (PDL_ABS(iend) > n) |
|
4899
|
|
|
|
|
|
|
iend = 0; |
|
4900
|
|
|
|
|
|
|
/* TREAT BEGINNING BOUNDARY CONDITION. */ |
|
4901
|
|
|
|
|
|
|
if (ibeg != 0) { |
|
4902
|
|
|
|
|
|
|
k = PDL_ABS(ibeg); |
|
4903
|
|
|
|
|
|
|
if (k == 1) { |
|
4904
|
|
|
|
|
|
|
/* BOUNDARY VALUE PROVIDED. */ |
|
4905
|
|
|
|
|
|
|
$d(n=>0) = $vc(two=>0); |
|
4906
|
|
|
|
|
|
|
} else if (k == 2) { |
|
4907
|
|
|
|
|
|
|
/* BOUNDARY SECOND DERIVATIVE PROVIDED. */ |
|
4908
|
|
|
|
|
|
|
$d(n=>0) = 0.5 * (3. * $slope(nless1=>0) - $d(n=>1) - 0.5 * $vc(two=>0) * $h(nless1=>0)); |
|
4909
|
|
|
|
|
|
|
} else if (k < 5) { |
|
4910
|
|
|
|
|
|
|
/* USE K-POINT DERIVATIVE FORMULA. */ |
|
4911
|
|
|
|
|
|
|
/* PICK UP FIRST K POINTS, IN REVERSE ORDER. */ |
|
4912
|
|
|
|
|
|
|
for (j = 0; j < k; ++j) { |
|
4913
|
|
|
|
|
|
|
PDL_Indx index = k - j; |
|
4914
|
|
|
|
|
|
|
/* INDEX RUNS FROM K DOWN TO 1. */ |
|
4915
|
|
|
|
|
|
|
xtemp[j] = $x(n=>index+1); |
|
4916
|
|
|
|
|
|
|
if (j < k-1) { |
|
4917
|
|
|
|
|
|
|
stemp[j] = $slope(nless1=>index); |
|
4918
|
|
|
|
|
|
|
} |
|
4919
|
|
|
|
|
|
|
} |
|
4920
|
|
|
|
|
|
|
/* ----------------------------- */ |
|
4921
|
|
|
|
|
|
|
$PCHDF(k, xtemp, stemp, $d(n=>0)); |
|
4922
|
|
|
|
|
|
|
/* ----------------------------- */ |
|
4923
|
|
|
|
|
|
|
} else { |
|
4924
|
|
|
|
|
|
|
/* USE 'NOT A KNOT' CONDITION. */ |
|
4925
|
|
|
|
|
|
|
$d(n=>0) = (3. * ($h(nless1=>0) * $slope(nless1=>1) + $h(nless1=>1) * $slope(nless1=>0)) - |
|
4926
|
|
|
|
|
|
|
2. * ($h(nless1=>0) + $h(nless1=>1)) * $d(n=>1) - $h(nless1=>0) * $d(n=>2)) / $h(nless1=>1); |
|
4927
|
|
|
|
|
|
|
} |
|
4928
|
|
|
|
|
|
|
/* CHECK D(1,1) FOR COMPATIBILITY WITH MONOTONICITY. */ |
|
4929
|
|
|
|
|
|
|
if (ibeg <= 0) { |
|
4930
|
|
|
|
|
|
|
if ($slope(nless1=>0) == 0.) { |
|
4931
|
|
|
|
|
|
|
if ($d(n=>0) != 0.) { |
|
4932
|
|
|
|
|
|
|
$d(n=>0) = 0.; |
|
4933
|
|
|
|
|
|
|
++($ierr()); |
|
4934
|
|
|
|
|
|
|
} |
|
4935
|
|
|
|
|
|
|
} else if ($PCHST($d(n=>0), $slope(nless1=>0)) < 0.) { |
|
4936
|
|
|
|
|
|
|
$d(n=>0) = 0.; |
|
4937
|
|
|
|
|
|
|
++($ierr()); |
|
4938
|
|
|
|
|
|
|
} else if (PDL_ABS($d(n=>0)) > 3. * PDL_ABS($slope(nless1=>0))) { |
|
4939
|
|
|
|
|
|
|
$d(n=>0) = 3. * $slope(nless1=>0); |
|
4940
|
|
|
|
|
|
|
++($ierr()); |
|
4941
|
|
|
|
|
|
|
} |
|
4942
|
|
|
|
|
|
|
} |
|
4943
|
|
|
|
|
|
|
} |
|
4944
|
|
|
|
|
|
|
/* TREAT END BOUNDARY CONDITION. */ |
|
4945
|
|
|
|
|
|
|
if (iend == 0) |
|
4946
|
|
|
|
|
|
|
break; |
|
4947
|
|
|
|
|
|
|
k = PDL_ABS(iend); |
|
4948
|
|
|
|
|
|
|
if (k == 1) { |
|
4949
|
|
|
|
|
|
|
/* BOUNDARY VALUE PROVIDED. */ |
|
4950
|
|
|
|
|
|
|
$d(n=>n-1) = $vc(two=>1); |
|
4951
|
|
|
|
|
|
|
} else if (k == 2) { |
|
4952
|
|
|
|
|
|
|
/* BOUNDARY SECOND DERIVATIVE PROVIDED. */ |
|
4953
|
|
|
|
|
|
|
$d(n=>n-1) = 0.5 * (3. * $slope(nless1=>n-2) - $d(n=>n-2) |
|
4954
|
|
|
|
|
|
|
+ 0.5 * $vc(two=>1) * $h(nless1=>n-2)); |
|
4955
|
|
|
|
|
|
|
} else if (k < 5) { |
|
4956
|
|
|
|
|
|
|
/* USE K-POINT DERIVATIVE FORMULA. */ |
|
4957
|
|
|
|
|
|
|
/* PICK UP LAST K POINTS. */ |
|
4958
|
|
|
|
|
|
|
for (j = 0; j < k; ++j) { |
|
4959
|
|
|
|
|
|
|
PDL_Indx index = n - k + j; |
|
4960
|
|
|
|
|
|
|
/* INDEX RUNS FROM N+1-K UP TO N. */ |
|
4961
|
|
|
|
|
|
|
xtemp[j] = $x(n=>index); |
|
4962
|
|
|
|
|
|
|
if (j < k-1) { |
|
4963
|
|
|
|
|
|
|
stemp[j] = $slope(nless1=>index); |
|
4964
|
|
|
|
|
|
|
} |
|
4965
|
|
|
|
|
|
|
} |
|
4966
|
|
|
|
|
|
|
/* ----------------------------- */ |
|
4967
|
|
|
|
|
|
|
$PCHDF(k, xtemp, stemp, $d(n=>n-1)); |
|
4968
|
|
|
|
|
|
|
/* ----------------------------- */ |
|
4969
|
|
|
|
|
|
|
} else { |
|
4970
|
|
|
|
|
|
|
/* USE 'NOT A KNOT' CONDITION. */ |
|
4971
|
|
|
|
|
|
|
$d(n=>n-1) = (3. * ($h(nless1=>n-2) * $slope(nless1=>n-3) + |
|
4972
|
|
|
|
|
|
|
$h(nless1=>n-3) * $slope(nless1=>n-2)) - 2. * ($h(nless1=>n-2) + $h(nless1=>n-3)) * |
|
4973
|
|
|
|
|
|
|
$d(n=>n-2) - $h(nless1=>n-2) * $d(n=>n-3)) / $h(nless1=>n-3); |
|
4974
|
|
|
|
|
|
|
} |
|
4975
|
|
|
|
|
|
|
if (iend > 0) |
|
4976
|
|
|
|
|
|
|
break; |
|
4977
|
|
|
|
|
|
|
/* CHECK D(1,N) FOR COMPATIBILITY WITH MONOTONICITY. */ |
|
4978
|
|
|
|
|
|
|
if ($slope(nless1=>n-2) == 0.) { |
|
4979
|
|
|
|
|
|
|
if ($d(n=>n-1) != 0.) { |
|
4980
|
|
|
|
|
|
|
$d(n=>n-1) = 0.; |
|
4981
|
|
|
|
|
|
|
$ierr() += 2; |
|
4982
|
|
|
|
|
|
|
} |
|
4983
|
|
|
|
|
|
|
} else if ($PCHST($d(n=>n-1), $slope(nless1=>n-2)) < 0.) { |
|
4984
|
|
|
|
|
|
|
$d(n=>n-1) = 0.; |
|
4985
|
|
|
|
|
|
|
$ierr() += 2; |
|
4986
|
|
|
|
|
|
|
} else if (PDL_ABS($d(n=>n-1)) > 3. * PDL_ABS($slope(nless1=>n-2))) { |
|
4987
|
|
|
|
|
|
|
$d(n=>n-1) = 3. * $slope(nless1=>n-2); |
|
4988
|
|
|
|
|
|
|
$ierr() += 2; |
|
4989
|
|
|
|
|
|
|
} |
|
4990
|
|
|
|
|
|
|
} while (0); /* end inlined dpchce */ |
|
4991
|
|
|
|
|
|
|
/* ------------------------------------------------------- */ |
|
4992
|
|
|
|
|
|
|
EOF |
|
4993
|
|
|
|
|
|
|
ParamDesc => { |
|
4994
|
|
|
|
|
|
|
ic => <<'EOF', |
|
4995
|
|
|
|
|
|
|
The first and second elements of C<$ic> determine the boundary |
|
4996
|
|
|
|
|
|
|
conditions at the start and end of the data respectively. |
|
4997
|
|
|
|
|
|
|
If the value is 0, then the default condition, as used by |
|
4998
|
|
|
|
|
|
|
L, is adopted. |
|
4999
|
|
|
|
|
|
|
If greater than zero, no adjustment for monotonicity is made, |
|
5000
|
|
|
|
|
|
|
otherwise if less than zero the derivative will be adjusted. |
|
5001
|
|
|
|
|
|
|
The allowed magnitudes for C are: |
|
5002
|
|
|
|
|
|
|
|
|
5003
|
|
|
|
|
|
|
=over |
|
5004
|
|
|
|
|
|
|
|
|
5005
|
|
|
|
|
|
|
=item * |
|
5006
|
|
|
|
|
|
|
|
|
5007
|
|
|
|
|
|
|
1 if first derivative at C is given in C. |
|
5008
|
|
|
|
|
|
|
|
|
5009
|
|
|
|
|
|
|
=item * |
|
5010
|
|
|
|
|
|
|
|
|
5011
|
|
|
|
|
|
|
2 if second derivative at C is given in C. |
|
5012
|
|
|
|
|
|
|
|
|
5013
|
|
|
|
|
|
|
=item * |
|
5014
|
|
|
|
|
|
|
|
|
5015
|
|
|
|
|
|
|
3 to use the 3-point difference formula for C. |
|
5016
|
|
|
|
|
|
|
(Reverts to the default b.c. if C 3>) |
|
5017
|
|
|
|
|
|
|
|
|
5018
|
|
|
|
|
|
|
=item * |
|
5019
|
|
|
|
|
|
|
|
|
5020
|
|
|
|
|
|
|
4 to use the 4-point difference formula for C. |
|
5021
|
|
|
|
|
|
|
(Reverts to the default b.c. if C 4>) |
|
5022
|
|
|
|
|
|
|
|
|
5023
|
|
|
|
|
|
|
=item * |
|
5024
|
|
|
|
|
|
|
|
|
5025
|
|
|
|
|
|
|
5 to set C so that the second derivative is |
|
5026
|
|
|
|
|
|
|
continuous at C. |
|
5027
|
|
|
|
|
|
|
(Reverts to the default b.c. if C 4>) |
|
5028
|
|
|
|
|
|
|
This option is somewhat analogous to the "not a knot" |
|
5029
|
|
|
|
|
|
|
boundary condition provided by DPCHSP. |
|
5030
|
|
|
|
|
|
|
|
|
5031
|
|
|
|
|
|
|
=back |
|
5032
|
|
|
|
|
|
|
|
|
5033
|
|
|
|
|
|
|
The values for C are the same as above, except that |
|
5034
|
|
|
|
|
|
|
the first-derivative value is stored in C for cases 1 and 2. |
|
5035
|
|
|
|
|
|
|
The values of C<$vc> need only be set if options 1 or 2 are chosen |
|
5036
|
|
|
|
|
|
|
for C<$ic>. NOTES: |
|
5037
|
|
|
|
|
|
|
|
|
5038
|
|
|
|
|
|
|
=over |
|
5039
|
|
|
|
|
|
|
|
|
5040
|
|
|
|
|
|
|
=item * |
|
5041
|
|
|
|
|
|
|
|
|
5042
|
|
|
|
|
|
|
Only in case C<$ic(n)> E 0 is it guaranteed that the interpolant |
|
5043
|
|
|
|
|
|
|
will be monotonic in the first interval. If the returned value of |
|
5044
|
|
|
|
|
|
|
D(start_or_end) lies between zero and 3*SLOPE(start_or_end), the |
|
5045
|
|
|
|
|
|
|
interpolant will be monotonic. This is B checked if C<$ic(n)> |
|
5046
|
|
|
|
|
|
|
E 0. |
|
5047
|
|
|
|
|
|
|
|
|
5048
|
|
|
|
|
|
|
=item * |
|
5049
|
|
|
|
|
|
|
|
|
5050
|
|
|
|
|
|
|
If C<$ic(n)> E 0 and D(0) had to be changed to achieve monotonicity, |
|
5051
|
|
|
|
|
|
|
a warning error is returned. |
|
5052
|
|
|
|
|
|
|
|
|
5053
|
|
|
|
|
|
|
=back |
|
5054
|
|
|
|
|
|
|
|
|
5055
|
|
|
|
|
|
|
Set C<$mflag = 0> if interpolant is required to be monotonic in |
|
5056
|
|
|
|
|
|
|
each interval, regardless of monotonicity of data. This causes C<$d> to be |
|
5057
|
|
|
|
|
|
|
set to 0 at all switch points. NOTES: |
|
5058
|
|
|
|
|
|
|
|
|
5059
|
|
|
|
|
|
|
=over |
|
5060
|
|
|
|
|
|
|
|
|
5061
|
|
|
|
|
|
|
=item * |
|
5062
|
|
|
|
|
|
|
|
|
5063
|
|
|
|
|
|
|
This will cause D to be set to zero at all switch points, thus |
|
5064
|
|
|
|
|
|
|
forcing extrema there. |
|
5065
|
|
|
|
|
|
|
|
|
5066
|
|
|
|
|
|
|
=item * |
|
5067
|
|
|
|
|
|
|
|
|
5068
|
|
|
|
|
|
|
The result of using this option with the default boundary conditions |
|
5069
|
|
|
|
|
|
|
will be identical to using DPCHIM, but will generally cost more |
|
5070
|
|
|
|
|
|
|
compute time. This option is provided only to facilitate comparison |
|
5071
|
|
|
|
|
|
|
of different switch and/or boundary conditions. |
|
5072
|
|
|
|
|
|
|
|
|
5073
|
|
|
|
|
|
|
=back |
|
5074
|
|
|
|
|
|
|
EOF |
|
5075
|
|
|
|
|
|
|
vc => 'See ic for details', |
|
5076
|
|
|
|
|
|
|
mflag => <<'EOF', |
|
5077
|
|
|
|
|
|
|
Set to non-zero to |
|
5078
|
|
|
|
|
|
|
use a formula based on the 3-point difference formula at switch |
|
5079
|
|
|
|
|
|
|
points. If C<$mflag E 0>, then the interpolant at switch points |
|
5080
|
|
|
|
|
|
|
is forced to not deviate from the data by more than C<$mflag*dfloc>, |
|
5081
|
|
|
|
|
|
|
where C is the maximum of the change of C<$f> on this interval |
|
5082
|
|
|
|
|
|
|
and its two immediate neighbours. |
|
5083
|
|
|
|
|
|
|
If C<$mflag E 0>, no such control is to be imposed. |
|
5084
|
|
|
|
|
|
|
EOF |
|
5085
|
|
|
|
|
|
|
x => <<'EOF', |
|
5086
|
|
|
|
|
|
|
array of independent variable values. The |
|
5087
|
|
|
|
|
|
|
elements of X must be strictly increasing: |
|
5088
|
|
|
|
|
|
|
|
|
5089
|
|
|
|
|
|
|
X(I-1) .LT. X(I), I = 2(1)N. |
|
5090
|
|
|
|
|
|
|
|
|
5091
|
|
|
|
|
|
|
(Error return if not.) |
|
5092
|
|
|
|
|
|
|
EOF |
|
5093
|
|
|
|
|
|
|
f => <<'EOF', |
|
5094
|
|
|
|
|
|
|
array of dependent variable values to be |
|
5095
|
|
|
|
|
|
|
interpolated. F(I) is value corresponding to X(I). |
|
5096
|
|
|
|
|
|
|
EOF |
|
5097
|
|
|
|
|
|
|
d => <<'EOF', |
|
5098
|
|
|
|
|
|
|
array of derivative values at the data |
|
5099
|
|
|
|
|
|
|
points. These values will determine a monotone cubic |
|
5100
|
|
|
|
|
|
|
Hermite function on each subinterval on which the data |
|
5101
|
|
|
|
|
|
|
are monotonic, except possibly adjacent to switches in |
|
5102
|
|
|
|
|
|
|
monotonicity. The value corresponding to X(I) is stored in D(I). |
|
5103
|
|
|
|
|
|
|
No other entries in D are changed. |
|
5104
|
|
|
|
|
|
|
EOF |
|
5105
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
5106
|
|
|
|
|
|
|
Error status: |
|
5107
|
|
|
|
|
|
|
|
|
5108
|
|
|
|
|
|
|
=over |
|
5109
|
|
|
|
|
|
|
|
|
5110
|
|
|
|
|
|
|
=item * |
|
5111
|
|
|
|
|
|
|
|
|
5112
|
|
|
|
|
|
|
0 if successful. |
|
5113
|
|
|
|
|
|
|
|
|
5114
|
|
|
|
|
|
|
=item * |
|
5115
|
|
|
|
|
|
|
|
|
5116
|
|
|
|
|
|
|
1 if C 0> and C had to be adjusted for |
|
5117
|
|
|
|
|
|
|
monotonicity. |
|
5118
|
|
|
|
|
|
|
|
|
5119
|
|
|
|
|
|
|
=item * |
|
5120
|
|
|
|
|
|
|
|
|
5121
|
|
|
|
|
|
|
2 if C 0> and C had to be adjusted |
|
5122
|
|
|
|
|
|
|
for monotonicity. |
|
5123
|
|
|
|
|
|
|
|
|
5124
|
|
|
|
|
|
|
=item * |
|
5125
|
|
|
|
|
|
|
|
|
5126
|
|
|
|
|
|
|
3 if both 1 and 2 are true. |
|
5127
|
|
|
|
|
|
|
|
|
5128
|
|
|
|
|
|
|
=item * |
|
5129
|
|
|
|
|
|
|
|
|
5130
|
|
|
|
|
|
|
-1 if C 2>. |
|
5131
|
|
|
|
|
|
|
|
|
5132
|
|
|
|
|
|
|
=item * |
|
5133
|
|
|
|
|
|
|
|
|
5134
|
|
|
|
|
|
|
-3 if C<$x> is not strictly increasing. |
|
5135
|
|
|
|
|
|
|
|
|
5136
|
|
|
|
|
|
|
=item * |
|
5137
|
|
|
|
|
|
|
|
|
5138
|
|
|
|
|
|
|
-4 if C 5>. |
|
5139
|
|
|
|
|
|
|
|
|
5140
|
|
|
|
|
|
|
=item * |
|
5141
|
|
|
|
|
|
|
|
|
5142
|
|
|
|
|
|
|
-5 if C 5>. |
|
5143
|
|
|
|
|
|
|
|
|
5144
|
|
|
|
|
|
|
=item * |
|
5145
|
|
|
|
|
|
|
|
|
5146
|
|
|
|
|
|
|
-6 if both -4 and -5 are true. |
|
5147
|
|
|
|
|
|
|
|
|
5148
|
|
|
|
|
|
|
=item * |
|
5149
|
|
|
|
|
|
|
|
|
5150
|
|
|
|
|
|
|
-7 if C 2*(n-1)>. |
|
5151
|
|
|
|
|
|
|
|
|
5152
|
|
|
|
|
|
|
=back |
|
5153
|
|
|
|
|
|
|
|
|
5154
|
|
|
|
|
|
|
(The D-array has not been changed in any of these cases.) |
|
5155
|
|
|
|
|
|
|
NOTE: The above errors are checked in the order listed, |
|
5156
|
|
|
|
|
|
|
and following arguments have B been validated. |
|
5157
|
|
|
|
|
|
|
EOF |
|
5158
|
|
|
|
|
|
|
}, |
|
5159
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
5160
|
|
|
|
|
|
|
=for ref |
|
5161
|
|
|
|
|
|
|
|
|
5162
|
|
|
|
|
|
|
Set derivatives needed to determine a piecewise monotone piecewise |
|
5163
|
|
|
|
|
|
|
cubic Hermite interpolant to given data. User control is available |
|
5164
|
|
|
|
|
|
|
over boundary conditions and/or treatment of points where monotonicity |
|
5165
|
|
|
|
|
|
|
switches direction. |
|
5166
|
|
|
|
|
|
|
|
|
5167
|
|
|
|
|
|
|
Calculate the derivatives needed to determine a piecewise monotone piecewise |
|
5168
|
|
|
|
|
|
|
cubic interpolant to the data given in (C<$x,$f>, |
|
5169
|
|
|
|
|
|
|
where C<$x> is strictly increasing). |
|
5170
|
|
|
|
|
|
|
Control over the boundary conditions is given by the |
|
5171
|
|
|
|
|
|
|
C<$ic> and C<$vc> ndarrays, and the value of C<$mflag> determines |
|
5172
|
|
|
|
|
|
|
the treatment of points where monotonicity switches |
|
5173
|
|
|
|
|
|
|
direction. A simpler, more restricted, interface is available |
|
5174
|
|
|
|
|
|
|
using L. |
|
5175
|
|
|
|
|
|
|
The resulting piecewise cubic Hermite function may be evaluated |
|
5176
|
|
|
|
|
|
|
by L or L. |
|
5177
|
|
|
|
|
|
|
|
|
5178
|
|
|
|
|
|
|
References: |
|
5179
|
|
|
|
|
|
|
|
|
5180
|
|
|
|
|
|
|
1. F. N. Fritsch, Piecewise Cubic Hermite Interpolation |
|
5181
|
|
|
|
|
|
|
Package, Report UCRL-87285, Lawrence Livermore National |
|
5182
|
|
|
|
|
|
|
Laboratory, July 1982. [Poster presented at the |
|
5183
|
|
|
|
|
|
|
SIAM 30th Anniversary Meeting, 19-23 July 1982.] |
|
5184
|
|
|
|
|
|
|
|
|
5185
|
|
|
|
|
|
|
2. F. N. Fritsch and J. Butland, A method for constructing |
|
5186
|
|
|
|
|
|
|
local monotone piecewise cubic interpolants, SIAM |
|
5187
|
|
|
|
|
|
|
Journal on Scientific and Statistical Computing 5, 2 |
|
5188
|
|
|
|
|
|
|
(June 1984), pp. 300-304. |
|
5189
|
|
|
|
|
|
|
|
|
5190
|
|
|
|
|
|
|
3. F. N. Fritsch and R. E. Carlson, Monotone piecewise |
|
5191
|
|
|
|
|
|
|
cubic interpolation, SIAM Journal on Numerical |
|
5192
|
|
|
|
|
|
|
Analysis 17, 2 (April 1980), pp. 238-246. |
|
5193
|
|
|
|
|
|
|
EOF |
|
5194
|
|
|
|
|
|
|
); |
|
5195
|
|
|
|
|
|
|
|
|
5196
|
|
|
|
|
|
|
pp_def('pchip_chsp', |
|
5197
|
|
|
|
|
|
|
Pars => 'sbyte ic(two=2); vc(two=2); x(n); f(n); |
|
5198
|
|
|
|
|
|
|
[o]d(n); indx [o]ierr(); |
|
5199
|
|
|
|
|
|
|
[t]dx(n); [t]dy_dx(n); |
|
5200
|
|
|
|
|
|
|
', |
|
5201
|
|
|
|
|
|
|
GenericTypes => $F, |
|
5202
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
5203
|
|
|
|
|
|
|
if ($SIZE(n) < 2) $CROAK("NUMBER OF DATA POINTS LESS THAN TWO"); |
|
5204
|
|
|
|
|
|
|
EOF |
|
5205
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
5206
|
|
|
|
|
|
|
/* SINGULAR SYSTEM. */ |
|
5207
|
|
|
|
|
|
|
/* *** THEORETICALLY, THIS CAN ONLY OCCUR IF SUCCESSIVE X-VALUES *** */ |
|
5208
|
|
|
|
|
|
|
/* *** ARE EQUAL, WHICH SHOULD ALREADY HAVE BEEN CAUGHT (IERR=-3). *** */ |
|
5209
|
|
|
|
|
|
|
#define dpchsp_singular(x, ind) \ |
|
5210
|
|
|
|
|
|
|
$ierr() = -8; $CROAK("SINGULAR LINEAR SYSTEM(" #x ") at %td", ind); |
|
5211
|
|
|
|
|
|
|
/* Local variables */ |
|
5212
|
|
|
|
|
|
|
$GENERIC() stemp[3], xtemp[4]; |
|
5213
|
|
|
|
|
|
|
PDL_Indx n = $SIZE(n), nm1 = n - 1; |
|
5214
|
|
|
|
|
|
|
/* VALIDITY-CHECK ARGUMENTS. */ |
|
5215
|
|
|
|
|
|
|
loop (n=1) %{ |
|
5216
|
|
|
|
|
|
|
if ($x() > $x(n=>n-1)) continue; |
|
5217
|
|
|
|
|
|
|
$ierr() = -1; |
|
5218
|
|
|
|
|
|
|
$CROAK("X-ARRAY NOT STRICTLY INCREASING"); |
|
5219
|
|
|
|
|
|
|
%} |
|
5220
|
|
|
|
|
|
|
PDL_Indx ibeg = $ic(two=>0), iend = $ic(two=>1), j; |
|
5221
|
|
|
|
|
|
|
$ierr() = 0; |
|
5222
|
|
|
|
|
|
|
if (PDL_ABS(ibeg) > 5) |
|
5223
|
|
|
|
|
|
|
--($ierr()); |
|
5224
|
|
|
|
|
|
|
if (PDL_ABS(iend) > 5) |
|
5225
|
|
|
|
|
|
|
$ierr() += -2; |
|
5226
|
|
|
|
|
|
|
if ($ierr() < 0) { |
|
5227
|
|
|
|
|
|
|
$ierr() += -3; |
|
5228
|
|
|
|
|
|
|
$CROAK("IC OUT OF RANGE"); |
|
5229
|
|
|
|
|
|
|
} |
|
5230
|
|
|
|
|
|
|
/* FUNCTION DEFINITION IS OK -- GO ON. */ |
|
5231
|
|
|
|
|
|
|
/* COMPUTE FIRST DIFFERENCES OF X SEQUENCE AND STORE IN WK(1,.). ALSO, */ |
|
5232
|
|
|
|
|
|
|
/* COMPUTE FIRST DIVIDED DIFFERENCE OF DATA AND STORE IN WK(2,.). */ |
|
5233
|
|
|
|
|
|
|
loop (n=1) %{ |
|
5234
|
|
|
|
|
|
|
$dx() = $x() - $x(n=>n-1); |
|
5235
|
|
|
|
|
|
|
$dy_dx() = ($f() - $f(n=>n-1)) / $dx(); |
|
5236
|
|
|
|
|
|
|
%} |
|
5237
|
|
|
|
|
|
|
/* SET TO DEFAULT BOUNDARY CONDITIONS IF N IS TOO SMALL. */ |
|
5238
|
|
|
|
|
|
|
if (ibeg > n) { |
|
5239
|
|
|
|
|
|
|
ibeg = 0; |
|
5240
|
|
|
|
|
|
|
} |
|
5241
|
|
|
|
|
|
|
if (iend > n) { |
|
5242
|
|
|
|
|
|
|
iend = 0; |
|
5243
|
|
|
|
|
|
|
} |
|
5244
|
|
|
|
|
|
|
/* SET UP FOR BOUNDARY CONDITIONS. */ |
|
5245
|
|
|
|
|
|
|
if (ibeg == 1 || ibeg == 2) { |
|
5246
|
|
|
|
|
|
|
$d(n=>0) = $vc(two=>0); |
|
5247
|
|
|
|
|
|
|
} else if (ibeg > 2) { |
|
5248
|
|
|
|
|
|
|
/* PICK UP FIRST IBEG POINTS, IN REVERSE ORDER. */ |
|
5249
|
|
|
|
|
|
|
for (j = 0; j < ibeg; ++j) { |
|
5250
|
|
|
|
|
|
|
PDL_Indx index = ibeg - j + 1; |
|
5251
|
|
|
|
|
|
|
/* INDEX RUNS FROM IBEG DOWN TO 1. */ |
|
5252
|
|
|
|
|
|
|
xtemp[j] = $x(n=>index); |
|
5253
|
|
|
|
|
|
|
if (j < ibeg-1) |
|
5254
|
|
|
|
|
|
|
stemp[j] = $dy_dx(n=>index); |
|
5255
|
|
|
|
|
|
|
} |
|
5256
|
|
|
|
|
|
|
/* -------------------------------- */ |
|
5257
|
|
|
|
|
|
|
$PCHDF(ibeg, xtemp, stemp, $d(n=>0)); |
|
5258
|
|
|
|
|
|
|
/* -------------------------------- */ |
|
5259
|
|
|
|
|
|
|
ibeg = 1; |
|
5260
|
|
|
|
|
|
|
} |
|
5261
|
|
|
|
|
|
|
if (iend == 1 || iend == 2) { |
|
5262
|
|
|
|
|
|
|
$d(n=>n-1) = $vc(two=>1); |
|
5263
|
|
|
|
|
|
|
} else if (iend > 2) { |
|
5264
|
|
|
|
|
|
|
/* PICK UP LAST IEND POINTS. */ |
|
5265
|
|
|
|
|
|
|
for (j = 0; j < iend; ++j) { |
|
5266
|
|
|
|
|
|
|
PDL_Indx index = n - iend + j; |
|
5267
|
|
|
|
|
|
|
/* INDEX RUNS FROM N+1-IEND UP TO N. */ |
|
5268
|
|
|
|
|
|
|
xtemp[j] = $x(n=>index); |
|
5269
|
|
|
|
|
|
|
if (j < iend-1) |
|
5270
|
|
|
|
|
|
|
stemp[j] = $dy_dx(n=>index+1); |
|
5271
|
|
|
|
|
|
|
} |
|
5272
|
|
|
|
|
|
|
/* -------------------------------- */ |
|
5273
|
|
|
|
|
|
|
$PCHDF(iend, xtemp, stemp, $d(n=>n-1)); |
|
5274
|
|
|
|
|
|
|
/* -------------------------------- */ |
|
5275
|
|
|
|
|
|
|
iend = 1; |
|
5276
|
|
|
|
|
|
|
} |
|
5277
|
|
|
|
|
|
|
/* --------------------( BEGIN CODING FROM CUBSPL )-------------------- */ |
|
5278
|
|
|
|
|
|
|
/* **** A TRIDIAGONAL LINEAR SYSTEM FOR THE UNKNOWN SLOPES S(J) OF */ |
|
5279
|
|
|
|
|
|
|
/* F AT X(J), J=1,...,N, IS GENERATED AND THEN SOLVED BY GAUSS ELIM- */ |
|
5280
|
|
|
|
|
|
|
/* INATION, WITH S(J) ENDING UP IN D(1,J), ALL J. */ |
|
5281
|
|
|
|
|
|
|
/* WK(1,.) AND WK(2,.) ARE USED FOR TEMPORARY STORAGE. */ |
|
5282
|
|
|
|
|
|
|
/* CONSTRUCT FIRST EQUATION FROM FIRST BOUNDARY CONDITION, OF THE FORM */ |
|
5283
|
|
|
|
|
|
|
/* WK(2,1)*S(1) + WK(1,1)*S(2) = D(1,1) */ |
|
5284
|
|
|
|
|
|
|
if (ibeg == 0) { |
|
5285
|
|
|
|
|
|
|
if (n == 2) { |
|
5286
|
|
|
|
|
|
|
/* NO CONDITION AT LEFT END AND N = 2. */ |
|
5287
|
|
|
|
|
|
|
$dy_dx(n=>0) = 1.; |
|
5288
|
|
|
|
|
|
|
$dx(n=>0) = 1.; |
|
5289
|
|
|
|
|
|
|
$d(n=>0) = 2. * $dy_dx(n=>1); |
|
5290
|
|
|
|
|
|
|
} else { |
|
5291
|
|
|
|
|
|
|
/* NOT-A-KNOT CONDITION AT LEFT END AND N .GT. 2. */ |
|
5292
|
|
|
|
|
|
|
$dy_dx(n=>0) = $dx(n=>2); |
|
5293
|
|
|
|
|
|
|
$dx(n=>0) = $dx(n=>1) + $dx(n=>2); |
|
5294
|
|
|
|
|
|
|
/* Computing 2nd power */ |
|
5295
|
|
|
|
|
|
|
$d(n=>0) = (($dx(n=>1) + 2. * $dx(n=>0)) * $dy_dx(n=>1) * $dx(n=>2) + $dx(n=>1) * |
|
5296
|
|
|
|
|
|
|
$dx(n=>1) * $dy_dx(n=>2)) / $dx(n=>0); |
|
5297
|
|
|
|
|
|
|
} |
|
5298
|
|
|
|
|
|
|
} else if (ibeg == 1) { |
|
5299
|
|
|
|
|
|
|
/* SLOPE PRESCRIBED AT LEFT END. */ |
|
5300
|
|
|
|
|
|
|
$dy_dx(n=>0) = 1.; |
|
5301
|
|
|
|
|
|
|
$dx(n=>0) = 0.; |
|
5302
|
|
|
|
|
|
|
} else { |
|
5303
|
|
|
|
|
|
|
/* SECOND DERIVATIVE PRESCRIBED AT LEFT END. */ |
|
5304
|
|
|
|
|
|
|
$dy_dx(n=>0) = 2.; |
|
5305
|
|
|
|
|
|
|
$dx(n=>0) = 1.; |
|
5306
|
|
|
|
|
|
|
$d(n=>0) = 3. * $dy_dx(n=>1) - 0.5 * $dx(n=>1) * $d(n=>0); |
|
5307
|
|
|
|
|
|
|
} |
|
5308
|
|
|
|
|
|
|
/* IF THERE ARE INTERIOR KNOTS, GENERATE THE CORRESPONDING EQUATIONS AND */ |
|
5309
|
|
|
|
|
|
|
/* CARRY OUT THE FORWARD PASS OF GAUSS ELIMINATION, AFTER WHICH THE J-TH */ |
|
5310
|
|
|
|
|
|
|
/* EQUATION READS WK(2,J)*S(J) + WK(1,J)*S(J+1) = D(1,J). */ |
|
5311
|
|
|
|
|
|
|
if (n > 2) { |
|
5312
|
|
|
|
|
|
|
loop (n=1:-1) %{ |
|
5313
|
|
|
|
|
|
|
if ($dy_dx(n=>n-1) == 0.) { |
|
5314
|
|
|
|
|
|
|
dpchsp_singular(1, n-1); |
|
5315
|
|
|
|
|
|
|
} |
|
5316
|
|
|
|
|
|
|
$GENERIC() g = -$dx(n=>n+1) / $dy_dx(n=>n-1); |
|
5317
|
|
|
|
|
|
|
$d() = g * $d(n=>n-1) + 3. * ($dx() * $dy_dx(n=>n+1) + |
|
5318
|
|
|
|
|
|
|
$dx(n=>n+1) * $dy_dx()); |
|
5319
|
|
|
|
|
|
|
$dy_dx() = g * $dx(n=>n-1) + 2. * ($dx() + $dx(n=>n+1)); |
|
5320
|
|
|
|
|
|
|
%} |
|
5321
|
|
|
|
|
|
|
} |
|
5322
|
|
|
|
|
|
|
/* CONSTRUCT LAST EQUATION FROM SECOND BOUNDARY CONDITION, OF THE FORM */ |
|
5323
|
|
|
|
|
|
|
/* (-G*WK(2,N-1))*S(N-1) + WK(2,N)*S(N) = D(1,N) */ |
|
5324
|
|
|
|
|
|
|
/* IF SLOPE IS PRESCRIBED AT RIGHT END, ONE CAN GO DIRECTLY TO BACK- */ |
|
5325
|
|
|
|
|
|
|
/* SUBSTITUTION, SINCE ARRAYS HAPPEN TO BE SET UP JUST RIGHT FOR IT */ |
|
5326
|
|
|
|
|
|
|
/* AT THIS POINT. */ |
|
5327
|
|
|
|
|
|
|
if (iend != 1) { |
|
5328
|
|
|
|
|
|
|
if (iend == 0 && n == 2 && ibeg == 0) { |
|
5329
|
|
|
|
|
|
|
/* NOT-A-KNOT AT RIGHT ENDPOINT AND AT LEFT ENDPOINT AND N = 2. */ |
|
5330
|
|
|
|
|
|
|
$d(n=>1) = $dy_dx(n=>1); |
|
5331
|
|
|
|
|
|
|
} else { |
|
5332
|
|
|
|
|
|
|
$GENERIC() g; |
|
5333
|
|
|
|
|
|
|
if (iend == 0) { |
|
5334
|
|
|
|
|
|
|
if (n == 2 || (n == 3 && ibeg == 0)) { |
|
5335
|
|
|
|
|
|
|
/* EITHER (N=3 AND NOT-A-KNOT ALSO AT LEFT) OR (N=2 AND *NOT* */ |
|
5336
|
|
|
|
|
|
|
/* NOT-A-KNOT AT LEFT END POINT). */ |
|
5337
|
|
|
|
|
|
|
$d(n=>n-1) = 2. * $dy_dx(n=>n-1); |
|
5338
|
|
|
|
|
|
|
$dy_dx(n=>n-1) = 1.; |
|
5339
|
|
|
|
|
|
|
if ($dy_dx(n=>n-2) == 0.) { |
|
5340
|
|
|
|
|
|
|
dpchsp_singular(2, n-2); |
|
5341
|
|
|
|
|
|
|
} |
|
5342
|
|
|
|
|
|
|
g = -1. / $dy_dx(n=>n-2); |
|
5343
|
|
|
|
|
|
|
} else { |
|
5344
|
|
|
|
|
|
|
/* NOT-A-KNOT AND N .GE. 3, AND EITHER N.GT.3 OR ALSO NOT-A- */ |
|
5345
|
|
|
|
|
|
|
/* KNOT AT LEFT END POINT. */ |
|
5346
|
|
|
|
|
|
|
g = $dx(n=>n-2) + $dx(n=>n-1); |
|
5347
|
|
|
|
|
|
|
/* DO NOT NEED TO CHECK FOLLOWING DENOMINATORS (X-DIFFERENCES). */ |
|
5348
|
|
|
|
|
|
|
/* Computing 2nd power */ |
|
5349
|
|
|
|
|
|
|
$GENERIC() dtmp = $dx(n=>n-1); |
|
5350
|
|
|
|
|
|
|
$d(n=>n-1) = (($dx(n=>n-1) + 2. * g) * $dy_dx(n=>n-1) * $dx(n=>n-2) + dtmp * dtmp * ($f(n=>n-2) - $f(n=>n-3)) / $dx(n=>n-2)) / g; |
|
5351
|
|
|
|
|
|
|
if ($dy_dx(n=>n-2) == 0.) { |
|
5352
|
|
|
|
|
|
|
dpchsp_singular(3, n-2); |
|
5353
|
|
|
|
|
|
|
} |
|
5354
|
|
|
|
|
|
|
g /= -$dy_dx(n=>n-2); |
|
5355
|
|
|
|
|
|
|
$dy_dx(n=>n-1) = $dx(n=>n-2); |
|
5356
|
|
|
|
|
|
|
} |
|
5357
|
|
|
|
|
|
|
} else { |
|
5358
|
|
|
|
|
|
|
/* SECOND DERIVATIVE PRESCRIBED AT RIGHT ENDPOINT. */ |
|
5359
|
|
|
|
|
|
|
$d(n=>n-1) = 3. * $dy_dx(n=>n-1) + 0.5 * $dx(n=>n-1) * $d(n=>n-1); |
|
5360
|
|
|
|
|
|
|
$dy_dx(n=>n-1) = 2.; |
|
5361
|
|
|
|
|
|
|
if ($dy_dx(n=>n-2) == 0.) { |
|
5362
|
|
|
|
|
|
|
dpchsp_singular(4, n-2); |
|
5363
|
|
|
|
|
|
|
} |
|
5364
|
|
|
|
|
|
|
g = -1. / $dy_dx(n=>n-2); |
|
5365
|
|
|
|
|
|
|
} |
|
5366
|
|
|
|
|
|
|
/* COMPLETE FORWARD PASS OF GAUSS ELIMINATION. */ |
|
5367
|
|
|
|
|
|
|
$dy_dx(n=>n-1) = g * $dx(n=>n-2) + $dy_dx(n=>n-1); |
|
5368
|
|
|
|
|
|
|
if ($dy_dx(n=>n-1) == 0.) { |
|
5369
|
|
|
|
|
|
|
dpchsp_singular(5, n-1); |
|
5370
|
|
|
|
|
|
|
} |
|
5371
|
|
|
|
|
|
|
$d(n=>n-1) = (g * $d(n=>n-2) + $d(n=>n-1)) / $dy_dx(n=>n-1); |
|
5372
|
|
|
|
|
|
|
} |
|
5373
|
|
|
|
|
|
|
} |
|
5374
|
|
|
|
|
|
|
/* CARRY OUT BACK SUBSTITUTION */ |
|
5375
|
|
|
|
|
|
|
loop (n=nm1-1::-1) %{ |
|
5376
|
|
|
|
|
|
|
if ($dy_dx() == 0.) { |
|
5377
|
|
|
|
|
|
|
dpchsp_singular(6, n); |
|
5378
|
|
|
|
|
|
|
} |
|
5379
|
|
|
|
|
|
|
$d() = ($d() - $dx() * $d(n=>n+1)) / $dy_dx(); |
|
5380
|
|
|
|
|
|
|
%} |
|
5381
|
|
|
|
|
|
|
/* --------------------( END CODING FROM CUBSPL )-------------------- */ |
|
5382
|
|
|
|
|
|
|
#undef dpchsp_singular |
|
5383
|
|
|
|
|
|
|
EOF |
|
5384
|
|
|
|
|
|
|
ParamDesc => { |
|
5385
|
|
|
|
|
|
|
ic => <<'EOF', |
|
5386
|
|
|
|
|
|
|
The first and second elements determine the boundary |
|
5387
|
|
|
|
|
|
|
conditions at the start and end of the data respectively. |
|
5388
|
|
|
|
|
|
|
The allowed values for C are: |
|
5389
|
|
|
|
|
|
|
|
|
5390
|
|
|
|
|
|
|
=over |
|
5391
|
|
|
|
|
|
|
|
|
5392
|
|
|
|
|
|
|
=item * |
|
5393
|
|
|
|
|
|
|
|
|
5394
|
|
|
|
|
|
|
0 to set C so that the third derivative is |
|
5395
|
|
|
|
|
|
|
continuous at C. |
|
5396
|
|
|
|
|
|
|
|
|
5397
|
|
|
|
|
|
|
=item * |
|
5398
|
|
|
|
|
|
|
|
|
5399
|
|
|
|
|
|
|
1 if first derivative at C is given in C). |
|
5400
|
|
|
|
|
|
|
|
|
5401
|
|
|
|
|
|
|
=item * |
|
5402
|
|
|
|
|
|
|
|
|
5403
|
|
|
|
|
|
|
2 if second derivative at C) is given in C. |
|
5404
|
|
|
|
|
|
|
|
|
5405
|
|
|
|
|
|
|
=item * |
|
5406
|
|
|
|
|
|
|
|
|
5407
|
|
|
|
|
|
|
3 to use the 3-point difference formula for C. |
|
5408
|
|
|
|
|
|
|
(Reverts to the default b.c. if C 3>.) |
|
5409
|
|
|
|
|
|
|
|
|
5410
|
|
|
|
|
|
|
=item * |
|
5411
|
|
|
|
|
|
|
|
|
5412
|
|
|
|
|
|
|
4 to use the 4-point difference formula for C. |
|
5413
|
|
|
|
|
|
|
(Reverts to the default b.c. if C 4>.) |
|
5414
|
|
|
|
|
|
|
|
|
5415
|
|
|
|
|
|
|
=back |
|
5416
|
|
|
|
|
|
|
|
|
5417
|
|
|
|
|
|
|
The values for C are the same as above, except that |
|
5418
|
|
|
|
|
|
|
the first-derivative value is stored in C for cases 1 and 2. |
|
5419
|
|
|
|
|
|
|
The values of C<$vc> need only be set if options 1 or 2 are chosen |
|
5420
|
|
|
|
|
|
|
for C<$ic>. |
|
5421
|
|
|
|
|
|
|
|
|
5422
|
|
|
|
|
|
|
NOTES: For the "natural" boundary condition, use IC(n)=2 and VC(n)=0. |
|
5423
|
|
|
|
|
|
|
EOF |
|
5424
|
|
|
|
|
|
|
vc => 'See ic for details', |
|
5425
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
5426
|
|
|
|
|
|
|
Error status: |
|
5427
|
|
|
|
|
|
|
|
|
5428
|
|
|
|
|
|
|
=over |
|
5429
|
|
|
|
|
|
|
|
|
5430
|
|
|
|
|
|
|
=item * |
|
5431
|
|
|
|
|
|
|
|
|
5432
|
|
|
|
|
|
|
0 if successful. |
|
5433
|
|
|
|
|
|
|
|
|
5434
|
|
|
|
|
|
|
=item * |
|
5435
|
|
|
|
|
|
|
|
|
5436
|
|
|
|
|
|
|
-1 if C 2>. |
|
5437
|
|
|
|
|
|
|
|
|
5438
|
|
|
|
|
|
|
=item * |
|
5439
|
|
|
|
|
|
|
|
|
5440
|
|
|
|
|
|
|
-3 if C<$x> is not strictly increasing. |
|
5441
|
|
|
|
|
|
|
|
|
5442
|
|
|
|
|
|
|
=item * |
|
5443
|
|
|
|
|
|
|
|
|
5444
|
|
|
|
|
|
|
-4 if C 0> or C 4>. |
|
5445
|
|
|
|
|
|
|
|
|
5446
|
|
|
|
|
|
|
=item * |
|
5447
|
|
|
|
|
|
|
|
|
5448
|
|
|
|
|
|
|
-5 if C 0> or C 4>. |
|
5449
|
|
|
|
|
|
|
|
|
5450
|
|
|
|
|
|
|
=item * |
|
5451
|
|
|
|
|
|
|
|
|
5452
|
|
|
|
|
|
|
-6 if both of the above are true. |
|
5453
|
|
|
|
|
|
|
|
|
5454
|
|
|
|
|
|
|
=item * |
|
5455
|
|
|
|
|
|
|
|
|
5456
|
|
|
|
|
|
|
-7 if C 2*n>. |
|
5457
|
|
|
|
|
|
|
|
|
5458
|
|
|
|
|
|
|
NOTE: The above errors are checked in the order listed, |
|
5459
|
|
|
|
|
|
|
and following arguments have B been validated. |
|
5460
|
|
|
|
|
|
|
(The D-array has not been changed in any of these cases.) |
|
5461
|
|
|
|
|
|
|
|
|
5462
|
|
|
|
|
|
|
=item * |
|
5463
|
|
|
|
|
|
|
|
|
5464
|
|
|
|
|
|
|
-8 in case of trouble solving the linear system |
|
5465
|
|
|
|
|
|
|
for the interior derivative values. |
|
5466
|
|
|
|
|
|
|
(The D-array may have been changed in this case. Do B use it!) |
|
5467
|
|
|
|
|
|
|
|
|
5468
|
|
|
|
|
|
|
=back |
|
5469
|
|
|
|
|
|
|
EOF |
|
5470
|
|
|
|
|
|
|
}, |
|
5471
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
5472
|
|
|
|
|
|
|
=for ref |
|
5473
|
|
|
|
|
|
|
|
|
5474
|
|
|
|
|
|
|
Calculate the derivatives of (x,f(x)) using cubic spline interpolation. |
|
5475
|
|
|
|
|
|
|
|
|
5476
|
|
|
|
|
|
|
Computes the Hermite representation of the cubic spline interpolant |
|
5477
|
|
|
|
|
|
|
to the data given in (C<$x,$f>), with the specified boundary conditions. |
|
5478
|
|
|
|
|
|
|
Control over the boundary conditions is given by the |
|
5479
|
|
|
|
|
|
|
C<$ic> and C<$vc> ndarrays. |
|
5480
|
|
|
|
|
|
|
The resulting values - C<$x,$f,$d> - can |
|
5481
|
|
|
|
|
|
|
be used in all the functions which expect a cubic |
|
5482
|
|
|
|
|
|
|
Hermite function, including L. |
|
5483
|
|
|
|
|
|
|
|
|
5484
|
|
|
|
|
|
|
References: Carl de Boor, A Practical Guide to Splines, Springer-Verlag, |
|
5485
|
|
|
|
|
|
|
New York, 1978, pp. 53-59. |
|
5486
|
|
|
|
|
|
|
EOF |
|
5487
|
|
|
|
|
|
|
); |
|
5488
|
|
|
|
|
|
|
|
|
5489
|
|
|
|
|
|
|
pp_def('pchip_chfd', |
|
5490
|
|
|
|
|
|
|
Pars => 'x(n); f(n); d(n); xe(ne); |
|
5491
|
|
|
|
|
|
|
[o] fe(ne); [o] de(ne); indx [o] ierr(); int [o] skip()', |
|
5492
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
5493
|
|
|
|
|
|
|
if ($SIZE(n) < 2) $CROAK("NUMBER OF DATA POINTS LESS THAN TWO"); |
|
5494
|
|
|
|
|
|
|
if ($SIZE(ne) < 1) $CROAK("NUMBER OF EVALUATION POINTS LESS THAN ONE"); |
|
5495
|
|
|
|
|
|
|
EOF |
|
5496
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
5497
|
|
|
|
|
|
|
$CHFD(1); |
|
5498
|
|
|
|
|
|
|
EOF |
|
5499
|
|
|
|
|
|
|
GenericTypes => $F, |
|
5500
|
|
|
|
|
|
|
ParamDesc => { |
|
5501
|
|
|
|
|
|
|
skip => <<'EOF', |
|
5502
|
|
|
|
|
|
|
Set to 1 to skip checks on the input data. |
|
5503
|
|
|
|
|
|
|
This will save time in case these checks have already |
|
5504
|
|
|
|
|
|
|
been performed (say, in L or L). |
|
5505
|
|
|
|
|
|
|
Will be set to TRUE on normal return. |
|
5506
|
|
|
|
|
|
|
EOF |
|
5507
|
|
|
|
|
|
|
xe => <<'EOF', |
|
5508
|
|
|
|
|
|
|
array of points at which the functions are to |
|
5509
|
|
|
|
|
|
|
be evaluated. NOTES: |
|
5510
|
|
|
|
|
|
|
|
|
5511
|
|
|
|
|
|
|
=over |
|
5512
|
|
|
|
|
|
|
|
|
5513
|
|
|
|
|
|
|
=item 1 |
|
5514
|
|
|
|
|
|
|
|
|
5515
|
|
|
|
|
|
|
The evaluation will be most efficient if the elements |
|
5516
|
|
|
|
|
|
|
of XE are increasing relative to X; |
|
5517
|
|
|
|
|
|
|
that is, XE(J) .GE. X(I) |
|
5518
|
|
|
|
|
|
|
implies XE(K) .GE. X(I), all K.GE.J . |
|
5519
|
|
|
|
|
|
|
|
|
5520
|
|
|
|
|
|
|
=item 2 |
|
5521
|
|
|
|
|
|
|
|
|
5522
|
|
|
|
|
|
|
If any of the XE are outside the interval [X(1),X(N)], |
|
5523
|
|
|
|
|
|
|
values are extrapolated from the nearest extreme cubic, |
|
5524
|
|
|
|
|
|
|
and a warning error is returned. |
|
5525
|
|
|
|
|
|
|
|
|
5526
|
|
|
|
|
|
|
=back |
|
5527
|
|
|
|
|
|
|
EOF |
|
5528
|
|
|
|
|
|
|
fe => <<'EOF', |
|
5529
|
|
|
|
|
|
|
array of values of the cubic Hermite |
|
5530
|
|
|
|
|
|
|
function defined by N, X, F, D at the points XE. |
|
5531
|
|
|
|
|
|
|
EOF |
|
5532
|
|
|
|
|
|
|
de => <<'EOF', |
|
5533
|
|
|
|
|
|
|
array of values of the first derivative of the same function at the points XE. |
|
5534
|
|
|
|
|
|
|
EOF |
|
5535
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
5536
|
|
|
|
|
|
|
Error status: |
|
5537
|
|
|
|
|
|
|
|
|
5538
|
|
|
|
|
|
|
=over |
|
5539
|
|
|
|
|
|
|
|
|
5540
|
|
|
|
|
|
|
=item * |
|
5541
|
|
|
|
|
|
|
|
|
5542
|
|
|
|
|
|
|
0 if successful. |
|
5543
|
|
|
|
|
|
|
|
|
5544
|
|
|
|
|
|
|
=item * |
|
5545
|
|
|
|
|
|
|
|
|
5546
|
|
|
|
|
|
|
E0 if extrapolation was performed at C points |
|
5547
|
|
|
|
|
|
|
(data still valid). |
|
5548
|
|
|
|
|
|
|
|
|
5549
|
|
|
|
|
|
|
=item * |
|
5550
|
|
|
|
|
|
|
|
|
5551
|
|
|
|
|
|
|
-1 if C 2> |
|
5552
|
|
|
|
|
|
|
|
|
5553
|
|
|
|
|
|
|
=item * |
|
5554
|
|
|
|
|
|
|
|
|
5555
|
|
|
|
|
|
|
-3 if C<$x> is not strictly increasing. |
|
5556
|
|
|
|
|
|
|
|
|
5557
|
|
|
|
|
|
|
=item * |
|
5558
|
|
|
|
|
|
|
|
|
5559
|
|
|
|
|
|
|
-4 if C 1>. |
|
5560
|
|
|
|
|
|
|
|
|
5561
|
|
|
|
|
|
|
=item * |
|
5562
|
|
|
|
|
|
|
|
|
5563
|
|
|
|
|
|
|
-5 if an error has occurred in a lower-level routine, |
|
5564
|
|
|
|
|
|
|
which should never happen. |
|
5565
|
|
|
|
|
|
|
|
|
5566
|
|
|
|
|
|
|
=back |
|
5567
|
|
|
|
|
|
|
EOF |
|
5568
|
|
|
|
|
|
|
}, |
|
5569
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
5570
|
|
|
|
|
|
|
=for ref |
|
5571
|
|
|
|
|
|
|
|
|
5572
|
|
|
|
|
|
|
Evaluate a piecewise cubic Hermite function and its first derivative |
|
5573
|
|
|
|
|
|
|
at an array of points. May be used by itself for Hermite interpolation, |
|
5574
|
|
|
|
|
|
|
or as an evaluator for DPCHIM or DPCHIC. |
|
5575
|
|
|
|
|
|
|
|
|
5576
|
|
|
|
|
|
|
Given a piecewise cubic Hermite function - such as from |
|
5577
|
|
|
|
|
|
|
L - evaluate the function (C<$fe>) and |
|
5578
|
|
|
|
|
|
|
derivative (C<$de>) at a set of points (C<$xe>). |
|
5579
|
|
|
|
|
|
|
If function values alone are required, use L. |
|
5580
|
|
|
|
|
|
|
EOF |
|
5581
|
|
|
|
|
|
|
); |
|
5582
|
|
|
|
|
|
|
|
|
5583
|
|
|
|
|
|
|
pp_def('pchip_chfe', |
|
5584
|
|
|
|
|
|
|
Pars => 'x(n); f(n); d(n); xe(ne); |
|
5585
|
|
|
|
|
|
|
[o] fe(ne); indx [o] ierr(); int [o] skip()', |
|
5586
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
5587
|
|
|
|
|
|
|
if ($SIZE(n) < 2) $CROAK("NUMBER OF DATA POINTS LESS THAN TWO"); |
|
5588
|
|
|
|
|
|
|
if ($SIZE(ne) < 1) $CROAK("NUMBER OF EVALUATION POINTS LESS THAN ONE"); |
|
5589
|
|
|
|
|
|
|
EOF |
|
5590
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
5591
|
|
|
|
|
|
|
$CHFD(0); |
|
5592
|
|
|
|
|
|
|
EOF |
|
5593
|
|
|
|
|
|
|
GenericTypes => $F, |
|
5594
|
|
|
|
|
|
|
ParamDesc => { |
|
5595
|
|
|
|
|
|
|
x => <<'EOF', |
|
5596
|
|
|
|
|
|
|
array of independent variable values. The |
|
5597
|
|
|
|
|
|
|
elements of X must be strictly increasing: |
|
5598
|
|
|
|
|
|
|
|
|
5599
|
|
|
|
|
|
|
X(I-1) .LT. X(I), I = 2(1)N. |
|
5600
|
|
|
|
|
|
|
|
|
5601
|
|
|
|
|
|
|
(Error return if not.) |
|
5602
|
|
|
|
|
|
|
EOF |
|
5603
|
|
|
|
|
|
|
f => <<'EOF', |
|
5604
|
|
|
|
|
|
|
array of function values. F(I) is the value corresponding to X(I). |
|
5605
|
|
|
|
|
|
|
EOF |
|
5606
|
|
|
|
|
|
|
d => <<'EOF', |
|
5607
|
|
|
|
|
|
|
array of derivative values. D(I) is the value corresponding to X(I). |
|
5608
|
|
|
|
|
|
|
EOF |
|
5609
|
|
|
|
|
|
|
skip => <<'EOF', |
|
5610
|
|
|
|
|
|
|
Set to 1 to skip checks on the input data. |
|
5611
|
|
|
|
|
|
|
This will save time in case these checks have already |
|
5612
|
|
|
|
|
|
|
been performed (say, in L or L). |
|
5613
|
|
|
|
|
|
|
Will be set to TRUE on normal return. |
|
5614
|
|
|
|
|
|
|
EOF |
|
5615
|
|
|
|
|
|
|
xe => <<'EOF', |
|
5616
|
|
|
|
|
|
|
array of points at which the function is to be evaluated. NOTES: |
|
5617
|
|
|
|
|
|
|
|
|
5618
|
|
|
|
|
|
|
=over |
|
5619
|
|
|
|
|
|
|
|
|
5620
|
|
|
|
|
|
|
=item 1 |
|
5621
|
|
|
|
|
|
|
|
|
5622
|
|
|
|
|
|
|
The evaluation will be most efficient if the elements |
|
5623
|
|
|
|
|
|
|
of XE are increasing relative to X; |
|
5624
|
|
|
|
|
|
|
that is, XE(J) .GE. X(I) |
|
5625
|
|
|
|
|
|
|
implies XE(K) .GE. X(I), all K.GE.J . |
|
5626
|
|
|
|
|
|
|
|
|
5627
|
|
|
|
|
|
|
=item 2 |
|
5628
|
|
|
|
|
|
|
|
|
5629
|
|
|
|
|
|
|
If any of the XE are outside the interval [X(1),X(N)], |
|
5630
|
|
|
|
|
|
|
values are extrapolated from the nearest extreme cubic, |
|
5631
|
|
|
|
|
|
|
and a warning error is returned. |
|
5632
|
|
|
|
|
|
|
|
|
5633
|
|
|
|
|
|
|
=back |
|
5634
|
|
|
|
|
|
|
EOF |
|
5635
|
|
|
|
|
|
|
fe => <<'EOF', |
|
5636
|
|
|
|
|
|
|
array of values of the cubic Hermite |
|
5637
|
|
|
|
|
|
|
function defined by N, X, F, D at the points XE. |
|
5638
|
|
|
|
|
|
|
EOF |
|
5639
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
5640
|
|
|
|
|
|
|
Error status returned by C<$>: |
|
5641
|
|
|
|
|
|
|
|
|
5642
|
|
|
|
|
|
|
=over |
|
5643
|
|
|
|
|
|
|
|
|
5644
|
|
|
|
|
|
|
=item * |
|
5645
|
|
|
|
|
|
|
|
|
5646
|
|
|
|
|
|
|
0 if successful. |
|
5647
|
|
|
|
|
|
|
|
|
5648
|
|
|
|
|
|
|
=item * |
|
5649
|
|
|
|
|
|
|
|
|
5650
|
|
|
|
|
|
|
E0 if extrapolation was performed at C points |
|
5651
|
|
|
|
|
|
|
(data still valid). |
|
5652
|
|
|
|
|
|
|
|
|
5653
|
|
|
|
|
|
|
=item * |
|
5654
|
|
|
|
|
|
|
|
|
5655
|
|
|
|
|
|
|
-1 if C 2> |
|
5656
|
|
|
|
|
|
|
|
|
5657
|
|
|
|
|
|
|
=item * |
|
5658
|
|
|
|
|
|
|
|
|
5659
|
|
|
|
|
|
|
-3 if C<$x> is not strictly increasing. |
|
5660
|
|
|
|
|
|
|
|
|
5661
|
|
|
|
|
|
|
=item * |
|
5662
|
|
|
|
|
|
|
|
|
5663
|
|
|
|
|
|
|
-4 if C 1>. |
|
5664
|
|
|
|
|
|
|
|
|
5665
|
|
|
|
|
|
|
=back |
|
5666
|
|
|
|
|
|
|
|
|
5667
|
|
|
|
|
|
|
(The FE-array has not been changed in any of these cases.) |
|
5668
|
|
|
|
|
|
|
NOTE: The above errors are checked in the order listed, |
|
5669
|
|
|
|
|
|
|
and following arguments have B been validated. |
|
5670
|
|
|
|
|
|
|
EOF |
|
5671
|
|
|
|
|
|
|
}, |
|
5672
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
5673
|
|
|
|
|
|
|
=for ref |
|
5674
|
|
|
|
|
|
|
|
|
5675
|
|
|
|
|
|
|
Evaluate a piecewise cubic Hermite function at an array of points. |
|
5676
|
|
|
|
|
|
|
May be used by itself for Hermite interpolation, or as an evaluator |
|
5677
|
|
|
|
|
|
|
for L or L. |
|
5678
|
|
|
|
|
|
|
|
|
5679
|
|
|
|
|
|
|
Given a piecewise cubic Hermite function - such as from |
|
5680
|
|
|
|
|
|
|
L - evaluate the function (C<$fe>) at |
|
5681
|
|
|
|
|
|
|
a set of points (C<$xe>). |
|
5682
|
|
|
|
|
|
|
If derivative values are also required, use L. |
|
5683
|
|
|
|
|
|
|
EOF |
|
5684
|
|
|
|
|
|
|
); |
|
5685
|
|
|
|
|
|
|
|
|
5686
|
|
|
|
|
|
|
pp_def('pchip_chia', |
|
5687
|
|
|
|
|
|
|
Pars => 'x(n); f(n); d(n); la(); lb(); |
|
5688
|
|
|
|
|
|
|
[o]ans(); indx [o]ierr(); int [o]skip()', |
|
5689
|
|
|
|
|
|
|
GenericTypes => $F, |
|
5690
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
5691
|
|
|
|
|
|
|
if ($SIZE(n) < 2) $CROAK("NUMBER OF DATA POINTS LESS THAN TWO"); |
|
5692
|
|
|
|
|
|
|
EOF |
|
5693
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
5694
|
|
|
|
|
|
|
PDL_Indx ia, ib, il; |
|
5695
|
|
|
|
|
|
|
$GENERIC() a = $la(), b = $lb(), xa, xb; |
|
5696
|
|
|
|
|
|
|
PDL_Indx ir, n = $SIZE(n); |
|
5697
|
|
|
|
|
|
|
$GENERIC() value = 0.; |
|
5698
|
|
|
|
|
|
|
if (!$skip()) { |
|
5699
|
|
|
|
|
|
|
loop (n=1) %{ |
|
5700
|
|
|
|
|
|
|
if ($x() > $x(n=>n-1)) continue; |
|
5701
|
|
|
|
|
|
|
$ierr() = -1; |
|
5702
|
|
|
|
|
|
|
$CROAK("X-ARRAY NOT STRICTLY INCREASING"); |
|
5703
|
|
|
|
|
|
|
%} |
|
5704
|
|
|
|
|
|
|
} |
|
5705
|
|
|
|
|
|
|
/* FUNCTION DEFINITION IS OK, GO ON. */ |
|
5706
|
|
|
|
|
|
|
$skip() = 1; |
|
5707
|
|
|
|
|
|
|
$ierr() = 0; |
|
5708
|
|
|
|
|
|
|
if (a < $x(n=>0) || a > $x(n=>n-1)) { |
|
5709
|
|
|
|
|
|
|
++($ierr()); |
|
5710
|
|
|
|
|
|
|
} |
|
5711
|
|
|
|
|
|
|
if (b < $x(n=>0) || b > $x(n=>n-1)) { |
|
5712
|
|
|
|
|
|
|
$ierr() += 2; |
|
5713
|
|
|
|
|
|
|
} |
|
5714
|
|
|
|
|
|
|
/* COMPUTE INTEGRAL VALUE. */ |
|
5715
|
|
|
|
|
|
|
if (a != b) { |
|
5716
|
|
|
|
|
|
|
xa = PDLMIN(a,b); |
|
5717
|
|
|
|
|
|
|
xb = PDLMAX(a,b); |
|
5718
|
|
|
|
|
|
|
if (xb <= $x(n=>1)) { |
|
5719
|
|
|
|
|
|
|
/* INTERVAL IS TO LEFT OF X(2), SO USE FIRST CUBIC. */ |
|
5720
|
|
|
|
|
|
|
/* --------------------------------------- */ |
|
5721
|
|
|
|
|
|
|
$CHFIE($x(n=>0), $x(n=>1), $f(n=>0), $f(n=>1), |
|
5722
|
|
|
|
|
|
|
$d(n=>0), $d(n=>1), a, b, value); |
|
5723
|
|
|
|
|
|
|
/* --------------------------------------- */ |
|
5724
|
|
|
|
|
|
|
} else if (xa >= $x(n=>n-2)) { |
|
5725
|
|
|
|
|
|
|
/* INTERVAL IS TO RIGHT OF X(N-1), SO USE LAST CUBIC. */ |
|
5726
|
|
|
|
|
|
|
/* ------------------------------------------ */ |
|
5727
|
|
|
|
|
|
|
$CHFIE($x(n=>n-2), $x(n=>n-1), $f(n=>n-2), $f(n=>n-1), $d(n=>n-2), $d(n=>n-1), a, b, value); |
|
5728
|
|
|
|
|
|
|
/* ------------------------------------------ */ |
|
5729
|
|
|
|
|
|
|
} else { |
|
5730
|
|
|
|
|
|
|
/* 'NORMAL' CASE -- XA.LT.XB, XA.LT.X(N-1), XB.GT.X(2). */ |
|
5731
|
|
|
|
|
|
|
/* ......LOCATE IA AND IB SUCH THAT */ |
|
5732
|
|
|
|
|
|
|
/* X(IA-1).LT.XA.LE.X(IA).LE.X(IB).LE.XB.LE.X(IB+1) */ |
|
5733
|
|
|
|
|
|
|
ia = 0; |
|
5734
|
|
|
|
|
|
|
loop (n=:-1) %{ |
|
5735
|
|
|
|
|
|
|
if (xa > $x()) |
|
5736
|
|
|
|
|
|
|
ia = n + 1; |
|
5737
|
|
|
|
|
|
|
%} |
|
5738
|
|
|
|
|
|
|
/* IA = 1 IMPLIES XA.LT.X(1) . OTHERWISE, */ |
|
5739
|
|
|
|
|
|
|
/* IA IS LARGEST INDEX SUCH THAT X(IA-1).LT.XA,. */ |
|
5740
|
|
|
|
|
|
|
ib = n - 1; |
|
5741
|
|
|
|
|
|
|
loop (n=:ia:-1) %{ |
|
5742
|
|
|
|
|
|
|
if (xb < $x()) |
|
5743
|
|
|
|
|
|
|
ib = n - 1; |
|
5744
|
|
|
|
|
|
|
%} |
|
5745
|
|
|
|
|
|
|
/* IB = N IMPLIES XB.GT.X(N) . OTHERWISE, */ |
|
5746
|
|
|
|
|
|
|
/* IB IS SMALLEST INDEX SUCH THAT XB.LT.X(IB+1) . */ |
|
5747
|
|
|
|
|
|
|
/* ......COMPUTE THE INTEGRAL. */ |
|
5748
|
|
|
|
|
|
|
if (ib <= ia) { |
|
5749
|
|
|
|
|
|
|
/* THIS MEANS IB = IA-1 AND */ |
|
5750
|
|
|
|
|
|
|
/* (A,B) IS A SUBSET OF (X(IB),X(IA)). */ |
|
5751
|
|
|
|
|
|
|
/* ------------------------------------------- */ |
|
5752
|
|
|
|
|
|
|
$CHFIE($x(n=>ib), $x(n=>ia), $f(n=>ib), |
|
5753
|
|
|
|
|
|
|
$f(n=>ia), $d(n=>ib), $d(n=>ia), a, b, value); |
|
5754
|
|
|
|
|
|
|
/* ------------------------------------------- */ |
|
5755
|
|
|
|
|
|
|
} else { |
|
5756
|
|
|
|
|
|
|
/* FIRST COMPUTE INTEGRAL OVER (X(IA),X(IB)). */ |
|
5757
|
|
|
|
|
|
|
/* (Case (IB .EQ. IA) is taken care of by initialization */ |
|
5758
|
|
|
|
|
|
|
/* of VALUE to ZERO.) */ |
|
5759
|
|
|
|
|
|
|
if (ib > ia-1) { |
|
5760
|
|
|
|
|
|
|
/* --------------------------------------------- */ |
|
5761
|
|
|
|
|
|
|
$PCHID(ia, ib, value); |
|
5762
|
|
|
|
|
|
|
/* --------------------------------------------- */ |
|
5763
|
|
|
|
|
|
|
} |
|
5764
|
|
|
|
|
|
|
/* THEN ADD ON INTEGRAL OVER (XA,X(IA)). */ |
|
5765
|
|
|
|
|
|
|
if (xa < $x(n=>ia)) { |
|
5766
|
|
|
|
|
|
|
/* Computing MAX */ |
|
5767
|
|
|
|
|
|
|
il = PDLMAX(0,ia - 1); |
|
5768
|
|
|
|
|
|
|
ir = il + 1; |
|
5769
|
|
|
|
|
|
|
/* ------------------------------------- */ |
|
5770
|
|
|
|
|
|
|
$GENERIC() chfie_ans = 0; |
|
5771
|
|
|
|
|
|
|
$CHFIE($x(n=>il), $x(n=>ir), $f(n=>il), $f(n=>ir), $d(n=>il), $d(n=>ir), xa, $x(n=>ia), chfie_ans); |
|
5772
|
|
|
|
|
|
|
value += chfie_ans; |
|
5773
|
|
|
|
|
|
|
/* ------------------------------------- */ |
|
5774
|
|
|
|
|
|
|
} |
|
5775
|
|
|
|
|
|
|
/* THEN ADD ON INTEGRAL OVER (X(IB),XB). */ |
|
5776
|
|
|
|
|
|
|
if (xb > $x(n=>ib)) { |
|
5777
|
|
|
|
|
|
|
/* Computing MIN */ |
|
5778
|
|
|
|
|
|
|
ir = PDLMIN(ib + 1,n-1); |
|
5779
|
|
|
|
|
|
|
il = ir - 1; |
|
5780
|
|
|
|
|
|
|
/* ------------------------------------- */ |
|
5781
|
|
|
|
|
|
|
$GENERIC() chfie_ans = 0; |
|
5782
|
|
|
|
|
|
|
$CHFIE($x(n=>il), $x(n=>ir), $f(n=>il), $f(n=>ir), $d(n=>il), $d(n=>ir), $x(n=>ib), xb, chfie_ans); |
|
5783
|
|
|
|
|
|
|
value += chfie_ans; |
|
5784
|
|
|
|
|
|
|
/* ------------------------------------- */ |
|
5785
|
|
|
|
|
|
|
} |
|
5786
|
|
|
|
|
|
|
/* FINALLY, ADJUST SIGN IF NECESSARY. */ |
|
5787
|
|
|
|
|
|
|
if (a > b) { |
|
5788
|
|
|
|
|
|
|
value = -value; |
|
5789
|
|
|
|
|
|
|
} |
|
5790
|
|
|
|
|
|
|
} |
|
5791
|
|
|
|
|
|
|
} |
|
5792
|
|
|
|
|
|
|
} |
|
5793
|
|
|
|
|
|
|
$ans() = value; |
|
5794
|
|
|
|
|
|
|
EOF |
|
5795
|
|
|
|
|
|
|
ParamDesc => { |
|
5796
|
|
|
|
|
|
|
x => <<'EOF', |
|
5797
|
|
|
|
|
|
|
array of independent variable values. The elements |
|
5798
|
|
|
|
|
|
|
of X must be strictly increasing (error return if not): |
|
5799
|
|
|
|
|
|
|
|
|
5800
|
|
|
|
|
|
|
X(I-1) .LT. X(I), I = 2(1)N. |
|
5801
|
|
|
|
|
|
|
EOF |
|
5802
|
|
|
|
|
|
|
f => <<'EOF', |
|
5803
|
|
|
|
|
|
|
array of function values. F(I) is the value corresponding to X(I). |
|
5804
|
|
|
|
|
|
|
EOF |
|
5805
|
|
|
|
|
|
|
d => <<'EOF', |
|
5806
|
|
|
|
|
|
|
should contain the derivative values, computed by L. |
|
5807
|
|
|
|
|
|
|
See L if the integration limits are data points. |
|
5808
|
|
|
|
|
|
|
EOF |
|
5809
|
|
|
|
|
|
|
skip => <<'EOF', |
|
5810
|
|
|
|
|
|
|
Set to 1 to skip checks on the input data. |
|
5811
|
|
|
|
|
|
|
This will save time in case these checks have already |
|
5812
|
|
|
|
|
|
|
been performed (say, in L or L). |
|
5813
|
|
|
|
|
|
|
Will be set to TRUE on return with IERR E= 0. |
|
5814
|
|
|
|
|
|
|
EOF |
|
5815
|
|
|
|
|
|
|
la => <<'EOF', |
|
5816
|
|
|
|
|
|
|
The values of C<$la> and C<$lb> do not have |
|
5817
|
|
|
|
|
|
|
to lie within C<$x>, although the resulting integral |
|
5818
|
|
|
|
|
|
|
value will be highly suspect if they are not. |
|
5819
|
|
|
|
|
|
|
EOF |
|
5820
|
|
|
|
|
|
|
lb => <<'EOF', |
|
5821
|
|
|
|
|
|
|
See la |
|
5822
|
|
|
|
|
|
|
EOF |
|
5823
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
5824
|
|
|
|
|
|
|
Error status: |
|
5825
|
|
|
|
|
|
|
|
|
5826
|
|
|
|
|
|
|
=over |
|
5827
|
|
|
|
|
|
|
|
|
5828
|
|
|
|
|
|
|
=item * |
|
5829
|
|
|
|
|
|
|
|
|
5830
|
|
|
|
|
|
|
0 if successful. |
|
5831
|
|
|
|
|
|
|
|
|
5832
|
|
|
|
|
|
|
=item * |
|
5833
|
|
|
|
|
|
|
|
|
5834
|
|
|
|
|
|
|
1 if C<$la> lies outside C<$x>. |
|
5835
|
|
|
|
|
|
|
|
|
5836
|
|
|
|
|
|
|
=item * |
|
5837
|
|
|
|
|
|
|
|
|
5838
|
|
|
|
|
|
|
2 if C<$lb> lies outside C<$x>. |
|
5839
|
|
|
|
|
|
|
|
|
5840
|
|
|
|
|
|
|
=item * |
|
5841
|
|
|
|
|
|
|
|
|
5842
|
|
|
|
|
|
|
3 if both 1 and 2 are true. (Note that this means that either [A,B] |
|
5843
|
|
|
|
|
|
|
contains data interval or the intervals do not intersect at all.) |
|
5844
|
|
|
|
|
|
|
|
|
5845
|
|
|
|
|
|
|
=item * |
|
5846
|
|
|
|
|
|
|
|
|
5847
|
|
|
|
|
|
|
-1 if C 2> |
|
5848
|
|
|
|
|
|
|
|
|
5849
|
|
|
|
|
|
|
=item * |
|
5850
|
|
|
|
|
|
|
|
|
5851
|
|
|
|
|
|
|
-3 if C<$x> is not strictly increasing. |
|
5852
|
|
|
|
|
|
|
|
|
5853
|
|
|
|
|
|
|
=item * |
|
5854
|
|
|
|
|
|
|
|
|
5855
|
|
|
|
|
|
|
-4 if an error has occurred in a lower-level routine, |
|
5856
|
|
|
|
|
|
|
which should never happen. |
|
5857
|
|
|
|
|
|
|
|
|
5858
|
|
|
|
|
|
|
=back |
|
5859
|
|
|
|
|
|
|
EOF |
|
5860
|
|
|
|
|
|
|
}, |
|
5861
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
5862
|
|
|
|
|
|
|
=for ref |
|
5863
|
|
|
|
|
|
|
|
|
5864
|
|
|
|
|
|
|
Integrate (x,f(x)) over arbitrary limits. |
|
5865
|
|
|
|
|
|
|
|
|
5866
|
|
|
|
|
|
|
Evaluate the definite integral of a piecewise |
|
5867
|
|
|
|
|
|
|
cubic Hermite function over an arbitrary interval, given by C<[$la,$lb]>. |
|
5868
|
|
|
|
|
|
|
EOF |
|
5869
|
|
|
|
|
|
|
); |
|
5870
|
|
|
|
|
|
|
|
|
5871
|
|
|
|
|
|
|
pp_def('pchip_chid', |
|
5872
|
|
|
|
|
|
|
Pars => 'x(n); f(n); d(n); |
|
5873
|
|
|
|
|
|
|
indx ia(); indx ib(); |
|
5874
|
|
|
|
|
|
|
[o]ans(); indx [o]ierr(); int [o]skip()', |
|
5875
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
5876
|
|
|
|
|
|
|
if ($SIZE(n) < 2) $CROAK("NUMBER OF DATA POINTS LESS THAN TWO"); |
|
5877
|
|
|
|
|
|
|
EOF |
|
5878
|
|
|
|
|
|
|
Code => <<'EOF', |
|
5879
|
|
|
|
|
|
|
if (!$skip()) { |
|
5880
|
|
|
|
|
|
|
loop (n=1) %{ |
|
5881
|
|
|
|
|
|
|
if ($x() > $x(n=>n-1)) continue; |
|
5882
|
|
|
|
|
|
|
$ierr() = -1; |
|
5883
|
|
|
|
|
|
|
$CROAK("X-ARRAY NOT STRICTLY INCREASING"); |
|
5884
|
|
|
|
|
|
|
%} |
|
5885
|
|
|
|
|
|
|
} |
|
5886
|
|
|
|
|
|
|
$PCHID($ia(), $ib(), $ans()); |
|
5887
|
|
|
|
|
|
|
EOF |
|
5888
|
|
|
|
|
|
|
GenericTypes => $F, |
|
5889
|
|
|
|
|
|
|
ParamDesc => { |
|
5890
|
|
|
|
|
|
|
x => <<'EOF', |
|
5891
|
|
|
|
|
|
|
array of independent variable values. The |
|
5892
|
|
|
|
|
|
|
elements of X must be strictly increasing: |
|
5893
|
|
|
|
|
|
|
|
|
5894
|
|
|
|
|
|
|
X(I-1) .LT. X(I), I = 2(1)N. |
|
5895
|
|
|
|
|
|
|
|
|
5896
|
|
|
|
|
|
|
(Error return if not.) |
|
5897
|
|
|
|
|
|
|
|
|
5898
|
|
|
|
|
|
|
It is a fatal error to pass in data with C E 2. |
|
5899
|
|
|
|
|
|
|
EOF |
|
5900
|
|
|
|
|
|
|
ia => <<'EOF', |
|
5901
|
|
|
|
|
|
|
IA,IB -- (input) indices in X-array for the limits of integration. |
|
5902
|
|
|
|
|
|
|
both must be in the range [0,N-1] (this is different from the Fortran |
|
5903
|
|
|
|
|
|
|
version) - error return if not. No restrictions on their relative |
|
5904
|
|
|
|
|
|
|
values. |
|
5905
|
|
|
|
|
|
|
EOF |
|
5906
|
|
|
|
|
|
|
ib => 'See ia for details', |
|
5907
|
|
|
|
|
|
|
f => 'array of function values. F(I) is the value corresponding to X(I).', |
|
5908
|
|
|
|
|
|
|
skip => <<'EOF', |
|
5909
|
|
|
|
|
|
|
Set to 1 to skip checks on the input data. |
|
5910
|
|
|
|
|
|
|
This will save time in case these checks have already |
|
5911
|
|
|
|
|
|
|
been performed (say, in L or L). |
|
5912
|
|
|
|
|
|
|
Will be set to TRUE on return with IERR of 0 or -4. |
|
5913
|
|
|
|
|
|
|
EOF |
|
5914
|
|
|
|
|
|
|
d => <<'EOF', |
|
5915
|
|
|
|
|
|
|
should contain the derivative values, computed by L. |
|
5916
|
|
|
|
|
|
|
EOF |
|
5917
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
5918
|
|
|
|
|
|
|
Error status - this will be set, but an exception |
|
5919
|
|
|
|
|
|
|
will also be thrown: |
|
5920
|
|
|
|
|
|
|
|
|
5921
|
|
|
|
|
|
|
=over |
|
5922
|
|
|
|
|
|
|
|
|
5923
|
|
|
|
|
|
|
=item * |
|
5924
|
|
|
|
|
|
|
|
|
5925
|
|
|
|
|
|
|
0 if successful. |
|
5926
|
|
|
|
|
|
|
|
|
5927
|
|
|
|
|
|
|
=item * |
|
5928
|
|
|
|
|
|
|
|
|
5929
|
|
|
|
|
|
|
-3 if C<$x> is not strictly increasing. |
|
5930
|
|
|
|
|
|
|
|
|
5931
|
|
|
|
|
|
|
=item * |
|
5932
|
|
|
|
|
|
|
|
|
5933
|
|
|
|
|
|
|
-4 if C<$ia> or C<$ib> is out of range. |
|
5934
|
|
|
|
|
|
|
|
|
5935
|
|
|
|
|
|
|
=back |
|
5936
|
|
|
|
|
|
|
|
|
5937
|
|
|
|
|
|
|
(VALUE will be zero in any of these cases.) |
|
5938
|
|
|
|
|
|
|
NOTE: The above errors are checked in the order listed, and following |
|
5939
|
|
|
|
|
|
|
arguments have B been validated. |
|
5940
|
|
|
|
|
|
|
EOF |
|
5941
|
|
|
|
|
|
|
}, |
|
5942
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
5943
|
|
|
|
|
|
|
=for ref |
|
5944
|
|
|
|
|
|
|
|
|
5945
|
|
|
|
|
|
|
Evaluate the definite integral of a piecewise cubic Hermite function |
|
5946
|
|
|
|
|
|
|
over an interval whose endpoints are data points. |
|
5947
|
|
|
|
|
|
|
|
|
5948
|
|
|
|
|
|
|
Evaluate the definite integral of a a piecewise cubic Hermite |
|
5949
|
|
|
|
|
|
|
function between C and C. |
|
5950
|
|
|
|
|
|
|
|
|
5951
|
|
|
|
|
|
|
See L for integration between arbitrary |
|
5952
|
|
|
|
|
|
|
limits. |
|
5953
|
|
|
|
|
|
|
EOF |
|
5954
|
|
|
|
|
|
|
); |
|
5955
|
|
|
|
|
|
|
|
|
5956
|
|
|
|
|
|
|
pp_def('pchip_chbs', |
|
5957
|
|
|
|
|
|
|
Pars => 'x(n); f(n); d(n); sbyte knotyp(); |
|
5958
|
|
|
|
|
|
|
[o]t(nknots=CALC(2*$SIZE(n)+4)); |
|
5959
|
|
|
|
|
|
|
[o]bcoef(ndim=CALC(2*$SIZE(n))); indx [o]ierr()', |
|
5960
|
|
|
|
|
|
|
GenericTypes => $F, |
|
5961
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
5962
|
|
|
|
|
|
|
/* Local variables */ |
|
5963
|
|
|
|
|
|
|
PDL_Indx n = $SIZE(n), ndim = $SIZE(ndim); |
|
5964
|
|
|
|
|
|
|
$ierr() = 0; |
|
5965
|
|
|
|
|
|
|
/* Check argument validity. Set up knot sequence if OK. */ |
|
5966
|
|
|
|
|
|
|
if ($knotyp() > 2) { |
|
5967
|
|
|
|
|
|
|
$ierr() = -1; |
|
5968
|
|
|
|
|
|
|
$CROAK("KNOTYP GREATER THAN 2"); |
|
5969
|
|
|
|
|
|
|
} |
|
5970
|
|
|
|
|
|
|
if ($knotyp() >= 0) { |
|
5971
|
|
|
|
|
|
|
/* Set up knot sequence. */ |
|
5972
|
|
|
|
|
|
|
do { /* inline dpchkt */ |
|
5973
|
|
|
|
|
|
|
/* Set interior knots. */ |
|
5974
|
|
|
|
|
|
|
PDL_Indx j = 0; |
|
5975
|
|
|
|
|
|
|
loop (n) %{ |
|
5976
|
|
|
|
|
|
|
j += 2; |
|
5977
|
|
|
|
|
|
|
$t(nknots=>j+1) = $t(nknots=>j) = $x(); |
|
5978
|
|
|
|
|
|
|
%} |
|
5979
|
|
|
|
|
|
|
/* Assertion: At this point T(3),...,T(NDIM+2) have been set and */ |
|
5980
|
|
|
|
|
|
|
/* J=NDIM+1. */ |
|
5981
|
|
|
|
|
|
|
/* Set end knots according to KNOTYP. */ |
|
5982
|
|
|
|
|
|
|
$GENERIC() hbeg = $x(n=>1) - $x(n=>0); |
|
5983
|
|
|
|
|
|
|
$GENERIC() hend = $x(n=>n-1) - $x(n=>n-2); |
|
5984
|
|
|
|
|
|
|
if ($knotyp() == 1) { |
|
5985
|
|
|
|
|
|
|
/* Extrapolate. */ |
|
5986
|
|
|
|
|
|
|
$t(nknots=>1) = $x(n=>0) - hbeg; |
|
5987
|
|
|
|
|
|
|
$t(nknots=>ndim+2) = $x(n=>n-1) + hend; |
|
5988
|
|
|
|
|
|
|
} else if ($knotyp() == 2) { |
|
5989
|
|
|
|
|
|
|
/* Periodic. */ |
|
5990
|
|
|
|
|
|
|
$t(nknots=>1) = $x(n=>0) - hend; |
|
5991
|
|
|
|
|
|
|
$t(nknots=>ndim+2) = $x(n=>n-1) + hbeg; |
|
5992
|
|
|
|
|
|
|
} else { |
|
5993
|
|
|
|
|
|
|
/* Quadruple end knots. */ |
|
5994
|
|
|
|
|
|
|
$t(nknots=>1) = $x(n=>0); |
|
5995
|
|
|
|
|
|
|
$t(nknots=>ndim+2) = $x(n=>n-1); |
|
5996
|
|
|
|
|
|
|
} |
|
5997
|
|
|
|
|
|
|
$t(nknots=>0) = $t(nknots=>1); |
|
5998
|
|
|
|
|
|
|
$t(nknots=>ndim+3) = $t(nknots=>ndim+2); |
|
5999
|
|
|
|
|
|
|
} while (0); /* end inline dpchkt */ |
|
6000
|
|
|
|
|
|
|
} |
|
6001
|
|
|
|
|
|
|
/* Compute B-spline coefficients. */ |
|
6002
|
|
|
|
|
|
|
$GENERIC() hnew = $t(nknots=>2) - $t(nknots=>0); |
|
6003
|
|
|
|
|
|
|
loop (n) %{ |
|
6004
|
|
|
|
|
|
|
$GENERIC() hold = hnew; |
|
6005
|
|
|
|
|
|
|
/* The following requires mixed mode arithmetic. */ |
|
6006
|
|
|
|
|
|
|
$GENERIC() dov3 = $d() / 3; |
|
6007
|
|
|
|
|
|
|
$bcoef(ndim=>2*n) = $f() - hold * dov3; |
|
6008
|
|
|
|
|
|
|
/* The following assumes T(2*K+1) = X(K). */ |
|
6009
|
|
|
|
|
|
|
hnew = $t(nknots=>2*n+4) - $t(nknots=>2*n+2); |
|
6010
|
|
|
|
|
|
|
$bcoef(ndim=>2*n+1) = $f() + hnew * dov3; |
|
6011
|
|
|
|
|
|
|
%} |
|
6012
|
|
|
|
|
|
|
EOF |
|
6013
|
|
|
|
|
|
|
ParamDesc => { |
|
6014
|
|
|
|
|
|
|
f => <<'EOF', |
|
6015
|
|
|
|
|
|
|
the array of dependent variable values. |
|
6016
|
|
|
|
|
|
|
C is the value corresponding to C. |
|
6017
|
|
|
|
|
|
|
EOF |
|
6018
|
|
|
|
|
|
|
d => <<'EOF', |
|
6019
|
|
|
|
|
|
|
the array of derivative values at the data points. |
|
6020
|
|
|
|
|
|
|
C is the value corresponding to C. |
|
6021
|
|
|
|
|
|
|
EOF |
|
6022
|
|
|
|
|
|
|
knotyp => <<'EOF', |
|
6023
|
|
|
|
|
|
|
flag which controls the knot sequence. |
|
6024
|
|
|
|
|
|
|
The knot sequence C is normally computed from C<$x> |
|
6025
|
|
|
|
|
|
|
by putting a double knot at each C and setting the end knot pairs |
|
6026
|
|
|
|
|
|
|
according to the value of C (where C): |
|
6027
|
|
|
|
|
|
|
|
|
6028
|
|
|
|
|
|
|
=over |
|
6029
|
|
|
|
|
|
|
|
|
6030
|
|
|
|
|
|
|
=item * |
|
6031
|
|
|
|
|
|
|
|
|
6032
|
|
|
|
|
|
|
0 - Quadruple knots at the first and last points. |
|
6033
|
|
|
|
|
|
|
|
|
6034
|
|
|
|
|
|
|
=item * |
|
6035
|
|
|
|
|
|
|
|
|
6036
|
|
|
|
|
|
|
1 - Replicate lengths of extreme subintervals: |
|
6037
|
|
|
|
|
|
|
C and |
|
6038
|
|
|
|
|
|
|
C |
|
6039
|
|
|
|
|
|
|
|
|
6040
|
|
|
|
|
|
|
=item * |
|
6041
|
|
|
|
|
|
|
|
|
6042
|
|
|
|
|
|
|
2 - Periodic placement of boundary knots: |
|
6043
|
|
|
|
|
|
|
C and |
|
6044
|
|
|
|
|
|
|
C |
|
6045
|
|
|
|
|
|
|
|
|
6046
|
|
|
|
|
|
|
=item * |
|
6047
|
|
|
|
|
|
|
|
|
6048
|
|
|
|
|
|
|
E0 - Assume the C and C were set in a previous call. |
|
6049
|
|
|
|
|
|
|
This option is provided for improved efficiency when used |
|
6050
|
|
|
|
|
|
|
in a parametric setting. |
|
6051
|
|
|
|
|
|
|
|
|
6052
|
|
|
|
|
|
|
=back |
|
6053
|
|
|
|
|
|
|
EOF |
|
6054
|
|
|
|
|
|
|
t => <<'EOF', |
|
6055
|
|
|
|
|
|
|
the array of C<2*n+4> knots for the B-representation |
|
6056
|
|
|
|
|
|
|
and may be changed by the routine. |
|
6057
|
|
|
|
|
|
|
If C= 0>, C will be changed so that the |
|
6058
|
|
|
|
|
|
|
interior double knots are equal to the x-values and the |
|
6059
|
|
|
|
|
|
|
boundary knots set as indicated above, |
|
6060
|
|
|
|
|
|
|
otherwise it is assumed that C was set by a |
|
6061
|
|
|
|
|
|
|
previous call (no check is made to verify that the data |
|
6062
|
|
|
|
|
|
|
forms a legitimate knot sequence). |
|
6063
|
|
|
|
|
|
|
EOF |
|
6064
|
|
|
|
|
|
|
bcoef => 'the array of 2*N B-spline coefficients.', |
|
6065
|
|
|
|
|
|
|
ierr => <<'EOF', |
|
6066
|
|
|
|
|
|
|
Error status: |
|
6067
|
|
|
|
|
|
|
|
|
6068
|
|
|
|
|
|
|
=over |
|
6069
|
|
|
|
|
|
|
|
|
6070
|
|
|
|
|
|
|
=item * |
|
6071
|
|
|
|
|
|
|
|
|
6072
|
|
|
|
|
|
|
0 if successful. |
|
6073
|
|
|
|
|
|
|
|
|
6074
|
|
|
|
|
|
|
=item * |
|
6075
|
|
|
|
|
|
|
|
|
6076
|
|
|
|
|
|
|
-4 if C 2>. (recoverable) |
|
6077
|
|
|
|
|
|
|
|
|
6078
|
|
|
|
|
|
|
=item * |
|
6079
|
|
|
|
|
|
|
|
|
6080
|
|
|
|
|
|
|
-5 if C 0> and C. (recoverable) |
|
6081
|
|
|
|
|
|
|
|
|
6082
|
|
|
|
|
|
|
=back |
|
6083
|
|
|
|
|
|
|
EOF |
|
6084
|
|
|
|
|
|
|
}, |
|
6085
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
6086
|
|
|
|
|
|
|
=for ref |
|
6087
|
|
|
|
|
|
|
|
|
6088
|
|
|
|
|
|
|
Piecewise Cubic Hermite function to B-Spline converter. |
|
6089
|
|
|
|
|
|
|
|
|
6090
|
|
|
|
|
|
|
Computes the B-spline representation of the PCH function |
|
6091
|
|
|
|
|
|
|
determined by N,X,F,D. The output is the B-representation for the |
|
6092
|
|
|
|
|
|
|
function: NKNOTS, T, BCOEF, NDIM, KORD. |
|
6093
|
|
|
|
|
|
|
|
|
6094
|
|
|
|
|
|
|
L, L, or L can be used to |
|
6095
|
|
|
|
|
|
|
determine an interpolating PCH function from a set of data. The |
|
6096
|
|
|
|
|
|
|
B-spline routine L can be used to evaluate the |
|
6097
|
|
|
|
|
|
|
resulting B-spline representation of the data |
|
6098
|
|
|
|
|
|
|
(i.e. C, C, C, C, and |
|
6099
|
|
|
|
|
|
|
C). |
|
6100
|
|
|
|
|
|
|
|
|
6101
|
|
|
|
|
|
|
Caution: Since it is assumed that the input PCH function has been |
|
6102
|
|
|
|
|
|
|
computed by one of the other routines in the package PCHIP, |
|
6103
|
|
|
|
|
|
|
input arguments N, X are B checked for validity. |
|
6104
|
|
|
|
|
|
|
|
|
6105
|
|
|
|
|
|
|
Restrictions/assumptions: |
|
6106
|
|
|
|
|
|
|
|
|
6107
|
|
|
|
|
|
|
=over |
|
6108
|
|
|
|
|
|
|
|
|
6109
|
|
|
|
|
|
|
=item C<1> |
|
6110
|
|
|
|
|
|
|
|
|
6111
|
|
|
|
|
|
|
N.GE.2 . (not checked) |
|
6112
|
|
|
|
|
|
|
|
|
6113
|
|
|
|
|
|
|
=item C<2> |
|
6114
|
|
|
|
|
|
|
|
|
6115
|
|
|
|
|
|
|
X(i).LT.X(i+1), i=1,...,N . (not checked) |
|
6116
|
|
|
|
|
|
|
|
|
6117
|
|
|
|
|
|
|
=item C<4> |
|
6118
|
|
|
|
|
|
|
|
|
6119
|
|
|
|
|
|
|
KNOTYP.LE.2 . (error return if not) |
|
6120
|
|
|
|
|
|
|
|
|
6121
|
|
|
|
|
|
|
=item C<6> |
|
6122
|
|
|
|
|
|
|
|
|
6123
|
|
|
|
|
|
|
T(2*k+1) = T(2*k) = X(k), k=1,...,N . (not checked) |
|
6124
|
|
|
|
|
|
|
|
|
6125
|
|
|
|
|
|
|
* Indicates this applies only if KNOTYP.LT.0 . |
|
6126
|
|
|
|
|
|
|
|
|
6127
|
|
|
|
|
|
|
=back |
|
6128
|
|
|
|
|
|
|
|
|
6129
|
|
|
|
|
|
|
References: F. N. Fritsch, "Representations for parametric cubic |
|
6130
|
|
|
|
|
|
|
splines," Computer Aided Geometric Design 6 (1989), pp.79-82. |
|
6131
|
|
|
|
|
|
|
EOF |
|
6132
|
|
|
|
|
|
|
); |
|
6133
|
|
|
|
|
|
|
|
|
6134
|
|
|
|
|
|
|
pp_def('pchip_bvalu', |
|
6135
|
|
|
|
|
|
|
Pars => 't(nplusk); a(n); indx ideriv(); x(); |
|
6136
|
|
|
|
|
|
|
[o]ans(); indx [o] inbv(); |
|
6137
|
|
|
|
|
|
|
[t] work(k3=CALC(3*($SIZE(nplusk)-$SIZE(n))));', |
|
6138
|
|
|
|
|
|
|
GenericTypes => $F, |
|
6139
|
|
|
|
|
|
|
RedoDimsCode => <<'EOF', |
|
6140
|
|
|
|
|
|
|
PDL_Indx k = $SIZE(nplusk) - $SIZE(n); |
|
6141
|
|
|
|
|
|
|
if (k < 1) $CROAK("K DOES NOT SATISFY K.GE.1"); |
|
6142
|
|
|
|
|
|
|
if ($SIZE(n) < k) $CROAK("N DOES NOT SATISFY N.GE.K"); |
|
6143
|
|
|
|
|
|
|
EOF |
|
6144
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
6145
|
88
|
|
|
|
|
70903
|
PDL_Indx k = $SIZE(nplusk) - $SIZE(n); |
|
6146
|
88
|
100
|
|
|
|
133
|
if ($ideriv() < 0 || $ideriv() >= k) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6147
|
70
|
|
|
|
|
2871
|
$CROAK("IDERIV DOES NOT SATISFY 0.LE.IDERIV.LT.K"); |
|
6148
|
|
|
|
|
|
|
PDL_Indx i; |
|
6149
|
|
|
|
|
|
|
int mflag; |
|
6150
|
|
|
|
|
|
|
/* *** FIND *I* IN (K,N) SUCH THAT T(I) .LE. X .LT. T(I+1) */ |
|
6151
|
|
|
|
|
|
|
/* (OR, .LE. T(I+1) IF T(I) .LT. T(I+1) = T(N+1)). */ |
|
6152
|
|
|
|
|
|
|
do { /* inlined dintrv */ |
|
6153
|
88
|
|
|
|
|
330
|
PDL_Indx ihi = $inbv() + 1, lxt = $SIZE(n); |
|
6154
|
88
|
0
|
|
|
|
138
|
if (ihi >= lxt) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6155
|
70
|
50
|
|
|
|
4271
|
if ($x() >= $t(nplusk=>lxt)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6156
|
70
|
|
|
|
|
50710
|
mflag = 1; i = lxt; break; |
|
6157
|
|
|
|
|
|
|
} |
|
6158
|
70
|
50
|
|
|
|
233
|
if (lxt <= 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6159
|
70
|
|
|
|
|
2662
|
mflag = -1; i = 0; break; |
|
6160
|
|
|
|
|
|
|
} |
|
6161
|
70
|
|
|
|
|
2648
|
ihi = $inbv() = lxt; |
|
6162
|
|
|
|
|
|
|
} |
|
6163
|
88
|
|
|
|
|
133
|
char skipflag = 0; |
|
6164
|
88
|
50
|
|
|
|
76800
|
if ($x() < $t(nplusk=>ihi)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6165
|
70
|
|
|
|
|
675
|
PDL_Indx inbv = $inbv(); |
|
6166
|
70
|
50
|
|
|
|
134
|
if ($x() >= $t(nplusk=>inbv)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6167
|
70
|
|
|
|
|
534
|
mflag = 0; i = $inbv(); break; |
|
6168
|
|
|
|
|
|
|
} |
|
6169
|
|
|
|
|
|
|
/* *** NOW X .LT. XT(IHI) . FIND LOWER BOUND */ |
|
6170
|
70
|
|
|
|
|
47286
|
PDL_Indx istep = 1; |
|
6171
|
70
|
|
|
|
|
1380
|
while (1) { |
|
6172
|
70
|
|
|
|
|
1201
|
ihi = $inbv(); |
|
6173
|
138
|
|
|
|
|
3819
|
$inbv() = ihi - istep; |
|
6174
|
138
|
100
|
|
|
|
466
|
if ($inbv() <= 0) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6175
|
138
|
|
|
|
|
673
|
break; |
|
6176
|
|
|
|
|
|
|
} |
|
6177
|
138
|
|
|
|
|
574
|
PDL_Indx inbv = $inbv(); |
|
6178
|
29
|
50
|
|
|
|
104
|
if ($x() >= $t(nplusk=>inbv)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6179
|
138
|
|
|
|
|
459
|
skipflag = 1; |
|
6180
|
2
|
|
|
|
|
9
|
break; |
|
6181
|
|
|
|
|
|
|
} |
|
6182
|
138
|
|
|
|
|
1126
|
istep <<= 1; |
|
6183
|
|
|
|
|
|
|
} |
|
6184
|
135
|
50
|
|
|
|
577
|
if (!skipflag) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6185
|
133
|
|
|
|
|
4601
|
$inbv() = 0; |
|
6186
|
133
|
100
|
|
|
|
1044
|
if ($x() < $t(nplusk=>0)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6187
|
0
|
|
|
|
|
0
|
mflag = -1; i = 0; break; |
|
6188
|
|
|
|
|
|
|
} |
|
6189
|
|
|
|
|
|
|
} |
|
6190
|
0
|
|
|
|
|
0
|
skipflag = 1; |
|
6191
|
|
|
|
|
|
|
/* *** NOW X .GE. XT(ILO) . FIND UPPER BOUND */ |
|
6192
|
|
|
|
|
|
|
} |
|
6193
|
18
|
50
|
|
|
|
0
|
if (!skipflag) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6194
|
18
|
|
|
|
|
0
|
PDL_Indx istep = 1; |
|
6195
|
|
|
|
|
|
|
while (1) { |
|
6196
|
68
|
|
|
|
|
0
|
$inbv() = ihi; |
|
6197
|
68
|
|
|
|
|
0
|
ihi = $inbv() + istep; |
|
6198
|
119
|
50
|
|
|
|
150
|
if (ihi >= lxt) break; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6199
|
115
|
50
|
|
|
|
252
|
if ($x() < $t(nplusk=>ihi)) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6200
|
60
|
|
|
|
|
136
|
skipflag = 1; |
|
6201
|
48
|
|
|
|
|
92
|
break; |
|
6202
|
|
|
|
|
|
|
} |
|
6203
|
84
|
|
|
|
|
128
|
istep <<= 1; |
|
6204
|
|
|
|
|
|
|
} |
|
6205
|
52
|
100
|
|
|
|
254
|
if (!skipflag) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6206
|
38
|
50
|
|
|
|
506
|
if ($x() >= $t(nplusk=>lxt)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6207
|
34
|
|
|
|
|
613
|
mflag = 1; i = lxt; break; |
|
6208
|
|
|
|
|
|
|
} |
|
6209
|
6
|
|
|
|
|
12
|
ihi = lxt; |
|
6210
|
|
|
|
|
|
|
} |
|
6211
|
|
|
|
|
|
|
} |
|
6212
|
|
|
|
|
|
|
/* *** NOW XT(ILO) .LE. X .LT. XT(IHI) . NARROW THE INTERVAL */ |
|
6213
|
44
|
|
|
|
|
13
|
while (1) { |
|
6214
|
62
|
|
|
|
|
7
|
PDL_Indx middle = ($inbv() + ihi) / 2; |
|
6215
|
62
|
50
|
|
|
|
11
|
if (middle == $inbv()) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6216
|
20
|
|
|
|
|
11
|
mflag = 0; i = $inbv(); break; |
|
6217
|
|
|
|
|
|
|
} |
|
6218
|
|
|
|
|
|
|
/* NOTE. IT IS ASSUMED THAT MIDDLE = ILO IN CASE IHI = ILO+1 */ |
|
6219
|
44
|
50
|
|
|
|
13
|
if ($x() < $t(nplusk=>middle)) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6220
|
14
|
|
|
|
|
24
|
ihi = middle; |
|
6221
|
|
|
|
|
|
|
else |
|
6222
|
32
|
|
|
|
|
10
|
$inbv() = middle; |
|
6223
|
|
|
|
|
|
|
} |
|
6224
|
|
|
|
|
|
|
} while (0); /* end dintrv inlined */ |
|
6225
|
20
|
50
|
|
|
|
29
|
if ($x() < $t(nplusk=>k-1)) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6226
|
2
|
|
|
|
|
37
|
$CROAK("X IS N0T GREATER THAN OR EQUAL TO T(K)"); |
|
6227
|
|
|
|
|
|
|
} |
|
6228
|
20
|
50
|
|
|
|
46
|
if (mflag != 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6229
|
0
|
100
|
|
|
|
0
|
if ($x() > $t(nplusk=>i)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6230
|
2
|
|
|
|
|
4
|
$CROAK("X IS NOT LESS THAN OR EQUAL TO T(N+1)"); |
|
6231
|
|
|
|
|
|
|
} |
|
6232
|
|
|
|
|
|
|
while (1) { |
|
6233
|
2
|
100
|
|
|
|
12
|
if (i == k-1) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6234
|
2
|
|
|
|
|
27
|
$CROAK("A LEFT LIMITING VALUE CANNOT BE OBTAINED AT T(K)"); |
|
6235
|
|
|
|
|
|
|
} |
|
6236
|
0
|
|
|
|
|
0
|
--i; |
|
6237
|
2
|
50
|
|
|
|
42
|
if ($x() != $t(nplusk=>i)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6238
|
19
|
|
|
|
|
53
|
break; |
|
6239
|
|
|
|
|
|
|
} |
|
6240
|
|
|
|
|
|
|
} |
|
6241
|
|
|
|
|
|
|
/* *** DIFFERENCE THE COEFFICIENTS *IDERIV* TIMES */ |
|
6242
|
|
|
|
|
|
|
/* WORK(I) = AJ(I), WORK(K+I) = DP(I), WORK(K+K+I) = DM(I), I=1.K */ |
|
6243
|
|
|
|
|
|
|
} |
|
6244
|
37
|
|
|
|
|
244
|
PDL_Indx imk = i+1 - k, j; |
|
6245
|
109
|
50
|
|
|
|
87
|
loop (k3=:k) %{ |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6246
|
90
|
|
|
|
|
224
|
$work() = $a(n=>imk+k3); |
|
6247
|
|
|
|
|
|
|
%} |
|
6248
|
36
|
50
|
|
|
|
17466
|
if ($ideriv() != 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6249
|
18
|
100
|
|
|
|
237
|
for (j = 0; j < $ideriv(); ++j) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6250
|
18
|
|
|
|
|
218
|
PDL_Indx kmj = k - j - 1; |
|
6251
|
18
|
|
|
|
|
933
|
$GENERIC() fkmj = kmj; |
|
6252
|
18
|
100
|
|
|
|
193
|
loop (k3=0:kmj) %{ |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6253
|
18
|
|
|
|
|
77878
|
PDL_Indx ihi = i+1 + k3; |
|
6254
|
18
|
|
|
|
|
121
|
$work() = ($work(k3=>k3+1) - $work()) / ($t(nplusk=>ihi) - $t(nplusk=>ihi-kmj)) * fkmj; |
|
6255
|
|
|
|
|
|
|
%} |
|
6256
|
|
|
|
|
|
|
} |
|
6257
|
|
|
|
|
|
|
/* *** COMPUTE VALUE AT *X* IN (T(I),T(I+1)) OF IDERIV-TH DERIVATIVE, */ |
|
6258
|
|
|
|
|
|
|
/* GIVEN ITS RELEVANT B-SPLINE COEFF. IN AJ(1),...,AJ(K-IDERIV). */ |
|
6259
|
|
|
|
|
|
|
} |
|
6260
|
36
|
|
|
|
|
74
|
PDL_Indx km1 = k - 1; |
|
6261
|
36
|
100
|
|
|
|
91
|
if ($ideriv() != km1) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6262
|
18
|
|
|
|
|
0
|
PDL_Indx j, j1 = k, kpk = k + k, j2 = kpk, kmider = k - $ideriv(); |
|
6263
|
90
|
100
|
|
|
|
0
|
for (j = 0; j < kmider; ++j) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6264
|
90
|
|
|
|
|
492
|
PDL_Indx ipj = i + j + 1; |
|
6265
|
90
|
|
|
|
|
968
|
$work(k3=>j1) = $t(nplusk=>ipj) - $x(); |
|
6266
|
90
|
|
|
|
|
237
|
$work(k3=>j2) = $x() - $t(nplusk=>i-j); |
|
6267
|
74
|
|
|
|
|
9
|
++j1; |
|
6268
|
74
|
|
|
|
|
5
|
++j2; |
|
6269
|
|
|
|
|
|
|
} |
|
6270
|
74
|
100
|
|
|
|
52
|
for (j = $ideriv(); j < km1; ++j) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6271
|
54
|
|
|
|
|
0
|
PDL_Indx kmj = k - j - 1, ilo = kpk + kmj - 1; |
|
6272
|
162
|
50
|
|
|
|
0
|
loop (k3=0:kmj) %{ |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6273
|
108
|
|
|
|
|
0
|
$work() = ($work(k3=>k3+1) * $work(k3=>ilo) + $work() * |
|
6274
|
110
|
|
|
|
|
16
|
$work(k3=>k+k3)) / ($work(k3=>ilo) + $work(k3=>k+k3)); |
|
6275
|
110
|
|
|
|
|
332
|
--ilo; |
|
6276
|
|
|
|
|
|
|
%} |
|
6277
|
|
|
|
|
|
|
} |
|
6278
|
|
|
|
|
|
|
} |
|
6279
|
20
|
|
|
|
|
60
|
$ans() = $work(k3=>0); |
|
6280
|
|
|
|
|
|
|
EOF |
|
6281
|
|
|
|
|
|
|
ParamDesc => { |
|
6282
|
|
|
|
|
|
|
t => <<'EOF', |
|
6283
|
|
|
|
|
|
|
knot vector of length N+K |
|
6284
|
|
|
|
|
|
|
EOF |
|
6285
|
|
|
|
|
|
|
a => <<'EOF', |
|
6286
|
|
|
|
|
|
|
B-spline coefficient vector of length N, |
|
6287
|
|
|
|
|
|
|
the number of B-spline coefficients; N = sum of knot multiplicities-K |
|
6288
|
|
|
|
|
|
|
EOF |
|
6289
|
|
|
|
|
|
|
ideriv => <<'EOF', |
|
6290
|
|
|
|
|
|
|
order of the derivative, 0 .LE. IDERIV .LE. K-1 |
|
6291
|
|
|
|
|
|
|
|
|
6292
|
|
|
|
|
|
|
IDERIV=0 returns the B-spline value |
|
6293
|
|
|
|
|
|
|
EOF |
|
6294
|
|
|
|
|
|
|
x => <<'EOF', |
|
6295
|
|
|
|
|
|
|
T(K) .LE. X .LE. T(N+1) |
|
6296
|
|
|
|
|
|
|
EOF |
|
6297
|
|
|
|
|
|
|
inbv => <<'EOF', |
|
6298
|
|
|
|
|
|
|
contains information for efficient processing after the initial |
|
6299
|
|
|
|
|
|
|
call and INBV must not |
|
6300
|
|
|
|
|
|
|
be changed by the user. Distinct splines require distinct INBV parameters. |
|
6301
|
|
|
|
|
|
|
EOF |
|
6302
|
|
|
|
|
|
|
ans => <<'EOF', |
|
6303
|
|
|
|
|
|
|
value of the IDERIV-th derivative at X |
|
6304
|
|
|
|
|
|
|
EOF |
|
6305
|
|
|
|
|
|
|
}, |
|
6306
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
6307
|
|
|
|
|
|
|
=for ref |
|
6308
|
|
|
|
|
|
|
|
|
6309
|
|
|
|
|
|
|
Evaluate the B-representation of a B-spline at X for the |
|
6310
|
|
|
|
|
|
|
function value or any of its derivatives. |
|
6311
|
|
|
|
|
|
|
|
|
6312
|
|
|
|
|
|
|
Evaluates the B-representation C<(T,A,N,K)> of a B-spline |
|
6313
|
|
|
|
|
|
|
at C for the function value on C or any of its |
|
6314
|
|
|
|
|
|
|
derivatives on C. Right limiting values |
|
6315
|
|
|
|
|
|
|
(right derivatives) are returned except at the right end |
|
6316
|
|
|
|
|
|
|
point C where left limiting values are computed. The |
|
6317
|
|
|
|
|
|
|
spline is defined on C. BVALU returns |
|
6318
|
|
|
|
|
|
|
a fatal error message when C is outside of this interval. |
|
6319
|
|
|
|
|
|
|
|
|
6320
|
|
|
|
|
|
|
To compute left derivatives or left limiting values at a |
|
6321
|
|
|
|
|
|
|
knot C, replace C by C and set C, C. |
|
6322
|
|
|
|
|
|
|
|
|
6323
|
|
|
|
|
|
|
References: Carl de Boor, Package for calculating with B-splines, |
|
6324
|
|
|
|
|
|
|
SIAM Journal on Numerical Analysis 14, 3 (June 1977), pp. 441-472. |
|
6325
|
|
|
|
|
|
|
EOF |
|
6326
|
|
|
|
|
|
|
); |
|
6327
|
|
|
|
|
|
|
|
|
6328
|
|
|
|
|
|
|
pp_addpm({At=>'Bot'},<<'EOD'); |
|
6329
|
|
|
|
|
|
|
|
|
6330
|
|
|
|
|
|
|
=head1 AUTHOR |
|
6331
|
|
|
|
|
|
|
|
|
6332
|
|
|
|
|
|
|
Copyright (C) Tuomas J. Lukka 1997 (lukka@husc.harvard.edu). Contributions |
|
6333
|
|
|
|
|
|
|
by Christian Soeller (c.soeller@auckland.ac.nz), Karl Glazebrook |
|
6334
|
|
|
|
|
|
|
(kgb@aaoepp.aao.gov.au), Craig DeForest (deforest@boulder.swri.edu) |
|
6335
|
|
|
|
|
|
|
and Jarle Brinchmann (jarle@astro.up.pt) |
|
6336
|
|
|
|
|
|
|
All rights reserved. There is no warranty. You are allowed |
|
6337
|
|
|
|
|
|
|
to redistribute this software / documentation under certain |
|
6338
|
|
|
|
|
|
|
conditions. For details, see the file COPYING in the PDL |
|
6339
|
|
|
|
|
|
|
distribution. If this file is separated from the PDL distribution, |
|
6340
|
|
|
|
|
|
|
the copyright notice should be included in the file. |
|
6341
|
|
|
|
|
|
|
|
|
6342
|
|
|
|
|
|
|
Updated for CPAN viewing compatibility by David Mertens. |
|
6343
|
|
|
|
|
|
|
|
|
6344
|
|
|
|
|
|
|
=cut |
|
6345
|
|
|
|
|
|
|
|
|
6346
|
|
|
|
|
|
|
EOD |
|
6347
|
|
|
|
|
|
|
|
|
6348
|
|
|
|
|
|
|
pp_done(); |