The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

AI::FuzzyLogic - Fuzzy Set Operations and Tools

SYNOPSIS

  use AI::FuzzyLogic;

  $i = new AI::FuzzyLogic $unittype, @numbers;          # new set with one subset
  $i = new AI::FuzzyLogic 'age', 0, 0.1, 0.2, 0.1, 0;   # same thing

  $i = new AI::FuzzyLogic $subset1, $subset2, $subset3; # new set with several subsets

  # another syntax for building a set with several subsets:
  $i = AI::FuzzyLogic->new(
       AI::FuzzyLogic->new('distance', 0.0, 0.1, 0.1, 0.5, 0.8, 0.6, 0.3, 0.0),
       AI::FuzzyLogic->new('time',     0.3, 0.3, 0.1, 0.1, 0.1, 0.2, 0.3, 0.3),
       AI::FuzzyLogic->new('heat',     0.0, 0.1, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2),
  );

  # constructors for explicit combinational behavior:
  $i = new AI::FuzzyLogic::Correlator 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;
  $i = new AI::FuzzyLogic::Permutator 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;
  $i = new AI::FuzzyLogic::Discriminator 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;
  $i = new AI::FuzzyLogic::Abstractor 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;

  # change combinational behavior:
  $set->as_correlator();      # operations work on matching subsets of same type
  $set->as_permutator();      # operations work across all subsets of each set
  $set->as_discriminator();   # operations best matching subset from right for each on left
  $set->as_abstractor();      # operations return one set with one subset summerizing fit

  $i->add_subsets($j);        # combine subsets or other sets in

  abs($i)                     # defuzzify to integer (centroid - curve middle, x axis)
  0+$i                        # defuzzify to integer (mean - average curve height, y axis)

  $a & $b                     # intersection of sets
  $a | $b                     # union of sets
  $i++                        # normalize curve to 1.0
  $i--                        # stretch curve to edges
  ~$i                         # negate set
  $i ** 0.5                   # dialation
  "$i"                        # convert subsets to ASCII graphs

  $a + $b                     # sum sets
  $a - $b                     # subtract sets
  $a * $b                     # multiply sets - useful for sensitivity control
  $a / $b                     # divide sets - useful for sensitivity control

  $h->larger($a)              # boolean: does $h completely encompass $a? 

  $a ^ $b                     # xor: same as ~($a | $b)
  $a < $b                     # compare volume: is $a smaller?
  $a > $b                     # compare volume: is $a larger?

  @sets = $a->unwrap();              # get subsets as list of AI::FuzzyLogic::Subset objects
  @sets = $a->query_type('type');    # get subsets of type 'type' as a list of AI::FuzzyLogic::Subset objects
  $a->change_type('fromtype', 'to'); # change type of subsets of type 'fromtype' to 'to'

DESCRIPTION

Performs all basic operations on Fuzzy Sets. Use English-like, intentionally vague objects representing concepts with which to make inferences. The inferences might be approximate reasoning about precise knowledge, or precise reasoning about approximate knowledge. This vagueness allows the capture and application of human expert knowledge.

Overloads Perl operators to perform operations on Fuzzy Sets.

Other Fuzzy Modules

AI::FuzzyInference and AI::Fuzzy appear to better supported and more mature modules.

How AI::FuzzyLogic is Different

It doesn't attempt to provide a structure for building inference chains - that is left to regular Perl code using overloaded operators, if statements, and the like. So, a major feature is the operator overloading and that interface.

We also define a larg set of operations, introduce sets-of-sets and combinational, permutational behavior for working on them.

Extensible framework. Modules in this distribution may be subclassed to define new Fuzzy operations, combinational behaviors, and other features. Extensions may be added to this distribute (if I like them), or you may distribute them seperately, with this module as a dependency.

Terminology

This is not standard Fuzzy Logic terminology but instead lingo used in this module. Sets (AI::FuzzyLogic) contain subsets (AI::FuzzyLogic::Subset). Subsets contains elements. Elements are just numbers in an array (this implementation may change, but it is useful to think of it this way). Elements are also called segments sometimes, as in segments in a LED display. Combinational Behavior controls what happens when an operation is performed between two sets, one or both of which have more than one subset.

Methods

These public methods expose parts of the interface that aren't available through the overloaded syntax. The overloaded syntax is of course the ability to use Perl built in operators on Fuzzy sets and have Fuzzy operations performed.

new

new() comes in two basic forms.

Create a new set, with exactly one subset, from raw input data:

  $i = new FuzzyLogic $unittype, @numbers;          # new set with one subset
  $i = new FuzzyLogic 'age', 0, 0.1, 0.2, 0.1, 0;   # same thing

Create a new set, with potentially many subsets, from several existing subsets.

  $i = new FuzzyLogic $subset1, $subset2, $subset3; # new set with several subsets

Subsets can be obtained form existing sets using the unwrap() method:

  $i = new FuzzyLogic $set1->unwrap(), $set2->unwrap();

unwrap() may return any number of subsets.

Though the module will extract the subsets from sets should sets be passed to the constructor. This is like perl arrays - combining arrays flattens them all into one large one. No, there is no equivilent to references. See the BUGS for another note on this.

AI::FuzzyLogic::Abstractor is the default type of new objects. If something else is desired, it should be specified explicitly, as the default is likely to change in future versions.

  # constructors for explicit combinational behavior:
  $i = new AI::FuzzyLogic::Correlator 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;
  $i = new AI::FuzzyLogic::Permutator 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;
  $i = new AI::FuzzyLogic::Discriminator 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;
  $i = new AI::FuzzyLogic::Abstractor 'speed', 0.1, 0.3, 0.2, 0.1, 0.1;

Beware! Once created, you'll need to change the combinational behavior frequently to get any work done. Use the as_correlator(), as_discriminator(), as_permutator(), and as_abstractor() methods to change the type of an existing object.

add_subsets

Just like new(), but adds new subsets to an existing set.

  $set->add_subsets(new AI::FuzzyLogic 'foo', 0.0, 0.1, 0.1, 0.1, 0.0);

Newly added subsets retain their type in the new object (though the output of an operation against an Abstractor is always a single set of type 'abstract').

new() calls this method to do its dirty work.

query_type

  $set->query_type('speed');

Return the subsets (AI::FuzzyLogic::Subset objects) of a given type ('speed', in this example. In scalar context, the first is returned. In list context, all matching subsets are returned. This allows access to subsets directly minipulate them. This can be used with the constructor to build a new AI::FuzzyLogic object containing all subsets of a given type:

  $speeds = new AI::FuzzyLogic $old_set->query_type('speed');

Returns undef if none are found.

unwrap

  @subsets = $set->unwrap();

Return all subsets from a set. These may be used to construct new sets, or they may be individually minipulated (type changed, perhaps). Some operators mutate (change the existing object) while others return new objects that reflect the changes. The former case will affect the state of the set from which the subset was obtained, and the latter won't.

Handy for debugging:

  foreach my $i ($set->unwrap()) {
    print "in set: ", $i->type(), "\n";
  }

Subsets also have an unwrap() method that returns an array of scalar floating point values that describe the set.

change_type

  $bar->change_type('abstract', 'foo'); # change result from "abstract" to "foo" type

To make the combinational magic specified by Combinational Behavior work, types must match up. This means frequently having to change the type of a subset in a set. Volts may go to ampres to watts, and will need to be renamed at each step. If sets with only one subset are used, it may be easier to just make all sets into Permutators:

  my $juice = AI::FuzzyLogic::new('juice', 0.5, 0.5, 0.5)->as_permutator();

This, and the result of all operations on which it is on the left hand side of, will all combine freely with other types. Otherwise, you'd eventually have to do:

  $juice->change_type('juice', 'watts'); 

Beware! Type is completely different than combinational behavior. Type controls how things combine, but the rules ultimately depend on the combinational behavior of the object on the left of the operation. Start with the description of the combinational behavior (Abstractor, Permutator, Discriminator, Correlator) and read how it uses type information.

larger

  $a->larger($b); # does $a completely encompass $b?

Test if one set fits entirely within another or not. If there are multiple subsets and combinational behavior and types allow, then it returns true if any matching subsets on the left are larger than any on the right.

Unlike the above, this is actually beleived to work and has been somewhat tested.

Combinational Behavior

A set contains subsets. How the subsets of two sets interact when an operation is performed is their combination behavior. Depending on what the data means and how you're using it, you'll need to specify how things combine.

Abstractors

Abstractors always return exactly one set, which is meant to be a gross summary of membership of one set in another. Returns one set, with about as many members as there are subsets in the object on the right. Gives a membership summery, or a composition of how well or how poorly all of the various attributes match up, by type. If the types don't match up, they are ignored. Otherwise, the comparision of the matching sets forms a single segment in the output set. The output set is balanced, with the line the highest in the center. Useful when used between a set containing patterns to match and set containing observations.

For example, subsets may represent color and size. One set, "a", is observed in the wild (the Internet, through data capture, what have you). Other sets, "x1", "x2", "x3", etc, each having the same subsets (color and size) are compared against "a" to find the best match in attempt to classify "a" as being stereotypical of one of a few known cases.

If the output is a flat zeros, no criteria matched. If it is a low curve, few things matched, and they matched poorly. If it is a low curve with some spikes in the middle, a few things matched well, but most criteria matched poorly. A nice bell curve is a fairly good match on most criteria, and a solid box with 1's across the board is a perfect fit.

  $set->as_abstractor();

The result is always balanced (the hump, if any, is in the middle).

The single result set contains exactly one subset, which is of type 'abstract'. To do operations on that with anything other than larger() or a Permutator, you'll need to change the type to match the desired subset type of the other set.

  my $foo = new AI::FuzzyLogic 'foo', 0.1, 0.2, 0.5, 0.2, 0.1;

  my $bar = $big_old_set->as_abstractor() & $another_big_old_set();

  $bar->change_type('abstract', 'foo'); # change result from "abstract" to "foo" type

  my $baz = $foo & $bar;

Beware! Once created, you'll need to change the combinational behavior frequently to get any work done. These as_... methods will need to be used over and over.

Discriminators

Discriminators pare down sets which have subsets.

Discriminators consider all of the permutations, but throw away all of them except the set from the right-hand-side which yeildeds the largest resulting set (defined by volume). Hence, whichever operation is performed on a discriminator only serves to give a criteria for selecting a set from the right-hand-side. Discriminators are useful for selecting one optimial case from a number of alternatives. Like the permutator, except we only keep the highest ranked cross matches. Always returns exactly one set from the right hand side. The left hand side is considered to be the rule by which to measure the left.

  $set->as_discriminator();

Permutators

Permutators consider every possible permutation between subsets in the object on the left-hand-side and the subsets in the object on the right-hand-side, and return an object with a subset for each permutation. Performs the desired operation as a cartesian product.

  $set->as_permutator();

Correlators

Correlators are like Permutators, except instead of considering all permutations, they only consider permutations between subsets with matching unit types. Permutators and Correlators are useful for generating alternative cases, possibly in several steps, which Discriminators or Abstractors may then select from.

Useful for finding optimal cases. For example, combinations of two or more gears can be considered, and then in an additional step, the combination best matching some criteria could be selected.

  $set->as_correlator();

INTRODUCTION TO FUZZY LOGIC

Since Perl is used rather than a dedicated Fuzzy language (like DCU), some aids for constructing control systems and expert systems with fuzzy logic are provided.

FuzzyLogic overloads most math operators.

Think of a fuzzy set as a box with a line running through it:

  ______________________________________________
  |                    ___                     |
  |                 __/   \__                  |
  |              __/         \__               |
  |           __/               \__            |
  |        __/                     \__         |
  |     __/                           \__      |
  |  __/                                 \__   |
  | /                                       \_ |
  ----------------------------------------------

The line has several interesting attributes:

Height at highest point
Average height, looking up and down, on the Y axis
Volume under the line
Center of mass, looking left to right, on the X axis

The X axis (left to right) is a continuum of some user defined metric. The metric can be anything measureable, but it is up to you to combine things in useful ways. Speed by time is distance, volts over resistance is ampres, and so forth. If you want to write a metaphysical module that couples color with mood, you're on your own. Each set measures one kind of thing: speed, distance, time, voltage, color, age, irritation, whatever. If the center of mass of the line is on the far left, it means "slow", "short", "quick", "low power", "red", "young", or "happy", respectively. The exact meaning of the left and the right depends on what the metric is. The system doesn't understand metrics beyond recognizing two metrics as being the same or different.

The Y axis of the box represents degree of membership. The top is expressed as "1.0". The bottom represents lack of membership and is expressed as "0.0". While up and down represent degree of membership, left and right are user-defined: they reprsent some continuum of which membership is measured. The above set could represent someone who is middle aged: they aren't young, they aren't old. The closer you get to the middle, the stronger the membership. "Age" would be our "unit type". The unit type describes what the continuum measures: age, color, speed, time, distance, size, or any other quality or quantity.

The line itself represents a mapping between the metric and the degree of membership. A "sharp" classification would give a precise X value and a precise Y value. A statistical system might give many precise X and Y values and make inferances from that. A Fuzzy system has a degree of membership (possibly 0) for each value of X.

The continuum is important. As operations are performed, and degrees of membership are measured, this line will start to fall like a circus tent, only being proped up in a few random places.

No definate meanings are defined for unit types, but it is handy to compose sets out of subsets, where each set might have a subset for color, size, and speed, for instance. We'll see shortly how unit types help with classification operations in the Purmutations section.

"Set", "curve", and "object" are used interchangeable to mean a fuzzy set. "Subset" and "property" are used interchangeable to mean one fuzzy set in an object that contains several.

Membership Tests

Membership tests are the heart of Fuzzy Logic.

A fuzzy set can be thought of as a curve inside of a box. The top of the box is 1.0, the bottom 0.0.

  ______________________________________
  |               __                    |
  |            __/  \___                |
  |         __/         \__             |
  |     ___/               \__          |
  | ___/                      \____     |
  |/                               \_   |
  --------------------------------------

Binary operators perform membership tests:

  $blue + $red;    # the sum of two sets - purple
  $sky & $blue;    # intersection of two sets - still blue
  $sky - $blue;    # the sky without blueness - redish hues show through
  $sky | $white;   # blue is what the sky and white have in common

To make any useful deductions, several membership tests must be chained together.

Fuzzy Sets have subsets. For instance, "Size" may be a collection of the subsets representing "Small", "Medium", and "Large". Comparing a set with the "Size" set will yield multiple results, one of which will have more volume then the others. Discriminator operations may be used to select a single set from a set that contains subsets, among other things. After discrimination, operations are available to "defuzzify" a set, and give precise numeric output.

  my $small = new AI::FuzzyLogic 'size', 0.3, 0.3, 0.3;

One of a few cases will apply to any given instance of AI::FuzzyLogic:

Contains several subsets, each of different unit-types

For example, speed, distance, temperature, etc. Each of these attributes describe the same object: perhaps a runner in a race, measured at a point in time.

Contains several things of the same unit type

For a unit type of "size", subsets might represent small, large, huge, etc. This will likely be used to describe, categorize, recognize, or classify another set that describes something concrete, like the runner in the previous item.

Output of some operation on sets of sets representing membership

To consider complex cases, multiple attributes must be distilled. To determine if a runner is holding steady and not losing momentum, you could test their distance, take that result, and test it against their speed. This might be a good way to predict a winner.

Manual Discrimination

Discriminator methods (smallest(), largest(), best(), and centroid()) take a set with subsets and another fuzzy object, and match them up according to some heuristic. This is useful to select a single set out of a pool of subsets. This can be done to select a type of control operation to perform from an exclusive pool, to select a hedge to describe a set, or to rid yourself of the subsets in general. This is designed to be used on objects of type FuzzyLogic::Discriminator, but may be useful with other subtypes as well.

For example, you may compare several hedges to a set to find out which description best suits it. You may compapre a set of speeds against a volicity. You may compare a set of sizes against an object. You may compare a set of known colors against a new color.

Or, given a series of objects, you may wish to know which is the fastest, largest, or redest of the lot.

  my $fast =    new FuzzyLogic 'speed', 1.0, 0.9, 0.7, 0.2, 0.0, 0.0, 0.0, 0.0;
  my $medium =  new FuzzyLogic 'speed', 0.0, 0.1, 0.3, 1.0, 1.0, 0.3, 0.1, 0.0;
  my $slow =    new FuzzyLogic 'speed', 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.7, 1.0;
  my $moving =  new FuzzyLogic 'speed', 0.5, 0.7, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0;
  my $stopped = new FuzzyLogic 'speed', 1.0, 0.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0;
  $speeds = new FuzzyLogic $slow, $medium, $fast, $moving, $stopped;

  # which speed hedge best describes the speed of the fuzzy object $volicity?
  # in this example, this would be the prefered method. it asks the system
  # to find a curve that closely resembles the input, considering both X
  # and Y axises.
  # probably one of fast, medium, or slow
  $volicity->best($speeds);

  # if moving and stopped weren't options, this would work well, but they are
  # reduced to their average X position by center of weight. 
  $volicity->centroid->($speeds); 

  # which speed hedge, if any, would be an understatement? this would be the
  # absolutely most specific statement that could be made.
  $volicity->smallest($speeds);

  # which speed hedge, if any, would be an overstatement, completely describing
  # the speed, even if it has to exaggerate a little? this would be the most 
  # general statement that could be made. probably moving or stopped, as they
  # are the most emcompassing, but likely one of fast, medium, or slow as well.
  $volicity->largest($speeds);

Like operators, manual discriminators are subject to the laws of combination behavior.

larger() is a special case - rather than filtering, it performs a simple binary test - does one set fit entirely within another? Doesn't work when more than (or less than) one subset is present in either set.

  # larger(), simple case:

  if($a->larger($b)) {
    # condition met
  }

Useful for after abstracting with Abstractor:

  # initialization time:

  $a = new AI::FuzzyLogic (
       AI::FuzzyLogic::Subset->new('foo', 0.0, 0.1, 0.3, 0.1, 0.0),
       AI::FuzzyLogic::Subset->new('bar', 1.0, 0.9, 0.7, 0.3, 0.1),
  );

  $a->as_abstractor();

  $b = new AI::FuzzyLogic 'abstract', 0.2, 0.3, 0.2;

  # run time:

  while(1) {
    
    # create $c here from sensor input or what not
  
    my $d = $a & $c;

    $d->balance(); # move large segments to the middle, making a nice hump

    if($d->larger($b)) {
      # conditions in $a met within criteria required by $b - match successful
    }

    sleep 1;

  }

This is a classic two-stage filtering: each criteria is individually operated on in the $a & $c line, doing a membership function. The $d-balance()> and $d-larger($b)> take that and make a final descision on whether or not the degree of membership is enough.

Combinational Behavior

Subclasses of the FuzzyLogic module combine their subsets in different ways. All Fuzzy objects are actually a subclass. If none is specified, new Fuzzy objects are instances of AI::FuzzyLogic::Abstractor. Depending which subclasses are loaded, one of them will take over the position of being the default type. There are four types defined: Discriminators, Correlators, Permutators, and Abstractors.

Combinational behaviors pare down possibilities, generate possibilities that may be later pared down, or apply an operation to every subset in a set without changing their numbers. This is an extention to normal Fuzzy systems. It should be thought of as glue for making useful Fuzzy operations tolerable to code in Perl, using overloaded operators. Of course, it wouldn't be needed with hyperoperators: @a = (new AI::FuzzyLogic ..., new AI::FuzzyLogic ...); @a = @a + @b;

The object on the left-hand-side of the operator specifies the details of how the two subsets in the objects combine, and specifies the default combinational behavior of the resulting object. Left-hand-side and right-hand-side refer to the two sets on either side of an operator. For example, given: $seta * $setb, $seta is on the left-hand-side and $setb is on the right-hand-side.

Combination behavior of an existing object may be changed with mutator methods. The same object, containing the same data but of the desired type, is returned, and modified in-place. The methods are:

  $set->as_correlator();
  $set->as_permutator();
  $set->as_discriminator();
  $set->as_abstractor();

Of course, this never hurts:

  $set = $set->as_correlator();

Operators

Unary operators behave in a predictable way. Binary operators act on two arguments and combine them in some form to create a result. How they are combined depends on the combinational behavior of the argument on the left.

  &       # set intersection (min)

The portion of the two sets that overlap is the result. This is the standard membership test. Keep the Abstractor in mind as you use this. See also the larger() method for a similar test that instead returns a boolean value.

  |       # set union (max)

Useful for building sets as compositions of other sets and for judgeing fit in some situations. The highest point from each line in each set is the output set. That is, the output contains the largest values from both input sets. Useful for building sets as a composite of other sets.

  ^       # set xor ;)

Defined for completeness. Let me know if you find a use for it. Output set plots the degree that neither input set registers.

  +       # set summation

Useful for building sets as composites of other sets. Output line is as high as the first input plus the second input. Good for massaging data before abstracting. Keep the Correlator in mind when using this.

  -       # set difference

Useful for building sets as composits of others. Output set is first input set minus the height of the second.

  *       # set multiply

For building composite sets. Keep the Correlator in mind when using this. Given an observation set (perhaps created from sensor data) and a set representing a floating sensitivity that goes up and down as needed to avoid feedback and false positives, the two sets would be multiplied together to apply the sensitivity control to the observation data. Since a set can't (in a non buggy implementation) contain values greater than 1.0, multiplication only serves to scale sets downwards, never up. Values get smaller. See ** below for a way to scale things up.

  /       # set divide

For building composite sets. Haven't found a purpose aside from the obvious manual tweaking of sets.

  neg()   # opposite

  ~       # opposite

Output set is input sets high points converted to low points, and low points converted to high points. When a set contains data of the wrong sense, this allows you to make another set from it of the right sense. For example, if you have a decaying frequency average, and you want reduce input sensitivity when the event happens frequently, you would invert the running average and multiply that by observation data before testing it. In other words, frequency can be converted to infrequency. Kind of obvious, really.

  **      # dialation (2nd arg must be number)

Scales entire set to some degree. The argument is an exponent that is applied to each individual segment in each subset in the set.

  <       # which has less area?

Compare sets by volume.

  >       # which has more area?

Compare sets by volume.

  ""      # make pretty little charts

A box with a line plotted through it will be output for each subset. Meant to be human-readable.

  abs     # defuzzify - centroid

Converts sets into a single integer between 0 and 1. Number is the relative position of the center of the "hump", along the X axis. The X axial meaning is decided by the user, so this value would be the point on the continuum where this observation best fits in. Calculation is a center of mass calcuation, where half of the volume is on each side of this point. Useful for arriving at a quantitative value after all Fuzzy processing is done. The number will usually represent degree of membership, and may be the result of several chained membership tests.

  0+      # defuzzify - average height

Converts set into a single integer between 0 and 1. Number is average of line height along the Y axis. The Y axis represents degree of membership, so the result is the average degree of membership over the measured continuum. Useful for arriving at a quantitative value after all Fuzzy processing is done. The number will usually represent degree of membership, and may be the result of several chained membership tests.

Subset Objects

AI::FuzzyLogic::Subset and AI::FuzzyLogic::MetaSubset implement subsets - one AI::FuzzyLogic object may contain any number of subsets. Subsets store three fields - name, type, and the set itself. The set shouldn't be directly access - unwrap() should be called to get a set of useful values representing it. If you're writing something to muck around in the internals, use the wrap() method. Pass it an array (by value) of data and it will dutifully load it in. Note that the cleanest solution would be to subclass Subset or MetaSubset and add additional accessors there, rather than having external code work on the data. However, the system isn't faithful about maintaining the exact subclass when operations are done on subsets.

  my $name = $subset->name();    # query name
  $subset->name('foo');          # set name
  $subset->name('foo') = 'name'; # also set name

To get to set data as an array of scalar floats:

  my @setdata = $subset->unwrap();

Other accessors use the same conventions. MetaSubset subclasses subset to add an attribute() method:

  my $attrib = $metasubset->attribute();
  $metasubset->attribute(new Foo::Bar $data, $moredata); 

The attribute field can hold objects, string, arrays (by reference) or whatever scalar data. I created it to associate data with sets in a search engine type thing. When a match is found, I want to know the information about the thing found. Merely saying "20 things found" isn't very useful.

EXAMPLES

  $apple = new AI::FuzzyLogic  'color', 0.9, 0.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0; 
  $orange = new AI::FuzzyLogic 'color', 0.0, 0.0, 0.1, 0.7, 0.5, 0.3, 0.1, 0.0;

  $red = new AI::FuzzyLogic    'color', 1.0, 0.7, 0.2, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0;
  $orange = new AI::FuzzyLogic 'color', 0.3, 0.7, 1.0, 0.7, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0;
  $green = new AI::FuzzyLogic  'color', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 1.0, 0.5, 0.0;

  $colors = new AI::FuzzyLogic $red, $orange, $green;

  # try to decide what kind of fruit we have by their color
  $fruitbycolor = $fruit->best($colors);
  print $fruitbycolor;

  # flat lines as sets to test degree of membership in output from another test
  my $hedges = AI::FuzyLogic->new(
    AI::FuzzyLogic->new('not',        0.0, 0.0),
    AI::FuzzyLogic->new('slightly',   0.1, 0.1),
    AI::FuzzyLogic->new('notvery',    0.2, 0.2),
    AI::FuzzyLogic->new('kindof',     0.3, 0.3),
    AI::FuzzyLogic->new('moderately', 0.4, 0.4),
    AI::FuzzyLogic->new('quite',      0.7, 0.7),
    AI::FuzzyLogic->new('definately', 0.8, 0.8),
    AI::FuzzyLogic->new('extremely',  1.0, 1.0)
  )->as_discriminator();

  # tell us how orangy our orange is, and how appley our apple is
  print $hedges->best($fruitbycolor)->type();

  $outputset = $hedges & $green; # how green is green?
  print $outputset->type(); # outputs one of: not, slightly, notvery, kindof, ...

REFERENCES

DCU, ... Introduction to Logic: Predicate Logic, Howard Pospesel, Prentice-Hall, Inc. 0-13-486225-2

SEE ALSO

http://perldesignpatterns.com/?FuzzyLogic was notes from a series of Perl Mongers presentations, and should serve a good forum/feedback area/list of resources/whatever. Examples include a Fuzzy control system and a Fuzzy classification system. AI::FuzzyInference and AI::Fuzzy appear to better supported and more mature modules.

BUGS

A huge number of fuzzy set operations have been defined at different points by different people. Only a small subset of those have been included here.

No effort is made to build lookup tables to increase performance. Subsets could also be coerced into standard sizes for speed, but aren't.

Combinational behavior has no counterpart in formal Fuzzy Logic and is difficult to explain.

When one FuzzyLogic object is passed to the constructor and made part of another, a reference is shared. This creates action-at-a-distance problems as mutators applied to one (like balance()) affect the other as well. A copy should be made in this case.

Subsets are objects - AI::FuzzyLogic::Subset or AI::FuzzyLogic::MetaSubset. MetaSubets are currently undocumented, but allow users to attach additional data to subsets for her own use. The objects implement actual Fuzzy (Sub)Set storage as an array of scalars. This makes very poor use of memory. In the future, PDL or strings may be used. Don't rely on a per-segment dynamic range of more than 0-200 to represent 0.0 - 0.1. In other words, pretend that each element in a set is accurate to half of 1/100th of a unit. Use the accessors to fetch the data as an array, don't grab it directly.

smallest(), largest, best, and centroid don't work. Rather than filtering sets, they just mangled failing members. Also, they are named badly.

Can't remember what library book had the DCU system. I just took a lot of notes and never even checked the book out. Also, some references to other resources are missing from the documentation.

The system isn't faithful about maintaining the exact subclass when operations are done on subsets. The package name is hardcoded in numerous places, when it should be taken from any existing object.

No unit tests. Sorry. I tested with demo applications. I'll have to mine those for tests. No tests exists for things I don't use. Some operators may not work at all.

This is an alpha "I've been sitting on the code for too long and it is time to release it as it is because it is all I'm going to do without some feedback, or encouragement" release.

Should be possible to ->clone() sets and subsets.

Implementation notes follow after this POD in the source code to this module.

EXPORT

Wussat? Why not an INHERIT section? C'mon, get with the times, Perl people!

AUTHOR

Scott Walters, scott@slowass.net, based on Math::BigInt, DCU, ... Math::BigInt was written by Mark Biggar, overloaded interface by Ilya Zakharevich. Ilya's example code was heavily relied upon. Thanks to Phoenix Perl Mongers for thier feedback (silenced awe and awkward confused sidelong glances).