mql-for-begginers/Include/Math/Fuzzy/sugenofuzzysystem.mqh
2025-07-22 18:30:17 +03:00

327 lines
13 KiB
MQL5

//+------------------------------------------------------------------+
//| sugenofuzzysystem.mqh |
//| Copyright 2000-2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
//| Implementation of Fuzzy library in MetaQuotes Language 5 |
//| |
//| The features of the library include: |
//| - Create Mamdani fuzzy model |
//| - Create Sugeno fuzzy model |
//| - Normal membership function |
//| - Triangular membership function |
//| - Trapezoidal membership function |
//| - Constant membership function |
//| - Defuzzification method of center of gravity (COG) |
//| - Defuzzification method of bisector of area (BOA) |
//| - Defuzzification method of mean of maxima (MeOM) |
//| |
//| This file is free software; you can redistribute it and/or |
//| modify it under the terms of the GNU General Public License as |
//| published by the Free Software Foundation (www.fsf.org); either |
//| version 2 of the License, or (at your option) any later version. |
//| |
//| This program is distributed in the hope that it will be useful, |
//| but WITHOUT ANY WARRANTY; without even the implied warranty of |
//| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
//| GNU General Public License for more details. |
//+------------------------------------------------------------------+
#include <Arrays\List.mqh>
#include "GenericFuzzySystem.mqh"
#include "InferenceMethod.mqh"
#include "RuleParser.mqh"
#include "FuzzyRule.mqh"
#include "SugenoVariable.mqh"
//+------------------------------------------------------------------+
//| Purpose: Creating Sugeno fuzzy system |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Sugeno fuzzy inference system |
//+------------------------------------------------------------------+
class CSugenoFuzzySystem : public CGenericFuzzySystem
{
private:
CList *m_output; // List of Sugeno variable
CList *m_rules; // List of Sugeno fuzzy rule
public:
CSugenoFuzzySystem(void);
~CSugenoFuzzySystem(void);
//--- method gets the output linguistic variables
CList* Output(void) { return(m_output); }
//--- method gets the fuzzy rule
CList* Rules(void) { return(m_rules); }
//--- maethod gets the variable by name
CSugenoVariable* OutputByName(const string name);
//--- method create new linear function
CLinearSugenoFunction* CreateSugenoFunction(const string name,CList *coeffs,const double constValue);
CLinearSugenoFunction* CreateSugenoFunction(const string name,const double &coeffs[]);
//--- method create a new rule
CSugenoFuzzyRule* EmptyRule(void);
//--- method for calculate result
CSugenoFuzzyRule* ParseRule(const string rule);
CList* EvaluateConditions(CList *fuzzifiedInput);
CList* EvaluateFunctions(CList *inputValues);
CList* CombineResult(CList *ruleWeights,CList *functionResults);
CList* Calculate(CList *inputValues);
};
//+------------------------------------------------------------------+
//| Constructor without parameters |
//+------------------------------------------------------------------+
CSugenoFuzzySystem::CSugenoFuzzySystem(void)
{
m_output=new CList;
m_rules=new CList;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CSugenoFuzzySystem::~CSugenoFuzzySystem(void)
{
delete m_output;
delete m_rules;
}
//+------------------------------------------------------------------+
//| Get the output variable of the system by name |
//+------------------------------------------------------------------+
CSugenoVariable *CSugenoFuzzySystem::OutputByName(const string name)
{
for(int i=0; i<m_output.Total(); i++)
{
CSugenoVariable *var=m_output.GetNodeAtIndex(i);
if(var.Name()==name)
{
//--- return Sugeno variable
return (var);
}
}
Print("Variable with that name is not found");
//--- return
return (NULL);
}
//+------------------------------------------------------------------------+
//| Use this method to create a linear function for the Sugeno fuzzy system|
//+------------------------------------------------------------------------+
CLinearSugenoFunction *CSugenoFuzzySystem::CreateSugenoFunction(const string name,CList *coeffs,const double constValue)
{
//--- return linear Sugeno function
return new CLinearSugenoFunction(name, CGenericFuzzySystem::Input(), coeffs, constValue);
}
//+------------------------------------------------------------------------+
//| Use this method to create a linear function for the Sugeno fuzzy system|
//+------------------------------------------------------------------------+
CLinearSugenoFunction *CSugenoFuzzySystem::CreateSugenoFunction(const string name,const double &coeffs[])
{
//--- return linear Sugeno function
return new CLinearSugenoFunction(name, Input(), coeffs);
}
//+------------------------------------------------------------------+
//| Use this method to create an empty rule for the system |
//+------------------------------------------------------------------+
CSugenoFuzzyRule *CSugenoFuzzySystem::EmptyRule()
{
//--- return Sugeno fuzzy rule
return new CSugenoFuzzyRule();
}
//+------------------------------------------------------------------+
//| Use this method to create rule by its textual representation |
//+------------------------------------------------------------------+
CSugenoFuzzyRule *CSugenoFuzzySystem::ParseRule(const string rule)
{
//--- return Sugeno fuzzy rule
return CRuleParser::Parse(rule, EmptyRule(), Input(), Output());
}
//+------------------------------------------------------------------+
//| Evaluate conditions |
//+------------------------------------------------------------------+
CList *CSugenoFuzzySystem::EvaluateConditions(CList *fuzzifiedInput)
{
CList *result=new CList;
for(int i=0; i<Rules().Total(); i++)
{
CDictionary_Obj_Double *p_rd=new CDictionary_Obj_Double;
CSugenoFuzzyRule *rule=Rules().GetNodeAtIndex(i);
p_rd.SetAll(rule,EvaluateCondition(rule.Condition(),fuzzifiedInput));
result.Add(p_rd);
}
//--- return result
return (result);
}
//+------------------------------------------------------------------+
//| Calculate functions results |
//+------------------------------------------------------------------+
CList *CSugenoFuzzySystem::EvaluateFunctions(CList *inputValues)
{
CList *result=new CList;
for(int i=0; i<Output().Total(); i++)
{
CSugenoVariable *var=Output().GetNodeAtIndex(i);
CList *varResult=new CList;
for(int j=0; j<var.Functions().Total(); j++)
{
CDictionary_Obj_Double *p_fd=new CDictionary_Obj_Double;
CLinearSugenoFunction *func=var.Functions().GetNodeAtIndex(j);
p_fd.SetAll(func,func.Evaluate(inputValues));
varResult.Add(p_fd);
}
CDictionary_Obj_Obj *p_vl=new CDictionary_Obj_Obj;
p_vl.SetAll(var,varResult);
result.Add(p_vl);
}
//--- return result
return (result);
}
//+------------------------------------------------------------------+
//| Combine results of functions and rule evaluation |
//+------------------------------------------------------------------+
CList *CSugenoFuzzySystem::CombineResult(CList *ruleWeights,CList *functionResults)
{
CList *results=new CList;
CList *numerators=new CList;
CDictionary_Obj_Double *p_vd1;
CList *denominators=new CList;
CDictionary_Obj_Double *p_vd2;
//--- Calculate numerator and denominator separately for each output
for(int i=0; i<Output().Total(); i++)
{
p_vd1=new CDictionary_Obj_Double;
p_vd1.SetAll(Output().GetNodeAtIndex(i),0.0);
numerators.Add(p_vd1);
p_vd2=new CDictionary_Obj_Double;
p_vd2.SetAll(Output().GetNodeAtIndex(i),0.0);
denominators.Add(p_vd2);
}
for(int i=0; i<ruleWeights.Total(); i++)
{
double z=NULL;
double w=NULL;
CDictionary_Obj_Double *p_rd=ruleWeights.GetNodeAtIndex(i);
CSugenoFuzzyRule *rule=p_rd.Key();
CSugenoVariable *var=rule.Conclusion().Var();
for(int j=0; j<functionResults.Total(); j++)
{
CDictionary_Obj_Obj *p_vl=functionResults.GetNodeAtIndex(j);
if(p_vl.Key()==var)
{
CList *list=p_vl.Value();
for(int k=0; k<list.Total(); k++)
{
CDictionary_Obj_Double *p_fd=list.GetNodeAtIndex(k);
if(p_fd.Key()==rule.Conclusion().Term())
{
z=p_fd.Value();
break;
}
}
break;
}
}
for(int j=0; j<ruleWeights.Total(); j++)
{
p_rd=ruleWeights.GetNodeAtIndex(j);
if(p_rd.Key()==rule)
{
w=p_rd.Value();
break;
}
}
for(int j=0; j<numerators.Total(); j++)
{
p_vd1=numerators.GetNodeAtIndex(j);
double num=p_vd1.Value();
if(p_vd1.Key()==rule.Conclusion().Var())
{
num=num+(z*w);
p_vd1.Value(num);
break;
}
}
for(int j=0; j<denominators.Total(); j++)
{
p_vd2=denominators.GetNodeAtIndex(j);
double den=p_vd2.Value();
if(p_vd2.Key()==rule.Conclusion().Var())
{
den=den+w;
p_vd2.Value(den);
break;
}
}
}
//--- Calculate the fractions
for(int i=0; i<Output().Total(); i++)
{
CSugenoVariable *var=Output().GetNodeAtIndex(i);
CDictionary_Obj_Double *p_vd_res=new CDictionary_Obj_Double;
CDictionary_Obj_Double *p_vd_num;
CDictionary_Obj_Double *p_vd_den;
for(int j=0; j<numerators.Total(); j++)
{
p_vd_num=numerators.GetNodeAtIndex(j);
if(p_vd_num.Key()==var)
{
break;
}
}
for(int j=0; j<denominators.Total(); j++)
{
p_vd_den=denominators.GetNodeAtIndex(j);
if(p_vd_den.Key()==var)
{
break;
}
}
if(p_vd_den.Value()==0.0)
{
p_vd_res.Value(0.0);
results.Add(p_vd_res);
}
else
{
p_vd_res.Value(p_vd_num.Value()/p_vd_den.Value());
results.Add(p_vd_res);
}
}
//--- return result
delete numerators;
delete denominators;
return (results);
}
//+------------------------------------------------------------------+
//| Calculate output of fuzzy system |
//+------------------------------------------------------------------+
CList *CSugenoFuzzySystem::Calculate(CList *inputValues)
{
//--- There should be one rule as minimum
if(m_rules.Total()==0)
{
Print("There should be one rule as minimum.");
//--- return
return (NULL);
}
//--- Fuzzification step
CList *fuzzifiedInput=Fuzzify(inputValues);
//--- Evaluate the conditions
CList *ruleWeights=EvaluateConditions(fuzzifiedInput);
//--- Functions evaluation
CList *functionsResult=EvaluateFunctions(inputValues);
//--- Combine output
CList *result=CombineResult(ruleWeights,functionsResult);
//---
for(int i=0; i<functionsResult.Total(); i++)
{
CDictionary_Obj_Obj *pair=functionsResult.GetNodeAtIndex(i);
delete pair.Value();
}
delete functionsResult;
delete ruleWeights;
for(int i=0; i<fuzzifiedInput.Total(); i++)
{
CDictionary_Obj_Obj *pair=fuzzifiedInput.GetNodeAtIndex(i);
delete pair.Value();
}
delete fuzzifiedInput;
//--- return result
return (result);
}
//+------------------------------------------------------------------+