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
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ Revision history for Math-Function-Interpolator

0.07 19/06/2014
Makefile improved, added required modules

0.08 23/06/2014
Removed Moose, Moo uses and made pure old style object oriented
12 changes: 9 additions & 3 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ WriteMakefile(
'Test::More' => 0,
'Test::FailWarnings' => 0,
'Test::Exception' => 0,
'Moo' => 0,
'Moo::Role' => 0,
'MooX::Traits' => 0,
'Module::Runtime' => 0,
'Module::Pluggable' => 0,
'Carp' => 0,
Expand All @@ -32,6 +29,15 @@ WriteMakefile(
'Number::Closest::XS' => 0,
'Scalar::Util' => 0,
},
(! eval { ExtUtils::MakeMaker->VERSION(6.46) } ? () :
(META_ADD => {
resources => {
homepage => 'https://github.com/binary-com/perl-Math-Function-Interpolator',
repository => 'git@github.com:binary-com/perl-Math-Function-Interpolator.git',
bugtracker => 'http://rt.cpan.org/NoAuth/Bugs.html?Dist=Math-Function-Interpolator',
},
})
),
PREREQ_PM => {
},
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
Expand Down
118 changes: 62 additions & 56 deletions lib/Math/Function/Interpolator.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,20 @@ use 5.006;
use strict;
use warnings FATAL => 'all';

use Moo;
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',
search_path => ['Math::Function::Interpolator'],
;

=head1 NAME

Math::Function::Interpolator - Interpolation made easy

=head1 VERSION

Version 0.07
Version 0.08

=head1 SYNOPSIS

Expand Down Expand Up @@ -54,51 +45,72 @@ HashRef of points for interpolations

=cut

our $VERSION = '0.07';

# Automatically load all interpolate methods
has 'interpolate_classes' => (
is => 'ro',
lazy => 1,
default => sub {
my ($self) = @_;
my @modules = $self->interpolate_methods();
foreach my $module (@modules) {
Module::Runtime::require_module($module);
}
return 1;
}
);

has points => (
is => 'ro',
isa => sub {
die "Points $_[0] shold be hash" unless ref $_[0] eq 'HASH';
},
required => 1,
);
our $VERSION = '0.08';

=head1 METHODS

=head2 BUILDARGS
=head2 new

BUILDARGS
New instance method

=cut

sub BUILDARGS { ## no critic (Subroutines::RequireArgUnpacking)
my $self = shift;
my %args = ref( $_[0] ) ? %{ $_[0] } : @_;
sub new {
my $class = shift;
my %params_ref = ref( $_[0] ) ? %{ $_[0] } : @_;

confess "points are required to do interpolation"
unless $params_ref{'points'};

# We can't interpolate properly on undef values so make sure we know
# they are missing by removing them entirely.
my $points = $args{points};
$args{points} = {
my $points = $params_ref{points};
$params_ref{points} = {
map { $_ => $points->{$_} }
grep { defined $points->{$_} } keys %$points
};

my $self = {
_points => $params_ref{'points'},
_classes_loaded => 0
};
my $obj = bless $self, $class;

if ( $class =~/Interpolator$/i ){
# Load all interpolator classes when only made object from main
# Interpolator classes
$obj->_load_interpolator_classes();
}

return $obj;
}

sub _load_interpolator_classes {
my ( $self ) = @_;

use Module::Runtime;
use Module::Pluggable
sub_name => 'interpolate_methods',
search_path => ['Math::Function::Interpolator'],
;

my @modules = $self->interpolate_methods();
foreach my $module (@modules) {
Module::Runtime::require_module($module);
}
$self->{'_classes_loaded'} = 1;
return 1;
}

=head2 points

points

=cut

return \%args;
sub points {
my ( $self ) = @_;
return $self->{'_points'};
}

=head2 linear
Expand All @@ -109,11 +121,9 @@ This method do the linear interpolation. It solves for point_y linearly given po

sub linear {
my ( $self, $x ) = @_;
confess "point_x must be numeric" if !looks_like_number($x);
$self->interpolate_classes();
return Math::Function::Interpolator->with_traits(
'Math::Function::Interpolator::Linear')->new( interpolate => $self )
->do_calculation($x);
return Math::Function::Interpolator::Linear->new(
points => $self->points
)->linear( $x );
}

=head2 quadratic
Expand All @@ -124,11 +134,9 @@ This method do the quadratic interpolation. It solves the interpolated_y value g

sub quadratic {
my ( $self, $x ) = @_;
confess "point_x must be numeric" if !looks_like_number($x);
$self->interpolate_classes();
return Math::Function::Interpolator->with_traits(
'Math::Function::Interpolator::Quadratic')->new( interpolate => $self )
->do_calculation($x);
return Math::Function::Interpolator::Quadratic->new(
points => $self->points
)->quadratic( $x );
}

=head2 cubic
Expand All @@ -139,11 +147,9 @@ This method do the cubic interpolation. It solves the interpolated_y given point

sub cubic {
my ( $self, $x ) = @_;
confess "point_x must be numeric" if !looks_like_number($x);
$self->interpolate_classes();
return Math::Function::Interpolator->with_traits(
'Math::Function::Interpolator::Cubic')->new( interpolate => $self )
->do_calculation($x);
return Math::Function::Interpolator::Cubic->new(
points => $self->points
)->cubic( $x );
}

=head2 closest_three_points
Expand Down
51 changes: 15 additions & 36 deletions lib/Math/Function/Interpolator/Cubic.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use 5.006;
use strict;
use warnings FATAL => 'all';

our $VERSION = '0.02';
our $VERSION = '0.03';

use Moo::Role;
use parent 'Math::Function::Interpolator';

use Carp qw(confess);
use List::MoreUtils qw(pairwise indexes);
Expand All @@ -19,9 +19,9 @@ Math::Function::Interpolator::Cubic

=head1 SYNOPSIS

use Math::Function::Interpolator;
use Math::Function::Interpolator::Cubic;

my $interpolator = Math::Function::Interpolator->new(
my $interpolator = Math::Function::Interpolator::Cubic->new(
points => {1=>2,2=>3,3=>4}
);

Expand All @@ -34,42 +34,21 @@ It solves the interpolated_y given point_x and a minimum of 5 data points.

=head1 FIELDS

=head2 interpolate (REQUIRED)
=head2 points (REQUIRED)

Interpolations class object
HashRef of points for interpolations

=cut

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

has _sorted_Xs => (
is => 'ro',
lazy => 1,
builder => '_build__sorted_Xs',
);

sub _build__sorted_Xs {
sub _sorted_Xs {
my ($self) = @_;
return [ sort { $a <=> $b } keys %{ $self->interpolate->points } ];
return [ sort { $a <=> $b } keys %{ $self->points } ];
}

has _spline_points => (
is => 'ro',
lazy => 1,
builder => '_build__spline_points',
);

sub _build__spline_points {
sub _spline_points {
my ($self) = @_;

my $points_ref = $self->interpolate->points;
my $points_ref = $self->points;
my $Xs = $self->_sorted_Xs;
my @Ys = map { $points_ref->{$_} } @$Xs;

Expand Down Expand Up @@ -121,18 +100,18 @@ sub _extrapolate_spline {

=head1 METHODS

=head2 do_calculation
=head2 cubic

do_calculation
cubic

=cut

# Returns the interpolated_y given point_x and a minimum of 5 data points
sub do_calculation {
sub cubic {
my ( $self, $x ) = @_;

confess "sought[$x] must be numeric" if !looks_like_number($x);
my $ap = $self->interpolate->points;
confess "sought_point[$x] must be a numeric" if !looks_like_number($x);
my $ap = $self->points;
return $ap->{$x} if defined $ap->{$x}; # No interpolation needed.

my $Xs = $self->_sorted_Xs;
Expand Down
30 changes: 11 additions & 19 deletions lib/Math/Function/Interpolator/Linear.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use 5.006;
use strict;
use warnings FATAL => 'all';

our $VERSION = '0.02';
use parent 'Math::Function::Interpolator';

our $VERSION = '0.03';

use Moo::Role;
use Carp qw(confess);
use Number::Closest::XS qw(find_closest_numbers_around);
use Scalar::Util qw(looks_like_number);
Expand All @@ -17,9 +18,9 @@ Math::Function::Interpolator::Linear - Interpolation made easy

=head1 SYNOPSIS

use Math::Function::Interpolator;
use Math::Function::Interpolator::Linear;

my $interpolator = Math::Function::Interpolator->new(
my $interpolator = Math::Function::Interpolator::Linear->new(
points => {1=>2,2=>3,3=>4}
);

Expand All @@ -32,35 +33,26 @@ It solves for point_y linearly given point_x and an array of points.

=head1 FIELDS

=head2 interpolate (REQUIRED)
=head2 points (REQUIRED)

Interpolations class object
HashRef of points for interpolations

=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
=head2 linear

do_calculation
linear

=cut

# Solves for point_y linearly given point_x and an array of points.
sub do_calculation {
sub linear {
my ( $self, $x ) = @_;

confess "sought_point[$x] must be a number" unless looks_like_number($x);
my $ap = $self->interpolate->points;
my $ap = $self->points;
return $ap->{$x} if defined $ap->{$x}; # no need to interpolate

my @Xs = keys %$ap;
Expand Down
Loading