Before reading this tutorial, be sure to read Getting Fuzzy: Part 1 and Implementing a Fuzzy Boolean.
Now we're going to look at fuzzy sets. The key characteristic of this is that every item of interest contains two values: the quantity of interest, and the probability that it is in the set. We can represent that probability using an Fbool. It has some nice properties that relate to the new functionality of the Fset. The real question is: how do we connect it with the quantity of interest?
The “obvious” choice is to use a set<T>. The problem is a set doesn't really deal with pairs of values. We could use a struct to define that quantity/probability pairing, but since a set<T> doesn't really provide any additional functionality that we explicitly care about. We don't want to use a vector<T> either, since we need to be able to access the probability directly through the quantity of interest. The container we really need is the map<T,X>. Since we might be interested in a variety of different quantities, our final Fset will actually be a template. Fset<T> will use map<T,Fbool> to contain its data. However, to get everything working we'll use Fset with map<string,Fbool>.
We'll want to be aware of the following features of a map as we move forward:
maps have the following methods/operations: size(), empty(), max_size(), ==, !=, <, >, <=, >=, find(key), lower_bound(key), upper_bound(key), equal_range(key), =, swap(), begin(), end(), rbegin(), rend(), insert(), erase(), clear(), and [].
We're going to define an insert, size, empty, erase, clear, &&, ||, !, and [] based on the definition of a Fuzzy Set presented in the first tutorial. With all this in mind, let's look at fset.h:
The actual definitions of the functions are located in fset.cpp:Code:#ifndef FSET_DEFINED #define FSET_DEFINED #include "fbool.h" #include <map> #include <string> class Fset { std::map<std::string,Fbool> setdata; public: void insert(const std::string,double); void insert(const std::string,bool); int size(); bool empty(); void erase(std::string); void clear(); Fset operator&&(Fset); Fset operator||(Fset); Fset operator!(); Fbool& operator[](std::string); }; #endif
fset.cpp
The operators && and || deserve some comment. In order to make sure we cover all the elements, we'll move through both fuzzy sets element by element, adding the appropriate pair. We are taking advantage of the fact that maps store the keys in order by <, so we can meaningfully compare the keys as we step through them with the iterators.Code:#include "fbool.h" #include "fset.h" #include <string> void Fset::insert(const std::string key, double prob) { Fset::setdata.insert(std::pair<std::string,Fbool>(key,prob)); } void Fset::insert(const std::string key, bool prob) { Fset::setdata.insert(std::pair<std::string,Fbool>(key,prob)); } int Fset::size() { return Fset::setdata.size(); } bool Fset::empty() { return Fset::setdata.empty(); } void Fset::erase(std::string key) { Fset::setdata.erase(key); } void Fset::clear() { Fset::setdata.clear(); } Fset Fset::operator&&(Fset operand) { Fset temp; Fbool temp2; std::map<std::string,Fbool>::iterator pos1; std::map<std::string,Fbool>::iterator pos2; for (pos1 = this->setdata.begin(), pos2 = operand.setdata.begin(); pos1 != this->setdata.end() && pos2 != operand.setdata.end();) { if (pos1->first < pos2->first) { temp2.setval(false); temp.insert(pos1->first,temp2.getval()); ++pos1; } else if (pos1->first > pos2->first) { temp2.setval(false); temp.insert(pos2->first,temp2.getval()); ++pos2; } else { temp.insert(pos2->first,((pos1->second)&&(pos2->second)).getval()); ++pos1; ++pos2; } } return temp; } Fset Fset::operator||(Fset operand) { Fset temp; std::map<std::string,Fbool>::iterator pos1; std::map<std::string,Fbool>::iterator pos2; for (pos1 = this->setdata.begin(), pos2 = operand.setdata.begin(); pos1 != this->setdata.end() && pos2 != operand.setdata.end();) { if (pos1->first < pos2->first) { temp.insert(pos1->first,(pos1->second).getval()); ++pos1; } else if (pos1->first > pos2->first) { temp.insert(pos2->first,(pos2->second).getval()); ++pos2; } else { temp.insert(pos2->first,((pos1->second)||(pos2->second)).getval()); ++pos1; ++pos2; } } return temp; } Fset Fset::operator!() { Fset temp; std::map<std::string,Fbool>::iterator pos1; for (pos1 = this->setdata.begin(); pos1 != this->setdata.end();++pos1) { temp.insert(pos1->first,(!(pos1->second)).getval()); } return temp; } Fbool& Fset::operator[](std::string key) { return Fset::setdata[key]; }
A simple test program is listed below:
testfset.cpp
This program will produce the following output:Code:#include "fset.h" #include <iostream> #include <string> using std::string; using std::cout; int main(int argc,char* argv[]) { Fset mytestset; cout<<"mytestset.empty = "<<mytestset.empty()<<"\n"; cout<<"mytestset.count = "<<mytestset.size()<<"\n"; mytestset.insert("false",false); mytestset.insert("true",true); mytestset.insert("third",0.33); mytestset.insert("half",0.5); cout<<"mytestset.empty = "<<mytestset.empty()<<"\n"; cout<<"mytestset.count = "<<mytestset.size()<<"\n"; Fset mytest2; mytest2.insert("false",true); mytest2.insert("true",false); mytest2.insert("quarter",0.25); mytest2.insert("half",0.5); cout<<"mytest2.empty = "<<mytest2.empty()<<"\n"; cout<<"mytest2.count = "<<mytest2.size()<<"\n"; Fset andset = mytest2&&mytestset; Fset orset = mytest2||mytestset; Fset notset = !mytestset; cout<<"andset[\"false\"] = "<<andset["false"].getval()<<"\n"; cout<<"orset[\"false\"] = "<<orset["false"].getval()<<"\n"; cout<<"notset[\"false\"] = "<<notset["false"].getval()<<"\n"; return 0; }
Code:mytestset.empty = 1 mytestset.count = 0 mytestset.empty = 0 mytestset.count = 4 mytest2.empty = 0 mytest2.count = 4 andset["false"] = 0 orset["false"] = 1 notset["false"] = 1
Last edited by WingedPanther; 11-20-2008 at 02:11 AM. Reason: correct includes based on file name changes between this post and my hard drive
Very cool! Thanks for the excellent read, again! +rep
The code shows Fset andset = mytest2&&mytestset;, I am guessing that second & should be & and for some reason got converted to its html entity?
You're right John. I'm not sure why that happened.
Where we can use Fuzzy set or Fuzzy logic in our programming?
It's used in AI, or anywhere that a truth value is probabilistic rather than deterministic.
I have registered only to ask you this (:
Fuzzy set is a set. Then why don't you use std::set to inherit from? Something like this:
in this case you don't need to redeclare functions like size(), empty(), insert(), etc.Code:#include <set> #include <utility> class FuzzySet: public std::set<std::pair<T, float> > { //some declarations like this: bool contains(T elem); };
If you don't want your class to use std interface of std::set, you can inherit it with private. If you need some of your functions differ from std, you can just override it as virtual (set::insert() for example (actually i don't know is it virtual) ) or you can overload some. For example:
Where am i wrong?Code:iterator FuzzySet::insert(T elem, float f);
I'd say you are correct. This tutorial was meant to be an introduction to fuzzy sets, and to give users an idea of how they could be implemented. I've also extended my own knowledge of C++ quite a bit since I wrote this, and probably would have reworked several things.
If you wanted to rework this class along the lines you suggest, I'd love to see a tutorial on it![]()
maybe a few days later (:
on the other hand it seems to be correct just to edit a little code and probably it needn't a single tutorial. It's just a small refactoring.
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks