line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Math::Function::Interpolator::Cubic; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
37
|
use 5.006; |
|
2
|
|
|
|
|
7
|
|
4
|
2
|
|
|
2
|
|
11
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
62
|
|
5
|
2
|
|
|
2
|
|
11
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
105
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '1.02'; ## VERSION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our @ISA = qw(Math::Function::Interpolator); |
10
|
|
|
|
|
|
|
|
11
|
2
|
|
|
2
|
|
12
|
use Carp qw(confess); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
99
|
|
12
|
2
|
|
|
2
|
|
14
|
use List::MoreUtils qw(pairwise indexes); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
25
|
|
13
|
2
|
|
|
2
|
|
1474
|
use Number::Closest::XS qw(find_closest_numbers_around); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
93
|
|
14
|
2
|
|
|
2
|
|
12
|
use Scalar::Util qw(looks_like_number); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1738
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 NAME |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Math::Function::Interpolator::Cubic |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
use Math::Function::Interpolator::Cubic; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
my $interpolator = Math::Function::Interpolator::Cubic->new( |
25
|
|
|
|
|
|
|
points => {1=>2,2=>3,3=>4,4=>5,5=>6,6=>7} |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
$interpolator->cubic(2.5); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 DESCRIPTION |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
Math::Function::Interpolator::Cubic helps you to do the interpolation calculation with cubic method. |
33
|
|
|
|
|
|
|
It solves the interpolated_y given point_x and a minimum of 5 data points. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 FIELDS |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=head2 points (REQUIRED) |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
HashRef of points for interpolations |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=cut |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub _sorted_Xs { |
44
|
23
|
|
|
23
|
|
48
|
my ($self) = @_; |
45
|
23
|
100
|
|
|
|
57
|
return $self->{'_sorted_Xs'} if $self->{'_sorted_Xs'}; |
46
|
5
|
|
|
|
|
10
|
$self->{'_sorted_Xs'} = [sort { $a <=> $b } keys %{$self->points}]; |
|
32
|
|
|
|
|
68
|
|
|
5
|
|
|
|
|
12
|
|
47
|
5
|
|
|
|
|
14
|
return $self->{'_sorted_Xs'}; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub _spline_points { |
51
|
18
|
|
|
18
|
|
33
|
my ($self) = @_; |
52
|
|
|
|
|
|
|
|
53
|
18
|
100
|
|
|
|
46
|
return $self->{'_spline_points'} if $self->{'_spline_points'}; |
54
|
|
|
|
|
|
|
|
55
|
4
|
|
|
|
|
12
|
my $points_ref = $self->points; |
56
|
4
|
|
|
|
|
9
|
my $Xs = $self->_sorted_Xs; |
57
|
4
|
|
|
|
|
9
|
my @Ys = map { $points_ref->{$_} } @$Xs; |
|
20
|
|
|
|
|
37
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# First element is 0 |
60
|
|
|
|
|
|
|
# Second derivative of the Ys |
61
|
4
|
|
|
|
|
10
|
my @y_2derivative = (0); |
62
|
4
|
|
|
|
|
8
|
my @u = (0); |
63
|
4
|
|
|
|
|
8
|
my $counter = @$Xs - 2; |
64
|
|
|
|
|
|
|
|
65
|
4
|
|
|
|
|
14
|
for my $i (1 .. $counter) { |
66
|
12
|
|
|
|
|
35
|
my $sig = ($Xs->[$i] - $Xs->[$i - 1]) / ($Xs->[$i + 1] - $Xs->[$i - 1]); |
67
|
12
|
|
|
|
|
28
|
my $p = $sig * $y_2derivative[$i - 1] + 2; |
68
|
12
|
|
|
|
|
23
|
$y_2derivative[$i] = ($sig - 1) / $p; |
69
|
12
|
|
|
|
|
39
|
$u[$i] = ($Ys[$i + 1] - $Ys[$i]) / ($Xs->[$i + 1] - $Xs->[$i]) - ($Ys[$i] - $Ys[$i - 1]) / ($Xs->[$i] - $Xs->[$i - 1]); |
70
|
12
|
|
|
|
|
35
|
$u[$i] = (($u[$i] * 6) / ($Xs->[$i + 1] - $Xs->[$i - 1]) - $sig * $u[$i - 1]) / $p; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Last element is 0 |
74
|
4
|
|
|
|
|
11
|
push @y_2derivative, 0; |
75
|
|
|
|
|
|
|
|
76
|
4
|
|
|
|
|
13
|
for (my $i = $counter; $i > 0; $i--) { |
77
|
12
|
|
|
|
|
34
|
$y_2derivative[$i] = $y_2derivative[$i] * $y_2derivative[$i + 1] + $u[$i]; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
4
|
|
|
20
|
|
53
|
my %y_2derivative_combined = pairwise { $a => $b } @$Xs, @y_2derivative; |
|
20
|
|
|
|
|
62
|
|
81
|
|
|
|
|
|
|
|
82
|
4
|
|
|
|
|
21
|
$self->{'_spline_points'} = \%y_2derivative_combined; |
83
|
|
|
|
|
|
|
|
84
|
4
|
|
|
|
|
14
|
return $self->{'_spline_points'}; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub _extrapolate_spline { |
88
|
8
|
|
|
8
|
|
17
|
my ($self, $args) = @_; |
89
|
8
|
|
|
|
|
12
|
my $x = $args->{x}; |
90
|
8
|
|
|
|
|
15
|
my $first = $args->{first}; |
91
|
8
|
|
|
|
|
13
|
my $second = $args->{second}; |
92
|
8
|
|
|
|
|
13
|
my $derivative2 = $args->{derivative2}; |
93
|
|
|
|
|
|
|
|
94
|
8
|
|
|
|
|
24
|
my $derivative1 = (($second->{y} - $first->{y}) / ($second->{x} - $first->{x})) - (($second->{x} - $first->{x}) * $derivative2) / 6; |
95
|
|
|
|
|
|
|
|
96
|
8
|
|
|
|
|
22
|
return $first->{y} - ($first->{x} - $x) * $derivative1; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 METHODS |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head2 cubic |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
cubic |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=cut |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# Returns the interpolated_y given point_x and a minimum of 5 data points |
108
|
|
|
|
|
|
|
sub cubic { |
109
|
20
|
|
|
20
|
1
|
6404
|
my ($self, $x) = @_; |
110
|
|
|
|
|
|
|
|
111
|
20
|
100
|
|
|
|
84
|
confess "sought_point[$x] must be a numeric" if !looks_like_number($x); |
112
|
19
|
|
|
|
|
54
|
my $ap = $self->points; |
113
|
19
|
50
|
|
|
|
82
|
return $ap->{$x} if defined $ap->{$x}; # No interpolation needed. |
114
|
|
|
|
|
|
|
|
115
|
19
|
|
|
|
|
49
|
my $Xs = $self->_sorted_Xs; |
116
|
19
|
100
|
|
|
|
57
|
confess "cannot interpolate with fewer than 5 data points" |
117
|
|
|
|
|
|
|
if scalar @$Xs < 5; |
118
|
|
|
|
|
|
|
|
119
|
18
|
|
|
|
|
38
|
my $splines = $self->_spline_points; |
120
|
|
|
|
|
|
|
|
121
|
18
|
|
|
|
|
30
|
my $y; |
122
|
18
|
100
|
100
|
|
|
76
|
if ($x < $Xs->[0] or $x > $Xs->[-1]) { |
123
|
8
|
100
|
|
|
|
24
|
my ($spline_key, $first, $second) = |
124
|
|
|
|
|
|
|
$x < $Xs->[0] |
125
|
|
|
|
|
|
|
? ($Xs->[1], $Xs->[0], $Xs->[1]) |
126
|
|
|
|
|
|
|
: ($Xs->[-2], $Xs->[-2], $Xs->[-1]); |
127
|
|
|
|
|
|
|
$y = $self->_extrapolate_spline({ |
128
|
|
|
|
|
|
|
x => $x, |
129
|
|
|
|
|
|
|
derivative2 => $splines->{$spline_key}, |
130
|
|
|
|
|
|
|
first => { |
131
|
|
|
|
|
|
|
x => $first, |
132
|
|
|
|
|
|
|
y => $ap->{$first}, |
133
|
|
|
|
|
|
|
}, |
134
|
|
|
|
|
|
|
second => { |
135
|
|
|
|
|
|
|
x => $second, |
136
|
8
|
|
|
|
|
54
|
y => $ap->{$second}, |
137
|
|
|
|
|
|
|
}, |
138
|
|
|
|
|
|
|
}, |
139
|
|
|
|
|
|
|
); |
140
|
|
|
|
|
|
|
} else { |
141
|
10
|
|
|
|
|
16
|
my ($first, $second) = @{find_closest_numbers_around($x, $Xs, 2)}; |
|
10
|
|
|
|
|
61
|
|
142
|
|
|
|
|
|
|
|
143
|
10
|
|
|
|
|
26
|
my $range = $second - $first; |
144
|
|
|
|
|
|
|
|
145
|
10
|
|
|
|
|
24
|
my $A = ($second - $x) / $range; |
146
|
10
|
|
|
|
|
19
|
my $B = 1 - $A; |
147
|
10
|
|
|
|
|
44
|
my $C = ($A**3 - $A) * ($range**2) / 6; |
148
|
10
|
|
|
|
|
27
|
my $D = ($B**3 - $B) * ($range**2) / 6; |
149
|
|
|
|
|
|
|
|
150
|
10
|
|
|
|
|
33
|
$y = $A * $ap->{$first} + $B * $ap->{$second} + $C * $splines->{$first} + $D * $splines->{$second}; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
18
|
|
|
|
|
91
|
return $y; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 AUTHOR |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Binary.com, C<< >> |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 BUGS |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
163
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
164
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head1 SUPPORT |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
perldoc Math::Function::Interpolator |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
You can also look for information at: |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=over 4 |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
L |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
L |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=item * CPAN Ratings |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
L |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=item * Search CPAN |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
L |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=back |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=cut |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
1; # End of Math::Function::Interpolator::Cubic |