#include <bits/stdc++.h>
using namespace std;
#define faster cin.tie(NULL);ios_base::sync_with_stdio(false);
#include <iostream>
#include <string>
//////////////////////////Fuzzy Set/////////////////////////////
class FuzzySet {
public:
string name;
string shape;
vector<double> Points;
FuzzySet(){}
FuzzySet( string name, string shape, vector<double> points)
: name(name), shape(shape), Points(points) {}
double solveEquation(double input, double x1, double x2, double y1, double y2) {
// y= ax+b -->a=slope
double slope = (y2 - y1) / (x2 - x1);
double b = y1 - (slope * x1); // by substitute
return (slope * input) + b; //intersection
}
double getCentroid()
{
double centroid=0;
for (int i = 0; i < Points.size(); ++i) {
centroid += Points[i];
}
centroid /= Points.size();
return centroid;
}
double getIntersection(double input) {
for (int i = 0; i < Points.size() - 1; ++i) {
if (input >= Points[i] && input <= Points[i + 1]) { // in between
double y1 = 1.0, y2 = 1.0;
if (i == 0) {
y1 = 0;
}
if (i + 1 == Points.size() - 1) {
y2 = 0;
}
return solveEquation(input, Points[i], Points[i + 1], y1, y2);
}
}
return 0.0; //no intersection
}
};
//////////////////////////Variable/////////////////////////////
class Variable {
public:
string name;
string type; //In or OUT
map<string,FuzzySet> sets;
double low;
double high;
Variable(){}
Variable( string name, string type, double low, double high)
: name(name), type(type), low(low), high(high) {}
void addSet(FuzzySet set) {
sets[set.name] = set;
}
map< string, double> CalcMembership(double input) {
map< string, double> map;
for (const auto& setName : sets) {
double membership = sets[setName.first].getIntersection(input);
map[setName.first] = membership;
}
return map;
}
};
//////////////////////////Rules/////////////////////////////
class Rules{
public:
vector<string>splitRuleInput;
vector<string>splitRuleOutput;
Rules(string rule)
{
string str="";
bool left=true;
for (int i = 0; i <rule.size() ; ++i) {
if(str=="=>")
{
left=false;
str="";
continue;
}
if(rule[i]==' ')
{
if(str!=""&&left)
splitRuleInput.push_back(str);
else if(str!=""&&!left)
{
splitRuleOutput.push_back(str);
}
str="";
continue;
}
str+=rule[i];
}
if(str!="") splitRuleOutput.push_back(str);
}
pair<double,string>calculate( map<string, map<string, double>> memberShip)
{
pair<double,string>current;
string name1=this->splitRuleInput[0];
string dec1=this->splitRuleInput[1];
double temp=memberShip[name1][dec1];
for (int i = 2; i < this->splitRuleInput.size()-2;i++) {
string op= this->splitRuleInput[i];
string name2= this->splitRuleInput[i+1];
string dec2=this->splitRuleInput[i+2];
i++;i++;
if(op=="or")
{
temp=max(temp,memberShip[name2][dec2]);
}
else if(op=="and")
{
temp=min(temp,memberShip[name2][dec2]);
}
else if(op=="and_not")
{
temp=min(temp,1-memberShip[name2][dec2]);
}
else if(op=="or_not")
{
temp=max(temp,1-memberShip[name2][dec2]);
}
}
current.first=temp;
current.second=this->splitRuleOutput[1];
return current;
}
};
//////////////////////////FuzzyLogicSystem/////////////////////////////
class FuzzyLogicSystem{
public:
string name;
string description;
vector<Rules>rules;
map<string,Variable>variables; //change
//add variables -> add their sets -> add rules -> run
bool steps[3]={false, false, false};
public:
FuzzyLogicSystem(string &name, string &description)
{
this->name=name;
this->description=description;
steps[0]=steps[1]=steps[2] = false;
}
void addVariables(Variable &variable)
{
variables[variable.name]=variable;
steps[0]= true;
}
bool checkStep2(){
for(auto variable :variables){
if(variable.second.sets.empty())
return false;
}
steps[1]=true;
return true;
}
void addRule(Rules rule)
{
if(steps[0]&&checkStep2()) {
rules.push_back(rule);
steps[2]=true;
}
else
cout<<"Please check that you Entered the variables and their sets!\n";
}
void addVariableSet(string varName, FuzzySet fuzzySet) {
variables[varName].addSet(fuzzySet);
}
/////////////////First Step//////////////////////////
map<string, map<string, double>> Fuzzification( map<string, Variable>& myVariables, map<string, double>& input) {
map<string, map<string, double>> fuzzification;
for (auto curr : myVariables) {
if (curr.second.type == "IN") {
map<string, double> memberships = curr.second.CalcMembership(input[curr.first]);
fuzzification[curr.first] = memberships; //input ---> intersection points for each variable
}
}
return fuzzification;
}
/////////////////Second Step//////////////////////////
vector<pair<double,string>>Inference( map<string, map<string, double>>memberShip, vector<Rules>rules)
{
vector<pair<double,string>> inference;
for (int i = 0; i < rules.size(); ++i) {
inference.push_back(rules[i].calculate(memberShip));
}
return inference;
}
/////////////////Third Step//////////////////////////
double Defuzificztion(map<string, Variable>& myVariables, vector<pair<double,string>>inference)
{
double defuzzification;
map<string,double>mp;
for (auto curr : myVariables) {
if (curr.second.type == "OUT") {
for (auto currFact:curr.second.sets) {
auto center=currFact.second.getCentroid();
// cout<<center<<endl;
mp[currFact.first]=center;
}
}
}
/////////weighted///////////
double total=0;
double weight=0;
for (int i = 0; i <inference.size() ; ++i) {
total+=(mp[inference[i].second]*inference[i].first);
weight+=inference[i].first;
}
defuzzification=total/weight;
return defuzzification;
}
bool ready(){
if(steps[0]&&steps[1]&&steps[2])
return true;
return false;
}
};
int main() {
while (true)
{
cout<<"Fuzzy Logic Toolbox\n"
"===================\n"
"1- Create a new fuzzy system\n"
"2- Quit\n";
int choice; cin>>choice;
if(choice==1)
{
cout<<"Enter the system’s name and a brief description:\n";
string fuzzyName,des; cin.ignore();
getline(cin,fuzzyName);
getline(cin,des);
FuzzyLogicSystem newFuzzy(fuzzyName,des);
while (true)
{
cout<<"Main Menu:\n"
"==========\n"
"1- Add variables.\n"
"2- Add fuzzy sets to an existing variable.\n"
"3- Add rules.\n"
"4- Run the simulation on crisp values.\n";
int option;cin>>option;
if(option==1)
{
cout<<"Enter the variable’s name, type (IN/OUT) and range ([lower, upper]):\n"
"(Press x to finish)";
string name;
while (cin>>name &&name!="x")
{
string type; int low, high;
char c;
cin>>type>>c>>low>>c>>high>>c;
int valid=1;
if((type!="IN"&&type!="OUT")||low>high)
valid=0;
while (!valid){
cout<<"Invalid Type or Range!"<<endl;
cout<<"Enter Type (IN/OUT) and range ([lower, upper]) Again:\n";
cin>>type>>c>>low>>c>>high>>c;
if((type=="IN"||type=="OUT")&&low<=high)
valid=1;
}
Variable variable(name,type,low,high);
newFuzzy.addVariables(variable);
}
}
else if(option==2)
{
cout<<"Enter the variable’s name:";
string varName; cin>>varName;
while (newFuzzy.variables.find(varName)==newFuzzy.variables.end()){
cout<<"Invalid Variable Name!\nEnter it Again: (Press x to finish)\n";
cin>>varName;
}
cout<<"Enter the fuzzy set name, type (TRI/TRAP) and values: (Press x to finish) ";
string name;
while (cin>>name &&name!="x")
{
string shape;cin>>shape;
while (shape!="TRI"&&shape!="TRAP"){
cout<<"Invalid Type!\nEnter it Again:\n";
cin>>shape;
}
vector<double>points;
if(shape=="TRI")
{
for (int i = 0; i <3 ; ++i) {
int currPoint; cin>>currPoint;
points.push_back(currPoint);
}
}
else
{
for (int i = 0; i <4 ; ++i) {
int currPoint; cin>>currPoint;
points.push_back(currPoint);
}
}
FuzzySet fuzzySet(name,shape,points);
newFuzzy.addVariableSet(varName, fuzzySet);
}
// map<string,double>input;
// input["proj_funding"]=50;
// input["exp_level"]=40;
// map<string,map<string, double> >res=newFuzzy.Fuzzification(newFuzzy.variables,input);
// cout<<"offfffffffffffffff"<<endl;
// cout<<res.size()<<endl;
// for (const auto &outer_pair : res) {
// std::cout << "Outer Key: " << outer_pair.first << std::endl;
//
// // Loop through the inner map
// for (const auto &inner_pair : outer_pair.second) {
// std::cout << "\tInner Key: " << inner_pair.first
// << ", Value: " << inner_pair.second << std::endl;
// }
// }
}
else if(option==3)
{
cout<<"Enter the rules in this format: (Press x to finish) \n"
"IN_variable set operator IN_variable set => OUT_variable set\n";
string rule;
cin.ignore();
///handle if it's invalid rule
while (getline(cin,rule)&&rule!="x")
{
//cout<<rule<<endl;
Rules myRule(rule);
newFuzzy.addRule(myRule);
}
}
else if(option==4)
{
cout<<"Enter the crisp values: ";
//////////////////////////////////////dd**///
if(!newFuzzy.ready()) {
cout << "CAN’T START THE SIMULATION! Please add the fuzzy sets and rules first.\n";
continue;
}
map<string,double>input;
int x;
for(auto currvar:newFuzzy.variables)
{
if(currvar.second.type=="IN")
{
cout<<currvar.first<<":";
cin>>x;
input[currvar.first]=x;
cout<<endl;
}
}
map<string,map<string, double> >memberShip=newFuzzy.Fuzzification(newFuzzy.variables,input);
vector<pair<double,string>>inference=newFuzzy.Inference( memberShip,newFuzzy.rules);
double defuzificztion =newFuzzy.Defuzificztion(newFuzzy.variables, inference);
cout<<defuzificztion<<endl;
}
else
break;
}
}
else
return 0;
}
}