#include "StdAfx.h" #include "Tsaur.h" #include "Param.h" #include "float.h" #include Tsaur::Tsaur(vector timeSeries, int countPointForecast){ this->countPointForecast = countPointForecast; this->trendType = trendType; this->seasonType = seasonType; this->x = timeSeries; this->partition(); } void Tsaur::init() { S.clear(); T.clear(); T.push_back(fuzzyfication(x[1]-x[0])); S.push_back(fuzzyfication(x[0])); fuzzyForecast.push_back(plusSet(S[0], T[0])); } // определить универсум для временного ряда // ищем максимум, минимум, производим разбиение на заданные интервалы void Tsaur::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 Tsaur::minusSet(A a, A b) { //if ((a.getLeft()- b.getLeft()) < (a.getRight() - b.getRight())) { return A(a.getLeft()- b.getLeft(), a.getRight() - b.getRight()); //} else { // return A(a.getRight() - b.getRight(), a.getLeft()- b.getLeft()); //} } // операция вычитания множеств A Tsaur::numMinusSet(double num, A a) { //if ((num - a.getLeft()) < (num - a.getRight())) { return A(num - a.getLeft(), num - a.getRight()); //} else { // return A(num - a.getRight(), num - a.getLeft()); //} } // операция деления множеств A Tsaur::divSet(A a, A b) { return A(a.getLeft()/b.getLeft(), a.getRight()/b.getRight()); } // операция деления множеств A Tsaur::divSet(A a, double b) { return A(a.getLeft()/b, a.getRight()/b); } // операция умножение множества на число A Tsaur::multSetNum(double num, A a) { //if ((a.getLeft() * num) < (a.getRight() * num)) { return A(a.getLeft() * num, a.getRight() * num); //} else { // return A(a.getRight() * num, a.getLeft() * num); //} } // операция сложения множеств A Tsaur::plusSet(A a, A b) { return A(a.getLeft()+ b.getLeft(), a.getRight() + b.getRight()); } // операция умножения множеств A Tsaur::multSet(A a, A b) { //if ((a.getLeft()* b.getLeft()) < (a.getRight() * b.getRight())) { return A(a.getLeft()* b.getLeft(), a.getRight() * b.getRight()); //} else { // return A(a.getLeft()* b.getLeft(), a.getRight() * b.getRight()); //} } // фаззифицировать только одну точку // возвращает индекс функции принадлежности с максимальным значением A Tsaur::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 Tsaur::createModelForEstimation() { defineUniversum(); A fuzzyBetta0 = fuzzyfication(xLearning[1]- xLearning[0]); A fuzzyBetta1 = A(lb1,rb1); A fuzzyBetta2 = A(lb2,rb2); A fuzzyAlpha = A(0, 1); fuzzyTs.clear(); fuzzyForecast.clear(); // фаззификация fuzzyTs.resize(xLearning.size()); init(); A e; //выполняется проход модели по сглаживанию и прогнозированию countPointForecast точек for (unsigned int t = 0; t < xLearning.size()-1+this->countPointForecast; t++) { if (t < xLearning.size()) { e = minusSet(fuzzyfication(xLearning[t]), fuzzyForecast[t]); } else { e = A(0,0); } S.push_back(plusSet(S[t], multSet(e, fuzzyAlpha))); T.push_back(plusSet(plusSet(fuzzyBetta0, multSetNum(t, fuzzyBetta1)), multSetNum(t*t, fuzzyBetta2))); fuzzyForecast.push_back(plusSet(multSetNum(alpha, S[t+1]), multSetNum((1-alpha), T[t+1]))); //fuzzyForecast.push_back(S[t+1]); } forecast.clear(); forecast.resize(fuzzyForecast.size()); for (unsigned int i = 0; i < fuzzyForecast.size(); i++) { if (_finite(defuzzyfication(fuzzyForecast[i])) == 0){ forecast[i] = (x[x.size()-1]); } else { forecast[i] = (defuzzyfication(fuzzyForecast[i])); } } } void Tsaur::createModel() { defineUniversum(); A fuzzyBetta0 = fuzzyfication(x[1]- x[0]); A fuzzyBetta1 = A(lb1,rb1); A fuzzyBetta2 = A(lb2,rb2); A fuzzyAlpha = A(0, 1); fuzzyTs.clear(); fuzzyForecast.clear(); // фаззификация fuzzyTs.resize(x.size()); init(); A e; //выполняется проход модели по сглаживанию и прогнозированию countPointForecast точек for (unsigned int t = 0; t < x.size()-1+this->countPointForecast; t++) { if (t < x.size()) { e = minusSet(fuzzyfication(x[t]), fuzzyForecast[t]); } else { e = A(0,0); } S.push_back(plusSet(S[t], multSet(e, fuzzyAlpha))); T.push_back(plusSet(plusSet(fuzzyBetta0, multSetNum(t, fuzzyBetta1)), multSetNum(t*t, fuzzyBetta2))); fuzzyForecast.push_back(plusSet(multSetNum(alpha, S[t+1]), multSetNum((1-alpha), T[t+1]))); //fuzzyForecast.push_back(S[t+1]); } forecast.clear(); forecast.resize(fuzzyForecast.size()); for (unsigned int i = 0; i < fuzzyForecast.size(); i++) { if (_finite(defuzzyfication(fuzzyForecast[i])) == 0){ forecast[i] = (x[x.size()-1]); } else { forecast[i] = (defuzzyfication(fuzzyForecast[i])); } } } // метод получения оценки модели double Tsaur::calcEstimation(Aic *aic) { return aic->getValue(3, this->xEstimation, this->forecast); } Tsaur::~Tsaur(void) { } double Tsaur::defuzzyfication(A a) { return a.getValueAtTop(); } vector Tsaur::defuzzyfication(vector fuz) { vector result; for (int i =0; i < fuz.size(); i++) { result.push_back(defuzzyfication(fuz[i])); } return result; } vector Tsaur::getForecast() { vector result; for (unsigned int i = forecast.size() - countPointForecast; i < forecast.size(); i++) { result.push_back(forecast[i]); } return result; } void Tsaur::setParam(string paramName, double value) { if (paramName.compare("countFuzzyParts") == 0) { this->countFuzzyParts = value; } else if (paramName.compare("alpha") == 0) { this->alpha = value; } else if (paramName.compare("lb1") == 0) { this->lb1 = value; } else if (paramName.compare("rb1") == 0) { this->rb1 = value; } else if (paramName.compare("lb2") == 0) { this->lb2 = value; } else if (paramName.compare("rb2") == 0) { this->rb2 = value; } } // метод получения оптимизированного значения одного параметра // TODO: реализовать Param* Tsaur::optimize(Estimation *est) { Param *optimal = new Param(); double minSmape = 99999; for (double a = 0; a < 1; a+= 0.1) { cout << "TSAUR " << a << " из 1" <<"\n";; for (double _lb1 = -10; _lb1 < 1; _lb1 += 0.2) { for (double _rb1 = _lb1; _rb1 < 1; _rb1 += 0.2) { for (double _lb2 = -1; _lb2 < 1; _lb2 += 0.2) { for (double _rb2 = _lb2; _rb2 < 1; _rb2 += 0.2) { for (double cfp = 2; cfp < 20;cfp+= 1) { this->setParam("countFuzzyParts", cfp); this->setParam("alpha", a); this->setParam("lb1", _lb1); this->setParam("rb1", _rb1); this->setParam("lb2", _lb2); this->setParam("rb2", _rb2); this->createModelForEstimation(); double smapeValue = est->getValue(getXEstimation(), getForecast()); if (minSmape > smapeValue) { minSmape = smapeValue; optimal->countFuzzyParts = cfp; optimal->alpha = a; optimal->lb1 = _lb1; optimal->lb2 = _lb2; optimal->rb1 = _rb1; optimal->rb2 = _rb2; } } } } } } } return optimal; }