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; |