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);
|
|
}
|
|
//+------------------------------------------------------------------+
|