Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.Designer.cs	(revision 16434)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.Designer.cs	(revision 16435)
@@ -19,4 +19,6 @@
  */
 #endregion
+
+
 namespace HeuristicLab.Problems.DataAnalysis.Views {
   partial class RegressionSolutionVariableImpactsView {
@@ -44,59 +46,76 @@
     /// </summary>
     private void InitializeComponent() {
+      this.ascendingCheckBox = new System.Windows.Forms.CheckBox();
+      this.sortByLabel = new System.Windows.Forms.Label();
+      this.sortByComboBox = new System.Windows.Forms.ComboBox();
+      this.factorVarReplComboBox = new System.Windows.Forms.ComboBox();
+      this.factorVarReplacementLabel = new System.Windows.Forms.Label();
+      this.replacementComboBox = new System.Windows.Forms.ComboBox();
+      this.numericVarReplacementLabel = new System.Windows.Forms.Label();
+      this.dataPartitionLabel = new System.Windows.Forms.Label();
+      this.dataPartitionComboBox = new System.Windows.Forms.ComboBox();
       this.variableImactsArrayView = new HeuristicLab.Data.Views.StringConvertibleArrayView();
-      this.dataPartitionComboBox = new System.Windows.Forms.ComboBox();
-      this.dataPartitionLabel = new System.Windows.Forms.Label();
-      this.numericVarReplacementLabel = new System.Windows.Forms.Label();
-      this.replacementComboBox = new System.Windows.Forms.ComboBox();
-      this.factorVarReplacementLabel = new System.Windows.Forms.Label();
-      this.factorVarReplComboBox = new System.Windows.Forms.ComboBox();
       this.SuspendLayout();
       // 
-      // variableImactsArrayView
-      // 
-      this.variableImactsArrayView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
-            | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.variableImactsArrayView.Caption = "StringConvertibleArray View";
-      this.variableImactsArrayView.Content = null;
-      this.variableImactsArrayView.Location = new System.Drawing.Point(3, 84);
-      this.variableImactsArrayView.Name = "variableImactsArrayView";
-      this.variableImactsArrayView.ReadOnly = true;
-      this.variableImactsArrayView.Size = new System.Drawing.Size(363, 278);
-      this.variableImactsArrayView.TabIndex = 2;
-      // 
-      // dataPartitionComboBox
-      // 
-      this.dataPartitionComboBox.FormattingEnabled = true;
-      this.dataPartitionComboBox.Items.AddRange(new object[] {
-            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.Training,
-            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.Test,
-            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.All});
-      this.dataPartitionComboBox.Location = new System.Drawing.Point(197, 3);
-      this.dataPartitionComboBox.Name = "dataPartitionComboBox";
-      this.dataPartitionComboBox.Size = new System.Drawing.Size(121, 21);
-      this.dataPartitionComboBox.TabIndex = 1;
-      this.dataPartitionComboBox.SelectedIndexChanged += new System.EventHandler(this.dataPartitionComboBox_SelectedIndexChanged);
-      // 
-      // dataPartitionLabel
-      // 
-      this.dataPartitionLabel.AutoSize = true;
-      this.dataPartitionLabel.Location = new System.Drawing.Point(3, 6);
-      this.dataPartitionLabel.Name = "dataPartitionLabel";
-      this.dataPartitionLabel.Size = new System.Drawing.Size(73, 13);
-      this.dataPartitionLabel.TabIndex = 0;
-      this.dataPartitionLabel.Text = "Data partition:";
-      // 
-      // numericVarReplacementLabel
-      // 
-      this.numericVarReplacementLabel.AutoSize = true;
-      this.numericVarReplacementLabel.Location = new System.Drawing.Point(3, 33);
-      this.numericVarReplacementLabel.Name = "numericVarReplacementLabel";
-      this.numericVarReplacementLabel.Size = new System.Drawing.Size(173, 13);
-      this.numericVarReplacementLabel.TabIndex = 2;
-      this.numericVarReplacementLabel.Text = "Replacement for numeric variables:";
+      // ascendingCheckBox
+      // 
+      this.ascendingCheckBox.AutoSize = true;
+      this.ascendingCheckBox.Location = new System.Drawing.Point(534, 6);
+      this.ascendingCheckBox.Name = "ascendingCheckBox";
+      this.ascendingCheckBox.Size = new System.Drawing.Size(76, 17);
+      this.ascendingCheckBox.TabIndex = 7;
+      this.ascendingCheckBox.Text = "Ascending";
+      this.ascendingCheckBox.UseVisualStyleBackColor = true;
+      this.ascendingCheckBox.CheckedChanged += new System.EventHandler(this.ascendingCheckBox_CheckedChanged);
+      // 
+      // sortByLabel
+      // 
+      this.sortByLabel.AutoSize = true;
+      this.sortByLabel.Location = new System.Drawing.Point(324, 6);
+      this.sortByLabel.Name = "sortByLabel";
+      this.sortByLabel.Size = new System.Drawing.Size(77, 13);
+      this.sortByLabel.TabIndex = 4;
+      this.sortByLabel.Text = "Sorting criteria:";
+      // 
+      // sortByComboBox
+      // 
+      this.sortByComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.sortByComboBox.FormattingEnabled = true;
+      this.sortByComboBox.Items.AddRange(new object[] {
+            HeuristicLab.Problems.DataAnalysis.Views.RegressionSolutionVariableImpactsView.SortingCriteria.ImpactValue,
+            HeuristicLab.Problems.DataAnalysis.Views.RegressionSolutionVariableImpactsView.SortingCriteria.Occurrence,
+            HeuristicLab.Problems.DataAnalysis.Views.RegressionSolutionVariableImpactsView.SortingCriteria.VariableName});
+      this.sortByComboBox.Location = new System.Drawing.Point(407, 3);
+      this.sortByComboBox.Name = "sortByComboBox";
+      this.sortByComboBox.Size = new System.Drawing.Size(121, 21);
+      this.sortByComboBox.TabIndex = 5;
+      this.sortByComboBox.SelectedIndexChanged += new System.EventHandler(this.sortByComboBox_SelectedIndexChanged);
+      // 
+      // factorVarReplComboBox
+      // 
+      this.factorVarReplComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.factorVarReplComboBox.FormattingEnabled = true;
+      this.factorVarReplComboBox.Items.AddRange(new object[] {
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Best,
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Mode,
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Shuffle});
+      this.factorVarReplComboBox.Location = new System.Drawing.Point(197, 57);
+      this.factorVarReplComboBox.Name = "factorVarReplComboBox";
+      this.factorVarReplComboBox.Size = new System.Drawing.Size(121, 21);
+      this.factorVarReplComboBox.TabIndex = 1;
+      this.factorVarReplComboBox.SelectedIndexChanged += new System.EventHandler(this.replacementComboBox_SelectedIndexChanged);
+      // 
+      // factorVarReplacementLabel
+      // 
+      this.factorVarReplacementLabel.AutoSize = true;
+      this.factorVarReplacementLabel.Location = new System.Drawing.Point(3, 60);
+      this.factorVarReplacementLabel.Name = "factorVarReplacementLabel";
+      this.factorVarReplacementLabel.Size = new System.Drawing.Size(188, 13);
+      this.factorVarReplacementLabel.TabIndex = 0;
+      this.factorVarReplacementLabel.Text = "Replacement for categorical variables:";
       // 
       // replacementComboBox
       // 
+      this.replacementComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
       this.replacementComboBox.FormattingEnabled = true;
       this.replacementComboBox.Items.AddRange(new object[] {
@@ -111,25 +130,48 @@
       this.replacementComboBox.SelectedIndexChanged += new System.EventHandler(this.replacementComboBox_SelectedIndexChanged);
       // 
-      // factorVarReplacementLabel
-      // 
-      this.factorVarReplacementLabel.AutoSize = true;
-      this.factorVarReplacementLabel.Location = new System.Drawing.Point(3, 60);
-      this.factorVarReplacementLabel.Name = "factorVarReplacementLabel";
-      this.factorVarReplacementLabel.Size = new System.Drawing.Size(188, 13);
-      this.factorVarReplacementLabel.TabIndex = 0;
-      this.factorVarReplacementLabel.Text = "Replacement for categorical variables:";
-      // 
-      // factorVarReplComboBox
-      // 
-      this.factorVarReplComboBox.FormattingEnabled = true;
-      this.factorVarReplComboBox.Items.AddRange(new object[] {
-            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Best,
-            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Mode,
-            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Shuffle});
-      this.factorVarReplComboBox.Location = new System.Drawing.Point(197, 57);
-      this.factorVarReplComboBox.Name = "factorVarReplComboBox";
-      this.factorVarReplComboBox.Size = new System.Drawing.Size(121, 21);
-      this.factorVarReplComboBox.TabIndex = 1;
-      this.factorVarReplComboBox.SelectedIndexChanged += new System.EventHandler(this.replacementComboBox_SelectedIndexChanged);
+      // numericVarReplacementLabel
+      // 
+      this.numericVarReplacementLabel.AutoSize = true;
+      this.numericVarReplacementLabel.Location = new System.Drawing.Point(3, 33);
+      this.numericVarReplacementLabel.Name = "numericVarReplacementLabel";
+      this.numericVarReplacementLabel.Size = new System.Drawing.Size(173, 13);
+      this.numericVarReplacementLabel.TabIndex = 2;
+      this.numericVarReplacementLabel.Text = "Replacement for numeric variables:";
+      // 
+      // dataPartitionLabel
+      // 
+      this.dataPartitionLabel.AutoSize = true;
+      this.dataPartitionLabel.Location = new System.Drawing.Point(3, 6);
+      this.dataPartitionLabel.Name = "dataPartitionLabel";
+      this.dataPartitionLabel.Size = new System.Drawing.Size(73, 13);
+      this.dataPartitionLabel.TabIndex = 0;
+      this.dataPartitionLabel.Text = "Data partition:";
+      // 
+      // dataPartitionComboBox
+      // 
+      this.dataPartitionComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.dataPartitionComboBox.FormattingEnabled = true;
+      this.dataPartitionComboBox.Items.AddRange(new object[] {
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.Training,
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.Test,
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.All});
+      this.dataPartitionComboBox.Location = new System.Drawing.Point(197, 3);
+      this.dataPartitionComboBox.Name = "dataPartitionComboBox";
+      this.dataPartitionComboBox.Size = new System.Drawing.Size(121, 21);
+      this.dataPartitionComboBox.TabIndex = 1;
+      this.dataPartitionComboBox.SelectedIndexChanged += new System.EventHandler(this.dataPartitionComboBox_SelectedIndexChanged);
+      // 
+      // variableImactsArrayView
+      // 
+      this.variableImactsArrayView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.variableImactsArrayView.Caption = "StringConvertibleArray View";
+      this.variableImactsArrayView.Content = null;
+      this.variableImactsArrayView.Location = new System.Drawing.Point(3, 84);
+      this.variableImactsArrayView.Name = "variableImactsArrayView";
+      this.variableImactsArrayView.ReadOnly = true;
+      this.variableImactsArrayView.Size = new System.Drawing.Size(706, 278);
+      this.variableImactsArrayView.TabIndex = 2;
       // 
       // RegressionSolutionVariableImpactsView
@@ -137,4 +179,7 @@
       this.AllowDrop = true;
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.ascendingCheckBox);
+      this.Controls.Add(this.sortByLabel);
+      this.Controls.Add(this.sortByComboBox);
       this.Controls.Add(this.factorVarReplComboBox);
       this.Controls.Add(this.factorVarReplacementLabel);
@@ -145,5 +190,6 @@
       this.Controls.Add(this.variableImactsArrayView);
       this.Name = "RegressionSolutionVariableImpactsView";
-      this.Size = new System.Drawing.Size(369, 365);
+      this.Size = new System.Drawing.Size(712, 365);
+      this.VisibleChanged += new System.EventHandler(this.RegressionSolutionVariableImpactsView_VisibleChanged);
       this.ResumeLayout(false);
       this.PerformLayout();
@@ -160,4 +206,7 @@
     private System.Windows.Forms.Label factorVarReplacementLabel;
     private System.Windows.Forms.ComboBox factorVarReplComboBox;
+    private System.Windows.Forms.Label sortByLabel;
+    private System.Windows.Forms.ComboBox sortByComboBox;
+    private System.Windows.Forms.CheckBox ascendingCheckBox;
   }
 }
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs	(revision 16434)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs	(revision 16435)
@@ -19,10 +19,13 @@
  */
 #endregion
+
 using System;
+using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using System.Threading.Tasks;
+using HeuristicLab.Common;
 using HeuristicLab.Data;
 using HeuristicLab.MainForm;
-using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
 
 namespace HeuristicLab.Problems.DataAnalysis.Views {
@@ -30,4 +33,11 @@
   [Content(typeof(IRegressionSolution))]
   public partial class RegressionSolutionVariableImpactsView : DataAnalysisSolutionEvaluationView {
+    private CancellationTokenSource cancellationToken = new CancellationTokenSource();
+    private enum SortingCriteria {
+      ImpactValue,
+      Occurrence,
+      VariableName
+    }
+    private List<Tuple<string, double>> rawVariableImpacts = new List<Tuple<string, double>>();
 
     public new IRegressionSolution Content {
@@ -41,10 +51,12 @@
       : base() {
       InitializeComponent();
+
+      //Set the default values
       this.dataPartitionComboBox.SelectedIndex = 0;
-      this.replacementComboBox.SelectedIndex = 0;
+      this.replacementComboBox.SelectedIndex = 3;
       this.factorVarReplComboBox.SelectedIndex = 0;
-    }
-
-    #region events
+      this.sortByComboBox.SelectedItem = SortingCriteria.ImpactValue;
+    }
+
     protected override void RegisterContentEvents() {
       base.RegisterContentEvents();
@@ -72,45 +84,121 @@
         variableImactsArrayView.Content = null;
       } else {
-        UpdateVariableImpacts();
-      }
-    }
-
-    private void UpdateVariableImpacts() {
-      if (Content == null || replacementComboBox.SelectedIndex < 0
-        || factorVarReplComboBox.SelectedIndex < 0
-        || dataPartitionComboBox.SelectedIndex < 0) return;
+        UpdateVariableImpact();
+      }
+    }
+
+    private void RegressionSolutionVariableImpactsView_VisibleChanged(object sender, EventArgs e) {
+      cancellationToken.Cancel();
+    }
+
+
+    private void dataPartitionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      UpdateVariableImpact();
+    }
+
+    private void replacementComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      UpdateVariableImpact();
+    }
+
+    private void sortByComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      //Update the default ordering (asc,desc), but remove the eventHandler beforehand (otherwise the data would be ordered twice)
+      ascendingCheckBox.CheckedChanged -= ascendingCheckBox_CheckedChanged;
+      ascendingCheckBox.Checked = (SortingCriteria)sortByComboBox.SelectedItem != SortingCriteria.ImpactValue;
+      ascendingCheckBox.CheckedChanged += ascendingCheckBox_CheckedChanged;
+
+      UpdateOrdering();
+    }
+
+    private void ascendingCheckBox_CheckedChanged(object sender, EventArgs e) {
+      UpdateOrdering();
+    }
+
+
+    private async void UpdateVariableImpact() {
+      IProgress progress;
+
+      //Check if the selection is valid
+      if (Content == null) { return; }
+      if (replacementComboBox.SelectedIndex < 0) { return; }
+      if (dataPartitionComboBox.SelectedIndex < 0) { return; }
+      if (factorVarReplComboBox.SelectedIndex < 0) { return; }
+
+      //Prepare arguments
       var mainForm = (MainForm.WindowsForms.MainForm)MainFormManager.MainForm;
+      var replMethod = (RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum)replacementComboBox.Items[replacementComboBox.SelectedIndex];
+      var factorReplMethod = (RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum)factorVarReplComboBox.Items[factorVarReplComboBox.SelectedIndex];
+      var dataPartition = (RegressionSolutionVariableImpactsCalculator.DataPartitionEnum)dataPartitionComboBox.SelectedItem;
+
       variableImactsArrayView.Caption = Content.Name + " Variable Impacts";
-      var replMethod =
-         (RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum)
-           replacementComboBox.Items[replacementComboBox.SelectedIndex];
-      var factorReplMethod =
-        (RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum)
-          factorVarReplComboBox.Items[factorVarReplComboBox.SelectedIndex];
-      var dataPartition =
-        (RegressionSolutionVariableImpactsCalculator.DataPartitionEnum)dataPartitionComboBox.SelectedItem;
-
-      Task.Factory.StartNew(() => {
-        try {
-          mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
-
-          var impacts = RegressionSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod, factorReplMethod);
-          var impactArray = new DoubleArray(impacts.Select(i => i.Item2).ToArray());
-          impactArray.ElementNames = impacts.Select(i => i.Item1);
-          variableImactsArrayView.Content = (DoubleArray)impactArray.AsReadOnly();
-        } finally {
-          mainForm.RemoveOperationProgressFromView(this);
-        }
-      });
-    }
-
-    #endregion
-
-    private void dataPartitionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      UpdateVariableImpacts();
-    }
-
-    private void replacementComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      UpdateVariableImpacts();
+      progress = mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
+      progress.ProgressValue = 0;
+
+      cancellationToken = new CancellationTokenSource();
+      //Remember the original ordering of the variables
+      try {
+        var impacts = await Task.Run(() => RegressionSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod, factorReplMethod,
+          (i, s) => {
+            progress.ProgressValue = i;
+            progress.Status = s;
+            return cancellationToken.Token.IsCancellationRequested;
+          }), cancellationToken.Token);
+
+        if (cancellationToken.Token.IsCancellationRequested) { return; }
+        var problemData = Content.ProblemData;
+        var inputvariables = new HashSet<string>(problemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
+        var originalVariableOrdering = problemData.Dataset.VariableNames
+          .Where(v => inputvariables.Contains(v))
+          .Where(v => problemData.Dataset.VariableHasType<double>(v) || problemData.Dataset.VariableHasType<string>(v))
+          .ToList();
+
+        rawVariableImpacts.Clear();
+        originalVariableOrdering.ForEach(v => rawVariableImpacts.Add(new Tuple<string, double>(v, impacts.First(vv => vv.Item1 == v).Item2)));
+        UpdateOrdering();
+      } finally {
+        ((MainForm.WindowsForms.MainForm)MainFormManager.MainForm).RemoveOperationProgressFromView(this);
+      }
+    }
+
+    /// <summary>
+    /// Updates the <see cref="variableImactsArrayView"/> according to the selected ordering <see cref="ascendingCheckBox"/> of the selected Column <see cref="sortByComboBox"/>
+    /// The default is "Descending" by "VariableImpact" (as in previous versions)
+    /// </summary>
+    private void UpdateOrdering() {
+      //Check if valid sortingCriteria is selected and data exists
+      if (sortByComboBox.SelectedIndex == -1) { return; }
+      if (rawVariableImpacts == null) { return; }
+      if (!rawVariableImpacts.Any()) { return; }
+
+      var selectedItem = (SortingCriteria)sortByComboBox.SelectedItem;
+      bool ascending = ascendingCheckBox.Checked;
+
+      IEnumerable<Tuple<string, double>> orderedEntries = null;
+
+      //Sort accordingly
+      switch (selectedItem) {
+        case SortingCriteria.ImpactValue:
+          orderedEntries = rawVariableImpacts.OrderBy(v => v.Item2);
+          break;
+        case SortingCriteria.Occurrence:
+          orderedEntries = rawVariableImpacts;
+          break;
+        case SortingCriteria.VariableName:
+          orderedEntries = rawVariableImpacts.OrderBy(v => v.Item1, new NaturalStringComparer());
+          break;
+        default:
+          throw new NotImplementedException("Ordering for selected SortingCriteria not implemented");
+      }
+
+      if (!ascending) { orderedEntries = orderedEntries.Reverse(); }
+
+      //Write the data back
+      var impactArray = new DoubleArray(orderedEntries.Select(i => i.Item2).ToArray()) {
+        ElementNames = orderedEntries.Select(i => i.Item1)
+      };
+
+      //Could be, if the View was closed
+      if (!variableImactsArrayView.IsDisposed) {
+        variableImactsArrayView.Content = (DoubleArray)impactArray.AsReadOnly();
+      }
     }
   }
Index: stable/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 16434)
+++ stable/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 16435)
@@ -96,5 +96,6 @@
       DataPartitionEnum data = DataPartitionEnum.Training,
       ReplacementMethodEnum replacementMethod = ReplacementMethodEnum.Median,
-      FactorReplacementMethodEnum factorReplacementMethod = FactorReplacementMethodEnum.Best) {
+      FactorReplacementMethodEnum factorReplacementMethod = FactorReplacementMethodEnum.Best,
+      Func<double, string, bool> progressCallback = null) {
 
       var problemData = solution.ProblemData;
@@ -134,6 +135,13 @@
       var allowedInputVariables = dataset.VariableNames.Where(v => inputvariables.Contains(v)).ToList();
 
+      int curIdx = 0;
+      int count = allowedInputVariables.Where(problemData.Dataset.VariableHasType<double>).Count();
       // calculate impacts for double variables
       foreach (var inputVariable in allowedInputVariables.Where(problemData.Dataset.VariableHasType<double>)) {
+        //Report the current progress in percent. If the callback returns true, it means the execution shall be stopped
+        if (progressCallback != null) {
+          curIdx++;
+          if (progressCallback((double)curIdx / count, string.Format("Calculating impact for variable {0} ({1} of {2})", inputVariable, curIdx, count))) { return null; }
+        }
         var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows, replacementMethod);
         var newR2 = OnlinePearsonsRCalculator.Calculate(targetValues, newEstimates, out error);
@@ -180,4 +188,5 @@
     }
 
+
     private static IEnumerable<double> EvaluateModelWithReplacedVariable(IRegressionModel model, string variable, ModifiableDataset dataset, IEnumerable<int> rows, ReplacementMethodEnum replacement = ReplacementMethodEnum.Median) {
       var originalValues = dataset.GetReadOnlyDoubleValues(variable).ToList();
Index: stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis-3.4/VariableImpactCalculationTest.cs
===================================================================
--- stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis-3.4/VariableImpactCalculationTest.cs	(revision 16435)
+++ stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis-3.4/VariableImpactCalculationTest.cs	(revision 16435)
@@ -0,0 +1,238 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Algorithms.ALPS;
+using HeuristicLab.Algorithms.DataAnalysis;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+using HeuristicLab.Problems.Instances.DataAnalysis;
+using HeuristicLab.Selection;
+using HeuristicLab.Tests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace HeuristicLab.Problems.DataAnalysis.Tests {
+
+  [TestClass()]
+  public class VariableImpactCalculationTest {
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis")]
+    [TestProperty("Time", "medium")]
+    public void RunAlpsSymRegFactoryVariableMibaC1Test() {
+      var alpsGA = CreateAlpsGaSymRegMibaC1Sample();
+      alpsGA.Start();
+      var ers = alpsGA.Results.FirstOrDefault(v => v.Name == "Variable impacts").Value as DoubleMatrix;
+      Assert.IsNotNull(ers);
+      Assert.IsTrue(ers.Rows == 22);
+      List<string> expectedVariableOrder = new List<string> { "Oil", "Grooving", "Material_Cat", "x20", "Material", "x14", "x12", "x3", "x7", "x2", "x16", "x15", "x8", "x10", "x11", "x22", "x4", "x5", "x6", "x9", "x17", "x13" };
+      List<double> expectedVariableImpacts = new List<double> { 0.206, 0.179, 0.136, 0.099, 0.092, 0.07, 0.048, 0.033, 0.029, 0.026, 0.017, 0.01, 0.007, 0.007, 0.007, 0.006, 0.005, 0.005, 0.005, 0.005, 0.005, 0.003 };
+      Assert.IsTrue(ers.RowNames.SequenceEqual(expectedVariableOrder));
+      Assert.IsTrue(ers.SequenceEqual(expectedVariableImpacts));
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis")]
+    [TestProperty("Time", "medium")]
+    public void RunAlpsSymRegFactoryVariableMibaWear1Test() {
+      var alpsGA = CreateAlpsGaSymRegMibaWear1Sample();
+      alpsGA.Start();
+      var ers = alpsGA.Results.FirstOrDefault(v => v.Name == "Variable impacts").Value as DoubleMatrix;
+      Assert.IsNotNull(ers);
+      Assert.IsTrue(ers.Rows == 27);
+      List<string> expectedVariableOrder = new List<string> { "Oil", "Material_Cat", "Material", "Grooving", "x8", "x1", "x14", "x11", "x19", "x10", "x5", "x9", "x17", "x6", "x18", "x7", "Source1", "x2", "x3", "x4", "x16", "x20", "x12", "x13", "x15", "x22", "x21" };
+      List<double> expectedVariableImpacts = new List<double> { 0.194, 0.184, 0.163, 0.155, 0.022, 0.019, 0.019, 0.018, 0.017, 0.016, 0.015, 0.015, 0.015, 0.014, 0.014, 0.013, 0.012, 0.011, 0.011, 0.011, 0.011, 0.011, 0.01, 0.009, 0.009, 0.008, 0.006 };
+      Assert.IsTrue(ers.RowNames.SequenceEqual(expectedVariableOrder));
+      Assert.IsTrue(ers.SequenceEqual(expectedVariableImpacts));
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis")]
+    [TestProperty("Time", "medium")]
+    public void RunAlpsSymRegFactoryVariableRealworldTowerTest() {
+      var alpsGA = CreateAlpsGaSymReRealworldTowerSample();
+      alpsGA.Start();
+      var ers = alpsGA.Results.FirstOrDefault(v => v.Name == "Variable impacts").Value as DoubleMatrix;
+      Assert.IsNotNull(ers);
+      Assert.IsTrue(ers.Rows == 25);
+      List<string> expectedVariableOrder = new List<string> { "x5", "x4", "x21", "x22", "x13", "x3", "x9", "x19", "x1", "x12", "x8", "x10", "x25", "x11", "x23", "x7", "x24", "x6", "x14", "x15", "x20", "x2", "x16", "x18", "x17" };
+      List<double> expectedVariableImpacts = new List<double> { 0.057, 0.051, 0.047, 0.047, 0.046, 0.045, 0.044, 0.044, 0.043, 0.043, 0.041, 0.04, 0.04, 0.038, 0.038, 0.037, 0.037, 0.036, 0.036, 0.034, 0.033, 0.031, 0.031, 0.031, 0.03 };
+      Assert.IsTrue(ers.RowNames.SequenceEqual(expectedVariableOrder));
+      Assert.IsTrue(ers.SequenceEqual(expectedVariableImpacts));
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis")]
+    [TestProperty("Time", "short")]
+    public void RunRandomForestPolyTenTest() {
+      var randomForestRegression = new RandomForestRegression() {
+        M = 0.4,
+        R = 0.3,
+        NumberOfTrees = 50,
+        SetSeedRandomly = false,
+        Seed = 42
+      };
+
+      var symbRegProblem = new SymbolicRegressionSingleObjectiveProblem();
+      symbRegProblem.ProblemData = new PolyTen(555000).GenerateRegressionData();
+      randomForestRegression.Problem = symbRegProblem;
+      randomForestRegression.Start();
+
+      var rfs = randomForestRegression.Results.FirstOrDefault(v => v.Name == "Random forest regression solution").Value as RandomForestRegressionSolution;
+      Assert.IsNotNull(rfs);
+      var result = new RegressionSolutionVariableImpactsCalculator().Calculate(rfs);
+
+      //Set expected impacts
+      List<Tuple<string, double>> aux = new List<Tuple<string, double>>();
+      aux.Add(new Tuple<string, double>("X6", 0.14984398650032071));
+      aux.Add(new Tuple<string, double>("X5", 0.14361275357221248));
+      aux.Add(new Tuple<string, double>("X1", 0.10607502238071009));
+      aux.Add(new Tuple<string, double>("X3", 0.1056849194554953));
+      aux.Add(new Tuple<string, double>("X4", 0.0906750779077492));
+      aux.Add(new Tuple<string, double>("X2", 0.089817766590950532));
+      aux.Add(new Tuple<string, double>("X8", 0.042797597332305481));
+      aux.Add(new Tuple<string, double>("X9", 0.038609311722408446));
+      aux.Add(new Tuple<string, double>("X10", 0.036202503161574362));
+      aux.Add(new Tuple<string, double>("X7", 0.033539038256832465));
+      Assert.IsTrue(result.SequenceEqual(aux));
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis")]
+    [TestProperty("Time", "short")]
+    public void RunLinearRegressionBreimanITest() {
+      LinearRegression lr = new LinearRegression();
+      var symbRegProblem = new SymbolicRegressionSingleObjectiveProblem();
+      symbRegProblem.ProblemData = new BreimanOne(1234).GenerateRegressionData();
+
+      lr.Problem = symbRegProblem;
+      lr.Start();
+
+      var lrs = lr.Results.FirstOrDefault(v => v.Name == "Linear regression solution").Value as SymbolicRegressionSolution;
+      Assert.IsNotNull(lrs);
+      var result = new RegressionSolutionVariableImpactsCalculator().Calculate(lrs);
+
+      //Set expected impacts
+      List<Tuple<string, double>> aux = new List<Tuple<string, double>>();
+      aux.Add(new Tuple<string, double>("X1", 0.43328518823918716));
+      aux.Add(new Tuple<string, double>("X2", 0.073284548674773631));
+      aux.Add(new Tuple<string, double>("X5", 0.070306657566311159));
+      aux.Add(new Tuple<string, double>("X3", 0.035352205426012917));
+      aux.Add(new Tuple<string, double>("X6", 0.031710492680145475));
+      aux.Add(new Tuple<string, double>("X4", 0.0081659530036176653));
+      aux.Add(new Tuple<string, double>("X7", 0.0070869550705255913));
+      aux.Add(new Tuple<string, double>("X9", 8.0546619615096127E-05));
+      aux.Add(new Tuple<string, double>("X8", 6.2072921147349192E-05));
+      aux.Add(new Tuple<string, double>("X10", 1.9113559758254794E-06));
+
+      Assert.IsTrue(result.SequenceEqual(aux));
+    }
+
+    private AlpsGeneticAlgorithm CreateAlpsGaSymRegMibaC1Sample() {
+      AlpsGeneticAlgorithm alpsGa = new AlpsGeneticAlgorithm();
+      #region Problem Configuration
+      var provider = new MibaFrictionRegressionInstanceProvider();
+      var instance = provider.GetDataDescriptors().Single(x => x.Name.StartsWith("CF1"));
+      var symbRegProblem = new SymbolicRegressionSingleObjectiveProblem();
+      symbRegProblem.Load(provider.LoadData(instance));
+
+      symbRegProblem.MaximumSymbolicExpressionTreeDepth.Value = 35;
+      symbRegProblem.MaximumSymbolicExpressionTreeLength.Value = 35;
+
+      var grammar = (TypeCoherentExpressionGrammar)symbRegProblem.SymbolicExpressionTreeGrammar;
+      grammar.Symbols.OfType<Exponential>().Single().Enabled = false;
+      grammar.Symbols.OfType<Logarithm>().Single().Enabled = false;
+
+      #endregion
+      #region Algorithm Configuration
+      alpsGa.Name = "ALPS Genetic Programming - Symbolic Regression";
+      alpsGa.Description = "An ALPS-GP to solve a symbolic regression problem";
+      alpsGa.Problem = symbRegProblem;
+      SamplesUtils.ConfigureAlpsGeneticAlgorithmParameters<GeneralizedRankSelector, SubtreeCrossover, MultiSymbolicExpressionTreeManipulator>(alpsGa,
+        numberOfLayers: 1000,
+        popSize: 100,
+        mutationRate: 0.25,
+        elites: 1,
+        plusSelection: false,
+        agingScheme: AgingScheme.Polynomial,
+        ageGap: 15,
+        ageInheritance: 1.0,
+        maxGens: 10);
+
+      alpsGa.SetSeedRandomly.Value = false;
+      alpsGa.Seed.Value = 1234;
+      #endregion
+      return alpsGa;
+    }
+    private AlpsGeneticAlgorithm CreateAlpsGaSymRegMibaWear1Sample() {
+      AlpsGeneticAlgorithm alpsGa = new AlpsGeneticAlgorithm();
+      #region Problem Configuration
+      var provider = new MibaFrictionRegressionInstanceProvider();
+      var instance = provider.GetDataDescriptors().Single(x => x.Name.StartsWith("Wear1"));
+      var symbRegProblem = new SymbolicRegressionSingleObjectiveProblem();
+      symbRegProblem.Load(provider.LoadData(instance));
+
+      symbRegProblem.MaximumSymbolicExpressionTreeDepth.Value = 77;
+      symbRegProblem.MaximumSymbolicExpressionTreeLength.Value = 77;
+
+      var grammar = (TypeCoherentExpressionGrammar)symbRegProblem.SymbolicExpressionTreeGrammar;
+
+      #endregion
+      #region Algorithm Configuration
+      alpsGa.Name = "ALPS Genetic Programming - Symbolic Regression";
+      alpsGa.Description = "An ALPS-GP to solve a symbolic regression problem";
+      alpsGa.Problem = symbRegProblem;
+      SamplesUtils.ConfigureAlpsGeneticAlgorithmParameters<RandomSelector, SubtreeCrossover, MultiSymbolicExpressionTreeManipulator>(alpsGa,
+        numberOfLayers: 1000,
+        popSize: 200,
+        mutationRate: 0.25,
+        elites: 1,
+        plusSelection: false,
+        agingScheme: AgingScheme.Polynomial,
+        ageGap: 15,
+        ageInheritance: 1.0,
+        maxGens: 10);
+
+      alpsGa.SetSeedRandomly.Value = false;
+      alpsGa.Seed.Value = 11121314;
+      #endregion
+      return alpsGa;
+    }
+    private AlpsGeneticAlgorithm CreateAlpsGaSymReRealworldTowerSample() {
+      AlpsGeneticAlgorithm alpsGa = new AlpsGeneticAlgorithm();
+      #region Problem Configuration
+      var provider = new RegressionRealWorldInstanceProvider();
+      var instance = provider.GetDataDescriptors().Single(x => x.Name.StartsWith("Tower"));
+      var symbRegProblem = new SymbolicRegressionSingleObjectiveProblem();
+      symbRegProblem.Load(provider.LoadData(instance));
+
+      symbRegProblem.MaximumSymbolicExpressionTreeDepth.Value = 77;
+      symbRegProblem.MaximumSymbolicExpressionTreeLength.Value = 77;
+
+      var grammar = (TypeCoherentExpressionGrammar)symbRegProblem.SymbolicExpressionTreeGrammar;
+
+      #endregion
+      #region Algorithm Configuration
+      alpsGa.Name = "ALPS Genetic Programming - Symbolic Regression";
+      alpsGa.Description = "An ALPS-GP to solve a symbolic regression problem";
+      alpsGa.Problem = symbRegProblem;
+      SamplesUtils.ConfigureAlpsGeneticAlgorithmParameters<RandomSelector, SubtreeCrossover, MultiSymbolicExpressionTreeManipulator>(alpsGa,
+        numberOfLayers: 1000,
+        popSize: 200,
+        mutationRate: 0.25,
+        elites: 1,
+        plusSelection: false,
+        agingScheme: AgingScheme.Polynomial,
+        ageGap: 15,
+        ageInheritance: 1.0,
+        maxGens: 10);
+
+      alpsGa.SetSeedRandomly.Value = false;
+      alpsGa.Seed.Value = 1111;
+      #endregion
+      return alpsGa;
+    }
+
+    //TODO: Add Function-Tests once the Branch of #2904 is done
+  }
+}
Index: stable/HeuristicLab.Tests/HeuristicLab.Tests.csproj
===================================================================
--- stable/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 16434)
+++ stable/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 16435)
@@ -586,4 +586,5 @@
     <Compile Include="HeuristicLab.Problems.DataAnalysis-3.4\OnlineCalculatorPerformanceTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis-3.4\StatisticCalculatorsTest.cs" />
+    <Compile Include="HeuristicLab.Problems.DataAnalysis-3.4\VariableImpactCalculationTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\InfixExpressionParserTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\SymbolicExpressionTreeBottomUpSimilarityCalculatorTest.cs" />
