NEW:

# Section 5 - Appendices

### Fuzzy Boolean Operators

//    Fuzzy operators

double Or(double x, double y)

{     if (x>y) return x; else return y;   }     // MAX

double And(double x, double y)

{     if (x>y) return y; else return x;   }     // MIN

double Not(double x)

{     return (1-x);     }

They can also be written as macros using the #define statement.

## Appendix 2

### Associating a Fuzzy Set to a Variable

{

if (FS != NULL) return -1;

m_nNumStates = fs.NumStates();

m_bIsInput = bIsInput;

FS = new CFuzzySet(m_nNumStates);

if (FS == 0) return -2;

FS->SetFSname(fs.GetFSName());      // copy FS name

CFLMembershipFunction * pMFo = fs.FuzzyStateArray();

CFLMembershipFunction * pMFd = FS->FuzzyStateArray();

// Fuzzy Sets are made of MFs, which do not have a Premise number

// defined until they are associated to a variable

// which is going to be done now

for (int i=0;i<m_nNumStates;i++)

{     // premises are numbered sequentially in order to suit

// the original rule set

pMFd[i].SetPremiseNumber(m_nNumStates *(m_nVarNumber-1)+ i+1);

pMFd[i].ResetDOM();

_MFshape s = pMFo[i].MFshape();

pMFd[i].SetMFshape(s);

}

m_bHasFS = TRUE;

return 0;

}

The important aspect to keep in mind here is that variable will keep their premise numbering determined by Variable Number and the number of Fuzzy States.

It is not a requirement per se, but if new premise numbers are created the Rule Set would also have to be always regenerated since reference to previous premise number would be obsolete.

## Appendix 3

### Calculating DOM (Degree of Membership)

It is very easy to calculate DOM (Degree of Membership) for a variable of value x in a particular Fuzzy State, using the following functions applicable to triangular shapes:

double ShoulderLeft(double x, double t1, double t2) ‘ /-

{

if (t1==t2) return 0.0;

if (x<=t1)  return 0.0;

if (x>=t2)  return 1.0;

return ((x-t1)/(t2-t1));

}

double ShoulderRight(double x, double t1, double t2) ‘ -\

{

if (t1==t2) return 0.0;

if (x<=t1)  return 1.0;

if (x>=t2)  return 0.0;

return ((x-t2)/(t1-t2));

}

double Triangle(double x, double t1, double t2) ‘ /\

{

if (x<=t1)  return 0.0;

if (x>=t2)  return 0.0;

if (x<=(t1+t2)/2) return ShoulderLeft(x,t1,(t1+t2)/2);

else              return ShoulderRight(x,(t1+t2)/2,t2);

}

double Triangle(double x, double t1, double t2, double center)

{

if (x<=t1)  return 0.0;

if (x>=t2)  return 0.0;

if (x<=center)    return ShoulderLeft(x,t1,center);

else              return ShoulderRight(x,center,t2);

}

These functions do not require the value x to be normalised, but it is a recommended convention nonetheless.  Please note that the centre used in the Triangle functions is the actual x-coordinate for the triangle peak (DOM = 1).

Example:

pFSet is the same pointer to the Fuzzy Set array as described above.

First, we create an empty shape.

_MFshape s;

s.Reset();

We can then retrieve a pointer to the Fuzzy State array.

CFLMembershipFunction *MF0 = pFSet[0].FuzzyStateArray();

The implementation code is a tutorial on how to use the FLC classes.  One should of course check the boundaries of that array.  MF0 can only contain 3 elements, for the 3 possible states, as defined.

// Set 1st Fuzzy Set

s.nType = 0; // ShoulderRight -\    "Neg" Center set to -1 (min)

s.dPoint1 = -0.5;

s.dPoint2 = 0;

s.dCenter = -1;

s.strName = "FS1-Neg";

MF0[0].SetMFshape(s);

s.nType = 1; // Triangle /\ "Null" Center = triangle center = 0

s.dPoint1 = -0.5;

s.dPoint2 = 0.5;

s.dCenter = 0.0;

s.strName = "FS1-Null";

MF0[1].SetMFshape(s);

s.nType = 2; // ShoulderLeft /- "Positive" Center set to +1 (max)

s.dPoint1 = 0.0;

s.dPoint2 = 0.5;

s.dCenter = 1;

s.strName = "FS1-Pos";

MF0[2].SetMFshape(s);

Again, such simple shape description will easily allow for optimisations wit Genetic Algorithms.  You will however notice that shouldered shapes do need to have their “dCenter” at the boundary of the range i.e. -1 or +1.  This is required in order to be able to get crisp values out of the FLC when needed.

## Appendix 4

The dialog implementation includes a function:

Each rule is defined internally using the following format:

ret = rs[0].SetPremise(0,1);// 1st variable (0) is "Negative" (1)

if (ret!=0) return -1;

ret = rs[0].SetBoolOp(0,AND); // AND

if (ret!=0) return -1;

ret = rs[0].SetPremise(1,4);  // 2nd variable is "Negative"

if (ret!=0) return -1;

ret = rs[0].SetBoolOp(1,NOTHING);

if (ret!=0) return -1;

rs[i].SetConsequent(7);       // Output is "Negative"

*rs being the Rule Set array, rs[0] is the first rule being defined above. The function SetPremise defines each premise in each rule. Here, the 1st premise (premise 0) is Premise No1, and the 2nd premise (premise 1) is Premise No4.  The Boolean operator is an AND.  The fuzzy AND operator is a Min using the common Min-Max convention.

The above rule is equivalent to:

IF Premise1 AND Premise4 THEN “Premise7”

Technically a consequent is not a premise, but this is a design shortcut taken to keep the overall FL model compact.  In the FL literature, Premise1 and Premise4 are antecedents.

In the dialog application, the default implementation is:

Premise1 is:     Var_0 IS Negative

Premise4 is:     Var_1 IS Negative

And the consequent (“Premise7”) is:  Output IS Negative

## Appendix 5 – Fuzzy Calculations

Again, one has to verify that components are loaded.

if (!FLC->boolFS())     return 0.00;

if (!FLC->boolVS())     return 0.00;

In this case, the fuzzy output is set to 0 if the FLC setup is not complete.  It may not be appropriate in some cases. Other conventions are possible.  For instance, as the fuzzy output ranges from -1 to +1, the error return value could be -2.

At this stage, all premises can be calculated, even if the Rule Set is not yet available.

CFLVariable * pVars = FLC->VarArray();

pVars[0].CalcPremises(Value1);

pVars[1].CalcPremises(Value2);

Each DOM for each Fuzzy State is now calculated for both inputs.

A Rule Set is now needed to evaluate all predicates.  This simple FLC model actually makes these calculations relatively straightforward.

We have seen that all premises are numbered, that all DOMs are calculated, and that the Rule Set is formatted in such a way that rule premises are indexed with premise numbers.

As seen earlier, Rules are interpreted as follows:

IF Premise1 AND Premise4 THEN “Premise7”

Now, that DOM is known for both input premises, one just has to apply a Fuzzy Boolean AND to them.  This is done in the following code snippet:

double *PredicateValue = new double[NumRules]; // 9 rules

int   *Consequent = new int[NumRules];

int np = FLC->RuleArray()->NumPremises(); // 2 input premises

int nv = FLC->GetNumVars();

double *RuleEstimate = new double[np];

for (int i=0 ; i<NumRules ; i++)

{

for (int n=0 ; n<np ; n++)

{

int *pP = pFLR[i].pPremise();

RuleEstimate[n] = 0.0;

for (int v=0 ; v<nv ; v++)

{

CFLMembershipFunction * pMF =

pVars[v].FuzzySet()->FuzzyStateArray();

if (pVars[v].IsInput())

for (int k=0 ; k<pVars[v].NumStates() ; k++)

if (pP[n] == pMF[k].PremiseNumber())

RuleEstimate[n] = pMF[k].GetDOM();

}

}

In this 1st part of the code, rules are scanned one by one.  For each rule, we scan variables (inputs only) to retrieve the DOM using the premise number.  The RuleEstimate array stores each and every DOM on which we can now apply the fuzzy Boolean indicator.

double value = 0.0;

for (int p=0 ; p<np ; p++)

{

int o = pFLR[i].Operation(p);

switch (o)

{

case AND:

value += And(RuleEstimate[p],RuleEstimate[p+1]);

break;

case OR:

value += Or(RuleEstimate[p],RuleEstimate[p+1]);

break;

case NOT:

value += Not(RuleEstimate[p]);

break;

case NOTHING:

// Do nothing

// End predicate evaluation

default:

;

}

}

PredicateValue[i] = value;

Consequent[i] = pFLR[i].RuleConsequent(); // will be used for defuzz

}

delete [] RuleEstimate; // no longer needed

RuleEstimate = NULL;

The rule predicates are now all known.

Please note that this design allows for more than 2 inputs, but this type of coding implies than premises are logically assessed sequentially.

### Calculating the Output Strength

It is now possible to calculate the output strength by scanning the Rule Set and analysing which rules contribute to each fuzzy state.  At the same time, we “defuzzify” the Output.

The method here used is the Fuzzy Centroid (also called Root-Sum-Squares), which is one of the most balanced method.  For more information, please check the Background Reading section at the beginning of this document.

int OutVarNo = FLC->GetNumVars() -1;      //  = 2

int NumOutputStates = pVars[OutVarNo].FuzzySet()->NumStates();

// After inferencing:

// OutputStrength stores the "strength" in each output fuzzy state.

double *OutputStrength = new double[NumOutputStates];

for (int i=0;i<NumOutputStates;i++) OutputStrength[i] = 0.0;

// pVars[2] is the output in this example

// Premises have been numbered incrementally

int FirstOutputState =

pVars[OutVarNo].FuzzySet()->

FuzzyStateElt(0).PremiseNumber();

int LastOutputState =

pVars[OutVarNo].FuzzySet()->

FuzzyStateElt(NumOutputStates-1).PremiseNumber();

double denom_out = 0.0;

for (int i=FirstOutputState;i<=LastOutputState;i++)

{     // Scanning through rule set to evaluate OutputStrength

//for each output fuzzy state

double sumsq = 0.0;

for (int j=0;j<NumRules;j++)

if (Consequent[j] == i) // Sum squares

sumsq += PredicateValue[j] * PredicateValue[j];

int k = i-FirstOutputState;

OutputStrength[k] = sqrt(sumsq);

denom_out += OutputStrength[k];     // root-sum-squares

}

In the above code snippet, one first retrieves the variable index for the output variable (2), then we just have to scan rules again to extract how each contributes to a particular fuzzy state for the Output variable.

At the same time, we prepare for the Fuzzy Centroid calculation by computing the Root-Sum-Squares.

Now, we only have to calculate the crisp value for the output:

// Calculate the Fuzzy Centroid of the area (cf tutorial for details)

double num_out = 0.0;

for (int i=0;i<NumOutputStates;i++)

{

double dCenter;

dCenter = pVars[2].FuzzySet()->FuzzyStateElt(i).GetShapeCenter();

num_out += dCenter * OutputStrength[i];

}

if (denom_out == 0.0)   OutputValue = 0.0;

else                    OutputValue = num_out / denom_out;

This is where the dCenter comes into play for each Output state.  This guarantees that a FLC can also compute crisp logic.

The rest of the code is the usual garbage collection…

 Best viewed with MS Internet Explorer 5 and above