327 lines
13 KiB
MQL5
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);
| |||
}
| |||
//+------------------------------------------------------------------+
|