Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
04/03/14 11:06:14 (11 years ago)
Author:
bburlacu
Message:

#1837: Moved quality calculation inside the SlidingWindowBestSolutionsCollection so that data can be cached across views. Added background worker for calculating qualities for each solution on all intervals. Added method for updating the qualities on the fly during the run (without recalculating). Added progress indicator for views.

Location:
branches/Sliding Window GP
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • branches/Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SlidingWindow/GenerationalRegressionSlidingWindowAnalyzer.cs

    r10681 r10720  
    4141    public GenerationalRegressionSlidingWindowAnalyzer() { }
    4242    public override IOperation Apply() {
    43       if (!ResultCollection.ContainsKey("Best Solutions")) {
    44         ResultCollection.Add(new Result("Best Solutions", new SlidingWindowBestRegressionSolutionsCollection()));
     43      if (!ResultCollection.ContainsKey(BestSlidingWindowSolutionsResultName)) {
     44        ResultCollection.Add(new Result(BestSlidingWindowSolutionsResultName, new SlidingWindowBestRegressionSolutionsCollection()));
    4545      }
    4646      return base.Apply();
  • branches/Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SlidingWindow/OffspringSelectionRegressionSlidingWindowAnalyzer.cs

    r10681 r10720  
    4141    public OffspringSelectionRegressionSlidingWindowAnalyzer() { }
    4242    public override IOperation Apply() {
    43       if (!ResultCollection.ContainsKey("Best Solutions")) {
    44         ResultCollection.Add(new Result("Best Solutions", new SlidingWindowBestRegressionSolutionsCollection()));
     43      if (!ResultCollection.ContainsKey(BestSlidingWindowSolutionsResultName)) {
     44        ResultCollection.Add(new Result(BestSlidingWindowSolutionsResultName, new SlidingWindowBestRegressionSolutionsCollection()));
    4545      }
    4646      return base.Apply();
  • branches/Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/SlidingWindowBestSolutionsCollectionHeatMapView.cs

    r10686 r10720  
    2121
    2222using System;
    23 using System.Collections.Generic;
     23using System.ComponentModel;
    2424using System.Linq;
    2525using System.Windows.Forms;
    2626using HeuristicLab.Analysis;
    2727using HeuristicLab.Core.Views;
    28 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    2928using HeuristicLab.MainForm;
    3029using HeuristicLab.Optimization;
     
    3938      set { base.Content = value; }
    4039    }
     40
     41    protected override void OnContentChanged() {
     42      base.OnContentChanged();
     43      if (Content != null) {
     44        if (Content.SlidingWindowQualities != null) {
     45          SetHeatmapContent(Content.SlidingWindowQualities);
     46        } else if (!Content.QualitiesCalculationInProgress) {
     47          progress.Start("Calculating best solution qualities...");
     48          Content.CalculateQualities();
     49        }
     50      }
     51    }
     52
     53    private readonly IProgress progress; // use this to show some progress when the sliding window qualities are calculated for each model
     54
    4155    public SlidingWindowBestSolutionsCollectionHeatMapView() {
    4256      InitializeComponent();
    43 
    44       qualityMeasure = (int)QualityMeasures.PEARSON;
     57      progress = new Progress();
     58      MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>().AddOperationProgressToView(this, progress);
    4559    }
    46 
    47     enum QualityMeasures { PEARSON, MSE };
    48 
    49     private int qualityMeasure;
    5060
    5161    protected override void DeregisterContentEvents() {
    5262      // TODO: Deregister your event handlers here
     63      Content.QualitiesCalculationCompleted -= bestSolutionsCollectionQualitiesCalculated;
     64      Content.QualitiesCalculationProgress -= bestSolutionCollectionQualitiesCalculationProgress;
     65      Content.QualitiesUpdated -= bestSolutionCollectionQualitiesUpdated;
    5366      base.DeregisterContentEvents();
    5467    }
     
    5770      base.RegisterContentEvents();
    5871      // TODO: Register your event handlers here
     72      Content.QualitiesCalculationCompleted += bestSolutionsCollectionQualitiesCalculated;
     73      Content.QualitiesCalculationProgress += bestSolutionCollectionQualitiesCalculationProgress;
     74      Content.QualitiesUpdated += bestSolutionCollectionQualitiesUpdated;
    5975    }
    6076
     77    private void bestSolutionsCollectionQualitiesCalculated(object sender, RunWorkerCompletedEventArgs e) {
     78      if (e.Cancelled || e.Error != null) {
     79        progress.Cancel();
     80        return;
     81      }
     82      SetHeatmapContent(Content.SlidingWindowQualities);
     83      progress.Finish();
     84    }
     85
     86    private void bestSolutionCollectionQualitiesUpdated(object sender, EventArgs e) {
     87      SetHeatmapContent(Content.SlidingWindowQualities);
     88    }
     89
     90    private void SetHeatmapContent(double[,] values) {
     91      double min = 0, max = 0;
     92      foreach (var q in values) {
     93        if (min > q) min = q;
     94        if (max < q) max = q;
     95      }
     96      int rows = values.GetLength(0);
     97      int cols = values.GetLength(1);
     98      var flipped = new double[rows, cols];
     99      for (int i = 0; i < rows; ++i) {
     100        for (int j = 0; j < cols; ++j) {
     101          flipped[i, j] = values[rows - i - 1, j];
     102        }
     103      }
     104      heatMapView.Content = new HeatMap(flipped, "Best Sliding Window Solutions", min, max);
     105    }
     106
     107    private void bestSolutionCollectionQualitiesCalculationProgress(object sender, ProgressChangedEventArgs e) {
     108      progress.ProgressValue = e.ProgressPercentage / 100.0;
     109    }
     110
     111    protected override void SetEnabledStateOfControls() {
     112      base.SetEnabledStateOfControls();
     113      // TODO: Enable or disable controls based on whether the content is null or the view is set readonly
     114    }
     115
     116    #region Event Handlers (child controls)
    61117    public void heatMapView_cellDoubleClick(object sender, DataGridViewCellEventArgs e) {
    62118      var dataGridView = (DataGridView)sender;
    63119      var cell = dataGridView.SelectedCells[0];
    64       var bestSolutions = Content.BestSolutions.Values.ToList();
     120      var bestSolutions = Content.SlidingWindowBestSolutions.Values.ToList();
    65121      var tree = bestSolutions[cell.RowIndex];
    66122      var model = Content.CreateModel(tree, Content.Interpreter);
     
    74130    }
    75131
    76     #region Event Handlers (Content)
    77     // TODO: Put event handlers of the content here
    78     #endregion
    79 
    80     protected override void OnContentChanged() {
    81       base.OnContentChanged();
    82       if (Content == null) {
    83         // TODO: Add code when content has been changed and is null
    84       } else {
    85         // TODO: Add code when content has been changed and is not null
    86         UpdateQualitiesMap();
    87       }
    88     }
    89 
    90     protected override void SetEnabledStateOfControls() {
    91       base.SetEnabledStateOfControls();
    92       // TODO: Enable or disable controls based on whether the content is null or the view is set readonly
    93     }
    94 
    95     #region Event Handlers (child controls)
    96     // TODO: Put event handlers of child controls here.
    97     #endregion
    98 
    99132    private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e) {
    100133      var combobox = (ComboBox)sender;
    101134      switch ((string)combobox.SelectedItem) {
    102135        case "Pearson R2": {
    103             qualityMeasure = (int)QualityMeasures.PEARSON;
     136            Content.QualityMeasure = SlidingWindowBestSolutionsCollection.QualityMeasures.PEARSON;
    104137            break;
    105138          }
    106139        case "Mean Squared Error": {
    107             qualityMeasure = (int)QualityMeasures.MSE;
     140            Content.QualityMeasure = SlidingWindowBestSolutionsCollection.QualityMeasures.MSE;
    108141            break;
    109142          }
    110143      }
    111       UpdateQualitiesMap();
    112144    }
    113 
    114     private void UpdateQualitiesMap() {
    115       var bestSolutions = Content.BestSolutions.Values.ToList();
    116       var swPositions = Content.BestSolutions.Keys.ToList();
    117 
    118       var nRows = bestSolutions.Count;
    119       var nCols = swPositions.Count + 1;
    120       var qualitiesMap = new double[nRows, nCols];
    121       double min = 0, max = 0;
    122 
    123       for (int i = 0; i < nCols - 1; ++i) {
    124         var pos = swPositions[i];
    125         var rows = Enumerable.Range(pos.Item1, pos.Item2 - pos.Item1).ToList();
    126 
    127         for (int j = nRows - 1; j >= 0; --j) {
    128           var tree = bestSolutions[j];
    129           var q = CalculateQuality(tree, rows);
    130           if (min > q) min = q;
    131           if (max < q) max = q;
    132           qualitiesMap[j, i] = q;
    133         }
    134       }
    135       // deal separately with the last column which represents the whole training partition interval
    136       for (int j = nRows - 1; j >= 0; --j) {
    137         var tree = bestSolutions[j];
    138         var q = CalculateQuality(tree, Content.ProblemData.TrainingIndices);
    139         if (min > q) min = q;
    140         if (max < q) max = q;
    141         qualitiesMap[j, nCols - 1] = q;
    142       }
    143 
    144       heatMapView.Content = new HeatMap(qualitiesMap);
    145       heatMapView.Content.Minimum = min;
    146       heatMapView.Content.Maximum = max;
    147     }
    148 
    149     private string GetTargetVariable(IDataAnalysisProblemData problemData) {
    150       var regressionProblemData = problemData as IRegressionProblemData;
    151       var classificationProblemData = problemData as IClassificationProblemData;
    152       if (regressionProblemData != null) return regressionProblemData.TargetVariable;
    153       if (classificationProblemData != null) return classificationProblemData.TargetVariable;
    154       throw new NotSupportedException();
    155     }
    156 
    157     private double CalculateQuality(ISymbolicExpressionTree tree, IEnumerable<int> rows) {
    158       var estimatedValues = Content.Interpreter.GetSymbolicExpressionTreeValues(tree, Content.ProblemData.Dataset, rows);
    159       var originalValues = Content.ProblemData.Dataset.GetDoubleValues(GetTargetVariable(Content.ProblemData), rows);
    160       double quality = 0;
    161       var errorState = new OnlineCalculatorError();
    162       switch ((QualityMeasures)qualityMeasure) {
    163         case QualityMeasures.PEARSON:
    164           quality = OnlinePearsonsRSquaredCalculator.Calculate(estimatedValues, originalValues, out errorState);
    165           break;
    166         case QualityMeasures.MSE:
    167           quality = OnlineMeanSquaredErrorCalculator.Calculate(estimatedValues, originalValues, out errorState);
    168           break;
    169       }
    170       return errorState == OnlineCalculatorError.None ? quality : double.NaN;
    171     }
     145    #endregion
    172146  }
    173147}
  • branches/Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/SlidingWindowBestSolutionsCollectionView.cs

    r10413 r10720  
    2222using System;
    2323using System.Collections.Generic;
     24using System.ComponentModel;
    2425using System.Linq;
    2526using System.Windows.Forms;
    2627using HeuristicLab.Core.Views;
    2728using HeuristicLab.Data;
    28 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    2929using HeuristicLab.MainForm;
    3030using HeuristicLab.Optimization;
     
    3939      set { base.Content = value; }
    4040    }
    41     public SlidingWindowBestSolutionsCollectionView() {
    42       InitializeComponent();
    4341
    44       qualityMeasure = (int)QualityMeasures.PEARSON;
     42    protected override void OnContentChanged() {
     43      base.OnContentChanged();
     44      if (Content != null) {
     45        if (Content.SlidingWindowQualities != null) {
     46          SetMatrixContent(Content.SlidingWindowQualities);
     47        } else if (!Content.QualitiesCalculationInProgress) {
     48          progress.Start("Calculating best solution qualities...");
     49          Content.CalculateQualities();
     50        }
     51      }
    4552    }
    4653
    47     enum QualityMeasures { PEARSON, MSE };
    48 
    49     private int qualityMeasure;
     54    private readonly Progress progress;
    5055
    5156    protected override void DeregisterContentEvents() {
    5257      // TODO: Deregister your event handlers here
    5358      enhancedStringConvertibleMatrixView.DataGridView.CellDoubleClick -= enhancedStringConvertibleMatrixView_cellDoubleClick;
     59      Content.QualitiesCalculationCompleted -= bestSolutionsCollectionQualitiesCalculated;
     60      Content.QualitiesCalculationProgress -= bestSolutionCollectionQualitiesCalculationProgress;
     61      Content.QualitiesUpdated -= bestSolutionCollectionQualitiesUpdated;
    5462      base.DeregisterContentEvents();
    5563    }
     
    5765    protected override void RegisterContentEvents() {
    5866      base.RegisterContentEvents();
     67      // TODO: Register your event handlers here
    5968      enhancedStringConvertibleMatrixView.DataGridView.CellDoubleClick += enhancedStringConvertibleMatrixView_cellDoubleClick;
    60       // TODO: Register your event handlers here
     69      Content.QualitiesCalculationCompleted += bestSolutionsCollectionQualitiesCalculated;
     70      Content.QualitiesCalculationProgress += bestSolutionCollectionQualitiesCalculationProgress;
     71      Content.QualitiesUpdated += bestSolutionCollectionQualitiesUpdated;
     72    }
     73
     74    public SlidingWindowBestSolutionsCollectionView() {
     75      InitializeComponent();
     76      progress = new Progress();
     77      MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>().AddOperationProgressToView(this, progress);
     78    }
     79
     80    #region Event Handlers (Content)
     81    private void bestSolutionsCollectionQualitiesCalculated(object sender, RunWorkerCompletedEventArgs e) {
     82      if (e.Cancelled || e.Error != null) {
     83        progress.Cancel();
     84        return;
     85      }
     86
     87      SetMatrixContent(Content.SlidingWindowQualities);
     88      progress.Finish();
     89    }
     90
     91    private void SetMatrixContent(double[,] values) {
     92      var qualitiesMap = new DoubleMatrix(values); // add an extra columns for the training data
     93      qualitiesMap.ColumnNames = Enumerable.Range(0, qualitiesMap.Columns - 1).Select(x => Content.SlidingWindowRanges[x].Start + " - " + Content.SlidingWindowRanges[x].End).Concat(new List<string> { "Training" });
     94      qualitiesMap.RowNames = Enumerable.Range(1, qualitiesMap.Rows).Select(x => "M" + x);
     95
     96      double min = 0, max = 0;
     97      foreach (var q in qualitiesMap) {
     98        if (min > q) min = q;
     99        if (max < q) max = q;
     100      }
     101
     102      enhancedStringConvertibleMatrixView.Minimum = min;
     103      enhancedStringConvertibleMatrixView.Maximum = max;
     104      enhancedStringConvertibleMatrixView.Content = qualitiesMap;
     105    }
     106
     107    private void bestSolutionCollectionQualitiesCalculationProgress(object sender, ProgressChangedEventArgs e) {
     108      progress.ProgressValue = e.ProgressPercentage / 100.0;
     109    }
     110
     111    private void bestSolutionCollectionQualitiesUpdated(object sender, EventArgs e) {
     112      SetMatrixContent(Content.SlidingWindowQualities);
     113    }
     114    #endregion
     115
     116    protected override void SetEnabledStateOfControls() {
     117      base.SetEnabledStateOfControls();
     118      // TODO: Enable or disable controls based on whether the content is null or the view is set readonly
     119    }
     120
     121    #region Event Handlers (child controls)
     122    private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e) {
     123      var combobox = (ComboBox)sender;
     124      switch ((string)combobox.SelectedItem) {
     125        case "Pearson R2": {
     126            Content.QualityMeasure = SlidingWindowBestSolutionsCollection.QualityMeasures.PEARSON;
     127            break;
     128          }
     129        case "Mean Squared Error": {
     130            Content.QualityMeasure = SlidingWindowBestSolutionsCollection.QualityMeasures.MSE;
     131            break;
     132          }
     133      }
    61134    }
    62135
     
    64137      var dataGridView = (DataGridView)sender;
    65138      var cell = dataGridView.SelectedCells[0];
    66       var bestSolutions = Content.BestSolutions.Values.ToList();
     139      var bestSolutions = Content.SlidingWindowBestSolutions.Values.ToList();
    67140      var tree = bestSolutions[cell.RowIndex];
    68141      var model = Content.CreateModel(tree, Content.Interpreter);
     
    75148      }
    76149    }
    77 
    78     #region Event Handlers (Content)
    79     // TODO: Put event handlers of the content here
    80150    #endregion
    81 
    82     protected override void OnContentChanged() {
    83       base.OnContentChanged();
    84       if (Content == null) {
    85         // TODO: Add code when content has been changed and is null
    86       } else {
    87         // TODO: Add code when content has been changed and is not null
    88         UpdateQualitiesMap();
    89       }
    90     }
    91 
    92     protected override void SetEnabledStateOfControls() {
    93       base.SetEnabledStateOfControls();
    94       // TODO: Enable or disable controls based on whether the content is null or the view is set readonly
    95     }
    96 
    97     #region Event Handlers (child controls)
    98     // TODO: Put event handlers of child controls here.
    99     #endregion
    100 
    101     private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e) {
    102       var combobox = (ComboBox)sender;
    103       switch ((string)combobox.SelectedItem) {
    104         case "Pearson R2": {
    105             qualityMeasure = (int)QualityMeasures.PEARSON;
    106             break;
    107           }
    108         case "Mean Squared Error": {
    109             qualityMeasure = (int)QualityMeasures.MSE;
    110             break;
    111           }
    112       }
    113       UpdateQualitiesMap();
    114     }
    115 
    116     private void UpdateQualitiesMap() {
    117       var bestSolutions = Content.BestSolutions.Values.ToList();
    118       var swPositions = Content.BestSolutions.Keys.ToList();
    119       var qualitiesMap = new DoubleMatrix(bestSolutions.Count, swPositions.Count + 1);
    120       qualitiesMap.ColumnNames = swPositions.Select(x => x.Item1 + "-" + x.Item2).Concat(new List<string> { "Training" });
    121       qualitiesMap.RowNames = Enumerable.Range(1, bestSolutions.Count).Select(x => "M" + x);
    122       double min = 0, max = 0;
    123 
    124       for (int i = 0; i < qualitiesMap.Columns - 1; ++i) {
    125         var pos = swPositions[i];
    126         var rows = Enumerable.Range(pos.Item1, pos.Item2 - pos.Item1).ToList();
    127 
    128         for (int j = 0; j < qualitiesMap.Rows; ++j) {
    129           var tree = bestSolutions[j];
    130           var q = CalculateQuality(tree, rows);
    131           if (min > q) min = q;
    132           if (max < q) max = q;
    133           qualitiesMap[j, i] = q;
    134         }
    135       }
    136       // deal separately with the last column which represents the whole training partition interval
    137       for (int j = 0; j < qualitiesMap.Rows; ++j) {
    138         var tree = bestSolutions[j];
    139         var q = CalculateQuality(tree, Content.ProblemData.TrainingIndices);
    140         if (min > q) min = q;
    141         if (max < q) max = q;
    142         qualitiesMap[j, qualitiesMap.Columns - 1] = q;
    143       }
    144 
    145       enhancedStringConvertibleMatrixView.Minimum = min;
    146       enhancedStringConvertibleMatrixView.Maximum = max;
    147       enhancedStringConvertibleMatrixView.Content = qualitiesMap;
    148     }
    149 
    150     private string GetTargetVariable(IDataAnalysisProblemData problemData) {
    151       var regressionProblemData = problemData as IRegressionProblemData;
    152       var classificationProblemData = problemData as IClassificationProblemData;
    153       if (regressionProblemData != null) return regressionProblemData.TargetVariable;
    154       if (classificationProblemData != null) return classificationProblemData.TargetVariable;
    155       throw new NotSupportedException();
    156     }
    157 
    158     private double CalculateQuality(ISymbolicExpressionTree tree, IEnumerable<int> rows) {
    159       var estimatedValues = Content.Interpreter.GetSymbolicExpressionTreeValues(tree, Content.ProblemData.Dataset, rows);
    160       var originalValues = Content.ProblemData.Dataset.GetDoubleValues(GetTargetVariable(Content.ProblemData), rows);
    161       double quality = 0;
    162       var errorState = new OnlineCalculatorError();
    163       switch ((QualityMeasures)qualityMeasure) {
    164         case QualityMeasures.PEARSON:
    165           quality = OnlinePearsonsRSquaredCalculator.Calculate(estimatedValues, originalValues, out errorState);
    166           break;
    167         case QualityMeasures.MSE:
    168           quality = OnlineMeanSquaredErrorCalculator.Calculate(estimatedValues, originalValues, out errorState);
    169           break;
    170       }
    171       return errorState == OnlineCalculatorError.None ? quality : double.NaN;
    172     }
    173151  }
    174152}
  • branches/Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SlidingWindow/SlidingWindowAnalyzer.cs

    r10413 r10720  
    3131using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    3232
     33
    3334namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    3435  [StorableClass]
     
    4546    private const string TerminateSlidingWindowParameterName = "TerminateSlidingWindow";
    4647    private const string InterpreterParameterName = "SymbolicExpressionTreeInterpreter";
     48    protected const string BestSlidingWindowSolutionsResultName = "Best Sliding Window Solutions";
    4749
    4850    #region parameter properties
     
    179181
    180182    private void SaveBestSolution() {
    181       var bestSolutionsCollection = (SlidingWindowBestSolutionsCollection)ResultCollection["Best Solutions"].Value;
     183      var bestSolutionsCollection = (SlidingWindowBestSolutionsCollection)ResultCollection[BestSlidingWindowSolutionsResultName].Value;
    182184
    183       if (bestSolutionsCollection.ProblemData == null)
    184         bestSolutionsCollection.ProblemData = ProblemData;
    185 
    186       if (bestSolutionsCollection.Interpreter == null)
    187         bestSolutionsCollection.Interpreter = Interpreter;
     185      bestSolutionsCollection.ProblemData = ProblemData;
     186      bestSolutionsCollection.Interpreter = Interpreter;
     187      bestSolutionsCollection.ApplyLinearScaling = ApplyLinearScalingParameter.ActualValue.Value;
    188188
    189189      var fitnessPartition = FitnessCalculationPartitionParameter.ActualValue;
    190190      var best = FindBestIndividual();
    191       var range = new Tuple<int, int>(fitnessPartition.Start, fitnessPartition.End);
     191      var range = new SlidingWindowRange(fitnessPartition.Start, fitnessPartition.End);
    192192
    193193      bestSolutionsCollection[range] = best;
  • branches/Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SlidingWindow/SlidingWindowBestSolutionsCollection.cs

    r10413 r10720  
    2020#endregion
    2121
     22using System;
    2223using System.Collections.Generic;
     24using System.ComponentModel;
     25using System.Linq;
    2326using HeuristicLab.Common;
    2427using HeuristicLab.Core;
     
    2629using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2730
    28 using SlidingWindowRange = System.Tuple<int, int>;
    29 
    3031namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    3132  [StorableClass]
     
    3334  public abstract class SlidingWindowBestSolutionsCollection : Item {
    3435    [Storable]
    35     private Dictionary<SlidingWindowRange, ISymbolicExpressionTree> bestSolutions;
    36     public Dictionary<SlidingWindowRange, ISymbolicExpressionTree> BestSolutions {
    37       get { return bestSolutions; }
    38       set { bestSolutions = value; }
     36    private List<SlidingWindowRange> slidingWindowRanges;
     37    public List<SlidingWindowRange> SlidingWindowRanges {
     38      get { return slidingWindowRanges; }
     39      private set { slidingWindowRanges = value; }
     40    }
     41
     42    [Storable(AllowOneWay = true, Name = "bestSolutions")]
     43    private Dictionary<Tuple<int, int>, ISymbolicExpressionTree> StorableBestSolutions {
     44      set {
     45        var bestSolutions = value;
     46        var ranges = bestSolutions.Keys.OrderBy(x => x.Item1).ToList();
     47        slidingWindowRanges = ranges.Select(x => new SlidingWindowRange(x.Item1, x.Item2)).ToList();
     48        slidingWindowBestSolutions = new Dictionary<SlidingWindowRange, ISymbolicExpressionTree>();
     49        for (int i = 0; i < slidingWindowRanges.Count; ++i) {
     50          slidingWindowBestSolutions.Add(slidingWindowRanges[i], bestSolutions[ranges[i]]);
     51        }
     52      }
     53    }
     54
     55    [Storable]
     56    private Dictionary<SlidingWindowRange, ISymbolicExpressionTree> slidingWindowBestSolutions;
     57    public Dictionary<SlidingWindowRange, ISymbolicExpressionTree> SlidingWindowBestSolutions {
     58      get { return slidingWindowBestSolutions; }
     59      set { slidingWindowBestSolutions = value; }
    3960    }
    4061
     
    5273      set { interpreter = value; }
    5374    }
     75
     76    [Storable]
     77    private bool applyLinearScaling;
     78    public bool ApplyLinearScaling {
     79      get { return applyLinearScaling; }
     80      set { applyLinearScaling = value; }
     81    }
     82
    5483    [StorableHook(HookType.AfterDeserialization)]
    5584    private void AfterDeserialization() {
     85      if (bw == null) {
     86        bw = new BackgroundWorker();
     87        bw.WorkerSupportsCancellation = true;
     88        bw.WorkerReportsProgress = true;
     89        bw.DoWork += CalculateQualities;
     90      }
     91    }
     92
     93    public double[,] SlidingWindowQualities { get; set; }
     94
     95    private BackgroundWorker bw;
     96
     97    public enum QualityMeasures { PEARSON, MSE };
     98
     99    private QualityMeasures qualityMeasure;
     100    public QualityMeasures QualityMeasure {
     101      get { return qualityMeasure; }
     102      set {
     103        if (qualityMeasure != value) {
     104          qualityMeasure = value;
     105          CalculateQualities();
     106        }
     107      }
     108    }
     109
     110    public bool QualitiesCalculationInProgress {
     111      get { return bw.IsBusy; }
     112    }
     113
     114    public event ProgressChangedEventHandler QualitiesCalculationProgress {
     115      add { bw.ProgressChanged += value; }
     116      remove { bw.ProgressChanged -= value; }
     117    }
     118
     119    public event RunWorkerCompletedEventHandler QualitiesCalculationCompleted {
     120      add { bw.RunWorkerCompleted += value; }
     121      remove { bw.RunWorkerCompleted -= value; }
     122    }
     123
     124    public event EventHandler QualitiesUpdated;
     125    private void OnQualitiesUpdated(object sender, EventArgs e) {
     126      var updated = QualitiesUpdated;
     127      if (updated != null) { updated(sender, e); }
    56128    }
    57129
     
    60132    protected SlidingWindowBestSolutionsCollection(SlidingWindowBestSolutionsCollection original, Cloner cloner)
    61133      : base(original, cloner) {
    62       this.bestSolutions = original.bestSolutions;
     134      this.slidingWindowBestSolutions = original.slidingWindowBestSolutions;
    63135      this.problemData = original.problemData;
    64136      this.interpreter = original.interpreter;
     137      this.applyLinearScaling = original.ApplyLinearScaling;
    65138    }
    66139    protected SlidingWindowBestSolutionsCollection() {
    67       bestSolutions = new Dictionary<SlidingWindowRange, ISymbolicExpressionTree>();
     140      slidingWindowBestSolutions = new Dictionary<SlidingWindowRange, ISymbolicExpressionTree>();
     141      slidingWindowRanges = new List<SlidingWindowRange>();
     142      qualityMeasure = QualityMeasures.PEARSON;
     143
     144      bw = new BackgroundWorker();
     145      bw.WorkerSupportsCancellation = true;
     146      bw.WorkerReportsProgress = true;
     147
     148      bw.DoWork += CalculateQualities;
    68149    }
    69150
    70151    public bool ContainsKey(SlidingWindowRange key) {
    71       return bestSolutions.ContainsKey(key);
     152      return slidingWindowBestSolutions.ContainsKey(key);
    72153    }
    73154
    74155    public ISymbolicExpressionTree this[SlidingWindowRange key] {
    75156      get {
    76         return bestSolutions[key];
     157        return slidingWindowBestSolutions[key];
    77158      }
    78159      set {
    79         if (bestSolutions.ContainsKey(key))
    80           bestSolutions[key] = value;
    81         else
    82           bestSolutions.Add(key, value);
     160        AddSolution(key, value); // this should be fast so there's no need for a background worker
     161        OnQualitiesUpdated(this, EventArgs.Empty);
    83162      }
    84163    }
    85164
    86165    public void Add(SlidingWindowRange range, ISymbolicExpressionTree solution) {
    87       bestSolutions.Add(range, solution);
     166      if (!slidingWindowBestSolutions.ContainsKey(range)) {
     167        slidingWindowBestSolutions.Add(range, solution);
     168        slidingWindowRanges.Add(range);
     169      } else {
     170        slidingWindowBestSolutions[range] = solution;
     171      }
    88172    }
    89173
    90174    public void Clear() {
    91       if (bestSolutions != null) bestSolutions.Clear();
     175      if (slidingWindowBestSolutions != null) slidingWindowBestSolutions.Clear();
     176      if (slidingWindowRanges != null) slidingWindowRanges.Clear();
    92177    }
    93178
     
    96181
    97182    public abstract ISymbolicDataAnalysisSolution CreateSolution(ISymbolicDataAnalysisModel model, IDataAnalysisProblemData problemData);
     183
     184    private void AddSolution(SlidingWindowRange range, ISymbolicExpressionTree solution) {
     185      // add a solution and update the qualities matrix
     186      Add(range, solution);
     187
     188      var solutions = slidingWindowRanges.Select(x => slidingWindowBestSolutions[x]).ToList();
     189
     190      var nRows = solutions.Count;
     191      var nCols = nRows + 1; // an extra column corresponding to the whole trainig partition
     192
     193      var trainingIndices = problemData.TrainingIndices.ToList();
     194      var matrix = new double[nRows, nCols];
     195      List<int> rows;
     196      // copy old qualities into the new matrix
     197      for (int i = 0; i < nRows - 1; ++i) {
     198        for (int j = 0; j < nCols - 1; ++j) {
     199          matrix[i, j] = SlidingWindowQualities[i, j];
     200        }
     201      }
     202      // copy qualities of new solution into the new matrix
     203      for (int i = 0; i < nCols; ++i) {
     204        rows = i == nCols - 1 ? trainingIndices : Enumerable.Range(slidingWindowRanges[i].Start, slidingWindowRanges[i].Size).ToList();
     205        matrix[nRows - 1, i] = CalculateQuality(solution, rows);
     206      }
     207      // shift old training qualities one column to the right
     208      rows = Enumerable.Range(range.Start, range.Size).ToList();
     209      for (int i = 0; i < nRows; ++i) {
     210        matrix[i, nCols - 1] = matrix[i, nCols - 2];
     211        matrix[i, nCols - 2] = CalculateQuality(solutions[i], rows);
     212      }
     213      // replace old matrix with new matrix
     214      SlidingWindowQualities = matrix;
     215    }
     216
     217    private void CalculateQualities(object sender, DoWorkEventArgs e) {
     218      var worker = sender as BackgroundWorker;
     219      if (worker == null) return;
     220      if (worker.CancellationPending) {
     221        e.Cancel = true;
     222        return;
     223      }
     224
     225      var ranges = SlidingWindowRanges;
     226      var solutions = ranges.Select(x => SlidingWindowBestSolutions[x]).ToList();
     227
     228      int rows = solutions.Count;
     229      int columns = ranges.Count + 1;
     230
     231      SlidingWindowQualities = new double[rows, columns];
     232
     233      for (int i = 0; i < rows; ++i) {
     234        if (worker.CancellationPending) {
     235          e.Cancel = true;
     236          return;
     237        }
     238
     239        var solution = solutions[i];
     240        for (int j = 0; j < columns; ++j) {
     241          var range = (j == columns - 1) ? ProblemData.TrainingIndices : Enumerable.Range(ranges[j].Start, ranges[j].Size);
     242          var q = CalculateQuality(solution, range);
     243
     244          SlidingWindowQualities[i, j] = q;
     245        }
     246
     247        worker.ReportProgress((int)Math.Round(i * 100.0 / rows));
     248      }
     249    }
     250
     251    public void CalculateQualities() {
     252      bw.RunWorkerAsync();
     253    }
     254
     255    private string GetTargetVariable(IDataAnalysisProblemData problemData) {
     256      var regressionProblemData = problemData as IRegressionProblemData;
     257      var classificationProblemData = problemData as IClassificationProblemData;
     258      if (regressionProblemData != null) return regressionProblemData.TargetVariable;
     259      if (classificationProblemData != null) return classificationProblemData.TargetVariable;
     260      throw new NotSupportedException();
     261    }
     262
     263    private double CalculateQuality(ISymbolicExpressionTree tree, IEnumerable<int> rows) {
     264      var estimatedValues = Interpreter.GetSymbolicExpressionTreeValues(tree, ProblemData.Dataset, rows);
     265      var originalValues = ProblemData.Dataset.GetDoubleValues(GetTargetVariable(ProblemData), rows);
     266      double quality = 0;
     267      var errorState = new OnlineCalculatorError();
     268      switch (QualityMeasure) {
     269        case QualityMeasures.PEARSON:
     270          quality = OnlinePearsonsRSquaredCalculator.Calculate(estimatedValues, originalValues, out errorState);
     271          break;
     272        case QualityMeasures.MSE:
     273          quality = OnlineMeanSquaredErrorCalculator.Calculate(estimatedValues, originalValues, out errorState);
     274          break;
     275      }
     276      return errorState == OnlineCalculatorError.None ? quality : double.NaN;
     277    }
     278  }
     279
     280  public class SlidingWindowRange : IEquatable<SlidingWindowRange> {
     281    private readonly Tuple<int, int> tuple;
     282
     283    public int Start { get { return tuple.Item1; } }
     284
     285    public int End { get { return tuple.Item2; } }
     286
     287    public SlidingWindowRange(int start, int end) {
     288      if (start > end) throw new ArgumentException("SlidingWindowRange: Start cannot be greater than End.");
     289      tuple = new Tuple<int, int>(start, end);
     290    }
     291
     292    public bool Equals(SlidingWindowRange other) {
     293      return tuple.Equals(other.tuple);
     294    }
     295
     296    public override int GetHashCode() {
     297      return tuple.GetHashCode();
     298    }
     299
     300    public int Size {
     301      get { return End - Start; }
     302    }
    98303  }
    99304}
Note: See TracChangeset for help on using the changeset viewer.