Index: /branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Mutators/SegmentOptimization/SamplingSegmentOptimizationManipulator.cs
===================================================================
--- /branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Mutators/SegmentOptimization/SamplingSegmentOptimizationManipulator.cs	(revision 18226)
+++ /branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Mutators/SegmentOptimization/SamplingSegmentOptimizationManipulator.cs	(revision 18227)
@@ -84,7 +84,10 @@
     public ValueParameter<EnumValue<SamplingPointsType>> SamplingPointsParameter => (ValueParameter<EnumValue<SamplingPointsType>>)Parameters["SamplingPoints"];
     public ValueParameter<BoolValue> CountSamplesAsEvaluationsParameter => (ValueParameter<BoolValue>)Parameters["CountSamplesAsEvaluations"];
+    public ValueParameter<BoolValue> CountCacheHitsAsEvaluationsParameter => (ValueParameter<BoolValue>)Parameters["CountCacheHitsAsEvaluations"];
 
     public LookupParameter<IntValue> EvaluatedSolutionsParameter => (LookupParameter<IntValue>)Parameters["EvaluatedSolutions"];
     #endregion
+
+    private IDictionary<Tuple<int, int>, double> cache;
 
     public SamplingSegmentOptimizationManipulator() {
@@ -97,4 +100,5 @@
       Parameters.Add(new ValueParameter<EnumValue<SamplingPointsType>>("SamplingPoints", new EnumValue<SamplingPointsType>(SamplingPointsType.BeforeCombinations | SamplingPointsType.AfterCombinations))); 
       Parameters.Add(new ValueParameter<BoolValue>("CountSamplesAsEvaluations", new BoolValue(false)));
+      Parameters.Add(new ValueParameter<BoolValue>("CountCacheHitsAsEvaluations", new BoolValue(true)));
       Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions"));
     }
@@ -115,8 +119,13 @@
       if (!Parameters.ContainsKey("DirectedRangeRange"))
         Parameters.Add(new ValueParameter<IntValue>("DirectedRangeRange", new IntValue(5)));
+      if (!Parameters.ContainsKey("CountCacheHitsAsEvaluations"))
+        Parameters.Add(new ValueParameter<BoolValue>("CountCacheHitsAsEvaluations", new BoolValue(true)));
+
     }
 
     protected override void ManipulateBounded(IRandom random, IntegerVector integerVector, IntMatrix bounds) {
-      var indices = CreateIndices(random, new IntegerVector(new [] { integerVector.Min(), integerVector.Max() }), bounds, Dimension, SearchRange, Evaluate, true,
+      var solution = new IntegerVector(new[] { integerVector.Min(), integerVector.Max() });
+
+      var indices = CreateIndices(random, solution, bounds, Dimension, SearchRange, EvaluateCached, true,
         this.DirectedRangeStepSize, this.DirectedRangeRange);
       
@@ -126,7 +135,7 @@
       var solutions = CreateCombinations(indices[0], indices[1]);
       if (!solutions.Any()) { 
-        if (SamplingPoints.HasFlag(SamplingPointsType.BeforeCombinations))
+        //if (SamplingPoints.HasFlag(SamplingPointsType.BeforeCombinations))
           return; // no valid combinations -> no mutation
-        throw new InvalidOperationException("no indices!");
+        //throw new InvalidOperationException("no indices!");
       }
 
@@ -134,13 +143,28 @@
         solutions = SampleIndices(solutions, Sampling, random, SampleCount);
 
-      if (CountSamplesAsEvaluationsParameter.Value.Value) {
-        int moves = solutions.Count();
-        EvaluatedSolutionsParameter.ActualValue.Value += moves - 1;
-      }
-
-      var best = FindBest(solutions, Evaluate);
+      //if (CountSamplesAsEvaluationsParameter.Value.Value) {
+      //  int moves = solutions.Count();
+      //  EvaluatedSolutionsParameter.ActualValue.Value += moves - 1;
+      //}
+
+      var best = FindBest(solutions, EvaluateCached);
       if (best != null) {
         CopyTo(best.Item1, integerVector);
       }
+    }
+
+    private double EvaluateCached(IntegerVector solution) {
+      if (cache == null) cache = new Dictionary<Tuple<int, int>, double>();
+      var key = Tuple.Create(solution.Min(), solution.Max());
+      if (cache.TryGetValue(key, out double cachedQuality)) {
+        if (CountSamplesAsEvaluationsParameter.Value.Value && CountCacheHitsAsEvaluationsParameter.Value.Value)
+          EvaluatedSolutionsParameter.ActualValue.Value += 1;
+        return cachedQuality;
+      }
+      var quality = Evaluate(solution);
+      if (CountSamplesAsEvaluationsParameter.Value.Value)
+        EvaluatedSolutionsParameter.ActualValue.Value += 1;
+      cache.Add(key, quality);
+      return quality;
     }
     
@@ -153,6 +177,6 @@
         indices[i] = CreateSingleIndices(integerVector, i, bounds, searchRange, evaluate, minimize, random, directedRangeStepSize, directedRangeRange).ToList();
         if (!indices[i].Any()) {
-          throw new InvalidOperationException("no indices!");
-          //indices[i] = new[] { integerVector[i] };
+          //throw new InvalidOperationException("no indices!");
+          indices[i] = new[] { integerVector[i] };
         }
       }
@@ -193,14 +217,18 @@
 
           double target = currentIndex - stepSize * slope;
-          int targetStart = (int)Math.Round(target - range / 2.0), targetEnd = (int)Math.Round(target + range / 2.0);
-
-          int start = Math.Min(Math.Max(targetStart, 0), currentIndex + 1);
-          int end = Math.Min(Math.Max(targetEnd, currentIndex), length);
+          int targetStart = (int)Math.Round(target - range / 2.0);
+          int targetEnd = (int)Math.Round(target + range / 2.0);
+
+          int start = Limit(targetStart, 0, currentIndex + 1);
+          int end = Limit(targetEnd, currentIndex, length);
           return Enumerable.Range(start, end - start + 1);
-          }
+        }
         default:
           throw new ArgumentOutOfRangeException(nameof(searchRange), searchRange, null);
       }
     }
+
+    private static double Limit(int x, double min, double max) { return Math.Min(Math.Max(x, min), max); }
+    private static int Limit(int x, int min, int max) { return Math.Min(Math.Max(x, min), max); }
 
     private static double CalculateSlope(IntegerVector position, int dim, Func<IntegerVector, double> evaluate) {
