AI-Fuzzy
view release on metacpan or search on metacpan
lib/AI/Fuzzy/Axis.pm view on Meta::CPAN
package AI::Fuzzy::Axis;
use AI::Fuzzy::Label;
## Container for Fuzzy Labels ####
sub new {
my ($class) = @_;
my $self = {};
$self->{labels} = {};
bless $self, $class;
return $self;
}
sub addlabel {
# adds a label for a range of values..
my ($self, $label, $low, $mid, $high) = @_;
if ($label->can("name") ) {
$self->{labels}->{$label->name} = $label;
} else {
$self->{labels}->{$label} = new AI::Fuzzy::Label($label, $low, $mid, $high);
}
return $self->{labels}->{$label};
}
sub applicability {
# this function should be called something else..
# calculates to what degree $label applies to a $value
my ($self, $value, $label) = @_;
my $membership = 0;
return $label->applicability($value) if ($label->can("applicability"));
return undef unless ( exists $self->{labels}->{$label} );
return $self->{labels}->{$label}->applicability($value);
}
sub label {
# returns a label associated with this text
my ($self, $name) = @_;
return $self->{labels}->{$name};
}
sub labelvalue {
# returns a label associated with this value
my ($self, $value) = @_;
my $label;
my %weight;
my $total_weight = 0;
my @range = $self->range();
# first, find out the applicability of each label
# and weight the labels accordingly.
lib/AI/Fuzzy/Axis.pm view on Meta::CPAN
$x += $weight{$label};
return $self->{labels}->{$label} if $x >= $v;
}
# and if none of that worked..
return 0;
}
sub range {
# returns a list of sorted labels
my ($self) = @_;
my $l = $self->{labels};
return sort { $a <=> $b } values %{$l};
}
sub lessthan {
my ($self, $labela, $labelb) = @_;
if ( exists $self->{labels}->{$labela} and exists $self->{labels}->{$labelb} ) {
my $la = $self->{labels}->{$labela};
my $lb = $self->{labels}->{$labelb};
return $la->lessthan($lb);
} else {
return undef;
}
}
sub lessequal {
my ($self, $labela, $labelb) = @_;
if ( exists $self->{labels}->{$labela} and exists $self->{labels}->{$labelb} ) {
my $la = $self->{labels}->{$labela};
my $lb = $self->{labels}->{$labelb};
return $la->lessequal($lb);
} else {
return undef;
}
}
sub greaterthan {
my ($self, $labela, $labelb) = @_;
if ( exists $self->{labels}->{$labela} and exists $self->{labels}->{$labelb} ) {
my $la = $self->{labels}->{$labela};
my $lb = $self->{labels}->{$labelb};
return $la->greaterthan($lb);
} else {
return undef;
}
}
sub greaterequal {
my ($self, $labela, $labelb) = @_;
if ( exists $self->{labels}->{$labela} and exists $self->{labels}->{$labelb} ) {
my $la = $self->{labels}->{$labela};
my $lb = $self->{labels}->{$labelb};
return $la->greaterequal($lb);
} else {
return undef;
}
}
sub between {
my ($self, $labela, $labelb, $labelc) = @_;
if ( exists $self->{labels}->{$labela} and exists $self->{labels}->{$labelb}
and exists $self->{labels}->{$labelc} ) {
my $la = $self->{labels}->{$labela};
my $lb = $self->{labels}->{$labelb};
my $lc = $self->{labels}->{$labelc};
return $la->between($lb, $lc);
} else {
lib/AI/Fuzzy/Label.pm view on Meta::CPAN
## Fuzzy Label ####
use overload ( '>' => \&greaterthan,
'<' => \&lessthan,
'>=' => \&greaterequal,
'<=' => \&lessequal,
'<=>'=> \&spaceship,
'""' => \&stringify
);
sub new {
my ($class, $name, $low, $mid, $high) = @_;
my $self = {};
bless $self, $class;
$self->{name} = $name;
$self->{low} = $low;
$self->{mid} = $mid;
$self->{high} = $high;
return $self;
}
sub name {
my ($self, $name) = @_;
$self->{name} = $name if ($name);
return $self->{name};
}
sub stringify {
my $self=shift;
return qq([$self->{name}: $self->{low},$self->{mid},$self->{high}]);
}
sub lessthan {
my ($self, $that) = @_;
if ($self->{low} < $that->{low}) {
return 1;
} else {
return 0;
}
}
sub lessequal {
my ($self, $that) = @_;
if ($self->{low} <= $that->{low}) {
return 1;
} else {
return 0;
}
}
sub greaterthan {
my ($self, $that) = @_;
if ($self->{high} > $that->{high}) {
return 1;
} else {
return 0;
}
}
sub greaterequal {
my ($self, $that) = @_;
if ($self->{high} >= $that->{high}) {
return 1;
} else {
return 0;
}
}
sub between {
my ($self, $that1, $that2) = @_;
if ( ( $that1 <= $self and $self <= $that2) ||
( $that2 <= $self and $self <= $that1) ) {
return 1;
} else {
return 0;
}
}
sub spaceship {
my ($self, $that) = @_;
return ( $self->{mid} <=> $that->{mid} );
}
sub applicability {
# this function should be called something else..
# calculates to what degree this label applies to a $value
my ($self, $value) = @_;
my $membership = 0;
# if the low and mid points are same as value, full membership
# same if mid and high are same as value
if ($self->{mid} == $self->{low} && $value == $self->{low}) { return 1 };
if ($self->{high} == $self->{mid} && $value == $self->{high}) { return 1 };
lib/AI/Fuzzy/Label.pm view on Meta::CPAN
$membership = ($value - $self->{low}) * $mIncreasing;
} elsif ($value == $self->{mid}) {
$membership = 1;
} else {
$membership = (($value - $self->{mid}) * $mDecreasing) + 1;
}
return $membership;
}
sub range {
# returns the distance from one endpoint to the other
my ($self) = @_;
return abs( $self->{high} - $self->{low} );
}
1;
lib/AI/Fuzzy/Set.pm view on Meta::CPAN
package AI::Fuzzy::Set;
## Fuzzy Set ####
sub new {
my $class = shift;
my $self = {} ;
# accepts a hash of member weights..
# ( $members{$member}=$weight )
%{$self->{members}} = @_;
bless $self, $class;
}
sub membership {
# naturally, it returns a fuzzy value - the degree
# to wich $item is a member of the set! :)
my $self = shift;
my $item = shift;
if (defined(${$self->{members}}{$item})) {
return ${$self->{members}}{$item};
} else {
return 0;
}
}
sub members {
# returns list of members, sorted from least membership to greatest
my $self = shift;
my %l = %{$self->{members}};
return sort { $l{$a} <=> $l{$b} } keys %l;
}
sub equal {
# returns true if the argument set is equal to this one
my $self = shift;
my $otherset = shift;
my (%us, %them);
%us = %{$self->{members}} if (exists $self->{members});
%them = %{$otherset->{members}} if (exists $otherset->{members});
# for all keys in us and them
foreach my $key (keys (%us), keys (%them)) {
lib/AI/Fuzzy/Set.pm view on Meta::CPAN
return 0 unless (exists ($us{$key}) && exists ($them{$key}) );
# not equal if the membership of the keys isn't equal
return 0 unless (float_equal($us{$key},$them{$key}, 10));
}
# otherwise they are equal
return 1;
}
sub union {
# returns a set that is the union of us and the argument set
my $self = shift;
my $otherset = shift;
my (%us, %them, %new);
%us = %{$self->{members}} if (exists $self->{members});
%them = %{$otherset->{members}} if (exists $otherset->{members});
# for all keys in us and them
foreach my $key (keys (%us), keys (%them)) {
lib/AI/Fuzzy/Set.pm view on Meta::CPAN
if ($us{$key} >= $them{$key}) {
$new{$key} = $us{$key};
} else {
$new{$key} = $them{$key};
}
}
return new AI::Fuzzy::Set(%new);
}
sub intersection {
# returns a set that is the intersection of us and the argument set
my $self = shift;
my $otherset = shift;
my (%us, %them, %new);
%us = %{$self->{members}} if (exists $self->{members});
%them = %{$otherset->{members}} if (exists $otherset->{members});
# for all keys in us and them
foreach my $key (keys (%us), keys (%them)) {
lib/AI/Fuzzy/Set.pm view on Meta::CPAN
if ($us{$key} <= $them{$key}) {
$new{$key} = $us{$key};
} else {
$new{$key} = $them{$key};
}
}
return new AI::Fuzzy::Set(%new);
}
sub complement {
# returns a set that is the complement of us
# requires that the set contain values from 0 to 1
my $self = shift;
my (%new);
foreach my $member ($self->members) {
my $comp = 1 - $self->membership($member);
return undef if ($comp < 0 || $comp >1);
$new{$member} = $comp;
}
return new AI::Fuzzy::Set(%new);
}
sub support {
# returns the support set.
# defined as the set of all elements in our set with a non-zero membership.
my $self = shift;
my (%support);
foreach my $member ($self->members) {
$support{$member}++ if ($self->membership($member) != 0);
}
return new AI::Fuzzy::Set(%support);
}
sub core {
# returns the core set.
# defined as the set of all elements in our set with full membership
my $self = shift;
my (%core);
foreach my $member ($self->members) {
$core{$member}++ if ($self->membership($member) == 1);
}
return new AI::Fuzzy::Set(%core);
}
sub height {
# returns the height of the set
# defined as the maximal membership value in our set
my $self = shift;
my ($max) = 0;
foreach my $member ($self->members) {
$max = $self->membership($member) if ($self->membership($member) > $max);
}
return $max;
}
sub is_normal {
# Logical return
# normal is defined as a set with a height of 1
my $self = shift;
return 1 if ($self->height == 1);
return 0;
}
sub is_subnormal {
# Logical return
# normal is defined as a set with a height less than 1
my $self = shift;
return 1 if ($self->height < 1);
return 0;
}
sub as_string {
my $self = shift;
my @members;
foreach my $member ($self->members) {
push (@members, "$member/" . $self->membership($member) );
}
return join(', ', @members);
}
sub float_equal {
my ($A, $B, $dp) = @_;
# print sprintf("%.${dp}g", $A). " eq " . sprintf("%.${dp}g", $B) . "\n";
return sprintf("%.${dp}g", $A) eq sprintf("%.${dp}g", $B);
}
1;
( run in 0.277 second using v1.01-cache-2.11-cpan-a5abf4f5562 )