Index: /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj
===================================================================
--- /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj	(revision 15945)
+++ /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj	(revision 15946)
@@ -125,6 +125,8 @@
     <Compile Include="Plugin.cs" />
     <Compile Include="SingleObjective\ConstantOptimizationAnalyzer.cs" />
+    <Compile Include="SingleObjective\EpsLexicaseAnalyzer.cs" />
     <Compile Include="SingleObjective\Evaluators\SymbolicRegressionMeanRelativeErrorEvaluator.cs" />
     <Compile Include="SingleObjective\SymbolicRegressionSolutionsAnalyzer.cs" />
+    <Compile Include="SingleObjective\EpsLexicaseSelection.cs" />
     <Compile Include="SymbolicRegressionPhenotypicDiversityAnalyzer.cs" />
     <Compile Include="SymbolicRegressionPruningAnalyzer.cs" />
@@ -254,4 +256,12 @@
       <Private>False</Private>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Random\3.3\HeuristicLab.Random-3.3.csproj">
+      <Project>{F4539FB6-4708-40C9-BE64-0A1390AEA197}</Project>
+      <Name>HeuristicLab.Random-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Selection\3.3\HeuristicLab.Selection-3.3.csproj">
+      <Project>{2C36CD4F-E5F5-43A4-801A-201EA895FE17}</Project>
+      <Name>HeuristicLab.Selection-3.3</Name>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Index: /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/EpsLexicaseAnalyzer.cs
===================================================================
--- /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/EpsLexicaseAnalyzer.cs	(revision 15946)
+++ /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/EpsLexicaseAnalyzer.cs	(revision 15946)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;              
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis; 
+ 
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
+  /// <summary>
+  /// Analyzer to use in combination with eps-lexicase selection
+  /// </summary>
+  [Item("EpsLexicaseAnalyzer", "")]
+  [StorableClass]
+  public sealed class EpsLexicaseAnalyzer : SymbolicDataAnalysisSingleObjectiveAnalyzer {
+
+    [StorableConstructor]
+    private EpsLexicaseAnalyzer(bool deserializing) : base(deserializing) { }
+    private EpsLexicaseAnalyzer(EpsLexicaseAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new EpsLexicaseAnalyzer(this, cloner);
+    }
+
+    public EpsLexicaseAnalyzer()
+      : base() {
+      Parameters.Add(new LookupParameter<IRegressionProblemData>("ProblemData"));
+      Parameters.Add(new LookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>("SymbolicExpressionTreeInterpreter"));
+      Parameters.Add(new LookupParameter<DoubleLimit>("EstimationLimits"));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleArray>("Errors", 1));
+    }
+
+    public override IOperation Apply() {
+      var problemData = (IRegressionProblemData)Parameters["ProblemData"].ActualValue;
+      var ds = problemData.Dataset;
+      var trainingRows = problemData.TrainingIndices.ToArray();
+      var y = problemData.TargetVariableTrainingValues.ToArray();
+      var trees = SymbolicExpressionTree;
+      var interpreter = (ISymbolicDataAnalysisExpressionTreeInterpreter)Parameters["SymbolicExpressionTreeInterpreter"].ActualValue;
+      var limits = (DoubleLimit)Parameters["EstimationLimits"].ActualValue;
+
+      var errors = new ItemArray<DoubleArray>(trees.Length);
+      int i = 0;
+      foreach (var tree in trees) {
+        var model = new SymbolicRegressionModel(problemData.TargetVariable, tree, (ISymbolicDataAnalysisExpressionTreeInterpreter)interpreter.Clone(), limits.Lower, limits.Upper);
+        if (ApplyLinearScalingParameter.ActualValue.Value)
+          model.Scale(problemData);
+
+        errors[i] = new DoubleArray(y.Zip(model.GetEstimatedValues(ds, trainingRows), (yi, pi) => Math.Abs(yi - pi)).ToArray());
+        i++;
+      }
+      Parameters["Errors"].ActualValue = errors;
+
+      return base.Apply();
+    }
+  }
+}
Index: /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/EpsLexicaseSelection.cs
===================================================================
--- /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/EpsLexicaseSelection.cs	(revision 15946)
+++ /branches/2389-EpsLexicase/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/EpsLexicaseSelection.cs	(revision 15946)
@@ -0,0 +1,169 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Random;
+using HeuristicLab.Selection;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
+  /// <summary>
+  /// eps-Lexicase Selection
+  /// </summary>
+  [Item("EpsLexicaseSelection", "")]
+  [StorableClass]
+  public sealed class EpsLexicaseSelection : StochasticSingleObjectiveSelector, ISingleObjectiveSelector {
+
+    [StorableConstructor]
+    private EpsLexicaseSelection(bool deserializing) : base(deserializing) { }
+    private EpsLexicaseSelection(EpsLexicaseSelection original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new EpsLexicaseSelection(this, cloner);
+    }
+
+    public EpsLexicaseSelection()
+      : base() {
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleArray>("Errors", 1));
+
+      var validPolicies = new ItemSet<StringValue>(new string[] { "ϵ_e", "ϵ_y", "ϵ_e,λ", "ϵ_y,λ" }.Select(s => new StringValue(s).AsReadOnly()));
+      Parameters.Add(new ConstrainedValueParameter<StringValue>("Policy", "The selection policy (see La Cava, Spector, Danai: eps-Lexicase Selection for Regression, GECCO 2016)", validPolicies));
+      Parameters.Add(new ValueParameter<DoubleValue>("ϵ", "The ϵ value for ϵ_e and ϵ_y policies", new DoubleValue(1.0)));
+      Parameters.Add(new LookupParameter<DoubleValue>("AvgConsideredTestCases", "The average number of considered test cases for selection."));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // remove
+      if (!Parameters.ContainsKey("AvgConsideredTestCases")) {
+        Parameters.Add(new LookupParameter<DoubleValue>("AvgConsideredTestCases", "The average number of considered test cases for selection."));
+      }
+    }
+
+    protected override IScope[] Select(List<IScope> scopes) {
+      // NOT efficiently implemented, used only for exploration of diversity for a paper
+
+      int parentCount = NumberOfSelectedSubScopesParameter.ActualValue.Value;
+      bool copy = CopySelectedParameter.Value.Value;
+      if (!copy) throw new ArgumentException("copy is false in eps-lexicase selection.");
+      IRandom random = RandomParameter.ActualValue;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      IScope[] selected = new IScope[parentCount];
+
+      int nScopes = scopes.Count();
+      var errors = (ItemArray<DoubleArray>)((IScopeTreeLookupParameter)Parameters["Errors"]).ActualValue;
+      if (errors == null || !errors.Any())
+        throw new ArgumentException("Have not found errors of models. Have you used an analyzer that calculates the errors and stores them in the scope?");
+
+      var e = errors.Select(e_m => e_m.ToArray()).ToArray();
+      errors = null; // don't use errors
+
+
+      // see La Cava, Spector, Danai: eps-Lexicase Selection for Regression, GECCO 2016
+      var ts = Enumerable.Range(0, e.First().Length).ToArray();
+
+      double eps = ((DoubleValue)Parameters["ϵ"].ActualValue).Value;
+      var selectionPolicy = ((StringValue)Parameters["Policy"].ActualValue).Value;
+
+      var selectedScopes = new IScope[parentCount];
+      var nCasesList = new List<double>(parentCount);
+      var lambda_e = ts.Select(t=> MAD(e.Select(e_m => e_m[t]).ToArray())).ToArray();  
+
+      for (int i = 0; i < parentCount; i++) {
+        int nCases;
+        var selectedIdx = SelectIdx(random, e, selectionPolicy, ts, eps, lambda_e, out nCases);
+        nCasesList.Add(nCases);
+        selectedScopes[i] = (IScope)(scopes[selectedIdx]).Clone();
+      }
+      Parameters["AvgConsideredTestCases"].ActualValue = new DoubleValue(nCasesList.Median());
+      return selectedScopes;
+    }
+
+    public static int SelectIdx(IRandom random, double[][] errors, string selectionPolicy, int[] ts, double eps, double[] lambda_e, out int nCases) {
+      ts.ShuffleInPlace(random);
+
+      var activeModelIdxs = new SortedSet<int>(Enumerable.Range(0, errors.Length));
+      nCases = 0;
+
+      foreach (var t in ts) {
+        if (activeModelIdxs.Count <= 1) break;
+        nCases++;
+
+        switch (selectionPolicy) {
+          case "ϵ_e": {
+              var bestError = errors.Select(err_m => err_m[t]).Min(); // as noted in corrected version of GECCO 2016 paper
+              activeModelIdxs.RemoveWhere(modelIdx => errors[modelIdx][t] > bestError * (1 + eps));
+              break;
+            }
+          case "ϵ_y": {
+              activeModelIdxs.RemoveWhere(modelIdx => errors[modelIdx][t] > eps);
+              break;
+            }
+          // Note in a corrected version of the GECCO Paper La Cava changed equations (2) and (5)
+          //    Equations 2 and 5 have been corrected to
+          //    indicate that the pass conditions for individuals in -lexicase
+          //    selection are defined relative to the best error in the population
+          //    on that training case, not in the selection pool.
+
+          // a more recent and detailed description of the algorithm is given in https://arxiv.org/pdf/1709.05394.pdf
+          // which indicates that semi-dynamic eps-lexicase performs best (Algorithm 4.2)
+          // -> we also implement semi-dynamic eps-lexicase which calculates lambda over the whole population
+
+          // I have not found a way to get reasonable convergence using MAD for lambda.
+          // If lambda_e[t] is zero this means that all models are effectively the same => select randomly.
+          // It seems that linear scaling (or the replacement of NaN outputs with the average of y) 
+          // has the effect that MAD is zero (especially in the beginning), which means there is not selection pressure at the beginning.
+          //  Semi-dynamic -Lexicase Selection
+          case "ϵ_e,λ": {
+              var bestError = activeModelIdxs.Select(modelIdx => errors[modelIdx][t]).Min(); // See   https://arxiv.org/pdf/1709.05394.pdf Alg 4.2
+              activeModelIdxs.RemoveWhere(modelIdx => errors[modelIdx][t] > bestError + lambda_e[t]); // in the gecco paper the acceptance criterion is err < lambda_et this is later correct to err <= lambda_et
+              break;
+            }
+          case "ϵ_y,λ": {
+              activeModelIdxs.RemoveWhere(modelIdx => errors[modelIdx][t] > lambda_e[t]); // in the gecco paper the acceptance criterion is err < lambda_et this is later correct to err <= lambda_et
+              break;
+            }
+          default: throw new ArgumentException("unknown policy " + selectionPolicy);
+        }
+      }
+
+      if (!activeModelIdxs.Any())
+        throw new ArgumentException("nothing left in the pool");
+      else
+        return activeModelIdxs.SampleRandom(random, 1).First();
+    }
+
+    private static double MAD(double[] x) {
+      var median_x = x.Median();
+      return x.Select(xi => Math.Abs(xi - median_x)).Median();
+    }
+    private static double StdDev(double[] x) {
+      return x.StandardDeviation();
+    }
+  }
+}
