355 lines
9.8 KiB
C++
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;
|
|
}
|