Simple Example using Java
Code
The Rule Executors and Other Things to Consider
Graphical Explanation of Rule Firing
Detailed Example
Multiple Antecedents in a Rule
Other Rule Types and Inferencing
Methods (Kosko’s SAM, Takagi-Sugeno-Kang,
Tsukamoto)
Jess Integration
A FuzzyRule holds three sets of FuzzyValues representing the antecedents, conclusions and input values of a fuzzy rule. A rule might be written as follows:
if antecedent1 and
antecedent2 and
...
antecedentn
then
conclusion1 and
conclusion2 and
...
conclusionm
The antecedents are the premises of the rule that must be true before the conclusions of the rule can be asserted. By attaching a set of fuzzy value inputs to the rule that correspond to actual values for the antecedents, a set of actual conclusions can be determined by executing (firing) the rule, using the FuzzyRuleExecutor that is associated with the rule. The executor will generally implement one of the common algorithms for fuzzy inferencing [Tsoukalas and Uhrig] such as the Mamdani min inference operator with the Max-Min composition operator.
Note that this allows only very simple (but still very useful) rules that have only fuzzy values on the left hand side (antecedents) and right hand side (conclusions). The FuzzyJ Toolkit is integrated with the Jess expert system shell and provides the ability to create much more complex rules, combining crisp and fuzzy values.
A very simple example of Java code that implements a rule and its firing follows. In English-like syntax the rule being implemented can be written as:
if temperature is
hot
then pressure is low or medium
Then by providing an input value for the temperature, in this case temperature is very medium, the rule can be fired and a conclusion is provided as the output of the rule firing. Note that this example is also coded in Jess using no Java code in the section on FuzzyJess.
In order to create a rule that can be executed (fired) we need to create an instance of a FuzzyRule and then add the FuzzyValues that make up the antecedents, the conclusions and the inputs. In order to create the appropriate FuzzyValues for the rule we need to create the FuzzyVariables for the concepts we are using (temperature and pressure).
//
some values used to describe the fuzzy terms in the temperature FuzzyVariable
double xHot[] =
{25, 35};
double yHot[] =
{0, 1};
double xCold[] =
{5, 15};
double yCold[] =
{1, 0};
// define our
temperature FuzzyVariable with terms hot,
// cold, very
hot and medium
FuzzyVariable temp
= new FuzzyVariable("temperature", 0, 100, "C");
temp.addTerm("hot",
xHot, yHot, 2);
temp.addTerm("cold",
xCold, yCold, 2);
temp.addTerm("veryHot",
"very hot");
temp.addTerm("medium",
"(not hot and (not cold))");
// define our
pressure FuzzyVariable with terms low, medium and high
FuzzyVariable
pressure = new FuzzyVariable("pressure", 0, 10,
"kilo-pascals");
pressure.addTerm("low",
new ZFuzzySet(2.0, 5.0));
pressure.addTerm("medium",
new PIFuzzySet(5.0, 2.5));
pressure.addTerm("high",
new SFuzzySet(5.0, 8.0));
// let's build
a rule ---
FuzzyRule rule1 =
new FuzzyRule();
FuzzyValue
antecedentFval = new FuzzyValue(temp, "hot");
FuzzyValue
conclusionFval = new FuzzyValue(pressure, "low or medium");
FuzzyValue
inputFval = new FuzzyValue(temp, "very medium");
rule1.addAntecedent(antecedentFval);
rule1.addConclusion(conclusionFval);
rule1.addInput(inputFval);
// execute this
simple rule with a single antecedent and
// a single
consequent using default rule executor --
//
MamdaniMinMaxMinRuleExecutor
FuzzyValueVector
fvv = rule1.execute();
// show the
results using the plotting methods for FuzzyValues
FuzzyValue fvals[]
= new FuzzyValue[2];
fvals[0] =
antecedentFval;
fvals[1] =
inputFval;
System.out.println(FuzzyValue.plotFuzzyValues("*+",
0, 50, fvals));
System.out.println(fval2.plotFuzzyValue("*",
0, 10));
System.out.println(fvv.fuzzyValueAt(0).plotFuzzyValue("*",
0, 10));
// execute
again with a different rule executor --
//
LarsenProductMaxMinRuleExecutor
fvv =
rule1.execute(new LarsenProductMaxMinRuleExecutor());
// and show
results
System.out.println(fvv.fuzzyValueAt(0).plotFuzzyValue("*",
0, 10));
The above would produce the following graphs as output:
The Antecedent (hot) and the input (very medium) fuzzy values
Fuzzy Value: temperature
Linguistic Value:
hot (*), very medium (+)
1.00
+++++++++++ ****************
0.95
0.90
*
0.85
0.80
+
+ *
0.75
0.70
*
0.65
+ +
0.60
*
0.55
0.50
+
+ *
0.45
0.40
*
0.35
+
+
0.30
*
0.25
+
+
0.20
*
0.15
+
+
0.10
+
* +
0.05
+
+
0.00+++++++*******************
+++++++++++++++++
|----|----|----|----|----|----|----|----|----|----|
0.00 10.00
20.00 30.00
40.00 50.00
The conclusion fuzzy value.
Fuzzy Value: pressure
Linguistic Value:
low or medium (*)
1.00************
***
0.95
* * *
0.90
* * *
0.85
*
0.80
* *
0.75
*
0.70
*
0.65
* *
0.60
0.55
* * *
0.50
0.45
*
0.40
* *
0.35
0.30
0.25
*
0.20
0.15
*
0.10
*
0.05
*
0.00
**************
|----|----|----|----|----|----|----|----|----|----|
0.00 2.00
4.00 6.00
8.00 10.00
The output using MamdaniMinMaxMinRuleExecutor
Fuzzy Value: pressure
Linguistic Value:
??? (*)
1.00
0.95
0.90
0.85
0.80
0.75
0.70
0.65
0.60
0.55
0.50
0.45
0.40*********************************
0.35
0.30
0.25
*
0.20
0.15
*
0.10
*
0.05
*
0.00
**************
|----|----|----|----|----|----|----|----|----|----|
0.00 2.00
4.00 6.00
8.00 10.00
The conclusion using LarsenProductMaxMinRuleExecutor.
Fuzzy Value: pressure
Linguistic Value:
??? (*)
1.00
0.95
0.90
0.85
0.80
0.75
0.70
0.65
0.60
0.55
0.50
0.45
0.40************
*
0.35
*** *** ***
0.30
* * *
0.25
* * *
0.20
* * *
0.15
** *
0.10
*
0.05
**
0.00
***************
|----|----|----|----|----|----|----|----|----|----|
0.00 2.00
4.00 6.00
8.00 10.00
There are a lot of methods that allow the antecedents, conclusions and inputs to be added, removed, and accessed more precisely than is shown by methods such as the addAntecedent method in the example above. The details can be checked in the Fuzzy Java Toolkit API documentation and by browsing other examples. However, let's look a bit more closely at some things that must be considered before executing rules.
First, in the example above we just went ahead and executed the rule after the inputs had been added to the rule. In this case everything works fine because we know (by the construction of the antecedent and the input) that in fact there is some matching (overlap) of the input and the antecedent fuzzy values. This means that the output will have a non-empty fuzzy value. However, had the input not matched the antecedent, the resulting output would have been an empty fuzzy value (i.e. the fuzzy set would have had zero values everywhere). A simple solution here is to execute the rule only when the method testRuleMatching returns true. In the above example we would have done:
if
(rule1.testRuleMatching())
{
FuzzyValueVector fvv = rule1.execute();
...
}
This also in general saves a lot of unnecessary time executing a rule when it will not yield a result. This is especially true for rules that have many antecedents. In a rule based system (like Jess with the Fuzzy extensions), this will be taken care of in the pattern matching of the antecedents as inputs are asserted into the system. It is also possible to control the degree of matching of the inputs and antecedents required to return a true from the testRuleMatching method. Normally any matching will result in a true value since the threshold value is defaulted to 0.0. One can change the threshold by calling the method testRuleMatching with an argument between 0 and 1. Suppose we use the value 0.1. Then the result is true only if the matching (overlap) of all of the corresponding inputs and antecedents is > 0.1. That is each pair of values must have an intersection with maximum value > 0.1. The default value for matching can also be controlled by calling the static FuzzyValue method, setMatchThreshold.
Secondly, if there are many rules that affect the same output variable (this is common in many applications), then it is often useful to merge the output variable of all of these rules into a single one. This is known as global contribution. A common strategy is to perform the union of all of the results from all of the rules using a fuzzy union. Then after all of the rules have fired we have the global effect of the contribution of each rule to an answer. The result is often then defuzzified to provide a crisp value to feed back to the system being controlled. The fuzzy shower problem provided as an example with the FuzzyJ Toolkit (and presented on the FuzzyJ web pages) is an example of this complete process. Note that in the FuzzyJess extensions, this global contribution is done for the user automatically as part of the rule's execution (when facts with fuzzy slots are asserted). As of Version 1.5 of FuzzyJ/FuzzyJess there is a Jess function set-fuzzy-global-contribution-operator that allows the user to control what operator (fuzzy union, fuzzy sum, none, etc.) is used to do this global contribution. In pure Java programs, the type of global contribution is easily controlled by performing the require operation in Java code. But previous to FuzzyJess 1.5 the global contribution was automatic and always a union operation. This provides the Jess programmer with the same flexibility and a way to extend the operators that can be used if required.
So the steps often used in many applications are:
Each rule has associated with it a FuzzyRuleExecutor. These FuzzyRuleExecutors are classes that implement the FuzzyRuleExecutorInterface and the Cloneable interface, so they must supply execute and clone methods. These execute methods are called when the FuzzyRule execute method is called. It is the FuzzyRuleExecutor's execute method that performs the magic of rule firing and produces the fuzzy outputs. There are many ways to perform this set of calculations. Currently three system defined FuzzyRuleExecutors are supplied, the MamdaniMinMaxMinRuleExecutor the LarsenProductMaxMinRuleExecutor and the TsukamotoRuleExecutor. These correspond using the Mamdani Min inference operator with MaxMin composition, the Larsen Product inference operator with MaxMin composition respectively and a special rule execution defined by Tsukamoto (details later in this text and in the New Features, Changes and Helpful Hints of the FuzzyJ User Guide). This is covered in detail in [Tsoukalas and Uhrig]. Other combinations may be implemented in the future but they do not lend themselves to such a simple and efficient implementation as these do due to some special characteristics. The first two are also the most commonly used approaches.
When a FuzzyRule is constructed, it will either be given a default rule
executor (this can be controlled by the user, see method setDefaultRuleExecutor
of the FuzzyRule class) or a specific rule executor is supplied to the
constructor. Because the rule executors may want to store state from invocation
to invocation, each FuzzyRule is given its own instance of the executor. This
assists the executor in providing an efficient implementation. This is also the
reason that FuzzyRuleExecutors must implement the Cloneable interface.
Below is a graphical look at how the 2 system supplied executors operate using a simple fuzzy rule.
The diagrams depict the rule:
If temperature is hot then turn thermostat down a lot, with the input temperature is warm.
Fist we’ll look at the MamdaniMinMaxMinRuleExecutor. The effect of this type of inference is to generate an output fuzzy value that is the conclusion fuzzy value clipped at the maximum value of the intersection of the antecedent fuzzy value and the input fuzzy value.
The next graphic depicts the use of the LarsenProductMaxMinRuleExecutor. This is similar to the previous method, except that the output is scaled by the maximum intersection value rather than being clipped.
Next is an example of the firing of 2 rules and the effect of globally combining the outputs of the two rules (using the default MamdaniMinMaxMinRuleExecutor and the default fuzzy union operation to combine the output of the 2 rules). The rules are:
If
temperature is hot then turn thermostat down a lot.
If temperature is cool then turn
thermostat up a little
with the input temperature is warm.
Notice that in this case the outputs from each rule firing are combined using a fuzzy union operator. The graphic also depicts the value of the crisp output of the result if the output fuzzy value was defuzzified using the momentDefuzzify method.
A partial listing of key parts of the Fuzzy Compiler example that is included with the FuzzyJ Toolkit are shown below. It shows the steps outlined above in some detail with a slightly more complex set of rules.
In this example we have 2 antecedent fuzzy variables and 1 conclusion fuzzy variable. They are:
Antecedent Fuzzy Variables
temperature 0 100 degrees
C pressure 0 500 kPa
terms: low, medium,
high
terms: low, medium, high
Conclusion Fuzzy Variable
throttle 0 1 units
terms: verylow, low, midlow, medium,
midhigh, high
The 9 rules can be written as:
if temperature is low |
if temperature is low |
if temperature is low |
if temperature is medium |
if temperature is medium |
if temperature is medium |
if temperature is high |
if temperature is high |
if temperature is high |
The partial code: (note that the rules could have been put into an array for efficiency but for readability this is better; in fact in the example shipped with version 1.5 or later of the FuzzyJ Toolkit some of the code was rewritten to use an array of rules; it is suggested that the new code be looked at as well)
// define the FuzzyRules and Fuzzy Variables we will use
FuzzyRule lowTempLowPressure = new FuzzyRule();
FuzzyRule lowTempMediumPressure = new FuzzyRule();
FuzzyRule lowTempHighPressure = new FuzzyRule();
FuzzyRule mediumTempLowPressure = new FuzzyRule();
FuzzyRule mediumTempMediumPressure = new FuzzyRule();
FuzzyRule mediumTempHighPressure = new FuzzyRule();
FuzzyRule highTempLowPressure = new FuzzyRule();
FuzzyRule highTempMediumPressure = new FuzzyRule();
FuzzyRule highTempHighPressure = new FuzzyRule();
FuzzyVariable temperature;
FuzzyVariable pressure;
FuzzyVariable throttle;
// define temperature variable with its terms
temperature = new FuzzyVariable("temperature", 0.0, 100.0,
"Degrees C");
temperature.addTerm("low", new PIFuzzySet(20, 20));
temperature.addTerm("medium", new PIFuzzySet(50, 20));
temperature.addTerm("high", new PIFuzzySet(80, 20));
// define pressure variable with its terms
pressure = new FuzzyVariable("pressure", 0.0, 500.0,
"kPa");
pressure.addTerm("low", new PIFuzzySet(100, 100));
pressure.addTerm("medium", new PIFuzzySet(250, 100));
pressure.addTerm("high", new PIFuzzySet(400, 100));
// define the throttle fuzzy variable with its terms
throttle = new FuzzyVariable("throttle", 0.0, 1.0,
"units");
throttle.addTerm("verylow", new PIFuzzySet(.1, .1));
throttle.addTerm("low", new PIFuzzySet(.25, .15));
throttle.addTerm("midlow", new PIFuzzySet(.4, .1));
throttle.addTerm("medium", new PIFuzzySet(.55, .15));
throttle.addTerm("midhigh", new PIFuzzySet(.75, .1));
throttle.addTerm("high", new PIFuzzySet(.9, .1));
// define the 9 rules
lowTempLowPressure.addAntecedent(new FuzzyValue(temperature,"low"));
lowTempLowPressure.addAntecedent(new FuzzyValue(pressure,"low"));
lowTempLowPressure.addConclusion(new FuzzyValue(throttle,"high"));
lowTempMediumPressure.addAntecedent(new
FuzzyValue(temperature,"low"));
lowTempMediumPressure.addAntecedent(new
FuzzyValue(pressure,"medium"));
lowTempMediumPressure.addConclusion(new
FuzzyValue(throttle,"medium"));
lowTempHighPressure.addAntecedent(new FuzzyValue(temperature,"low"));
lowTempHighPressure.addAntecedent(new FuzzyValue(pressure,"high"));
lowTempHighPressure.addConclusion(new FuzzyValue(throttle,"midlow"));
mediumTempLowPressure.addAntecedent(new
FuzzyValue(temperature,"medium"));
mediumTempLowPressure.addAntecedent(new FuzzyValue(pressure,"low"));
mediumTempLowPressure.addConclusion(new
FuzzyValue(throttle,"midhigh"));
mediumTempMediumPressure.addAntecedent(new
FuzzyValue(temperature,"medium"));
mediumTempMediumPressure.addAntecedent(new
FuzzyValue(pressure,"medium"));
mediumTempMediumPressure.addConclusion(new
FuzzyValue(throttle,"midlow"));
mediumTempHighPressure.addAntecedent(new
FuzzyValue(temperature,"medium"));
mediumTempHighPressure.addAntecedent(new
FuzzyValue(pressure,"high"));
mediumTempHighPressure.addConclusion(new FuzzyValue(throttle,"low"));
highTempLowPressure.addAntecedent(new FuzzyValue(temperature,"high"));
highTempLowPressure.addAntecedent(new FuzzyValue(pressure,"low"));
highTempLowPressure.addConclusion(new FuzzyValue(throttle,"midlow"));
highTempMediumPressure.addAntecedent(new
FuzzyValue(temperature,"high"));
highTempMediumPressure.addAntecedent(new
FuzzyValue(pressure,"medium"));
highTempMediumPressure.addConclusion(new FuzzyValue(throttle,"low"));
highTempHighPressure.addAntecedent(new
FuzzyValue(temperature,"high"));
highTempHighPressure.addAntecedent(new FuzzyValue(pressure,"high"));
highTempHighPressure.addConclusion(new
FuzzyValue(throttle,"verylow"));
// fire the rules for values of temp from 5 to 95 (increments of 5)
// and of pressure from 10 to 490, storing the results of the rule firings
// (i.e. the de-fuzzified result of the combination of all rules) in a
// 2D array.
for (i=0; i<19; i++)
{ for (j=0; j<49; j++)
{ try
{ // each iteration corresponds to collecting a set of inputs
// could have done this below more efficiently (codewise) but ...
// ie. use an array of rules rather than specific named rules
double temp = i*5+5; // temperature crisp input
double press = j*10+10; // pressure crisp input
globalOutput = null; // global contribution of outputs of
each rule
// Fuzzify the crisp inputs as fuzzy values
FuzzyValue tempFv = new FuzzyValue(this.temperature,new PIFuzzySet(temp, 0.5));
FuzzyValue pressFv = new FuzzyValue(this.pressure,new PIFuzzySet(press, 0.5));
FuzzyValue fv;
// add inputs to rules and fire them and do global contribution
// Note: we use testRuleMatching
to
see if the rule really needed to fire
this.lowTempLowPressure.removeAllInputs(); // clear previous inputs if any
this.lowTempLowPressure.addInput(tempFv);
this.lowTempLowPressure.addInput(pressFv);
if (this.lowTempLowPressure.testRuleMatching())
{
fvv = lowTempLowPressure.execute(); // get output of the rule
globalOutput = fvv.fuzzyValueAt(0); // 1st rule ... it becomes global output
}
this.lowTempMediumPressure.removeAllInputs();
this.lowTempMediumPressure.addInput(tempFv);
this.lowTempMediumPressure.addInput(pressFv);
if (this.lowTempMediumPressure.testRuleMatching())
{
fvv = lowTempMediumPressure.execute(); // get output of the rule
fv =
fvv.fuzzyValueAt(0);
// not 1st rule so add to previous
if (globalOutput ==
null)
// global output
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
this.lowTempHighPressure.removeAllInputs();
this.lowTempHighPressure.addInput(tempFv);
this.lowTempHighPressure.addInput(pressFv);
if (this.lowTempHighPressure.testRuleMatching())
{
fvv = lowTempHighPressure.execute();
fv = fvv.fuzzyValueAt(0);
if (globalOutput == null)
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
this.mediumTempLowPressure.removeAllInputs();
this.mediumTempLowPressure.addInput(tempFv);
this.mediumTempLowPressure.addInput(pressFv);
if (this.mediumTempLowPressure.testRuleMatching())
{
fvv = mediumTempLowPressure.execute();
fv = fvv.fuzzyValueAt(0);
if (globalOutput == null)
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
this.mediumTempMediumPressure.removeAllInputs();
this.mediumTempMediumPressure.addInput(tempFv);
this.mediumTempMediumPressure.addInput(pressFv);
if (this.mediumTempMediumPressure.testRuleMatching())
{
fvv = mediumTempMediumPressure.execute();
fv = fvv.fuzzyValueAt(0);
if (globalOutput == null)
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
this.mediumTempHighPressure.removeAllInputs();
this.mediumTempHighPressure.addInput(tempFv);
this.mediumTempHighPressure.addInput(pressFv);
if (this.mediumTempHighPressure.testRuleMatching())
{
fvv = mediumTempHighPressure.execute();
fv = fvv.fuzzyValueAt(0);
if (globalOutput == null)
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
this.highTempLowPressure.removeAllInputs();
this.highTempLowPressure.addInput(tempFv);
this.highTempLowPressure.addInput(pressFv);
if (this.highTempLowPressure.testRuleMatching())
{
fvv = highTempLowPressure.execute();
fv = fvv.fuzzyValueAt(0);
if (globalOutput == null)
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
this.highTempMediumPressure.removeAllInputs();
this.highTempMediumPressure.addInput(tempFv);
this.highTempMediumPressure.addInput(pressFv);
if (this.highTempMediumPressure.testRuleMatching())
{
fvv = highTempMediumPressure.execute();
fv = fvv.fuzzyValueAt(0);
if (globalOutput == null)
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
this.highTempHighPressure.removeAllInputs();
this.highTempHighPressure.addInput(tempFv);
this.highTempHighPressure.addInput(pressFv);
if (this.highTempHighPressure.testRuleMatching())
{
fvv = highTempHighPressure.execute();
fv = fvv.fuzzyValueAt(0);
if (globalOutput == null)
globalOutput = fv;
else
globalOutput = globalOutput.fuzzyUnion(fv);
}
// defuzzify the final output (global) to get a crisp value
// ... in this case store it in an array
results[i][j] = globalOutput.momentDefuzzify();
}
catch (FuzzyException e)
{ System.out.println(e);
System.out.println("At "+i+","+j+" .../n"+
globalOutput);
}
}
}
In the last example there were two antecedents in the rule. Previous examples with one fuzzy antecedent showed that we used the match value (maximum value of the intersection of the antecedent and its input) to determine how to modify the output fuzzy values. For the MamdaniMinMaxMinRuleExecutor we clipped the output at this value and for the LarsenProductMaxMinRuleExecutor we scaled the outputs. However, when there are several match values due to multiple antecedents then we have to determine how these values should be combined to affect the output values. By default (and in all versions of FuzzyJ before 1.5), the combining operator was a minimum of the match values. As of version 1.5 an interface (AntecedentCombineOperatorInterface), an abstract class (AntecedentCombineOperator) and a couple of classes that extend the abstract class (MinimumAntecedentCombineOperator and ProductAntecedentCombineOperator) were added to allow us to easily control how these match values are combined. Each rule can determine it’s own combining operator and the default operator can be controlled as well (See the FuzzyRule class documentation in the FuzzyJ API). All of the Rule Executors use this information to decide how to manage multiple antecedents. In FuzzyJ version 1.5a a third combine operator was added (CompensatoryAndAntecedentCombineOperator). This is described in the API, but basically it provides an operator that gives a value larger than the minimum or product operators. For example, if you have three antecedents and two match at 1.0 and one at 0.1, then the CompensatoryAnd operator will give a value larger than 0.1 (it can be adjusted by a parameter setting).
The Fuzzy Compiler example shown above has been modified (in FuzzyJ Toolkit 1.5 and later) to allow the user to control the Rule Executor (as before), plus the Antecedent Combining Operator (minimum or product) and the operator to use when global contribution of output fuzzy values is done (fuzzy union or fuzzy sum). Take a look at the code of this example to see how these options can be controlled.
So we see that there are now quite a few options that control the execution
of rules: the Rule Executor, the Antecedent Combining Operator and the Global
Contribution Operator. In many cases the defaults (mandami, minimum, union) are
just fine. However, there are valid reasons to have a choice. In particular,
Bart Kosko, in his book Fuzzy Engineering (see
references section), clearly argues for a method called SAM (the Standard
Additive Model), which is implemented in FuzzyJ using the
MamdaniMinMaxMinRuleExecutor, the ProductAntecedentCombineOperator, the fuzzySum for Global Contribution
and the momentDefuzzify method.
We have discussed the
two most common rule inference procedures using MandaminiMinMaxMin or
LarsenProductMaxMin rule executors. However, there are two other commonly used
methods for creating and executing rules that can be implemented in FuzzyJ.
These are the Tsukamoto inference method and Takagi-Sugeno-Kang (TSK) type
rules.
Takagi-Sugeno-Kang rules have fuzzy inputs but they have specialized crisp outputs that are generally either constants (zero order TSK rules) or crisp outputs that are defined by a function that computes a crisp value (usually a function of the crisp values of the input variable). A description of how to implement these TSK rules in FuzzyJ/FuzzyJess is provided in the section New Features, Changes and Helpful Hints.
Tsukamoto rules use
consequents that are strictly increasing or strictly decreasing functions. When
a rule fires and the outputs are generated a crisp x value and a membership
value are recorded. The membership value is the DOF (Degree of Fulfillment or
degree of matching) of the rule. The x value is chosen by looking at the
consequent fuzzy set to see which x value has that membership value. The final output of all of the rules is the
weighted average of all the x values, using the membership values as the
weights. In FuzzyJ we have a special RuleExecutor, TsukamotoRuleExecutor, that
generates outputs that are singleton fuzzy values at the selected x value with
a membership value equal to the DOF of the rule. These output fuzzy values
should be combined using the fuzzySum method (rather than the default fuzzyUnion)
and then defuzzified using the weightedAverageDefuzzify method. This produces
the Tsukamoto inference results. In summary to implement Tsukamoto type rules:
1. Make sure the rules fuzzy outputs are defined using strictly
increasing or strictly decreasing functions that cover all of the membership
values from 0.0 to 1.0 (some example fuzzy sets that have this property are
SFuzzySet, ZFuzzySet, LeftLinearFuzzySet, and RightLineraFuzzySet.
2. Use the fuzzySum method as the rule output combine (global
contribution) operator.
3. Use the weightedAverageDefuzzify method to defuzzify the combined
output of the rules.
This is shown below for a simple 2-rule situation.
For details on building rules in Jess that have fuzzy components see the section on FuzzyJess.