Section 5 - Appendices
|
Home
NEW:
US Markets Daily |
Section 5 - AppendicesFuzzy 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 2Associating a Fuzzy Set to a Variableint CFLVariable::LoadFuzzySet(CFuzzySet &fs, BOOL bIsInput) { 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 3Calculating 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 4The 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 CalculationsAgain, 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 StrengthIt 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… |
Page last modified:
May 08, 2008 |