AI-FuzzyEngine
view release on metacpan or search on metacpan
t/02-fuzzyEngine-pdl_aware.t view on Meta::CPAN
use Test::Most;
use List::MoreUtils;
use AI::FuzzyEngine::Set;
use AI::FuzzyEngine::Variable;
use AI::FuzzyEngine;
sub class { 'AI::FuzzyEngine' };
sub set_class { 'AI::FuzzyEngine::Set' };
sub var_class { 'AI::FuzzyEngine::Variable' };
my $class = class();
my $set_class = set_class();
my $var_class = var_class();
# Can PDL be loaded? skip_all if not.
my $module = 'PDL';
my $msg = qq{Cannot find $module. }
. qq{$class is not $module aware on your computer};
if (not eval "use $module; 1") { plan skip_all => $msg };
subtest "$class internal functions" => sub {
# _cat_array_of_piddles
my @vals = (0..2);
my $vals = $class->_cat_array_of_piddles(@vals);
is( $vals->ndims, 1, 'ndims of cat topdl with scalars');
ok_all( $vals == pdl( [ 0, 1, 2 ] ),
'cat topdl with scalars',
);
@vals = map {pdl([$_])} (0..2);
$vals = $class->_cat_array_of_piddles(@vals);
is( $vals->ndims, 2, 'ndims of cat topdl with pdl([scalar])' );
ok_all( $vals == pdl( [ [0], [1], [2], ] ),
'cat topdl with scalars',
);
@vals = map {pdl([[$_, 1], [7]])} (0..2);
$vals = $class->_cat_array_of_piddles(@vals);
is( $vals->ndims, 3, 'cat of 2dim' );
@vals =( 6, pdl( [[5, 7], [1, 2]] ) );
$vals = $class->_cat_array_of_piddles(@vals);
ok_all( $vals == pdl( [[6, 6], [6, 6]],
[[5, 7], [1, 2]],
),
'cat topdl scalar, 2dim 4elem pdl',
) or diag $vals;
@vals = ( pdl([[11],[21]]), pdl([[11, 12]]));
$vals = $class->_cat_array_of_piddles(@vals);
ok_all( $vals == pdl( [[11, 11], [21, 21]],
[[11, 12], [11, 12]],
),
'cat topdl two 2dim 4elem pdls',
) or diag $vals;
@vals = ( pdl([1]), pdl([]) );
throws_ok { $class->_cat_array_of_piddles(@vals)
} qr/empty/i,
'_cat_array_of_piddles checks for empty piddles';
};
subtest "$class PDL operations" => sub {
my $fe = $class->new();
# Negation:
my $c = $fe->not( 0.4 );
ok( ref $c eq '', 'not scalar: scalar' );
ok( $c == 0.6, 'not scalar: result' );
$c = $fe->not( pdl( 0.4 ) );
isa_ok( $c, 'PDL', 'not(PDL scalar)' );
ok( $c == 0.6, 'not(PDL scalar): result' );
$c = $fe->not( pdl([0.4, 0.5], [0, 1]) );
isa_ok( $c, 'PDL', 'not(PDL 2elem)' );
ok_all( $c == pdl([0.6, 0.5], [1, 0]), 'not(PDL 2elem): result' );
# And and or use _cat_array_of_piddles
# to bring input to the same dimensions
# And
$c = $fe->and( 0.4, pdl( [0.5] ) );
isa_ok( $c, 'PDL', 'and(scalar, PDL)' );
ok_all( $c == 0.4, 'and(scalar, PDL): result' );
$c = $fe->and( 0.6, pdl( [0.5, 0.7] ) );
isa_ok( $c, 'PDL', 'and(scalar, 2elem PDL)' );
ok_all( $c == pdl([0.5, 0.6]), 'and(scalar, 2elem PDL): result' );
# Or
$c = $fe->or( 0.4, pdl( [0.5] ) );
isa_ok( $c, 'PDL', 'or(scalar, PDL)' );
ok_all( $c == 0.5, 'or(scalar, PDL): result' );
$c = $fe->or( 0.6, pdl( [0.5, 0.7] ) );
isa_ok( $c, 'PDL', 'or(scalar, 2elem PDL)' );
ok_all( $c == pdl([0.6, 0.7]), 'or(scalar, 2elem PDL): result' );
};
my $fe = a_fuzzyEngine();
my %set_pars = ( fuzzyEngine => $fe,
variable => a_variable( $fe ),
name => 'few',
memb_fun => [[7, 8] => [0, 1]],
);
subtest "$set_class PDL degree" => sub {
my $s = $set_class->new(%set_pars);
is( $s->degree, 0, 'Initial (internal) membership degree is 0' );
$s->degree( pdl(0.2) );
is( $s->degree, 0.2, 'degree can be set by assignment of a piddle' );
isa_ok( $s->degree, 'PDL', '$s->degree' );
$s->degree( 0.1 );
is( $s->degree, 0.2, 'Disjunction of last and new degree (1)' );
$s->degree( 0.3 );
is( $s->degree, 0.3, 'Disjunction of last and new degree (2)' );
isa_ok( $s->degree, 'PDL', '$s->degree after recalculation' );
$s->reset();
is( ref $s->degree, '', 'reset makes degree a scalar again' );
$s->degree( 0.3, pdl([0.5, 0.2]) );
ok_all( $s->degree == pdl([0.3, 0.2] ),
'Conjunction of multiple inputs ("and" operation)',
);
local $set_pars{memb_fun} = pdl( [[7, 8] => [0, 1]] );
throws_ok{ $set_class->new(%set_pars)
} qr/array ref/, 'Checks pureness of membership function';
};
subtest "$set_class PDL _interpol & fuzzify" => sub {
local $set_pars{memb_fun} = [ [0.2, 0.3, 0.8, 1.0], # x
[0.1, 0.5, 0.5, 0.0], # y
];
my $s = $set_class->new(%set_pars);
# fuzzify some values
# (no extrapolation in this test case)
my $x = pdl(0.2, 0.25, 0.3, 0.5, 0.8, 0.90, 1);
my $expected = pdl(0.1, 0.30, 0.5, 0.5, 0.5, 0.25, 0 );
my $got = $s->fuzzify( $x );
isa_ok( $got, 'PDL', 'What fuzzify (_interpol) returns' );
ok_all( $got == $expected, 'fuzzify' ) or diag $got;
};
subtest "$var_class fuzzification with piddles" => sub {
my $v = $var_class->new( $fe,
0 => 10,
'low' => [ 3, 1, 6, 0],
'med' => [ 5, 0.5],
'high' => [ -5, 0, 15, 1],
);
my $vals = pdl( [10, 5]);
$v->fuzzify( $vals );
isa_ok( $v->low, 'PDL', 'What $v->low returns' );
ok_all( $v->low == pdl([ 0, 1/3]), '$v->low' ); # :-))
ok_all( $v->med == pdl([0.5, 0.5]), '$v->med' );
ok_all( $v->high == pdl([3/4, 1/2]), '$v->high' );
};
subtest "$var_class defuzzification with piddles" => sub {
my $v = AI::FuzzyEngine::Variable
->new( $fe,
0 => 2,
low => [0 => 1, 1 => 1, 1.00001 => 0, 2 => 0],
high => [0 => 0, 1 => 0, 1.00001 => 1, 2 => 1],
);
$v->low( pdl(1, 0, 1) );
$v->high( 0.5 ); # non pdl
my $val = $v->defuzzify;
isa_ok( $val, 'PDL', 'What $v->defuzzify returns from scalar+pdl' );
my @size = $val->dims;
is_deeply( \@size, [3], 'dimensions' );
$v->reset;
$v->low( pdl(1, 0, 1) );
$v->high( pdl(0, 0.5, 0.5) );
( run in 0.815 second using v1.01-cache-2.11-cpan-39bf76dae61 )