/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: CorrelationFunctions.hh * Author: hacene * * Created on September 27, 2021, 3:35 PM */ #ifndef CORRELATIONFUNCTIONS_HH #define CORRELATIONFUNCTIONS_HH #include "DicError.hh" #include "AMDA_exception.hh" #include "Parameter.hh" #include "ParamData.hh" #include "DataTypeMath.hh" #include "Operation.hh" #include #include #include #include #include #include "Toolbox.hh" #include "AbstractFunc.hh" namespace AMDA { namespace Parameters { namespace StatisticFunctions { #define AVERAGE_TIME 1200 // (seconds) #define MAX_GAP_SIZE 3600 // (seconds) enum COEFS { COVARIANCE = 1, PAERSON = 2, SPEARMAN = 3, KENDALL = 4, }; static std::map coefsToStr = { {"covariance", COEFS::COVARIANCE}, {"pearson", COEFS::PAERSON}, {"spearman", COEFS::SPEARMAN}, {"kendall", COEFS::KENDALL}, {"1", COEFS::COVARIANCE}, {"2", COEFS::PAERSON}, {"3", COEFS::SPEARMAN}, {"4", COEFS::KENDALL}, }; template class AbstractCorrelationFunc : public AbstractFuncBase { public: /** * @brief Constructor. * @details Create the ParamData type of the input ParamData. */ AbstractCorrelationFunc(Process& pProcess, TimeIntervalListSPtr pTimeIntervalList, ParamDataSpec& firstParamInput, ParamDataSpec& secondParamInput, double windowtime) : AbstractFuncBase(pProcess, pTimeIntervalList, windowtime), _firstParamInput(firstParamInput), _secondParamInput(secondParamInput), _paramOutput(new ParamDataSpec) { _paramDataOutput = _paramOutput; } virtual ~AbstractCorrelationFunc() { } virtual void pushData(double time, std::pair& elem) = 0; virtual OutputElemType compute() = 0; void pushSecondParamData(ParamDataIndexInfo &pParamDataIndexInfo) { for (unsigned int _index = pParamDataIndexInfo._startIndex; _index < pParamDataIndexInfo._startIndex + pParamDataIndexInfo._nbDataToProcess; ++_index) { double time = _secondParamInput.getTime(_index); InputElemType val_ = _secondParamInput.get(_index); _secondParamInputData.push_back(std::pair (time, val_)); } } virtual InputElemType getValue(std::vector >& input, double time) = 0; /** * @overload Operation::write(ParamDataIndexInfo &pParamDataIndexInfo) */ void write(ParamDataIndexInfo &pParamDataIndexInfo) { if ((pParamDataIndexInfo._nbDataToProcess > 0)) { if (pParamDataIndexInfo._startIndex == 0) { _nanVal = _firstParamInput.get(0); _nanVal << NotANumber(); } for (unsigned int _index = pParamDataIndexInfo._startIndex; _index < pParamDataIndexInfo._startIndex + pParamDataIndexInfo._nbDataToProcess; ++_index) { double crtTime = _firstParamInput.getTime(_index); InputElemType firstVal = _firstParamInput.get(_index); // get the second element InputElemType secondVal = getValue(_secondParamInputData, crtTime); std::pair crtVal(firstVal, secondVal); if (needToChangeTarget(crtTime)) { _paramOutput->pushTime(getTarget()); _paramOutput->push(compute()); pushData(crtTime, crtVal); nextTarget(); bool skip = false; while (!skip && needToChangeTarget(crtTime)) { _paramOutput->pushTime(getTarget()); _paramOutput->push(compute()); skip = nextTarget(); } } else { pushData(crtTime, crtVal); if (needInit()) { init(); } } } } if (pParamDataIndexInfo._timeIntToProcessChanged || pParamDataIndexInfo._noMoreTimeInt) { if (!needInit()) { do { if (inInt(getTarget())) { _paramOutput->pushTime(getTarget()); _paramOutput->push(compute()); } } while (nextTarget()); } } } double getInputParamSampling() { return _firstParamInput.getMinSampling(); } private: ParamDataSpec& _firstParamInput; ParamDataSpec& _secondParamInput; ParamDataSpec* _paramOutput; std::vector > _secondParamInputData; protected: OutputElemType _nanVal; }; /** * * @param pProcess * @param pTimeIntervalList * @param firstParamInput * @param secondParamInput * @param windowtime * @param type */ template class Correlation : public AbstractCorrelationFunc { public: Correlation(Process & pProcess, TimeIntervalListSPtr pTimeIntervalList, ParamDataSpec& firstParamInput, ParamDataSpec& secondParamInput, double windowtime, std::string correlationType) : AbstractCorrelationFunc (pProcess, pTimeIntervalList, firstParamInput, secondParamInput, windowtime), _correlationType(correlationType) { } virtual ~Correlation() { } virtual void init() { AbstractCorrelationFunc::setTarget(AbstractCorrelationFunc::getIntStartTime()); AbstractCorrelationFunc::setNeedInit(false); } virtual bool nextTarget() { double target = AbstractCorrelationFunc::getTarget() + AbstractCorrelationFunc::getWindowTime(); bool res = AbstractCorrelationFunc::setTarget(target); while (!_mem.empty() && !AbstractCorrelationFunc::inWindow(_mem.front().first)) { _mem.pop_front(); } return res; } virtual bool needToChangeTarget(double crtTime) { return !AbstractCorrelationFunc::needInit() && !AbstractCorrelationFunc::inWindow(crtTime); } virtual double getSampling() { return AbstractCorrelationFunc::getWindowTime(); } virtual void pushData(double time, std::pair& elem) { _mem.push_back(std::make_pair(time, elem)); } virtual void resetFunc() { _mem.clear(); } InputElemType getValue(std::vector >& input, double time) { double min_t = time - AVERAGE_TIME / 2.; double max_t = time + AVERAGE_TIME / 2.; std::vector > values_for_mean; InputElemType nanVal; nanVal << NotANumber(); std::pair prev_value(NAN, nanVal); std::pair next_value(NAN, nanVal); InputElemType value = nanVal; for (auto it = input.begin(); it != input.end(); ++it) { if (it->first == time) { value = it->second; return value; break; } else if (isNAN(it->second)) continue; else if (it->first > max_t) { next_value = *it; break; } else if (it->first < min_t) { prev_value = *it; } else { values_for_mean.push_back(*it); } } if (!values_for_mean.empty()) { //Compute mean InputElemType sum = 0; for (auto it = values_for_mean.begin(); it != values_for_mean.end(); ++it) { sum += it->second; } value = sum / (InputElemType) values_for_mean.size(); } else { if (!isNAN(prev_value.first) && !isNAN(next_value.first) && (next_value.first - prev_value.first <= MAX_GAP_SIZE)) { //Compute interpolated value value = prev_value.second + (time - prev_value.first) / (next_value.first - prev_value.first) * (next_value.second - prev_value.second); } } return value; } OutputElemType compute() { return computeCorrelation(_mem, AbstractCorrelationFunc::_nanVal, _correlationType); } OutputElemType computeCorrelation(std::list>>&mem, OutputElemType& nanVal, std::string type) { OutputElemType result = nanVal; if (mem.empty()) { return result; } std::list> list; for (typename std::list>>::iterator it = mem.begin(); it != mem.end(); ++it) { list.push_back(it->second); } if (coefsToStr.find(type) == coefsToStr.end()) { BOOST_THROW_EXCEPTION(AMDA::AMDA_exception() << AMDA::errno_code(AMDA_ERROR_UNKNOWN) << AMDA::ex_msg("StatisticFunctions::CorrelationFunction unknown correlation type " + type)); } switch (coefsToStr[type]) { case COEFS::COVARIANCE: getCovariance(list, result); break; case COEFS::PAERSON: getPearson(list, result); break; case COEFS::SPEARMAN: getSpearman(list, result); break; case COEFS::KENDALL: getKendall(list, result); break; default: BOOST_THROW_EXCEPTION(AMDA::AMDA_exception() << AMDA::errno_code(AMDA_ERROR_UNKNOWN) << AMDA::ex_msg("StatisticFunctions::CorrelationFunction unknown correlation type :" + type)); } return result; } protected: std::string _correlationType; std::list> > _mem; }; } } } #endif /* CORRELATIONFUNCTIONS_HH */