1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)


4  *


5  * This file is part of HeuristicLab.


6  *


7  * HeuristicLab is free software: you can redistribute it and/or modify


8  * it under the terms of the GNU General Public License as published by


9  * the Free Software Foundation, either version 3 of the License, or


10  * (at your option) any later version.


11  *


12  * HeuristicLab is distributed in the hope that it will be useful,


13  * but WITHOUT ANY WARRANTY; without even the implied warranty of


14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the


15  * GNU General Public License for more details.


16  *


17  * You should have received a copy of the GNU General Public License


18  * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.


19  */


20  #endregion


21 


22  using System;


23  using System.Collections.Generic;


24 


25  namespace HeuristicLab.Problems.DataAnalysis {


26  public class OnlineTheilsUStatisticCalculator : IOnlineCalculator {


27  private OnlineMeanAndVarianceCalculator squaredErrorMeanCalculator;


28  private OnlineMeanAndVarianceCalculator unbiasedEstimatorMeanCalculator;


29  private double prevOriginal;


30  private int n;


31 


32  public double TheilsUStatistic {


33  get {


34  return Math.Sqrt(squaredErrorMeanCalculator.Mean) / Math.Sqrt(unbiasedEstimatorMeanCalculator.Mean);


35  }


36  }


37 


38  private OnlineCalculatorError errorState;


39  public OnlineCalculatorError ErrorState {


40  get { return errorState  squaredErrorMeanCalculator.MeanErrorState  unbiasedEstimatorMeanCalculator.MeanErrorState; }


41  }


42 


43  public OnlineTheilsUStatisticCalculator() {


44  squaredErrorMeanCalculator = new OnlineMeanAndVarianceCalculator();


45  unbiasedEstimatorMeanCalculator = new OnlineMeanAndVarianceCalculator();


46  Reset();


47  }


48 


49  #region IOnlineEvaluator Members


50  public double Value {


51  get { return TheilsUStatistic; }


52  }


53 


54  public void Add(double original, double estimated) {


55  if (double.IsNaN(estimated)  double.IsInfinity(estimated)  double.IsNaN(original)  double.IsInfinity(original)  (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {


56  errorState = errorState  OnlineCalculatorError.InvalidValueAdded;


57  } else if (n == 0) {


58  prevOriginal = original;


59  n++;


60  } else {


61  // error of predicted change


62  double errorEstimatedChange = (estimated  original);


63  squaredErrorMeanCalculator.Add(errorEstimatedChange * errorEstimatedChange);


64 


65  double errorNoChange = (original  prevOriginal);


66  unbiasedEstimatorMeanCalculator.Add(errorNoChange * errorNoChange);


67  errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded); // n >= 1


68  prevOriginal = original;


69  n++;


70  }


71  }


72 


73 


74  public void Reset() {


75  prevOriginal = double.NaN;


76  n = 0;


77  squaredErrorMeanCalculator.Reset();


78  unbiasedEstimatorMeanCalculator.Reset();


79  errorState = OnlineCalculatorError.InsufficientElementsAdded;


80  }


81 


82  #endregion


83 


84  public static double Calculate(IEnumerable<double> estimatedValues, IEnumerable<double> originalValues, out OnlineCalculatorError errorState) {


85  IEnumerator<double> originalValuesEnumerator = originalValues.GetEnumerator();


86  IEnumerator<double> estimatedValuesEnumerator = estimatedValues.GetEnumerator();


87  OnlineTheilsUStatisticCalculator calculator = new OnlineTheilsUStatisticCalculator();


88 


89  // add first element of time series as a reference point


90  originalValuesEnumerator.MoveNext();


91  estimatedValuesEnumerator.MoveNext();


92  calculator.Add(originalValuesEnumerator.Current, estimatedValuesEnumerator.Current);


93 


94  // always move forward both enumerators (do not use shortcircuit evaluation!)


95  while (originalValuesEnumerator.MoveNext() & estimatedValuesEnumerator.MoveNext()) {


96  double estimated = estimatedValuesEnumerator.Current;


97  double original = originalValuesEnumerator.Current;


98  calculator.Add(original, estimated);


99  if (calculator.ErrorState != OnlineCalculatorError.None) break;


100  }


101 


102  // check if both enumerators are at the end to make sure both enumerations have the same length


103  if (calculator.ErrorState == OnlineCalculatorError.None &&


104  (estimatedValuesEnumerator.MoveNext()  originalValuesEnumerator.MoveNext())) {


105  throw new ArgumentException("Number of elements in first and second enumeration doesn't match.");


106  } else {


107  errorState = calculator.ErrorState;


108  return calculator.TheilsUStatistic;


109  }


110  }


111  }


112  }

