Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 6604)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 6606)
@@ -31,11 +31,18 @@
   [StorableClass]
   public abstract class ClassificationSolution : ClassificationSolutionBase {
+    protected readonly Dictionary<int, double> evaluationCache;
+
     [StorableConstructor]
-    protected ClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected ClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+    }
     protected ClassificationSolution(ClassificationSolution original, Cloner cloner)
       : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
     }
     public ClassificationSolution(IClassificationModel model, IClassificationProblemData problemData)
       : base(model, problemData) {
+      evaluationCache = new Dictionary<int, double>();
     }
 
@@ -51,5 +58,23 @@
 
     public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
-      return Model.GetEstimatedClassValues(ProblemData.Dataset, rows);
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
     }
   }
Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 6604)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 6606)
@@ -33,12 +33,24 @@
   [Item("DiscriminantFunctionClassificationSolution", "Represents a classification solution that uses a discriminant function and classification thresholds.")]
   public abstract class DiscriminantFunctionClassificationSolution : DiscriminantFunctionClassificationSolutionBase {
+    protected readonly Dictionary<int, double> valueEvaluationCache;
+    protected readonly Dictionary<int, double> classValueEvaluationCache;
 
     [StorableConstructor]
-    protected DiscriminantFunctionClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected DiscriminantFunctionClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+    }
     protected DiscriminantFunctionClassificationSolution(DiscriminantFunctionClassificationSolution original, Cloner cloner)
       : base(original, cloner) {
+      valueEvaluationCache = new Dictionary<int, double>(original.valueEvaluationCache);
+      classValueEvaluationCache = new Dictionary<int, double>(original.classValueEvaluationCache);
     }
     protected DiscriminantFunctionClassificationSolution(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
       : base(model, problemData) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+
+      SetAccuracyMaximizingThresholds();
     }
 
@@ -54,5 +66,13 @@
 
     public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
-      return Model.GetEstimatedClassValues(ProblemData.Dataset, rows);
+      var rowsToEvaluate = rows.Except(classValueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        classValueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => classValueEvaluationCache[row]);
     }
 
@@ -69,5 +89,28 @@
 
     public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
-      return Model.GetEstimatedValues(ProblemData.Dataset, rows);
+      var rowsToEvaluate = rows.Except(valueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        valueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => valueEvaluationCache[row]);
+    }
+
+    protected override void OnModelChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnModelChanged();
+    }
+    protected override void OnModelThresholdsChanged(System.EventArgs e) {
+      classValueEvaluationCache.Clear();
+      base.OnModelThresholdsChanged(e);
+    }
+    protected override void OnProblemDataChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnProblemDataChanged();
     }
   }
Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 6604)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 6606)
@@ -86,5 +86,4 @@
       Add(new Result(TestRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
 
-      SetAccuracyMaximizingThresholds();
       RegisterEventHandler();
     }
@@ -95,9 +94,9 @@
     }
 
-    protected override void OnModelChanged(EventArgs e) {
+    protected override void OnModelChanged() {
       DeregisterEventHandler();
       SetAccuracyMaximizingThresholds();
       RegisterEventHandler();
-      base.OnModelChanged(e);
+      base.OnModelChanged();
     }
 
@@ -149,5 +148,5 @@
 
     protected virtual void OnModelThresholdsChanged(EventArgs e) {
-      RecalculateResults();
+      CalculateResults();
     }
 
