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