1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022013 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 OnlineCovarianceCalculator : IOnlineCalculator {


27 


28  private double xMean, yMean, Cn;


29  private int n;


30  public double Covariance {


31  get {


32  return n > 0 ? Cn / n : 0.0;


33  }


34  }


35 


36  public OnlineCovarianceCalculator() {


37  Reset();


38  }


39 


40  #region IOnlineCalculator Members


41  private OnlineCalculatorError errorState;


42  public OnlineCalculatorError ErrorState {


43  get { return errorState; }


44  }


45  public double Value {


46  get { return Covariance; }


47  }


48  public void Reset() {


49  n = 0;


50  Cn = 0.0;


51  xMean = 0.0;


52  yMean = 0.0;


53  errorState = OnlineCalculatorError.InsufficientElementsAdded;


54  }


55 


56  public void Add(double x, double y) {


57  if (double.IsNaN(y)  double.IsInfinity(y)  double.IsNaN(x)  double.IsInfinity(x)  (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {


58  errorState = errorState  OnlineCalculatorError.InvalidValueAdded;


59  } else {


60  n++;


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


62 


63  // online calculation of tMean


64  xMean = xMean + (x  xMean) / n;


65  double delta = y  yMean; // delta = (y  yMean(n1))


66  yMean = yMean + delta / n;


67 


68  // online calculation of covariance


69  Cn = Cn + delta * (x  xMean); // C(n) = C(n1) + (y  yMean(n1)) (t  tMean(n))


70  }


71  }


72  #endregion


73 


74  public static double Calculate(IEnumerable<double> first, IEnumerable<double> second, out OnlineCalculatorError errorState) {


75  IEnumerator<double> firstEnumerator = first.GetEnumerator();


76  IEnumerator<double> secondEnumerator = second.GetEnumerator();


77  OnlineCovarianceCalculator covarianceCalculator = new OnlineCovarianceCalculator();


78 


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


80  while (firstEnumerator.MoveNext() & secondEnumerator.MoveNext()) {


81  double x = secondEnumerator.Current;


82  double y = firstEnumerator.Current;


83  covarianceCalculator.Add(x, y);


84  if (covarianceCalculator.ErrorState != OnlineCalculatorError.None) break;


85  }


86 


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


88  if (covarianceCalculator.ErrorState == OnlineCalculatorError.None &&


89  (secondEnumerator.MoveNext()  firstEnumerator.MoveNext())) {


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


91  } else {


92  errorState = covarianceCalculator.ErrorState;


93  return covarianceCalculator.Covariance;


94  }


95  }


96  }


97  }

