//+------------------------------------------------------------------+ //| ruleparser.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 #include #include "Dictionary.mqh" #include "FuzzyRule.mqh" #include "Helper.mqh" #include "InferenceMethod.mqh" #include "SugenoVariable.mqh" //+------------------------------------------------------------------+ //| Purpose: Analysis of the fuzzy rules | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Base class for all expression | //+------------------------------------------------------------------+ class IExpression : public CObject { public: //--- method gets the text of expression virtual string Text(void)=NULL; //--- method to check type virtual bool IsTypeOf(EnLexem type) { return(type==TYPE_CLASS_IExpression); } }; //+------------------------------------------------------------------+ //| Class for creating lexem | //+------------------------------------------------------------------+ class CLexem : public IExpression { public: //--- method gets the text of expression virtual string Text(void)=NULL; //--- method to check type virtual bool IsTypeOf(EnLexem type) { return(type==TYPE_CLASS_Lexem); } }; //+------------------------------------------------------------------+ //| Class condition expression | //+------------------------------------------------------------------+ class CConditionExpression : public IExpression { private: CArrayObj *m_expressions; // List of expression CFuzzyCondition *m_condition; // Fuzzy condition public: CConditionExpression(CArrayObj *expressions,CFuzzyCondition *condition); ~CConditionExpression(void); //--- methods gets or sets array of expression CArrayObj *Expressions(void) { return (m_expressions); } void Expressions(CArrayObj *value) { m_expressions=value; } //--- methods gets or sets fuzzy condition CFuzzyCondition *Condition(void) { return m_condition; } void Condition(CFuzzyCondition *value) { m_condition=value; } //--- method gets the text of expressions string Text(void); //--- method to check type virtual bool IsTypeOf(EnLexem type) { return(type==TYPE_CLASS_ConditionExpression); } }; //+------------------------------------------------------------------+ //| Constructor with parameters | //+------------------------------------------------------------------+ CConditionExpression::CConditionExpression(CArrayObj *expressions,CFuzzyCondition *condition) { m_expressions=expressions; m_condition=condition; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CConditionExpression::~CConditionExpression(void) { } //+------------------------------------------------------------------+ //| Convert all expressions to text(string) | //+------------------------------------------------------------------+ string CConditionExpression::Text(void) { string sb; for(int i=0; i0 && StringGetCharacter(sb,StringLen(sb)-1)==' ') { //--- Do not duplicate spaces } else { sb+=CharToString(' '); } sb+=CharToString(ch); sb+=CharToString(' '); } else { if(ch==' ' && StringLen(sb)>0 && StringGetCharacter(sb,StringLen(sb)-1)==' ') { // Do not duplicate spaces } else { sb+=CharToString(ch); } } } //--- Remove spaces //+------------------------------------------------------------------+ //| Use conditional compilation to determine | //| the type of program MQL4 or MQL5 because they have | //| different realization of StringTrimRight() and StringTrimLeft() | //+------------------------------------------------------------------+ #ifdef __MQL5__ StringTrimRight(sb); StringTrimLeft(sb); #else #ifdef __MQL4__ sb=StringTrimRight(sb); sb=StringTrimLeft(sb); #endif #endif string prepRule=sb; //--- Build lexems dictionary CList *lexemsDict=BuildLexemsList(in,out); //--- At first we parse lexems CArrayObj *expressions=ParseLexems(prepRule,lexemsDict); if(expressions.Total()==0) { Print("No valid identifiers found."); //--- return return (NULL); } //--- Find condition & conclusion parts part CDictionary_String_Obj *p_so; for(int i=0; i0) { IExpression *expr0=copyExpressions.At(index); if(expr0.IsTypeOf(TYPE_CLASS_VarLexem)) { //--- Parse variable CVarLexem *varLexem=copyExpressions.At(index); if(copyExpressions.Total()<3) { Print(StringFormat("Condition strated with '%s' is incorrect.",varLexem.Text())); //--- return return(NULL); } if(varLexem.Input()==false) { Print("The variable in condition part must be an input variable."); //--- return return(NULL); } //--- Parse 'is' lexem CLexem *exprIs=copyExpressions.At(index+1); CDictionary_String_Obj *p_so; for(int i=0;i0) { ICondition *cond=NULL; for(int i=0; i0) { if((copyExpressions.At(index)==p_so_and.Value() && p_so_and.Key()=="and") || (copyExpressions.At(index)==p_so_or.Value() && p_so_or.Key()=="or")) { if(copyExpressions.Total()-index<2) { condExp=copyExpressions.At(index); Print(StringFormat("Error at %s in condition part.",condExp.Text())); //--- return return (NULL); } //--- Set and/or for conditions list OperatorType newOp=NULL; if(copyExpressions.At(index)==p_so_and.Value() && p_so_and.Key()=="and") { newOp=And; } if(copyExpressions.At(index)==p_so_or.Value() && p_so_or.Key()=="or") { newOp=Or; } if(setOrAnd) { if(conds.Op()!=newOp) { Print("At the one nesting level cannot be mixed and/or operations."); //--- return return (NULL); } } else { conds.Op(newOp); setOrAnd=true; } index=index+1; } else { string str; condExp=copyExpressions.At(index); str=condExp.Text(); condExp=copyExpressions.At(index+1); Print(StringFormat("%s cannot goes after %s",str,condExp.Text())); //--- return return (NULL); } } } //--- return conditions return (conds); } } //+------------------------------------------------------------------+ //| Parse conclusion | //+------------------------------------------------------------------+ static CSingleCondition *CRuleParser::ParseConclusion(CArrayObj *conditionExpression,CList *out,CList *lexems) { CArrayObj *copyExpression=conditionExpression; //--- Remove extra brackets CDictionary_String_Obj *p_so; CDictionary_String_Obj *p_so_open; CDictionary_String_Obj *p_so_close; for(int i=0; i=2 && (copyExpression.At(index)==p_so_open.Value() && copyExpression.At(index+conditionExpression.Total()-1)==p_so_close.Value())) { index=index+1; Total=Total-2; } if(Total!=3) { Print("Conclusion part of the rule should be in form: 'variable is term'"); //--- return return (NULL); } //--- Parse variable CLexem *exprVariable=copyExpression.At(index); if(!exprVariable.IsTypeOf(TYPE_CLASS_VarLexem)) { Print(StringFormat("Wrong identifier '%s' in conclusion part of the rule.",exprVariable.Text())); //--- return return (NULL); } CVarLexem *varLexem=exprVariable; if(varLexem.Input()==true) { Print("The variable in conclusion part must be an output variable."); //--- return return (NULL); } //--- Parse 'is' lexem CLexem *exprIs=copyExpression.At(index+1); for(int i=0; i