A fuzzy logic C++ library

NAVIGATION
This page describes how rules are handled. Two types of rules are handled, see RULE and RULE_IDX. The first is for handling linguistic rules, while the second stores data in indexes, and is not supposed to be used directly. It is supposed to be generated automatically through learning.
The SLIFIS class contains a single RULE_BASE object, that is basically an STL vector of RULE_IDX. RULE objects will be anyway "translated" into RULE_IDX objects in the rule base when they are added to the FIS with function SLIFIS::AddRule( const RULE& rule ).
The linguistic rules can be created using the RULE class, and then added to the FIS, as in the following example. However, remember that since translation of linguistic terms into indexes are made at this point, The Fis must have its inputs and output defined before adding rules.
SLIFIS fis; // ... here, define inputs/output RULE r( OPR_AND ); // rule 1 : "if temperature is 'warm' and pressure is 'low', then output is 'bad'" r.AddCondition( "temperature", "Warm" ); r.AddCondition( "pressure", "Low" ); r.SetConsequence( "Bad" ); fis.AddRule( r ); // rule 2 : "if temperature is 'warm' and pressure is 'high', then output is 'not so bad'" r.ClearConditions(); r.AddCondition( "temperature", "Warm" ); r.AddCondition( "pressure", "High" ); r.SetConsequence( "Not So Bad" ); fis.AddRule( r ); ...
Please note usage of RULE::ClearConditions() for clearing the antecedent part of the rule before adding a new one.
These lines could also have been written in the following way:
// rule 1 : "if temperature is 'warm' and pressure is 'low', then output is 'bad'" RULE r1( OPR_AND, "Bad" ); r1.AddCondition( "temperature", "Warm" ); r1.AddCondition( "pressure", "Low" ); fis.AddRule( r1 ); // rule 2 : "if temperature is 'warm' and pressure is 'high', then output is 'not so bad'" RULE r2( OPR_AND, "Not so bad" ); r2.AddCondition( "temperature", "Warm" ); r2.AddCondition( "pressure", "High" ); fis.AddRule( r ); ...
A rule can have an (theorically...) unlimited number of terms, and a minimum of one term is required. And a FIS can have an (also theorically...) unlimited number of rules.
PLease note that to add a rule to the FIS, the input and output sets of functions must have been defined. This is because internally, when adding a rule, it is converted to a RULE_IDX object holding indexes on membership function. So if there are no functions defined in the set, this conversion fails...
Of course, the linguistic output terms must correspond to the ones that have been given to the output set of functions:
fs_out.AddMf( MEMBFUNC( MF_HL, "Bad", 10, 20 ) ); fs_out.AddMf( MEMBFUNC( MF_LH, "Not So Bad", 40, 70 ) ); fs_out.AddMf( MEMBFUNC( MF_LL, "Ok", 20, 40, 50, 60 ) );
Please note that an output set of membership function must only contain functions that are finite, or else it will be impossible to obtain a defuzzyfied value.
The class RULE_IDX holds terms and associated values as numerical indexes. Therefore, it is not designed to be edited by humans. Objects of this type are created either by learning a rule base through data (see page Learning rules from data), either when adding linguistic rules to a rule base: then, the rules are automatically translated into objects of type RULE_IDX.
Each rule can be either of Mamdani" type or "TakagiSugeno" (TS) type. This is defined at object construction, by passing the appropriate value:
RULE r1( TYPE_MAMDANI ); RULE r2( TYPE_SUGENO ); RULE r3; // Default is "Mamdani"
For TS rules, you can manually specify the coefficients, for example:
RULE r( TYPE_SUGENO ); r.SetTSConstCoeff( 2.0 ); r.SetTSCoeff( 0, 1.5 ); r.SetTSCoeff( 1, 3.0 ); r.SetTSCoeff( 2, 4.0 );
This rule will be suitable for a 3input FIS, and in case it is triggered (notice we omitted here to specify premisses), then the output value will be:
Of course, usually, these coefficients are not assigned manually but computed through fitting from a data set (see Learning rules from data).
The class RULE_BASE holds the set of rules, stored as an stl::vector of RULE_IDX. The rule can be added one by one:
SLIFIS fis; ... add inputs and output sets of membership functions RULE r1; ... describe rule fis.AddRule( r1 );
Please note that to do this, sets of functions MUST be assigned to Fis, because this code actually translates the RULE object into a RULE_IDX object, and this can be done only if the input and output set of functions are defined. Similarly, if you add a function to an input for example, you will probably need to redefine the set of rules, as they might become meaningful.
You can get a reference on the rule base of a Fis with SLIFIS::GetRuleBase(), and print it with the following code:
SLIFIS fis; ... RULE_BASE& rb = fis.GetRuleBase(); rb.Print( stdout );
The prints the rules using the inputs and output names:
 Rule base :   Nb of rules: 3  Avg degree=1.000, Min=1.000 Max=1.000 # : 1 : IF service IS poor OR food IS rancid THEN tip IS cheap (degree=1.000) 2 : IF service IS good THEN tip IS average (degree=1.000) 3 : IF service IS excellent OR food IS delicious THEN tip IS generous (degree=1.000) 
However, it is suitable only for rulebases that have a link with a corresponding Fis (such as in the given example). If you have an "independent" rule base, that is, one that has no link with a Fis, then you can only get the indexes values. To print it that way, add 'true' as third argument of RULE_BASE::Print() :
rb.Print( stdout, "tipping", true );
This produces the following output:

Rule base : tipping

 Has 3 rules
 Has been reduced : false
 Nb of input vectors left aside (unable to find adequate functions) : 0
 Nb of rules needed to be complete : 6
 Avg degree=1.000, Min=1.000 Max=1.000
in(0) in(1) output
# :Terms: [02] [01] [02]
1 : 2 : IF 0 OR 0 THEN 0 (1.000)
2 : 1 : IF 1 THEN 1 (1.000)
3 : 2 : IF 2 OR 1 THEN 2 (1.000)

Finally, this rule base can be plotted using the associated graphical library (see Slifis Graphical API for plotting):