1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022018 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  using HeuristicLab.Common;


25 


26  namespace HeuristicLab.Problems.DataAnalysis {


27  public class OnlineCovarianceCalculator : DeepCloneable, IOnlineCalculator {


28 


29  private double xMean, yMean, Cn;


30  private int n;


31  public double Covariance


32  {


33  get


34  {


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


36  }


37  }


38 


39  public OnlineCovarianceCalculator() {


40  Reset();


41  }


42 


43  protected OnlineCovarianceCalculator(OnlineCovarianceCalculator original, Cloner cloner)


44  : base(original, cloner) {


45  Cn = original.Cn;


46  xMean = original.xMean;


47  yMean = original.yMean;


48  n = original.n;


49  errorState = original.errorState;


50  }


51 


52  public override IDeepCloneable Clone(Cloner cloner) {


53  return new OnlineCovarianceCalculator(this, cloner);


54  }


55 


56  #region IOnlineCalculator Members


57  private OnlineCalculatorError errorState;


58  public OnlineCalculatorError ErrorState


59  {


60  get { return errorState; }


61  }


62  public double Value


63  {


64  get { return Covariance; }


65  }


66  public void Reset() {


67  n = 0;


68  Cn = 0.0;


69  xMean = 0.0;


70  yMean = 0.0;


71  errorState = OnlineCalculatorError.InsufficientElementsAdded;


72  }


73 


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


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


76  errorState = errorState  OnlineCalculatorError.InvalidValueAdded;


77  } else {


78  n++;


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


80 


81  // online calculation of tMean


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


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


84  yMean = yMean + delta / n;


85 


86  // online calculation of covariance


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


88  }


89  }


90  #endregion


91 


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


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


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


95  OnlineCovarianceCalculator covarianceCalculator = new OnlineCovarianceCalculator();


96 


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


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


99  double x = secondEnumerator.Current;


100  double y = firstEnumerator.Current;


101  covarianceCalculator.Add(x, y);


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


103  }


104 


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


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


107  (secondEnumerator.MoveNext()  firstEnumerator.MoveNext())) {


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


109  } else {


110  errorState = covarianceCalculator.ErrorState;


111  return covarianceCalculator.Covariance;


112  }


113  }


114 


115  public double CalculateValue(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {


116  return Calculate(originalValues, estimatedValues, out errorState);


117  }


118  }


119  }

