To understand fuzzy logic, let us take a very simple example.

Imagine a simple light bulb which has two states: light on and light off.

We can mark the light off as false, and light on as true. This would be simple system that has two states and is described with George Boole’s logic. In his honor we have bool data type in C++.

Next, imagine that the simple light bulb could also be dimmed.

The light switch could be rotated and it has the ability to change the states between true and false. To describe this you will have a function with range of results from 0 to 1.

This light could be dimmed so that you have the possibility to change the amount of light.

Next, we could define a function: When the light is turned off the value of function would be 0. When the light is turned off the value of the function would be 1. For all states in between 0 and 1, we would have different values described with double data type that are bigger than zero and smaller than one.

The above is just a very simplified example of a basic fuzzy system.

The following are few more cases of fuzzy systems:

- A glass filed with some liquid (empty and full)
- A Train in a tunnel (it is out of the tunnel, it is partially in the tunnel, and it is fully in the tunnel)
- Oil price (the price is low, the price is moderate, and the price is high)
- Tipping in a restaurant depending on the quality of the food and service
- etc.

To develop full fuzzy logic inference process, we could apply four steps.

- First, we have the non-fuzzy inputs that are numbers from certain range, and you will find how to represent those non-fuzzy values with fuzzy sets.
- Next, we have fuzzy rules. One alternative approach is matrix off rules.
- The results of rules are combined and used to calculate non-fuzzy results.
- As we see the last two steps are combined into one because numbers are way easier to handle than fuzzy sets. For fuzzy sets, there is defuzzification.

### Step 1: Define Non Fuzzy Inputs with Fuzzy Sets

In the first round you have inputs that are numbers and this is used to calculate fuzzy values. If you have the temperature as one input you get result like: cold, warm or hot depending on that particular input you have.

In case of two values, for example: food quality and service, you take two values that are numbers and see how good the food was and how good the service was. In this case the range is described with few functions.

In most cases you use: triangular function, trapezoid function, singleton, bell function, gauss function, or some other type of the function.

In our example, we will develop solution that will use: triangular or trapezoid functions.

### Step 2: Define Fuzzy Rules

Next thing we need to accomplish, are the rules, or the matrix of rules.

Some examples of rules are: If food is great and service is excellent then tip is big. Or, if price is small or reserve is small then purchase the merchandise. Or, any other other rules that would help in decision making for your situation

You could use some most common operators in rules like: union, intersection, negation etc. This would be good for developing class that would be useful in the case we need to calculate: union, intersection etc.

One better way, from programmer’s point of view, is to have the matrix that will be constructed to each combination of input values.

So, if you wish to create system for oil purchase, you could have two input variables:

- Oil price with its possible inputs: low, good or expensive.
- All reserves with its possible inputs: low, medium, and big.

Those are input values for a function of two variables.

The actions that could be result are: not recommended, shy approach, not aggressive, assertive approach, and must to buy. This would be result for each combination of two inputs in this case. In another words, those are all possible outcomes. You would end up with matrix of 3*3 elements that could be filled with five possible results.

### Step 3: Calculate Results

Next stage could be called the rule evaluation results. In other words, you need some results, and those results will be in form of fuzzy set.

So, what is done at this step? The results are clipped from appropriate membership functions.

Then you apply the union on all those clipped functions to get some results that are fuzzy sets. For practical use, we prefer to handle the actual numbers and this is the reason why we need next stage.

### Step 4: Defuzzification

Because the fuzzy sets are not practical as the results, now you go into defuzzification phase. To obtain the crisp results we could apply few approaches: Centroid method, Bisector, Mean of Maximum, Smallest of the maximum etc.

The output is one number that could be used to make decision to by the oil or not, or to turn the fan down or to maintain the level or to sound alarm, or should we be afraid of storm or not.

### Example Fuzzy Logic Solution

In our solution we have the following three classes:

- CFuzzyFunction
- CTriangle
- CTrapezoid

Class CFuzzyFunction is a base class that is a parent of classes: CTriangle and CTrapezoid.

This way, you could implement the common things for classes CTriangle and CTrapezoid in a class CFuzzyFunction, and broaden them with their specifics. Class CFuzzyFunction has at least one pure virtual function, that makes her an abstract class, which means that we will not have ability to instance objects from this class, but we will be able to create pointers of this type, which will be used to create the container of different objects. In this case we will have array of tree objects, but you could use different containers to handle those objects.

Let us analyze first class CFuzzyFunction. The data in protected part are:

double dLeft, dRight; char cType; char* sName;

The first two attributes; dLeft and dRight, are used to keep the left and right side off the function. It is two of tree dots that define the triangle. The left one is used to marks left part of the interval and right one is used to mark the right part of the interval.

The CType will be used to store the type of function: in this case we use ‘t’ for triangle and ‘r’ for trapezoid function. If you have more functions you could use some menu to write this.

The char* sName is used to store the name of the function. For example: low price, good price, to expensive etc.

Then, we have the constructor that has a same name like our class, we could write the class without one, and you would get one by default.

CFuzzyFunction();

The destructor is virtual, and in this case we need destructor, because the sName has more characters congregated together. The name of destructor is same as the name of the class, but it has one additional character also known as tilda.

The destructor is virtual because it is in abstract class.

virtual ~CFuzzyFunction()

Next thing we need is method setInterval which is used to set values dLeft and dRight. Those values are far left and far right edges of the membership functions.

virtual void setInterval(double l,double r)

Next method is setMiddle, it has two arguments because trapezoid function has two points between dLeft and dRight. In the case that you wish to broaden your solution, it might be a good idea to use array for this.

virtual void setMiddle( double dL=0,double dR=0)

Method setType is used to set the type of the function. In our case t will be triangle and r will be used for trapezoid functions.

virtual void setType(char c)

Method setName is interesting because it copies one array of chars into second one. This technique is very interesting too.

It would be nice to explain the copy constructor as well, and sometimes it has the same technique used. This method is used for names like: good, bade, etc.

virtual void setName(const char* s)

Method isDotInInterval is used to check if the value is in the interval of functions. It checks if dLeft is greater than value and dRight smaller than the value. If those two conditions are fullfiled the value will be in the interval.

bool isDotInInterval(double t)

Next tree methods: getType, getName, getValue are used to obtain: type of fuzzy function, it’s name or the calculated value. The last value is specific to each of the classes so it is pure virtual function in this case.

char getType(void)const void getName() const virtual double getValue(double t)

The next two classes: CTriangle and CTrapeziod have two methods each. First one is setMiddle, that one is used to set the middle point for triangle function and two middle points for trapezoid functions.

voidsetMiddle(double dL=0, double dR=0)

We have method getValue that is used to calculate how much value belongs to the functions. This is very compact way to calculate this.

double getValue(double t)

Next, we will analyze the code in main function.

After the three headers, we have the following two constants:

const double cdMinimumPrice =0; const double cdMaximumPrice =70;

We will use them to limit the range of the function, for those who are interested in this subject, I recommend that you try to improve this approach. Firs off all, you could use left and right trapezoid, those functions are very useful in practical cases.

Then we have the std name space.

Declarations and implementations of classed are in same file as the function main. You could create separate file with those classes or even organize them in one name space.

My recommendation would be to create namespace FuzzySolution, after that you could incorporate all needed classes that could be reused and even distributed to other people.

In the main function we declare array of pointers:

CFuzzyFunction* FuzzySet[3];

In this case, I have used only tree pointers of CFuzzyFunction type. It is possible to use dynamic array or vector instead, or some more interesting container.

This way we will keep the objects organized in one structure. Now you have ability to manipulate the objects of different type that are congregated in one container.

After we have reserved the place for our objects, we will create tree of them:

FuzzySet[0] = new CTrapezoid; FuzzySet[1] = new CTriangle; FuzzySet[2] = new CTrapezoid;

In this case we could create the array of unknown size, we could also fill the array with adequate objects, but the code would be more complicated. You would need to have one do while loop and few: ifs or case-switches. It is not too difficult to understand or to implement that.

Now we need to fill our objects with some values:

FuzzySet[i]->setInterval(a,d);

Now we could calculate the membership for concrete values. It could become bit clumsy to calculate those membership functions on the slopes, so you would have your calculator for that now.

To calculate memberships off certain value, we have endless loop, in which you input the value you wish to calculate. This way you have illusion that you have created the interactive program.

If you wish to test the program you could input these values: -10, 0, 15, 27, 25, 35, 48, 46, 50, 70 and 75.

### Fuzzy Logic Example Program

#include <iostream> #include <cmath> #include <cstring> const double cdMinimumPrice =0; const double cdMaximumPrice =70; using namespace std; class CFuzzyFunction { protected : double dLeft, dRight; char cType; char* sName; public: CFuzzyFunction(){}; virtual ~CFuzzyFunction(){ delete [] sName; sName=NULL;} virtual void setInterval(double l, double r) {dLeft=l; dRight=r;} virtual void setMiddle( double dL=0, double dR=0)=0; virtual void setType(char c) { cType=c;} virtual void setName(const char* s) { sName = new char[strlen(s)+1]; strcpy(sName,s); } bool isDotInInterval(double t) { if((t>=dLeft)&&(t<=dRight)) return true; else return false; } char getType(void)const{ return cType;} void getName() const { cout<<sName<<endl; } virtual double getValue(double t)=0; }; class CTriangle : public CFuzzyFunction { private: double dMiddle; public: void setMiddle(double dL, double dR) { dMiddle=dL; } double getValue(double t) { if(t<=dLeft) return 0; else if(t<dMiddle) return (t-dLeft)/(dMiddle-dLeft); else if(t==dMiddle) return 1.0; else if(t<dRight) return (dRight-t)/(dRight-dMiddle); else return 0; } }; class CTrapezoid : public CFuzzyFunction { private: double dLeftMiddle, dRightMiddle; public: void setMiddle(double dL, double dR) { dLeftMiddle=dL; dRightMiddle=dR; } double getValue(double t) { if(t<=dLeft) return 0; else if(t<dLeftMiddle) return (t-dLeft)/(dLeftMiddle-dLeft); else if(t<=dRightMiddle) return 1.0; else if(t<dRight) return (dRight-t)/(dRight-dRightMiddle); else return 0; } }; int main(void) { CFuzzyFunction *FuzzySet[3]; FuzzySet[0] = new CTrapezoid; FuzzySet[1] = new CTriangle; FuzzySet[2] = new CTrapezoid; FuzzySet[0]->setInterval(-5,30); FuzzySet[0]->setMiddle(0,20); FuzzySet[0]->setType('r'); FuzzySet[0]->setName("low_price"); FuzzySet[1]->setInterval(25,45); FuzzySet[1]->setMiddle(35,35); FuzzySet[1]->setType('t'); FuzzySet[1]->setName("good_price"); FuzzySet[2]->setInterval(40,75); FuzzySet[2]->setMiddle(50,70); FuzzySet[2]->setType('r'); FuzzySet[2]->setName("to_expensive"); double dValue; do { cout<<"\nImput the value->"; cin>>dValue; if(dValue<cdMinimumPrice) continue; if(dValue>cdMaximumPrice) continue; for(int i=0; i<3; i++) { cout<<"\nThe dot="<<dValue<<endl; if(FuzzySet[i]->isDotInInterval(dValue)) cout<<"In the interval"; else cout<<"Not in the interval"; cout<<endl; cout<<"The name of function is"<<endl; FuzzySet[i]->getName(); cout<<"and the membership is="; cout<<FuzzySet[i]->getValue(dValue); } } while(true); return EXIT_SUCCESS; }

{ 4 comments… read them below or add one }

Next, we could define a function: When the light is turned off the value of function would be 0. When the light is turned off the value of the function would be 1. <<< Needs correction.

Exchange the place for true and false, would do it.

THX for pointing out.

As additional exercise try to create class CDevice and with inheritance create subclasses CSoundCard, CGraphicalCard etc… it would be possible to use arrays of objects as well to create CCommputer.

As you might notice it would be useful to have something like that to avoid some things like many functions that are hard to work with and some problems that arise from it. Consider CSoftwate as the passe for CProgram, CFile, CService etc…

Yes, it would be alternative way to implement OOP in PC, Server, or any device!