Algorithm-CurveFit-Simple

 view release on metacpan or  search on metacpan

lib/Algorithm/CurveFit/Simple.pm  view on Meta::CPAN

    print "$src\n";

    sub converto {
        my($x) = @_;
        my $y = -5340.93059104837 + 249.23009968947 * $x + -3.87745746448 * $x**2 + 0.02114780993 * $x**3;
        return $y;
    }

=item C<fit(bounds_check =E<gt> 1)>

When set, the implementation will include logic for checking whether the input is out-of-bounds, per the highest and lowest x points in the data used to fit the formula.  For implementation languages which support exceptions, an exception will be thr...

For instance, if the highest x in C<$xydata> is 83.0 and the lowest x is 60.0:

    my($max_dev, $avg_dev, $src) = fit(xydata => \@xy, bounds_check => 1);

    print "$src\n";

    sub x2y {
        my($x) = @_;
        die "x out of bounds (high)" if ($x > 83.80000000000);

lib/Algorithm/CurveFit/Simple.pm  view on Meta::CPAN

=item C<fit_calib_parar>: Arrayref of formula parameters as returned by L<Algorithm::CurveFit> after a short fitting attempt used for timing calibration.

=item C<fit_calib_time>: The number of seconds L<Algorithm::CurveFit> spent in the calibration run.

=item C<fit_iter>: The iterations parameter passed to L<Algorithm::CurveFit>.

=item C<fit_parar>: Arrayref of formula parameters as returned by L<Algorithm::CurveFit>.

=item C<fit_time>: The number of seconds L<Algorithm::CurveFit> actually spent fitting the formula.

=item C<impl_exception>: The exception thrown when the implementation was used to calculate the deviations, or the empty string if none.

=item C<impl_formula>: The formula part of the implementation.

=item C<impl_source>: The implementation source string.

=item C<iter_mode>: One of C<"time"> or C<"iter">, indicating whether a time limit was used or an iteration count.

=item C<xdata>: Arrayref of x data points as passed to L<Algorithm::CurveFit>.

=item C<ydata>: Arrayref of y data points as passed to L<Algorithm::CurveFit>.

t/00-fit.t  view on Meta::CPAN


# Pass an argument for profiling purposes, will also dump source code string and statistics
my $N_TERMS = int($ARGV[0] // 0) || '3';
my $LANG    = $ARGV[1] // 'perl';

my $tm0 = Time::HiRes::time();
my ($max_dev, $avg_dev, $src) = eval { fit(terms => $N_TERMS, xydata => [[1, 3], [2, 7], [3, 11], [4, 19], [5, 35], [6, 54], [7, 69], [8, 81], [9, 90], [10, 96]], impl_lang => $LANG); };
print "# exception: $@\n" if ($@);
my $tm_elapsed = Time::HiRes::time() - $tm0;

ok !$@, "no thrown exceptions";
ok $tm_elapsed // 0 <= 4.0, "time elapsed is within expectations";
ok $max_dev    // 0 <= 1.4, "maximum deviation is within expectations";
ok $avg_dev    // 0 <= 1.1, "average deviation is within expectations";

if ($ARGV[0]) {
    print "$src\n";
    print JSON::PP::encode_json([$max_dev, $avg_dev, \%STATS_H])."\n";
}

done_testing();

t/01-init-formula.t  view on Meta::CPAN

use warnings;
use Test::Most;
use JSON::PP;

use lib "./lib";
use Algorithm::CurveFit::Simple qw(%STATS_H);

my $f = eval { Algorithm::CurveFit::Simple::_init_formula(); };
print "# exception: $@\n" if ($@);

ok !$@, "default - no thrown exceptions";
ok defined($f), "default - returned a defined value";
$f //= '';
is ref($f), '', "default - returned string";
ok $f =~ /^k (\+ \w\s?\*\s?x\^?\d*\s*)+$/, "default - formula is well-formed" if($f);

my $formula;
for (my $i = 1; $i < 10; $i++) {
    $f = eval { Algorithm::CurveFit::Simple::_init_formula(terms => $i); };
    $formula = $f if ($i == 3);
    ok !$@, "with $i terms - no thrown exceptions";
    ok defined($f), "with $i terms - returned a defined value";
    $f //= '';
    is ref($f), '', "with $i terms - returned string";
    ok $f =~ /^k (\+ \w\s?\*\s?x\^?\d*\s*){$i}$/, "with $i terms - formula is well-formed" if($f);
}

if ($ARGV[0]) {
    print "formula=$formula\n";
    print JSON::PP::encode_json(\%STATS_H)."\n";
}

t/02-init-data.t  view on Meta::CPAN

#!/bin/env perl
use strict;
use warnings;
use Test::Most;
use JSON::PP;

use lib "./lib";
use Algorithm::CurveFit::Simple;

my ($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(); };
is $@, "must provide at least xydata or both xdata and ydata\n", "exception thrown for no parameters";

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xdata => [1, 2, 3]); };
is $@, "must provide at least xydata or both xdata and ydata\n", "exception thrown for lacking ydata";

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(ydata => [1, 2, 3]); };
is $@, "must provide at least xydata or both xdata and ydata\n", "exception thrown for lacking xdata";

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xdata => [1], ydata => [1]); };
is $@, "must have more than one data-point\n", "exception thrown for insufficient data";

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xdata => [1, 2], ydata => [1]); };
is $@, "xdata and ydata must have the same number of elements\n", "exception thrown for extraneous xdata";

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xdata => [1], ydata => [1, 2]); };
is $@, "xdata and ydata must have the same number of elements\n", "exception thrown for extraneous ydata";

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xdata => [1, 2], ydata => [3, 4]); };
ok !$@, "no exceptions when passed xdata, ydata";
is JSON::PP::encode_json($x), '[1,2]', 'xdata returned as xdata';
is JSON::PP::encode_json($y), '[3,4]', 'ydata returned as ydata';

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xdata => [1, 2], ydata => [3, 4], inv => 1); };
ok !$@, 'no exceptions when passed xdata, ydata with inverted mode';
is JSON::PP::encode_json($y), '[1,2]', 'xdata returned as ydata with inverted mode';
is JSON::PP::encode_json($x), '[3,4]', 'ydata returned as xdata with inverted mode';

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xydata => [[1], [3]]); };
is $@, "pairwise xydata must have two data points per element\n", 'exception thrown for short xydata';

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xydata => [[1, 2], [3, 4], [5, 6]]); };
ok !$@, 'no exceptions when passed well-formed xydata';
# print "$@\n";
# print JSON::PP::encode_json(\%Algorithm::CurveFit::Simple::STATS_H)."\n";
is JSON::PP::encode_json($x), '[1,3,5]', 'xdata returned as xdata from xydata';
is JSON::PP::encode_json($y), '[2,4,6]', 'ydata returned as ydata from xydata';

($x, $y) = eval { Algorithm::CurveFit::Simple::_init_data(xydata => [[1, 2, 3, 4], [3, 4, 5, 6]]); };
ok !$@, 'no exceptions when passed xdata, ydata';

t/04-implement-formula.t  view on Meta::CPAN

use Test::Most;
use JSON::PP;

use lib "./lib";
use Algorithm::CurveFit::Simple;

my $parar = [["k", 10, 1], ["a", 2, 1], ["b", 3, 1], ["c", 4, 1]];
my $xdata = [8, 3, 5, 11, 9, 7, 4];

my $s = eval { Algorithm::CurveFit::Simple::_implement_formula($parar, "", "x2y", $xdata, {}); };
ok defined($s), "implementation default throws no exceptions";
ok $s =~ /^sub x2y /, "implementation default is perl";

$s = eval { Algorithm::CurveFit::Simple::_implement_formula($parar, "coderef", "x2y", $xdata, {}); };
ok defined($s), "implementation coderef throws no exceptions";
is ref($s), "CODE", "implementation coderef is coderef";

# perl implementation:

$s = eval { Algorithm::CurveFit::Simple::_implement_formula($parar, "perl", "x2y", $xdata, {}); };
ok defined($s), "implementation perl throws no exceptions";
ok $s =~ /^sub x2y /, "implementation perl is perl";
ok $s !~ /x out of bounds/, "implementation perl without bounds check is permissive";
ok $s !~ /y = int/, "implementation perl without rounding check returns precision result";

$s = eval { Algorithm::CurveFit::Simple::_implement_formula($parar, "perl", "x2y", $xdata, {bounds_check => 1}); };
ok $s =~ /x out of bounds/, "implementation perl with bounds check is limited";
ok $s !~ /y = int/, "implementation perl with bounds check without round result returns precision result";

$s = eval { Algorithm::CurveFit::Simple::_implement_formula($parar, "perl", "x2y", $xdata, {round_result => 1}); };
ok $s !~ /x out of bounds/, "implementation perl without bounds check with round result is permissive";
ok $s =~ /y = int/, "implementation perl without bounds check with round result returns rounded result";

# C implementation:

$s = eval { Algorithm::CurveFit::Simple::_implement_formula($parar, "c", "x2y", $xdata, {}); };
ok defined($s), "implementation C throws no exceptions";
ok $s =~ /double x2y\(double x\) \{/, "implementation C is C";
ok $s !~ /return -1.0/, "implementation C without bounds check is permissive";
ok $s !~ /y = round/, "implementation C without rounding check returns precision result";
print $Algorithm::CurveFit::Simple::STATS_H{impl_source} . "\n" if ($ARGV[0]);

$s = eval { Algorithm::CurveFit::Simple::_implement_formula($parar, "c", "x2y", $xdata, {bounds_check => 1}); };
ok $s =~ /return -1.0/, "implementation C with bounds check is limited";
ok $s !~ /y = round/, "implementation C with bounds check without round result returns precision result";
print $Algorithm::CurveFit::Simple::STATS_H{impl_source} . "\n" if ($ARGV[0]);



( run in 0.268 second using v1.01-cache-2.11-cpan-496ff517765 )