CorrelationFunctions.hh 14.1 KB
/*
 * 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 "Parameter.hh"
#include "ParamData.hh"
#include "DataTypeMath.hh"
#include "Operation.hh"
#include <vector>
#include <iostream>
#include <iterator>
#include <c++/4.8.2/bits/stl_vector.h>
#include <c++/4.8.2/bits/stl_pair.h>
#include "AbstractFunc.hh"

namespace AMDA {
    namespace Parameters {
        namespace StatisticFunctions {

#define AVERAGE_TIME 1200 // (seconds)
#define MAX_GAP_SIZE 3600 // (seconds)

            class CorrelationBase {
            public:

                CorrelationBase() {
                }

                virtual ~CorrelationBase() {
                }
                void virtual pushSecondParamData(ParamDataIndexInfo &pParamDataIndexInfo) = 0;
            };

            template <typename InputElemType, typename OutputElemType>
            class AbstractCorrelationFunc : public AbstractFuncBase {
            public:

                /**
                 * @brief Constructor.
                 * @details Create the ParamData type of the input ParamData.
                 */
                AbstractCorrelationFunc(Process& pProcess, TimeIntervalListSPtr pTimeIntervalList, ParamDataSpec<InputElemType>& firstParamInput, ParamDataSpec<InputElemType>& secondParamInput, double windowtime)
                : AbstractFuncBase(pProcess, pTimeIntervalList, windowtime),
                _firstParamInput(firstParamInput),
                _secondParamInput(secondParamInput),
                _paramOutput(new ParamDataSpec<OutputElemType>) {
                    _paramDataOutput = _paramOutput;
                }

                virtual ~AbstractCorrelationFunc() {
                }

                virtual void pushData(double time, std::pair<InputElemType, InputElemType>& 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<double, InputElemType> (time, val_));
                    }
                }

                virtual InputElemType getValue(std::vector<std::pair<double, InputElemType> >& 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<InputElemType, InputElemType> 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<InputElemType>& _firstParamInput;

                ParamDataSpec<InputElemType>& _secondParamInput;

                ParamDataSpec<OutputElemType>* _paramOutput;

                std::vector<std::pair<double, InputElemType> > _secondParamInputData;

            protected:
                OutputElemType _nanVal;
            };

            /**
             * 
             * @param pProcess
             * @param pTimeIntervalList
             * @param firstParamInput
             * @param secondParamInput
             * @param windowtime
             * @param type
             */
            template <typename InputElemType, typename OutputElemType>
            class Correlation : public AbstractCorrelationFunc<InputElemType, OutputElemType> {
            public:

                Correlation(Process& pProcess, TimeIntervalListSPtr pTimeIntervalList, ParamDataSpec<InputElemType>
                        & firstParamInput, ParamDataSpec<InputElemType>& secondParamInput, double windowtime, std::string correlationType), _correlationType(correlationType) :
                AbstractCorrelationFunc<InputElemType, OutputElemType> (pProcess, pTimeIntervalList, firstParamInput, secondParamInput, windowtime) {

                }

                virtual ~Correlation() {
                }

                virtual void init() {
                    AbstractCorrelationFunc<InputElemType, OutputElemType>::setTarget(AbstractCorrelationFunc<InputElemType, OutputElemType>::getIntStartTime());
                    AbstractCorrelationFunc<InputElemType, OutputElemType>::setNeedInit(false);
                }

                virtual bool nextTarget() {
                    double target = AbstractCorrelationFunc<InputElemType, OutputElemType>::getTarget() + AbstractCorrelationFunc<InputElemType, OutputElemType>::getWindowTime();
                    bool res = AbstractCorrelationFunc<InputElemType, OutputElemType>::setTarget(target);
                    while (!_mem.empty() && !AbstractCorrelationFunc<InputElemType, OutputElemType>::inWindow(_mem.front().first)) {
                        _mem.pop_front();
                    }
                    return res;
                }

                virtual bool needToChangeTarget(double crtTime) {
                    return !AbstractCorrelationFunc<InputElemType, OutputElemType>::needInit() && !AbstractCorrelationFunc<InputElemType, OutputElemType>::inWindow(crtTime);
                }

                virtual double getSampling() {
                    return AbstractCorrelationFunc<InputElemType, OutputElemType>::getWindowTime();
                }

                virtual void pushData(double time, std::pair<InputElemType, InputElemType>& elem) {
                    _mem.push_back(std::make_pair(time, elem));
                }

                virtual void resetFunc() {
                    _mem.clear();
                }

                InputElemType getValue(std::vector<std::pair<double, InputElemType> >& input, double time) {
                    double min_t = time - AVERAGE_TIME / 2.;
                    double max_t = time + AVERAGE_TIME / 2.;
                    std::vector<std::pair<double, InputElemType> > values_for_mean;
                    InputElemType nanVal = input[0]->second;
                    nanVal << NotANumber();
                    std::pair<double, InputElemType> prev_value(NAN, nanVal);
                    std::pair<double, InputElemType> next_value(NAN, nanVal);
                    for (std::vector<std::pair<double, InputElemType> >::iterator it = input.begin(); it != input.end(); ++it) {
                        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);
                        }
                    }

                    InputElemType value = nanVal;
                    if (!values_for_mean.empty()) {
                        //Compute mean
                        InputElemType sum = 0;
                        for (std::vector<std::pair<double, InputElemType> >::iterator 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(ClassicAbstractFunc<InputElemType, OutputElemType>::_mem, ClassicAbstractFunc<InputElemType, OutputElemType>::_nanVal, _correlationType);
                }

                /**
                template <typename Type>
                std::pair<Type, Type> getMean(std::list<std::pair<Type, Type>> &list) {
                    std::pair<Type, Type> result(0, 0);
                    std::pair<int, int> counter(0,0);
                    for (int i = 0; i < 2; i++) {
                        for (auto elt : list) {
                            if (!isNan(std::get<i>(elt))) {
                                std::get<i>(result) += std::get<i>(elt);
                                std::get<i>(counter) += 1;
                            }
                        }
                        if(std::get<i>(counter) != 0)
                            std::get<i>(result) /= std::get<i>(counter);
                        return result;
                    }
                }

                template <typename Type>
                std::pair<Type, Type> getStd(std::list<std::pair<Type, Type>> &list) {
                    std::pair<Type, Type> mean = getMean(list);
                    std::pair<Type, Type> result(0, 0);
                    int counter1 = 0;
                    int counter2 = 0;
                    for (auto elt : list) {
                        if (!isNan(elt->first)) {
                            result.first += (elt->first - mean.first)*(elt->first - mean.first);
                            counter1 += 1;
                        }
                        if (!isNan(elt->second)) {
                            result.second += (elt->second - mean.second)*(elt->second - mean.second);
                            counter2 += 1;
                        }
                    }
                    if (counter1 != 0) {
                        result.first /= counter1;
                    } else {
                        result.first << NotANumber();
                    }
                    if (counter2 != 0) {
                        result.second /= counter2;
                    } else {
                        result.second << NotANumber();
                    }
                    return result;
                }

                template <typename Type>
                bool getCovariance(std::list<std::pair<Type, Type>> list, std::pair<Type, Type> &result) {
                    if (list.empty()) {
                        return false;
                    }
                    std::pair<Type, Type> mean = getMean(list);

                    return true;
                }
                 */
                
                OutputElemType computeCorrelation(std::list<std::pair<double, std::pair<InputElemType, InputElemType>>>&mem, OutputElemType& nanVal, std::string type) {
                    OutputElemType result = nanVal;
                    if (mem.empty()) {
                        return result;
                    }
                    std::list<std::pair<InputElemType, InputElemType>> list;
                    for (typename std::list<std::pair<double, std::pair < InputElemType, InputElemType>>>::iterator it = mem.begin(); it != mem.end(); ++it) {
                        list.push_back(it->second);
                    }
        //            getCovariance(list, result);
                    return result;
                }
                
            protected:
                std::string _correlationType;
                std::list<std::pair<double, std::pair<InputElemType, InputElemType>> > _mem;

            };

        }
    }
}


#endif /* CORRELATIONFUNCTIONS_HH */