Math-InterpolationCompiler

 view release on metacpan or  search on metacpan

lib/Math/InterpolationCompiler.pm  view on Meta::CPAN

package Math::InterpolationCompiler;
use 5.006001;
use Moo 2;
use Types::Standard 1;
use Carp;
use Exporter 'import';

our @EXPORT_OK= qw( linear_clamp_fn linear_extrapolate_fn );

our $VERSION= '0.002000';

# ABSTRACT: Compile interpolations into perl coderefs


has domain        => ( is => 'ro', isa => Types::Standard::ArrayRef, required => 1 );
has range         => ( is => 'ro', isa => Types::Standard::ArrayRef, required => 1 );
has algorithm     => ( is => 'ro', default => sub { 'linear' } );
has beyond_domain => ( is => 'ro', default => sub { 'clamp' } );
has perl_code     => ( is => 'lazy' );
has fn            => ( is => 'lazy' );
has sanitize      => ( is => 'ro', default => sub { 1 } );

sub BUILDARGS {
	my $self= shift;
	my $args= $self->next::method(@_);
	if ($args->{points} && !$args->{domain} && !$args->{range}) {
		my (@domain, @range);
		ref $args->{points} eq 'ARRAY'
			or croak "points must be an arrayref";
		# If points is an arrayref of arrayrefs, assume each point is a 2-element arrayref
		if (ref $args->{points}[0]) {
			for (@{ delete $args->{points} }) {
				push @domain, $_->[0];
				push @range,  $_->[1];
			}
		}
		# else assume points is an arrayref with the x/y in odd/even slots
		else {
			my $flip= 0;
			for (@{ delete $args->{points} }) {
				$flip++ & 1? (push @range,  $_)
					: (push @domain, $_);
			}
			!($flip & 1)
				or croak "odd number of elements in points";
		}
		$args->{domain}= \@domain;
		$args->{range}=  \@range;
	}
	return $args;
}

sub _sanitize_number_array {
	return [
		map {
			defined $_ or croak "<undef> is not a number";
			my $n= "$_";
			$n =~ /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/ or croak "$n is not a number";
			$n
		} @{ $_[0] }
	];
}

sub BUILD {
	my $self= shift;
	@{ $self->domain } == @{ $self->range }
		or croak "Domain and range differ in length (".@{ $self->domain }." != ".@{ $self->range }.")";
	@{ $self->domain } > 1
		or croak "Domain does not contain any intervals";
	my $prev;
	if ($self->sanitize) {
		$self->{domain}= _sanitize_number_array($self->domain);
		$self->{range}=  _sanitize_number_array($self->range);
	}
	for (@{ $self->domain }) {
		croak "Domain is not sorted in non-decreasing order"



( run in 0.687 second using v1.01-cache-2.11-cpan-39bf76dae61 )