AI-FuzzyEngine
view release on metacpan or search on metacpan
lib/AI/FuzzyEngine/Variable.pm view on Meta::CPAN
return $self;
};
sub is_internal { shift->{is_internal} }
sub from { shift->{from} };
sub to { shift->{to} };
sub sets { shift->{sets} };
sub set_names { @{shift->{set_names}} };
sub set {
my ($self, $set_name) = @_;
return $self->{sets}{$set_name};
};
sub fuzzyEngine { shift->{fuzzyEngine} };
sub is_valid_set {
my ($self, $set_name) = @_;
# Should be simplified to exists $self->{sets}{$set_name}
return List::MoreUtils::any { $_ eq $set_name } keys %{ $self->sets };
}
sub fuzzify {
my ($self, $val) = @_;
croak "Fuzzification not allowed for internal variables"
if $self->is_internal;
for my $set (values %{ $self->sets } ) {
$set->fuzzify( $val );
};
return;
}
sub defuzzify {
my ($self) = @_;
croak "Defuzzification not allowed for internal variables"
if $self->is_internal;
my @sets = values %{$self->sets};
my @funs = map { $_->memb_fun } @sets;
my @degrees = map { $_->degree } @sets;
# If all degrees are real scalars a shortcut is possible
if (_non_is_a_piddle(@degrees)) {
my $funs = _clipped_funs( \@funs, \@degrees);
my $fun_agg = $set_class->max_of_funs( @$funs );
my $c = $set_class->centroid( $fun_agg );
return $c;
};
# Need a function of my FuzzyEngine
my $fe = $self->fuzzyEngine;
die 'Internal: fuzzy_engine is lost' unless $fe;
# Unify dimensions of all @degrees (at least one is a pdl)
my @synched_degrees = $fe->_cat_array_of_piddles(@degrees)->dog;
my @dims_to_reshape = $synched_degrees[0]->dims;
# Make degrees flat to proceed them as lists
my @flat_degrees = map {$_->flat} @synched_degrees;
my $flat_degrees = PDL::cat( @flat_degrees );
# Proceed degrees of @sets as synchronized lists
my @degrees_per_el = $flat_degrees->transpose->dog;
my @defuzzified;
for my $ix (reverse 0..$#degrees_per_el) {
my $el_degrees = $degrees_per_el[$ix];
# The next two lines cost much (75% of defuzzify)
my $funs = _clipped_funs( \@funs, [$el_degrees->list] );
my $fun_agg = $set_class->max_of_funs( @$funs );
my $c = $set_class->centroid( $fun_agg );
$defuzzified[$ix] = $c;
};
# Build result in shape of unified membership degrees
my $flat_defuzzified = PDL->pdl( @defuzzified );
my $defuzzified = $flat_defuzzified->reshape(@dims_to_reshape);
return $defuzzified;
}
sub _clipped_funs {
# Clip all membership functions of a variable
# according to the respective membership degree (array of scalar)
my ($funs, $degrees) = @_;
my @funs = @$funs; # Dereferencing here saves some time
my @degrees = @$degrees;
my @clipped = List::MoreUtils::pairwise {
$set_class->clip_fun($a => $b)
} @funs, @degrees;
return \@clipped;
}
sub reset {
my ($self) = @_;
$_->reset() for values %{$self->sets};
return $self;
}
sub change_set {
my ($self, $setname, $new_memb_fun) = @_;
my $set = $self->set( $setname );
# Some checks
croak "Set $setname does not exist" unless defined $set;
croak 'Variable is internal' if $self->is_internal;
# Convert to internal representation
my $fun = $self->_curve_to_fun( $new_memb_fun );
# clip membership function to borders
$set->set_x_limits( $fun, $self->from => $self->to );
# Hand the new function over to the set
$set->replace_memb_fun( $fun );
# and reset the variable
$self->reset;
return;
}
sub _init {
my ($self, @pars) = @_;
( run in 0.456 second using v1.01-cache-2.11-cpan-39bf76dae61 )