/**
 * Copyright (C) 2013-2017 Vasilis Vryniotis 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datumbox.framework.core.statistics.timeseries;

import com.datumbox.framework.common.dataobjects.FlatDataList;

/**
 * This class provides several Smoothing and moving average methods.
 * 
 * @author Vasilis Vryniotis 
 */
public class Smoothing {
    
    /**
     * Simple Moving Average
     * 
     * @param flatDataList
     * @param N
     * @return 
     */
    public static double simpleMovingAverage(FlatDataList flatDataList, int N) {
        double SMA=0;

        int counter=0;
        for(int i=flatDataList.size()-1;i>=0;--i) {
            double Yti = flatDataList.getDouble(i);
            if(counter>=N) {
                break;
            }
            SMA+=Yti; //possible numeric overflow 
            ++counter;
        }

        SMA/=counter;

        return SMA;
    }
    
    /**
     * Simple Moving Average: Calculates Ft+1 by using previous results. A quick version of the simpleMovingAverage
     * 
     * @param Yt
     * @param YtminusN
     * @param Ft
     * @param N
     * @return 
     */
    public static double simpleMovingAverageQuick(double Yt, double YtminusN, double Ft, int N) {
        double SMA=(Yt-YtminusN)/N+Ft;

        return SMA;
    }
    
    /**
     * Weighted Moving Average
     * 
     * @param flatDataList
     * @param N
     * @return 
     */
    public static double weightedMovingAverage(FlatDataList flatDataList, int N) {
        double WMA=0;

        double denominator=0.0;
        int counter=0;
        for(int i=flatDataList.size()-1;i>=0;--i) {
            double Yti = flatDataList.getDouble(i);
            
            if(counter>=N) {
                break;
            }

            double weight=(N-counter);
            WMA+=weight*Yti; //possible numeric overflow 

            denominator+=weight;
            ++counter;
        }

        WMA/=denominator;

        return WMA;
    }
    
    /**
     * Simple Explonential Smoothing
     * 
     * @param flatDataList
     * @param a
     * @return 
     */
    public static double simpleExponentialSmoothing(FlatDataList flatDataList, double a) {
        double EMA=0;
        int count=0;
        for(int i=flatDataList.size()-1;i>=0;--i) {
            double Yti = flatDataList.getDouble(i);
            EMA+=a*Math.pow(1-a,count)*Yti;

            ++count;
        }

        return EMA;
    }
    
    /**
     * Simple Explonential Smoothing: Calculates Ft+1 by using previous results. A quick version of the simpleExponentialSmoothing
     * 
     * @param Ytminus1
     * @param Stminus1
     * @param a
     * @return 
     */
    public static double simpleExponentialSmoothingQuick(double Ytminus1, double Stminus1, double a) {
        double EMA=a*Ytminus1+(1-a)*Stminus1;

        return EMA;
    }

    /**
     * Smooth supplied timeline internalData 3 ways - overall, by trend and by season. 
     * Ported from https://github.com/ianbarber/PHPIR/blob/master/holtwinters.php
     * 
     * @param flatDataList - list of internalData
     * @param season_length - the number of entries that represent a 'season'. example = 7
     * @param alpha - internalData smoothing factor. example = 0.2
     * @param beta - trend smoothing factor. example = 0.01
     * @param gamma - seasonality smoothing factor. example = 0.01
     * @param dev_gamma - smoothing factor for deviations. example = 0.1
     * @return 
     */
    public static double holtWintersSmoothing(FlatDataList flatDataList, int season_length, double alpha, double beta, double gamma, double dev_gamma) {
        int n = flatDataList.size();
        // Calculate an initial trend level
        double trend1 = 0.0;
        for(int i = 0; i < season_length; ++i) {
            trend1 += flatDataList.getDouble(i);
        }
        trend1 /= season_length;

        double trend2 = 0.0;
        for(int i = season_length; i < 2*season_length; ++i) {
            trend2 += flatDataList.getDouble(i);
        }
        trend2 /= season_length;

        double initial_trend = (trend2 - trend1) / season_length;

        // Take the first value as the initial level
        double initial_level = flatDataList.getDouble(0);
        
        // Build index
        double[] index = new double[n];
        for(int i = 0; i 

Ads help maintain this website.