Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ Revision history for Math-Function-Interpolator
0.03 12/06/2014
Big fix, unwanted typo

0.04 14/06/2014
CPAN fail test improved

0.05 15/06/2014
method closest_three_points exported, could be usefull for the Mathmatician

32 changes: 30 additions & 2 deletions lib/Math/Function/Interpolator.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ with qw(MooX::Traits);

use Carp qw(confess);
use Scalar::Util qw(looks_like_number);

use Number::Closest::XS qw(find_closest_numbers_around);
use List::MoreUtils qw(pairwise indexes);
use List::Util qw(min max);

use Module::Runtime;
use Module::Pluggable
sub_name => 'interpolate_methods',
Expand All @@ -21,7 +26,7 @@ Math::Function::Interpolator - Interpolation made easy

=head1 VERSION

Version 0.03
Version 0.05

=head1 SYNOPSIS

Expand Down Expand Up @@ -49,7 +54,7 @@ HashRef of points for interpolations

=cut

our $VERSION = '0.03';
our $VERSION = '0.05';

# Automatically load all interpolate methods
has 'interpolate_classes' => (
Expand Down Expand Up @@ -141,6 +146,29 @@ sub cubic {
->do_calculation($x);
}

=head2 closest_three_points

Returns the the closest three points to the sought point.
The third point is chosen based on the point which is closer to mid point

=cut

sub closest_three_points {
my ( $self, $sought, $all_points ) = @_;

my @ap = sort { $a <=> $b } @{$all_points};
my $length = scalar @ap;

my ( $first, $second ) =
@{ find_closest_numbers_around( $sought, $all_points, 2 ) };
my @indexes = indexes { $first == $_ or $second == $_ } @ap;
my $third_index =
( max(@indexes) < $length - 2 ) ? max(@indexes) + 1 : min(@indexes) - 1;
my @sorted = sort { $a <=> $b } ( $first, $second, $ap[$third_index] );

return @sorted;
}

=head1 AUTHOR

Binary.com, C<< <perl at binary.com> >>
Expand Down
8 changes: 7 additions & 1 deletion lib/Math/Function/Interpolator/Cubic.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use 5.006;
use strict;
use warnings FATAL => 'all';

our $VERSION = '0.01';
our $VERSION = '0.02';

use Moo::Role;

Expand Down Expand Up @@ -32,6 +32,12 @@ Math::Function::Interpolator::Cubic
Math::Function::Interpolator::Cubic helps you to do the interpolation calculation with cubic method.
It solves the interpolated_y given point_x and a minimum of 5 data points.

=head1 FIELDS

=head2 interpolate (REQUIRED)

Interpolations class object

=cut

has 'interpolate' => (
Expand Down
8 changes: 7 additions & 1 deletion lib/Math/Function/Interpolator/Linear.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use 5.006;
use strict;
use warnings FATAL => 'all';

our $VERSION = '0.01';
our $VERSION = '0.02';

use Moo::Role;
use Carp qw(confess);
Expand All @@ -30,6 +30,12 @@ Math::Function::Interpolator::Linear - Interpolation made easy
Math::Function::Interpolator::Linear helps you to do the interpolation calculation with linear method.
It solves for point_y linearly given point_x and an array of points.

=head1 FIELDS

=head2 interpolate (REQUIRED)

Interpolations class object

=cut

has 'interpolate' => (
Expand Down
56 changes: 20 additions & 36 deletions lib/Math/Function/Interpolator/Quadratic.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,15 @@ use 5.006;
use strict;
use warnings FATAL => 'all';

our $VERSION = '0.01';
our $VERSION = '0.03';

use Moo::Role;

use Carp qw(confess);
use List::MoreUtils qw(pairwise indexes);
use List::Util qw(min max);
use Math::Cephes::Matrix qw(mat);
use Number::Closest::XS qw(find_closest_numbers_around);
use POSIX;
use Scalar::Util qw(looks_like_number);
use Try::Tiny;

has 'interpolate' => (
is => 'ro',
isa => sub {
die "Must be Interpolate class"
unless ref $_[0] eq 'Math::Function::Interpolator';
},
required => 1
);

=head1 NAME

Math::Function::Interpolator::Quadratic
Expand All @@ -45,6 +32,24 @@ Math::Function::Interpolator::Quadratic
Math::Function::Interpolator::Quadratic helps you to do the interpolation calculation with quadratic method.
It solves the interpolated_y given point_x and a minimum of 5 data points.

=head1 FIELDS

=head2 interpolate (REQUIRED)

Interpolations class object

=cut

has 'interpolate' => (
is => 'ro',
isa => sub {
die "Must be Interpolate class"
unless ref $_[0] eq 'Math::Function::Interpolator';
},
required => 1
);


=head1 METHODS

=head2 do_calculation
Expand All @@ -65,7 +70,7 @@ sub do_calculation {
confess "cannot interpolate with fewer than 3 data points"
if scalar @Xs < 3;

my @points = $self->_get_closest_three_points( $x, \@Xs );
my @points = $self->interpolate->closest_three_points( $x, \@Xs );

# Three cofficient
my $abc = mat( [ map { [ $_**2, $_, 1 ] } @points ] );
Expand All @@ -80,27 +85,6 @@ sub do_calculation {
return ( $a * ( $x**2 ) + $b * $x + $c );
}


# Returns the the closest three points to the sought point.
# The third point is chosen based on the point which is closer to mid point
# $interpolator->_get_closest_three_points(2.4,[1,2,3,4,9]) #returns (2,3,4)

sub _get_closest_three_points {
my ( $self, $sought, $all_points ) = @_;

my @ap = sort { $a <=> $b } @{$all_points};
my $length = scalar @ap;

my ( $first, $second ) =
@{ find_closest_numbers_around( $sought, $all_points, 2 ) };
my @indexes = indexes { $first == $_ or $second == $_ } @ap;
my $third_index =
( max(@indexes) < $length - 2 ) ? max(@indexes) + 1 : min(@indexes) - 1;
my @sorted = sort { $a <=> $b } ( $first, $second, $ap[$third_index] );

return @sorted;
}

=head1 AUTHOR

Binary.com, C<< <perl at binary.com> >>
Expand Down