#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using HeuristicLab.PluginInfrastructure;
using FCE = HeuristicLab.Problems.DataAnalysis.FeatureCorrelationEnums;
namespace HeuristicLab.Problems.DataAnalysis {
public class FeatureCorrelationCalculator : Object {
private BackgroundWorker bw;
private BackgroundWorkerInfo bwInfo;
private IDataAnalysisProblemData problemData;
public IDataAnalysisProblemData ProblemData {
set {
if (bw != null) {
bw.CancelAsync();
}
problemData = value;
}
}
public FeatureCorrelationCalculator()
: base() { }
public FeatureCorrelationCalculator(IDataAnalysisProblemData problemData)
: base() {
this.problemData = problemData;
}
public void CalculateElements(FCE.CorrelationCalculators calc, FCE.Partitions partition) {
CalculateElements(problemData.Dataset, calc, partition);
}
// returns if any calculation takes place
public bool CalculateTimeframeElements(FCE.CorrelationCalculators calc, FCE.Partitions partition, string variable, int frames, double[,] correlation = null) {
if (correlation == null || correlation.GetLength(1) <= frames) {
CalculateElements(problemData.Dataset, calc, partition, variable, frames, correlation);
return true;
} else {
return false;
}
}
private double[,] GetElementsOfCorrelation(double[,] corr, int frames) {
double[,] elements = new double[corr.GetLength(0), frames + 1];
for (int i = 0; i < corr.GetLength(0); i++) {
for (int j = 0; j <= frames; j++) {
elements[i, j] = corr[i, j];
}
}
return elements;
}
private void CalculateElements(Dataset dataset, FCE.CorrelationCalculators calc, FCE.Partitions partition, string variable = null, int frames = 0, double[,] alreadyCalculated = null) {
bwInfo = new BackgroundWorkerInfo { Dataset = dataset, Calculator = calc, Partition = partition, Variable = variable, Frames = frames, AlreadyCalculated = alreadyCalculated };
if (bw == null) {
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(BwDoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(BwProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BwRunWorkerCompleted);
}
if (bw.IsBusy) {
bw.CancelAsync();
} else {
bw.RunWorkerAsync(bwInfo);
}
}
#region backgroundworker
private void BwDoWork(object sender, DoWorkEventArgs e) {
BackgroundWorkerInfo bwInfo = (BackgroundWorkerInfo)e.Argument;
if (bwInfo.Variable == null) {
BwCalculateCorrelation(sender, e);
} else {
BwCalculateTimeframeCorrelation(sender, e);
}
}
private void BwCalculateCorrelation(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
BackgroundWorkerInfo bwInfo = (BackgroundWorkerInfo)e.Argument;
Dataset dataset = bwInfo.Dataset;
FCE.Partitions partition = bwInfo.Partition;
FCE.CorrelationCalculators calc = bwInfo.Calculator;
IList doubleVariableNames = dataset.DoubleVariables.ToList();
OnlineCalculatorError error = OnlineCalculatorError.None;
int length = doubleVariableNames.Count;
double[,] elements = new double[length, length];
double calculations = (Math.Pow(length, 2) + length) / 2;
worker.ReportProgress(0);
for (int i = 0; i < length; i++) {
for (int j = 0; j < i + 1; j++) {
if (worker.CancellationPending) {
e.Cancel = true;
return;
}
IEnumerable var1 = GetRelevantValues(problemData, partition, doubleVariableNames[i]);
IEnumerable var2 = GetRelevantValues(problemData, partition, doubleVariableNames[j]);
elements[i, j] = CalculateElementWithCalculator(calc, var1, var2, out error);
if (!error.Equals(OnlineCalculatorError.None)) {
elements[i, j] = double.NaN;
}
elements[j, i] = elements[i, j];
worker.ReportProgress((int)Math.Round((((Math.Pow(i, 2) + i) / 2 + j + 1.0) / calculations) * 100));
}
}
e.Result = elements;
}
private void BwCalculateTimeframeCorrelation(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
BackgroundWorkerInfo bwInfo = (BackgroundWorkerInfo)e.Argument;
Dataset dataset = bwInfo.Dataset;
FCE.Partitions partition = bwInfo.Partition;
FCE.CorrelationCalculators calc = bwInfo.Calculator;
string variable = bwInfo.Variable;
int frames = bwInfo.Frames;
double[,] alreadyCalculated = bwInfo.AlreadyCalculated;
IList doubleVariableNames = dataset.DoubleVariables.ToList();
OnlineCalculatorError error = OnlineCalculatorError.None;
int length = doubleVariableNames.Count;
double[,] elements = new double[length, frames + 1];
double calculations = (frames + 1) * length;
worker.ReportProgress(0);
int start = 0;
if (alreadyCalculated != null) {
for (int i = 0; i < alreadyCalculated.GetLength(0); i++) {
Array.Copy(alreadyCalculated, i * alreadyCalculated.GetLength(1), elements, i * elements.GetLength(1), alreadyCalculated.GetLength(1));
}
start = alreadyCalculated.GetLength(1);
}
for (int i = 0; i < length; i++) {
for (int j = start; j <= frames; j++) {
if (worker.CancellationPending) {
e.Cancel = true;
return;
}
IEnumerable var1 = GetRelevantValues(problemData, partition, variable);
IEnumerable var2 = GetRelevantValues(problemData, partition, doubleVariableNames[i]);
var valuesInFrame = var1.Take(j);
var help = var1.Skip(j).ToList();
help.AddRange(valuesInFrame);
var1 = help;
elements[i, j] = CalculateElementWithCalculator(calc, var1, var2, out error);
if (!error.Equals(OnlineCalculatorError.None)) {
elements[i, j] = double.NaN;
}
worker.ReportProgress((int)((100.0 / calculations) * (i * (frames + 1) + j + 1)));
}
}
e.Result = elements;
}
private IEnumerable GetRelevantValues(IDataAnalysisProblemData problemData, FCE.Partitions partition, string variable) {
IEnumerable var = problemData.Dataset.GetDoubleValues(variable);
if (partition.Equals(FCE.Partitions.TrainingSamples)) {
var = var.Skip(problemData.TrainingPartition.Start).Take(problemData.TrainingPartition.End - problemData.TrainingPartition.Start);
} else if (partition.Equals(FCE.Partitions.TestSamples)) {
var = var.Skip(problemData.TestPartition.Start).Take(problemData.TestPartition.End - problemData.TestPartition.Start);
}
return var;
}
private double CalculateElementWithCalculator(FCE.CorrelationCalculators calc, IEnumerable var1, IEnumerable var2, out OnlineCalculatorError error) {
if (calc.Equals(FCE.CorrelationCalculators.HoeffdingsDependence)) {
return HoeffdingsDependenceCalculator.Calculate(var1, var2, out error);
} else if (calc.Equals(FCE.CorrelationCalculators.SpearmansRank)) {
return SpearmansRankCorrelationCoefficientCalculator.Calculate(var1, var2, out error);
} else if (calc.Equals(FCE.CorrelationCalculators.PearsonsRSquared)) {
return OnlinePearsonsRSquaredCalculator.Calculate(var1, var2, out error);
} else {
return Math.Sqrt(OnlinePearsonsRSquaredCalculator.Calculate(var1, var2, out error));
}
}
private void BwRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
if (!e.Cancelled && !worker.CancellationPending) {
if (!(e.Error == null)) {
ErrorHandling.ShowErrorDialog(e.Error);
} else {
OnCorrelationCalculationFinished((double[,])e.Result, bwInfo.Calculator, bwInfo.Partition, bwInfo.Variable);
}
} else {
bw.RunWorkerAsync(bwInfo);
}
}
#endregion
#region events
public class CorrelationCalculationFinishedArgs : EventArgs {
public double[,] Correlation { get; private set; }
public FCE.CorrelationCalculators Calculcator { get; private set; }
public FCE.Partitions Partition { get; private set; }
public string Variable { get; private set; }
public CorrelationCalculationFinishedArgs(double[,] correlation, FCE.CorrelationCalculators calculator, FCE.Partitions partition, string variable = null) {
this.Correlation = correlation;
this.Calculcator = calculator;
this.Partition = partition;
this.Variable = variable;
}
}
public delegate void CorrelationCalculationFinishedHandler(object sender, CorrelationCalculationFinishedArgs e);
public event CorrelationCalculationFinishedHandler CorrelationCalculationFinished;
protected virtual void OnCorrelationCalculationFinished(double[,] correlation, FCE.CorrelationCalculators calculator, FCE.Partitions partition, string variable = null) {
var handler = CorrelationCalculationFinished;
if (handler != null)
handler(this, new CorrelationCalculationFinishedArgs(correlation, calculator, partition, variable));
}
public delegate void ProgressCalculationHandler(object sender, ProgressChangedEventArgs e);
public event ProgressCalculationHandler ProgressCalculation;
protected void BwProgressChanged(object sender, ProgressChangedEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
if (!worker.CancellationPending && ProgressCalculation != null) {
ProgressCalculation(sender, e);
}
}
#endregion
protected class BackgroundWorkerInfo {
public Dataset Dataset { get; set; }
public FCE.CorrelationCalculators Calculator { get; set; }
public FCE.Partitions Partition { get; set; }
public string Variable { get; set; }
public int Frames { get; set; }
public double[,] AlreadyCalculated { get; set; }
}
}
}