Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs	(revision 12742)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs	(revision 12745)
@@ -45,8 +45,6 @@
     private const string TotalNumberOfPrunedSubtreesParameterName = "Number of pruned subtrees";
     private const string TotalNumberOfPrunedTreesParameterName = "Number of pruned trees";
+    private const string TotalNumberOfPrunedNodesParameterName = "Number of pruned nodes";
     private const string RandomParameterName = "Random";
-    private const string PruneOnlyZeroImpactNodesParameterName = "PruneOnlyZeroImpactNodes";
-    private const string NodeImpactThresholdParameterName = "ImpactThreshold";
-    private const string PruningOperatorParameterName = "PruningOperator";
     private const string ResultsParameterName = "Results";
     private const string PopulationSizeParameterName = "PopulationSize";
@@ -54,4 +52,5 @@
 
     #region private members
+    private DataReducer prunedNodesReducer;
     private DataReducer prunedSubtreesReducer;
     private DataReducer prunedTreesReducer;
@@ -61,13 +60,4 @@
 
     #region parameter properties
-    public IValueParameter<SymbolicDataAnalysisExpressionPruningOperator> PruningOperatorParameter {
-      get { return (IValueParameter<SymbolicDataAnalysisExpressionPruningOperator>)Parameters[PruningOperatorParameterName]; }
-    }
-    public IFixedValueParameter<BoolValue> PruneOnlyZeroImpactNodesParameter {
-      get { return (IFixedValueParameter<BoolValue>)Parameters[PruneOnlyZeroImpactNodesParameterName]; }
-    }
-    public IFixedValueParameter<DoubleValue> NodeImpactThresholdParameter {
-      get { return (IFixedValueParameter<DoubleValue>)Parameters[NodeImpactThresholdParameterName]; }
-    }
     public ILookupParameter<IRandom> RandomParameter {
       get { return (ILookupParameter<IRandom>)Parameters[RandomParameterName]; }
@@ -91,5 +81,5 @@
 
     #region properties
-    protected SymbolicDataAnalysisExpressionPruningOperator PruningOperator { get { return PruningOperatorParameter.Value; } }
+    protected abstract SymbolicDataAnalysisExpressionPruningOperator PruningOperator { get; }
     protected int UpdateInterval { get { return UpdateIntervalParameter.Value.Value; } }
 
@@ -112,13 +102,4 @@
       get { return PruningProbabilityParameter.Value.Value; }
       set { PruningProbabilityParameter.Value.Value = value; }
-    }
-
-    protected bool PruneOnlyZeroImpactNodes {
-      get { return PruneOnlyZeroImpactNodesParameter.Value.Value; }
-      set { PruneOnlyZeroImpactNodesParameter.Value.Value = value; }
-    }
-    protected double NodeImpactThreshold {
-      get { return NodeImpactThresholdParameter.Value.Value; }
-      set { NodeImpactThresholdParameter.Value.Value = value; }
     }
     #endregion
@@ -140,4 +121,6 @@
     protected SymbolicDataAnalysisSingleObjectivePruningAnalyzer(SymbolicDataAnalysisSingleObjectivePruningAnalyzer original, Cloner cloner)
       : base(original, cloner) {
+      if (original.prunedNodesReducer != null)
+        this.prunedNodesReducer = (DataReducer)original.prunedNodesReducer.Clone();
       if (original.prunedSubtreesReducer != null)
         this.prunedSubtreesReducer = (DataReducer)original.prunedSubtreesReducer.Clone();
@@ -197,6 +180,4 @@
       Parameters.Add(new LookupParameter<IRandom>(RandomParameterName, "The random number generator."));
       Parameters.Add(new LookupParameter<IDataAnalysisProblemData>(ProblemDataParameterName, "The problem data."));
-      Parameters.Add(new FixedValueParameter<DoubleValue>(NodeImpactThresholdParameterName, "The impact threshold  below which an individual should be pruned.", new DoubleValue(0.0)));
-      Parameters.Add(new FixedValueParameter<BoolValue>(PruneOnlyZeroImpactNodesParameterName, "Switch to determine of only zero impact individuals should be pruned.", new BoolValue(false)));
       Parameters.Add(new LookupParameter<IntValue>(PopulationSizeParameterName, "The population of individuals."));
       #endregion
@@ -225,5 +206,6 @@
       var qualities = Quality.Select(x => x.Value).ToArray();
       var indices = Enumerable.Range(0, qualities.Length).ToArray();
-      Array.Sort(qualities, indices);
+      indices.StableSort((a, b) => qualities[a].CompareTo(qualities[b]));
+
       if (!Maximization.Value) Array.Reverse(indices);
 
@@ -233,5 +215,5 @@
       var empty = new EmptyOperator();
 
-      for (int i = 0; i < subscopes.Count; ++i) {
+      for (int i = 0; i < indices.Length; ++i) {
         IOperator @operator;
         if (range.Start <= i && i < range.End && random.NextDouble() <= PruningProbability)
@@ -250,7 +232,8 @@
       UpdateCounter = 0;
 
-      if (prunedSubtreesReducer == null || prunedTreesReducer == null || valuesCollector == null || resultsCollector == null) { InitializeOperators(); }
+      if (prunedNodesReducer == null || prunedSubtreesReducer == null || prunedTreesReducer == null || valuesCollector == null || resultsCollector == null) { InitializeOperators(); }
 
       var prune = CreatePruningOperation();
+      var reducePrunedNodes = ExecutionContext.CreateChildOperation(prunedNodesReducer);
       var reducePrunedSubtrees = ExecutionContext.CreateChildOperation(prunedSubtreesReducer);
       var reducePrunedTrees = ExecutionContext.CreateChildOperation(prunedTreesReducer);
@@ -258,8 +241,14 @@
       var collectResults = ExecutionContext.CreateChildOperation(resultsCollector);
 
-      return new OperationCollection { prune, reducePrunedSubtrees, reducePrunedTrees, collectValues, collectResults, base.Apply() };
+      return new OperationCollection { prune, reducePrunedNodes, reducePrunedSubtrees, reducePrunedTrees, collectValues, collectResults, base.Apply() };
     }
 
     private void InitializeOperators() {
+      prunedNodesReducer = new DataReducer();
+      prunedNodesReducer.ParameterToReduce.ActualName = PruningOperator.PrunedNodesParameter.ActualName;
+      prunedNodesReducer.ReductionOperation.Value = new ReductionOperation(ReductionOperations.Sum); // sum all the pruned subtrees parameter values
+      prunedNodesReducer.TargetOperation.Value = new ReductionOperation(ReductionOperations.Assign); // asign the sum to the target parameter
+      prunedNodesReducer.TargetParameter.ActualName = TotalNumberOfPrunedNodesParameterName;
+
       prunedSubtreesReducer = new DataReducer();
       prunedSubtreesReducer.ParameterToReduce.ActualName = PruningOperator.PrunedSubtreesParameter.ActualName;
@@ -275,4 +264,5 @@
 
       valuesCollector = new DataTableValuesCollector();
+      valuesCollector.CollectedValues.Add(new LookupParameter<IntValue>(TotalNumberOfPrunedNodesParameterName));
       valuesCollector.CollectedValues.Add(new LookupParameter<IntValue>(TotalNumberOfPrunedSubtreesParameterName));
       valuesCollector.CollectedValues.Add(new LookupParameter<IntValue>(TotalNumberOfPrunedTreesParameterName));
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interfaces/ISymbolicDataAnalysisImpactValuesCalculator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interfaces/ISymbolicDataAnalysisImpactValuesCalculator.cs	(revision 12742)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interfaces/ISymbolicDataAnalysisImpactValuesCalculator.cs	(revision 12745)
@@ -6,7 +6,7 @@
   public interface ISymbolicDataAnalysisSolutionImpactValuesCalculator : IItem {
     double CalculateReplacementValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows);
-    double CalculateImpactValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, double originalQuality = double.NaN);
+    double CalculateImpactValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, double qualityForImpactsCalculation = double.NaN);
     void CalculateImpactAndReplacementValues(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData,
-      IEnumerable<int> rows, out double impactValue, out double replacementValue, double originalQuality = double.NaN);
+      IEnumerable<int> rows, out double impactValue, out double replacementValue, out double newQualityForImpactsCalculation, double qualityForImpactsCalculation = double.NaN);
   }
 }
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionPruningOperator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionPruningOperator.cs	(revision 12742)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionPruningOperator.cs	(revision 12745)
@@ -34,5 +34,5 @@
   [StorableClass]
   [Item("SymbolicExpressionTreePruningOperator", "An operator that replaces introns with constant values in a symbolic expression tree.")]
-  public abstract class SymbolicDataAnalysisExpressionPruningOperator : SingleSuccessorOperator {
+  public abstract class SymbolicDataAnalysisExpressionPruningOperator : SingleSuccessorOperator, ISymbolicExpressionTreeOperator {
     #region parameter names
     private const string ProblemDataParameterName = "ProblemData";
@@ -41,4 +41,5 @@
     private const string PrunedSubtreesParameterName = "PrunedSubtrees";
     private const string PrunedTreesParameterName = "PrunedTrees";
+    private const string PrunedNodesParameterName = "PrunedNodes";
     private const string FitnessCalculationPartitionParameterName = "FitnessCalculationPartition";
     private const string NodeImpactThresholdParameterName = "ImpactThreshold";
@@ -48,4 +49,5 @@
     private const string EstimationLimitsParameterName = "EstimationLimits";
     private const string InterpreterParameterName = "SymbolicExpressionTreeInterpreter";
+    private const string ApplyLinearScalingParameterName = "ApplyLinearScaling";
     #endregion
 
@@ -72,4 +74,7 @@
       get { return (ILookupParameter<IntValue>)Parameters[PrunedTreesParameterName]; }
     }
+    public ILookupParameter<IntValue> PrunedNodesParameter {
+      get { return (ILookupParameter<IntValue>)Parameters[PrunedNodesParameterName]; }
+    }
     public IFixedValueParameter<DoubleValue> NodeImpactThresholdParameter {
       get { return (IFixedValueParameter<DoubleValue>)Parameters[NodeImpactThresholdParameterName]; }
@@ -84,22 +89,22 @@
       get { return (ILookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>)Parameters[InterpreterParameterName]; }
     }
+    public ILookupParameter<BoolValue> ApplyLinearScalingParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters[ApplyLinearScalingParameterName]; }
+    }
     #endregion
 
     #region properties
-    protected IDataAnalysisProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
-    protected ISymbolicDataAnalysisSolutionImpactValuesCalculator ImpactValuesCalculator { get { return ImpactValuesCalculatorParameter.Value; } }
-    protected IntRange FitnessCalculationPartition { get { return FitnessCalculationPartitionParameter.ActualValue; } }
-    protected bool PruneOnlyZeroImpactNodes {
+    public ISymbolicDataAnalysisSolutionImpactValuesCalculator ImpactValuesCalculator {
+      get { return ImpactValuesCalculatorParameter.Value; }
+      set { ImpactValuesCalculatorParameter.Value = value; }
+    }
+    public bool PruneOnlyZeroImpactNodes {
       get { return PruneOnlyZeroImpactNodesParameter.Value.Value; }
       set { PruneOnlyZeroImpactNodesParameter.Value.Value = value; }
     }
-    protected double NodeImpactThreshold {
+    public double NodeImpactThreshold {
       get { return NodeImpactThresholdParameter.Value.Value; }
       set { NodeImpactThresholdParameter.Value.Value = value; }
     }
-    protected ISymbolicExpressionTree SymbolicExpressionTree { get { return SymbolicExpressionTreeParameter.ActualValue; } }
-    protected DoubleValue Quality { get { return QualityParameter.ActualValue; } }
-    protected DoubleLimit EstimationLimits { get { return EstimationLimitsParameter.ActualValue; } }
-    protected ISymbolicDataAnalysisExpressionTreeInterpreter Interpreter { get { return InterpreterParameter.ActualValue; } }
     #endregion
 
@@ -109,9 +114,10 @@
       : base(original, cloner) { }
 
-    protected SymbolicDataAnalysisExpressionPruningOperator() {
+    protected SymbolicDataAnalysisExpressionPruningOperator(ISymbolicDataAnalysisSolutionImpactValuesCalculator impactValuesCalculator) {
       #region add parameters
       Parameters.Add(new LookupParameter<IDataAnalysisProblemData>(ProblemDataParameterName));
       Parameters.Add(new LookupParameter<ISymbolicDataAnalysisModel>(SymbolicDataAnalysisModelParameterName));
       Parameters.Add(new LookupParameter<IntRange>(FitnessCalculationPartitionParameterName));
+      Parameters.Add(new LookupParameter<IntValue>(PrunedNodesParameterName, "A counter of how many nodes were pruned."));
       Parameters.Add(new LookupParameter<IntValue>(PrunedSubtreesParameterName, "A counter of how many subtrees were replaced."));
       Parameters.Add(new LookupParameter<IntValue>(PrunedTreesParameterName, "A counter of how many trees were pruned."));
@@ -122,19 +128,45 @@
       Parameters.Add(new LookupParameter<ISymbolicExpressionTree>(SymbolicExpressionTreeParameterName));
       Parameters.Add(new LookupParameter<DoubleValue>(QualityParameterName));
+      Parameters.Add(new LookupParameter<BoolValue>(ApplyLinearScalingParameterName));
+      Parameters.Add(new ValueParameter<ISymbolicDataAnalysisSolutionImpactValuesCalculator>(ImpactValuesCalculatorParameterName, impactValuesCalculator));
       #endregion
     }
 
-    protected abstract ISymbolicDataAnalysisModel CreateModel();
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(PrunedNodesParameterName)) {
+        Parameters.Add(new LookupParameter<IntValue>(PrunedNodesParameterName, "A counter of how many nodes were pruned."));
+      }
+      if (!Parameters.ContainsKey(ApplyLinearScalingParameterName)) {
+        Parameters.Add(new LookupParameter<BoolValue>(ApplyLinearScalingParameterName));
+      }
+      if (!Parameters.ContainsKey(ImpactValuesCalculatorParameterName)) {
+        // value must be set by derived operators (regression/classification)
+        Parameters.Add(new ValueParameter<ISymbolicDataAnalysisSolutionImpactValuesCalculator>(ImpactValuesCalculatorParameterName));
+      }
+      #endregion
+    }
+
+    protected abstract ISymbolicDataAnalysisModel CreateModel(ISymbolicExpressionTree tree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, IDataAnalysisProblemData problemData, DoubleLimit estimationLimits);
 
     protected abstract double Evaluate(IDataAnalysisModel model);
 
     public override IOperation Apply() {
-      var model = CreateModel();
-      var nodes = SymbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0).IterateNodesPrefix().ToList();
-      var rows = Enumerable.Range(FitnessCalculationPartition.Start, FitnessCalculationPartition.Size);
+      var tree = SymbolicExpressionTreeParameter.ActualValue;
+      var problemData = ProblemDataParameter.ActualValue;
+      var fitnessCalculationPartition = FitnessCalculationPartitionParameter.ActualValue;
+      var estimationLimits = EstimationLimitsParameter.ActualValue;
+      var interpreter = InterpreterParameter.ActualValue;
+
+      var model = CreateModel(tree, interpreter, problemData, estimationLimits);
+      var nodes = tree.Root.GetSubtree(0).GetSubtree(0).IterateNodesPrefix().ToList();
+      var rows = Enumerable.Range(fitnessCalculationPartition.Start, fitnessCalculationPartition.Size).ToList();
       var prunedSubtrees = 0;
       var prunedTrees = 0;
-
-      double quality = Evaluate(model);
+      var prunedNodes = 0;
+
+      double qualityForImpactsCalculation = double.NaN;
 
       for (int i = 0; i < nodes.Count; ++i) {
@@ -143,21 +175,21 @@
 
         double impactValue, replacementValue;
-        ImpactValuesCalculator.CalculateImpactAndReplacementValues(model, node, ProblemData, rows, out impactValue, out replacementValue, quality);
-
-        if (PruneOnlyZeroImpactNodes) {
-          if (!impactValue.IsAlmost(0.0)) continue;
-        } else if (NodeImpactThreshold < impactValue) {
-          continue;
-        }
+        double newQualityForImpacts;
+        ImpactValuesCalculator.CalculateImpactAndReplacementValues(model, node, problemData, rows, out impactValue, out replacementValue, out newQualityForImpacts, qualityForImpactsCalculation);
+
+        if (PruneOnlyZeroImpactNodes && !impactValue.IsAlmost(0.0)) continue;
+        if (!PruneOnlyZeroImpactNodes && impactValue > NodeImpactThreshold) continue;
 
         var constantNode = (ConstantTreeNode)node.Grammar.GetSymbol("Constant").CreateTreeNode();
         constantNode.Value = replacementValue;
 
+        var length = node.GetLength();
         ReplaceWithConstant(node, constantNode);
-        i += node.GetLength() - 1; // skip subtrees under the node that was folded
-
-        quality -= impactValue;
+        i += length - 1; // skip subtrees under the node that was folded
 
         prunedSubtrees++;
+        prunedNodes += length;
+
+        qualityForImpactsCalculation = newQualityForImpacts;
       }
 
@@ -165,9 +197,13 @@
       PrunedSubtreesParameter.ActualValue = new IntValue(prunedSubtrees);
       PrunedTreesParameter.ActualValue = new IntValue(prunedTrees);
+      PrunedNodesParameter.ActualValue = new IntValue(prunedNodes);
+
+      if (prunedSubtrees > 0) // if nothing was pruned then there's no need to re-evaluate the tree
+        QualityParameter.ActualValue.Value = Evaluate(model);
 
       return base.Apply();
     }
 
-    private static void ReplaceWithConstant(ISymbolicExpressionTreeNode original, ISymbolicExpressionTreeNode replacement) {
+    protected static void ReplaceWithConstant(ISymbolicExpressionTreeNode original, ISymbolicExpressionTreeNode replacement) {
       var parent = original.Parent;
       var i = parent.IndexOfSubtree(original);
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionImpactValuesCalculator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionImpactValuesCalculator.cs	(revision 12742)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionImpactValuesCalculator.cs	(revision 12745)
@@ -37,6 +37,6 @@
     protected SymbolicDataAnalysisSolutionImpactValuesCalculator(bool deserializing) : base(deserializing) { }
     public abstract double CalculateReplacementValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows);
-    public abstract double CalculateImpactValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, double originalQuality = double.NaN);
-    public abstract void CalculateImpactAndReplacementValues(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, out double impactValue, out double replacementValue, double originalQuality = double.NaN);
+    public abstract double CalculateImpactValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, double qualityForImpactsCalculation = double.NaN);
+    public abstract void CalculateImpactAndReplacementValues(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, out double impactValue, out double replacementValue, out double newQualityForImpactsCalculation, double qualityForImpactsCalculation = double.NaN);
 
     protected static double CalculateReplacementValue(ISymbolicExpressionTreeNode node, ISymbolicExpressionTree sourceTree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
