#include "StdAfx.h" #include "FuzzyWithSets.h" #include #include #include "Param.h" #include "float.h" FuzzyWithSets::FuzzyWithSets(string trendType, string seasonType, vector timeSeries, int countPointForecast){ this->countPointForecast = countPointForecast; this->trendType = trendType; this->seasonType = seasonType; this->x = timeSeries; this->partition(); } FuzzyWithSets::~FuzzyWithSets(void) { } void FuzzyWithSets::init() { S.clear(); T.clear(); I.clear(); if (trendType.compare("None") == 0) { if (seasonType.compare("None") == 0) { S.push_back(fuzzyTs[0]); fuzzyForecast.push_back(fuzzyTs[0]); } else if (seasonType.compare("Add") == 0) { A sumS = fuzzyTs[0]; for (unsigned int t = 1; t < p; t++) { sumS = plusSet(sumS, fuzzyTs[t]); } S.push_back(divSet(sumS, p)); I.resize(p); for (unsigned int t = 0; t < p; t++) { I[t] = minusSet(fuzzyTs[t], S[0]); } fuzzyForecast.push_back(plusSet(S[0], I[0])); } else if (seasonType.compare("Mult") == 0) { A sumS = fuzzyTs[0]; for (unsigned int t = 1; t < p; t++) { sumS = plusSet(sumS, fuzzyTs[t]); } S.push_back(divSet(sumS, p)); I.resize(p); for (unsigned int t = 0; t < p; t++) { I[t] = divSet(fuzzyTs[t], S[0]); } fuzzyForecast.push_back(multSet(S[0], I[0])); } } else if (trendType.compare("Add") == 0) { if (seasonType.compare("None") == 0) { T.push_back(minusSet(fuzzyTs[1], fuzzyTs[0])); S.push_back(fuzzyTs[0]); fuzzyForecast.push_back(plusSet(S[0], T[0])); } else if (seasonType.compare("Add") == 0) { A sumS = fuzzyTs[0]; A sumT = fuzzyTs[0]; for (unsigned int t = 1; t < p; t++) { sumS = plusSet(sumS, fuzzyTs[t]); sumT = plusSet(sumT, fuzzyTs[t+p]); } S.push_back(divSet(sumS, p)); T.push_back(divSet(minusSet(divSet(sumT, p), S[0]), p)); I.resize(p); for (unsigned int t = 0; t < p; t++) { I[t] = minusSet(fuzzyTs[t], S[0]); } fuzzyForecast.push_back(plusSet(S[0], plusSet(T[0], I[0]))); } else if (seasonType.compare("Mult") == 0) { A sumS = fuzzyTs[0]; A sumT = fuzzyTs[0]; for (unsigned int t = 1; t < p; t++) { sumS = plusSet(sumS, fuzzyTs[t]); sumT = plusSet(sumT, fuzzyTs[t+p]); } S.push_back(divSet(sumS, p)); T.push_back(divSet(minusSet(divSet(sumT, p), S[0]), p)); I.resize(p); for (unsigned int t = 0; t < p; t++) { I[t] = divSet(fuzzyTs[t], S[0]); } fuzzyForecast.push_back(multSet(plusSet(S[0],T[0]), I[0])); } } else if (trendType.compare("Mult") == 0) { if (seasonType.compare("None") == 0) { T.push_back(divSet(fuzzyTs[1], fuzzyTs[0])); S.push_back(fuzzyTs[0]); fuzzyForecast.push_back(multSet(S[0], T[0])); } else if (seasonType.compare("Add") == 0) { A sumS = fuzzyTs[0]; A sumT = fuzzyTs[0]; for (unsigned int t = 1; t < p; t++) { sumS = plusSet(sumS, fuzzyTs[t]); sumT = plusSet(sumT, fuzzyTs[t+p]); } S.push_back(divSet(sumS, p)); T.push_back(divSet(minusSet(divSet(sumT, p), S[0]), p)); I.resize(p); for (unsigned int t = 0; t < p; t++) { I[t] = minusSet(fuzzyTs[t], S[0]); } fuzzyForecast.push_back(plusSet(multSet(S[0], T[0]), I[0])); } else if (seasonType.compare("Mult") == 0) { A sumS = fuzzyTs[0]; A sumT = fuzzyTs[0]; for (unsigned int t = 1; t < p; t++) { sumS = plusSet(sumS, fuzzyTs[t]); sumT = plusSet(sumT, fuzzyTs[t+p]); } S.push_back(divSet(sumS, p)); T.push_back(divSet(minusSet(divSet(sumT, p), S[0]), p)); I.resize(p); for (unsigned int t = 0; t < p; t++) { I[t] = divSet(fuzzyTs[t], S[0]); } fuzzyForecast.push_back(multSet(multSet(S[0],T[0]), I[0])); } } } // определить универсум для временного ряда // ищем максимум, минимум, производим разбиение на заданные интервалы void FuzzyWithSets::defineUniversum() { this->universumMax = x[0]; this->universumMin = x[0]; for (int i = 1; i < x.size(); i++) { if (universumMax < x[i]) { universumMax = x[i]; } if (universumMin > x[i]) { universumMin = x[i]; } } // создаем функции принадлежности // принимаем по умолчанию, что соседние перекрываются на половину между собой // раз есть количество интервалов, то вычисляем размер основания треугольника double baseSize = (universumMax - universumMin) / countFuzzyParts; a.resize(countFuzzyParts + 1); for (int i=0; i < countFuzzyParts + 1;i++){ a[i] = (A(universumMin + (i-1) * baseSize, universumMin + (i+1)*baseSize)); } } // операция вычитания множеств A FuzzyWithSets::minusSet(A a, A b) { return A(a.getLeft()- b.getLeft(), a.getRight() - b.getRight()); } // операция деления множеств A FuzzyWithSets::divSet(A a, A b) { return A(a.getLeft()/b.getLeft(), a.getRight()/b.getRight()); } // операция деления множеств A FuzzyWithSets::divSet(A a, double b) { return A(a.getLeft()/b, a.getRight()/b); } // операция умножение множества на число A FuzzyWithSets::multSetNum(double num, A a) { return A(a.getLeft() * num, a.getRight() * num); } // операция сложения множеств A FuzzyWithSets::plusSet(A a, A b) { return A(a.getLeft()+ b.getLeft(), a.getRight() + b.getRight()); } // операция умножения множеств A FuzzyWithSets::multSet(A a, A b) { return A(a.getLeft()* b.getLeft(), a.getRight() * b.getRight()); } // фаззифицировать только одну точку // возвращает индекс функции принадлежности с максимальным значением A FuzzyWithSets::fuzzyfication(double value) { // перебираем все функции принадлежности, // если нашли наибольшую степень принадлежности, то фиксируем индекс функции A aMax = a[0]; for (int j = 0; j < a.size(); j++) { if (a[j].getValue(value) > aMax.getValue(value)) { aMax = a[j]; } } return aMax; } void FuzzyWithSets::createModelForEstimation() { fuzzyTs.clear(); fuzzyForecast.clear(); defineUniversum(); // фаззификация fuzzyTs.resize(xLearning.size()); for (int i = 0; i < xLearning.size();i++) { fuzzyTs[i] = (fuzzyfication(xLearning[i])); } init(); A fuzzyLast = fuzzyTs[fuzzyTs.size()-1]; A e; //выполняется проход модели по сглаживанию и прогнозированию countPointForecast точек for (unsigned int t = 0; t < xLearning.size()-1+this->countPointForecast; t++) { if (trendType.compare("None") == 0) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < fuzzyTs.size()) { e = minusSet(fuzzyTs[t], fuzzyForecast[t]); } else { e = A(0,0); } if (seasonType.compare("None") == 0) { S.push_back(plusSet(S[t],multSetNum(alpha, e))); fuzzyForecast.push_back(S[t+1]); } else if (seasonType.compare("Add") == 0) { S.push_back(plusSet(S[t], multSetNum(alpha, e))); I.push_back(plusSet(I[t], multSetNum(delta, e))); fuzzyForecast.push_back(plusSet(S[t+1], I[t+1])); } else if (seasonType.compare("Mult") == 0) { S.push_back(plusSet(S[t], divSet(multSetNum(alpha, e), I[t]))); I.push_back(plusSet(I[t], divSet(multSetNum(delta, e), S[t]))); fuzzyForecast.push_back(multSet(S[t+1], I[t+1])); } } else if (trendType.compare("Add") == 0) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < fuzzyTs.size()) { e = minusSet(fuzzyTs[t], fuzzyForecast[t]); } else { e = A(0,0); } if (seasonType.compare("None") == 0) { S.push_back(plusSet(S[t], plusSet(T[t], multSetNum(alpha, e)))); T.push_back(plusSet(T[t], multSetNum(alpha, multSetNum(gamma, e)))); fuzzyForecast.push_back(plusSet(S[t+1], T[t+1])); } else if (seasonType.compare("Add") == 0) { S.push_back(plusSet(S[t], plusSet(T[t], multSetNum(alpha, e)))); T.push_back(plusSet(T[t], multSetNum(alpha, multSetNum(gamma, e)))); I.push_back(plusSet(I[t], multSetNum(delta, e))); fuzzyForecast.push_back(plusSet(S[t+1], plusSet(T[t+1], I[t+1]))); } else if (seasonType.compare("Mult") == 0) { S.push_back(plusSet(S[t], plusSet(T[t], divSet(multSetNum(alpha, e), I[t])))); T.push_back(plusSet(T[t], divSet(multSetNum(alpha, multSetNum(gamma, e)), I[t]))); I.push_back(plusSet(I[t], divSet(multSetNum(delta, e), plusSet(S[t], T[t])))); fuzzyForecast.push_back(multSet(plusSet(S[t+1], T[t+1]), I[t+1])); } } else if (trendType.compare("Mult") == 0) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < fuzzyTs.size()) { e = minusSet(fuzzyTs[t], fuzzyForecast[t]); } else { e = A(0,0); } if (seasonType.compare("None") == 0) { S.push_back(plusSet(multSet(S[t], T[t]), multSetNum(alpha, e))); T.push_back(plusSet(T[t], divSet(multSetNum(alpha, multSetNum(gamma, e)), S[t]))); fuzzyForecast.push_back(multSet(S[t+1], T[t+1])); } else if (seasonType.compare("Add") == 0) { S.push_back(plusSet(multSet(S[t], T[t]), multSetNum(alpha, e))); T.push_back(plusSet(T[t], divSet(multSetNum(alpha, multSetNum(gamma, e)), S[t]))); I.push_back(plusSet(I[t], multSetNum(delta, e))); fuzzyForecast.push_back(plusSet(multSet(S[t+1], T[t+1]), I[t])); } else if (seasonType.compare("Mult") == 0) { S.push_back(plusSet(multSet(S[t], T[t]), divSet(multSetNum(alpha, e), I[t]))); T.push_back(plusSet( T[t], divSet( divSet( multSetNum( alpha, multSetNum( gamma, e) ), S[t]), I[t]) ) ); I.push_back(plusSet(I[t], divSet(divSet(multSetNum(delta, e), S[t]), T[t]))); fuzzyForecast.push_back(multSet(S[t+1], multSet(T[t+1], I[t]))); } } } } // фаззиикация, создать список функций принадлежности по всему ряду void FuzzyWithSets::createModel() { fuzzyTs.clear(); fuzzyForecast.clear(); defineUniversum(); // фаззификация fuzzyTs.resize(x.size()); for (int i = 0; i < x.size();i++) { fuzzyTs[i] = (fuzzyfication(x[i])); } init(); A fuzzyLast = fuzzyTs[fuzzyTs.size()-1]; A e; //выполняется проход модели по сглаживанию и прогнозированию countPointForecast точек for (unsigned int t = 0; t < x.size()-1+this->countPointForecast; t++) { if (trendType.compare("None") == 0) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < fuzzyTs.size()) { e = minusSet(fuzzyTs[t], fuzzyForecast[t]); } else { e = A(0,0); } if (seasonType.compare("None") == 0) { S.push_back(plusSet(S[t],multSetNum(alpha, e))); fuzzyForecast.push_back(S[t+1]); } else if (seasonType.compare("Add") == 0) { S.push_back(plusSet(S[t], multSetNum(alpha, e))); I.push_back(plusSet(I[t], multSetNum(delta, e))); fuzzyForecast.push_back(plusSet(S[t+1], I[t+1])); } else if (seasonType.compare("Mult") == 0) { S.push_back(plusSet(S[t], divSet(multSetNum(alpha, e), I[t]))); I.push_back(plusSet(I[t], divSet(multSetNum(delta, e), S[t]))); fuzzyForecast.push_back(multSet(S[t+1], I[t+1])); } } else if (trendType.compare("Add") == 0) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < fuzzyTs.size()) { e = minusSet(fuzzyTs[t], fuzzyForecast[t]); } else { e = A(0,0); } if (seasonType.compare("None") == 0) { S.push_back(plusSet(S[t], plusSet(T[t], multSetNum(alpha, e)))); T.push_back(plusSet(T[t], multSetNum(alpha, multSetNum(gamma, e)))); fuzzyForecast.push_back(plusSet(S[t+1], T[t+1])); } else if (seasonType.compare("Add") == 0) { S.push_back(plusSet(S[t], plusSet(T[t], multSetNum(alpha, e)))); T.push_back(plusSet(T[t], multSetNum(alpha, multSetNum(gamma, e)))); I.push_back(plusSet(I[t], multSetNum(delta, e))); fuzzyForecast.push_back(plusSet(S[t+1], plusSet(T[t+1], I[t+1]))); } else if (seasonType.compare("Mult") == 0) { S.push_back(plusSet(S[t], plusSet(T[t], divSet(multSetNum(alpha, e), I[t])))); T.push_back(plusSet(T[t], divSet(multSetNum(alpha, multSetNum(gamma, e)), I[t]))); I.push_back(plusSet(I[t], divSet(multSetNum(delta, e), plusSet(S[t], T[t])))); fuzzyForecast.push_back(multSet(plusSet(S[t+1], T[t+1]), I[t+1])); } } else if (trendType.compare("Mult") == 0) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < fuzzyTs.size()) { e = minusSet(fuzzyTs[t], fuzzyForecast[t]); } else { e = A(0,0); } if (seasonType.compare("None") == 0) { S.push_back(plusSet(multSet(S[t], T[t]), multSetNum(alpha, e))); T.push_back(plusSet(T[t], divSet(multSetNum(alpha, multSetNum(gamma, e)), S[t]))); fuzzyForecast.push_back(multSet(S[t+1], T[t+1])); } else if (seasonType.compare("Add") == 0) { S.push_back(plusSet(multSet(S[t], T[t]), multSetNum(alpha, e))); T.push_back(plusSet(T[t], divSet(multSetNum(alpha, multSetNum(gamma, e)), S[t]))); I.push_back(plusSet(I[t], multSetNum(delta, e))); fuzzyForecast.push_back(plusSet(multSet(S[t+1], T[t+1]), I[t])); } else if (seasonType.compare("Mult") == 0) { S.push_back(plusSet(multSet(S[t], T[t]), divSet(multSetNum(alpha, e), I[t]))); T.push_back(plusSet( T[t], divSet( divSet( multSetNum( alpha, multSetNum( gamma, e) ), S[t]), I[t]) ) ); I.push_back(plusSet(I[t], divSet(divSet(multSetNum(delta, e), S[t]), T[t]))); fuzzyForecast.push_back(multSet(S[t+1], multSet(T[t+1], I[t]))); } } } } vector FuzzyWithSets::getForecast() { vector result; /* result.resize(countPointForecast); for (unsigned int i = fuzzyForecast.size() - countPointForecast; i < fuzzyForecast.size(); i++) { if (_finite(defuzzyfication(fuzzyForecast[i])) == 0){ result[i - (fuzzyForecast.size() - countPointForecast)] = (x[x.size()-1]); } else { result[i - (fuzzyForecast.size() - countPointForecast)] = (defuzzyfication(fuzzyForecast[i])); } }*/ result.resize(fuzzyForecast.size()); for (unsigned int i = 0; i < fuzzyForecast.size(); i++) { if (_finite(defuzzyfication(fuzzyForecast[i])) == 0){ result[i] = (x[x.size()-1]); } else { result[i] = (defuzzyfication(fuzzyForecast[i])); } } return result; } double FuzzyWithSets::defuzzyfication(A a) { return a.getValueAtTop(); } vector FuzzyWithSets::defuzzyfication(vector fuz) { vector result; for (int i =0; i < fuz.size(); i++) { result.push_back(defuzzyfication(fuz[i])); } return result; } void FuzzyWithSets::setParam(string paramName, double value) { if (paramName.compare("countFuzzyParts") == 0) { this->countFuzzyParts = value; } else if (paramName.compare("p") == 0) { this->p = value; } else if (paramName.compare("gamma") == 0) { this->gamma = value; } else if (paramName.compare("alpha") == 0) { this->alpha = value; } else if (paramName.compare("delta") == 0) { this->delta = value; } if (paramName.compare("0") == 0) { this->countFuzzyParts = value * 100; } else if (paramName.compare("1") == 0) { this->alpha = value; } else if (paramName.compare("2") == 0) { this->gamma = value; } else if (paramName.compare("3") == 0) { this->delta = value; } else if (paramName.compare("4") == 0) { this->alpha = value; } } // метод получения оценки модели double FuzzyWithSets::calcEstimation(Aic *aic) { return aic->getValue(3, this->xEstimation, this->forecast); } // метод получения оптимизированного значения одного параметра // TODO: реализовать Param* FuzzyWithSets::optimize(Estimation *est) { Param *optimal = new Param(); double minSmape = 99999; for (double al = 0; al < 1; al+= 0.1) { cout << "FWS " << al << " из 1" <<"\n"; for (double gam = 0; gam < 1; gam+= 0.1) { for (double del = 0; del < 1;del+= 0.1) { for (double cfp = 2; cfp < 50;cfp+= 2) { this->setParam("alpha", al); this->setParam("gamma", gam); this->setParam("delta", del); this->setParam("countFuzzyParts", cfp); double smapeValue = 0; int maxShift = 5; if (maxShift > this->countPointForecast) { maxShift = this->countPointForecast-1; } this->countPointForecast -= maxShift; for (int shift=0; shift <= maxShift; shift++) { this->partition(); this->createModelForEstimation(); smapeValue += est->getValue(x, getForecast()); this->countPointForecast++; } this->countPointForecast--; smapeValue = smapeValue / maxShift; if (minSmape > smapeValue) { minSmape = smapeValue; optimal->alpha = al; optimal->gamma = gam; optimal->delta = del; optimal->estim = smapeValue; optimal->countFuzzyParts = cfp; } } } } } return optimal; } int FuzzyWithSets::getNamberParam() { return 5; }