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 )