| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
=head1 NAME |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Math::Interpolator - interpolate between lazily-evaluated points |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use Math::Interpolator; |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
$ipl = Math::Interpolator->new(@points); |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
@points = $ipl->nhood_x($x, 1); |
|
12
|
|
|
|
|
|
|
@points = $ipl->nhood_y($y, 1); |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
This class supports interpolation of a curve between known points, |
|
17
|
|
|
|
|
|
|
known as "knots", with the knots being lazily evaluated. An object of |
|
18
|
|
|
|
|
|
|
this type represents a set of knots on a one-dimensional curve, the knots |
|
19
|
|
|
|
|
|
|
possibly not being predetermined. The methods implemented in this class |
|
20
|
|
|
|
|
|
|
extract knots, forcing evaluation as required. Subclasses implement |
|
21
|
|
|
|
|
|
|
interpolation by various algorithms. |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
This code is neutral as to numeric type. The coordinate values used |
|
24
|
|
|
|
|
|
|
in interpolation may be native Perl numbers, C objects, |
|
25
|
|
|
|
|
|
|
or possibly other types. Mixing types within a single interpolation is |
|
26
|
|
|
|
|
|
|
not recommended. |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=cut |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
package Math::Interpolator; |
|
31
|
|
|
|
|
|
|
|
|
32
|
9
|
|
|
9
|
|
24074
|
{ use 5.006; } |
|
|
9
|
|
|
|
|
30
|
|
|
|
9
|
|
|
|
|
427
|
|
|
33
|
9
|
|
|
9
|
|
45
|
use warnings; |
|
|
9
|
|
|
|
|
18
|
|
|
|
9
|
|
|
|
|
283
|
|
|
34
|
9
|
|
|
9
|
|
54
|
use strict; |
|
|
9
|
|
|
|
|
14
|
|
|
|
9
|
|
|
|
|
391
|
|
|
35
|
|
|
|
|
|
|
|
|
36
|
9
|
|
|
9
|
|
42
|
use Carp qw(croak); |
|
|
9
|
|
|
|
|
14
|
|
|
|
9
|
|
|
|
|
2641
|
|
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
our $VERSION = "0.005"; |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=over |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item Math::Interpolator->new(POINT ...) |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
A list of zero or more point objects must be supplied. They are wrapped |
|
47
|
|
|
|
|
|
|
up as an interpolator object, which is returned. |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
The objects in the list must each implement the interface of either |
|
50
|
|
|
|
|
|
|
C or C. It is |
|
51
|
|
|
|
|
|
|
not necessary for them to actually be of those classes; reimplementing |
|
52
|
|
|
|
|
|
|
the same interfaces is acceptable. They do not need to all be of the |
|
53
|
|
|
|
|
|
|
same class. A knot-interface object represents a single point on the |
|
54
|
|
|
|
|
|
|
curve, whereas a source-interface object represents an undetermined set |
|
55
|
|
|
|
|
|
|
of knots within a particular range of x coordinates. |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
The point objects must be sorted such that their x coordinates are |
|
58
|
|
|
|
|
|
|
monotonically non-decreasing. The range of x coordinates covered by |
|
59
|
|
|
|
|
|
|
each source must not include any individual knot nor overlap the range |
|
60
|
|
|
|
|
|
|
of any other source. |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
If reverse interpolation (determining an x coordinate given a y |
|
63
|
|
|
|
|
|
|
coordinate) is to be performed, then the y coordinates must be similarly |
|
64
|
|
|
|
|
|
|
sorted. |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Normally it would not be desired to instantiate this class directly, |
|
67
|
|
|
|
|
|
|
because it contains no interpolation methods. A subclass such as |
|
68
|
|
|
|
|
|
|
C or C should |
|
69
|
|
|
|
|
|
|
be instantiated instead. |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=cut |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub new { |
|
74
|
16
|
|
|
16
|
1
|
41
|
my $class = shift; |
|
75
|
16
|
|
|
|
|
73
|
return bless(\@_, $class); |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=back |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head1 METHODS |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=over |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=item $ipl->nhood_x(X, N) |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
Returns a list of 2*N consecutive knots (with the |
|
87
|
|
|
|
|
|
|
C interface) defining the curve in the |
|
88
|
|
|
|
|
|
|
neighbourhood of x=X. There will be N knots on either side of x=X. |
|
89
|
|
|
|
|
|
|
If one of the knots has x=X exactly then that knot will be treated as |
|
90
|
|
|
|
|
|
|
if it had x
|
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=item $ipl->nhood_y(Y, N) |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Does the same thing as C, but for y coordinates. This is |
|
95
|
|
|
|
|
|
|
only possible if the y coordinates are monotonically non-decreasing for |
|
96
|
|
|
|
|
|
|
increasing x. |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=back |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub _expand { |
|
103
|
12
|
|
|
12
|
|
22
|
my($self, $n) = @_; |
|
104
|
12
|
|
|
|
|
39
|
my $exp = $self->[$n]->expand; |
|
105
|
12
|
|
|
|
|
43
|
splice @$self, $n, 1, @$exp; |
|
106
|
12
|
|
|
|
|
60
|
return @$exp - 1; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _nhood { |
|
110
|
136
|
|
|
136
|
|
202
|
my($self, $x_method, $x, $n) = @_; |
|
111
|
|
|
|
|
|
|
START: |
|
112
|
137
|
50
|
|
|
|
380
|
if(@$self < 2) { |
|
113
|
0
|
|
0
|
|
|
0
|
while(@$self == 1 && $self->[0]->role eq "SOURCE") { |
|
114
|
0
|
|
|
|
|
0
|
$self->_expand(0); |
|
115
|
|
|
|
|
|
|
} |
|
116
|
0
|
0
|
|
|
|
0
|
croak "no useful data" if @$self < 2; |
|
117
|
|
|
|
|
|
|
} |
|
118
|
137
|
|
|
|
|
157
|
my $min = 0; |
|
119
|
137
|
|
|
|
|
256
|
my $max = @$self - 1; |
|
120
|
|
|
|
|
|
|
BINSEARCH: |
|
121
|
148
|
|
|
|
|
338
|
while($max != $min + 1) { |
|
122
|
9
|
|
|
9
|
|
8000
|
my $try = do { use integer; ($min + $max) / 2 }; |
|
|
9
|
|
|
|
|
94
|
|
|
|
9
|
|
|
|
|
50
|
|
|
|
317
|
|
|
|
|
354
|
|
|
|
317
|
|
|
|
|
418
|
|
|
123
|
317
|
100
|
|
|
|
934
|
if($x >= $self->[$try]->$x_method) { |
|
124
|
181
|
|
|
|
|
430
|
$min = $try; |
|
125
|
|
|
|
|
|
|
} else { |
|
126
|
136
|
|
|
|
|
359
|
$max = $try; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
} |
|
129
|
148
|
100
|
100
|
|
|
775
|
if($min == 0 && $x < $self->[$min]->$x_method) { |
|
|
|
100
|
100
|
|
|
|
|
|
130
|
7
|
100
|
|
|
|
33
|
croak "data does not extend to $x_method=$x" |
|
131
|
|
|
|
|
|
|
unless $self->[0]->role eq "SOURCE"; |
|
132
|
2
|
|
|
|
|
6
|
$max += $self->_expand(0); |
|
133
|
2
|
50
|
|
|
|
6
|
goto START if $min == $max; |
|
134
|
2
|
|
|
|
|
15
|
goto BINSEARCH; |
|
135
|
|
|
|
|
|
|
} elsif($max == @$self-1 && $x > $self->[$max]->$x_method) { |
|
136
|
7
|
100
|
|
|
|
518
|
croak "data does not extend to $x_method=$x" |
|
137
|
|
|
|
|
|
|
unless $self->[$max]->role eq "SOURCE"; |
|
138
|
2
|
|
|
|
|
6
|
$max += $self->_expand($max); |
|
139
|
2
|
50
|
|
|
|
6
|
goto START if $min == $max; |
|
140
|
2
|
|
|
|
|
16
|
goto BINSEARCH; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
134
|
100
|
|
|
|
401
|
if($self->[$min]->role eq "SOURCE") { |
|
|
|
100
|
|
|
|
|
|
|
143
|
2
|
|
|
|
|
6
|
$max += $self->_expand($min); |
|
144
|
2
|
50
|
|
|
|
7
|
goto START if $min == $max; |
|
145
|
2
|
50
|
|
|
|
6
|
$min-- unless $min == 0; |
|
146
|
2
|
|
|
|
|
11
|
goto BINSEARCH; |
|
147
|
|
|
|
|
|
|
} elsif($self->[$max]->role eq "SOURCE") { |
|
148
|
6
|
|
|
|
|
34
|
$max += $self->_expand($max); |
|
149
|
6
|
100
|
|
|
|
27
|
goto START if $min == $max; |
|
150
|
5
|
100
|
|
|
|
16
|
$max++ unless $max == @$self - 1; |
|
151
|
5
|
|
|
|
|
36
|
goto BINSEARCH; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
126
|
|
|
|
|
679
|
while(1) { |
|
154
|
200
|
50
|
33
|
|
|
554
|
croak "non-knot in region" |
|
155
|
|
|
|
|
|
|
unless $self->[$min]->role eq "KNOT" && |
|
156
|
|
|
|
|
|
|
$self->[$max]->role eq "KNOT"; |
|
157
|
200
|
100
|
|
|
|
428
|
last unless --$n; |
|
158
|
76
|
|
|
|
|
80
|
while(1) { |
|
159
|
76
|
100
|
100
|
|
|
717
|
croak "data does not extend to $x_method=$x" |
|
160
|
|
|
|
|
|
|
if $min == 0 || $max == @$self - 1; |
|
161
|
74
|
|
|
|
|
79
|
my $expanded; |
|
162
|
74
|
50
|
|
|
|
411
|
if($self->[$min-1]->role eq "SOURCE") { |
|
163
|
0
|
|
|
|
|
0
|
my $diff = $self->_expand($min-1); |
|
164
|
0
|
|
|
|
|
0
|
$min += $diff; |
|
165
|
0
|
|
|
|
|
0
|
$max += $diff; |
|
166
|
0
|
|
|
|
|
0
|
$expanded = 1; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
74
|
50
|
|
|
|
224
|
if($self->[$max+1]->role eq "SOURCE") { |
|
169
|
0
|
|
|
|
|
0
|
$self->_expand($max+1); |
|
170
|
0
|
|
|
|
|
0
|
$expanded = 1; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
74
|
50
|
|
|
|
321
|
last unless $expanded; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
74
|
|
|
|
|
75
|
$min--; |
|
175
|
74
|
|
|
|
|
79
|
$max++; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
124
|
|
|
|
|
211
|
return @{$self}[$min..$max]; |
|
|
124
|
|
|
|
|
552
|
|
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub nhood_x { |
|
181
|
126
|
|
|
126
|
1
|
216
|
my($self, $x, $n) = @_; |
|
182
|
126
|
|
|
|
|
418
|
return $self->_nhood("x", $x, $n); |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub nhood_y { |
|
186
|
10
|
|
|
10
|
1
|
16
|
my($self, $y, $n) = @_; |
|
187
|
10
|
|
|
|
|
20
|
return $self->_nhood("y", $y, $n); |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=pod |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
The following two methods are not implemented in this class, but are |
|
193
|
|
|
|
|
|
|
the standard interpolation interface to be implemented by subclasses. |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=over |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=item $ipl->y(X) |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Interpolates a y value for the given x coordinate, and returns it. |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=item $ipl->x(Y) |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Interpolates an x value for the given y coordinate, and returns it. This |
|
204
|
|
|
|
|
|
|
is only possible if the y coordinates are monotonically non-decreasing |
|
205
|
|
|
|
|
|
|
for increasing x. |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=back |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
L, |
|
212
|
|
|
|
|
|
|
L, |
|
213
|
|
|
|
|
|
|
L, |
|
214
|
|
|
|
|
|
|
L |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head1 AUTHOR |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Andrew Main (Zefram) |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Copyright (C) 2006, 2007, 2009, 2010, 2012 |
|
223
|
|
|
|
|
|
|
Andrew Main (Zefram) |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=head1 LICENSE |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it |
|
228
|
|
|
|
|
|
|
under the same terms as Perl itself. |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=cut |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
1; |