``````package AI::Fuzzy::Label;

## 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 };

# m = slope of the line.. (change in y/change in x)
#     change in y is 1 as membership increases, -1 as it decreases
my \$mIncreasing =  1 / (\$self->{mid} - \$self->{low});
my \$mDecreasing = -1 / (\$self->{high} - \$self->{mid});

# reject values that are "out of bounds"
return (\$membership = 0)
if (\$value <= \$self->{low} ) or (\$value >= \$self->{high} );

# now calculate membership:
# y=mx+b , just like in algebra
if (\$value < \$self->{mid}) {
\$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;
``````