ts-aggregator/project_template/Fuzzy.cpp
2022-12-13 12:36:06 +04:00

355 lines
9.8 KiB
C++

#include "StdAfx.h"
#include "Fuzzy.h"
#include <iostream>
#include "Param.h"
#include <time.h>
Fuzzy::Fuzzy(string trendType, string seasonType, vector<double> timeSeries, int countPointForecast){
this->countPointForecast = countPointForecast;
this->trendType = trendType;
this->seasonType = seasonType;
this->x = timeSeries;
this->partition();
}
Fuzzy::~Fuzzy(void) {
}
void Fuzzy::init() {
defineUniversum();
fuzzyTs.clear();
}
// îïðåäåëèòü óíèâåðñóì äëÿ âðåìåííîãî ðÿäà
// èùåì ìàêñèìóì, ìèíèìóì, ïðîèçâîäèì ðàçáèåíèå íà çàäàííûå èíòåðâàëû
void Fuzzy::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));
}
}
// ôàççèôèöèðîâàòü òîëüêî îäíó òî÷êó
// âîçâðàùàåò èíäåêñ ôóíêöèè ïðèíàäëåæíîñòè ñ ìàêñèìàëüíûì çíà÷åíèåì
int Fuzzy::fuzzyfication(double value) {
// ïåðåáèðàåì âñå ôóíêöèè ïðèíàäëåæíîñòè,
// åñëè íàøëè íàèáîëüøóþ ñòåïåíü ïðèíàäëåæíîñòè, òî ôèêñèðóåì èíäåêñ ôóíêöèè
int indMax = 0;
double max = a[0].getValue(value);
for (int j =0; j < a.size(); j++) {
if (a[j].getValue(value) > max) {
indMax = j;
max = a[j].getValue(value);
}
}
return indMax;
}
void Fuzzy::createRules() {
rulesIn.clear();
rulesIn.resize(fuzzyTs.size() - countRulesIn);
rulesOut.clear();
rulesOut.resize(fuzzyTs.size() - countRulesIn);
for (int i=0; i < fuzzyTs.size() - countRulesIn; i ++) {
vector<int> v;
v.resize(countRulesIn);
for (int j=i; j < i + countRulesIn; j++) {
v[j-i] = fuzzyTs[j];
}
rulesIn[i] = v;
rulesOut[i] = fuzzyTs[i+countRulesIn];
}
}
vector<int> Fuzzy::searchRules(vector<int> inPart) {
vector<int> res(rulesOut.size());
int countRes = 0;
for (int i = 0; i < rulesIn.size(); i++) {
bool isRuleFound = true;
for (int j = 0; j < rulesIn[i].size(); j++) {
if (rulesIn[i][j] != inPart[j]) {
isRuleFound = false;
}
}
if (isRuleFound) {
res[countRes++] = rulesOut[i];
}
}
res.resize(countRes);
return res;
}
vector<int> Fuzzy::searchRulesForSeason(int index) {
vector<int> res;
int i =index - p;
while (i > 0) {
res.push_back(fuzzyfication(x[i]));
i -= p;
}
return res;
}
void Fuzzy::createModelForEstimation() {
init();
fuzzyTs.resize(xLearning.size());
for (int t = 0; t < xLearning.size(); t++) {
fuzzyTs[t] = fuzzyfication(xLearning[t]);
}
createRules();
forecast.clear();
forecast.resize(fuzzyTs.size()+countPointForecast);
for (int i=0; i < fuzzyTs.size();i++) {
forecast[i] = defuzzyfication(fuzzyTs[i]);
}
int k = fuzzyTs.size();
for (int i=0; i < countPointForecast;i++) {
vector<int> lastPoints;
lastPoints.resize(countRulesIn);
for (int j = countRulesIn; j > 0; j--) {
lastPoints[countRulesIn -j] = (fuzzyTs[fuzzyTs.size() - j]);
}
vector<int> foundFuncs = searchRules(lastPoints);
if (foundFuncs.size() == 0) {
foundFuncs.push_back(fuzzyTs[fuzzyTs.size()-1]);
}
double sum = 0;
for (int j =0; j < foundFuncs.size(); j++) {
sum += a[foundFuncs[j]].getValueAtTop();
}
// òðåíäîâàÿ ñîñòàâëÿþùàÿ
double globInfo = sum / foundFuncs.size();
A at = this->a[fuzzyTs[fuzzyTs.size()-1]];
A atPrev = this->a[fuzzyTs[fuzzyTs.size()-2]];
double localInfo = at.getLeft() + (at.getRight() - at.getLeft())/2 + (at.getValueAtTop() - atPrev.getValueAtTop()) / (at.getValueAtTop() + atPrev.getValueAtTop());
// ñåçîííàÿ êîìïîíåíòà
vector<int> foundSeasonFuncs = searchRulesForSeason(fuzzyTs.size());
sum = 0;
for (int j =0; j < foundSeasonFuncs.size(); j++) {
sum += a[foundSeasonFuncs[j]].getValueAtTop();
}
double valueAtSeason = sum / foundSeasonFuncs.size();
if (trendType.compare("None") == 0) {
if (seasonType.compare("None") == 0) {
forecast[i+k] = (localInfo);
} else if (seasonType.compare("Add") == 0) {
forecast[i+k] = (gamma * localInfo + (1-gamma) * valueAtSeason);
}
} else if (trendType.compare("Add") == 0) {
if (seasonType.compare("None") == 0) {
forecast[i+k] = (delta * localInfo + (1-delta) * globInfo);
} else if (seasonType.compare("Add") == 0) {
forecast[i+k] = (gamma * delta * localInfo + (1-gamma) * valueAtSeason + (1-delta) * globInfo);
}
}
int index = fuzzyfication(forecast[i+k]);
// äîáàâèòü ïðîãíîçóþ òî÷êó â êîíåö ðÿäà
fuzzyTs.push_back(index);
xLearning.push_back(forecast[i+k]);
createRules();
}
for (int i=0; i < countPointForecast;i++) {
fuzzyTs.pop_back();
rulesIn.pop_back();
rulesOut.pop_back();
xLearning.pop_back();
}
}
// ôàççèèêàöèÿ, ñîçäàòü ñïèñîê ôóíêöèé ïðèíàäëåæíîñòè ïî âñåìó ðÿäó
void Fuzzy::createModel() {
init();
fuzzyTs.resize(x.size());
for (int i = 0; i < x.size(); i++) {
fuzzyTs[i] = fuzzyfication(x[i]);
}
createRules();
forecast.clear();
forecast.resize(fuzzyTs.size()+countPointForecast);
for (int i=0; i < fuzzyTs.size();i++) {
forecast[i] = defuzzyfication(fuzzyTs[i]);
}
int k = fuzzyTs.size();
for (int i=0; i < countPointForecast;i++) {
vector<int> lastPoints;
lastPoints.resize(countRulesIn);
for (int j = countRulesIn; j > 0; j--) {
lastPoints[countRulesIn -j] = (fuzzyTs[fuzzyTs.size() - j]);
}
vector<int> foundFuncs = searchRules(lastPoints);
if (foundFuncs.size() == 0) {
foundFuncs.push_back(fuzzyTs[fuzzyTs.size()-1]);
}
double sum = 0;
for (int j =0; j < foundFuncs.size(); j++) {
sum += a[foundFuncs[j]].getValueAtTop();
}
// òðåíäîâàÿ ñîñòàâëÿþùàÿ
double globInfo = sum / foundFuncs.size();
A at = this->a[fuzzyTs[fuzzyTs.size()-1]];
A atPrev = this->a[fuzzyTs[fuzzyTs.size()-2]];
double localInfo = at.getLeft() + (at.getRight() - at.getLeft())/2 + (at.getValueAtTop() - atPrev.getValueAtTop()) / (at.getValueAtTop() + atPrev.getValueAtTop());
// ñåçîííàÿ êîìïîíåíòà
vector<int> foundSeasonFuncs = searchRulesForSeason(fuzzyTs.size());
sum = 0;
for (int j =0; j < foundSeasonFuncs.size(); j++) {
sum += a[foundSeasonFuncs[j]].getValueAtTop();
}
double valueAtSeason = sum / foundSeasonFuncs.size();
if (trendType.compare("None") == 0) {
if (seasonType.compare("None") == 0) {
forecast[i+k] = (localInfo);
} else if (seasonType.compare("Add") == 0) {
forecast[i+k] = (gamma * localInfo + (1-gamma) * valueAtSeason);
}
} else if (trendType.compare("Add") == 0) {
if (seasonType.compare("None") == 0) {
forecast[i+k] = (delta * localInfo + (1-delta) * globInfo);
} else if (seasonType.compare("Add") == 0) {
forecast[i+k] = (gamma * delta * localInfo + (1-gamma) * valueAtSeason + (1-delta) * globInfo);
}
}
int index = fuzzyfication(forecast[i+k]);
// äîáàâèòü ïðîãíîçóþ òî÷êó â êîíåö ðÿäà
fuzzyTs.push_back(index);
x.push_back(forecast[i+k]);
createRules();
}
for (int i=0; i < countPointForecast;i++) {
fuzzyTs.pop_back();
rulesIn.pop_back();
rulesOut.pop_back();
x.pop_back();
}
}
vector<double> Fuzzy::getForecast() {
vector<double> result;
for (unsigned int i = forecast.size() - countPointForecast; i < forecast.size(); i++) {
result.push_back(forecast[i]);
}
return forecast;
}
double Fuzzy::defuzzyfication(int index) {
return this->a[index].getValueAtTop();
}
void Fuzzy::setParam(string paramName, double value) {
if (paramName.compare("countFuzzyParts") == 0) {
this->countFuzzyParts = value;
} else if (paramName.compare("countRulesIn") == 0) {
if (this->xLearning.size() < value) {
this->countRulesIn = this->xLearning.size();
} else {
this->countRulesIn = value;
}
} else if (paramName.compare("p") == 0) {
this->p = value;
} else if (paramName.compare("gamma") == 0) {
this->gamma = 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) {
if (this->xLearning.size() < value * 5) {
this->countRulesIn = this->xLearning.size();
} else {
this->countRulesIn = value * 5;
}
} else if (paramName.compare("2") == 0) {
this->gamma = value;
} else if (paramName.compare("3") == 0) {
this->delta = value;
}
}
// ìåòîä ïîëó÷åíèÿ îöåíêè ìîäåëè
double Fuzzy::calcEstimation(Aic *aic) {
return aic->getValue(3, this->xEstimation, this->forecast);
}
// ìåòîä ïîëó÷åíèÿ îïòèìèçèðîâàííîãî çíà÷åíèÿ îäíîãî ïàðàìåòðà
// TODO: ðåàëèçîâàòü
Param* Fuzzy::optimize(Estimation *est) {
Param *optimal = new Param();
double minSmape = 99999;
for (double gam = 0; gam < 1; gam+= 0.1) {
cout << "fuzzy " << gam << " èç 1" <<"\n";;
for (double del = 0; del < 1;del+= 0.1) {
for (double cri = 1; cri < 5;cri+= 1) {
for (double cfp = 2; cfp < 50;cfp+= 2) {
this->setParam("gamma", gam);
this->setParam("delta", del);
this->setParam("countRulesIn", cri);
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->gamma = gam;
optimal->delta = del;
optimal->estim = smapeValue;
optimal->countFuzzyParts = cfp;
optimal->countRulesIn = cri;
}
}
}
}
}
return optimal;
}
int Fuzzy::getNamberParam() {
return 4;
}