662 lines
26 KiB
MQL5
662 lines
26 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| TestFuzzy.mq5 |
|
||
|
//| 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 <Math\Fuzzy\MamdaniFuzzySystem.mqh>
|
||
|
#include <Math\Fuzzy\SugenoFuzzySystem.mqh>
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_NormalCombinationMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_NormalCombinationMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4.0,5.1,0.1};
|
||
|
double b1=1.2;
|
||
|
double sigma1=0.45;
|
||
|
double b2=3.1;
|
||
|
double sigma2=0.9;
|
||
|
CNormalCombinationMembershipFunction function(b1,sigma1,b2,sigma2);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=0.0;
|
||
|
if(x[i]<1.2)
|
||
|
{
|
||
|
expected=MathExp(MathPow(x[i]-b1,2)/(-2.0*MathPow(0.45,2)));
|
||
|
}
|
||
|
else if(x[i]>3.1)
|
||
|
{
|
||
|
expected=MathExp(MathPow(x[i]-b2,2)/(-2.0*MathPow(0.9,2)));
|
||
|
}
|
||
|
if(MathAbs(actual-expected)>1e-20)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_GeneralizedBellShapedMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_GeneralizedBellShapedMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4,5.1,0.1};
|
||
|
double a = 2.4;
|
||
|
double b = 0.9;
|
||
|
double c = 1.33;
|
||
|
CGeneralizedBellShapedMembershipFunction function(a,b,c);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=1/(1+MathPow(MathAbs((x[i]-a)/c),2*b));
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_SigmoidalMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_SigmoidalMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4,4.1,0.1};
|
||
|
double a = 1.75;
|
||
|
double c = -M_PI/2;
|
||
|
CSigmoidalMembershipFunction function(a,c);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=1/(1.0+MathExp(-a *(x[i]-c)));
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_ProductTwoSigmoidalMembershipFunctions() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_ProductTwoSigmoidalMembershipFunctions()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4.0,4.1,0.1};
|
||
|
double a1 = -1.75;
|
||
|
double c1 = -M_PI/2.0;
|
||
|
double a2 = 0.972;
|
||
|
double c2 = 0.43;
|
||
|
CProductTwoSigmoidalMembershipFunctions function(a1,c1,a2,c2);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=((1.0/(1.0+MathExp(-a1 *(x[i]-c1)))) *
|
||
|
(1.0/(1.0+MathExp(-a2 *(x[i]-c2)))));
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_TrapezoidMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_TrapezoidMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4,3.1,0.1};
|
||
|
double x1 = -4;
|
||
|
double x2 = -4;
|
||
|
double x3 = 2;
|
||
|
double x4 = M_PI;
|
||
|
CTrapezoidMembershipFunction function(x1,x2,x3,x4);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=1.0;
|
||
|
if(x[i]>2 && x[i]<M_PI)
|
||
|
{
|
||
|
expected=(-x[i]/(x4-x3))+(x4/(x4-x3));
|
||
|
}
|
||
|
else if(x[i]>M_PI)
|
||
|
{
|
||
|
expected=0;
|
||
|
}
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_NormalMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_NormalMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4,5.1,0.1};
|
||
|
double b=1.33;
|
||
|
double sigma=0.45;
|
||
|
CNormalMembershipFunction function(b,sigma);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=MathExp(MathPow(x[i]-1.33,2.0)/(-2.0*MathPow(0.45,2.0)));
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_TriangularMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_TriangularMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4,4.1,0.1};
|
||
|
double x1 = -M_PI;
|
||
|
double x2 = -M_E/2.0;
|
||
|
double x3 = M_PI/5.0;
|
||
|
CTriangularMembershipFunction function(x1,x2,x3);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=0;
|
||
|
if(x[i]==x2)
|
||
|
{
|
||
|
expected=1;
|
||
|
}
|
||
|
else if(x[i]>x1 && x[i]<x2)
|
||
|
{
|
||
|
expected=(x[i]/(x2-x1)) -(x1/(x2-x1));
|
||
|
}
|
||
|
else if(x[i]>x2 && x[i]<x3)
|
||
|
{
|
||
|
expected=(-x[i]/(x3-x2))+(x3/(x3-x2));
|
||
|
}
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_ConstantMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_ConstantMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4,4.1,0.1};
|
||
|
double value=1.0;
|
||
|
CConstantMembershipFunction function(1.0);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=function.GetValue(x[i]);
|
||
|
double expected=value;
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_P_S_Z_ShapedMembershipFunction() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_P_S_Z_ShapedMembershipFunction()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-20;
|
||
|
double x[]={-4.0,4.1,0.1};
|
||
|
CS_ShapedMembershipFunction sfunction(-1.0/137.0,M_PI/2.0);
|
||
|
CZ_ShapedMembershipFunction zfunction(MathExp(1.0),M_PI);
|
||
|
CP_ShapedMembershipFunction pfunction(-1.0/137.0,M_PI/2.0,MathExp(1.0),M_PI);
|
||
|
for(int i=0; i<ArraySize(x); i++)
|
||
|
{
|
||
|
double actual=pfunction.GetValue(x[i]);
|
||
|
double expected=sfunction.GetValue(x[i])*zfunction.GetValue(x[i]);
|
||
|
if(actual!=expected)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_Bisector() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_Bisector()
|
||
|
{
|
||
|
double delta=1e-10;
|
||
|
CMamdaniFuzzySystem system();
|
||
|
system.SetDefuzzificationMethod(BisectorDef);
|
||
|
CTriangularMembershipFunction *function=new CTriangularMembershipFunction(0,5,5);
|
||
|
double actual=system.Defuzzify(function,0,5);
|
||
|
double expected=3.5;
|
||
|
if(MathAbs(actual-expected)>=delta)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
return (false);
|
||
|
}
|
||
|
return (true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_Centroid() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_Centroid()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-1;
|
||
|
CMamdaniFuzzySystem system();
|
||
|
system.SetDefuzzificationMethod(CentroidDef);
|
||
|
double mean[]={-5,-3,-1,1,3,5};
|
||
|
double sigma[]={1,2};
|
||
|
for(int i=0; i<ArraySize(mean); i++)
|
||
|
{
|
||
|
for(int j=0; j<ArraySize(sigma); j++)
|
||
|
{
|
||
|
CNormalMembershipFunction *function=new CNormalMembershipFunction(mean[i],sigma[j]);
|
||
|
double actual=system.Defuzzify(function,-10,10);
|
||
|
double expected=mean[i];
|
||
|
if(MathAbs(actual-expected)>=delta)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_Defuzzification() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_Defuzzification()
|
||
|
{
|
||
|
bool result=true;
|
||
|
double delta=1e-12;
|
||
|
CMamdaniFuzzySystem system();
|
||
|
double actual=0.0;
|
||
|
double expected=0.0;
|
||
|
//---
|
||
|
system.SetDefuzzificationMethod(CentroidDef);
|
||
|
actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10);
|
||
|
if(MathAbs(actual-expected)>=delta)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
//---
|
||
|
system.SetDefuzzificationMethod(BisectorDef);
|
||
|
actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10);
|
||
|
if(MathAbs(actual-expected)>=delta)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
//---
|
||
|
system.SetDefuzzificationMethod(AverageMaximumDef);
|
||
|
actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10);
|
||
|
if(MathAbs(actual-expected)>=delta)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
//---
|
||
|
system.SetDefuzzificationMethod(SmallestMaximumDef);
|
||
|
actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10);
|
||
|
if(MathAbs(actual-expected)>=delta)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
//---
|
||
|
system.SetDefuzzificationMethod(LargestMaximumDef);
|
||
|
actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10);
|
||
|
if(MathAbs(actual-expected)>=delta)
|
||
|
{
|
||
|
Print("Expected: ",expected," +/- ",delta," ; But was: ",actual);
|
||
|
result=false;
|
||
|
}
|
||
|
return (result);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_TipingProblem() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_TipingProblem()
|
||
|
{
|
||
|
//--- Mamdani Fuzzy System
|
||
|
CMamdaniFuzzySystem *fsTips=new CMamdaniFuzzySystem();
|
||
|
//--- Create first input variables for the system
|
||
|
CFuzzyVariable *fvService=new CFuzzyVariable("service",0.0,10.0);
|
||
|
fvService.Terms().Add(new CFuzzyTerm("poor", new CTriangularMembershipFunction(-5.0, 0.0, 5.0)));
|
||
|
fvService.Terms().Add(new CFuzzyTerm("good", new CTriangularMembershipFunction(0.0, 5.0, 10.0)));
|
||
|
fvService.Terms().Add(new CFuzzyTerm("excellent", new CTriangularMembershipFunction(5.0, 10.0, 15.0)));
|
||
|
fsTips.Input().Add(fvService);
|
||
|
//--- Create second input variables for the system
|
||
|
CFuzzyVariable *fvFood=new CFuzzyVariable("food",0.0,10.0);
|
||
|
fvFood.Terms().Add(new CFuzzyTerm("rancid", new CTrapezoidMembershipFunction(0.0, 0.0, 1.0, 3.0)));
|
||
|
fvFood.Terms().Add(new CFuzzyTerm("delicious", new CTrapezoidMembershipFunction(7.0, 9.0, 10.0, 10.0)));
|
||
|
fsTips.Input().Add(fvFood);
|
||
|
//--- Create Output
|
||
|
CFuzzyVariable *fvTips=new CFuzzyVariable("tips",0.0,30.0);
|
||
|
fvTips.Terms().Add(new CFuzzyTerm("cheap", new CTriangularMembershipFunction(0.0, 5.0, 10.0)));
|
||
|
fvTips.Terms().Add(new CFuzzyTerm("average", new CTriangularMembershipFunction(10.0, 15.0, 20.0)));
|
||
|
fvTips.Terms().Add(new CFuzzyTerm("generous", new CTriangularMembershipFunction(20.0, 25.0, 30.0)));
|
||
|
fsTips.Output().Add(fvTips);
|
||
|
//--- Create three Mamdani fuzzy rule
|
||
|
CMamdaniFuzzyRule *rule1 = fsTips.ParseRule("if (service is poor ) or (food is rancid) then tips is cheap");
|
||
|
CMamdaniFuzzyRule *rule2 = fsTips.ParseRule("if ((service is good)) then tips is average");
|
||
|
CMamdaniFuzzyRule *rule3 = fsTips.ParseRule("if (service is excellent) or (food is delicious) then (tips is generous)");
|
||
|
//--- Add three Mamdani fuzzy rule in system
|
||
|
fsTips.Rules().Add(rule1);
|
||
|
fsTips.Rules().Add(rule2);
|
||
|
fsTips.Rules().Add(rule3);
|
||
|
//--- Set input value
|
||
|
CList *in=new CList;
|
||
|
CDictionary_Obj_Double *p_od_Service=new CDictionary_Obj_Double;
|
||
|
CDictionary_Obj_Double *p_od_Food=new CDictionary_Obj_Double;
|
||
|
//--- Testing values
|
||
|
double Food=6.5;
|
||
|
double Service=9.8;
|
||
|
double expected=24.3;
|
||
|
p_od_Service.SetAll(fvService,Service);
|
||
|
p_od_Food.SetAll(fvFood,Food);
|
||
|
in.Add(p_od_Service);
|
||
|
in.Add(p_od_Food);
|
||
|
//--- Get result
|
||
|
CList *result;
|
||
|
CDictionary_Obj_Double *p_od_Tips;
|
||
|
result=fsTips.Calculate(in);
|
||
|
p_od_Tips=result.GetNodeAtIndex(0);
|
||
|
double actual=NormalizeDouble(p_od_Tips.Value(),1);
|
||
|
delete in;
|
||
|
delete result;
|
||
|
delete fsTips;
|
||
|
if(expected!=actual)
|
||
|
{
|
||
|
Print("Expected: ",expected," ; But was: ",actual);
|
||
|
//--- failed
|
||
|
return (false);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//--- success
|
||
|
return (true);
|
||
|
}
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Test_TypicalFuzzyControlSystem() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool Test_TypicalFuzzyControlSystem()
|
||
|
{
|
||
|
//--- Sugeno Fuzzy System
|
||
|
CSugenoFuzzySystem *fsCruiseControl=new CSugenoFuzzySystem();
|
||
|
//--- Create first input variables for the system
|
||
|
CFuzzyVariable *fvSpeedError=new CFuzzyVariable("SpeedError",-20.0,20.0);
|
||
|
fvSpeedError.Terms().Add(new CFuzzyTerm("slower",new CTriangularMembershipFunction(-35.0,-20.0,-5.0)));
|
||
|
fvSpeedError.Terms().Add(new CFuzzyTerm("zero", new CTriangularMembershipFunction(-15.0, -0.0, 15.0)));
|
||
|
fvSpeedError.Terms().Add(new CFuzzyTerm("faster", new CTriangularMembershipFunction(5.0, 20.0, 35.0)));
|
||
|
fsCruiseControl.Input().Add(fvSpeedError);
|
||
|
//--- Create second input variables for the system
|
||
|
CFuzzyVariable *fvSpeedErrorDot=new CFuzzyVariable("SpeedErrorDot",-5.0,5.0);
|
||
|
fvSpeedErrorDot.Terms().Add(new CFuzzyTerm("slower", new CTriangularMembershipFunction(-9.0, -5.0, -1.0)));
|
||
|
fvSpeedErrorDot.Terms().Add(new CFuzzyTerm("zero", new CTriangularMembershipFunction(-4.0, -0.0, 4.0)));
|
||
|
fvSpeedErrorDot.Terms().Add(new CFuzzyTerm("faster", new CTriangularMembershipFunction(1.0, 5.0, 9.0)));
|
||
|
fsCruiseControl.Input().Add(fvSpeedErrorDot);
|
||
|
//--- Create Output
|
||
|
CSugenoVariable *svAccelerate=new CSugenoVariable("Accelerate");
|
||
|
double coeff1[3]={0.0,0.0,0.0};
|
||
|
svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("zero",coeff1));
|
||
|
double coeff2[3]={0.0,0.0,1.0};
|
||
|
svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("faster",coeff2));
|
||
|
double coeff3[3]={0.0,0.0,-1.0};
|
||
|
svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("slower",coeff3));
|
||
|
double coeff4[3]={-0.04,-0.1,0.0};
|
||
|
svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("func",coeff4));
|
||
|
fsCruiseControl.Output().Add(svAccelerate);
|
||
|
//--- Craete Sugeno fuzzy rules
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"slower","slower","faster");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"slower","zero","faster");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"slower","faster","zero");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"zero","slower","faster");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"zero","zero","func");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"zero","faster","slower");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"faster","slower","zero");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"faster","zero","slower");
|
||
|
AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"faster","faster","slower");
|
||
|
//--- Set input value and get result
|
||
|
CList *in=new CList;
|
||
|
CDictionary_Obj_Double *p_od_Error=new CDictionary_Obj_Double;
|
||
|
CDictionary_Obj_Double *p_od_ErrorDot=new CDictionary_Obj_Double;
|
||
|
double Speed_Error=18.3;
|
||
|
double Speed_ErrorDot=-3.5;
|
||
|
double expected=-16.7;
|
||
|
p_od_Error.SetAll(fvSpeedError,Speed_Error);
|
||
|
p_od_ErrorDot.SetAll(fvSpeedErrorDot,Speed_ErrorDot);
|
||
|
in.Add(p_od_Error);
|
||
|
in.Add(p_od_ErrorDot);
|
||
|
//--- Get result
|
||
|
CList *result;
|
||
|
CDictionary_Obj_Double *p_od_Accelerate;
|
||
|
result=fsCruiseControl.Calculate(in);
|
||
|
p_od_Accelerate=result.GetNodeAtIndex(0);
|
||
|
double actual=NormalizeDouble(p_od_Accelerate.Value()*100,1);
|
||
|
delete in;
|
||
|
delete result;
|
||
|
delete fsCruiseControl;
|
||
|
if(expected!=actual)
|
||
|
{
|
||
|
Print("Expected: ",expected," ; But was: ",actual);
|
||
|
//--- failed
|
||
|
return (false);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//--- success
|
||
|
return (true);
|
||
|
}
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| AddSugenoFuzzyRule() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void AddSugenoFuzzyRule(CSugenoFuzzySystem *fs,CFuzzyVariable *fv1,CFuzzyVariable *fv2,CSugenoVariable *sv,
|
||
|
const string value1,const string value2,const string result)
|
||
|
{
|
||
|
CSugenoFuzzyRule *rule=fs.EmptyRule();
|
||
|
rule.Conclusion(new CSingleCondition());
|
||
|
rule.Condition().Op(OperatorType::And);
|
||
|
rule.Condition().ConditionsList().Add(rule.CreateCondition(fv1, fv1.GetTermByName(value1)));
|
||
|
rule.Condition().ConditionsList().Add(rule.CreateCondition(fv2, fv2.GetTermByName(value2)));
|
||
|
rule.Conclusion().Var(sv);
|
||
|
INamedValue *sf=sv.GetFuncByName(result);
|
||
|
rule.Conclusion().Term(sf);
|
||
|
fs.Rules().Add(rule);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| TestMembersipFunctions |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool TestMembersipFunctions(const string test_name)
|
||
|
{
|
||
|
PrintFormat("%s started",test_name);
|
||
|
//--- test 1
|
||
|
PrintFormat("%s: Test 1: calculation of the values for combination two normal membership function",test_name);
|
||
|
if(!Test_NormalCombinationMembershipFunction())
|
||
|
return (false);
|
||
|
//--- test 2
|
||
|
PrintFormat("%s: Test 2: calculation of the values for generalized bell-shaped membership function",test_name);
|
||
|
if(!Test_GeneralizedBellShapedMembershipFunction())
|
||
|
return (false);
|
||
|
//--- test 3
|
||
|
PrintFormat("%s: Test 3: calculation of the values for sigmoidal membership function",test_name);
|
||
|
if(!Test_SigmoidalMembershipFunction())
|
||
|
return (false);
|
||
|
//--- test 4
|
||
|
PrintFormat("%s: Test 4: calculation of the values for product two sigmoidal membership function",test_name);
|
||
|
if(!Test_ProductTwoSigmoidalMembershipFunctions())
|
||
|
return (false);
|
||
|
//--- test 5
|
||
|
PrintFormat("%s: Test 5: calculation of the values for trapezoid membership function",test_name);
|
||
|
if(!Test_TrapezoidMembershipFunction())
|
||
|
return (false);
|
||
|
//--- test 6
|
||
|
PrintFormat("%s: Test 6: calculation of the values for normal membership function",test_name);
|
||
|
if(!Test_NormalMembershipFunction())
|
||
|
return (false);
|
||
|
//--- test 7
|
||
|
PrintFormat("%s: Test 7: calculation of the values for triangular membership function",test_name);
|
||
|
if(!Test_TriangularMembershipFunction())
|
||
|
return (false);
|
||
|
//--- test 8
|
||
|
PrintFormat("%s: Test 8: calculation of the values for constant membership function",test_name);
|
||
|
if(!Test_ConstantMembershipFunction())
|
||
|
return (false);
|
||
|
//--- test 9
|
||
|
PrintFormat("%s: Test 9: comparing the results of calculations 'P' shaped function and product 'S' and 'Z' shaped function",test_name);
|
||
|
if(!Test_P_S_Z_ShapedMembershipFunction())
|
||
|
return (false);
|
||
|
//--- successful
|
||
|
PrintFormat("%s passed",test_name);
|
||
|
return (true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| TestDefuzzificationMethods |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool TestDefuzzificationMethods(const string test_name)
|
||
|
{
|
||
|
PrintFormat("%s started",test_name);
|
||
|
//--- test 1
|
||
|
PrintFormat("%s: Test 1: application of the Bisector defuzzification for a triangular membership function",test_name);
|
||
|
if(!Test_Bisector())
|
||
|
return (false);
|
||
|
//--- test 2
|
||
|
PrintFormat("%s: Test 2: application of the Centroid defuzzification for a normal membership function",test_name);
|
||
|
if(!Test_Centroid())
|
||
|
return (false);
|
||
|
//--- test 3
|
||
|
PrintFormat("%s: Test 3: application of the Bisector, Centroid, Middle, Smallest, and Largest of Maximum defuzzification for a normal membership function",test_name);
|
||
|
if(!Test_Defuzzification())
|
||
|
return (false);
|
||
|
//--- successful
|
||
|
PrintFormat("%s passed",test_name);
|
||
|
return (true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| TestFuzzySystems |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool TestFuzzySystems(const string test_name)
|
||
|
{
|
||
|
PrintFormat("%s started",test_name);
|
||
|
//--- test 1
|
||
|
PrintFormat("%s: Test 1: calculate result for Mamdani fuzzy system",test_name);
|
||
|
if(!Test_TipingProblem())
|
||
|
return (false);
|
||
|
//--- test 2
|
||
|
PrintFormat("%s: Test 2: calculate result for Sugeno fuzzy system",test_name);
|
||
|
if(!Test_TypicalFuzzyControlSystem())
|
||
|
return (false);
|
||
|
//--- successful
|
||
|
PrintFormat("%s passed",test_name);
|
||
|
return (true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| TestFuzzy |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void TestFuzzy(int &tests_performed,int &tests_passed)
|
||
|
{
|
||
|
//--- Membersip functions
|
||
|
tests_performed++;
|
||
|
string test_name="Membersip functions test";
|
||
|
if(TestMembersipFunctions(test_name))
|
||
|
tests_passed++;
|
||
|
else
|
||
|
PrintFormat("%s failed",test_name);
|
||
|
|
||
|
//--- Defuzzification methods
|
||
|
tests_performed++;
|
||
|
test_name="Defuzzification methods test";
|
||
|
if(TestDefuzzificationMethods(test_name))
|
||
|
tests_passed++;
|
||
|
else
|
||
|
PrintFormat("%s failed",test_name);
|
||
|
|
||
|
//--- Fuzzy systems
|
||
|
tests_performed++;
|
||
|
test_name="Fuzzy systems test";
|
||
|
if(TestFuzzySystems(test_name))
|
||
|
tests_passed++;
|
||
|
else
|
||
|
PrintFormat("%s failed",test_name);
|
||
|
return;
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| UnitTests() |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void UnitTests(const string package_name)
|
||
|
{
|
||
|
PrintFormat("Unit tests for Package %s\n",package_name);
|
||
|
//--- initial values
|
||
|
int tests_performed=0;
|
||
|
int tests_passed=0;
|
||
|
//--- test distributions
|
||
|
TestFuzzy(tests_performed,tests_passed);
|
||
|
//--- print statistics
|
||
|
PrintFormat("\n%d of %d passed",tests_passed,tests_performed);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Script program start function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnStart()
|
||
|
{
|
||
|
UnitTests("Fuzzy");
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|