Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs	(revision 10456)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs	(revision 10459)
@@ -5,6 +5,6 @@
 using HeuristicLab.Core;
 using HeuristicLab.Data;
-using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-using HeuristicLab.Optimization;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization.Operators;
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -14,29 +14,29 @@
   [Item("SymbolicDataAnalysisSingleObjectivePruningAnalyzer", "An analyzer that prunes introns from trees in single objective symbolic data analysis problems.")]
   public abstract class SymbolicDataAnalysisSingleObjectivePruningAnalyzer : SymbolicDataAnalysisSingleObjectiveAnalyzer {
+    #region parameter names
     private const string ProblemDataParameterName = "ProblemData";
-    private const string InterpreterParameterName = "SymbolicExpressionTreeInterpreter";
-
     private const string UpdateIntervalParameterName = "UpdateInverval";
     private const string UpdateCounterParameterName = "UpdateCounter";
-
     private const string PopulationSliceParameterName = "PopulationSlice";
     private const string PruningProbabilityParameterName = "PruningProbability";
-
-    private const string NumberOfPrunedSubtreesParameterName = "PrunedSubtrees";
-    private const string NumberOfPrunedTreesParameterName = "PrunedTrees";
-
+    private const string TotalNumberOfPrunedSubtreesParameterName = "Number of pruned subtrees";
+    private const string TotalNumberOfPrunedTreesParameterName = "Number of pruned trees";
     private const string RandomParameterName = "Random";
-    private const string EstimationLimitsParameterName = "EstimationLimits";
-
     private const string PruneOnlyZeroImpactNodesParameterName = "PruneOnlyZeroImpactNodes";
     private const string NodeImpactThresholdParameterName = "ImpactThreshold";
-
-    private const string FitnessCalculationPartitionParameterName = "FitnessCalculationPartition";
-
-    private bool reentry;
-    [Storable]
-    protected ISymbolicDataAnalysisSolutionImpactValuesCalculator impactValuesCalculator;
-
+    private const string PruningOperatorParameterName = "PruningOperator";
+    private const string ResultsParameterName = "Results";
+    #endregion
+    #region private members
+    private DataReducer prunedSubtreesReducer;
+    private DataReducer prunedTreesReducer;
+    private DataTableValuesCollector valuesCollector;
+    private ResultsCollector resultsCollector;
+    private EmptyOperator emptyOp;
+    #endregion
     #region parameter properties
+    public IValueParameter<SymbolicDataAnalysisExpressionPruningOperator> PruningOperatorParameter {
+      get { return (IValueParameter<SymbolicDataAnalysisExpressionPruningOperator>)Parameters[PruningOperatorParameterName]; }
+    }
     public IFixedValueParameter<BoolValue> PruneOnlyZeroImpactNodesParameter {
       get { return (IFixedValueParameter<BoolValue>)Parameters[PruneOnlyZeroImpactNodesParameterName]; }
@@ -45,7 +45,4 @@
       get { return (IFixedValueParameter<DoubleValue>)Parameters[NodeImpactThresholdParameterName]; }
     }
-    public ILookupParameter<DoubleLimit> EstimationLimitsParameter {
-      get { return (ILookupParameter<DoubleLimit>)Parameters[EstimationLimitsParameterName]; }
-    }
     public ILookupParameter<IRandom> RandomParameter {
       get { return (ILookupParameter<IRandom>)Parameters[RandomParameterName]; }
@@ -53,10 +50,4 @@
     private ILookupParameter<IDataAnalysisProblemData> ProblemDataParameter {
       get { return (ILookupParameter<IDataAnalysisProblemData>)Parameters[ProblemDataParameterName]; }
-    }
-    public ILookupParameter<IntRange> FitnessCalculationPartitionParameter {
-      get { return (ILookupParameter<IntRange>)Parameters[FitnessCalculationPartitionParameterName]; }
-    }
-    private ILookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter> InterpreterParameter {
-      get { return (ILookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>)Parameters[InterpreterParameterName]; }
     }
     public IValueParameter<IntValue> UpdateIntervalParameter {
@@ -72,39 +63,24 @@
       get { return (IValueParameter<DoubleValue>)Parameters[PruningProbabilityParameterName]; }
     }
-    public IFixedValueParameter<DoubleValue> NumberOfPrunedSubtreesParameter {
-      get { return (IFixedValueParameter<DoubleValue>)Parameters[NumberOfPrunedSubtreesParameterName]; }
-    }
-    public IFixedValueParameter<DoubleValue> NumberOfPrunedTreesParameter {
-      get { return (IFixedValueParameter<DoubleValue>)Parameters[NumberOfPrunedTreesParameterName]; }
-    }
     #endregion
     #region properties
+    protected SymbolicDataAnalysisExpressionPruningOperator PruningOperator { get { return PruningOperatorParameter.Value; } }
     protected IDataAnalysisProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
-    protected IntRange FitnessCalculationPartition { get { return FitnessCalculationPartitionParameter.ActualValue; } }
-    protected ISymbolicDataAnalysisExpressionTreeInterpreter Interpreter { get { return InterpreterParameter.ActualValue; } }
     protected IntValue UpdateInterval { get { return UpdateIntervalParameter.Value; } }
     protected IntValue UpdateCounter { get { return UpdateCounterParameter.Value; } }
     protected DoubleRange PopulationSlice { get { return PopulationSliceParameter.Value; } }
     protected DoubleValue PruningProbability { get { return PruningProbabilityParameter.Value; } }
-    protected DoubleValue PrunedSubtrees { get { return NumberOfPrunedSubtreesParameter.Value; } }
-    protected DoubleValue PrunedTrees { get { return NumberOfPrunedTreesParameter.Value; } }
-    protected DoubleLimit EstimationLimits { get { return EstimationLimitsParameter.ActualValue; } }
     protected IRandom Random { get { return RandomParameter.ActualValue; } }
     protected DoubleValue NodeImpactThreshold { get { return NodeImpactThresholdParameter.Value; } }
     protected BoolValue PruneOnlyZeroImpactNodes { get { return PruneOnlyZeroImpactNodesParameter.Value; } }
     #endregion
-
     #region IStatefulItem members
     public override void InitializeState() {
       base.InitializeState();
       UpdateCounter.Value = 0;
-      PrunedSubtrees.Value = 0;
-      PrunedTrees.Value = 0;
     }
     public override void ClearState() {
       base.ClearState();
       UpdateCounter.Value = 0;
-      PrunedSubtrees.Value = 0;
-      PrunedTrees.Value = 0;
     }
     #endregion
@@ -112,95 +88,101 @@
     [StorableConstructor]
     protected SymbolicDataAnalysisSingleObjectivePruningAnalyzer(bool deserializing) : base(deserializing) { }
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      if (!Parameters.ContainsKey(FitnessCalculationPartitionParameterName))
-        Parameters.Add(new LookupParameter<IntRange>(FitnessCalculationPartitionParameterName, ""));
-    }
     protected SymbolicDataAnalysisSingleObjectivePruningAnalyzer(SymbolicDataAnalysisSingleObjectivePruningAnalyzer original, Cloner cloner)
       : base(original, cloner) {
-      impactValuesCalculator = original.impactValuesCalculator;
+      this.prunedSubtreesReducer = (DataReducer)original.prunedSubtreesReducer.Clone();
+      this.prunedTreesReducer = (DataReducer)original.prunedTreesReducer.Clone();
+      this.valuesCollector = (DataTableValuesCollector)original.valuesCollector.Clone();
+      this.resultsCollector = (ResultsCollector)original.resultsCollector.Clone();
     }
     protected SymbolicDataAnalysisSingleObjectivePruningAnalyzer() {
+      #region add parameters
       Parameters.Add(new ValueParameter<DoubleRange>(PopulationSliceParameterName, new DoubleRange(0.75, 1)));
       Parameters.Add(new ValueParameter<DoubleValue>(PruningProbabilityParameterName, new DoubleValue(0.5)));
-      // analyzer parameters
       Parameters.Add(new ValueParameter<IntValue>(UpdateIntervalParameterName, "The interval in which the tree length analysis should be applied.", new IntValue(1)));
       Parameters.Add(new ValueParameter<IntValue>(UpdateCounterParameterName, "The value which counts how many times the operator was called", new IntValue(0)));
       Parameters.Add(new LookupParameter<IRandom>(RandomParameterName));
       Parameters.Add(new LookupParameter<IDataAnalysisProblemData>(ProblemDataParameterName));
-      Parameters.Add(new LookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>(InterpreterParameterName));
-
-      Parameters.Add(new FixedValueParameter<DoubleValue>(NumberOfPrunedSubtreesParameterName, new DoubleValue(0)));
-      Parameters.Add(new FixedValueParameter<DoubleValue>(NumberOfPrunedTreesParameterName, new DoubleValue(0)));
-      Parameters.Add(new LookupParameter<DoubleLimit>(EstimationLimitsParameterName));
       Parameters.Add(new FixedValueParameter<DoubleValue>(NodeImpactThresholdParameterName, new DoubleValue(0.0)));
       Parameters.Add(new FixedValueParameter<BoolValue>(PruneOnlyZeroImpactNodesParameterName, new BoolValue(false)));
-      Parameters.Add(new LookupParameter<IntRange>(FitnessCalculationPartitionParameterName, ""));
+      #endregion
+    }
+
+    private void InitializeOperators() {
+      prunedSubtreesReducer = new DataReducer();
+      prunedSubtreesReducer.ParameterToReduce.ActualName = PruningOperator.PrunedSubtreesParameter.ActualName;
+      prunedSubtreesReducer.ReductionOperation.Value = new ReductionOperation(ReductionOperations.Sum); // sum all the pruned subtrees parameter values
+      prunedSubtreesReducer.TargetOperation.Value = new ReductionOperation(ReductionOperations.Assign); // asign the sum to the target parameter
+      prunedSubtreesReducer.TargetParameter.ActualName = TotalNumberOfPrunedSubtreesParameterName;
+
+      prunedTreesReducer = new DataReducer();
+      prunedTreesReducer.ParameterToReduce.ActualName = PruningOperator.PrunedTreesParameter.ActualName;
+      prunedTreesReducer.ReductionOperation.Value = new ReductionOperation(ReductionOperations.Sum);
+      prunedTreesReducer.TargetOperation.Value = new ReductionOperation(ReductionOperations.Assign);
+      prunedTreesReducer.TargetParameter.ActualName = TotalNumberOfPrunedTreesParameterName;
+
+      valuesCollector = new DataTableValuesCollector();
+      valuesCollector.CollectedValues.Add(new LookupParameter<IntValue>(TotalNumberOfPrunedSubtreesParameterName));
+      valuesCollector.CollectedValues.Add(new LookupParameter<IntValue>(TotalNumberOfPrunedTreesParameterName));
+      valuesCollector.DataTableParameter.ActualName = "Population pruning";
+
+      resultsCollector = new ResultsCollector();
+      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>("Population pruning"));
+      resultsCollector.ResultsParameter.ActualName = ResultsParameterName;
+
+      emptyOp = new EmptyOperator();
+    }
+
+    // 
+    /// <summary>
+    /// Computes the closed interval bounding the portion of the population that is to be pruned. 
+    /// </summary>
+    /// <returns>Returns an int range [start, end]</returns>
+    private IntRange GetSliceBounds() {
+      var count = ExecutionContext.Scope.SubScopes.Count;
+      var start = (int)Math.Round(PopulationSlice.Start * count);
+      var end = (int)Math.Round(PopulationSlice.End * count);
+      if (end > count) end = count;
+
+      if (start >= end) throw new ArgumentOutOfRangeException("Invalid PopulationSlice bounds.");
+      return new IntRange(start, end);
+    }
+
+    private IOperation CreatePruningOperation() {
+      var oc = new OperationCollection { Parallel = true };
+      var range = GetSliceBounds();
+      var qualities = Quality.Select(x => x.Value).ToArray();
+      var indices = Enumerable.Range(0, qualities.Length).ToArray();
+      Array.Sort(qualities, indices);
+      if (!Maximization.Value) Array.Reverse(indices);
+
+      var subscopes = ExecutionContext.Scope.SubScopes;
+
+      for (int i = 0; i < subscopes.Count; ++i) {
+        IOperator op;
+        if (range.Start <= i && i < range.End && Random.NextDouble() <= PruningProbability.Value)
+          op = PruningOperator;
+        else op = emptyOp;
+        var index = indices[i];
+        var subscope = subscopes[index];
+        oc.Add(ExecutionContext.CreateChildOperation(op, subscope));
+      }
+      return oc;
     }
 
     public override IOperation Apply() {
-      if (reentry) {
-        UpdateCounter.Value++;
+      UpdateCounter.Value++;
+      if (UpdateCounter.Value != UpdateInterval.Value) return base.Apply();
+      UpdateCounter.Value = 0;
 
-        if (UpdateCounter.Value != UpdateInterval.Value) return base.Apply();
-        UpdateCounter.Value = 0;
+      if (prunedSubtreesReducer == null || prunedTreesReducer == null || valuesCollector == null || resultsCollector == null) { InitializeOperators(); }
 
-        var trees = SymbolicExpressionTreeParameter.ActualValue.ToList();
-        var qualities = QualityParameter.ActualValue.ToList();
+      var prune = CreatePruningOperation();
+      var reducePrunedSubtrees = ExecutionContext.CreateChildOperation(prunedSubtreesReducer);
+      var reducePrunedTrees = ExecutionContext.CreateChildOperation(prunedTreesReducer);
+      var collectValues = ExecutionContext.CreateChildOperation(valuesCollector);
+      var collectResults = ExecutionContext.CreateChildOperation(resultsCollector);
 
-        var population = trees.Zip(qualities, (tree, quality) => new { Tree = tree, Quality = quality }).ToList();
-        Func<double, double, int> compare = (a, b) => Maximization.Value ? a.CompareTo(b) : b.CompareTo(a);
-        population.Sort((a, b) => compare(a.Quality.Value, b.Quality.Value));
-
-        var start = (int)Math.Round(PopulationSlice.Start * trees.Count);
-        var end = (int)Math.Round(PopulationSlice.End * trees.Count);
-
-        if (end == population.Count) end--;
-
-        if (start >= end || end >= population.Count) throw new Exception("Invalid PopulationSlice bounds.");
-
-        PrunedSubtrees.Value = 0;
-        PrunedTrees.Value = 0;
-
-        reentry = false;
-
-        var operations = new OperationCollection { Parallel = true };
-        foreach (var p in population.Skip(start).Take(end)) {
-          if (Random.NextDouble() > PruningProbability.Value) continue;
-          var op = new SymbolicDataAnalysisExpressionPruningOperator {
-            Model = CreateModel(p.Tree, Interpreter, EstimationLimits.Lower, EstimationLimits.Upper),
-            ImpactsCalculator = impactValuesCalculator,
-            ProblemData = ProblemData,
-            Random = Random,
-            PruneOnlyZeroImpactNodes = PruneOnlyZeroImpactNodes.Value,
-            NodeImpactThreshold = NodeImpactThreshold.Value,
-            FitnessCalculationPartition = FitnessCalculationPartition
-          };
-          operations.Add(ExecutionContext.CreateChildOperation(op, ExecutionContext.Scope));
-        }
-        return new OperationCollection { operations, ExecutionContext.CreateOperation(this) };
-      }
-
-      DataTable table;
-
-      if (ResultCollection.ContainsKey("Population Pruning")) {
-        table = (DataTable)ResultCollection["Population Pruning"].Value;
-      } else {
-        table = new DataTable("Population Pruning");
-        table.Rows.Add(new DataRow("Pruned Trees") { VisualProperties = { StartIndexZero = true } });
-        table.Rows.Add(new DataRow("Pruned Subtrees") { VisualProperties = { StartIndexZero = true } });
-        ResultCollection.Add(new Result("Population Pruning", table));
-      }
-
-      table.Rows["Pruned Trees"].Values.Add(PrunedTrees.Value);
-      table.Rows["Pruned Subtrees"].Values.Add(PrunedSubtrees.Value);
-
-      reentry = true;
-
-      return base.Apply();
+      return new OperationCollection { prune, reducePrunedSubtrees, reducePrunedTrees, collectValues, collectResults, base.Apply() };
     }
-
-    protected abstract ISymbolicDataAnalysisModel CreateModel(ISymbolicExpressionTree tree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
-      double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue);
   }
 }
